< prev index next >

src/java.base/share/classes/java/util/zip/ZipOutputStream.java

Print this page
rev 51866 : 6194856: Zip Files lose ALL ownership and permissions of the files

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -23,18 +23,20 @@
  * questions.
  */
 
 package java.util.zip;
 
-import java.io.OutputStream;
+import static java.util.zip.ZipConstants64.*;
+import static java.util.zip.ZipUtils.*;
+
 import java.io.IOException;
+import java.io.OutputStream;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
-import java.util.Vector;
 import java.util.HashSet;
-import static java.util.zip.ZipConstants64.*;
-import static java.util.zip.ZipUtils.*;
+import java.util.Vector;
+
 import sun.security.action.GetPropertyAction;
 
 /**
  * This class implements an output stream filter for writing files in the
  * ZIP file format. Includes support for both compressed and uncompressed

@@ -65,10 +67,12 @@
             this.entry = entry;
             this.offset = offset;
         }
     }
 
+    private static int VERSION_BASE_UNIX = ZipFile.FILE_ATTRIBUTES_UNIX << 8;
+
     private XEntry current;
     private Vector<XEntry> xentries = new Vector<>();
     private HashSet<String> names = new HashSet<>();
     private CRC32 crc = new CRC32();
     private long written = 0;

@@ -79,19 +83,33 @@
 
     private boolean closed = false;
 
     private final ZipCoder zc;
 
-    private static int version(ZipEntry e) throws ZipException {
+    private static int version(ZipEntry e, boolean zip64)
+        throws ZipException
+    {
+        if (zip64) {
+            return 45;
+        }
         switch (e.method) {
         case DEFLATED: return 20;
         case STORED:   return 10;
         default: throw new ZipException("unsupported compression method");
         }
     }
 
     /**
+     * Adds information about compatibility of file attribute information
+     * to a version value.
+     */
+    private static int versionMadeBy(ZipEntry e, int version) {
+        return (e.posixPerms < 0) ? version :
+            VERSION_BASE_UNIX | (version & 0xff);
+    }
+
+    /**
      * Checks to make sure that this stream has not been closed.
      */
     private void ensureOpen() throws IOException {
         if (closed) {
             throw new IOException("Stream closed");

@@ -384,36 +402,34 @@
      * Writes local file (LOC) header for specified entry.
      */
     private void writeLOC(XEntry xentry) throws IOException {
         ZipEntry e = xentry.entry;
         int flag = e.flag;
-        boolean hasZip64 = false;
+        boolean zip64 = false;
         int elen = getExtraLen(e.extra);
 
         writeInt(LOCSIG);               // LOC header signature
         if ((flag & 8) == 8) {
-            writeShort(version(e));     // version needed to extract
+            writeShort(version(e, zip64)); // version needed to extract
             writeShort(flag);           // general purpose bit flag
             writeShort(e.method);       // compression method
             writeInt(e.xdostime);       // last modification time
             // store size, uncompressed size, and crc-32 in data descriptor
             // immediately following compressed entry data
             writeInt(0);
             writeInt(0);
             writeInt(0);
         } else {
             if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
-                hasZip64 = true;
-                writeShort(45);         // ver 4.5 for zip64
-            } else {
-                writeShort(version(e)); // version needed to extract
+                zip64 = true;
             }
+            writeShort(version(e, zip64)); // version needed to extract
             writeShort(flag);           // general purpose bit flag
             writeShort(e.method);       // compression method
             writeInt(e.xdostime);       // last modification time
             writeInt(e.crc);            // crc-32
-            if (hasZip64) {
+            if (zip64) {
                 writeInt(ZIP64_MAGICVAL);
                 writeInt(ZIP64_MAGICVAL);
                 elen += 20;        //headid(2) + size(2) + size(8) + csize(8)
             } else {
                 writeInt(e.csize);  // compressed size

@@ -453,11 +469,11 @@
                 elen += (elenEXTT + 5);    // headid(2) + size(2) + flag(1) + data
             }
         }
         writeShort(elen);
         writeBytes(nameBytes, 0, nameBytes.length);
-        if (hasZip64) {
+        if (zip64) {
             writeShort(ZIP64_EXTID);
             writeShort(16);
             writeLong(e.size);
             writeLong(e.csize);
         }

@@ -510,54 +526,49 @@
     /*
      * Write central directory (CEN) header for specified entry.
      * REMIND: add support for file attributes
      */
     private void writeCEN(XEntry xentry) throws IOException {
-        ZipEntry e  = xentry.entry;
+        ZipEntry e = xentry.entry;
         int flag = e.flag;
-        int version = version(e);
         long csize = e.csize;
         long size = e.size;
         long offset = xentry.offset;
         int elenZIP64 = 0;
-        boolean hasZip64 = false;
-
+        boolean zip64 = false;
         if (e.csize >= ZIP64_MAGICVAL) {
             csize = ZIP64_MAGICVAL;
-            elenZIP64 += 8;              // csize(8)
-            hasZip64 = true;
+            elenZIP64 += 8;           // csize(8)
+            zip64 = true;
         }
         if (e.size >= ZIP64_MAGICVAL) {
             size = ZIP64_MAGICVAL;    // size(8)
             elenZIP64 += 8;
-            hasZip64 = true;
+            zip64 = true;
         }
         if (xentry.offset >= ZIP64_MAGICVAL) {
             offset = ZIP64_MAGICVAL;
-            elenZIP64 += 8;              // offset(8)
-            hasZip64 = true;
+            elenZIP64 += 8;           // offset(8)
+            zip64 = true;
         }
+        int version = version(e, zip64);
+
         writeInt(CENSIG);           // CEN header signature
-        if (hasZip64) {
-            writeShort(45);         // ver 4.5 for zip64
-            writeShort(45);
-        } else {
-            writeShort(version);    // version made by
-            writeShort(version);    // version needed to extract
-        }
+        writeShort(versionMadeBy(e, version)); // version made by
+        writeShort(version);        // version needed to extract
         writeShort(flag);           // general purpose bit flag
         writeShort(e.method);       // compression method
         writeInt(e.xdostime);       // last modification time
         writeInt(e.crc);            // crc-32
         writeInt(csize);            // compressed size
         writeInt(size);             // uncompressed size
         byte[] nameBytes = zc.getBytes(e.name);
         writeShort(nameBytes.length);
 
         int elen = getExtraLen(e.extra);
-        if (hasZip64) {
-            elen += (elenZIP64 + 4);// + headid(2) + datasize(2)
+        if (zip64) {
+            elen += (elenZIP64 + 4); // + headid(2) + datasize(2)
         }
         // cen info-zip extended timestamp only outputs mtime
         // but set the flag for a/ctime, if present in loc
         int flagEXTT = 0;
         long umtime = -1;

@@ -596,16 +607,18 @@
             commentBytes = null;
             writeShort(0);
         }
         writeShort(0);              // starting disk number
         writeShort(0);              // internal file attributes (unused)
-        writeInt(0);                // external file attributes (unused)
+        writeInt(e.posixPerms > 0 ? e.posixPerms << 16 : 0); // external file
+                                    // attributes, used for storing posix
+                                    // permissions
         writeInt(offset);           // relative offset of local header
         writeBytes(nameBytes, 0, nameBytes.length);
 
         // take care of EXTID_ZIP64 and EXTID_EXTT
-        if (hasZip64) {
+        if (zip64) {
             writeShort(ZIP64_EXTID);// Zip64 extra
             writeShort(elenZIP64);
             if (size == ZIP64_MAGICVAL)
                 writeLong(e.size);
             if (csize == ZIP64_MAGICVAL)

@@ -648,29 +661,29 @@
 
     /*
      * Writes end of central directory (END) header.
      */
     private void writeEND(long off, long len) throws IOException {
-        boolean hasZip64 = false;
+        boolean zip64 = false;
         long xlen = len;
         long xoff = off;
         if (xlen >= ZIP64_MAGICVAL) {
             xlen = ZIP64_MAGICVAL;
-            hasZip64 = true;
+            zip64 = true;
         }
         if (xoff >= ZIP64_MAGICVAL) {
             xoff = ZIP64_MAGICVAL;
-            hasZip64 = true;
+            zip64 = true;
         }
         int count = xentries.size();
         if (count >= ZIP64_MAGICCOUNT) {
-            hasZip64 |= !inhibitZip64;
-            if (hasZip64) {
+            zip64 |= !inhibitZip64;
+            if (zip64) {
                 count = ZIP64_MAGICCOUNT;
             }
         }
-        if (hasZip64) {
+        if (zip64) {
             long off64 = written;
             //zip64 end of central directory record
             writeInt(ZIP64_ENDSIG);        // zip64 END record signature
             writeLong(ZIP64_ENDHDR - 12);  // size of zip64 end
             writeShort(45);                // version made by
< prev index next >