< prev index next >

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

Print this page
rev 51534 : 8034802: (zipfs) newFileSystem throws UOE when the zip file is located in a custom file system
Reviewed-by: xiaofeya, clanger

*** 28,37 **** --- 28,38 ---- import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.File; + import java.io.FilterOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer;
*** 68,104 **** class ZipFileSystem extends FileSystem { private final ZipFileSystemProvider provider; private final Path zfpath; final ZipCoder zc; - private final boolean noExtt; // see readExtra() private final ZipPath rootdir; // configurable by env map private final boolean useTempFile; // use a temp file for newOS, default // is to use BAOS for better performance - private boolean readOnly = false; // readonly file system private static final boolean isWindows = AccessController.doPrivileged( (PrivilegedAction<Boolean>) () -> System.getProperty("os.name") .startsWith("Windows")); private final boolean forceEnd64; ZipFileSystem(ZipFileSystemProvider provider, Path zfpath, Map<String, ?> env) throws IOException { - // create a new zip if not exists - boolean createNew = "true".equals(env.get("create")); // default encoding for name/comment String nameEncoding = env.containsKey("encoding") ? (String)env.get("encoding") : "UTF-8"; this.noExtt = "false".equals(env.get("zipinfo-time")); ! this.useTempFile = TRUE.equals(env.get("useTempFile")); ! this.forceEnd64 = "true".equals(env.get("forceZIP64End")); ! this.provider = provider; ! this.zfpath = zfpath; if (Files.notExists(zfpath)) { ! if (createNew) { try (OutputStream os = Files.newOutputStream(zfpath, CREATE_NEW, WRITE)) { new END().write(os, 0, forceEnd64); } } else { throw new FileSystemNotFoundException(zfpath.toString()); --- 69,106 ---- class ZipFileSystem extends FileSystem { private final ZipFileSystemProvider provider; private final Path zfpath; final ZipCoder zc; private final ZipPath rootdir; + private boolean readOnly = false; // readonly file system + // configurable by env map + private final boolean noExtt; // see readExtra() private final boolean useTempFile; // use a temp file for newOS, default // is to use BAOS for better performance private static final boolean isWindows = AccessController.doPrivileged( (PrivilegedAction<Boolean>) () -> System.getProperty("os.name") .startsWith("Windows")); private final boolean forceEnd64; + private final int defaultMethod; // METHOD_STORED if "noCompression=true" + // METHOD_DEFLATED otherwise ZipFileSystem(ZipFileSystemProvider provider, Path zfpath, Map<String, ?> env) throws IOException { // default encoding for name/comment String nameEncoding = env.containsKey("encoding") ? (String)env.get("encoding") : "UTF-8"; this.noExtt = "false".equals(env.get("zipinfo-time")); ! this.useTempFile = isTrue(env, "useTempFile"); ! this.forceEnd64 = isTrue(env, "forceZIP64End"); ! this.defaultMethod = isTrue(env, "noCompression") ? METHOD_STORED: METHOD_DEFLATED; if (Files.notExists(zfpath)) { ! // create a new zip if not exists ! if (isTrue(env, "create")) { try (OutputStream os = Files.newOutputStream(zfpath, CREATE_NEW, WRITE)) { new END().write(os, 0, forceEnd64); } } else { throw new FileSystemNotFoundException(zfpath.toString());
*** 120,129 **** --- 122,138 ---- } catch (IOException xx) { x.addSuppressed(xx); } throw x; } + this.provider = provider; + this.zfpath = zfpath; + } + + // returns true if there is a name=true/"true" setting in env + private static boolean isTrue(Map<String, ?> env, String name) { + return "true".equals(env.get(name)) || TRUE.equals(env.get(name)); } @Override public FileSystemProvider provider() { return provider;
*** 267,277 **** try { AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> { sync(); return null; }); ch.close(); // close the ch just in case no update ! } catch (PrivilegedActionException e) { // and sync dose not close the ch throw (IOException)e.getException(); } finally { endWrite(); } --- 276,287 ---- try { AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> { sync(); return null; }); ch.close(); // close the ch just in case no update ! // and sync didn't close the ch ! } catch (PrivilegedActionException e) { throw (IOException)e.getException(); } finally { endWrite(); }
*** 314,325 **** 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(); } --- 324,335 ---- e = getEntry(path); if (e == null) { IndexNode inode = getInode(path); if (inode == null) return null; ! // pseudo directory, uses METHOD_STORED ! e = new Entry(inode.name, inode.isdir, METHOD_STORED); e.mtime = e.atime = e.ctime = zfsDefaultTimeStamp; } } finally { endRead(); }
*** 423,434 **** 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(); } } --- 433,443 ---- 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, METHOD_STORED); update(e); } finally { endWrite(); } }
*** 525,544 **** if (e.isDir() || hasCreateNew) throw new FileAlreadyExistsException(getString(path)); if (hasAppend) { InputStream is = getInputStream(e); OutputStream os = getOutputStream(new Entry(e, Entry.NEW)); ! copyStream(is, os); is.close(); return os; } 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(); } } --- 534,553 ---- if (e.isDir() || hasCreateNew) throw new FileAlreadyExistsException(getString(path)); if (hasAppend) { InputStream is = getInputStream(e); OutputStream os = getOutputStream(new Entry(e, Entry.NEW)); ! is.transferTo(os); is.close(); return os; } 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, defaultMethod)); } } finally { endRead(); } }
*** 570,579 **** --- 579,619 ---- } if (options.contains(APPEND) && options.contains(TRUNCATE_EXISTING)) throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed"); } + + // Returns an output SeekableByteChannel for either + // (1) writing the contents of a new entry, if the entry doesn't exit, or + // (2) updating/replacing the contents of an existing entry. + // Note: The content is not compressed. + private class EntryOutputChannel extends ByteArrayChannel { + Entry e; + + EntryOutputChannel(Entry e) throws IOException { + super(e.size > 0? (int)e.size : 8192, false); + this.e = e; + if (e.mtime == -1) + e.mtime = System.currentTimeMillis(); + if (e.method == -1) + e.method = defaultMethod; + // store size, compressed size, and crc-32 in datadescriptor + e.flag = FLAG_DATADESCR; + if (zc.isUTF8()) + e.flag |= FLAG_USE_UTF8; + } + + @Override + public void close() throws IOException { + e.bytes = toByteArray(); + e.size = e.bytes.length; + e.crc = -1; + super.close(); + update(e); + } + } + // Returns a Writable/ReadByteChannel for now. Might consdier to use // newFileChannel() instead, which dump the entry data into a regular // file on the default file system and create a FileChannel on top of // it. SeekableByteChannel newByteChannel(byte[] path,
*** 583,698 **** { checkOptions(options); if (options.contains(StandardOpenOption.WRITE) || options.contains(StandardOpenOption.APPEND)) { checkWritable(); ! beginRead(); try { ! final WritableByteChannel wbc = Channels.newChannel( ! newOutputStream(path, options.toArray(new OpenOption[0]))); ! long leftover = 0; ! if (options.contains(StandardOpenOption.APPEND)) { Entry e = getEntry(path); ! if (e != null && e.size >= 0) ! leftover = e.size; ! } ! final long offset = leftover; ! return new SeekableByteChannel() { ! long written = offset; ! public boolean isOpen() { ! return wbc.isOpen(); ! } ! ! public long position() throws IOException { ! return written; ! } ! ! public SeekableByteChannel position(long pos) ! throws IOException ! { ! throw new UnsupportedOperationException(); ! } ! ! public int read(ByteBuffer dst) throws IOException { ! throw new UnsupportedOperationException(); } - - public SeekableByteChannel truncate(long size) - throws IOException - { - throw new UnsupportedOperationException(); } - - public int write(ByteBuffer src) throws IOException { - int n = wbc.write(src); - written += n; - return n; } ! ! public long size() throws IOException { ! return written; } - public void close() throws IOException { - wbc.close(); - } - }; } finally { endRead(); } } else { beginRead(); try { ensureOpen(); Entry e = getEntry(path); if (e == null || e.isDir()) throw new NoSuchFileException(getString(path)); ! final ReadableByteChannel rbc = ! Channels.newChannel(getInputStream(e)); ! final long size = e.size; ! return new SeekableByteChannel() { ! long read = 0; ! public boolean isOpen() { ! return rbc.isOpen(); } - - public long position() throws IOException { - return read; - } - - public SeekableByteChannel position(long pos) - throws IOException - { - throw new UnsupportedOperationException(); - } - - public int read(ByteBuffer dst) throws IOException { - int n = rbc.read(dst); - if (n > 0) { - read += n; - } - return n; - } - - public SeekableByteChannel truncate(long size) - throws IOException - { - throw new NonWritableChannelException(); - } - - public int write (ByteBuffer src) throws IOException { - throw new NonWritableChannelException(); - } - - public long size() throws IOException { - return size; - } - - public void close() throws IOException { - rbc.close(); - } - }; } finally { endRead(); } } } --- 623,676 ---- { checkOptions(options); if (options.contains(StandardOpenOption.WRITE) || options.contains(StandardOpenOption.APPEND)) { checkWritable(); ! beginRead(); // only need a readlock, the "update()" will obtain ! // thewritelock when the channel is closed try { ! ensureOpen(); Entry e = getEntry(path); ! if (e != null) { ! if (e.isDir() || options.contains(CREATE_NEW)) ! throw new FileAlreadyExistsException(getString(path)); ! SeekableByteChannel sbc = ! new EntryOutputChannel(new Entry(e, Entry.NEW)); ! if (options.contains(APPEND)) { ! try (InputStream is = getInputStream(e)) { // copyover ! byte[] buf = new byte[8192]; ! ByteBuffer bb = ByteBuffer.wrap(buf); ! int n; ! while ((n = is.read(buf)) != -1) { ! bb.position(0); ! bb.limit(n); ! sbc.write(bb); } } } ! return sbc; } + if (!options.contains(CREATE) && !options.contains(CREATE_NEW)) + throw new NoSuchFileException(getString(path)); + checkParents(path); + return new EntryOutputChannel( + new Entry(path, Entry.NEW, false, defaultMethod)); } finally { endRead(); } } else { beginRead(); try { ensureOpen(); Entry e = getEntry(path); if (e == null || e.isDir()) throw new NoSuchFileException(getString(path)); ! try (InputStream is = getInputStream(e)) { ! // TBD: if (e.size < NNNNN); ! return new ByteArrayChannel(is.readAllBytes(), true); } } finally { endRead(); } } }
*** 844,857 **** // the outstanding input streams that need to be closed private Set<InputStream> streams = Collections.synchronizedSet(new HashSet<InputStream>()); - // the ex-channel and ex-path that need to close when their outstanding - // input streams are all closed by the obtainers. - private Set<ExChannelCloser> exChClosers = new HashSet<>(); - private Set<Path> tmppaths = Collections.synchronizedSet(new HashSet<Path>()); private Path getTempPathForEntry(byte[] path) throws IOException { Path tmpPath = createTempFileInSameDirectoryAs(zfpath); if (path != null) { Entry e = getEntry(path); --- 822,831 ----
*** 1085,1095 **** 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); } --- 1059,1069 ---- 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, pos, nlen); inodes.put(inode, inode); // skip ext and comment pos += (CENHDR + nlen + elen + clen); }
*** 1198,1220 **** locoff += n; } return written; } ! // sync the zip file system, if there is any udpate ! private void sync() throws IOException { ! // System.out.printf("->sync(%s) starting....!%n", toString()); ! // check ex-closer ! if (!exChClosers.isEmpty()) { ! for (ExChannelCloser ecc : exChClosers) { ! if (ecc.streams.isEmpty()) { ! ecc.ch.close(); ! Files.delete(ecc.path); ! exChClosers.remove(ecc); } } } if (!hasUpdate) return; Path tmpFile = createTempFileInSameDirectoryAs(zfpath); try (OutputStream os = new BufferedOutputStream(Files.newOutputStream(tmpFile, WRITE))) { --- 1172,1212 ---- locoff += n; } return written; } ! private long writeEntry(Entry e, OutputStream os, byte[] buf) ! throws IOException { ! ! if (e.bytes == null && e.file == null) // dir, 0-length data ! return 0; ! ! long written = 0; ! try (OutputStream os2 = e.method == METHOD_STORED ? ! new EntryOutputStreamCRC32(e, os) : new EntryOutputStreamDef(e, os)) { ! if (e.bytes != null) { // in-memory ! os2.write(e.bytes, 0, e.bytes.length); ! } else if (e.file != null) { // tmp file ! if (e.type == Entry.NEW || e.type == Entry.FILECH) { ! try (InputStream is = Files.newInputStream(e.file)) { ! is.transferTo(os2); ! } ! } ! Files.delete(e.file); ! tmppaths.remove(e.file); } } + written += e.csize; + if ((e.flag & FLAG_DATADESCR) != 0) { + written += e.writeEXT(os); + } + return written; } + + // sync the zip file system, if there is any udpate + private void sync() throws IOException { + if (!hasUpdate) return; Path tmpFile = createTempFileInSameDirectoryAs(zfpath); try (OutputStream os = new BufferedOutputStream(Files.newOutputStream(tmpFile, WRITE))) {
*** 1236,1273 **** // file LOC entry. written += copyLOCEntry(e, true, os, written, buf); } else { // NEW, FILECH or CEN e.locoff = written; written += e.writeLOC(os); // write loc header ! if (e.bytes != null) { // in-memory, deflated ! os.write(e.bytes); // already ! written += e.bytes.length; ! } else if (e.file != null) { // tmp file ! try (InputStream is = Files.newInputStream(e.file)) { ! int n; ! if (e.type == Entry.NEW) { // deflated already ! while ((n = is.read(buf)) != -1) { ! os.write(buf, 0, n); ! written += n; ! } ! } else if (e.type == Entry.FILECH) { ! // the data are not deflated, use ZEOS ! try (OutputStream os2 = new EntryOutputStream(e, os)) { ! while ((n = is.read(buf)) != -1) { ! os2.write(buf, 0, n); ! } ! } ! written += e.csize; ! if ((e.flag & FLAG_DATADESCR) != 0) ! written += e.writeEXT(os); ! } ! } ! Files.delete(e.file); ! tmppaths.remove(e.file); ! } else { ! // dir, 0-length data ! } } elist.add(e); } catch (IOException x) { x.printStackTrace(); // skip any in-accurate entry } --- 1228,1238 ---- // file LOC entry. written += copyLOCEntry(e, true, os, written, buf); } else { // NEW, FILECH or CEN e.locoff = written; written += e.writeLOC(os); // write loc header ! written += writeEntry(e, os, buf); } elist.add(e); } catch (IOException x) { x.printStackTrace(); // skip any in-accurate entry }
*** 1292,1322 **** } end.centot = elist.size(); end.cenlen = written - end.cenoff; end.write(os, written, forceEnd64); } ! if (!streams.isEmpty()) { ! // ! // TBD: ExChannelCloser should not be necessary if we only ! // sync when being closed, all streams should have been ! // closed already. Keep the logic here for now. ! // ! // There are outstanding input streams open on existing "ch", ! // so, don't close the "cha" and delete the "file for now, let ! // the "ex-channel-closer" to handle them ! ExChannelCloser ecc = new ExChannelCloser( ! createTempFileInSameDirectoryAs(zfpath), ! ch, ! streams); ! Files.move(zfpath, ecc.path, REPLACE_EXISTING); ! exChClosers.add(ecc); ! streams = Collections.synchronizedSet(new HashSet<InputStream>()); ! } else { ch.close(); Files.delete(zfpath); - } - Files.move(tmpFile, zfpath, REPLACE_EXISTING); hasUpdate = false; // clear } IndexNode getInode(byte[] path) { --- 1257,1269 ---- } end.centot = elist.size(); end.cenlen = written - end.cenoff; end.write(os, written, forceEnd64); } ! ch.close(); Files.delete(zfpath); Files.move(tmpFile, zfpath, REPLACE_EXISTING); hasUpdate = false; // clear } IndexNode getInode(byte[] path) {
*** 1350,1380 **** throw new DirectoryNotEmptyException(getString(path)); updateDelete(inode); } } - private static void copyStream(InputStream is, OutputStream os) - throws IOException - { - byte[] copyBuf = new byte[8192]; - int n; - while ((n = is.read(copyBuf)) != -1) { - os.write(copyBuf, 0, n); - } - } - // Returns an out stream for either // (1) writing the contents of a new entry, if the entry exits, or // (2) updating/replacing the contents of the specified existing entry. private OutputStream getOutputStream(Entry e) throws IOException { if (e.mtime == -1) e.mtime = System.currentTimeMillis(); if (e.method == -1) ! e.method = METHOD_DEFLATED; // TBD: use default method ! // store size, compressed size, and crc-32 in LOC header ! e.flag = 0; if (zc.isUTF8()) e.flag |= FLAG_USE_UTF8; OutputStream os; if (useTempFile) { e.file = getTempPathForEntry(null); --- 1297,1317 ---- throw new DirectoryNotEmptyException(getString(path)); updateDelete(inode); } } // Returns an out stream for either // (1) writing the contents of a new entry, if the entry exits, or // (2) updating/replacing the contents of the specified existing entry. private OutputStream getOutputStream(Entry e) throws IOException { if (e.mtime == -1) e.mtime = System.currentTimeMillis(); if (e.method == -1) ! e.method = defaultMethod; ! // store size, compressed size, and crc-32 in datadescr ! e.flag = FLAG_DATADESCR; if (zc.isUTF8()) e.flag |= FLAG_USE_UTF8; OutputStream os; if (useTempFile) { e.file = getTempPathForEntry(null);
*** 1383,1402 **** os = new ByteArrayOutputStream((e.size > 0)? (int)e.size : 8192); } return new EntryOutputStream(e, os); } private InputStream getInputStream(Entry e) throws IOException { InputStream eis = null; if (e.type == Entry.NEW) { if (e.bytes != null) ! eis = new ByteArrayInputStream(e.bytes); else if (e.file != null) ! eis = Files.newInputStream(e.file); else throw new ZipException("update entry data is missing"); } else if (e.type == Entry.FILECH) { // FILECH result is un-compressed. eis = Files.newInputStream(e.file); --- 1320,1453 ---- os = new ByteArrayOutputStream((e.size > 0)? (int)e.size : 8192); } return new EntryOutputStream(e, os); } + private class EntryOutputStream extends FilterOutputStream { + private Entry e; + private long written; + private boolean isClosed; + + EntryOutputStream(Entry e, OutputStream os) throws IOException { + super(os); + this.e = Objects.requireNonNull(e, "Zip entry is null"); + // this.written = 0; + } + + @Override + public synchronized void write(int b) throws IOException { + out.write(b); + written += 1; + } + + @Override + public synchronized void write(byte b[], int off, int len) + throws IOException { + out.write(b, off, len); + written += len; + } + + @Override + public synchronized void close() throws IOException { + if (isClosed) { + return; + } + isClosed = true; + e.size = written; + if (out instanceof ByteArrayOutputStream) + e.bytes = ((ByteArrayOutputStream)out).toByteArray(); + super.close(); + update(e); + } + } + + // Wrapper output stream class to write out a "stored" entry. + // (1) this class does not close the underlying out stream when + // being closed. + // (2) no need to be "synchronized", only used by sync() + private class EntryOutputStreamCRC32 extends FilterOutputStream { + private Entry e; + private CRC32 crc; + private long written; + private boolean isClosed; + + EntryOutputStreamCRC32(Entry e, OutputStream os) throws IOException { + super(os); + this.e = Objects.requireNonNull(e, "Zip entry is null"); + this.crc = new CRC32(); + } + + @Override + public void write(int b) throws IOException { + out.write(b); + crc.update(b); + written += 1; + } + + @Override + public void write(byte b[], int off, int len) + throws IOException { + out.write(b, off, len); + crc.update(b, off, len); + written += len; + } + + @Override + public void close() throws IOException { + if (isClosed) + return; + isClosed = true; + e.size = e.csize = written; + e.size = crc.getValue(); + } + } + + // Wrapper output stream class to write out a "deflated" entry. + // (1) this class does not close the underlying out stream when + // being closed. + // (2) no need to be "synchronized", only used by sync() + private class EntryOutputStreamDef extends DeflaterOutputStream { + private CRC32 crc; + private Entry e; + private boolean isClosed; + + EntryOutputStreamDef(Entry e, OutputStream os) throws IOException { + super(os, getDeflater()); + this.e = Objects.requireNonNull(e, "Zip entry is null"); + this.crc = new CRC32(); + } + + @Override + public void write(byte b[], int off, int len) + throws IOException { + super.write(b, off, len); + crc.update(b, off, len); + } + + @Override + public void close() throws IOException { + if (isClosed) + return; + isClosed = true; + finish(); + e.size = def.getBytesRead(); + e.csize = def.getBytesWritten(); + e.crc = crc.getValue(); + } + } + private InputStream getInputStream(Entry e) throws IOException { InputStream eis = null; if (e.type == Entry.NEW) { + // now bytes & file is uncompressed. if (e.bytes != null) ! return new ByteArrayInputStream(e.bytes); else if (e.file != null) ! return Files.newInputStream(e.file); else throw new ZipException("update entry data is missing"); } else if (e.type == Entry.FILECH) { // FILECH result is un-compressed. eis = Files.newInputStream(e.file);
*** 1558,1648 **** pos += LOCHDR + LOCNAM(buf) + LOCEXT(buf); } } } - class EntryOutputStream extends DeflaterOutputStream - { - private CRC32 crc; - private Entry e; - private long written; - private boolean isClosed = false; - - EntryOutputStream(Entry e, OutputStream os) - throws IOException - { - super(os, getDeflater()); - if (e == null) - throw new NullPointerException("Zip entry is null"); - this.e = e; - crc = new CRC32(); - } - - @Override - public synchronized void write(byte b[], int off, int len) - throws IOException - { - if (e.type != Entry.FILECH) // only from sync - ensureOpen(); - if (isClosed) { - throw new IOException("Stream closed"); - } - if (off < 0 || len < 0 || off > b.length - len) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return; - } - switch (e.method) { - case METHOD_DEFLATED: - super.write(b, off, len); - break; - case METHOD_STORED: - written += len; - out.write(b, off, len); - break; - default: - throw new ZipException("invalid compression method"); - } - crc.update(b, off, len); - } - - @Override - public synchronized void close() throws IOException { - if (isClosed) { - return; - } - isClosed = true; - // TBD ensureOpen(); - switch (e.method) { - case METHOD_DEFLATED: - finish(); - e.size = def.getBytesRead(); - e.csize = def.getBytesWritten(); - e.crc = crc.getValue(); - break; - case METHOD_STORED: - // we already know that both e.size and e.csize are the same - e.size = e.csize = written; - e.crc = crc.getValue(); - break; - default: - throw new ZipException("invalid compression method"); - } - //crc.reset(); - if (out instanceof ByteArrayOutputStream) - e.bytes = ((ByteArrayOutputStream)out).toByteArray(); - - if (e.type == Entry.FILECH) { - releaseDeflater(def); - return; - } - super.close(); - releaseDeflater(def); - update(e); - } - } - static void zerror(String msg) throws ZipException { throw new ZipException(msg); } // Maxmum number of de/inflater we cache --- 1609,1618 ----
*** 1795,1805 **** 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]; --- 1765,1775 ---- name(name); this.pos = pos; } // constructor for cenInit() ! IndexNode(byte[] cen, int noff, int pos, int nlen) { if (cen[noff + nlen - 1] == '/') { isdir = true; nlen--; } name = new byte[nlen + 1];
*** 1886,1907 **** 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); --- 1856,1877 ---- long locoff; byte[] comment; Entry() {} ! Entry(byte[] name, boolean isdir, int method) { 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; } ! Entry(byte[] name, int type, boolean isdir, int method) { ! this(name, isdir, method); this.type = type; } Entry (Entry e, int type) { name(e.name);
*** 1925,1937 **** 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 { if (method == METHOD_DEFLATED) return 20; --- 1895,1906 ---- this.comment = e.comment; this.type = type; } Entry (byte[] name, Path file, int type) { ! this(name, type, false, METHOD_STORED); this.file = file; } int version() throws ZipException { if (method == METHOD_DEFLATED) return 20;
*** 2406,2415 **** --- 2375,2385 ---- } public String toString() { StringBuilder sb = new StringBuilder(1024); Formatter fm = new Formatter(sb); + fm.format(" name : %s%n", new String(name)); fm.format(" creationTime : %tc%n", creationTime().toMillis()); fm.format(" lastAccessTime : %tc%n", lastAccessTime().toMillis()); fm.format(" lastModifiedTime: %tc%n", lastModifiedTime().toMillis()); fm.format(" isRegularFile : %b%n", isRegularFile()); fm.format(" isDirectory : %b%n", isDirectory());
*** 2423,2446 **** fm.close(); return sb.toString(); } } - private static class ExChannelCloser { - Path path; - SeekableByteChannel ch; - Set<InputStream> streams; - ExChannelCloser(Path path, - SeekableByteChannel ch, - Set<InputStream> streams) - { - this.path = path; - this.ch = ch; - this.streams = streams; - } - } - // ZIP directory has two issues: // (1) ZIP spec does not require the ZIP file to include // directory entry // (2) all entries are not stored/organized in a "tree" // structure. --- 2393,2402 ----
< prev index next >