< prev index next >

src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java

Print this page
rev 53081 : 8213031: (zipfs) Add support for POSIX file permissions
Reviewed-by: simonis


  26 package jdk.nio.zipfs;
  27 
  28 import java.io.BufferedOutputStream;
  29 import java.io.ByteArrayInputStream;
  30 import java.io.ByteArrayOutputStream;
  31 import java.io.EOFException;
  32 import java.io.FilterOutputStream;
  33 import java.io.IOException;
  34 import java.io.InputStream;
  35 import java.io.OutputStream;
  36 import java.nio.ByteBuffer;
  37 import java.nio.MappedByteBuffer;
  38 import java.nio.channels.FileChannel;
  39 import java.nio.channels.FileLock;
  40 import java.nio.channels.ReadableByteChannel;
  41 import java.nio.channels.SeekableByteChannel;
  42 import java.nio.channels.WritableByteChannel;
  43 import java.nio.file.*;
  44 import java.nio.file.attribute.FileAttribute;
  45 import java.nio.file.attribute.FileTime;



  46 import java.nio.file.attribute.UserPrincipalLookupService;
  47 import java.nio.file.spi.FileSystemProvider;
  48 import java.security.AccessController;
  49 import java.security.PrivilegedAction;
  50 import java.security.PrivilegedActionException;
  51 import java.security.PrivilegedExceptionAction;
  52 import java.util.*;
  53 import java.util.concurrent.locks.ReadWriteLock;
  54 import java.util.concurrent.locks.ReentrantReadWriteLock;
  55 import java.util.regex.Pattern;
  56 import java.util.zip.CRC32;
  57 import java.util.zip.Deflater;
  58 import java.util.zip.DeflaterOutputStream;
  59 import java.util.zip.Inflater;
  60 import java.util.zip.InflaterInputStream;
  61 import java.util.zip.ZipException;
  62 
  63 import static java.lang.Boolean.TRUE;
  64 import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES;
  65 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;


 354             if (getInode(path) == null) {
 355                 throw new NoSuchFileException(toString());
 356             }
 357 
 358         } finally {
 359             endRead();
 360         }
 361     }
 362 
 363     void setTimes(byte[] path, FileTime mtime, FileTime atime, FileTime ctime)
 364         throws IOException
 365     {
 366         checkWritable();
 367         beginWrite();
 368         try {
 369             ensureOpen();
 370             Entry e = getEntry(path);    // ensureOpen checked
 371             if (e == null)
 372                 throw new NoSuchFileException(getString(path));
 373             if (e.type == Entry.CEN)
 374                 e.type = Entry.COPY;      // copy e
 375             if (mtime != null)
 376                 e.mtime = mtime.toMillis();
 377             if (atime != null)
 378                 e.atime = atime.toMillis();
 379             if (ctime != null)
 380                 e.ctime = ctime.toMillis();
 381             update(e);
 382         } finally {
 383             endWrite();
 384         }
 385     }
 386 





















 387     boolean exists(byte[] path)
 388         throws IOException
 389     {
 390         beginRead();
 391         try {
 392             ensureOpen();
 393             return getInode(path) != null;
 394         } finally {
 395             endRead();
 396         }
 397     }
 398 
 399     boolean isDirectory(byte[] path)
 400         throws IOException
 401     {
 402         beginRead();
 403         try {
 404             IndexNode n = getInode(path);
 405             return n != null && n.isDir();
 406         } finally {


 437                     list.add(zpath);
 438                 child = child.sibling;
 439             }
 440             return list.iterator();
 441         } finally {
 442             endWrite();
 443         }
 444     }
 445 
 446     void createDirectory(byte[] dir, FileAttribute<?>... attrs)
 447         throws IOException
 448     {
 449         checkWritable();
 450         //  dir = toDirectoryPath(dir);
 451         beginWrite();
 452         try {
 453             ensureOpen();
 454             if (dir.length == 0 || exists(dir))  // root dir, or exiting dir
 455                 throw new FileAlreadyExistsException(getString(dir));
 456             checkParents(dir);
 457             Entry e = new Entry(dir, Entry.NEW, true, METHOD_STORED);
 458             update(e);
 459         } finally {
 460             endWrite();
 461         }
 462     }
 463 
 464     void copyFile(boolean deletesrc, byte[]src, byte[] dst, CopyOption... options)
 465         throws IOException
 466     {
 467         checkWritable();
 468         if (Arrays.equals(src, dst))
 469             return;    // do nothing, src and dst are the same
 470 
 471         beginWrite();
 472         try {
 473             ensureOpen();
 474             Entry eSrc = getEntry(src);  // ensureOpen checked
 475 
 476             if (eSrc == null)
 477                 throw new NoSuchFileException(getString(src));


 659                     SeekableByteChannel sbc =
 660                             new EntryOutputChannel(new Entry(e, Entry.NEW));
 661                     if (options.contains(APPEND)) {
 662                         try (InputStream is = getInputStream(e)) {  // copyover
 663                             byte[] buf = new byte[8192];
 664                             ByteBuffer bb = ByteBuffer.wrap(buf);
 665                             int n;
 666                             while ((n = is.read(buf)) != -1) {
 667                                 bb.position(0);
 668                                 bb.limit(n);
 669                                 sbc.write(bb);
 670                             }
 671                         }
 672                     }
 673                     return sbc;
 674                 }
 675                 if (!options.contains(CREATE) && !options.contains(CREATE_NEW))
 676                     throw new NoSuchFileException(getString(path));
 677                 checkParents(path);
 678                 return new EntryOutputChannel(
 679                     new Entry(path, Entry.NEW, false, getCompressMethod(attrs)));
 680 
 681             } finally {
 682                 endRead();
 683             }
 684         } else {
 685             beginRead();
 686             try {
 687                 ensureOpen();
 688                 Entry e = getEntry(path);
 689                 if (e == null || e.isDir())
 690                     throw new NoSuchFileException(getString(path));
 691                 try (InputStream is = getInputStream(e)) {
 692                     // TBD: if (e.size < NNNNN);
 693                     return new ByteArrayChannel(is.readAllBytes(), true);
 694                 }
 695             } finally {
 696                 endRead();
 697             }
 698         }
 699     }


 724                     }
 725                 } else {
 726                     if (options.contains(StandardOpenOption.CREATE_NEW)) {
 727                         throw new FileAlreadyExistsException(getString(path));
 728                     }
 729                     if (e.isDir())
 730                         throw new FileAlreadyExistsException("directory <"
 731                             + getString(path) + "> exists");
 732                 }
 733                 options = new HashSet<>(options);
 734                 options.remove(StandardOpenOption.CREATE_NEW); // for tmpfile
 735             } else if (e == null || e.isDir()) {
 736                 throw new NoSuchFileException(getString(path));
 737             }
 738 
 739             final boolean isFCH = (e != null && e.type == Entry.FILECH);
 740             final Path tmpfile = isFCH ? e.file : getTempPathForEntry(path);
 741             final FileChannel fch = tmpfile.getFileSystem()
 742                                            .provider()
 743                                            .newFileChannel(tmpfile, options, attrs);
 744             final Entry u = isFCH ? e : new Entry(path, tmpfile, Entry.FILECH);
 745             if (forWrite) {
 746                 u.flag = FLAG_DATADESCR;
 747                 u.method = getCompressMethod(attrs);
 748             }
 749             // is there a better way to hook into the FileChannel's close method?
 750             return new FileChannel() {
 751                 public int write(ByteBuffer src) throws IOException {
 752                     return fch.write(src);
 753                 }
 754                 public long write(ByteBuffer[] srcs, int offset, int length)
 755                     throws IOException
 756                 {
 757                     return fch.write(srcs, offset, length);
 758                 }
 759                 public long position() throws IOException {
 760                     return fch.position();
 761                 }
 762                 public FileChannel position(long newPosition)
 763                     throws IOException
 764                 {


1853 
1854         IndexNode() {}
1855         IndexNode sibling;
1856         IndexNode child;  // 1st child
1857     }
1858 
1859     static class Entry extends IndexNode implements ZipFileAttributes {
1860 
1861         static final int CEN    = 1;  // entry read from cen
1862         static final int NEW    = 2;  // updated contents in bytes or file
1863         static final int FILECH = 3;  // fch update in "file"
1864         static final int COPY   = 4;  // copy of a CEN entry
1865 
1866         byte[] bytes;                 // updated content bytes
1867         Path   file;                  // use tmp file to store bytes;
1868         int    type = CEN;            // default is the entry read from cen
1869 
1870         // entry attributes
1871         int    version;
1872         int    flag;

1873         int    method = -1;    // compression method
1874         long   mtime  = -1;    // last modification time (in DOS time)
1875         long   atime  = -1;    // last access time
1876         long   ctime  = -1;    // create time
1877         long   crc    = -1;    // crc-32 of entry data
1878         long   csize  = -1;    // compressed size of entry data
1879         long   size   = -1;    // uncompressed size of entry data
1880         byte[] extra;
1881 
1882         // cen
1883 
1884         // these fields are not used by anyone and writeCEN uses "0"
1885         // int    versionMade;
1886         // int    disk;
1887         // int    attrs;
1888         // long   attrsEx;
1889         long   locoff;
1890         byte[] comment;
1891 
1892         Entry() {}
1893 
1894         Entry(byte[] name, boolean isdir, int method) {
1895             name(name);
1896             this.isdir = isdir;
1897             this.mtime  = this.ctime = this.atime = System.currentTimeMillis();
1898             this.crc    = 0;
1899             this.size   = 0;
1900             this.csize  = 0;
1901             this.method = method;
1902         }
1903 
1904         Entry(byte[] name, int type, boolean isdir, int method) {

1905             this(name, isdir, method);
1906             this.type = type;






1907         }
1908 
1909         Entry (Entry e, int type) {
1910             name(e.name);
1911             this.isdir     = e.isdir;
1912             this.version   = e.version;
1913             this.ctime     = e.ctime;
1914             this.atime     = e.atime;
1915             this.mtime     = e.mtime;
1916             this.crc       = e.crc;
1917             this.size      = e.size;
1918             this.csize     = e.csize;
1919             this.method    = e.method;
1920             this.extra     = e.extra;
1921             /*
1922             this.versionMade = e.versionMade;
1923             this.disk      = e.disk;
1924             this.attrs     = e.attrs;
1925             this.attrsEx   = e.attrsEx;
1926             */
1927             this.locoff    = e.locoff;
1928             this.comment   = e.comment;

1929             this.type      = type;
1930         }
1931 
1932         Entry (byte[] name, Path file, int type) {

1933             this(name, type, false, METHOD_STORED);
1934             this.file = file;






1935         }
1936 
1937         int version() throws ZipException {



1938             if (method == METHOD_DEFLATED)
1939                 return 20;
1940             else if (method == METHOD_STORED)
1941                 return 10;
1942             throw new ZipException("unsupported compression method");
1943         }
1944 









1945         ///////////////////// CEN //////////////////////
1946         static Entry readCEN(ZipFileSystem zipfs, IndexNode inode)
1947             throws IOException
1948         {
1949             return new Entry().cen(zipfs, inode);
1950         }
1951 
1952         private Entry cen(ZipFileSystem zipfs, IndexNode inode)
1953             throws IOException
1954         {
1955             byte[] cen = zipfs.cen;
1956             int pos = inode.pos;
1957             if (!cenSigAt(cen, pos))
1958                 zerror("invalid CEN header (bad signature)");
1959             version     = CENVER(cen, pos);
1960             flag        = CENFLG(cen, pos);
1961             method      = CENHOW(cen, pos);
1962             mtime       = dosToJavaTime(CENTIM(cen, pos));
1963             crc         = CENCRC(cen, pos);
1964             csize       = CENSIZ(cen, pos);
1965             size        = CENLEN(cen, pos);
1966             int nlen    = CENNAM(cen, pos);
1967             int elen    = CENEXT(cen, pos);
1968             int clen    = CENCOM(cen, pos);
1969             /*
1970             versionMade = CENVEM(cen, pos);
1971             disk        = CENDSK(cen, pos);
1972             attrs       = CENATT(cen, pos);
1973             attrsEx     = CENATX(cen, pos);
1974             */



1975             locoff      = CENOFF(cen, pos);
1976             pos += CENHDR;
1977             this.name = inode.name;
1978             this.isdir = inode.isdir;
1979             this.hashcode = inode.hashcode;
1980 
1981             pos += nlen;
1982             if (elen > 0) {
1983                 extra = Arrays.copyOfRange(cen, pos, pos + elen);
1984                 pos += elen;
1985                 readExtra(zipfs);
1986             }
1987             if (clen > 0) {
1988                 comment = Arrays.copyOfRange(cen, pos, pos + clen);
1989             }
1990             return this;
1991         }
1992 
1993         int writeCEN(OutputStream os) throws IOException {
1994             int version0 = version();
1995             long csize0  = csize;
1996             long size0   = size;
1997             long locoff0 = locoff;
1998             int elen64   = 0;                // extra for ZIP64
1999             int elenNTFS = 0;                // extra for NTFS (a/c/mtime)
2000             int elenEXTT = 0;                // extra for Extended Timestamp
2001             boolean foundExtraTime = false;  // if time stamp NTFS, EXTT present
2002 
2003             byte[] zname = isdir ? toDirectoryPath(name) : name;
2004 
2005             // confirm size/length
2006             int nlen = (zname != null) ? zname.length - 1 : 0;  // name has [0] as "slash"
2007             int elen = (extra != null) ? extra.length : 0;
2008             int eoff = 0;
2009             int clen = (comment != null) ? comment.length : 0;
2010             if (csize >= ZIP64_MINVAL) {
2011                 csize0 = ZIP64_MINVAL;
2012                 elen64 += 8;                 // csize(8)
2013             }
2014             if (size >= ZIP64_MINVAL) {
2015                 size0 = ZIP64_MINVAL;        // size(8)
2016                 elen64 += 8;
2017             }
2018             if (locoff >= ZIP64_MINVAL) {
2019                 locoff0 = ZIP64_MINVAL;
2020                 elen64 += 8;                 // offset(8)
2021             }
2022             if (elen64 != 0) {
2023                 elen64 += 4;                 // header and data sz 4 bytes
2024             }


2025             while (eoff + 4 < elen) {
2026                 int tag = SH(extra, eoff);
2027                 int sz = SH(extra, eoff + 2);
2028                 if (tag == EXTID_EXTT || tag == EXTID_NTFS) {
2029                     foundExtraTime = true;
2030                 }
2031                 eoff += (4 + sz);
2032             }
2033             if (!foundExtraTime) {
2034                 if (isWindows) {             // use NTFS
2035                     elenNTFS = 36;           // total 36 bytes
2036                 } else {                     // Extended Timestamp otherwise
2037                     elenEXTT = 9;            // only mtime in cen
2038                 }
2039             }
2040             writeInt(os, CENSIG);            // CEN header signature
2041             if (elen64 != 0) {
2042                 writeShort(os, 45);          // ver 4.5 for zip64
2043                 writeShort(os, 45);
2044             } else {
2045                 writeShort(os, version0);    // version made by
2046                 writeShort(os, version0);    // version needed to extract
2047             }
2048             writeShort(os, flag);            // general purpose bit flag
2049             writeShort(os, method);          // compression method
2050                                              // last modification time
2051             writeInt(os, (int)javaToDosTime(mtime));
2052             writeInt(os, crc);               // crc-32
2053             writeInt(os, csize0);            // compressed size
2054             writeInt(os, size0);             // uncompressed size
2055             writeShort(os, nlen);
2056             writeShort(os, elen + elen64 + elenNTFS + elenEXTT);
2057 
2058             if (comment != null) {
2059                 writeShort(os, Math.min(clen, 0xffff));
2060             } else {
2061                 writeShort(os, 0);
2062             }
2063             writeShort(os, 0);              // starting disk number
2064             writeShort(os, 0);              // internal file attributes (unused)
2065             writeInt(os, 0);                // external file attributes (unused)


2066             writeInt(os, locoff0);          // relative offset of local header
2067             writeBytes(os, zname, 1, nlen);
2068             if (elen64 != 0) {
2069                 writeShort(os, EXTID_ZIP64);// Zip64 extra
2070                 writeShort(os, elen64 - 4); // size of "this" extra block
2071                 if (size0 == ZIP64_MINVAL)
2072                     writeLong(os, size);
2073                 if (csize0 == ZIP64_MINVAL)
2074                     writeLong(os, csize);
2075                 if (locoff0 == ZIP64_MINVAL)
2076                     writeLong(os, locoff);
2077             }
2078             if (elenNTFS != 0) {
2079                 writeShort(os, EXTID_NTFS);
2080                 writeShort(os, elenNTFS - 4);
2081                 writeInt(os, 0);            // reserved
2082                 writeShort(os, 0x0001);     // NTFS attr tag
2083                 writeShort(os, 24);
2084                 writeLong(os, javaToWinTime(mtime));
2085                 writeLong(os, javaToWinTime(atime));
2086                 writeLong(os, javaToWinTime(ctime));
2087             }
2088             if (elenEXTT != 0) {
2089                 writeShort(os, EXTID_EXTT);
2090                 writeShort(os, elenEXTT - 4);
2091                 if (ctime == -1)
2092                     os.write(0x3);          // mtime and atime
2093                 else
2094                     os.write(0x7);          // mtime, atime and ctime
2095                 writeInt(os, javaToUnixTime(mtime));
2096             }
2097             if (extra != null)              // whatever not recognized
2098                 writeBytes(os, extra);
2099             if (comment != null)            //TBD: 0, Math.min(commentBytes.length, 0xffff));
2100                 writeBytes(os, comment);
2101             return CENHDR + nlen + elen + clen + elen64 + elenNTFS + elenEXTT;
2102         }
2103 
2104         ///////////////////// LOC //////////////////////
2105 
2106         int writeLOC(OutputStream os) throws IOException {
2107             int version0 = version();
2108             byte[] zname = isdir ? toDirectoryPath(name) : name;
2109             int nlen = (zname != null) ? zname.length - 1 : 0; // [0] is slash
2110             int elen = (extra != null) ? extra.length : 0;
2111             boolean foundExtraTime = false;     // if extra timestamp present
2112             int eoff = 0;
2113             int elen64 = 0;

2114             int elenEXTT = 0;
2115             int elenNTFS = 0;
2116             writeInt(os, LOCSIG);               // LOC header signature
2117             if ((flag & FLAG_DATADESCR) != 0) {
2118                 writeShort(os, version0);       // version needed to extract
2119                 writeShort(os, flag);           // general purpose bit flag
2120                 writeShort(os, method);         // compression method
2121                 // last modification time
2122                 writeInt(os, (int)javaToDosTime(mtime));
2123                 // store size, uncompressed size, and crc-32 in data descriptor
2124                 // immediately following compressed entry data
2125                 writeInt(os, 0);
2126                 writeInt(os, 0);
2127                 writeInt(os, 0);
2128             } else {
2129                 if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) {
2130                     elen64 = 20;    //headid(2) + size(2) + size(8) + csize(8)
2131                     writeShort(os, 45);         // ver 4.5 for zip64
2132                 } else {
2133                     writeShort(os, version0);   // version needed to extract
2134                 }

2135                 writeShort(os, flag);           // general purpose bit flag
2136                 writeShort(os, method);         // compression method
2137                                                 // last modification time
2138                 writeInt(os, (int)javaToDosTime(mtime));
2139                 writeInt(os, crc);              // crc-32
2140                 if (elen64 != 0) {
2141                     writeInt(os, ZIP64_MINVAL);
2142                     writeInt(os, ZIP64_MINVAL);
2143                 } else {
2144                     writeInt(os, csize);        // compressed size
2145                     writeInt(os, size);         // uncompressed size
2146                 }
2147             }
2148             while (eoff + 4 < elen) {
2149                 int tag = SH(extra, eoff);
2150                 int sz = SH(extra, eoff + 2);
2151                 if (tag == EXTID_EXTT || tag == EXTID_NTFS) {
2152                     foundExtraTime = true;
2153                 }
2154                 eoff += (4 + sz);
2155             }
2156             if (!foundExtraTime) {
2157                 if (isWindows) {
2158                     elenNTFS = 36;              // NTFS, total 36 bytes
2159                 } else {                        // on unix use "ext time"
2160                     elenEXTT = 9;
2161                     if (atime != -1)
2162                         elenEXTT += 4;
2163                     if (ctime != -1)
2164                         elenEXTT += 4;
2165                 }
2166             }
2167             writeShort(os, nlen);
2168             writeShort(os, elen + elen64 + elenNTFS + elenEXTT);
2169             writeBytes(os, zname, 1, nlen);
2170             if (elen64 != 0) {
2171                 writeShort(os, EXTID_ZIP64);
2172                 writeShort(os, 16);
2173                 writeLong(os, size);
2174                 writeLong(os, csize);
2175             }
2176             if (elenNTFS != 0) {
2177                 writeShort(os, EXTID_NTFS);
2178                 writeShort(os, elenNTFS - 4);
2179                 writeInt(os, 0);            // reserved
2180                 writeShort(os, 0x0001);     // NTFS attr tag
2181                 writeShort(os, 24);
2182                 writeLong(os, javaToWinTime(mtime));
2183                 writeLong(os, javaToWinTime(atime));
2184                 writeLong(os, javaToWinTime(ctime));
2185             }
2186             if (elenEXTT != 0) {
2187                 writeShort(os, EXTID_EXTT);
2188                 writeShort(os, elenEXTT - 4);// size for the folowing data block
2189                 int fbyte = 0x1;
2190                 if (atime != -1)           // mtime and atime
2191                     fbyte |= 0x2;
2192                 if (ctime != -1)           // mtime, atime and ctime
2193                     fbyte |= 0x4;
2194                 os.write(fbyte);           // flags byte
2195                 writeInt(os, javaToUnixTime(mtime));
2196                 if (atime != -1)
2197                     writeInt(os, javaToUnixTime(atime));
2198                 if (ctime != -1)
2199                     writeInt(os, javaToUnixTime(ctime));
2200             }
2201             if (extra != null) {
2202                 writeBytes(os, extra);
2203             }
2204             return LOCHDR + nlen + elen + elen64 + elenNTFS + elenEXTT;
2205         }
2206 
2207         // Data Descriptior
2208         int writeEXT(OutputStream os) throws IOException {
2209             writeInt(os, EXTSIG);           // EXT header signature
2210             writeInt(os, crc);              // crc-32
2211             if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) {
2212                 writeLong(os, csize);
2213                 writeLong(os, size);
2214                 return 24;
2215             } else {
2216                 writeInt(os, csize);        // compressed size
2217                 writeInt(os, size);         // uncompressed size
2218                 return 16;
2219             }
2220         }
2221 
2222         // read NTFS, UNIX and ZIP64 data from cen.extra
2223         void readExtra(ZipFileSystem zipfs) throws IOException {
2224             if (extra == null)
2225                 return;
2226             int elen = extra.length;
2227             int off = 0;


2362         @Override
2363         public FileTime lastModifiedTime() {
2364             return FileTime.fromMillis(mtime);
2365         }
2366 
2367         @Override
2368         public long size() {
2369             return size;
2370         }
2371 
2372         @Override
2373         public boolean isSymbolicLink() {
2374             return false;
2375         }
2376 
2377         @Override
2378         public Object fileKey() {
2379             return null;
2380         }
2381 
2382         ///////// zip entry attributes ///////////





























2383         public long compressedSize() {
2384             return csize;
2385         }
2386 

2387         public long crc() {
2388             return crc;
2389         }
2390 

2391         public int method() {
2392             return method;
2393         }
2394 

2395         public byte[] extra() {
2396             if (extra != null)
2397                 return Arrays.copyOf(extra, extra.length);
2398             return null;
2399         }
2400 

2401         public byte[] comment() {
2402             if (comment != null)
2403                 return Arrays.copyOf(comment, comment.length);
2404             return null;
2405         }
2406 

2407         public String toString() {
2408             StringBuilder sb = new StringBuilder(1024);
2409             Formatter fm = new Formatter(sb);
2410             fm.format("    name            : %s%n", new String(name));
2411             fm.format("    creationTime    : %tc%n", creationTime().toMillis());
2412             fm.format("    lastAccessTime  : %tc%n", lastAccessTime().toMillis());
2413             fm.format("    lastModifiedTime: %tc%n", lastModifiedTime().toMillis());
2414             fm.format("    isRegularFile   : %b%n", isRegularFile());
2415             fm.format("    isDirectory     : %b%n", isDirectory());
2416             fm.format("    isSymbolicLink  : %b%n", isSymbolicLink());
2417             fm.format("    isOther         : %b%n", isOther());
2418             fm.format("    fileKey         : %s%n", fileKey());
2419             fm.format("    size            : %d%n", size());
2420             fm.format("    compressedSize  : %d%n", compressedSize());
2421             fm.format("    crc             : %x%n", crc());
2422             fm.format("    method          : %d%n", method());



2423             fm.close();
2424             return sb.toString();
2425         }
2426     }
2427 
2428     // ZIP directory has two issues:
2429     // (1) ZIP spec does not require the ZIP file to include
2430     //     directory entry
2431     // (2) all entries are not stored/organized in a "tree"
2432     //     structure.
2433     // A possible solution is to build the node tree ourself as
2434     // implemented below.
2435 
2436     // default time stamp for pseudo entries
2437     private long zfsDefaultTimeStamp = System.currentTimeMillis();
2438 
2439     private void removeFromTree(IndexNode inode) {
2440         IndexNode parent = inodes.get(LOOKUPKEY.as(getParent(inode.name)));
2441         IndexNode child = parent.child;
2442         if (child.equals(inode)) {




  26 package jdk.nio.zipfs;
  27 
  28 import java.io.BufferedOutputStream;
  29 import java.io.ByteArrayInputStream;
  30 import java.io.ByteArrayOutputStream;
  31 import java.io.EOFException;
  32 import java.io.FilterOutputStream;
  33 import java.io.IOException;
  34 import java.io.InputStream;
  35 import java.io.OutputStream;
  36 import java.nio.ByteBuffer;
  37 import java.nio.MappedByteBuffer;
  38 import java.nio.channels.FileChannel;
  39 import java.nio.channels.FileLock;
  40 import java.nio.channels.ReadableByteChannel;
  41 import java.nio.channels.SeekableByteChannel;
  42 import java.nio.channels.WritableByteChannel;
  43 import java.nio.file.*;
  44 import java.nio.file.attribute.FileAttribute;
  45 import java.nio.file.attribute.FileTime;
  46 import java.nio.file.attribute.GroupPrincipal;
  47 import java.nio.file.attribute.PosixFilePermission;
  48 import java.nio.file.attribute.UserPrincipal;
  49 import java.nio.file.attribute.UserPrincipalLookupService;
  50 import java.nio.file.spi.FileSystemProvider;
  51 import java.security.AccessController;
  52 import java.security.PrivilegedAction;
  53 import java.security.PrivilegedActionException;
  54 import java.security.PrivilegedExceptionAction;
  55 import java.util.*;
  56 import java.util.concurrent.locks.ReadWriteLock;
  57 import java.util.concurrent.locks.ReentrantReadWriteLock;
  58 import java.util.regex.Pattern;
  59 import java.util.zip.CRC32;
  60 import java.util.zip.Deflater;
  61 import java.util.zip.DeflaterOutputStream;
  62 import java.util.zip.Inflater;
  63 import java.util.zip.InflaterInputStream;
  64 import java.util.zip.ZipException;
  65 
  66 import static java.lang.Boolean.TRUE;
  67 import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES;
  68 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;


 357             if (getInode(path) == null) {
 358                 throw new NoSuchFileException(toString());
 359             }
 360 
 361         } finally {
 362             endRead();
 363         }
 364     }
 365 
 366     void setTimes(byte[] path, FileTime mtime, FileTime atime, FileTime ctime)
 367         throws IOException
 368     {
 369         checkWritable();
 370         beginWrite();
 371         try {
 372             ensureOpen();
 373             Entry e = getEntry(path);    // ensureOpen checked
 374             if (e == null)
 375                 throw new NoSuchFileException(getString(path));
 376             if (e.type == Entry.CEN)
 377                 e.type = Entry.COPY;     // copy e
 378             if (mtime != null)
 379                 e.mtime = mtime.toMillis();
 380             if (atime != null)
 381                 e.atime = atime.toMillis();
 382             if (ctime != null)
 383                 e.ctime = ctime.toMillis();
 384             update(e);
 385         } finally {
 386             endWrite();
 387         }
 388     }
 389 
 390     void setPermissions(byte[] path, Set<PosixFilePermission> perms)
 391         throws IOException
 392     {
 393         checkWritable();
 394         beginWrite();
 395         try {
 396             ensureOpen();
 397             Entry e = getEntry(path);    // ensureOpen checked
 398             if (e == null) {
 399                 throw new NoSuchFileException(getString(path));
 400             }
 401             if (e.type == Entry.CEN) {
 402                 e.type = Entry.COPY;     // copy e
 403             }
 404             e.posixPerms = perms == null ? -1 : ZipUtils.permsToFlags(perms);
 405             update(e);
 406         } finally {
 407             endWrite();
 408         }
 409     }
 410 
 411     boolean exists(byte[] path)
 412         throws IOException
 413     {
 414         beginRead();
 415         try {
 416             ensureOpen();
 417             return getInode(path) != null;
 418         } finally {
 419             endRead();
 420         }
 421     }
 422 
 423     boolean isDirectory(byte[] path)
 424         throws IOException
 425     {
 426         beginRead();
 427         try {
 428             IndexNode n = getInode(path);
 429             return n != null && n.isDir();
 430         } finally {


 461                     list.add(zpath);
 462                 child = child.sibling;
 463             }
 464             return list.iterator();
 465         } finally {
 466             endWrite();
 467         }
 468     }
 469 
 470     void createDirectory(byte[] dir, FileAttribute<?>... attrs)
 471         throws IOException
 472     {
 473         checkWritable();
 474         //  dir = toDirectoryPath(dir);
 475         beginWrite();
 476         try {
 477             ensureOpen();
 478             if (dir.length == 0 || exists(dir))  // root dir, or exiting dir
 479                 throw new FileAlreadyExistsException(getString(dir));
 480             checkParents(dir);
 481             Entry e = new Entry(dir, Entry.NEW, true, METHOD_STORED, attrs);
 482             update(e);
 483         } finally {
 484             endWrite();
 485         }
 486     }
 487 
 488     void copyFile(boolean deletesrc, byte[]src, byte[] dst, CopyOption... options)
 489         throws IOException
 490     {
 491         checkWritable();
 492         if (Arrays.equals(src, dst))
 493             return;    // do nothing, src and dst are the same
 494 
 495         beginWrite();
 496         try {
 497             ensureOpen();
 498             Entry eSrc = getEntry(src);  // ensureOpen checked
 499 
 500             if (eSrc == null)
 501                 throw new NoSuchFileException(getString(src));


 683                     SeekableByteChannel sbc =
 684                             new EntryOutputChannel(new Entry(e, Entry.NEW));
 685                     if (options.contains(APPEND)) {
 686                         try (InputStream is = getInputStream(e)) {  // copyover
 687                             byte[] buf = new byte[8192];
 688                             ByteBuffer bb = ByteBuffer.wrap(buf);
 689                             int n;
 690                             while ((n = is.read(buf)) != -1) {
 691                                 bb.position(0);
 692                                 bb.limit(n);
 693                                 sbc.write(bb);
 694                             }
 695                         }
 696                     }
 697                     return sbc;
 698                 }
 699                 if (!options.contains(CREATE) && !options.contains(CREATE_NEW))
 700                     throw new NoSuchFileException(getString(path));
 701                 checkParents(path);
 702                 return new EntryOutputChannel(
 703                     new Entry(path, Entry.NEW, false, getCompressMethod(attrs), attrs));
 704 
 705             } finally {
 706                 endRead();
 707             }
 708         } else {
 709             beginRead();
 710             try {
 711                 ensureOpen();
 712                 Entry e = getEntry(path);
 713                 if (e == null || e.isDir())
 714                     throw new NoSuchFileException(getString(path));
 715                 try (InputStream is = getInputStream(e)) {
 716                     // TBD: if (e.size < NNNNN);
 717                     return new ByteArrayChannel(is.readAllBytes(), true);
 718                 }
 719             } finally {
 720                 endRead();
 721             }
 722         }
 723     }


 748                     }
 749                 } else {
 750                     if (options.contains(StandardOpenOption.CREATE_NEW)) {
 751                         throw new FileAlreadyExistsException(getString(path));
 752                     }
 753                     if (e.isDir())
 754                         throw new FileAlreadyExistsException("directory <"
 755                             + getString(path) + "> exists");
 756                 }
 757                 options = new HashSet<>(options);
 758                 options.remove(StandardOpenOption.CREATE_NEW); // for tmpfile
 759             } else if (e == null || e.isDir()) {
 760                 throw new NoSuchFileException(getString(path));
 761             }
 762 
 763             final boolean isFCH = (e != null && e.type == Entry.FILECH);
 764             final Path tmpfile = isFCH ? e.file : getTempPathForEntry(path);
 765             final FileChannel fch = tmpfile.getFileSystem()
 766                                            .provider()
 767                                            .newFileChannel(tmpfile, options, attrs);
 768             final Entry u = isFCH ? e : new Entry(path, tmpfile, Entry.FILECH, attrs);
 769             if (forWrite) {
 770                 u.flag = FLAG_DATADESCR;
 771                 u.method = getCompressMethod(attrs);
 772             }
 773             // is there a better way to hook into the FileChannel's close method?
 774             return new FileChannel() {
 775                 public int write(ByteBuffer src) throws IOException {
 776                     return fch.write(src);
 777                 }
 778                 public long write(ByteBuffer[] srcs, int offset, int length)
 779                     throws IOException
 780                 {
 781                     return fch.write(srcs, offset, length);
 782                 }
 783                 public long position() throws IOException {
 784                     return fch.position();
 785                 }
 786                 public FileChannel position(long newPosition)
 787                     throws IOException
 788                 {


1877 
1878         IndexNode() {}
1879         IndexNode sibling;
1880         IndexNode child;  // 1st child
1881     }
1882 
1883     static class Entry extends IndexNode implements ZipFileAttributes {
1884 
1885         static final int CEN    = 1;  // entry read from cen
1886         static final int NEW    = 2;  // updated contents in bytes or file
1887         static final int FILECH = 3;  // fch update in "file"
1888         static final int COPY   = 4;  // copy of a CEN entry
1889 
1890         byte[] bytes;                 // updated content bytes
1891         Path   file;                  // use tmp file to store bytes;
1892         int    type = CEN;            // default is the entry read from cen
1893 
1894         // entry attributes
1895         int    version;
1896         int    flag;
1897         int    posixPerms = -1; // posix permissions
1898         int    method = -1;    // compression method
1899         long   mtime  = -1;    // last modification time (in DOS time)
1900         long   atime  = -1;    // last access time
1901         long   ctime  = -1;    // create time
1902         long   crc    = -1;    // crc-32 of entry data
1903         long   csize  = -1;    // compressed size of entry data
1904         long   size   = -1;    // uncompressed size of entry data
1905         byte[] extra;
1906 
1907         // cen
1908 
1909         // these fields are not used by anyone and writeCEN uses "0"
1910         // int    versionMade;
1911         // int    disk;
1912         // int    attrs;
1913         // long   attrsEx;
1914         long   locoff;
1915         byte[] comment;
1916 
1917         Entry() {}
1918 
1919         Entry(byte[] name, boolean isdir, int method) {
1920             name(name);
1921             this.isdir = isdir;
1922             this.mtime  = this.ctime = this.atime = System.currentTimeMillis();
1923             this.crc    = 0;
1924             this.size   = 0;
1925             this.csize  = 0;
1926             this.method = method;
1927         }
1928 
1929         @SuppressWarnings("unchecked")
1930         Entry(byte[] name, int type, boolean isdir, int method, FileAttribute<?>... attrs) {
1931             this(name, isdir, method);
1932             this.type = type;
1933             for (FileAttribute<?> attr : attrs) {
1934                 String attrName = attr.name();
1935                 if (attrName.equals("posix:permissions") || attrName.equals("unix:permissions")) {
1936                     posixPerms = ZipUtils.permsToFlags((Set<PosixFilePermission>)attr.value());
1937                 }
1938             }
1939         }
1940 
1941         Entry(Entry e, int type) {
1942             name(e.name);
1943             this.isdir     = e.isdir;
1944             this.version   = e.version;
1945             this.ctime     = e.ctime;
1946             this.atime     = e.atime;
1947             this.mtime     = e.mtime;
1948             this.crc       = e.crc;
1949             this.size      = e.size;
1950             this.csize     = e.csize;
1951             this.method    = e.method;
1952             this.extra     = e.extra;
1953             /*
1954             this.versionMade = e.versionMade;
1955             this.disk      = e.disk;
1956             this.attrs     = e.attrs;
1957             this.attrsEx   = e.attrsEx;
1958             */
1959             this.locoff    = e.locoff;
1960             this.comment   = e.comment;
1961             this.posixPerms = e.posixPerms;
1962             this.type      = type;
1963         }
1964 
1965         @SuppressWarnings("unchecked")
1966         Entry(byte[] name, Path file, int type, FileAttribute<?>... attrs) {
1967             this(name, type, false, METHOD_STORED);
1968             this.file = file;
1969             for (FileAttribute<?> attr : attrs) {
1970                 String attrName = attr.name();
1971                 if (attrName.equals("posix:permissions") || attrName.equals("unix:permissions")) {
1972                     posixPerms = ZipUtils.permsToFlags((Set<PosixFilePermission>)attr.value());
1973                 }
1974             }
1975         }
1976 
1977         int version(boolean zip64) throws ZipException {
1978             if (zip64) {
1979                 return 45;
1980             }
1981             if (method == METHOD_DEFLATED)
1982                 return 20;
1983             else if (method == METHOD_STORED)
1984                 return 10;
1985             throw new ZipException("unsupported compression method");
1986         }
1987 
1988         /**
1989          * Adds information about compatibility of file attribute information
1990          * to a version value.
1991          */
1992         int versionMadeBy(int version) {
1993             return (posixPerms < 0) ? version :
1994                 VERSION_BASE_UNIX | (version & 0xff);
1995         }
1996 
1997         ///////////////////// CEN //////////////////////
1998         static Entry readCEN(ZipFileSystem zipfs, IndexNode inode)
1999             throws IOException
2000         {
2001             return new Entry().cen(zipfs, inode);
2002         }
2003 
2004         private Entry cen(ZipFileSystem zipfs, IndexNode inode)
2005             throws IOException
2006         {
2007             byte[] cen = zipfs.cen;
2008             int pos = inode.pos;
2009             if (!cenSigAt(cen, pos))
2010                 zerror("invalid CEN header (bad signature)");
2011             version     = CENVER(cen, pos);
2012             flag        = CENFLG(cen, pos);
2013             method      = CENHOW(cen, pos);
2014             mtime       = dosToJavaTime(CENTIM(cen, pos));
2015             crc         = CENCRC(cen, pos);
2016             csize       = CENSIZ(cen, pos);
2017             size        = CENLEN(cen, pos);
2018             int nlen    = CENNAM(cen, pos);
2019             int elen    = CENEXT(cen, pos);
2020             int clen    = CENCOM(cen, pos);
2021             /*
2022             versionMade = CENVEM(cen, pos);
2023             disk        = CENDSK(cen, pos);
2024             attrs       = CENATT(cen, pos);
2025             attrsEx     = CENATX(cen, pos);
2026             */
2027             if (CENVEM_FA(cen, pos) == FILE_ATTRIBUTES_UNIX) {
2028                 posixPerms = CENATX_PERMS(cen, pos) & 0xFFF; // 12 bits for setuid, setgid, sticky + perms
2029             }
2030             locoff      = CENOFF(cen, pos);
2031             pos += CENHDR;
2032             this.name = inode.name;
2033             this.isdir = inode.isdir;
2034             this.hashcode = inode.hashcode;
2035 
2036             pos += nlen;
2037             if (elen > 0) {
2038                 extra = Arrays.copyOfRange(cen, pos, pos + elen);
2039                 pos += elen;
2040                 readExtra(zipfs);
2041             }
2042             if (clen > 0) {
2043                 comment = Arrays.copyOfRange(cen, pos, pos + clen);
2044             }
2045             return this;
2046         }
2047 
2048         int writeCEN(OutputStream os) throws IOException {

2049             long csize0  = csize;
2050             long size0   = size;
2051             long locoff0 = locoff;
2052             int elen64   = 0;                // extra for ZIP64
2053             int elenNTFS = 0;                // extra for NTFS (a/c/mtime)
2054             int elenEXTT = 0;                // extra for Extended Timestamp
2055             boolean foundExtraTime = false;  // if time stamp NTFS, EXTT present
2056 
2057             byte[] zname = isdir ? toDirectoryPath(name) : name;
2058 
2059             // confirm size/length
2060             int nlen = (zname != null) ? zname.length - 1 : 0;  // name has [0] as "slash"
2061             int elen = (extra != null) ? extra.length : 0;
2062             int eoff = 0;
2063             int clen = (comment != null) ? comment.length : 0;
2064             if (csize >= ZIP64_MINVAL) {
2065                 csize0 = ZIP64_MINVAL;
2066                 elen64 += 8;                 // csize(8)
2067             }
2068             if (size >= ZIP64_MINVAL) {
2069                 size0 = ZIP64_MINVAL;        // size(8)
2070                 elen64 += 8;
2071             }
2072             if (locoff >= ZIP64_MINVAL) {
2073                 locoff0 = ZIP64_MINVAL;
2074                 elen64 += 8;                 // offset(8)
2075             }
2076             if (elen64 != 0) {
2077                 elen64 += 4;                 // header and data sz 4 bytes
2078             }
2079             boolean zip64 = (elen64 != 0);
2080             int version0 = version(zip64);
2081             while (eoff + 4 < elen) {
2082                 int tag = SH(extra, eoff);
2083                 int sz = SH(extra, eoff + 2);
2084                 if (tag == EXTID_EXTT || tag == EXTID_NTFS) {
2085                     foundExtraTime = true;
2086                 }
2087                 eoff += (4 + sz);
2088             }
2089             if (!foundExtraTime) {
2090                 if (isWindows) {             // use NTFS
2091                     elenNTFS = 36;           // total 36 bytes
2092                 } else {                     // Extended Timestamp otherwise
2093                     elenEXTT = 9;            // only mtime in cen
2094                 }
2095             }
2096             writeInt(os, CENSIG);            // CEN header signature
2097             writeShort(os, versionMadeBy(version0)); // version made by
2098             writeShort(os, version0);        // version needed to extract





2099             writeShort(os, flag);            // general purpose bit flag
2100             writeShort(os, method);          // compression method
2101                                              // last modification time
2102             writeInt(os, (int)javaToDosTime(mtime));
2103             writeInt(os, crc);               // crc-32
2104             writeInt(os, csize0);            // compressed size
2105             writeInt(os, size0);             // uncompressed size
2106             writeShort(os, nlen);
2107             writeShort(os, elen + elen64 + elenNTFS + elenEXTT);
2108 
2109             if (comment != null) {
2110                 writeShort(os, Math.min(clen, 0xffff));
2111             } else {
2112                 writeShort(os, 0);
2113             }
2114             writeShort(os, 0);              // starting disk number
2115             writeShort(os, 0);              // internal file attributes (unused)
2116             writeInt(os, posixPerms > 0 ? posixPerms << 16 : 0); // external file
2117                                             // attributes, used for storing posix
2118                                             // permissions
2119             writeInt(os, locoff0);          // relative offset of local header
2120             writeBytes(os, zname, 1, nlen);
2121             if (zip64) {
2122                 writeShort(os, EXTID_ZIP64);// Zip64 extra
2123                 writeShort(os, elen64 - 4); // size of "this" extra block
2124                 if (size0 == ZIP64_MINVAL)
2125                     writeLong(os, size);
2126                 if (csize0 == ZIP64_MINVAL)
2127                     writeLong(os, csize);
2128                 if (locoff0 == ZIP64_MINVAL)
2129                     writeLong(os, locoff);
2130             }
2131             if (elenNTFS != 0) {
2132                 writeShort(os, EXTID_NTFS);
2133                 writeShort(os, elenNTFS - 4);
2134                 writeInt(os, 0);            // reserved
2135                 writeShort(os, 0x0001);     // NTFS attr tag
2136                 writeShort(os, 24);
2137                 writeLong(os, javaToWinTime(mtime));
2138                 writeLong(os, javaToWinTime(atime));
2139                 writeLong(os, javaToWinTime(ctime));
2140             }
2141             if (elenEXTT != 0) {
2142                 writeShort(os, EXTID_EXTT);
2143                 writeShort(os, elenEXTT - 4);
2144                 if (ctime == -1)
2145                     os.write(0x3);          // mtime and atime
2146                 else
2147                     os.write(0x7);          // mtime, atime and ctime
2148                 writeInt(os, javaToUnixTime(mtime));
2149             }
2150             if (extra != null)              // whatever not recognized
2151                 writeBytes(os, extra);
2152             if (comment != null)            //TBD: 0, Math.min(commentBytes.length, 0xffff));
2153                 writeBytes(os, comment);
2154             return CENHDR + nlen + elen + clen + elen64 + elenNTFS + elenEXTT;
2155         }
2156 
2157         ///////////////////// LOC //////////////////////
2158 
2159         int writeLOC(OutputStream os) throws IOException {

2160             byte[] zname = isdir ? toDirectoryPath(name) : name;
2161             int nlen = (zname != null) ? zname.length - 1 : 0; // [0] is slash
2162             int elen = (extra != null) ? extra.length : 0;
2163             boolean foundExtraTime = false;     // if extra timestamp present
2164             int eoff = 0;
2165             int elen64 = 0;
2166             boolean zip64 = false;
2167             int elenEXTT = 0;
2168             int elenNTFS = 0;
2169             writeInt(os, LOCSIG);               // LOC header signature
2170             if ((flag & FLAG_DATADESCR) != 0) {
2171                 writeShort(os, version(zip64)); // version needed to extract
2172                 writeShort(os, flag);           // general purpose bit flag
2173                 writeShort(os, method);         // compression method
2174                 // last modification time
2175                 writeInt(os, (int)javaToDosTime(mtime));
2176                 // store size, uncompressed size, and crc-32 in data descriptor
2177                 // immediately following compressed entry data
2178                 writeInt(os, 0);
2179                 writeInt(os, 0);
2180                 writeInt(os, 0);
2181             } else {
2182                 if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) {
2183                     elen64 = 20;    //headid(2) + size(2) + size(8) + csize(8)
2184                     zip64 = true;


2185                 }
2186                 writeShort(os, version(zip64)); // version needed to extract
2187                 writeShort(os, flag);           // general purpose bit flag
2188                 writeShort(os, method);         // compression method
2189                                                 // last modification time
2190                 writeInt(os, (int)javaToDosTime(mtime));
2191                 writeInt(os, crc);              // crc-32
2192                 if (zip64) {
2193                     writeInt(os, ZIP64_MINVAL);
2194                     writeInt(os, ZIP64_MINVAL);
2195                 } else {
2196                     writeInt(os, csize);        // compressed size
2197                     writeInt(os, size);         // uncompressed size
2198                 }
2199             }
2200             while (eoff + 4 < elen) {
2201                 int tag = SH(extra, eoff);
2202                 int sz = SH(extra, eoff + 2);
2203                 if (tag == EXTID_EXTT || tag == EXTID_NTFS) {
2204                     foundExtraTime = true;
2205                 }
2206                 eoff += (4 + sz);
2207             }
2208             if (!foundExtraTime) {
2209                 if (isWindows) {
2210                     elenNTFS = 36;              // NTFS, total 36 bytes
2211                 } else {                        // on unix use "ext time"
2212                     elenEXTT = 9;
2213                     if (atime != -1)
2214                         elenEXTT += 4;
2215                     if (ctime != -1)
2216                         elenEXTT += 4;
2217                 }
2218             }
2219             writeShort(os, nlen);
2220             writeShort(os, elen + elen64 + elenNTFS + elenEXTT);
2221             writeBytes(os, zname, 1, nlen);
2222             if (zip64) {
2223                 writeShort(os, EXTID_ZIP64);
2224                 writeShort(os, 16);
2225                 writeLong(os, size);
2226                 writeLong(os, csize);
2227             }
2228             if (elenNTFS != 0) {
2229                 writeShort(os, EXTID_NTFS);
2230                 writeShort(os, elenNTFS - 4);
2231                 writeInt(os, 0);            // reserved
2232                 writeShort(os, 0x0001);     // NTFS attr tag
2233                 writeShort(os, 24);
2234                 writeLong(os, javaToWinTime(mtime));
2235                 writeLong(os, javaToWinTime(atime));
2236                 writeLong(os, javaToWinTime(ctime));
2237             }
2238             if (elenEXTT != 0) {
2239                 writeShort(os, EXTID_EXTT);
2240                 writeShort(os, elenEXTT - 4);// size for the folowing data block
2241                 int fbyte = 0x1;
2242                 if (atime != -1)           // mtime and atime
2243                     fbyte |= 0x2;
2244                 if (ctime != -1)           // mtime, atime and ctime
2245                     fbyte |= 0x4;
2246                 os.write(fbyte);           // flags byte
2247                 writeInt(os, javaToUnixTime(mtime));
2248                 if (atime != -1)
2249                     writeInt(os, javaToUnixTime(atime));
2250                 if (ctime != -1)
2251                     writeInt(os, javaToUnixTime(ctime));
2252             }
2253             if (extra != null) {
2254                 writeBytes(os, extra);
2255             }
2256             return LOCHDR + nlen + elen + elen64 + elenNTFS + elenEXTT;
2257         }
2258 
2259         // Data Descriptor
2260         int writeEXT(OutputStream os) throws IOException {
2261             writeInt(os, EXTSIG);           // EXT header signature
2262             writeInt(os, crc);              // crc-32
2263             if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) {
2264                 writeLong(os, csize);
2265                 writeLong(os, size);
2266                 return 24;
2267             } else {
2268                 writeInt(os, csize);        // compressed size
2269                 writeInt(os, size);         // uncompressed size
2270                 return 16;
2271             }
2272         }
2273 
2274         // read NTFS, UNIX and ZIP64 data from cen.extra
2275         void readExtra(ZipFileSystem zipfs) throws IOException {
2276             if (extra == null)
2277                 return;
2278             int elen = extra.length;
2279             int off = 0;


2414         @Override
2415         public FileTime lastModifiedTime() {
2416             return FileTime.fromMillis(mtime);
2417         }
2418 
2419         @Override
2420         public long size() {
2421             return size;
2422         }
2423 
2424         @Override
2425         public boolean isSymbolicLink() {
2426             return false;
2427         }
2428 
2429         @Override
2430         public Object fileKey() {
2431             return null;
2432         }
2433 
2434         ///////// posix file attributes ///////////
2435 
2436         @Override
2437         public UserPrincipal owner() {
2438             throw new UnsupportedOperationException(
2439                 "ZipFileSystem does not support owner.");
2440         }
2441 
2442         @Override
2443         public GroupPrincipal group() {
2444             throw new UnsupportedOperationException(
2445                 "ZipFileSystem does not support group.");
2446         }
2447 
2448         @Override
2449         public Set<PosixFilePermission> permissions() {
2450             if (posixPerms == -1) {
2451                 // in case there are no Posix permissions associated with the
2452                 // entry, we should not return an empty set of permissions
2453                 // because that would be an explicit set of permissions meaning
2454                 // no permissions for anyone
2455                 throw new UnsupportedOperationException(
2456                     "No posix permissions associated with zip entry.");
2457             }
2458             return ZipUtils.permsFromFlags(posixPerms);
2459         }
2460 
2461         ///////// zip file attributes ///////////
2462 
2463         @Override
2464         public long compressedSize() {
2465             return csize;
2466         }
2467 
2468         @Override
2469         public long crc() {
2470             return crc;
2471         }
2472 
2473         @Override
2474         public int method() {
2475             return method;
2476         }
2477 
2478         @Override
2479         public byte[] extra() {
2480             if (extra != null)
2481                 return Arrays.copyOf(extra, extra.length);
2482             return null;
2483         }
2484 
2485         @Override
2486         public byte[] comment() {
2487             if (comment != null)
2488                 return Arrays.copyOf(comment, comment.length);
2489             return null;
2490         }
2491 
2492         @Override
2493         public String toString() {
2494             StringBuilder sb = new StringBuilder(1024);
2495             Formatter fm = new Formatter(sb);
2496             fm.format("    name            : %s%n", new String(name));
2497             fm.format("    creationTime    : %tc%n", creationTime().toMillis());
2498             fm.format("    lastAccessTime  : %tc%n", lastAccessTime().toMillis());
2499             fm.format("    lastModifiedTime: %tc%n", lastModifiedTime().toMillis());
2500             fm.format("    isRegularFile   : %b%n", isRegularFile());
2501             fm.format("    isDirectory     : %b%n", isDirectory());
2502             fm.format("    isSymbolicLink  : %b%n", isSymbolicLink());
2503             fm.format("    isOther         : %b%n", isOther());
2504             fm.format("    fileKey         : %s%n", fileKey());
2505             fm.format("    size            : %d%n", size());
2506             fm.format("    compressedSize  : %d%n", compressedSize());
2507             fm.format("    crc             : %x%n", crc());
2508             fm.format("    method          : %d%n", method());
2509             if (posixPerms != -1) {
2510                 fm.format("    permissions     : %s%n", permissions());
2511             }
2512             fm.close();
2513             return sb.toString();
2514         }
2515     }
2516 
2517     // ZIP directory has two issues:
2518     // (1) ZIP spec does not require the ZIP file to include
2519     //     directory entry
2520     // (2) all entries are not stored/organized in a "tree"
2521     //     structure.
2522     // A possible solution is to build the node tree ourself as
2523     // implemented below.
2524 
2525     // default time stamp for pseudo entries
2526     private long zfsDefaultTimeStamp = System.currentTimeMillis();
2527 
2528     private void removeFromTree(IndexNode inode) {
2529         IndexNode parent = inodes.get(LOOKUPKEY.as(getParent(inode.name)));
2530         IndexNode child = parent.child;
2531         if (child.equals(inode)) {


< prev index next >