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

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 2009, 2015, 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 --- 1,7 ---- /* ! * Copyright (c) 2009, 2017, 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
*** 312,322 **** e = getEntry(path); if (e == null) { IndexNode inode = getInode(path); if (inode == null) return null; ! e = new Entry(inode.name); // pseudo directory e.method = METHOD_STORED; // STORED for dir e.mtime = e.atime = e.ctime = zfsDefaultTimeStamp; } } finally { endRead(); --- 312,322 ---- e = getEntry(path); if (e == null) { IndexNode inode = getInode(path); if (inode == null) return null; ! e = new Entry(inode.name, inode.isdir); // pseudo directory e.method = METHOD_STORED; // STORED for dir e.mtime = e.atime = e.ctime = zfsDefaultTimeStamp; } } finally { endRead();
*** 398,408 **** if (inode == null) throw new NotDirectoryException(getString(path)); List<Path> list = new ArrayList<>(); IndexNode child = inode.child; while (child != null) { ! ZipPath zp = new ZipPath(this, child.name); if (filter == null || filter.accept(zp)) list.add(zp); child = child.sibling; } return list.iterator(); --- 398,409 ---- if (inode == null) throw new NotDirectoryException(getString(path)); List<Path> list = new ArrayList<>(); IndexNode child = inode.child; while (child != null) { ! // assume all path from zip file itself is "normalized" ! ZipPath zp = new ZipPath(this, child.name, true); if (filter == null || filter.accept(zp)) list.add(zp); child = child.sibling; } return list.iterator();
*** 413,430 **** void createDirectory(byte[] dir, FileAttribute<?>... attrs) throws IOException { checkWritable(); ! dir = toDirectoryPath(dir); beginWrite(); try { ensureOpen(); if (dir.length == 0 || exists(dir)) // root dir, or exiting dir throw new FileAlreadyExistsException(getString(dir)); checkParents(dir); ! Entry e = new Entry(dir, Entry.NEW); e.method = METHOD_STORED; // STORED for dir update(e); } finally { endWrite(); } --- 414,431 ---- void createDirectory(byte[] dir, FileAttribute<?>... attrs) throws IOException { checkWritable(); ! // dir = toDirectoryPath(dir); beginWrite(); try { ensureOpen(); if (dir.length == 0 || exists(dir)) // root dir, or exiting dir throw new FileAlreadyExistsException(getString(dir)); checkParents(dir); ! Entry e = new Entry(dir, Entry.NEW, true); e.method = METHOD_STORED; // STORED for dir update(e); } finally { endWrite(); }
*** 531,541 **** return getOutputStream(new Entry(e, Entry.NEW)); } else { if (!hasCreate && !hasCreateNew) throw new NoSuchFileException(getString(path)); checkParents(path); ! return getOutputStream(new Entry(path, Entry.NEW)); } } finally { endRead(); } } --- 532,542 ---- return getOutputStream(new Entry(e, Entry.NEW)); } else { if (!hasCreate && !hasCreateNew) throw new NoSuchFileException(getString(path)); checkParents(path); ! return getOutputStream(new Entry(path, Entry.NEW, false)); } } finally { endRead(); } }
*** 885,895 **** private static byte[] ROOTPATH = new byte[] { '/' }; private static byte[] getParent(byte[] path) { int off = getParentOff(path); if (off <= 1) return ROOTPATH; ! return Arrays.copyOf(path, off + 1); } private static int getParentOff(byte[] path) { int off = path.length - 1; if (off > 0 && path[off] == '/') // isDirectory --- 886,896 ---- private static byte[] ROOTPATH = new byte[] { '/' }; private static byte[] getParent(byte[] path) { int off = getParentOff(path); if (off <= 1) return ROOTPATH; ! return Arrays.copyOf(path, off); } private static int getParentOff(byte[] path) { int off = path.length - 1; if (off > 0 && path[off] == '/') // isDirectory
*** 1073,1087 **** zerror("invalid CEN header (unsupported compression method: " + method + ")"); } if (pos + CENHDR + nlen > limit) { zerror("invalid CEN header (bad header size)"); } ! byte[] name = new byte[nlen + 1]; ! System.arraycopy(cen, pos + CENHDR, name, 1, nlen); ! name[0] = '/'; ! IndexNode inode = new IndexNode(name, pos); inodes.put(inode, inode); // skip ext and comment pos += (CENHDR + nlen + elen + clen); } if (pos + ENDHDR != cen.length) { zerror("invalid CEN header (bad header size)"); --- 1074,1086 ---- zerror("invalid CEN header (unsupported compression method: " + method + ")"); } if (pos + CENHDR + nlen > limit) { zerror("invalid CEN header (bad header size)"); } ! IndexNode inode = new IndexNode(cen, pos + CENHDR, nlen, pos); inodes.put(inode, inode); + // skip ext and comment pos += (CENHDR + nlen + elen + clen); } if (pos + ENDHDR != cen.length) { zerror("invalid CEN header (bad header size)");
*** 1110,1120 **** ////////////////////update & sync ////////////////////////////////////// private boolean hasUpdate = false; // shared key. consumer guarantees the "writeLock" before use it. ! private final IndexNode LOOKUPKEY = IndexNode.keyOf(null); private void updateDelete(IndexNode inode) { beginWrite(); try { removeFromTree(inode); --- 1109,1119 ---- ////////////////////update & sync ////////////////////////////////////// private boolean hasUpdate = false; // shared key. consumer guarantees the "writeLock" before use it. ! private final IndexNode LOOKUPKEY = new IndexNode(null, -1); private void updateDelete(IndexNode inode) { beginWrite(); try { removeFromTree(inode);
*** 1310,1329 **** } IndexNode getInode(byte[] path) { if (path == null) throw new NullPointerException("path"); ! IndexNode key = IndexNode.keyOf(path); ! IndexNode inode = inodes.get(key); ! if (inode == null && ! (path.length == 0 || path[path.length -1] != '/')) { ! // if does not ends with a slash ! path = Arrays.copyOf(path, path.length + 1); ! path[path.length - 1] = '/'; ! inode = inodes.get(key.as(path)); ! } ! return inode; } Entry getEntry(byte[] path) throws IOException { IndexNode inode = getInode(path); if (inode instanceof Entry) --- 1309,1319 ---- } IndexNode getInode(byte[] path) { if (path == null) throw new NullPointerException("path"); ! return inodes.get(IndexNode.keyOf(path)); } Entry getEntry(byte[] path) throws IOException { IndexNode inode = getInode(path); if (inode instanceof Entry)
*** 1780,1801 **** static class IndexNode { byte[] name; int hashcode; // node is hashable/hashed by its name int pos = -1; // position in cen table, -1 menas the // entry does not exists in zip file ! IndexNode(byte[] name) { name(name); this.pos = -1; } IndexNode(byte[] name, int pos) { name(name); this.pos = pos; } final static IndexNode keyOf(byte[] name) { // get a lookup key; ! return new IndexNode(name, -1); } final void name(byte[] name) { this.name = name; this.hashcode = Arrays.hashCode(name); --- 1770,1814 ---- static class IndexNode { byte[] name; int hashcode; // node is hashable/hashed by its name int pos = -1; // position in cen table, -1 menas the // entry does not exists in zip file ! boolean isdir; ! ! IndexNode(byte[] name, boolean isdir) { name(name); + this.isdir = isdir; this.pos = -1; } IndexNode(byte[] name, int pos) { name(name); this.pos = pos; } + // constructor for cenInit() + IndexNode(byte[] cen, int noff, int nlen, int pos) { + if (cen[noff + nlen - 1] == '/') { + isdir = true; + nlen--; + } + name = new byte[nlen + 1]; + System.arraycopy(cen, pos + CENHDR, name, 1, nlen); + name[0] = '/'; + name(name); + this.pos = pos; + } + + private static final ThreadLocal<IndexNode> cachedKey = new ThreadLocal<>(); + final static IndexNode keyOf(byte[] name) { // get a lookup key; ! IndexNode key = cachedKey.get(); ! if (key == null) { ! key = new IndexNode(name, -1); ! cachedKey.set(key); ! } ! return key.as(name); } final void name(byte[] name) { this.name = name; this.hashcode = Arrays.hashCode(name);
*** 1805,1816 **** name(name); // as a lookup "key" return this; } boolean isDir() { ! return name != null && ! (name.length == 0 || name[name.length - 1] == '/'); } public boolean equals(Object other) { if (!(other instanceof IndexNode)) { return false; --- 1818,1828 ---- name(name); // as a lookup "key" return this; } boolean isDir() { ! return isdir; } public boolean equals(Object other) { if (!(other instanceof IndexNode)) { return false;
*** 1863,1888 **** long locoff; byte[] comment; Entry() {} ! Entry(byte[] name) { name(name); this.mtime = this.ctime = this.atime = System.currentTimeMillis(); this.crc = 0; this.size = 0; this.csize = 0; this.method = METHOD_DEFLATED; } ! Entry(byte[] name, int type) { ! this(name); this.type = type; } Entry (Entry e, int type) { name(e.name); this.version = e.version; this.ctime = e.ctime; this.atime = e.atime; this.mtime = e.mtime; this.crc = e.crc; --- 1875,1902 ---- long locoff; byte[] comment; Entry() {} ! Entry(byte[] name, boolean isdir) { name(name); + this.isdir = isdir; this.mtime = this.ctime = this.atime = System.currentTimeMillis(); this.crc = 0; this.size = 0; this.csize = 0; this.method = METHOD_DEFLATED; } ! Entry(byte[] name, int type, boolean isdir) { ! this(name, isdir); this.type = type; } Entry (Entry e, int type) { name(e.name); + this.isdir = e.isdir; this.version = e.version; this.ctime = e.ctime; this.atime = e.atime; this.mtime = e.mtime; this.crc = e.crc;
*** 1900,1910 **** this.comment = e.comment; this.type = type; } Entry (byte[] name, Path file, int type) { ! this(name, type); this.file = file; this.method = METHOD_STORED; } int version() throws ZipException { --- 1914,1924 ---- this.comment = e.comment; this.type = type; } Entry (byte[] name, Path file, int type) { ! this(name, type, false); this.file = file; this.method = METHOD_STORED; } int version() throws ZipException {
*** 1946,1955 **** --- 1960,1970 ---- attrsEx = CENATX(cen, pos); */ locoff = CENOFF(cen, pos); pos += CENHDR; this.name = inode.name; + this.isdir = inode.isdir; this.hashcode = inode.hashcode; pos += nlen; if (elen > 0) { extra = Arrays.copyOfRange(cen, pos, pos + elen);
*** 1972,1984 **** int elen64 = 0; // extra for ZIP64 int elenNTFS = 0; // extra for NTFS (a/c/mtime) int elenEXTT = 0; // extra for Extended Timestamp boolean foundExtraTime = false; // if time stamp NTFS, EXTT present ! // confirm size/length ! int nlen = (name != null) ? name.length - 1 : 0; // name has [0] as "slash" int elen = (extra != null) ? extra.length : 0; int eoff = 0; int clen = (comment != null) ? comment.length : 0; if (csize >= ZIP64_MINVAL) { csize0 = ZIP64_MINVAL; --- 1987,2000 ---- int elen64 = 0; // extra for ZIP64 int elenNTFS = 0; // extra for NTFS (a/c/mtime) int elenEXTT = 0; // extra for Extended Timestamp boolean foundExtraTime = false; // if time stamp NTFS, EXTT present ! byte[] zname = isdir ? toDirectoryPath(name) : name; ! // confirm size/length ! int nlen = (zname != null) ? zname.length - 1 : 0; // name has [0] as "slash" int elen = (extra != null) ? extra.length : 0; int eoff = 0; int clen = (comment != null) ? comment.length : 0; if (csize >= ZIP64_MINVAL) { csize0 = ZIP64_MINVAL;
*** 2035,2045 **** } writeShort(os, 0); // starting disk number writeShort(os, 0); // internal file attributes (unused) writeInt(os, 0); // external file attributes (unused) writeInt(os, locoff0); // relative offset of local header ! writeBytes(os, name, 1, nlen); if (elen64 != 0) { writeShort(os, EXTID_ZIP64);// Zip64 extra writeShort(os, elen64 - 4); // size of "this" extra block if (size0 == ZIP64_MINVAL) writeLong(os, size); --- 2051,2061 ---- } writeShort(os, 0); // starting disk number writeShort(os, 0); // internal file attributes (unused) writeInt(os, 0); // external file attributes (unused) writeInt(os, locoff0); // relative offset of local header ! writeBytes(os, zname, 1, nlen); if (elen64 != 0) { writeShort(os, EXTID_ZIP64);// Zip64 extra writeShort(os, elen64 - 4); // size of "this" extra block if (size0 == ZIP64_MINVAL) writeLong(os, size);
*** 2073,2163 **** writeBytes(os, comment); return CENHDR + nlen + elen + clen + elen64 + elenNTFS + elenEXTT; } ///////////////////// LOC ////////////////////// - static Entry readLOC(ZipFileSystem zipfs, long pos) - throws IOException - { - return readLOC(zipfs, pos, new byte[1024]); - } - - static Entry readLOC(ZipFileSystem zipfs, long pos, byte[] buf) - throws IOException - { - return new Entry().loc(zipfs, pos, buf); - } - - Entry loc(ZipFileSystem zipfs, long pos, byte[] buf) - throws IOException - { - assert (buf.length >= LOCHDR); - if (zipfs.readFullyAt(buf, 0, LOCHDR , pos) != LOCHDR) - throw new ZipException("loc: reading failed"); - if (!locSigAt(buf, 0)) - throw new ZipException("loc: wrong sig ->" - + Long.toString(getSig(buf, 0), 16)); - //startPos = pos; - version = LOCVER(buf); - flag = LOCFLG(buf); - method = LOCHOW(buf); - mtime = dosToJavaTime(LOCTIM(buf)); - crc = LOCCRC(buf); - csize = LOCSIZ(buf); - size = LOCLEN(buf); - int nlen = LOCNAM(buf); - int elen = LOCEXT(buf); - - name = new byte[nlen + 1]; - name[0] = '/'; - if (zipfs.readFullyAt(name, 1, nlen, pos + LOCHDR) != nlen) { - throw new ZipException("loc: name reading failed"); - } - if (elen > 0) { - extra = new byte[elen]; - if (zipfs.readFullyAt(extra, 0, elen, pos + LOCHDR + nlen) - != elen) { - throw new ZipException("loc: ext reading failed"); - } - } - pos += (LOCHDR + nlen + elen); - if ((flag & FLAG_DATADESCR) != 0) { - // Data Descriptor - Entry e = zipfs.getEntry(name); // get the size/csize from cen - if (e == null) - throw new ZipException("loc: name not found in cen"); - size = e.size; - csize = e.csize; - pos += (method == METHOD_STORED ? size : csize); - if (size >= ZIP64_MINVAL || csize >= ZIP64_MINVAL) - pos += 24; - else - pos += 16; - } else { - if (extra != null && - (size == ZIP64_MINVAL || csize == ZIP64_MINVAL)) { - // zip64 ext: must include both size and csize - int off = 0; - while (off + 20 < elen) { // HeaderID+DataSize+Data - int sz = SH(extra, off + 2); - if (SH(extra, off) == EXTID_ZIP64 && sz == 16) { - size = LL(extra, off + 4); - csize = LL(extra, off + 12); - break; - } - off += (sz + 4); - } - } - pos += (method == METHOD_STORED ? size : csize); - } - return this; - } int writeLOC(OutputStream os) throws IOException { writeInt(os, LOCSIG); // LOC header signature int version = version(); ! int nlen = (name != null) ? name.length - 1 : 0; // [0] is slash int elen = (extra != null) ? extra.length : 0; boolean foundExtraTime = false; // if extra timestamp present int eoff = 0; int elen64 = 0; int elenEXTT = 0; --- 2089,2105 ---- writeBytes(os, comment); return CENHDR + nlen + elen + clen + elen64 + elenNTFS + elenEXTT; } ///////////////////// LOC ////////////////////// int writeLOC(OutputStream os) throws IOException { writeInt(os, LOCSIG); // LOC header signature int version = version(); ! ! byte[] zname = isdir ? toDirectoryPath(name) : name; ! int nlen = (zname != null) ? zname.length - 1 : 0; // [0] is slash int elen = (extra != null) ? extra.length : 0; boolean foundExtraTime = false; // if extra timestamp present int eoff = 0; int elen64 = 0; int elenEXTT = 0;
*** 2212,2222 **** elenEXTT += 4; } } writeShort(os, nlen); writeShort(os, elen + elen64 + elenNTFS + elenEXTT); ! writeBytes(os, name, 1, nlen); if (elen64 != 0) { writeShort(os, EXTID_ZIP64); writeShort(os, 16); writeLong(os, size); writeLong(os, csize); --- 2154,2164 ---- elenEXTT += 4; } } writeShort(os, nlen); writeShort(os, elen + elen64 + elenNTFS + elenEXTT); ! writeBytes(os, zname, 1, nlen); if (elen64 != 0) { writeShort(os, EXTID_ZIP64); writeShort(os, 16); writeLong(os, size); writeLong(os, csize);
*** 2549,2559 **** } private void buildNodeTree() throws IOException { beginWrite(); try { ! IndexNode root = new IndexNode(ROOTPATH); IndexNode[] nodes = inodes.keySet().toArray(new IndexNode[0]); inodes.put(root, root); ParentLookup lookup = new ParentLookup(); for (IndexNode node : nodes) { IndexNode parent; --- 2491,2501 ---- } private void buildNodeTree() throws IOException { beginWrite(); try { ! IndexNode root = new IndexNode(ROOTPATH, true); IndexNode[] nodes = inodes.keySet().toArray(new IndexNode[0]); inodes.put(root, root); ParentLookup lookup = new ParentLookup(); for (IndexNode node : nodes) { IndexNode parent;
*** 2562,2580 **** if (off <= 1) { // parent is root node.sibling = root.child; root.child = node; break; } ! lookup = lookup.as(node.name, off + 1); if (inodes.containsKey(lookup)) { parent = inodes.get(lookup); node.sibling = parent.child; parent.child = node; break; } // add new pseudo directory entry ! parent = new IndexNode(Arrays.copyOf(node.name, off + 1)); inodes.put(parent, parent); node.sibling = parent.child; parent.child = node; node = parent; } --- 2504,2522 ---- if (off <= 1) { // parent is root node.sibling = root.child; root.child = node; break; } ! lookup = lookup.as(node.name, off); if (inodes.containsKey(lookup)) { parent = inodes.get(lookup); node.sibling = parent.child; parent.child = node; break; } // add new pseudo directory entry ! parent = new IndexNode(Arrays.copyOf(node.name, off), true); inodes.put(parent, parent); node.sibling = parent.child; parent.child = node; node = parent; }