Mercurial > hg > release > icedtea7-forest-2.3 > jdk
changeset 3385:9cc67a600965
Merge
author | lana |
---|---|
date | Mon, 13 Dec 2010 16:25:26 -0800 |
parents | 0df2e740bd4e (current diff) 78885e69c42c (diff) |
children | 550a81304d04 |
files | src/share/demo/nio/zipfs/META-INF/services/java.nio.file.spi.FileSystemProvider src/share/demo/nio/zipfs/com/sun/nio/zipfs/JarFileSystemProvider.java src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipCoder.java src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipConstants.java src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipDirectoryStream.java src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileAttributeView.java src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileAttributes.java src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileStore.java src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileSystem.java src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileSystemProvider.java src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipInfo.java src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipPath.java src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipUtils.java |
diffstat | 188 files changed, 8409 insertions(+), 6421 deletions(-) [+] |
line wrap: on
line diff
--- a/make/common/shared/Defs-linux.gmk Mon Dec 13 16:22:29 2010 -0800 +++ b/make/common/shared/Defs-linux.gmk Mon Dec 13 16:25:26 2010 -0800 @@ -123,7 +123,7 @@ # GCC29_COMPILER_PATH: is the path to where the gcc 2.9 compiler is installed # NOTE: Must end with / so that it could be empty, allowing PATH usage. -ifneq "$(origin ALT_GCC29_COMPILER_PATH)" "undefined" +ifdef ALT_GCC29_COMPILER_PATH GCC29_COMPILER_PATH :=$(call PrefixPath,$(ALT_GCC29_COMPILER_PATH)) else GCC29_COMPILER_PATH = $(JDK_DEVTOOLS_DIR)/$(PLATFORM)/gcc29/usr/
--- a/make/common/shared/Defs-versions.gmk Mon Dec 13 16:22:29 2010 -0800 +++ b/make/common/shared/Defs-versions.gmk Mon Dec 13 16:25:26 2010 -0800 @@ -65,7 +65,7 @@ # If we are using freetype, the freetype version expected. # # REQUIRED_GCC_VER -# Solaris and Linux only. The required version of gcc/g++ for the plugin. +# Solaris and Linux only. The required version of gcc/g++ for the legacy OJI plugin. # # REQUIRED_LINK_VER # Windows only: The version of link.exe expected.
--- a/make/common/shared/Sanity.gmk Mon Dec 13 16:22:29 2010 -0800 +++ b/make/common/shared/Sanity.gmk Mon Dec 13 16:25:26 2010 -0800 @@ -99,12 +99,16 @@ echo "RedHat"; \ elif [ -f /etc/SuSE-release ] ; then \ echo "SuSE"; \ + elif [ -f /etc/lsb-release ] ; then \ + $(EGREP) DISTRIB_ID /etc/lsb-release | $(SED) -e 's@.*DISTRIB_ID=\(.*\)@\1@'; \ else \ echo "Unknown"; \ fi) OS_VARIANT_VERSION := $(shell \ if [ "$(OS_VARIANT_NAME)" = "Fedora" ] ; then \ $(CAT) /etc/fedora-release | $(HEAD) -1 | $(NAWK) '{ print $$3; }' ; \ + elif [ -f /etc/lsb-release ] ; then \ + $(EGREP) DISTRIB_RELEASE /etc/lsb-release | $(SED) -e 's@.*DISTRIB_RELEASE=\(.*\)@\1@'; \ fi) ALSA_INCLUDE=/usr/include/alsa/version.h ALSA_LIBRARY=/usr/lib/libasound.so @@ -279,7 +283,7 @@ fi ###################################################### -# Check the OS version (windows and linus have release name checks) +# Check the OS version (windows and linux have release name checks) # NOTE: OPENJDK explicitly does not check for OS release information. # Unless we know for sure that it will not build somewhere, we cannot # generate a fatal sanity error, and a warning about the official @@ -1476,20 +1480,20 @@ endif ###################################################### -# Check the Solaris GNU c++ compiler for solaris plugin +# Check the GNU C++ compiler for OJI plugin ###################################################### sane-gcc-compiler: -ifeq ($(PLATFORM), solaris) - ifndef OPENJDK - @if [ -r $(GCC_COMPILER_PATH) ]; then \ - if [ ! "$(GCC_VER)" = $(REQUIRED_GCC_VERSION) ]; then \ - $(ECHO) "ERROR: The Solaris GCC compiler version must be $(REQUIRED_GCC_VERSION). \n" \ +ifndef OPENJDK + ifeq ($(PLATFORM), solaris) + @if [ -r $(GCC_COMPILER_PATH) ]; then \ + if [ ! "$(GCC_VER)" = $(REQUIRED_GCC_VER) ]; then \ + $(ECHO) "ERROR: The Solaris GCC compiler version must be $(REQUIRED_GCC_VER). \n" \ " You are using the following compiler version: $(GCC_VER) \n" \ " The compiler was obtained from the following location: \n" \ " $(GCC_COMPILER_PATH) \n" \ " Please change your compiler. \n" \ "" >> $(ERROR_FILE) ; \ - fi \ + fi \ else \ $(ECHO) "ERROR: You do not have a valid GCC_COMPILER_PATH setting. \n" \ " Please check your access to \n" \ @@ -1501,15 +1505,16 @@ endif ifeq ($(PLATFORM), linux) + ifeq ($(ARCH_DATA_MODEL), 32) ifdef ALT_GCC29_COMPILER_PATH @if [ ! -x $(ALT_GCC29_COMPILER_PATH)/bin/gcc ]; then \ - $(ECHO) "ERROR: You do not have a valid ALT_GCC29_COMPILER_PATH setting. \n" \ + $(ECHO) "ERROR: You do not have a valid ALT_GCC29_COMPILER_PATH setting. \n" \ " Please check your access to \n" \ " $(ALT_GCC29_COMPILER_PATH)/bin/gcc \n" \ " This will affect you if you build the plugin target. \n" \ "" >> $(ERROR_FILE) ; \ fi - endif + else ifdef ALT_GCC29_PLUGIN_LIB_PATH @if [ ! -r $(ALT_GCC29_PLUGIN_LIB_PATH)/libjavaplugin_oji.so ]; then \ $(ECHO) "Error: You do not have a valid ALT_GCC29_PLUGIN_LIB_PATH setting. \n" \ @@ -1523,13 +1528,15 @@ $(ECHO) "ERROR: You do not have a valid GCC29_COMPILER_PATH setting. \n" \ " Please check your access to \n" \ " $(GCC29_COMPILER_PATH) \n" \ - " and/or check your value of ALT_GCC29_COMPILER_PATH. \n" \ + " and/or check your value of ALT_GCC29_COMPILER_PATH or ALT_GCC29_PLUGIN_LIB_PATH \n" \ " This will affect you if you build the plugin target. \n" \ "" >> $(ERROR_FILE) ; \ fi - endif - endif -endif + endif # ALT_GCC29_PLUGIN_LIB_PATH + endif # ALT_GCC29_COMPILER_PATH + endif # ARCH_DATA_MODEL, 32 + endif # LINUX +endif # OPEN_JDK ######################################################
--- a/make/docs/Makefile Mon Dec 13 16:22:29 2010 -0800 +++ b/make/docs/Makefile Mon Dec 13 16:25:26 2010 -0800 @@ -190,7 +190,6 @@ # Common javadoc options used by all COMMON_JAVADOCFLAGS = \ $(NO_PROPRIETARY_API_WARNINGS) \ - -source 1.5 \ -quiet \ -use \ -keywords \
--- a/make/java/java/FILES_java.gmk Mon Dec 13 16:22:29 2010 -0800 +++ b/make/java/java/FILES_java.gmk Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1996, 2010, 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 @@ -137,6 +137,7 @@ java/lang/Comparable.java \ java/lang/Readable.java \ java/lang/Override.java \ + java/lang/SafeVarargs.java \ java/lang/SuppressWarnings.java \ java/lang/ref/Reference.java \ java/lang/ref/SoftReference.java \
--- a/make/mkdemo/nio/zipfs/Makefile Mon Dec 13 16:22:29 2010 -0800 +++ b/make/mkdemo/nio/zipfs/Makefile Mon Dec 13 16:25:26 2010 -0800 @@ -33,8 +33,8 @@ include $(BUILDDIR)/common/Defs.gmk DEMO_ROOT = $(SHARE_SRC)/demo/nio/$(DEMONAME) -DEMO_TOPFILES = ./README.txt -DEMO_SRCDIR = $(DEMO_ROOT) +DEMO_TOPFILES = README.txt Demo.java +DEMO_SRCDIR = $(DEMO_ROOT)/src DEMO_DESTDIR = $(DEMODIR)/nio/$(DEMONAME) # @@ -42,10 +42,10 @@ # include $(BUILDDIR)/common/Demo.gmk -#EXTJAR = $(EXTDIR)/$(DEMONAME).jar -# -#all : build $(EXTJAR) -# -#$(EXTJAR) : $(DEMO_JAR) -# $(prep-target) -# $(CP) $(DEMO_JAR) $(EXTJAR) +EXTJAR = $(EXTDIR)/$(DEMONAME).jar + +all : build $(EXTJAR) + +$(EXTJAR) : $(DEMO_JAR) + $(prep-target) + $(CP) $(DEMO_JAR) $(EXTJAR)
--- a/src/share/classes/com/sun/jndi/ldap/BasicControl.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/com/sun/jndi/ldap/BasicControl.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, 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 @@ -113,6 +113,6 @@ * ASN.1 BER encoded value. */ public byte[] getEncodedValue() { - return value; + return value == null ? null : value.clone(); } }
--- a/src/share/classes/com/sun/jndi/ldap/Filter.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/com/sun/jndi/ldap/Filter.java Mon Dec 13 16:25:26 2010 -0800 @@ -427,7 +427,10 @@ } } else { // descriptor - if (filter[i] != '-' && + // The underscore ("_") character is not allowed by + // the LDAP specification. We allow it here to + // tolerate the incorrect use in practice. + if (filter[i] != '-' && filter[i] != '_' && !(filter[i] >= '0' && filter[i] <= '9') && !(filter[i] >= 'A' && filter[i] <= 'Z') && !(filter[i] >= 'a' && filter[i] <= 'z')) { @@ -467,7 +470,10 @@ break; } - if (filter[i] != '-' && + // The underscore ("_") character is not allowed by + // the LDAP specification. We allow it here to + // tolerate the incorrect use in practice. + if (filter[i] != '-' && filter[i] != '_' && !(filter[i] >= '0' && filter[i] <= '9') && !(filter[i] >= 'A' && filter[i] <= 'Z') && !(filter[i] >= 'a' && filter[i] <= 'z')) { @@ -515,7 +521,10 @@ } } else { // descriptor - if (filter[j] != '-' && + // The underscore ("_") character is not allowed by + // the LDAP specification. We allow it here to + // tolerate the incorrect use in practice. + if (filter[j] != '-' && filter[j] != '_' && !(filter[j] >= '0' && filter[j] <= '9') && !(filter[j] >= 'A' && filter[j] <= 'Z') && !(filter[j] >= 'a' && filter[j] <= 'z')) {
--- a/src/share/classes/com/sun/security/auth/module/NTSystem.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/com/sun/security/auth/module/NTSystem.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, 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 @@ -25,8 +25,6 @@ package com.sun.security.auth.module; -import javax.security.auth.login.LoginException; - /** * <p> This class implementation retrieves and makes available NT * security information for the current user. @@ -124,7 +122,7 @@ * @return the group SIDs for the current NT user. */ public String[] getGroupIDs() { - return groupIDs; + return groupIDs == null ? null : groupIDs.clone(); } /**
--- a/src/share/classes/com/sun/security/auth/module/SolarisSystem.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/com/sun/security/auth/module/SolarisSystem.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, 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 @@ -25,9 +25,6 @@ package com.sun.security.auth.module; -import javax.security.auth.*; -import javax.security.auth.login.*; - /** * <p> This class implementation retrieves and makes available Solaris * UID/GID/groups information for the current user. @@ -92,6 +89,6 @@ * @return the supplementary groups for the current Solaris user. */ public long[] getGroups() { - return groups; + return groups == null ? null : groups.clone(); } }
--- a/src/share/classes/com/sun/security/auth/module/UnixSystem.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/com/sun/security/auth/module/UnixSystem.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, 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 @@ -25,9 +25,6 @@ package com.sun.security.auth.module; -import javax.security.auth.*; -import javax.security.auth.login.*; - /** * <p> This class implementation retrieves and makes available Unix * UID/GID/groups information for the current user. @@ -92,6 +89,6 @@ * @return the supplementary groups for the current Unix user. */ public long[] getGroups() { - return groups; + return groups == null ? null : groups.clone(); } }
--- a/src/share/classes/java/io/FileOutputStream.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/io/FileOutputStream.java Mon Dec 13 16:25:26 2010 -0800 @@ -56,7 +56,15 @@ */ private final FileDescriptor fd; - private FileChannel channel= null; + /** + * True if the file is opened for append. + */ + private final boolean append; + + /** + * The associated channel, initalized lazily. + */ + private FileChannel channel; private final Object closeLock = new Object(); private volatile boolean closed = false; @@ -196,7 +204,9 @@ if (name == null) { throw new NullPointerException(); } - fd = new FileDescriptor(); + this.fd = new FileDescriptor(); + this.append = append; + fd.incrementAndGetUseCount(); open(name, append); } @@ -232,7 +242,8 @@ if (security != null) { security.checkWrite(fdObj); } - fd = fdObj; + this.fd = fdObj; + this.append = false; /* * FileDescriptor is being shared by streams. @@ -251,22 +262,36 @@ throws FileNotFoundException; /** + * Writes the specified byte to this file output stream. + * + * @param b the byte to be written. + * @param append {@code true} if the write operation first + * advances the position to the end of file + */ + private native void write(int b, boolean append) throws IOException; + + /** * Writes the specified byte to this file output stream. Implements * the <code>write</code> method of <code>OutputStream</code>. * * @param b the byte to be written. * @exception IOException if an I/O error occurs. */ - public native void write(int b) throws IOException; + public void write(int b) throws IOException { + write(b, append); + } /** * Writes a sub array as a sequence of bytes. * @param b the data to be written * @param off the start offset in the data * @param len the number of bytes that are written + * @param append {@code true} to first advance the position to the + * end of file * @exception IOException If an I/O error has occurred. */ - private native void writeBytes(byte b[], int off, int len) throws IOException; + private native void writeBytes(byte b[], int off, int len, boolean append) + throws IOException; /** * Writes <code>b.length</code> bytes from the specified byte array @@ -276,7 +301,7 @@ * @exception IOException if an I/O error occurs. */ public void write(byte b[]) throws IOException { - writeBytes(b, 0, b.length); + writeBytes(b, 0, b.length, append); } /** @@ -289,7 +314,7 @@ * @exception IOException if an I/O error occurs. */ public void write(byte b[], int off, int len) throws IOException { - writeBytes(b, off, len); + writeBytes(b, off, len, append); } /** @@ -372,7 +397,7 @@ public FileChannel getChannel() { synchronized (this) { if (channel == null) { - channel = FileChannelImpl.open(fd, false, true, this); + channel = FileChannelImpl.open(fd, false, true, append, this); /* * Increment fd's use count. Invoking the channel's close()
--- a/src/share/classes/java/io/ObjectInputStream.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/io/ObjectInputStream.java Mon Dec 13 16:25:26 2010 -0800 @@ -3498,8 +3498,8 @@ return ((int[]) array).clone(); } else if (array instanceof long[]) { return ((long[]) array).clone(); - } else if (array instanceof double[]) { - return ((double[]) array).clone(); + } else if (array instanceof short[]) { + return ((short[]) array).clone(); } else { throw new AssertionError(); }
--- a/src/share/classes/java/lang/Double.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/lang/Double.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2010, 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 @@ -973,7 +973,8 @@ if (d1 > d2) return 1; // Neither val is NaN, thisVal is larger - long thisBits = Double.doubleToLongBits(d1); + // Cannot use doubleToRawLongBits because of possibility of NaNs. + long thisBits = Double.doubleToLongBits(d1); long anotherBits = Double.doubleToLongBits(d2); return (thisBits == anotherBits ? 0 : // Values are equal
--- a/src/share/classes/java/lang/Float.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/lang/Float.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2010, 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 @@ -872,12 +872,13 @@ * @since 1.4 */ public static int compare(float f1, float f2) { - if (f1 < f2) + if (f1 < f2) return -1; // Neither val is NaN, thisVal is smaller if (f1 > f2) return 1; // Neither val is NaN, thisVal is larger - int thisBits = Float.floatToIntBits(f1); + // Cannot use floatToRawIntBits because of possibility of NaNs. + int thisBits = Float.floatToIntBits(f1); int anotherBits = Float.floatToIntBits(f2); return (thisBits == anotherBits ? 0 : // Values are equal
--- a/src/share/classes/java/lang/ProcessBuilder.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/lang/ProcessBuilder.java Mon Dec 13 16:25:26 2010 -0800 @@ -537,7 +537,11 @@ */ public File file() { return null; } - FileOutputStream toFileOutputStream() throws IOException { + /** + * When redirected to a destination file, indicates if the output + * is to be written to the end of the file. + */ + boolean append() { throw new UnsupportedOperationException(); } @@ -588,9 +592,7 @@ public String toString() { return "redirect to write to file \"" + file + "\""; } - FileOutputStream toFileOutputStream() throws IOException { - return new FileOutputStream(file, false); - } + boolean append() { return false; } }; } @@ -620,9 +622,7 @@ public String toString() { return "redirect to append to file \"" + file + "\""; } - FileOutputStream toFileOutputStream() throws IOException { - return new FileOutputStream(file, true); - } + boolean append() { return true; } }; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/java/lang/SafeVarargs.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2010, 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 + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import java.lang.annotation.*; + +/** + * A programmer assertion that the body of the annotated method or + * constructor does not perform potentially unsafe operations on its + * varargs parameter. Applying this annotation to a method or + * constructor suppresses unchecked warnings about a + * <i>non-reifiable</i> variable-arity (vararg) type and suppresses + * unchecked warnings about parameterized array creation at call + * sites. + * + * <p> In addition to the usage restrictions imposed by its {@link + * Target @Target} meta-annotation, compilers are required to implement + * additional usage restrictions on this annotation type; it is a + * compile-time error if a method or constructor declaration is + * annotated with a {@code @SafeVarargs} annotation, and either: + + * <ul> + * <li> the declaration is a fixed-arity method or constructor + * + * <li> the declaration is a variable-arity method that is neither + * {@code static} nor {@code final}. + * + * </ul> + * + * <p> Compilers are encouraged to issue warnings when this annotation + * type is applied to a method or constructor declaration where: + * + * <ul> + * + * <li> The variable-arity parameter has a reifiable element type, + * which includes primitive types, {@code Object}, and {@code String}. + * (The unchecked warnings this annotation type suppresses already do + * not occur for a reifiable element type.) + * + * <li> The body of the method or constructor declaration performs + * potentially unsafe operations, such as an assignment to an element + * of the variable-arity parameter's array that generates an unchecked + * warning. + * + * <p>Future versions of the platform may mandate compiler errors for + * such unsafe operations. + * + * </ul> + * + * @jls3 4.7 Reifiable Types + * @jls3 8.4.1 Formal Parameters + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.CONSTRUCTOR, ElementType.METHOD}) +public @interface SafeVarargs {}
--- a/src/share/classes/java/lang/StrictMath.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/lang/StrictMath.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, 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 @@ -801,8 +801,9 @@ return (a >= b) ? a : b; } - private static long negativeZeroFloatBits = Float.floatToIntBits(-0.0f); - private static long negativeZeroDoubleBits = Double.doubleToLongBits(-0.0d); + // Use raw bit-wise conversions on guaranteed non-NaN arguments. + private static long negativeZeroFloatBits = Float.floatToRawIntBits(-0.0f); + private static long negativeZeroDoubleBits = Double.doubleToRawLongBits(-0.0d); /** * Returns the greater of two {@code float} values. That is, @@ -819,9 +820,12 @@ * @return the larger of {@code a} and {@code b}. */ public static float max(float a, float b) { - if (a != a) return a; // a is NaN - if ((a == 0.0f) && (b == 0.0f) - && (Float.floatToIntBits(a) == negativeZeroFloatBits)) { + if (a != a) + return a; // a is NaN + if ((a == 0.0f) && + (b == 0.0f) && + (Float.floatToRawIntBits(a) == negativeZeroFloatBits)) { + // Raw conversion ok since NaN can't map to -0.0. return b; } return (a >= b) ? a : b; @@ -842,9 +846,12 @@ * @return the larger of {@code a} and {@code b}. */ public static double max(double a, double b) { - if (a != a) return a; // a is NaN - if ((a == 0.0d) && (b == 0.0d) - && (Double.doubleToLongBits(a) == negativeZeroDoubleBits)) { + if (a != a) + return a; // a is NaN + if ((a == 0.0d) && + (b == 0.0d) && + (Double.doubleToRawLongBits(a) == negativeZeroDoubleBits)) { + // Raw conversion ok since NaN can't map to -0.0. return b; } return (a >= b) ? a : b; @@ -893,9 +900,12 @@ * @return the smaller of {@code a} and {@code b.} */ public static float min(float a, float b) { - if (a != a) return a; // a is NaN - if ((a == 0.0f) && (b == 0.0f) - && (Float.floatToIntBits(b) == negativeZeroFloatBits)) { + if (a != a) + return a; // a is NaN + if ((a == 0.0f) && + (b == 0.0f) && + (Float.floatToRawIntBits(b) == negativeZeroFloatBits)) { + // Raw conversion ok since NaN can't map to -0.0. return b; } return (a <= b) ? a : b; @@ -916,9 +926,12 @@ * @return the smaller of {@code a} and {@code b}. */ public static double min(double a, double b) { - if (a != a) return a; // a is NaN - if ((a == 0.0d) && (b == 0.0d) - && (Double.doubleToLongBits(b) == negativeZeroDoubleBits)) { + if (a != a) + return a; // a is NaN + if ((a == 0.0d) && + (b == 0.0d) && + (Double.doubleToRawLongBits(b) == negativeZeroDoubleBits)) { + // Raw conversion ok since NaN can't map to -0.0. return b; } return (a <= b) ? a : b;
--- a/src/share/classes/java/lang/Thread.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/lang/Thread.java Mon Dec 13 16:25:26 2010 -0800 @@ -209,7 +209,7 @@ * initialized to indicate thread 'not yet started' */ - private int threadStatus = 0; + private volatile int threadStatus = 0; private static synchronized long nextThreadID() {
--- a/src/share/classes/java/nio/charset/Charset.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/nio/charset/Charset.java Mon Dec 13 16:25:26 2010 -0800 @@ -275,18 +275,17 @@ /* -- Static methods -- */ - private static String bugLevel = null; + private static volatile String bugLevel = null; static boolean atBugLevel(String bl) { // package-private - if (bugLevel == null) { + String level = bugLevel; + if (level == null) { if (!sun.misc.VM.isBooted()) return false; - bugLevel = AccessController.doPrivileged( - new GetPropertyAction("sun.nio.cs.bugLevel")); - if (bugLevel == null) - bugLevel = ""; + bugLevel = level = AccessController.doPrivileged( + new GetPropertyAction("sun.nio.cs.bugLevel", "")); } - return (bugLevel != null) && bugLevel.equals(bl); + return level.equals(bl); } /**
--- a/src/share/classes/java/security/CodeSigner.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/security/CodeSigner.java Mon Dec 13 16:25:26 2010 -0800 @@ -25,7 +25,7 @@ package java.security; -import java.io.Serializable; +import java.io.*; import java.security.cert.CRL; import java.security.cert.CertPath; import sun.misc.JavaSecurityCodeSignerAccess; @@ -205,4 +205,10 @@ }); } + // Explicitly reset hash code value to -1 + private void readObject(ObjectInputStream ois) + throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + myhash = -1; + } }
--- a/src/share/classes/java/security/Timestamp.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/security/Timestamp.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, 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 @@ -25,10 +25,12 @@ package java.security; -import java.io.Serializable; +import java.io.*; +import java.security.cert.Certificate; import java.security.cert.CertPath; import java.security.cert.X509Extension; import java.util.Date; +import java.util.List; /** * This class encapsulates information about a signed timestamp. @@ -142,8 +144,20 @@ StringBuffer sb = new StringBuffer(); sb.append("("); sb.append("timestamp: " + timestamp); - sb.append("TSA: " + signerCertPath.getCertificates().get(0)); + List<? extends Certificate> certs = signerCertPath.getCertificates(); + if (!certs.isEmpty()) { + sb.append("TSA: " + certs.get(0)); + } else { + sb.append("TSA: <empty>"); + } sb.append(")"); return sb.toString(); } + + // Explicitly reset hash code value to -1 + private void readObject(ObjectInputStream ois) + throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + myhash = -1; + } }
--- a/src/share/classes/java/util/AbstractCollection.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/AbstractCollection.java Mon Dec 13 16:25:26 2010 -0800 @@ -96,14 +96,14 @@ * @throws NullPointerException {@inheritDoc} */ public boolean contains(Object o) { - Iterator<E> e = iterator(); + Iterator<E> it = iterator(); if (o==null) { - while (e.hasNext()) - if (e.next()==null) + while (it.hasNext()) + if (it.next()==null) return true; } else { - while (e.hasNext()) - if (o.equals(e.next())) + while (it.hasNext()) + if (o.equals(it.next())) return true; } return false; @@ -269,18 +269,18 @@ * @throws NullPointerException {@inheritDoc} */ public boolean remove(Object o) { - Iterator<E> e = iterator(); + Iterator<E> it = iterator(); if (o==null) { - while (e.hasNext()) { - if (e.next()==null) { - e.remove(); + while (it.hasNext()) { + if (it.next()==null) { + it.remove(); return true; } } } else { - while (e.hasNext()) { - if (o.equals(e.next())) { - e.remove(); + while (it.hasNext()) { + if (o.equals(it.next())) { + it.remove(); return true; } } @@ -304,9 +304,8 @@ * @see #contains(Object) */ public boolean containsAll(Collection<?> c) { - Iterator<?> e = c.iterator(); - while (e.hasNext()) - if (!contains(e.next())) + for (Object e : c) + if (!contains(e)) return false; return true; } @@ -331,11 +330,9 @@ */ public boolean addAll(Collection<? extends E> c) { boolean modified = false; - Iterator<? extends E> e = c.iterator(); - while (e.hasNext()) { - if (add(e.next())) + for (E e : c) + if (add(e)) modified = true; - } return modified; } @@ -362,10 +359,10 @@ */ public boolean removeAll(Collection<?> c) { boolean modified = false; - Iterator<?> e = iterator(); - while (e.hasNext()) { - if (c.contains(e.next())) { - e.remove(); + Iterator<?> it = iterator(); + while (it.hasNext()) { + if (c.contains(it.next())) { + it.remove(); modified = true; } } @@ -395,10 +392,10 @@ */ public boolean retainAll(Collection<?> c) { boolean modified = false; - Iterator<E> e = iterator(); - while (e.hasNext()) { - if (!c.contains(e.next())) { - e.remove(); + Iterator<E> it = iterator(); + while (it.hasNext()) { + if (!c.contains(it.next())) { + it.remove(); modified = true; } } @@ -421,10 +418,10 @@ * @throws UnsupportedOperationException {@inheritDoc} */ public void clear() { - Iterator<E> e = iterator(); - while (e.hasNext()) { - e.next(); - e.remove(); + Iterator<E> it = iterator(); + while (it.hasNext()) { + it.next(); + it.remove(); } } @@ -442,18 +439,18 @@ * @return a string representation of this collection */ public String toString() { - Iterator<E> i = iterator(); - if (! i.hasNext()) + Iterator<E> it = iterator(); + if (! it.hasNext()) return "[]"; StringBuilder sb = new StringBuilder(); sb.append('['); for (;;) { - E e = i.next(); + E e = it.next(); sb.append(e == this ? "(this Collection)" : e); - if (! i.hasNext()) + if (! it.hasNext()) return sb.append(']').toString(); - sb.append(", "); + sb.append(',').append(' '); } }
--- a/src/share/classes/java/util/AbstractList.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/AbstractList.java Mon Dec 13 16:25:26 2010 -0800 @@ -175,15 +175,15 @@ * @throws NullPointerException {@inheritDoc} */ public int indexOf(Object o) { - ListIterator<E> e = listIterator(); + ListIterator<E> it = listIterator(); if (o==null) { - while (e.hasNext()) - if (e.next()==null) - return e.previousIndex(); + while (it.hasNext()) + if (it.next()==null) + return it.previousIndex(); } else { - while (e.hasNext()) - if (o.equals(e.next())) - return e.previousIndex(); + while (it.hasNext()) + if (o.equals(it.next())) + return it.previousIndex(); } return -1; } @@ -200,15 +200,15 @@ * @throws NullPointerException {@inheritDoc} */ public int lastIndexOf(Object o) { - ListIterator<E> e = listIterator(size()); + ListIterator<E> it = listIterator(size()); if (o==null) { - while (e.hasPrevious()) - if (e.previous()==null) - return e.nextIndex(); + while (it.hasPrevious()) + if (it.previous()==null) + return it.nextIndex(); } else { - while (e.hasPrevious()) - if (o.equals(e.previous())) - return e.nextIndex(); + while (it.hasPrevious()) + if (o.equals(it.previous())) + return it.nextIndex(); } return -1; } @@ -517,7 +517,7 @@ ListIterator<E> e1 = listIterator(); ListIterator e2 = ((List) o).listIterator(); - while(e1.hasNext() && e2.hasNext()) { + while (e1.hasNext() && e2.hasNext()) { E o1 = e1.next(); Object o2 = e2.next(); if (!(o1==null ? o2==null : o1.equals(o2)))
--- a/src/share/classes/java/util/AbstractMap.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/AbstractMap.java Mon Dec 13 16:25:26 2010 -0800 @@ -523,7 +523,7 @@ sb.append(value == this ? "(this Map)" : value); if (! i.hasNext()) return sb.append('}').toString(); - sb.append(", "); + sb.append(',').append(' '); } }
--- a/src/share/classes/java/util/ArrayList.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/ArrayList.java Mon Dec 13 16:25:26 2010 -0800 @@ -120,9 +120,9 @@ /** * Constructs an empty list with the specified initial capacity. * - * @param initialCapacity the initial capacity of the list - * @exception IllegalArgumentException if the specified initial capacity - * is negative + * @param initialCapacity the initial capacity of the list + * @throws IllegalArgumentException if the specified initial capacity + * is negative */ public ArrayList(int initialCapacity) { super(); @@ -173,7 +173,7 @@ * necessary, to ensure that it can hold at least the number of elements * specified by the minimum capacity argument. * - * @param minCapacity the desired minimum capacity + * @param minCapacity the desired minimum capacity */ public void ensureCapacity(int minCapacity) { if (minCapacity > 0)
--- a/src/share/classes/java/util/Collections.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/Collections.java Mon Dec 13 16:25:26 2010 -0800 @@ -124,7 +124,7 @@ * * <p>The implementation takes equal advantage of ascending and * descending order in its input array, and can take advantage of - * ascending and descending order in different parts of the the same + * ascending and descending order in different parts of the same * input array. It is well-suited to merging two or more sorted arrays: * simply concatenate the arrays and sort the resulting array. * @@ -184,7 +184,7 @@ * * <p>The implementation takes equal advantage of ascending and * descending order in its input array, and can take advantage of - * ascending and descending order in different parts of the the same + * ascending and descending order in different parts of the same * input array. It is well-suited to merging two or more sorted arrays: * simply concatenate the arrays and sort the resulting array. * @@ -823,7 +823,7 @@ i -= size; displaced = list.set(i, displaced); nMoved ++; - } while(i != cycleStart); + } while (i != cycleStart); } } @@ -1452,9 +1452,9 @@ * when o is a Map.Entry, and calls o.setValue. */ public boolean containsAll(Collection<?> coll) { - Iterator<?> e = coll.iterator(); - while (e.hasNext()) - if (!contains(e.next())) // Invokes safe contains() above + Iterator<?> it = coll.iterator(); + while (it.hasNext()) + if (!contains(it.next())) // Invokes safe contains() above return false; return true; } @@ -1482,12 +1482,12 @@ UnmodifiableEntry(Map.Entry<? extends K, ? extends V> e) {this.e = e;} - public K getKey() {return e.getKey();} - public V getValue() {return e.getValue();} + public K getKey() {return e.getKey();} + public V getValue() {return e.getValue();} public V setValue(V value) { throw new UnsupportedOperationException(); } - public int hashCode() {return e.hashCode();} + public int hashCode() {return e.hashCode();} public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; @@ -1495,7 +1495,7 @@ return eq(e.getKey(), t.getKey()) && eq(e.getValue(), t.getValue()); } - public String toString() {return e.toString();} + public String toString() {return e.toString();} } } } @@ -1562,7 +1562,7 @@ * <pre> * Collection c = Collections.synchronizedCollection(myCollection); * ... - * synchronized(c) { + * synchronized (c) { * Iterator i = c.iterator(); // Must be in the synchronized block * while (i.hasNext()) * foo(i.next()); @@ -1611,19 +1611,19 @@ } public int size() { - synchronized(mutex) {return c.size();} + synchronized (mutex) {return c.size();} } public boolean isEmpty() { - synchronized(mutex) {return c.isEmpty();} + synchronized (mutex) {return c.isEmpty();} } public boolean contains(Object o) { - synchronized(mutex) {return c.contains(o);} + synchronized (mutex) {return c.contains(o);} } public Object[] toArray() { - synchronized(mutex) {return c.toArray();} + synchronized (mutex) {return c.toArray();} } public <T> T[] toArray(T[] a) { - synchronized(mutex) {return c.toArray(a);} + synchronized (mutex) {return c.toArray(a);} } public Iterator<E> iterator() { @@ -1631,32 +1631,32 @@ } public boolean add(E e) { - synchronized(mutex) {return c.add(e);} + synchronized (mutex) {return c.add(e);} } public boolean remove(Object o) { - synchronized(mutex) {return c.remove(o);} + synchronized (mutex) {return c.remove(o);} } public boolean containsAll(Collection<?> coll) { - synchronized(mutex) {return c.containsAll(coll);} + synchronized (mutex) {return c.containsAll(coll);} } public boolean addAll(Collection<? extends E> coll) { - synchronized(mutex) {return c.addAll(coll);} + synchronized (mutex) {return c.addAll(coll);} } public boolean removeAll(Collection<?> coll) { - synchronized(mutex) {return c.removeAll(coll);} + synchronized (mutex) {return c.removeAll(coll);} } public boolean retainAll(Collection<?> coll) { - synchronized(mutex) {return c.retainAll(coll);} + synchronized (mutex) {return c.retainAll(coll);} } public void clear() { - synchronized(mutex) {c.clear();} + synchronized (mutex) {c.clear();} } public String toString() { - synchronized(mutex) {return c.toString();} + synchronized (mutex) {return c.toString();} } private void writeObject(ObjectOutputStream s) throws IOException { - synchronized(mutex) {s.defaultWriteObject();} + synchronized (mutex) {s.defaultWriteObject();} } } @@ -1671,7 +1671,7 @@ * <pre> * Set s = Collections.synchronizedSet(new HashSet()); * ... - * synchronized(s) { + * synchronized (s) { * Iterator i = s.iterator(); // Must be in the synchronized block * while (i.hasNext()) * foo(i.next()); @@ -1709,10 +1709,10 @@ } public boolean equals(Object o) { - synchronized(mutex) {return c.equals(o);} + synchronized (mutex) {return c.equals(o);} } public int hashCode() { - synchronized(mutex) {return c.hashCode();} + synchronized (mutex) {return c.hashCode();} } } @@ -1728,7 +1728,7 @@ * <pre> * SortedSet s = Collections.synchronizedSortedSet(new TreeSet()); * ... - * synchronized(s) { + * synchronized (s) { * Iterator i = s.iterator(); // Must be in the synchronized block * while (i.hasNext()) * foo(i.next()); @@ -1739,7 +1739,7 @@ * SortedSet s = Collections.synchronizedSortedSet(new TreeSet()); * SortedSet s2 = s.headSet(foo); * ... - * synchronized(s) { // Note: s, not s2!!! + * synchronized (s) { // Note: s, not s2!!! * Iterator i = s2.iterator(); // Must be in the synchronized block * while (i.hasNext()) * foo(i.next()); @@ -1766,7 +1766,7 @@ { private static final long serialVersionUID = 8695801310862127406L; - final private SortedSet<E> ss; + private final SortedSet<E> ss; SynchronizedSortedSet(SortedSet<E> s) { super(s); @@ -1778,31 +1778,31 @@ } public Comparator<? super E> comparator() { - synchronized(mutex) {return ss.comparator();} + synchronized (mutex) {return ss.comparator();} } public SortedSet<E> subSet(E fromElement, E toElement) { - synchronized(mutex) { + synchronized (mutex) { return new SynchronizedSortedSet<E>( ss.subSet(fromElement, toElement), mutex); } } public SortedSet<E> headSet(E toElement) { - synchronized(mutex) { + synchronized (mutex) { return new SynchronizedSortedSet<E>(ss.headSet(toElement), mutex); } } public SortedSet<E> tailSet(E fromElement) { - synchronized(mutex) { + synchronized (mutex) { return new SynchronizedSortedSet<E>(ss.tailSet(fromElement),mutex); } } public E first() { - synchronized(mutex) {return ss.first();} + synchronized (mutex) {return ss.first();} } public E last() { - synchronized(mutex) {return ss.last();} + synchronized (mutex) {return ss.last();} } } @@ -1817,7 +1817,7 @@ * <pre> * List list = Collections.synchronizedList(new ArrayList()); * ... - * synchronized(list) { + * synchronized (list) { * Iterator i = list.iterator(); // Must be in synchronized block * while (i.hasNext()) * foo(i.next()); @@ -1863,34 +1863,34 @@ } public boolean equals(Object o) { - synchronized(mutex) {return list.equals(o);} + synchronized (mutex) {return list.equals(o);} } public int hashCode() { - synchronized(mutex) {return list.hashCode();} + synchronized (mutex) {return list.hashCode();} } public E get(int index) { - synchronized(mutex) {return list.get(index);} + synchronized (mutex) {return list.get(index);} } public E set(int index, E element) { - synchronized(mutex) {return list.set(index, element);} + synchronized (mutex) {return list.set(index, element);} } public void add(int index, E element) { - synchronized(mutex) {list.add(index, element);} + synchronized (mutex) {list.add(index, element);} } public E remove(int index) { - synchronized(mutex) {return list.remove(index);} + synchronized (mutex) {return list.remove(index);} } public int indexOf(Object o) { - synchronized(mutex) {return list.indexOf(o);} + synchronized (mutex) {return list.indexOf(o);} } public int lastIndexOf(Object o) { - synchronized(mutex) {return list.lastIndexOf(o);} + synchronized (mutex) {return list.lastIndexOf(o);} } public boolean addAll(int index, Collection<? extends E> c) { - synchronized(mutex) {return list.addAll(index, c);} + synchronized (mutex) {return list.addAll(index, c);} } public ListIterator<E> listIterator() { @@ -1902,7 +1902,7 @@ } public List<E> subList(int fromIndex, int toIndex) { - synchronized(mutex) { + synchronized (mutex) { return new SynchronizedList<E>(list.subList(fromIndex, toIndex), mutex); } @@ -1943,7 +1943,7 @@ } public List<E> subList(int fromIndex, int toIndex) { - synchronized(mutex) { + synchronized (mutex) { return new SynchronizedRandomAccessList<E>( list.subList(fromIndex, toIndex), mutex); } @@ -1975,7 +1975,7 @@ * ... * Set s = m.keySet(); // Needn't be in synchronized block * ... - * synchronized(m) { // Synchronizing on m, not s! + * synchronized (m) { // Synchronizing on m, not s! * Iterator i = s.iterator(); // Must be in synchronized block * while (i.hasNext()) * foo(i.next()); @@ -2016,32 +2016,32 @@ } public int size() { - synchronized(mutex) {return m.size();} + synchronized (mutex) {return m.size();} } public boolean isEmpty() { - synchronized(mutex) {return m.isEmpty();} + synchronized (mutex) {return m.isEmpty();} } public boolean containsKey(Object key) { - synchronized(mutex) {return m.containsKey(key);} + synchronized (mutex) {return m.containsKey(key);} } public boolean containsValue(Object value) { - synchronized(mutex) {return m.containsValue(value);} + synchronized (mutex) {return m.containsValue(value);} } public V get(Object key) { - synchronized(mutex) {return m.get(key);} + synchronized (mutex) {return m.get(key);} } public V put(K key, V value) { - synchronized(mutex) {return m.put(key, value);} + synchronized (mutex) {return m.put(key, value);} } public V remove(Object key) { - synchronized(mutex) {return m.remove(key);} + synchronized (mutex) {return m.remove(key);} } public void putAll(Map<? extends K, ? extends V> map) { - synchronized(mutex) {m.putAll(map);} + synchronized (mutex) {m.putAll(map);} } public void clear() { - synchronized(mutex) {m.clear();} + synchronized (mutex) {m.clear();} } private transient Set<K> keySet = null; @@ -2049,7 +2049,7 @@ private transient Collection<V> values = null; public Set<K> keySet() { - synchronized(mutex) { + synchronized (mutex) { if (keySet==null) keySet = new SynchronizedSet<K>(m.keySet(), mutex); return keySet; @@ -2057,7 +2057,7 @@ } public Set<Map.Entry<K,V>> entrySet() { - synchronized(mutex) { + synchronized (mutex) { if (entrySet==null) entrySet = new SynchronizedSet<Map.Entry<K,V>>(m.entrySet(), mutex); return entrySet; @@ -2065,7 +2065,7 @@ } public Collection<V> values() { - synchronized(mutex) { + synchronized (mutex) { if (values==null) values = new SynchronizedCollection<V>(m.values(), mutex); return values; @@ -2073,16 +2073,16 @@ } public boolean equals(Object o) { - synchronized(mutex) {return m.equals(o);} + synchronized (mutex) {return m.equals(o);} } public int hashCode() { - synchronized(mutex) {return m.hashCode();} + synchronized (mutex) {return m.hashCode();} } public String toString() { - synchronized(mutex) {return m.toString();} + synchronized (mutex) {return m.toString();} } private void writeObject(ObjectOutputStream s) throws IOException { - synchronized(mutex) {s.defaultWriteObject();} + synchronized (mutex) {s.defaultWriteObject();} } } @@ -2101,7 +2101,7 @@ * ... * Set s = m.keySet(); // Needn't be in synchronized block * ... - * synchronized(m) { // Synchronizing on m, not s! + * synchronized (m) { // Synchronizing on m, not s! * Iterator i = s.iterator(); // Must be in synchronized block * while (i.hasNext()) * foo(i.next()); @@ -2114,7 +2114,7 @@ * ... * Set s2 = m2.keySet(); // Needn't be in synchronized block * ... - * synchronized(m) { // Synchronizing on m, not m2 or s2! + * synchronized (m) { // Synchronizing on m, not m2 or s2! * Iterator i = s.iterator(); // Must be in synchronized block * while (i.hasNext()) * foo(i.next()); @@ -2154,31 +2154,31 @@ } public Comparator<? super K> comparator() { - synchronized(mutex) {return sm.comparator();} + synchronized (mutex) {return sm.comparator();} } public SortedMap<K,V> subMap(K fromKey, K toKey) { - synchronized(mutex) { + synchronized (mutex) { return new SynchronizedSortedMap<K,V>( sm.subMap(fromKey, toKey), mutex); } } public SortedMap<K,V> headMap(K toKey) { - synchronized(mutex) { + synchronized (mutex) { return new SynchronizedSortedMap<K,V>(sm.headMap(toKey), mutex); } } public SortedMap<K,V> tailMap(K fromKey) { - synchronized(mutex) { + synchronized (mutex) { return new SynchronizedSortedMap<K,V>(sm.tailMap(fromKey),mutex); } } public K firstKey() { - synchronized(mutex) {return sm.firstKey();} + synchronized (mutex) {return sm.firstKey();} } public K lastKey() { - synchronized(mutex) {return sm.lastKey();} + synchronized (mutex) {return sm.lastKey();} } } @@ -3317,7 +3317,7 @@ { private static final long serialVersionUID = 3193687207550431679L; - final private E element; + private final E element; SingletonSet(E e) {element = e;} @@ -3448,7 +3448,7 @@ * @param o the element to appear repeatedly in the returned list. * @return an immutable list consisting of <tt>n</tt> copies of the * specified object. - * @throws IllegalArgumentException if n < 0. + * @throws IllegalArgumentException if {@code n < 0} * @see List#addAll(Collection) * @see List#addAll(int, Collection) */
--- a/src/share/classes/java/util/ComparableTimSort.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/ComparableTimSort.java Mon Dec 13 16:25:26 2010 -0800 @@ -207,7 +207,7 @@ * @param lo the index of the first element in the range to be sorted * @param hi the index after the last element in the range to be sorted * @param start the index of the first element in the range that is - * not already known to be sorted (@code lo <= start <= hi} + * not already known to be sorted ({@code lo <= start <= hi}) */ @SuppressWarnings("fallthrough") private static void binarySort(Object[] a, int lo, int hi, int start) { @@ -245,7 +245,7 @@ */ int n = start - left; // The number of elements to move // Switch is just an optimization for arraycopy in default case - switch(n) { + switch (n) { case 2: a[left + 2] = a[left + 1]; case 1: a[left + 1] = a[left]; break; @@ -275,7 +275,7 @@ * @param a the array in which a run is to be counted and possibly reversed * @param lo index of the first element in the run * @param hi index after the last element that may be contained in the run. - It is required that @code{lo < hi}. + It is required that {@code lo < hi}. * @return the length of the run beginning at the specified position in * the specified array */ @@ -288,7 +288,7 @@ // Find end of run, and reverse range if descending if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0) { // Descending - while(runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0) + while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0) runHi++; reverseRange(a, lo, runHi); } else { // Ascending
--- a/src/share/classes/java/util/FormattableFlags.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/FormattableFlags.java Mon Dec 13 16:25:26 2010 -0800 @@ -59,10 +59,10 @@ * <pre> * out.toUpperCase() </pre> * - * <p> This flag corresponds to <tt>'^'</tt> (<tt>'\u005e'</tt>) in + * <p> This flag corresponds to <tt>'S'</tt> (<tt>'\u0053'</tt>) in * the format specifier. */ - public static final int UPPERCASE = 1<<1; // '^' + public static final int UPPERCASE = 1<<1; // 'S' /** * Requires the output to use an alternate form. The definition of the
--- a/src/share/classes/java/util/Random.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/Random.java Mon Dec 13 16:25:26 2010 -0800 @@ -77,9 +77,9 @@ */ private final AtomicLong seed; - private final static long multiplier = 0x5DEECE66DL; - private final static long addend = 0xBL; - private final static long mask = (1L << 48) - 1; + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; /** * Creates a new random number generator. This constructor sets @@ -285,7 +285,7 @@ * @return the next pseudorandom, uniformly distributed {@code int} * value between {@code 0} (inclusive) and {@code n} (exclusive) * from this random number generator's sequence - * @exception IllegalArgumentException if n is not positive + * @throws IllegalArgumentException if n is not positive * @since 1.2 */
--- a/src/share/classes/java/util/Stack.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/Stack.java Mon Dec 13 16:25:26 2010 -0800 @@ -73,9 +73,9 @@ * Removes the object at the top of this stack and returns that * object as the value of this function. * - * @return The object at the top of this stack (the last item - * of the <tt>Vector</tt> object). - * @exception EmptyStackException if this stack is empty. + * @return The object at the top of this stack (the last item + * of the <tt>Vector</tt> object). + * @throws EmptyStackException if this stack is empty. */ public synchronized E pop() { E obj; @@ -91,9 +91,9 @@ * Looks at the object at the top of this stack without removing it * from the stack. * - * @return the object at the top of this stack (the last item - * of the <tt>Vector</tt> object). - * @exception EmptyStackException if this stack is empty. + * @return the object at the top of this stack (the last item + * of the <tt>Vector</tt> object). + * @throws EmptyStackException if this stack is empty. */ public synchronized E peek() { int len = size();
--- a/src/share/classes/java/util/TimSort.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/TimSort.java Mon Dec 13 16:25:26 2010 -0800 @@ -239,7 +239,7 @@ * @param lo the index of the first element in the range to be sorted * @param hi the index after the last element in the range to be sorted * @param start the index of the first element in the range that is - * not already known to be sorted (@code lo <= start <= hi} + * not already known to be sorted ({@code lo <= start <= hi}) * @param c comparator to used for the sort */ @SuppressWarnings("fallthrough") @@ -278,7 +278,7 @@ */ int n = start - left; // The number of elements to move // Switch is just an optimization for arraycopy in default case - switch(n) { + switch (n) { case 2: a[left + 2] = a[left + 1]; case 1: a[left + 1] = a[left]; break; @@ -308,7 +308,7 @@ * @param a the array in which a run is to be counted and possibly reversed * @param lo index of the first element in the run * @param hi index after the last element that may be contained in the run. - It is required that @code{lo < hi}. + It is required that {@code lo < hi}. * @param c the comparator to used for the sort * @return the length of the run beginning at the specified position in * the specified array @@ -322,7 +322,7 @@ // Find end of run, and reverse range if descending if (c.compare(a[runHi++], a[lo]) < 0) { // Descending - while(runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0) + while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0) runHi++; reverseRange(a, lo, runHi); } else { // Ascending
--- a/src/share/classes/java/util/TreeMap.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/TreeMap.java Mon Dec 13 16:25:26 2010 -0800 @@ -1056,11 +1056,11 @@ public Comparator<? super E> comparator() { return m.comparator(); } public E pollFirst() { Map.Entry<E,Object> e = m.pollFirstEntry(); - return e == null? null : e.getKey(); + return (e == null) ? null : e.getKey(); } public E pollLast() { Map.Entry<E,Object> e = m.pollLastEntry(); - return e == null? null : e.getKey(); + return (e == null) ? null : e.getKey(); } public boolean remove(Object o) { int oldSize = size(); @@ -1196,7 +1196,7 @@ * Test two values for equality. Differs from o1.equals(o2) only in * that it copes with {@code null} o1 properly. */ - final static boolean valEquals(Object o1, Object o2) { + static final boolean valEquals(Object o1, Object o2) { return (o1==null ? o2==null : o1.equals(o2)); } @@ -1204,7 +1204,7 @@ * Return SimpleImmutableEntry for entry, or null if null */ static <K,V> Map.Entry<K,V> exportEntry(TreeMap.Entry<K,V> e) { - return e == null? null : + return (e == null) ? null : new AbstractMap.SimpleImmutableEntry<K,V>(e); } @@ -1212,7 +1212,7 @@ * Return key for entry, or null if null */ static <K,V> K keyOrNull(TreeMap.Entry<K,V> e) { - return e == null? null : e.key; + return (e == null) ? null : e.key; } /** @@ -1237,7 +1237,7 @@ /** * @serial include */ - static abstract class NavigableSubMap<K,V> extends AbstractMap<K,V> + abstract static class NavigableSubMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, java.io.Serializable { /** * The backing map. @@ -1412,11 +1412,11 @@ } public final V get(Object key) { - return !inRange(key)? null : m.get(key); + return !inRange(key) ? null : m.get(key); } public final V remove(Object key) { - return !inRange(key)? null : m.remove(key); + return !inRange(key) ? null : m.remove(key); } public final Map.Entry<K,V> ceilingEntry(K key) { @@ -1559,7 +1559,8 @@ if (!inRange(key)) return false; TreeMap.Entry<K,V> node = m.getEntry(key); - if (node!=null && valEquals(node.getValue(),entry.getValue())){ + if (node!=null && valEquals(node.getValue(), + entry.getValue())) { m.deleteEntry(node); return true; } @@ -1724,7 +1725,7 @@ false, toKey, inclusive); } - public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive){ + public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) { if (!inRange(fromKey, inclusive)) throw new IllegalArgumentException("fromKey out of range"); return new AscendingSubMap(m, @@ -1805,7 +1806,7 @@ toEnd, hi, hiInclusive); } - public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive){ + public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) { if (!inRange(fromKey, inclusive)) throw new IllegalArgumentException("fromKey out of range"); return new DescendingSubMap(m, @@ -2143,7 +2144,7 @@ // If strictly internal, copy successor's element to p and then make p // point to successor. if (p.left != null && p.right != null) { - Entry<K,V> s = successor (p); + Entry<K,V> s = successor(p); p.key = s.key; p.value = s.value; p = s;
--- a/src/share/classes/java/util/TreeSet.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/TreeSet.java Mon Dec 13 16:25:26 2010 -0800 @@ -452,7 +452,7 @@ */ public E pollFirst() { Map.Entry<E,?> e = m.pollFirstEntry(); - return (e == null)? null : e.getKey(); + return (e == null) ? null : e.getKey(); } /** @@ -460,7 +460,7 @@ */ public E pollLast() { Map.Entry<E,?> e = m.pollLastEntry(); - return (e == null)? null : e.getKey(); + return (e == null) ? null : e.getKey(); } /**
--- a/src/share/classes/java/util/Vector.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/Vector.java Mon Dec 13 16:25:26 2010 -0800 @@ -919,7 +919,7 @@ * elements (optional), or if the specified collection is null * @since 1.2 */ - public synchronized boolean retainAll(Collection<?> c) { + public synchronized boolean retainAll(Collection<?> c) { return super.retainAll(c); }
--- a/src/share/classes/java/util/concurrent/AbstractExecutorService.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/AbstractExecutorService.java Mon Dec 13 16:25:26 2010 -0800 @@ -51,20 +51,20 @@ * <p> <b>Extension example</b>. Here is a sketch of a class * that customizes {@link ThreadPoolExecutor} to use * a <tt>CustomTask</tt> class instead of the default <tt>FutureTask</tt>: - * <pre> + * <pre> {@code * public class CustomThreadPoolExecutor extends ThreadPoolExecutor { * - * static class CustomTask<V> implements RunnableFuture<V> {...} + * static class CustomTask<V> implements RunnableFuture<V> {...} * - * protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) { - * return new CustomTask<V>(c); + * protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) { + * return new CustomTask<V>(c); * } - * protected <V> RunnableFuture<V> newTaskFor(Runnable r, V v) { - * return new CustomTask<V>(r, v); + * protected <V> RunnableFuture<V> newTaskFor(Runnable r, V v) { + * return new CustomTask<V>(r, v); * } * // ... add constructors, etc. - * } - * </pre> + * }}</pre> + * * @since 1.5 * @author Doug Lea */ @@ -106,7 +106,7 @@ */ public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); - RunnableFuture<Object> ftask = newTaskFor(task, null); + RunnableFuture<Void> ftask = newTaskFor(task, null); execute(ftask); return ftask; } @@ -158,7 +158,7 @@ // Record exceptions so that if we fail to obtain any // result, we can throw the last exception we got. ExecutionException ee = null; - long lastTime = (timed)? System.nanoTime() : 0; + long lastTime = timed ? System.nanoTime() : 0; Iterator<? extends Callable<T>> it = tasks.iterator(); // Start one task for sure; the rest incrementally @@ -191,8 +191,6 @@ --active; try { return f.get(); - } catch (InterruptedException ie) { - throw ie; } catch (ExecutionException eex) { ee = eex; } catch (RuntimeException rex) {
--- a/src/share/classes/java/util/concurrent/ConcurrentHashMap.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/ConcurrentHashMap.java Mon Dec 13 16:25:26 2010 -0800 @@ -1270,7 +1270,7 @@ * for each key-value mapping, followed by a null pair. * The key-value mappings are emitted in no particular order. */ - private void writeObject(java.io.ObjectOutputStream s) throws IOException { + private void writeObject(java.io.ObjectOutputStream s) throws IOException { s.defaultWriteObject(); for (int k = 0; k < segments.length; ++k) { @@ -1298,7 +1298,7 @@ * @param s the stream */ private void readObject(java.io.ObjectInputStream s) - throws IOException, ClassNotFoundException { + throws IOException, ClassNotFoundException { s.defaultReadObject(); // Initialize each segment to be minimally sized, and let grow.
--- a/src/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java Mon Dec 13 16:25:26 2010 -0800 @@ -38,7 +38,6 @@ import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Collection; -import java.util.ConcurrentModificationException; import java.util.Deque; import java.util.Iterator; import java.util.NoSuchElementException; @@ -212,7 +211,7 @@ * The actual representation we use is that p.next == p means to * goto the first node (which in turn is reached by following prev * pointers from head), and p.next == null && p.prev == p means - * that the iteration is at an end and that p is a (final static) + * that the iteration is at an end and that p is a (static final) * dummy node, NEXT_TERMINATOR, and not the last active node. * Finishing the iteration when encountering such a TERMINATOR is * good enough for read-only traversals, so such traversals can use @@ -271,7 +270,7 @@ */ private transient volatile Node<E> tail; - private final static Node<Object> PREV_TERMINATOR, NEXT_TERMINATOR; + private static final Node<Object> PREV_TERMINATOR, NEXT_TERMINATOR; static { PREV_TERMINATOR = new Node<Object>(null); @@ -401,7 +400,7 @@ } } - private final static int HOPS = 2; + private static final int HOPS = 2; /** * Unlinks non-null node x. @@ -871,7 +870,7 @@ /** * Inserts the specified element at the front of this deque. * - * @throws NullPointerException {@inheritDoc} + * @throws NullPointerException if the specified element is null */ public void addFirst(E e) { linkFirst(e); @@ -882,7 +881,7 @@ * * <p>This method is equivalent to {@link #add}. * - * @throws NullPointerException {@inheritDoc} + * @throws NullPointerException if the specified element is null */ public void addLast(E e) { linkLast(e); @@ -892,7 +891,7 @@ * Inserts the specified element at the front of this deque. * * @return {@code true} always - * @throws NullPointerException {@inheritDoc} + * @throws NullPointerException if the specified element is null */ public boolean offerFirst(E e) { linkFirst(e); @@ -905,7 +904,7 @@ * <p>This method is equivalent to {@link #add}. * * @return {@code true} always - * @throws NullPointerException {@inheritDoc} + * @throws NullPointerException if the specified element is null */ public boolean offerLast(E e) { linkLast(e); @@ -940,7 +939,7 @@ /** * @throws NoSuchElementException {@inheritDoc} */ - public E getLast() { + public E getLast() { return screenNullResult(peekLast()); } @@ -1016,7 +1015,7 @@ * * @param o element to be removed from this deque, if present * @return {@code true} if the deque contained the specified element - * @throws NullPointerException if the specified element is {@code null} + * @throws NullPointerException if the specified element is null */ public boolean removeFirstOccurrence(Object o) { checkNotNull(o); @@ -1037,7 +1036,7 @@ * * @param o element to be removed from this deque, if present * @return {@code true} if the deque contained the specified element - * @throws NullPointerException if the specified element is {@code null} + * @throws NullPointerException if the specified element is null */ public boolean removeLastOccurrence(Object o) { checkNotNull(o); @@ -1110,7 +1109,7 @@ * * @param o element to be removed from this deque, if present * @return {@code true} if the deque contained the specified element - * @throws NullPointerException if the specified element is {@code null} + * @throws NullPointerException if the specified element is null */ public boolean remove(Object o) { return removeFirstOccurrence(o); @@ -1165,7 +1164,7 @@ beginningOfTheEnd.lazySetPrev(p); // CAS piggyback if (p.casNext(null, beginningOfTheEnd)) { // Successful CAS is the linearization point - // for all elements to be added to this queue. + // for all elements to be added to this deque. if (!casTail(t, last)) { // Try a little harder to update tail, // since we may be adding many elements. @@ -1251,12 +1250,12 @@ * Returns an iterator over the elements in this deque in proper sequence. * The elements will be returned in order from first (head) to last (tail). * - * <p>The returned {@code Iterator} is a "weakly consistent" iterator that + * <p>The returned iterator is a "weakly consistent" iterator that * will never throw {@link java.util.ConcurrentModificationException - * ConcurrentModificationException}, - * and guarantees to traverse elements as they existed upon - * construction of the iterator, and may (but is not guaranteed to) - * reflect any modifications subsequent to construction. + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. * * @return an iterator over the elements in this deque in proper sequence */ @@ -1269,12 +1268,12 @@ * sequential order. The elements will be returned in order from * last (tail) to first (head). * - * <p>The returned {@code Iterator} is a "weakly consistent" iterator that + * <p>The returned iterator is a "weakly consistent" iterator that * will never throw {@link java.util.ConcurrentModificationException - * ConcurrentModificationException}, - * and guarantees to traverse elements as they existed upon - * construction of the iterator, and may (but is not guaranteed to) - * reflect any modifications subsequent to construction. + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. * * @return an iterator over the elements in this deque in reverse order */
--- a/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java Mon Dec 13 16:25:26 2010 -0800 @@ -65,8 +65,8 @@ * <p>Iterators are <i>weakly consistent</i>, returning elements * reflecting the state of the queue at some point at or since the * creation of the iterator. They do <em>not</em> throw {@link - * ConcurrentModificationException}, and may proceed concurrently with - * other operations. Elements contained in the queue since the creation + * java.util.ConcurrentModificationException}, and may proceed concurrently + * with other operations. Elements contained in the queue since the creation * of the iterator will be returned exactly once. * * <p>Beware that, unlike in most collections, the {@code size} method @@ -634,12 +634,12 @@ * Returns an iterator over the elements in this queue in proper sequence. * The elements will be returned in order from first (head) to last (tail). * - * <p>The returned {@code Iterator} is a "weakly consistent" iterator that + * <p>The returned iterator is a "weakly consistent" iterator that * will never throw {@link java.util.ConcurrentModificationException - * ConcurrentModificationException}, - * and guarantees to traverse elements as they existed upon - * construction of the iterator, and may (but is not guaranteed to) - * reflect any modifications subsequent to construction. + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. * * @return an iterator over the elements in this queue in proper sequence */
--- a/src/share/classes/java/util/concurrent/ConcurrentSkipListSet.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/ConcurrentSkipListSet.java Mon Dec 13 16:25:26 2010 -0800 @@ -362,12 +362,12 @@ public E pollFirst() { Map.Entry<E,Object> e = m.pollFirstEntry(); - return e == null? null : e.getKey(); + return (e == null) ? null : e.getKey(); } public E pollLast() { Map.Entry<E,Object> e = m.pollLastEntry(); - return e == null? null : e.getKey(); + return (e == null) ? null : e.getKey(); }
--- a/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Mon Dec 13 16:25:26 2010 -0800 @@ -547,7 +547,7 @@ * @param fromIndex index of first element to be removed * @param toIndex index after last element to be removed * @throws IndexOutOfBoundsException if fromIndex or toIndex out of range - * (@code{fromIndex < 0 || toIndex > size() || toIndex < fromIndex}) + * ({@code{fromIndex < 0 || toIndex > size() || toIndex < fromIndex}) */ private void removeRange(int fromIndex, int toIndex) { final ReentrantLock lock = this.lock; @@ -989,7 +989,7 @@ } private static class COWIterator<E> implements ListIterator<E> { - /** Snapshot of the array **/ + /** Snapshot of the array */ private final Object[] snapshot; /** Index of element to be returned by subsequent call to next. */ private int cursor;
--- a/src/share/classes/java/util/concurrent/CopyOnWriteArraySet.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/CopyOnWriteArraySet.java Mon Dec 13 16:25:26 2010 -0800 @@ -59,24 +59,23 @@ * copy-on-write set to maintain a set of Handler objects that * perform some action upon state updates. * - * <pre> + * <pre> {@code * class Handler { void handle(); ... } * * class X { - * private final CopyOnWriteArraySet<Handler> handlers - * = new CopyOnWriteArraySet<Handler>(); - * public void addHandler(Handler h) { handlers.add(h); } + * private final CopyOnWriteArraySet<Handler> handlers + * = new CopyOnWriteArraySet<Handler>(); + * public void addHandler(Handler h) { handlers.add(h); } * - * private long internalState; - * private synchronized void changeState() { internalState = ...; } + * private long internalState; + * private synchronized void changeState() { internalState = ...; } * - * public void update() { - * changeState(); - * for (Handler handler : handlers) - * handler.handle(); - * } - * } - * </pre> + * public void update() { + * changeState(); + * for (Handler handler : handlers) + * handler.handle(); + * } + * }}</pre> * * <p>This class is a member of the * <a href="{@docRoot}/../technotes/guides/collections/index.html">
--- a/src/share/classes/java/util/concurrent/CountDownLatch.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/CountDownLatch.java Mon Dec 13 16:25:26 2010 -0800 @@ -175,7 +175,7 @@ } protected int tryAcquireShared(int acquires) { - return getState() == 0? 1 : -1; + return (getState() == 0) ? 1 : -1; } protected boolean tryReleaseShared(int releases) {
--- a/src/share/classes/java/util/concurrent/DelayQueue.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/DelayQueue.java Mon Dec 13 16:25:26 2010 -0800 @@ -482,12 +482,14 @@ /** * Returns an iterator over all the elements (both expired and * unexpired) in this queue. The iterator does not return the - * elements in any particular order. The returned - * <tt>Iterator</tt> is a "weakly consistent" iterator that will - * never throw {@link ConcurrentModificationException}, and - * guarantees to traverse elements as they existed upon - * construction of the iterator, and may (but is not guaranteed - * to) reflect any modifications subsequent to construction. + * elements in any particular order. + * + * <p>The returned iterator is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. * * @return an iterator over the elements in this queue */
--- a/src/share/classes/java/util/concurrent/Exchanger.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/Exchanger.java Mon Dec 13 16:25:26 2010 -0800 @@ -355,7 +355,9 @@ else if (y == null && // Try to occupy slot.compareAndSet(null, me)) { if (index == 0) // Blocking wait for slot 0 - return timed? awaitNanos(me, slot, nanos): await(me, slot); + return timed ? + awaitNanos(me, slot, nanos) : + await(me, slot); Object v = spinWait(me, slot); // Spin wait for non-0 if (v != CANCEL) return v; @@ -597,8 +599,8 @@ * dormant until one of two things happens: * <ul> * <li>Some other thread enters the exchange; or - * <li>Some other thread {@linkplain Thread#interrupt interrupts} the current - * thread. + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread. * </ul> * <p>If the current thread: * <ul> @@ -616,7 +618,7 @@ */ public V exchange(V x) throws InterruptedException { if (!Thread.interrupted()) { - Object v = doExchange(x == null? NULL_ITEM : x, false, 0); + Object v = doExchange((x == null) ? NULL_ITEM : x, false, 0); if (v == NULL_ITEM) return null; if (v != CANCEL) @@ -671,7 +673,7 @@ public V exchange(V x, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException { if (!Thread.interrupted()) { - Object v = doExchange(x == null? NULL_ITEM : x, + Object v = doExchange((x == null) ? NULL_ITEM : x, true, unit.toNanos(timeout)); if (v == NULL_ITEM) return null;
--- a/src/share/classes/java/util/concurrent/Executor.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/Executor.java Mon Dec 13 16:25:26 2010 -0800 @@ -79,37 +79,37 @@ * serializes the submission of tasks to a second executor, * illustrating a composite executor. * - * <pre> + * <pre> {@code * class SerialExecutor implements Executor { - * final Queue<Runnable> tasks = new ArrayDeque<Runnable>(); - * final Executor executor; - * Runnable active; + * final Queue<Runnable> tasks = new ArrayDeque<Runnable>(); + * final Executor executor; + * Runnable active; * - * SerialExecutor(Executor executor) { - * this.executor = executor; - * } + * SerialExecutor(Executor executor) { + * this.executor = executor; + * } * - * public synchronized void execute(final Runnable r) { - * tasks.offer(new Runnable() { - * public void run() { - * try { - * r.run(); - * } finally { - * scheduleNext(); - * } - * } - * }); - * if (active == null) { - * scheduleNext(); + * public synchronized void execute(final Runnable r) { + * tasks.offer(new Runnable() { + * public void run() { + * try { + * r.run(); + * } finally { + * scheduleNext(); * } + * } + * }); + * if (active == null) { + * scheduleNext(); * } + * } * - * protected synchronized void scheduleNext() { - * if ((active = tasks.poll()) != null) { - * executor.execute(active); - * } + * protected synchronized void scheduleNext() { + * if ((active = tasks.poll()) != null) { + * executor.execute(active); * } - * }</pre> + * } + * }}</pre> * * The <tt>Executor</tt> implementations provided in this package * implement {@link ExecutorService}, which is a more extensive
--- a/src/share/classes/java/util/concurrent/ExecutorCompletionService.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/ExecutorCompletionService.java Mon Dec 13 16:25:26 2010 -0800 @@ -197,7 +197,8 @@ return completionQueue.poll(); } - public Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException { + public Future<V> poll(long timeout, TimeUnit unit) + throws InterruptedException { return completionQueue.poll(timeout, unit); }
--- a/src/share/classes/java/util/concurrent/Executors.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/Executors.java Mon Dec 13 16:25:26 2010 -0800 @@ -83,7 +83,7 @@ * * @param nThreads the number of threads in the pool * @return the newly created thread pool - * @throws IllegalArgumentException if <tt>nThreads <= 0</tt> + * @throws IllegalArgumentException if {@code nThreads <= 0} */ public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, @@ -108,7 +108,7 @@ * @param threadFactory the factory to use when creating new threads * @return the newly created thread pool * @throws NullPointerException if threadFactory is null - * @throws IllegalArgumentException if <tt>nThreads <= 0</tt> + * @throws IllegalArgumentException if {@code nThreads <= 0} */ public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, @@ -242,7 +242,7 @@ * @param corePoolSize the number of threads to keep in the pool, * even if they are idle. * @return a newly created scheduled thread pool - * @throws IllegalArgumentException if <tt>corePoolSize < 0</tt> + * @throws IllegalArgumentException if {@code corePoolSize < 0} */ public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); @@ -256,7 +256,7 @@ * @param threadFactory the factory to use when the executor * creates a new thread. * @return a newly created scheduled thread pool - * @throws IllegalArgumentException if <tt>corePoolSize < 0</tt> + * @throws IllegalArgumentException if {@code corePoolSize < 0} * @throws NullPointerException if threadFactory is null */ public static ScheduledExecutorService newScheduledThreadPool( @@ -562,8 +562,8 @@ DefaultThreadFactory() { SecurityManager s = System.getSecurityManager(); - group = (s != null)? s.getThreadGroup() : - Thread.currentThread().getThreadGroup(); + group = (s != null) ? s.getThreadGroup() : + Thread.currentThread().getThreadGroup(); namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; @@ -669,7 +669,7 @@ FinalizableDelegatedExecutorService(ExecutorService executor) { super(executor); } - protected void finalize() { + protected void finalize() { super.shutdown(); } }
--- a/src/share/classes/java/util/concurrent/Future.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/Future.java Mon Dec 13 16:25:26 2010 -0800 @@ -47,21 +47,21 @@ * computation has completed, the computation cannot be cancelled. * If you would like to use a <tt>Future</tt> for the sake * of cancellability but not provide a usable result, you can - * declare types of the form <tt>Future<?></tt> and + * declare types of the form {@code Future<?>} and * return <tt>null</tt> as a result of the underlying task. * * <p> * <b>Sample Usage</b> (Note that the following classes are all * made-up.) <p> - * <pre> + * <pre> {@code * interface ArchiveSearcher { String search(String target); } * class App { * ExecutorService executor = ... * ArchiveSearcher searcher = ... * void showSearch(final String target) * throws InterruptedException { - * Future<String> future - * = executor.submit(new Callable<String>() { + * Future<String> future + * = executor.submit(new Callable<String>() { * public String call() { * return searcher.search(target); * }}); @@ -70,20 +70,18 @@ * displayText(future.get()); // use future * } catch (ExecutionException ex) { cleanup(); return; } * } - * } - * </pre> + * }}</pre> * * The {@link FutureTask} class is an implementation of <tt>Future</tt> that * implements <tt>Runnable</tt>, and so may be executed by an <tt>Executor</tt>. * For example, the above construction with <tt>submit</tt> could be replaced by: - * <pre> - * FutureTask<String> future = - * new FutureTask<String>(new Callable<String>() { + * <pre> {@code + * FutureTask<String> future = + * new FutureTask<String>(new Callable<String>() { * public String call() { * return searcher.search(target); * }}); - * executor.execute(future); - * </pre> + * executor.execute(future);}</pre> * * <p>Memory consistency effects: Actions taken by the asynchronous computation * <a href="package-summary.html#MemoryVisibility"> <i>happen-before</i></a>
--- a/src/share/classes/java/util/concurrent/FutureTask.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/FutureTask.java Mon Dec 13 16:25:26 2010 -0800 @@ -85,7 +85,7 @@ * @param result the result to return on successful completion. If * you don't need a particular result, consider using * constructions of the form: - * <tt>Future<?> f = new FutureTask<Object>(runnable, null)</tt> + * {@code Future<?> f = new FutureTask<Void>(runnable, null)} * @throws NullPointerException if runnable is null */ public FutureTask(Runnable runnable, V result) {
--- a/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java Mon Dec 13 16:25:26 2010 -0800 @@ -1004,12 +1004,13 @@ /** * Returns an iterator over the elements in this deque in proper sequence. * The elements will be returned in order from first (head) to last (tail). - * The returned {@code Iterator} is a "weakly consistent" iterator that + * + * <p>The returned iterator is a "weakly consistent" iterator that * will never throw {@link java.util.ConcurrentModificationException - * ConcurrentModificationException}, - * and guarantees to traverse elements as they existed upon - * construction of the iterator, and may (but is not guaranteed to) - * reflect any modifications subsequent to construction. + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. * * @return an iterator over the elements in this deque in proper sequence */ @@ -1021,12 +1022,13 @@ * Returns an iterator over the elements in this deque in reverse * sequential order. The elements will be returned in order from * last (tail) to first (head). - * The returned {@code Iterator} is a "weakly consistent" iterator that + * + * <p>The returned iterator is a "weakly consistent" iterator that * will never throw {@link java.util.ConcurrentModificationException - * ConcurrentModificationException}, - * and guarantees to traverse elements as they existed upon - * construction of the iterator, and may (but is not guaranteed to) - * reflect any modifications subsequent to construction. + * ConcurrentModificationException}, and guarantees to traverse + * elements as they existed upon construction of the iterator, and + * may (but is not guaranteed to) reflect any modifications + * subsequent to construction. */ public Iterator<E> descendingIterator() { return new DescendingItr();
--- a/src/share/classes/java/util/concurrent/RecursiveAction.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/RecursiveAction.java Mon Dec 13 16:25:26 2010 -0800 @@ -159,7 +159,9 @@ protected abstract void compute(); /** - * Always returns null. + * Always returns {@code null}. + * + * @return {@code null} always */ public final Void getRawResult() { return null; }
--- a/src/share/classes/java/util/concurrent/ScheduledExecutorService.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/ScheduledExecutorService.java Mon Dec 13 16:25:26 2010 -0800 @@ -72,24 +72,23 @@ * Here is a class with a method that sets up a ScheduledExecutorService * to beep every ten seconds for an hour: * - * <pre> + * <pre> {@code * import static java.util.concurrent.TimeUnit.*; * class BeeperControl { - * private final ScheduledExecutorService scheduler = - * Executors.newScheduledThreadPool(1); + * private final ScheduledExecutorService scheduler = + * Executors.newScheduledThreadPool(1); * - * public void beepForAnHour() { - * final Runnable beeper = new Runnable() { - * public void run() { System.out.println("beep"); } - * }; - * final ScheduledFuture<?> beeperHandle = - * scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS); - * scheduler.schedule(new Runnable() { - * public void run() { beeperHandle.cancel(true); } - * }, 60 * 60, SECONDS); - * } - * } - * </pre> + * public void beepForAnHour() { + * final Runnable beeper = new Runnable() { + * public void run() { System.out.println("beep"); } + * }; + * final ScheduledFuture<?> beeperHandle = + * scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS); + * scheduler.schedule(new Runnable() { + * public void run() { beeperHandle.cancel(true); } + * }, 60 * 60, SECONDS); + * } + * }}</pre> * * @since 1.5 * @author Doug Lea
--- a/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java Mon Dec 13 16:25:26 2010 -0800 @@ -62,8 +62,8 @@ * time of cancellation. * * <p>Successive executions of a task scheduled via - * <code>scheduleAtFixedRate</code> or - * <code>scheduleWithFixedDelay</code> do not overlap. While different + * {@code scheduleAtFixedRate} or + * {@code scheduleWithFixedDelay} do not overlap. While different * executions may be performed by different threads, the effects of * prior executions <a * href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> @@ -436,7 +436,7 @@ * @throws NullPointerException if {@code threadFactory} is null */ public ScheduledThreadPoolExecutor(int corePoolSize, - ThreadFactory threadFactory) { + ThreadFactory threadFactory) { super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, new DelayedWorkQueue(), threadFactory); } @@ -453,7 +453,7 @@ * @throws NullPointerException if {@code handler} is null */ public ScheduledThreadPoolExecutor(int corePoolSize, - RejectedExecutionHandler handler) { + RejectedExecutionHandler handler) { super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, new DelayedWorkQueue(), handler); } @@ -473,8 +473,8 @@ * {@code handler} is null */ public ScheduledThreadPoolExecutor(int corePoolSize, - ThreadFactory threadFactory, - RejectedExecutionHandler handler) { + ThreadFactory threadFactory, + RejectedExecutionHandler handler) { super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS, new DelayedWorkQueue(), threadFactory, handler); }
--- a/src/share/classes/java/util/concurrent/Semaphore.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/Semaphore.java Mon Dec 13 16:25:26 2010 -0800 @@ -223,7 +223,7 @@ /** * NonFair version */ - final static class NonfairSync extends Sync { + static final class NonfairSync extends Sync { private static final long serialVersionUID = -2694183684443567898L; NonfairSync(int permits) { @@ -238,7 +238,7 @@ /** * Fair version */ - final static class FairSync extends Sync { + static final class FairSync extends Sync { private static final long serialVersionUID = 2014338818796000944L; FairSync(int permits) { @@ -282,7 +282,7 @@ * else {@code false} */ public Semaphore(int permits, boolean fair) { - sync = (fair)? new FairSync(permits) : new NonfairSync(permits); + sync = fair ? new FairSync(permits) : new NonfairSync(permits); } /**
--- a/src/share/classes/java/util/concurrent/ThreadLocalRandom.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/ThreadLocalRandom.java Mon Dec 13 16:25:26 2010 -0800 @@ -63,9 +63,9 @@ */ public class ThreadLocalRandom extends Random { // same constants as Random, but must be redeclared because private - private final static long multiplier = 0x5DEECE66DL; - private final static long addend = 0xBL; - private final static long mask = (1L << 48) - 1; + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; /** * The random seed. We can't use super.seed.
--- a/src/share/classes/java/util/concurrent/TimeUnit.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/TimeUnit.java Mon Dec 13 16:25:26 2010 -0800 @@ -53,12 +53,12 @@ * java.util.concurrent.locks.Lock lock} is not available: * * <pre> Lock lock = ...; - * if ( lock.tryLock(50L, TimeUnit.MILLISECONDS) ) ... + * if (lock.tryLock(50L, TimeUnit.MILLISECONDS)) ... * </pre> * while this code will timeout in 50 seconds: * <pre> * Lock lock = ...; - * if ( lock.tryLock(50L, TimeUnit.SECONDS) ) ... + * if (lock.tryLock(50L, TimeUnit.SECONDS)) ... * </pre> * * Note however, that there is no guarantee that a particular timeout @@ -291,7 +291,8 @@ abstract int excessNanos(long d, long m); /** - * Performs a timed <tt>Object.wait</tt> using this time unit. + * Performs a timed {@link Object#wait(long, int) Object.wait} + * using this time unit. * This is a convenience method that converts timeout arguments * into the form required by the <tt>Object.wait</tt> method. * @@ -299,21 +300,22 @@ * method (see {@link BlockingQueue#poll BlockingQueue.poll}) * using: * - * <pre> public synchronized Object poll(long timeout, TimeUnit unit) throws InterruptedException { - * while (empty) { - * unit.timedWait(this, timeout); - * ... - * } - * }</pre> + * <pre> {@code + * public synchronized Object poll(long timeout, TimeUnit unit) + * throws InterruptedException { + * while (empty) { + * unit.timedWait(this, timeout); + * ... + * } + * }}</pre> * * @param obj the object to wait on * @param timeout the maximum time to wait. If less than * or equal to zero, do not wait at all. - * @throws InterruptedException if interrupted while waiting. - * @see Object#wait(long, int) + * @throws InterruptedException if interrupted while waiting */ public void timedWait(Object obj, long timeout) - throws InterruptedException { + throws InterruptedException { if (timeout > 0) { long ms = toMillis(timeout); int ns = excessNanos(timeout, ms); @@ -322,17 +324,18 @@ } /** - * Performs a timed <tt>Thread.join</tt> using this time unit. + * Performs a timed {@link Thread#join(long, int) Thread.join} + * using this time unit. * This is a convenience method that converts time arguments into the * form required by the <tt>Thread.join</tt> method. + * * @param thread the thread to wait for * @param timeout the maximum time to wait. If less than * or equal to zero, do not wait at all. - * @throws InterruptedException if interrupted while waiting. - * @see Thread#join(long, int) + * @throws InterruptedException if interrupted while waiting */ public void timedJoin(Thread thread, long timeout) - throws InterruptedException { + throws InterruptedException { if (timeout > 0) { long ms = toMillis(timeout); int ns = excessNanos(timeout, ms); @@ -341,13 +344,14 @@ } /** - * Performs a <tt>Thread.sleep</tt> using this unit. + * Performs a {@link Thread#sleep(long, int) Thread.sleep} using + * this time unit. * This is a convenience method that converts time arguments into the * form required by the <tt>Thread.sleep</tt> method. + * * @param timeout the minimum time to sleep. If less than * or equal to zero, do not sleep at all. - * @throws InterruptedException if interrupted while sleeping. - * @see Thread#sleep + * @throws InterruptedException if interrupted while sleeping */ public void sleep(long timeout) throws InterruptedException { if (timeout > 0) {
--- a/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java Mon Dec 13 16:25:26 2010 -0800 @@ -55,7 +55,7 @@ * @author Doug Lea * @param <T> The type of the object holding the updatable field */ -public abstract class AtomicIntegerFieldUpdater<T> { +public abstract class AtomicIntegerFieldUpdater<T> { /** * Creates and returns an updater for objects with the given field. * The Class argument is needed to check that reflective types and @@ -279,7 +279,7 @@ sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers); sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); - } catch(Exception ex) { + } catch (Exception ex) { throw new RuntimeException(ex); }
--- a/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java Mon Dec 13 16:25:26 2010 -0800 @@ -55,7 +55,7 @@ * @author Doug Lea * @param <T> The type of the object holding the updatable field */ -public abstract class AtomicLongFieldUpdater<T> { +public abstract class AtomicLongFieldUpdater<T> { /** * Creates and returns an updater for objects with the given field. * The Class argument is needed to check that reflective types and @@ -278,7 +278,7 @@ sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers); sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); - } catch(Exception ex) { + } catch (Exception ex) { throw new RuntimeException(ex); } @@ -331,7 +331,7 @@ if (cclass.isInstance(obj)) { return; } - throw new RuntimeException ( + throw new RuntimeException( new IllegalAccessException("Class " + cclass.getName() + " can not access a protected member of class " + @@ -361,7 +361,7 @@ sun.reflect.misc.ReflectUtil.ensureMemberAccess( caller, tclass, null, modifiers); sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); - } catch(Exception ex) { + } catch (Exception ex) { throw new RuntimeException(ex); } @@ -387,7 +387,7 @@ public boolean compareAndSet(T obj, long expect, long update) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); - synchronized(this) { + synchronized (this) { long v = unsafe.getLong(obj, offset); if (v != expect) return false; @@ -402,7 +402,7 @@ public void set(T obj, long newValue) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); - synchronized(this) { + synchronized (this) { unsafe.putLong(obj, offset, newValue); } } @@ -413,7 +413,7 @@ public long get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); - synchronized(this) { + synchronized (this) { return unsafe.getLong(obj, offset); } } @@ -422,7 +422,7 @@ if (cclass.isInstance(obj)) { return; } - throw new RuntimeException ( + throw new RuntimeException( new IllegalAccessException("Class " + cclass.getName() + " can not access a protected member of class " +
--- a/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java Mon Dec 13 16:25:26 2010 -0800 @@ -45,13 +45,13 @@ * independently subject to atomic updates. For example, a tree node * might be declared as * - * <pre> + * <pre> {@code * class Node { * private volatile Node left, right; * - * private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater = + * private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater = * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left"); - * private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater = + * private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater = * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right"); * * Node getLeft() { return left; } @@ -59,8 +59,7 @@ * return leftUpdater.compareAndSet(this, expect, update); * } * // ... and so on - * } - * </pre> + * }}</pre> * * <p>Note that the guarantees of the {@code compareAndSet} * method in this class are weaker than in other atomic classes. @@ -74,7 +73,7 @@ * @param <T> The type of the object holding the updatable field * @param <V> The type of the field */ -public abstract class AtomicReferenceFieldUpdater<T, V> { +public abstract class AtomicReferenceFieldUpdater<T, V> { /** * Creates and returns an updater for objects with the given field. @@ -291,7 +290,7 @@ if (cclass.isInstance(obj)) { return; } - throw new RuntimeException ( + throw new RuntimeException( new IllegalAccessException("Class " + cclass.getName() + " can not access a protected member of class " +
--- a/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java Mon Dec 13 16:25:26 2010 -0800 @@ -990,7 +990,8 @@ * can represent anything you like. * @throws InterruptedException if the current thread is interrupted */ - public final void acquireInterruptibly(long arg) throws InterruptedException { + public final void acquireInterruptibly(long arg) + throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (!tryAcquire(arg)) @@ -1014,7 +1015,8 @@ * @return {@code true} if acquired; {@code false} if timed out * @throws InterruptedException if the current thread is interrupted */ - public final boolean tryAcquireNanos(long arg, long nanosTimeout) throws InterruptedException { + public final boolean tryAcquireNanos(long arg, long nanosTimeout) + throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); return tryAcquire(arg) || @@ -1070,7 +1072,8 @@ * you like. * @throws InterruptedException if the current thread is interrupted */ - public final void acquireSharedInterruptibly(long arg) throws InterruptedException { + public final void acquireSharedInterruptibly(long arg) + throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (tryAcquireShared(arg) < 0) @@ -1093,7 +1096,8 @@ * @return {@code true} if acquired; {@code false} if timed out * @throws InterruptedException if the current thread is interrupted */ - public final boolean tryAcquireSharedNanos(long arg, long nanosTimeout) throws InterruptedException { + public final boolean tryAcquireSharedNanos(long arg, long nanosTimeout) + throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); return tryAcquireShared(arg) >= 0 || @@ -1841,7 +1845,8 @@ * <li> If interrupted while blocked in step 4, throw InterruptedException. * </ol> */ - public final long awaitNanos(long nanosTimeout) throws InterruptedException { + public final long awaitNanos(long nanosTimeout) + throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); @@ -1885,7 +1890,8 @@ * <li> If timed out while blocked in step 4, return false, else true. * </ol> */ - public final boolean awaitUntil(Date deadline) throws InterruptedException { + public final boolean awaitUntil(Date deadline) + throws InterruptedException { if (deadline == null) throw new NullPointerException(); long abstime = deadline.getTime(); @@ -1928,7 +1934,8 @@ * <li> If timed out while blocked in step 4, return false, else true. * </ol> */ - public final boolean await(long time, TimeUnit unit) throws InterruptedException { + public final boolean await(long time, TimeUnit unit) + throws InterruptedException { if (unit == null) throw new NullPointerException(); long nanosTimeout = unit.toNanos(time); @@ -2084,7 +2091,7 @@ /** * CAS waitStatus field of a node. */ - private final static boolean compareAndSetWaitStatus(Node node, + private static final boolean compareAndSetWaitStatus(Node node, int expect, int update) { return unsafe.compareAndSwapInt(node, waitStatusOffset, @@ -2094,7 +2101,7 @@ /** * CAS next field of a node. */ - private final static boolean compareAndSetNext(Node node, + private static final boolean compareAndSetNext(Node node, Node expect, Node update) { return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
--- a/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Mon Dec 13 16:25:26 2010 -0800 @@ -265,7 +265,7 @@ * boolean isSignalled() { return getState() != 0; } * * protected int tryAcquireShared(int ignore) { - * return isSignalled()? 1 : -1; + * return isSignalled() ? 1 : -1; * } * * protected boolean tryReleaseShared(int ignore) { @@ -1213,7 +1213,8 @@ * can represent anything you like. * @throws InterruptedException if the current thread is interrupted */ - public final void acquireInterruptibly(int arg) throws InterruptedException { + public final void acquireInterruptibly(int arg) + throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (!tryAcquire(arg)) @@ -1237,7 +1238,8 @@ * @return {@code true} if acquired; {@code false} if timed out * @throws InterruptedException if the current thread is interrupted */ - public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException { + public final boolean tryAcquireNanos(int arg, long nanosTimeout) + throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); return tryAcquire(arg) || @@ -1293,7 +1295,8 @@ * you like. * @throws InterruptedException if the current thread is interrupted */ - public final void acquireSharedInterruptibly(int arg) throws InterruptedException { + public final void acquireSharedInterruptibly(int arg) + throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (tryAcquireShared(arg) < 0) @@ -1316,7 +1319,8 @@ * @return {@code true} if acquired; {@code false} if timed out * @throws InterruptedException if the current thread is interrupted */ - public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException { + public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) + throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); return tryAcquireShared(arg) >= 0 || @@ -2062,7 +2066,8 @@ * <li> If interrupted while blocked in step 4, throw InterruptedException. * </ol> */ - public final long awaitNanos(long nanosTimeout) throws InterruptedException { + public final long awaitNanos(long nanosTimeout) + throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); @@ -2106,7 +2111,8 @@ * <li> If timed out while blocked in step 4, return false, else true. * </ol> */ - public final boolean awaitUntil(Date deadline) throws InterruptedException { + public final boolean awaitUntil(Date deadline) + throws InterruptedException { if (deadline == null) throw new NullPointerException(); long abstime = deadline.getTime(); @@ -2149,7 +2155,8 @@ * <li> If timed out while blocked in step 4, return false, else true. * </ol> */ - public final boolean await(long time, TimeUnit unit) throws InterruptedException { + public final boolean await(long time, TimeUnit unit) + throws InterruptedException { if (unit == null) throw new NullPointerException(); long nanosTimeout = unit.toNanos(time); @@ -2305,7 +2312,7 @@ /** * CAS waitStatus field of a node. */ - private final static boolean compareAndSetWaitStatus(Node node, + private static final boolean compareAndSetWaitStatus(Node node, int expect, int update) { return unsafe.compareAndSwapInt(node, waitStatusOffset, @@ -2315,7 +2322,7 @@ /** * CAS next field of a node. */ - private final static boolean compareAndSetNext(Node node, + private static final boolean compareAndSetNext(Node node, Node expect, Node update) { return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
--- a/src/share/classes/java/util/concurrent/locks/LockSupport.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/locks/LockSupport.java Mon Dec 13 16:25:26 2010 -0800 @@ -200,8 +200,8 @@ * <li>Some other thread invokes {@link #unpark unpark} with the * current thread as the target; or * - * <li>Some other thread {@linkplain Thread#interrupt interrupts} the current - * thread; or + * <li>Some other thread {@linkplain Thread#interrupt interrupts} + * the current thread; or * * <li>The specified waiting time elapses; or *
--- a/src/share/classes/java/util/concurrent/locks/ReentrantLock.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/locks/ReentrantLock.java Mon Dec 13 16:25:26 2010 -0800 @@ -116,7 +116,7 @@ * into fair and nonfair versions below. Uses AQS state to * represent the number of holds on the lock. */ - static abstract class Sync extends AbstractQueuedSynchronizer { + abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; /** @@ -200,7 +200,7 @@ /** * Sync object for non-fair locks */ - final static class NonfairSync extends Sync { + static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** @@ -222,7 +222,7 @@ /** * Sync object for fair locks */ - final static class FairSync extends Sync { + static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { @@ -269,7 +269,7 @@ * @param fair {@code true} if this lock should use a fair ordering policy */ public ReentrantLock(boolean fair) { - sync = (fair)? new FairSync() : new NonfairSync(); + sync = fair ? new FairSync() : new NonfairSync(); } /** @@ -440,7 +440,8 @@ * @throws NullPointerException if the time unit is null * */ - public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { + public boolean tryLock(long timeout, TimeUnit unit) + throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); }
--- a/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java Mon Dec 13 16:25:26 2010 -0800 @@ -155,7 +155,7 @@ * } * // Downgrade by acquiring read lock before releasing write lock * rwl.readLock().lock(); - * } finally { + * } finally { * rwl.writeLock().unlock(); // Unlock write, still hold read * } * } @@ -215,7 +215,8 @@ * @author Doug Lea * */ -public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { +public class ReentrantReadWriteLock + implements ReadWriteLock, java.io.Serializable { private static final long serialVersionUID = -6992448646407690164L; /** Inner class providing readlock */ private final ReentrantReadWriteLock.ReadLock readerLock; @@ -251,7 +252,7 @@ * Synchronization implementation for ReentrantReadWriteLock. * Subclassed into fair and nonfair versions. */ - static abstract class Sync extends AbstractQueuedSynchronizer { + abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 6317671515068378041L; /* @@ -618,7 +619,7 @@ final Thread getOwner() { // Must read state before owner to ensure memory consistency - return ((exclusiveCount(getState()) == 0)? + return ((exclusiveCount(getState()) == 0) ? null : getExclusiveOwnerThread()); } @@ -669,7 +670,7 @@ /** * Nonfair version of Sync */ - final static class NonfairSync extends Sync { + static final class NonfairSync extends Sync { private static final long serialVersionUID = -8159625535654395037L; final boolean writerShouldBlock() { return false; // writers can always barge @@ -689,7 +690,7 @@ /** * Fair version of Sync */ - final static class FairSync extends Sync { + static final class FairSync extends Sync { private static final long serialVersionUID = -2274990926593161451L; final boolean writerShouldBlock() { return hasQueuedPredecessors(); @@ -702,7 +703,7 @@ /** * The lock returned by method {@link ReentrantReadWriteLock#readLock}. */ - public static class ReadLock implements Lock, java.io.Serializable { + public static class ReadLock implements Lock, java.io.Serializable { private static final long serialVersionUID = -5992448646407690164L; private final Sync sync; @@ -867,7 +868,8 @@ * @throws NullPointerException if the time unit is null * */ - public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { + public boolean tryLock(long timeout, TimeUnit unit) + throws InterruptedException { return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); } @@ -908,7 +910,7 @@ /** * The lock returned by method {@link ReentrantReadWriteLock#writeLock}. */ - public static class WriteLock implements Lock, java.io.Serializable { + public static class WriteLock implements Lock, java.io.Serializable { private static final long serialVersionUID = -4992448646407690164L; private final Sync sync; @@ -1108,7 +1110,8 @@ * @throws NullPointerException if the time unit is null * */ - public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { + public boolean tryLock(long timeout, TimeUnit unit) + throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); }
--- a/src/share/classes/java/util/zip/ZipFile.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/java/util/zip/ZipFile.java Mon Dec 13 16:25:26 2010 -0800 @@ -315,7 +315,7 @@ private static native void freeEntry(long jzfile, long jzentry); // the outstanding inputstreams that need to be closed. - private Set<ZipFileInputStream> streams = new HashSet<ZipFileInputStream>(); + private Set<InputStream> streams = new HashSet<>(); /** * Returns an input stream for reading the contents of the specified @@ -348,55 +348,58 @@ return null; } in = new ZipFileInputStream(jzentry); - streams.add(in); - } - final ZipFileInputStream zfin = in; - switch (getEntryMethod(jzentry)) { - case STORED: - return zfin; - case DEFLATED: - // MORE: Compute good size for inflater stream: - long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack - if (size > 65536) size = 8192; - if (size <= 0) size = 4096; - return new InflaterInputStream(zfin, getInflater(), (int)size) { - private boolean isClosed = false; - public void close() throws IOException { - if (!isClosed) { - releaseInflater(inf); - this.in.close(); - isClosed = true; + switch (getEntryMethod(jzentry)) { + case STORED: + streams.add(in); + return in; + case DEFLATED: + final ZipFileInputStream zfin = in; + // MORE: Compute good size for inflater stream: + long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack + if (size > 65536) size = 8192; + if (size <= 0) size = 4096; + InputStream is = new InflaterInputStream(zfin, getInflater(), (int)size) { + private boolean isClosed = false; + + public void close() throws IOException { + if (!isClosed) { + super.close(); + releaseInflater(inf); + isClosed = true; + } } - } - // Override fill() method to provide an extra "dummy" byte - // at the end of the input stream. This is required when - // using the "nowrap" Inflater option. - protected void fill() throws IOException { - if (eof) { - throw new EOFException( - "Unexpected end of ZLIB input stream"); - } - len = this.in.read(buf, 0, buf.length); - if (len == -1) { - buf[0] = 0; - len = 1; - eof = true; + // Override fill() method to provide an extra "dummy" byte + // at the end of the input stream. This is required when + // using the "nowrap" Inflater option. + protected void fill() throws IOException { + if (eof) { + throw new EOFException( + "Unexpected end of ZLIB input stream"); + } + len = this.in.read(buf, 0, buf.length); + if (len == -1) { + buf[0] = 0; + len = 1; + eof = true; + } + inf.setInput(buf, 0, len); } - inf.setInput(buf, 0, len); - } - private boolean eof; + private boolean eof; - public int available() throws IOException { - if (isClosed) - return 0; - long avail = zfin.size() - inf.getBytesWritten(); - return avail > (long) Integer.MAX_VALUE ? - Integer.MAX_VALUE : (int) avail; - } - }; - default: - throw new ZipException("invalid compression method"); + public int available() throws IOException { + if (isClosed) + return 0; + long avail = zfin.size() - inf.getBytesWritten(); + return avail > (long) Integer.MAX_VALUE ? + Integer.MAX_VALUE : (int) avail; + } + }; + streams.add(is); + return is; + default: + throw new ZipException("invalid compression method"); + } } } @@ -539,9 +542,9 @@ closeRequested = true; if (streams.size() !=0) { - Set<ZipFileInputStream> copy = streams; - streams = new HashSet<ZipFileInputStream>(); - for (ZipFileInputStream is: copy) + Set<InputStream> copy = streams; + streams = new HashSet<InputStream>(); + for (InputStream is: copy) is.close(); }
--- a/src/share/classes/javax/sql/rowset/serial/SerialBlob.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/javax/sql/rowset/serial/SerialBlob.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, 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 @@ -166,8 +166,9 @@ length = (int)len; } - if (pos < 1 || length - pos < 0 ) { - throw new SerialException("Invalid arguments: position cannot be less that 1"); + if (pos < 1 || len - pos < 0 ) { + throw new SerialException("Invalid arguments: position cannot be " + + "less than 1 or greater than the length of the SerialBlob"); } pos--; // correct pos to array index
--- a/src/share/classes/sun/misc/FpUtils.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/misc/FpUtils.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010 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 @@ -29,9 +29,9 @@ import sun.misc.DoubleConsts; /** - * The class <code>FpUtils</code> contains static utility methods for - * manipulating and inspecting <code>float</code> and - * <code>double</code> floating-point numbers. These methods include + * The class {@code FpUtils} contains static utility methods for + * manipulating and inspecting {@code float} and + * {@code double} floating-point numbers. These methods include * functionality recommended or required by the IEEE 754 * floating-point standard. * @@ -136,7 +136,7 @@ // tests for exception cases. /** - * Returns unbiased exponent of a <code>double</code>. + * Returns unbiased exponent of a {@code double}. */ public static int getExponent(double d){ /* @@ -149,7 +149,7 @@ } /** - * Returns unbiased exponent of a <code>float</code>. + * Returns unbiased exponent of a {@code float}. */ public static int getExponent(float f){ /* @@ -185,15 +185,15 @@ * Returns the first floating-point argument with the sign of the * second floating-point argument. Note that unlike the {@link * FpUtils#copySign(double, double) copySign} method, this method - * does not require NaN <code>sign</code> arguments to be treated + * does not require NaN {@code sign} arguments to be treated * as positive values; implementations are permitted to treat some * NaN arguments as positive and other NaN arguments as negative * to allow greater performance. * * @param magnitude the parameter providing the magnitude of the result * @param sign the parameter providing the sign of the result - * @return a value with the magnitude of <code>magnitude</code> - * and the sign of <code>sign</code>. + * @return a value with the magnitude of {@code magnitude} + * and the sign of {@code sign}. * @author Joseph D. Darcy */ public static double rawCopySign(double magnitude, double sign) { @@ -208,15 +208,15 @@ * Returns the first floating-point argument with the sign of the * second floating-point argument. Note that unlike the {@link * FpUtils#copySign(float, float) copySign} method, this method - * does not require NaN <code>sign</code> arguments to be treated + * does not require NaN {@code sign} arguments to be treated * as positive values; implementations are permitted to treat some * NaN arguments as positive and other NaN arguments as negative * to allow greater performance. * * @param magnitude the parameter providing the magnitude of the result * @param sign the parameter providing the sign of the result - * @return a value with the magnitude of <code>magnitude</code> - * and the sign of <code>sign</code>. + * @return a value with the magnitude of {@code magnitude} + * and the sign of {@code sign}. * @author Joseph D. Darcy */ public static float rawCopySign(float magnitude, float sign) { @@ -230,129 +230,129 @@ /* ***************************************************************** */ /** - * Returns <code>true</code> if the argument is a finite - * floating-point value; returns <code>false</code> otherwise (for + * Returns {@code true} if the argument is a finite + * floating-point value; returns {@code false} otherwise (for * NaN and infinity arguments). * - * @param d the <code>double</code> value to be tested - * @return <code>true</code> if the argument is a finite - * floating-point value, <code>false</code> otherwise. + * @param d the {@code double} value to be tested + * @return {@code true} if the argument is a finite + * floating-point value, {@code false} otherwise. */ public static boolean isFinite(double d) { return Math.abs(d) <= DoubleConsts.MAX_VALUE; } /** - * Returns <code>true</code> if the argument is a finite - * floating-point value; returns <code>false</code> otherwise (for + * Returns {@code true} if the argument is a finite + * floating-point value; returns {@code false} otherwise (for * NaN and infinity arguments). * - * @param f the <code>float</code> value to be tested - * @return <code>true</code> if the argument is a finite - * floating-point value, <code>false</code> otherwise. + * @param f the {@code float} value to be tested + * @return {@code true} if the argument is a finite + * floating-point value, {@code false} otherwise. */ public static boolean isFinite(float f) { return Math.abs(f) <= FloatConsts.MAX_VALUE; } /** - * Returns <code>true</code> if the specified number is infinitely - * large in magnitude, <code>false</code> otherwise. + * Returns {@code true} if the specified number is infinitely + * large in magnitude, {@code false} otherwise. * * <p>Note that this method is equivalent to the {@link * Double#isInfinite(double) Double.isInfinite} method; the * functionality is included in this class for convenience. * * @param d the value to be tested. - * @return <code>true</code> if the value of the argument is positive - * infinity or negative infinity; <code>false</code> otherwise. + * @return {@code true} if the value of the argument is positive + * infinity or negative infinity; {@code false} otherwise. */ public static boolean isInfinite(double d) { return Double.isInfinite(d); } /** - * Returns <code>true</code> if the specified number is infinitely - * large in magnitude, <code>false</code> otherwise. + * Returns {@code true} if the specified number is infinitely + * large in magnitude, {@code false} otherwise. * * <p>Note that this method is equivalent to the {@link * Float#isInfinite(float) Float.isInfinite} method; the * functionality is included in this class for convenience. * * @param f the value to be tested. - * @return <code>true</code> if the argument is positive infinity or - * negative infinity; <code>false</code> otherwise. + * @return {@code true} if the argument is positive infinity or + * negative infinity; {@code false} otherwise. */ public static boolean isInfinite(float f) { return Float.isInfinite(f); } /** - * Returns <code>true</code> if the specified number is a - * Not-a-Number (NaN) value, <code>false</code> otherwise. + * Returns {@code true} if the specified number is a + * Not-a-Number (NaN) value, {@code false} otherwise. * * <p>Note that this method is equivalent to the {@link * Double#isNaN(double) Double.isNaN} method; the functionality is * included in this class for convenience. * * @param d the value to be tested. - * @return <code>true</code> if the value of the argument is NaN; - * <code>false</code> otherwise. + * @return {@code true} if the value of the argument is NaN; + * {@code false} otherwise. */ public static boolean isNaN(double d) { return Double.isNaN(d); } /** - * Returns <code>true</code> if the specified number is a - * Not-a-Number (NaN) value, <code>false</code> otherwise. + * Returns {@code true} if the specified number is a + * Not-a-Number (NaN) value, {@code false} otherwise. * * <p>Note that this method is equivalent to the {@link * Float#isNaN(float) Float.isNaN} method; the functionality is * included in this class for convenience. * * @param f the value to be tested. - * @return <code>true</code> if the argument is NaN; - * <code>false</code> otherwise. + * @return {@code true} if the argument is NaN; + * {@code false} otherwise. */ public static boolean isNaN(float f) { return Float.isNaN(f); } /** - * Returns <code>true</code> if the unordered relation holds + * Returns {@code true} if the unordered relation holds * between the two arguments. When two floating-point values are * unordered, one value is neither less than, equal to, nor * greater than the other. For the unordered relation to be true, - * at least one argument must be a <code>NaN</code>. + * at least one argument must be a {@code NaN}. * * @param arg1 the first argument * @param arg2 the second argument - * @return <code>true</code> if at least one argument is a NaN, - * <code>false</code> otherwise. + * @return {@code true} if at least one argument is a NaN, + * {@code false} otherwise. */ public static boolean isUnordered(double arg1, double arg2) { return isNaN(arg1) || isNaN(arg2); } /** - * Returns <code>true</code> if the unordered relation holds + * Returns {@code true} if the unordered relation holds * between the two arguments. When two floating-point values are * unordered, one value is neither less than, equal to, nor * greater than the other. For the unordered relation to be true, - * at least one argument must be a <code>NaN</code>. + * at least one argument must be a {@code NaN}. * * @param arg1 the first argument * @param arg2 the second argument - * @return <code>true</code> if at least one argument is a NaN, - * <code>false</code> otherwise. + * @return {@code true} if at least one argument is a NaN, + * {@code false} otherwise. */ public static boolean isUnordered(float arg1, float arg2) { return isNaN(arg1) || isNaN(arg2); } /** - * Returns unbiased exponent of a <code>double</code>; for + * Returns unbiased exponent of a {@code double}; for * subnormal values, the number is treated as if it were * normalized. That is for all finite, non-zero, positive numbers * <i>x</i>, <code>scalb(<i>x</i>, -ilogb(<i>x</i>))</code> is @@ -378,7 +378,6 @@ return (1<<30); // 2^30 else // infinite value return (1<<28); // 2^28 - // break; case DoubleConsts.MIN_EXPONENT-1: // zero or subnormal if(d == 0.0) { @@ -414,18 +413,16 @@ exponent < DoubleConsts.MIN_EXPONENT); return exponent; } - // break; default: assert( exponent >= DoubleConsts.MIN_EXPONENT && exponent <= DoubleConsts.MAX_EXPONENT); return exponent; - // break; } } /** - * Returns unbiased exponent of a <code>float</code>; for + * Returns unbiased exponent of a {@code float}; for * subnormal values, the number is treated as if it were * normalized. That is for all finite, non-zero, positive numbers * <i>x</i>, <code>scalb(<i>x</i>, -ilogb(<i>x</i>))</code> is @@ -451,7 +448,6 @@ return (1<<30); // 2^30 else // infinite value return (1<<28); // 2^28 - // break; case FloatConsts.MIN_EXPONENT-1: // zero or subnormal if(f == 0.0f) { @@ -487,13 +483,11 @@ exponent < FloatConsts.MIN_EXPONENT); return exponent; } - // break; default: assert( exponent >= FloatConsts.MIN_EXPONENT && exponent <= FloatConsts.MAX_EXPONENT); return exponent; - // break; } } @@ -534,22 +528,22 @@ */ /** - * Return <code>d</code> × - * 2<sup><code>scale_factor</code></sup> rounded as if performed + * Return {@code d} × + * 2<sup>{@code scale_factor}</sup> rounded as if performed * by a single correctly rounded floating-point multiply to a * member of the double value set. See <a * href="http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html#9208">§4.2.3</a> * of the <a href="http://java.sun.com/docs/books/jls/html/">Java * Language Specification</a> for a discussion of floating-point * value sets. If the exponent of the result is between the - * <code>double</code>'s minimum exponent and maximum exponent, + * {@code double}'s minimum exponent and maximum exponent, * the answer is calculated exactly. If the exponent of the - * result would be larger than <code>doubles</code>'s maximum + * result would be larger than {@code doubles}'s maximum * exponent, an infinity is returned. Note that if the result is - * subnormal, precision may be lost; that is, when <code>scalb(x, - * n)</code> is subnormal, <code>scalb(scalb(x, n), -n)</code> may + * subnormal, precision may be lost; that is, when {@code scalb(x, + * n)} is subnormal, {@code scalb(scalb(x, n), -n)} may * not equal <i>x</i>. When the result is non-NaN, the result has - * the same sign as <code>d</code>. + * the same sign as {@code d}. * *<p> * Special cases: @@ -562,8 +556,8 @@ * </ul> * * @param d number to be scaled by a power of two. - * @param scale_factor power of 2 used to scale <code>d</code> - * @return <code>d * </code>2<sup><code>scale_factor</code></sup> + * @param scale_factor power of 2 used to scale {@code d} + * @return {@code d * }2<sup>{@code scale_factor}</sup> * @author Joseph D. Darcy */ public static double scalb(double d, int scale_factor) { @@ -644,22 +638,22 @@ } /** - * Return <code>f </code>× - * 2<sup><code>scale_factor</code></sup> rounded as if performed + * Return {@code f} × + * 2<sup>{@code scale_factor}</sup> rounded as if performed * by a single correctly rounded floating-point multiply to a * member of the float value set. See <a * href="http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html#9208">§4.2.3</a> * of the <a href="http://java.sun.com/docs/books/jls/html/">Java * Language Specification</a> for a discussion of floating-point * value set. If the exponent of the result is between the - * <code>float</code>'s minimum exponent and maximum exponent, the + * {@code float}'s minimum exponent and maximum exponent, the * answer is calculated exactly. If the exponent of the result - * would be larger than <code>float</code>'s maximum exponent, an + * would be larger than {@code float}'s maximum exponent, an * infinity is returned. Note that if the result is subnormal, - * precision may be lost; that is, when <code>scalb(x, n)</code> - * is subnormal, <code>scalb(scalb(x, n), -n)</code> may not equal + * precision may be lost; that is, when {@code scalb(x, n)} + * is subnormal, {@code scalb(scalb(x, n), -n)} may not equal * <i>x</i>. When the result is non-NaN, the result has the same - * sign as <code>f</code>. + * sign as {@code f}. * *<p> * Special cases: @@ -672,8 +666,8 @@ * </ul> * * @param f number to be scaled by a power of two. - * @param scale_factor power of 2 used to scale <code>f</code> - * @return <code>f * </code>2<sup><code>scale_factor</code></sup> + * @param scale_factor power of 2 used to scale {@code f} + * @return {@code f * }2<sup>{@code scale_factor}</sup> * @author Joseph D. Darcy */ public static float scalb(float f, int scale_factor) { @@ -709,34 +703,34 @@ * <ul> * <li> If either argument is a NaN, then NaN is returned. * - * <li> If both arguments are signed zeros, <code>direction</code> + * <li> If both arguments are signed zeros, {@code direction} * is returned unchanged (as implied by the requirement of * returning the second argument if the arguments compare as * equal). * - * <li> If <code>start</code> is - * ±<code>Double.MIN_VALUE</code> and <code>direction</code> + * <li> If {@code start} is + * ±{@code Double.MIN_VALUE} and {@code direction} * has a value such that the result should have a smaller - * magnitude, then a zero with the same sign as <code>start</code> + * magnitude, then a zero with the same sign as {@code start} * is returned. * - * <li> If <code>start</code> is infinite and - * <code>direction</code> has a value such that the result should - * have a smaller magnitude, <code>Double.MAX_VALUE</code> with the - * same sign as <code>start</code> is returned. + * <li> If {@code start} is infinite and + * {@code direction} has a value such that the result should + * have a smaller magnitude, {@code Double.MAX_VALUE} with the + * same sign as {@code start} is returned. * - * <li> If <code>start</code> is equal to ± - * <code>Double.MAX_VALUE</code> and <code>direction</code> has a + * <li> If {@code start} is equal to ± + * {@code Double.MAX_VALUE} and {@code direction} has a * value such that the result should have a larger magnitude, an - * infinity with same sign as <code>start</code> is returned. + * infinity with same sign as {@code start} is returned. * </ul> * * @param start starting floating-point value * @param direction value indicating which of - * <code>start</code>'s neighbors or <code>start</code> should + * {@code start}'s neighbors or {@code start} should * be returned - * @return The floating-point number adjacent to <code>start</code> in the - * direction of <code>direction</code>. + * @return The floating-point number adjacent to {@code start} in the + * direction of {@code direction}. * @author Joseph D. Darcy */ public static double nextAfter(double start, double direction) { @@ -809,34 +803,34 @@ * <ul> * <li> If either argument is a NaN, then NaN is returned. * - * <li> If both arguments are signed zeros, a <code>float</code> - * zero with the same sign as <code>direction</code> is returned + * <li> If both arguments are signed zeros, a {@code float} + * zero with the same sign as {@code direction} is returned * (as implied by the requirement of returning the second argument * if the arguments compare as equal). * - * <li> If <code>start</code> is - * ±<code>Float.MIN_VALUE</code> and <code>direction</code> + * <li> If {@code start} is + * ±{@code Float.MIN_VALUE} and {@code direction} * has a value such that the result should have a smaller - * magnitude, then a zero with the same sign as <code>start</code> + * magnitude, then a zero with the same sign as {@code start} * is returned. * - * <li> If <code>start</code> is infinite and - * <code>direction</code> has a value such that the result should - * have a smaller magnitude, <code>Float.MAX_VALUE</code> with the - * same sign as <code>start</code> is returned. + * <li> If {@code start} is infinite and + * {@code direction} has a value such that the result should + * have a smaller magnitude, {@code Float.MAX_VALUE} with the + * same sign as {@code start} is returned. * - * <li> If <code>start</code> is equal to ± - * <code>Float.MAX_VALUE</code> and <code>direction</code> has a + * <li> If {@code start} is equal to ± + * {@code Float.MAX_VALUE} and {@code direction} has a * value such that the result should have a larger magnitude, an - * infinity with same sign as <code>start</code> is returned. + * infinity with same sign as {@code start} is returned. * </ul> * * @param start starting floating-point value * @param direction value indicating which of - * <code>start</code>'s neighbors or <code>start</code> should + * {@code start}'s neighbors or {@code start} should * be returned - * @return The floating-point number adjacent to <code>start</code> in the - * direction of <code>direction</code>. + * @return The floating-point number adjacent to {@code start} in the + * direction of {@code direction}. * @author Joseph D. Darcy */ public static float nextAfter(float start, double direction) { @@ -900,12 +894,12 @@ } /** - * Returns the floating-point value adjacent to <code>d</code> in + * Returns the floating-point value adjacent to {@code d} in * the direction of positive infinity. This method is - * semantically equivalent to <code>nextAfter(d, - * Double.POSITIVE_INFINITY)</code>; however, a <code>nextUp</code> + * semantically equivalent to {@code nextAfter(d, + * Double.POSITIVE_INFINITY)}; however, a {@code nextUp} * implementation may run faster than its equivalent - * <code>nextAfter</code> call. + * {@code nextAfter} call. * * <p>Special Cases: * <ul> @@ -915,7 +909,7 @@ * positive infinity. * * <li> If the argument is zero, the result is - * <code>Double.MIN_VALUE</code> + * {@code Double.MIN_VALUE} * * </ul> * @@ -935,12 +929,12 @@ } /** - * Returns the floating-point value adjacent to <code>f</code> in + * Returns the floating-point value adjacent to {@code f} in * the direction of positive infinity. This method is - * semantically equivalent to <code>nextAfter(f, - * Double.POSITIVE_INFINITY)</code>; however, a <code>nextUp</code> + * semantically equivalent to {@code nextAfter(f, + * Double.POSITIVE_INFINITY)}; however, a {@code nextUp} * implementation may run faster than its equivalent - * <code>nextAfter</code> call. + * {@code nextAfter} call. * * <p>Special Cases: * <ul> @@ -950,7 +944,7 @@ * positive infinity. * * <li> If the argument is zero, the result is - * <code>Float.MIN_VALUE</code> + * {@code Float.MIN_VALUE} * * </ul> * @@ -970,12 +964,12 @@ } /** - * Returns the floating-point value adjacent to <code>d</code> in + * Returns the floating-point value adjacent to {@code d} in * the direction of negative infinity. This method is - * semantically equivalent to <code>nextAfter(d, - * Double.NEGATIVE_INFINITY)</code>; however, a - * <code>nextDown</code> implementation may run faster than its - * equivalent <code>nextAfter</code> call. + * semantically equivalent to {@code nextAfter(d, + * Double.NEGATIVE_INFINITY)}; however, a + * {@code nextDown} implementation may run faster than its + * equivalent {@code nextAfter} call. * * <p>Special Cases: * <ul> @@ -985,7 +979,7 @@ * negative infinity. * * <li> If the argument is zero, the result is - * <code>-Double.MIN_VALUE</code> + * {@code -Double.MIN_VALUE} * * </ul> * @@ -1007,12 +1001,12 @@ } /** - * Returns the floating-point value adjacent to <code>f</code> in + * Returns the floating-point value adjacent to {@code f} in * the direction of negative infinity. This method is - * semantically equivalent to <code>nextAfter(f, - * Float.NEGATIVE_INFINITY)</code>; however, a - * <code>nextDown</code> implementation may run faster than its - * equivalent <code>nextAfter</code> call. + * semantically equivalent to {@code nextAfter(f, + * Float.NEGATIVE_INFINITY)}; however, a + * {@code nextDown} implementation may run faster than its + * equivalent {@code nextAfter} call. * * <p>Special Cases: * <ul> @@ -1022,7 +1016,7 @@ * negative infinity. * * <li> If the argument is zero, the result is - * <code>-Float.MIN_VALUE</code> + * {@code -Float.MIN_VALUE} * * </ul> * @@ -1046,13 +1040,13 @@ /** * Returns the first floating-point argument with the sign of the * second floating-point argument. For this method, a NaN - * <code>sign</code> argument is always treated as if it were + * {@code sign} argument is always treated as if it were * positive. * * @param magnitude the parameter providing the magnitude of the result * @param sign the parameter providing the sign of the result - * @return a value with the magnitude of <code>magnitude</code> - * and the sign of <code>sign</code>. + * @return a value with the magnitude of {@code magnitude} + * and the sign of {@code sign}. * @author Joseph D. Darcy * @since 1.5 */ @@ -1063,13 +1057,13 @@ /** * Returns the first floating-point argument with the sign of the * second floating-point argument. For this method, a NaN - * <code>sign</code> argument is always treated as if it were + * {@code sign} argument is always treated as if it were * positive. * * @param magnitude the parameter providing the magnitude of the result * @param sign the parameter providing the sign of the result - * @return a value with the magnitude of <code>magnitude</code> - * and the sign of <code>sign</code>. + * @return a value with the magnitude of {@code magnitude} + * and the sign of {@code sign}. * @author Joseph D. Darcy */ public static float copySign(float magnitude, float sign) { @@ -1078,8 +1072,8 @@ /** * Returns the size of an ulp of the argument. An ulp of a - * <code>double</code> value is the positive distance between this - * floating-point value and the <code>double</code> value next + * {@code double} value is the positive distance between this + * floating-point value and the {@code double} value next * larger in magnitude. Note that for non-NaN <i>x</i>, * <code>ulp(-<i>x</i>) == ulp(<i>x</i>)</code>. * @@ -1089,8 +1083,8 @@ * <li> If the argument is positive or negative infinity, then the * result is positive infinity. * <li> If the argument is positive or negative zero, then the result is - * <code>Double.MIN_VALUE</code>. - * <li> If the argument is ±<code>Double.MAX_VALUE</code>, then + * {@code Double.MIN_VALUE}. + * <li> If the argument is ±{@code Double.MAX_VALUE}, then * the result is equal to 2<sup>971</sup>. * </ul> * @@ -1105,11 +1099,9 @@ switch(exp) { case DoubleConsts.MAX_EXPONENT+1: // NaN or infinity return Math.abs(d); - // break; case DoubleConsts.MIN_EXPONENT-1: // zero or subnormal return Double.MIN_VALUE; - // break default: assert exp <= DoubleConsts.MAX_EXPONENT && exp >= DoubleConsts.MIN_EXPONENT; @@ -1126,14 +1118,13 @@ return Double.longBitsToDouble(1L << (exp - (DoubleConsts.MIN_EXPONENT - (DoubleConsts.SIGNIFICAND_WIDTH-1)) )); } - // break } } /** * Returns the size of an ulp of the argument. An ulp of a - * <code>float</code> value is the positive distance between this - * floating-point value and the <code>float</code> value next + * {@code float} value is the positive distance between this + * floating-point value and the {@code float} value next * larger in magnitude. Note that for non-NaN <i>x</i>, * <code>ulp(-<i>x</i>) == ulp(<i>x</i>)</code>. * @@ -1143,8 +1134,8 @@ * <li> If the argument is positive or negative infinity, then the * result is positive infinity. * <li> If the argument is positive or negative zero, then the result is - * <code>Float.MIN_VALUE</code>. - * <li> If the argument is ±<code>Float.MAX_VALUE</code>, then + * {@code Float.MIN_VALUE}. + * <li> If the argument is ±{@code Float.MAX_VALUE}, then * the result is equal to 2<sup>104</sup>. * </ul> * @@ -1159,11 +1150,9 @@ switch(exp) { case FloatConsts.MAX_EXPONENT+1: // NaN or infinity return Math.abs(f); - // break; case FloatConsts.MIN_EXPONENT-1: // zero or subnormal return FloatConsts.MIN_VALUE; - // break default: assert exp <= FloatConsts.MAX_EXPONENT && exp >= FloatConsts.MIN_EXPONENT; @@ -1180,7 +1169,6 @@ return Float.intBitsToFloat(1 << (exp - (FloatConsts.MIN_EXPONENT - (FloatConsts.SIGNIFICAND_WIDTH-1)) )); } - // break } }
--- a/src/share/classes/sun/misc/VM.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/misc/VM.java Mon Dec 13 16:25:26 2010 -0800 @@ -25,6 +25,7 @@ package sun.misc; +import static java.lang.Thread.State.*; import java.util.Properties; import java.util.HashMap; import java.util.Map; @@ -332,69 +333,37 @@ } } - + /** + * Returns Thread.State for the given threadStatus + */ public static Thread.State toThreadState(int threadStatus) { - // Initialize the threadStateMap - initThreadStateMap(); - - Thread.State s = threadStateMap.get(threadStatus); - if (s == null) { - // default to RUNNABLE if the threadStatus value is unknown - s = Thread.State.RUNNABLE; + if ((threadStatus & JVMTI_THREAD_STATE_RUNNABLE) != 0) { + return RUNNABLE; + } else if ((threadStatus & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) != 0) { + return BLOCKED; + } else if ((threadStatus & JVMTI_THREAD_STATE_WAITING_INDEFINITELY) != 0) { + return WAITING; + } else if ((threadStatus & JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT) != 0) { + return TIMED_WAITING; + } else if ((threadStatus & JVMTI_THREAD_STATE_TERMINATED) != 0) { + return TERMINATED; + } else if ((threadStatus & JVMTI_THREAD_STATE_ALIVE) == 0) { + return NEW; + } else { + return RUNNABLE; } - return s; } - // a map of threadStatus values to the corresponding Thread.State - private static Map<Integer, Thread.State> threadStateMap = null; - private static Map<Integer, String> threadStateNames = null; - - private synchronized static void initThreadStateMap() { - if (threadStateMap != null) { - return; - } - - final Thread.State[] ts = Thread.State.values(); - - final int[][] vmThreadStateValues = new int[ts.length][]; - final String[][] vmThreadStateNames = new String[ts.length][]; - getThreadStateValues(vmThreadStateValues, vmThreadStateNames); - - threadStateMap = new HashMap<Integer, Thread.State>(); - threadStateNames = new HashMap<Integer, String>(); - for (int i = 0; i < ts.length; i++) { - String state = ts[i].name(); - int[] values = null; - String[] names = null; - for (int j = 0; j < ts.length; j++) { - if (vmThreadStateNames[j][0].startsWith(state)) { - values = vmThreadStateValues[j]; - names = vmThreadStateNames[j]; - } - } - if (values == null) { - throw new InternalError("No VM thread state mapped to " + - state); - } - if (values.length != names.length) { - throw new InternalError("VM thread state values and names " + - " mapped to " + state + ": length not matched" ); - } - for (int k = 0; k < values.length; k++) { - threadStateMap.put(values[k], ts[i]); - threadStateNames.put(values[k], names[k]); - } - } - } - // Fill in vmThreadStateValues with int arrays, each of which contains - // the threadStatus values mapping to the Thread.State enum constant. - // Fill in vmThreadStateNames with String arrays, each of which contains - // the name of each threadStatus value of the format: - // <Thread.State.name()>[.<Substate name>] - // e.g. WAITING.OBJECT_WAIT - // - private native static void getThreadStateValues(int[][] vmThreadStateValues, - String[][] vmThreadStateNames); + /* The threadStatus field is set by the VM at state transition + * in the hotspot implementation. Its value is set according to + * the JVM TI specification GetThreadState function. + */ + private final static int JVMTI_THREAD_STATE_ALIVE = 0x0001; + private final static int JVMTI_THREAD_STATE_TERMINATED = 0x0002; + private final static int JVMTI_THREAD_STATE_RUNNABLE = 0x0004; + private final static int JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER = 0x0400; + private final static int JVMTI_THREAD_STATE_WAITING_INDEFINITELY = 0x0010; + private final static int JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT = 0x0020; static { initialize();
--- a/src/share/classes/sun/net/httpserver/Request.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/net/httpserver/Request.java Mon Dec 13 16:25:26 2010 -0800 @@ -129,9 +129,22 @@ hdrs = new Headers(); char s[] = new char[10]; + int len = 0; + int firstc = is.read(); + + // check for empty headers + if (firstc == CR || firstc == LF) { + int c = is.read(); + if (c == CR || c == LF) { + return hdrs; + } + s[0] = (char)firstc; + len = 1; + firstc = c; + } + while (firstc != LF && firstc != CR && firstc >= 0) { - int len = 0; int keyend = -1; int c; boolean inKey = firstc > ' '; @@ -191,6 +204,7 @@ else v = String.copyValueOf(s, keyend, len - keyend); hdrs.add (k,v); + len = 0; } return hdrs; }
--- a/src/share/classes/sun/net/httpserver/SSLStreams.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/net/httpserver/SSLStreams.java Mon Dec 13 16:25:26 2010 -0800 @@ -74,8 +74,8 @@ private void configureEngine(HttpsConfigurator cfg, InetSocketAddress addr){ if (cfg != null) { Parameters params = new Parameters (cfg, addr); +//BEGIN_TIGER_EXCLUDE cfg.configure (params); -//BEGIN_TIGER_EXCLUDE SSLParameters sslParams = params.getSSLParameters(); if (sslParams != null) { engine.setSSLParameters (sslParams);
--- a/src/share/classes/sun/net/httpserver/ServerConfig.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/net/httpserver/ServerConfig.java Mon Dec 13 16:25:26 2010 -0800 @@ -42,7 +42,7 @@ static final int DEFAULT_CLOCK_TICK = 10000 ; // 10 sec. /* These values must be a reasonable multiple of clockTick */ - static final long DEFAULT_IDLE_INTERVAL = 300 ; // 5 min + static final long DEFAULT_IDLE_INTERVAL = 30 ; // 5 min static final int DEFAULT_MAX_IDLE_CONNECTIONS = 200 ; static final long DEFAULT_MAX_REQ_TIME = -1; // default: forever
--- a/src/share/classes/sun/nio/ch/FileChannelImpl.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/nio/ch/FileChannelImpl.java Mon Dec 13 16:25:26 2010 -0800 @@ -39,12 +39,11 @@ public class FileChannelImpl extends FileChannel { + // Memory allocation size for mapping buffers + private static final long allocationGranularity; // Used to make native read and write calls - private static final FileDispatcher nd; - - // Memory allocation size for mapping buffers - private static final long allocationGranularity; + private final FileDispatcher nd; // File descriptor private final FileDescriptor fd; @@ -63,22 +62,29 @@ private final Object positionLock = new Object(); private FileChannelImpl(FileDescriptor fd, boolean readable, - boolean writable, Object parent) + boolean writable, boolean append, Object parent) { this.fd = fd; this.readable = readable; this.writable = writable; this.parent = parent; + this.nd = new FileDispatcherImpl(append); } - // Invoked by getChannel() methods - // of java.io.File{Input,Output}Stream and RandomAccessFile - // + // Used by FileInputStream.getChannel() and RandomAccessFile.getChannel() public static FileChannel open(FileDescriptor fd, boolean readable, boolean writable, Object parent) { - return new FileChannelImpl(fd, readable, writable, parent); + return new FileChannelImpl(fd, readable, writable, false, parent); + } + + // Used by FileOutputStream.getChannel + public static FileChannel open(FileDescriptor fd, + boolean readable, boolean writable, + boolean append, Object parent) + { + return new FileChannelImpl(fd, readable, writable, append, parent); } private void ensureOpen() throws IOException { @@ -704,6 +710,9 @@ private static class Unmapper implements Runnable { + // may be required to close file + private static final NativeDispatcher nd = new FileDispatcherImpl(); + // keep track of mapped buffer usage static volatile int count; static volatile long totalSize; @@ -1119,7 +1128,6 @@ static { Util.load(); allocationGranularity = initIDs(); - nd = new FileDispatcherImpl(); } }
--- a/src/share/classes/sun/nio/cs/UTF_32Coder.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/nio/cs/UTF_32Coder.java Mon Dec 13 16:25:26 2010 -0800 @@ -144,7 +144,7 @@ protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) { int mark = src.position(); - if (!doneBOM) { + if (!doneBOM && src.hasRemaining()) { if (dst.remaining() < 4) return CoderResult.OVERFLOW; put(BOM_BIG, dst);
--- a/src/share/classes/sun/nio/cs/UnicodeEncoder.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/nio/cs/UnicodeEncoder.java Mon Dec 13 16:25:26 2010 -0800 @@ -70,13 +70,12 @@ protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) { int mark = src.position(); - if (needsMark) { + if (needsMark && src.hasRemaining()) { if (dst.remaining() < 2) return CoderResult.OVERFLOW; put(BYTE_ORDER_MARK, dst); needsMark = false; } - try { while (src.hasRemaining()) { char c = src.get();
--- a/src/share/classes/sun/security/provider/SeedGenerator.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/security/provider/SeedGenerator.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, 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 @@ -138,13 +138,7 @@ instance.getSeedBytes(result); } - void getSeedBytes(byte[] result) { - for (int i = 0; i < result.length; i++) { - result[i] = getSeedByte(); - } - } - - abstract byte getSeedByte(); + abstract void getSeedBytes(byte[] result); /** * Retrieve some system information, hashed. @@ -369,6 +363,13 @@ } } + @Override + void getSeedBytes(byte[] result) { + for (int i = 0; i < result.length; i++) { + result[i] = getSeedByte(); + } + } + byte getSeedByte() { byte b = 0; @@ -455,8 +456,7 @@ static class URLSeedGenerator extends SeedGenerator { private String deviceName; - private BufferedInputStream devRandom; - + private InputStream devRandom; /** * The constructor is only called once to construct the one @@ -465,7 +465,7 @@ */ URLSeedGenerator(String egdurl) throws IOException { - if (egdurl == null) { + if (egdurl == null) { throw new IOException("No random source specified"); } deviceName = egdurl; @@ -478,41 +478,78 @@ private void init() throws IOException { final URL device = new URL(deviceName); - devRandom = java.security.AccessController.doPrivileged - (new java.security.PrivilegedAction<BufferedInputStream>() { - public BufferedInputStream run() { - try { - return new BufferedInputStream(device.openStream()); - } catch (IOException ioe) { - return null; + try { + devRandom = java.security.AccessController.doPrivileged + (new java.security.PrivilegedExceptionAction<InputStream>() { + public InputStream run() throws IOException { + /* + * return a FileInputStream for file URLs and + * avoid buffering. The openStream() call wraps + * InputStream in a BufferedInputStream which + * can buffer up to 8K bytes. This read is a + * performance issue for entropy sources which + * can be slow to replenish. + */ + if (device.getProtocol().equalsIgnoreCase("file")) { + File deviceFile = getDeviceFile(device); + return new FileInputStream(deviceFile); + } else { + return device.openStream(); } } }); - - if (devRandom == null) { - throw new IOException("failed to open " + device); + } catch (Exception e) { + throw new IOException("Failed to open " + deviceName, e.getCause()); } } - byte getSeedByte() { - byte b[] = new byte[1]; - int stat; + /* + * Use a URI to access this File. Previous code used a URL + * which is less strict on syntax. If we encounter a + * URISyntaxException we make best efforts for backwards + * compatibility. e.g. space character in deviceName string. + * + * Method called within PrivilegedExceptionAction block. + */ + private File getDeviceFile(URL device) throws IOException { try { - stat = devRandom.read(b, 0, b.length); + URI deviceURI = device.toURI(); + if(deviceURI.isOpaque()) { + // File constructor does not accept opaque URI + URI localDir = new File(System.getProperty("user.dir")).toURI(); + String uriPath = localDir.toString() + + deviceURI.toString().substring(5); + return new File(URI.create(uriPath)); + } else { + return new File(deviceURI); + } + } catch (URISyntaxException use) { + /* + * Make best effort to access this File. + * We can try using the URL path. + */ + return new File(device.getPath()); + } + } + + @Override + void getSeedBytes(byte[] result) { + int len = result.length; + int read = 0; + try { + while (read < len) { + int count = devRandom.read(result, read, len - read); + // /dev/random blocks - should never have EOF + if (count < 0) + throw new InternalError("URLSeedGenerator " + deviceName + + " reached end of file"); + read += count; + } } catch (IOException ioe) { throw new InternalError("URLSeedGenerator " + deviceName + " generated exception: " + ioe.getMessage()); } - if (stat == b.length) { - return b[0]; - } else if (stat == -1) { - throw new InternalError("URLSeedGenerator " + deviceName + - " reached end of file"); - } else { - throw new InternalError("URLSeedGenerator " + deviceName + - " failed read"); - } } }
--- a/src/share/classes/sun/security/rsa/RSASignature.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/security/rsa/RSASignature.java Mon Dec 13 16:25:26 2010 -0800 @@ -185,6 +185,11 @@ // verify the data and return the result. See JCA doc protected boolean engineVerify(byte[] sigBytes) throws SignatureException { + if (sigBytes.length != RSACore.getByteLength(publicKey)) { + throw new SignatureException("Signature length not correct: got " + + sigBytes.length + " but was expecting " + + RSACore.getByteLength(publicKey)); + } byte[] digest = getDigestValue(); try { byte[] decrypted = RSACore.rsa(sigBytes, publicKey);
--- a/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java Mon Dec 13 16:25:26 2010 -0800 @@ -103,7 +103,8 @@ String s = ((protocolVersion.v >= ProtocolVersion.TLS12.v) ? "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret"); KeyGenerator kg = JsseJce.getKeyGenerator(s); - kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor)); + kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor), + generator); preMaster = kg.generateKey(); Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
--- a/src/share/classes/sun/security/tools/JarSigner.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/security/tools/JarSigner.java Mon Dec 13 16:25:26 2010 -0800 @@ -658,7 +658,9 @@ boolean inScope = (inStoreOrScope & IN_SCOPE) != 0; notSignedByAlias |= (inStoreOrScope & NOT_ALIAS) != 0; - aliasNotInStore |= isSigned && (!inStore && !inScope); + if (keystore != null) { + aliasNotInStore |= isSigned && (!inStore && !inScope); + } // Only used when -verbose provided StringBuffer sb = null; @@ -723,7 +725,7 @@ if (signatureRelated(name)) { // Entries inside META-INF and other unsigned // entries are grouped separately. - label = "-" + label.substring(1); + label = "-" + label; } // The label finally contains 2 parts separated by '|': @@ -752,7 +754,7 @@ List<String> files = s.getValue(); String key = s.getKey(); if (key.charAt(0) == '-') { // the signature-related group - key = ' ' + key.substring(1); + key = key.substring(1); } int pipe = key.indexOf('|'); if (verbose.equals("all")) { @@ -889,7 +891,7 @@ * Note: no newline character at the end */ String printCert(String tab, Certificate c, boolean checkValidityPeriod, - long now) { + long now, boolean checkUsage) { StringBuilder certStr = new StringBuilder(); String space = rb.getString("SPACE"); @@ -959,24 +961,26 @@ } certStr.append("]"); - boolean[] bad = new boolean[3]; - checkCertUsage(x509Cert, bad); - if (bad[0] || bad[1] || bad[2]) { - String x = ""; - if (bad[0]) { - x ="KeyUsage"; - } - if (bad[1]) { - if (x.length() > 0) x = x + ", "; - x = x + "ExtendedKeyUsage"; - } - if (bad[2]) { - if (x.length() > 0) x = x + ", "; - x = x + "NetscapeCertType"; - } - certStr.append("\n").append(tab) + if (checkUsage) { + boolean[] bad = new boolean[3]; + checkCertUsage(x509Cert, bad); + if (bad[0] || bad[1] || bad[2]) { + String x = ""; + if (bad[0]) { + x ="KeyUsage"; + } + if (bad[1]) { + if (x.length() > 0) x = x + ", "; + x = x + "ExtendedKeyUsage"; + } + if (bad[2]) { + if (x.length() > 0) x = x + ", "; + x = x + "NetscapeCertType"; + } + certStr.append("\n").append(tab) .append(MessageFormat.format(rb.getString( ".{0}.extension.does.not.support.code.signing."), x)); + } } } return certStr.toString(); @@ -1335,7 +1339,7 @@ certUrl); } System.out.println(rb.getString("TSA.certificate.") + - printCert("", tsaCert, false, 0)); + printCert("", tsaCert, false, 0, false)); } if (signingMechanism != null) { System.out.println( @@ -1544,10 +1548,13 @@ s.append(printTimestamp(tab, timestamp)); s.append('\n'); } - // display the certificate(s) + // display the certificate(s). The first one is end-enity cert and + // its KeyUsage should be checked. + boolean first = true; for (Certificate c : certs) { - s.append(printCert(tab, c, true, now)); + s.append(printCert(tab, c, true, now, first)); s.append('\n'); + first = false; } try { CertPath cp = certificateFactory.generateCertPath(certs); @@ -1847,7 +1854,7 @@ // We don't meant to print anything, the next call // checks validity and keyUsage etc - printCert("", certChain[0], true, 0); + printCert("", certChain[0], true, 0, true); try { CertPath cp = certificateFactory.generateCertPath(Arrays.asList(certChain));
--- a/src/share/classes/sun/security/tools/policytool/PolicyTool.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/security/tools/policytool/PolicyTool.java Mon Dec 13 16:25:26 2010 -0800 @@ -49,7 +49,7 @@ /** * PolicyTool may be used by users and administrators to configure the * overall java security policy (currently stored in the policy file). - * Using PolicyTool administators may add and remove policies from + * Using PolicyTool administrators may add and remove policies from * the policy file. <p> * * @see java.security.Policy @@ -1343,11 +1343,6 @@ PolicyTool.rb.getString ("Actions."); - /* gridbag index for display OverWriteFile (OW) components */ - public static final int OW_LABEL = 0; - public static final int OW_OK_BUTTON = 1; - public static final int OW_CANCEL_BUTTON = 2; - /* gridbag index for display PolicyEntry (PE) components */ public static final int PE_CODEBASE_LABEL = 0; public static final int PE_CODEBASE_TEXTFIELD = 1; @@ -1523,44 +1518,6 @@ } /** - * ask user if they want to overwrite an existing file - */ - void displayOverWriteFileDialog(String filename, int nextEvent) { - - // find where the PolicyTool gui is - Point location = tw.getLocationOnScreen(); - setBounds(location.x + 75, location.y + 100, 400, 150); - setLayout(new GridBagLayout()); - - // ask the user if they want to over write the existing file - MessageFormat form = new MessageFormat(PolicyTool.rb.getString - ("OK.to.overwrite.existing.file.filename.")); - Object[] source = {filename}; - Label label = new Label(form.format(source)); - tw.addNewComponent(this, label, OW_LABEL, - 0, 0, 2, 1, 0.0, 0.0, GridBagConstraints.BOTH, - tw.TOP_PADDING); - - // OK button - Button button = new Button(PolicyTool.rb.getString("OK")); - button.addActionListener(new OverWriteFileOKButtonListener - (tool, tw, this, filename, nextEvent)); - tw.addNewComponent(this, button, OW_OK_BUTTON, - 0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.VERTICAL, - tw.TOP_PADDING); - - // Cancel button - // -- if the user hits cancel, do NOT go on to the next event - button = new Button(PolicyTool.rb.getString("Cancel")); - button.addActionListener(new CancelButtonListener(this)); - tw.addNewComponent(this, button, OW_CANCEL_BUTTON, - 1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.VERTICAL, - tw.TOP_PADDING); - - setVisible(true); - } - - /** * pop up a dialog so the user can enter info to add a new PolicyEntry * - if edit is TRUE, then the user is editing an existing entry * and we should display the original info as well. @@ -2339,47 +2296,39 @@ return; // get the entered filename - String filename = new String(fd.getDirectory() + fd.getFile()); + File saveAsFile = new File(fd.getDirectory(), fd.getFile()); + String filename = saveAsFile.getPath(); fd.dispose(); - // see if the file already exists - File saveAsFile = new File(filename); - if (saveAsFile.exists()) { - // display a dialog box for the user to enter policy info - ToolDialog td = new ToolDialog - (PolicyTool.rb.getString("Overwrite.File"), tool, tw, true); - td.displayOverWriteFileDialog(filename, nextEvent); - } else { - try { - // save the policy entries to a file - tool.savePolicy(filename); - - // display status - MessageFormat form = new MessageFormat(PolicyTool.rb.getString - ("Policy.successfully.written.to.filename")); - Object[] source = {filename}; - tw.displayStatusDialog(null, form.format(source)); - - // display the new policy filename - TextField newFilename = (TextField)tw.getComponent - (tw.MW_FILENAME_TEXTFIELD); - newFilename.setText(filename); - tw.setVisible(true); - - // now continue with the originally requested command - // (QUIT, NEW, or OPEN) - userSaveContinue(tool, tw, this, nextEvent); - - } catch (FileNotFoundException fnfe) { - if (filename == null || filename.equals("")) { - tw.displayErrorDialog(null, new FileNotFoundException - (PolicyTool.rb.getString("null.filename"))); - } else { - tw.displayErrorDialog(null, fnfe); - } - } catch (Exception ee) { - tw.displayErrorDialog(null, ee); + try { + // save the policy entries to a file + tool.savePolicy(filename); + + // display status + MessageFormat form = new MessageFormat(PolicyTool.rb.getString + ("Policy.successfully.written.to.filename")); + Object[] source = {filename}; + tw.displayStatusDialog(null, form.format(source)); + + // display the new policy filename + TextField newFilename = (TextField)tw.getComponent + (tw.MW_FILENAME_TEXTFIELD); + newFilename.setText(filename); + tw.setVisible(true); + + // now continue with the originally requested command + // (QUIT, NEW, or OPEN) + userSaveContinue(tool, tw, this, nextEvent); + + } catch (FileNotFoundException fnfe) { + if (filename == null || filename.equals("")) { + tw.displayErrorDialog(null, new FileNotFoundException + (PolicyTool.rb.getString("null.filename"))); + } else { + tw.displayErrorDialog(null, fnfe); } + } catch (Exception ee) { + tw.displayErrorDialog(null, ee); } } @@ -2494,7 +2443,7 @@ return; // get the entered filename - String policyFile = new String(fd.getDirectory() + fd.getFile()); + String policyFile = new File(fd.getDirectory(), fd.getFile()).getPath(); try { // open the policy file @@ -2862,67 +2811,6 @@ } /** - * Event handler for OverWriteFileOKButton button - */ -class OverWriteFileOKButtonListener implements ActionListener { - - private PolicyTool tool; - private ToolWindow tw; - private ToolDialog td; - private String filename; - private int nextEvent; - - OverWriteFileOKButtonListener(PolicyTool tool, ToolWindow tw, - ToolDialog td, String filename, int nextEvent) { - this.tool = tool; - this.tw = tw; - this.td = td; - this.filename = filename; - this.nextEvent = nextEvent; - } - - public void actionPerformed(ActionEvent e) { - try { - // save the policy entries to a file - tool.savePolicy(filename); - - // display status - MessageFormat form = new MessageFormat - (PolicyTool.rb.getString - ("Policy.successfully.written.to.filename")); - Object[] source = {filename}; - tw.displayStatusDialog(null, form.format(source)); - - // display the new policy filename - TextField newFilename = (TextField)tw.getComponent - (tw.MW_FILENAME_TEXTFIELD); - newFilename.setText(filename); - tw.setVisible(true); - - // now continue with the originally requested command - // (QUIT, NEW, or OPEN) - td.setVisible(false); - td.dispose(); - td.userSaveContinue(tool, tw, td, nextEvent); - - } catch (FileNotFoundException fnfe) { - if (filename == null || filename.equals("")) { - tw.displayErrorDialog(null, new FileNotFoundException - (PolicyTool.rb.getString("null.filename"))); - } else { - tw.displayErrorDialog(null, fnfe); - } - td.setVisible(false); - td.dispose(); - } catch (Exception ee) { - tw.displayErrorDialog(null, ee); - td.setVisible(false); - td.dispose(); - } - } -} - -/** * Event handler for AddEntryDoneButton button * * -- if edit is TRUE, then we are EDITing an existing PolicyEntry
--- a/src/share/classes/sun/security/util/ManifestEntryVerifier.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/security/util/ManifestEntryVerifier.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, 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 @@ -44,6 +44,16 @@ private static final Debug debug = Debug.getInstance("jar"); + /** + * Holder class to lazily load Sun provider. NOTE: if + * Providers.getSunProvider returned a cached provider, we could avoid the + * need for caching the provider with this holder class; we should try to + * revisit this in JDK 8. + */ + private static class SunProviderHolder { + private static final Provider instance = Providers.getSunProvider(); + } + /** the created digest objects */ HashMap<String, MessageDigest> createdDigests; @@ -125,7 +135,7 @@ try { digest = MessageDigest.getInstance - (algorithm, Providers.getSunProvider()); + (algorithm, SunProviderHolder.instance); createdDigests.put(algorithm, digest); } catch (NoSuchAlgorithmException nsae) { // ignore @@ -185,7 +195,10 @@ Hashtable<String, CodeSigner[]> sigFileSigners) throws JarException { - if (skip) return null; + // MANIFEST.MF should not be skipped. It has signers. + if (skip && !entry.getName().equals(JarFile.MANIFEST_NAME)) { + return null; + } if (signers != null) return signers;
--- a/src/share/classes/sun/security/util/SignatureFileVerifier.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/classes/sun/security/util/SignatureFileVerifier.java Mon Dec 13 16:25:26 2010 -0800 @@ -265,6 +265,9 @@ debug.println("processSignature unsigned name = "+name); } } + + // MANIFEST.MF is always regarded as signed + updateSigners(newSigners, signers, JarFile.MANIFEST_NAME); } /**
--- a/src/share/demo/nio/zipfs/Demo.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/demo/nio/zipfs/Demo.java Mon Dec 13 16:25:26 2010 -0800 @@ -45,12 +45,7 @@ /* * ZipFileSystem usage demo * - * java [-cp .../zipfs.jar:./] Demo action ZipfileName [...] - * - * To deploy the provider, either copy the zipfs.jar into JDK/JRE - * extensions directory or add - * <JDK_HOME>/demo/nio/ZipFileSystem/zipfs.jar - * into your class path as showed above. + * java Demo action ZipfileName [...] * * @author Xueming Shen */ @@ -153,14 +148,11 @@ Action action = Action.valueOf(args[0]); Map<String, Object> env = env = new HashMap<>(); if (action == Action.create) - env.put("createNew", true); + env.put("create", "true"); if (action == Action.tlist || action == Action.twalk) env.put("buildDirTree", true); + FileSystem fs = FileSystems.newFileSystem(Paths.get(args[1]), env, null); - FileSystem fs = FileSystems.newFileSystem( - URI.create("zip" + Paths.get(args[1]).toUri().toString().substring(4)), - env, - null); try { FileSystem fs2; Path path, src, dst; @@ -207,19 +199,13 @@ src.copyTo(dst, COPY_ATTRIBUTES); break; case zzmove: - fs2 = FileSystems.newFileSystem( - URI.create("zip" + Paths.get(args[2]).toUri().toString().substring(4)), - env, - null); + fs2 = FileSystems.newFileSystem(Paths.get(args[2]), env, null); //sf1.getPath(args[3]).moveTo(fs2.getPath(args[3])); z2zmove(fs, fs2, args[3]); fs2.close(); break; case zzcopy: - fs2 = FileSystems.newFileSystem( - URI.create("zip" + Paths.get(args[2]).toUri().toString().substring(4)), - env, - null); + fs2 = FileSystems.newFileSystem(Paths.get(args[2]), env, null); //sf1.getPath(args[3]).copyTo(fs2.getPath(args[3])); z2zcopy(fs, fs2, args[3]); fs2.close();
--- a/src/share/demo/nio/zipfs/META-INF/services/java.nio.file.spi.FileSystemProvider Mon Dec 13 16:22:29 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -com.sun.nio.zipfs.ZipFileSystemProvider -com.sun.nio.zipfs.JarFileSystemProvider -
--- a/src/share/demo/nio/zipfs/README.txt Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/demo/nio/zipfs/README.txt Mon Dec 13 16:25:26 2010 -0800 @@ -1,10 +1,6 @@ ZipFileSystem is a file system provider that treats the contents of a zip or JAR file as a java.nio.file.FileSystem. -To deploy the provider you must copy zipfs.jar into your extensions -directory or else add <JDK_HOME>/demo/nio/zipfs/zipfs.jar -to your class path. - The factory methods defined by the java.nio.file.FileSystems class can be used to create a FileSystem, eg: @@ -15,9 +11,9 @@ -or - // locate file system by URI + // locate file system by the legacy JAR URL syntax Map<String,?> env = Collections.emptyMap(); - URI uri = URI.create("zip:///mydir/foo.jar"); + URI uri = URI.create("jar:file:/mydir/foo.jar"); FileSystem fs = FileSystems.newFileSystem(uri, env); Once a FileSystem is created then classes in the java.nio.file package @@ -26,4 +22,6 @@ Path mf = fs.getPath("/META-INF/MANIFEST.MF"); InputStream in = mf.newInputStream(); +See Demo.java for more interesting usages. +
--- a/src/share/demo/nio/zipfs/com/sun/nio/zipfs/JarFileSystemProvider.java Mon Dec 13 16:22:29 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Sun Microsystems nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.sun.nio.zipfs; - -import java.nio.file.*; -import java.nio.file.spi.*; -import java.nio.file.attribute.*; -import java.nio.file.spi.FileSystemProvider; - -import java.net.URI; -import java.io.IOException; -import java.net.URISyntaxException; -import java.nio.channels.FileChannel; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -public class JarFileSystemProvider extends ZipFileSystemProvider -{ - - @Override - public String getScheme() { - return "jar"; - } - - @Override - protected Path uriToPath(URI uri) { - String scheme = uri.getScheme(); - if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) { - throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'"); - } - try { - String uristr = uri.toString(); - int end = uristr.indexOf("!/"); - uristr = uristr.substring(4, (end == -1) ? uristr.length() : end); - uri = new URI(uristr); - return Paths.get(new URI("file", uri.getHost(), uri.getPath(), null)) - .toAbsolutePath(); - } catch (URISyntaxException e) { - throw new AssertionError(e); //never thrown - } - } - - @Override - public Path getPath(URI uri) { - FileSystem fs = getFileSystem(uri); - String path = uri.getFragment(); - if (path == null) { - String uristr = uri.toString(); - int off = uristr.indexOf("!/"); - if (off != -1) - path = uristr.substring(off + 2); - } - if (path != null) - return fs.getPath(path); - throw new IllegalArgumentException("URI: " - + uri - + " does not contain path fragment ex. jar:///c:/foo.zip!/BAR"); - } -}
--- a/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipCoder.java Mon Dec 13 16:22:29 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.sun.nio.zipfs; - -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; -import java.util.Arrays; - -/** - * Utility class for zipfile name and comment decoding and encoding - * - * @author Xueming Shen - */ - -final class ZipCoder { - - String toString(byte[] ba, int length) { - CharsetDecoder cd = decoder().reset(); - int len = (int)(length * cd.maxCharsPerByte()); - char[] ca = new char[len]; - if (len == 0) - return new String(ca); - ByteBuffer bb = ByteBuffer.wrap(ba, 0, length); - CharBuffer cb = CharBuffer.wrap(ca); - CoderResult cr = cd.decode(bb, cb, true); - if (!cr.isUnderflow()) - throw new IllegalArgumentException(cr.toString()); - cr = cd.flush(cb); - if (!cr.isUnderflow()) - throw new IllegalArgumentException(cr.toString()); - return new String(ca, 0, cb.position()); - } - - String toString(byte[] ba) { - return toString(ba, ba.length); - } - - byte[] getBytes(String s) { - CharsetEncoder ce = encoder().reset(); - char[] ca = s.toCharArray(); - int len = (int)(ca.length * ce.maxBytesPerChar()); - byte[] ba = new byte[len]; - if (len == 0) - return ba; - ByteBuffer bb = ByteBuffer.wrap(ba); - CharBuffer cb = CharBuffer.wrap(ca); - CoderResult cr = ce.encode(cb, bb, true); - if (!cr.isUnderflow()) - throw new IllegalArgumentException(cr.toString()); - cr = ce.flush(bb); - if (!cr.isUnderflow()) - throw new IllegalArgumentException(cr.toString()); - if (bb.position() == ba.length) // defensive copy? - return ba; - else - return Arrays.copyOf(ba, bb.position()); - } - - // assume invoked only if "this" is not utf8 - byte[] getBytesUTF8(String s) { - if (isutf8) - return getBytes(s); - if (utf8 == null) - utf8 = new ZipCoder(Charset.forName("UTF-8")); - return utf8.getBytes(s); - } - - String toStringUTF8(byte[] ba, int len) { - if (isutf8) - return toString(ba, len); - if (utf8 == null) - utf8 = new ZipCoder(Charset.forName("UTF-8")); - return utf8.toString(ba, len); - } - - boolean isUTF8() { - return isutf8; - } - - private Charset cs; - private boolean isutf8; - private ZipCoder utf8; - - private ZipCoder(Charset cs) { - this.cs = cs; - this.isutf8 = cs.name().equals("UTF-8"); - } - - static ZipCoder get(Charset charset) { - return new ZipCoder(charset); - } - - static ZipCoder get(String csn) { - try { - return new ZipCoder(Charset.forName(csn)); - } catch (Throwable t) { - t.printStackTrace(); - } - return new ZipCoder(Charset.defaultCharset()); - } - - private final ThreadLocal<CharsetDecoder> decTL = new ThreadLocal<>(); - private final ThreadLocal<CharsetEncoder> encTL = new ThreadLocal<>(); - - private CharsetDecoder decoder() { - CharsetDecoder dec = decTL.get(); - if (dec == null) { - dec = cs.newDecoder() - .onMalformedInput(CodingErrorAction.REPORT) - .onUnmappableCharacter(CodingErrorAction.REPORT); - decTL.set(dec); - } - return dec; - } - - private CharsetEncoder encoder() { - CharsetEncoder enc = encTL.get(); - if (enc == null) { - enc = cs.newEncoder() - .onMalformedInput(CodingErrorAction.REPORT) - .onUnmappableCharacter(CodingErrorAction.REPORT); - encTL.set(enc); - } - return enc; - } -}
--- a/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipConstants.java Mon Dec 13 16:22:29 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.sun.nio.zipfs; - - -/** - * - * @author Xueming Shen - */ - -class ZipConstants { - /* - * Compression methods - */ - static final int METHOD_STORED = 0; - static final int METHOD_DEFLATED = 8; - static final int METHOD_DEFLATED64 = 9; - static final int METHOD_BZIP2 = 12; - static final int METHOD_LZMA = 14; - static final int METHOD_LZ77 = 19; - static final int METHOD_AES = 99; - - /* - * General purpose big flag - */ - static final int FLAG_ENCRYPTED = 0x01; - static final int FLAG_DATADESCR = 0x08; // crc, size and csize in dd - static final int FLAG_EFS = 0x800; // If this bit is set the filename and - // comment fields for this file must be - // encoded using UTF-8. - /* - * Header signatures - */ - static long LOCSIG = 0x04034b50L; // "PK\003\004" - static long EXTSIG = 0x08074b50L; // "PK\007\008" - static long CENSIG = 0x02014b50L; // "PK\001\002" - static long ENDSIG = 0x06054b50L; // "PK\005\006" - - /* - * Header sizes in bytes (including signatures) - */ - static final int LOCHDR = 30; // LOC header size - static final int EXTHDR = 16; // EXT header size - static final int CENHDR = 46; // CEN header size - static final int ENDHDR = 22; // END header size - - /* - * Local file (LOC) header field offsets - */ - static final int LOCVER = 4; // version needed to extract - static final int LOCFLG = 6; // general purpose bit flag - static final int LOCHOW = 8; // compression method - static final int LOCTIM = 10; // modification time - static final int LOCCRC = 14; // uncompressed file crc-32 value - static final int LOCSIZ = 18; // compressed size - static final int LOCLEN = 22; // uncompressed size - static final int LOCNAM = 26; // filename length - static final int LOCEXT = 28; // extra field length - - /* - * Extra local (EXT) header field offsets - */ - static final int EXTCRC = 4; // uncompressed file crc-32 value - static final int EXTSIZ = 8; // compressed size - static final int EXTLEN = 12; // uncompressed size - - /* - * Central directory (CEN) header field offsets - */ - static final int CENVEM = 4; // version made by - static final int CENVER = 6; // version needed to extract - static final int CENFLG = 8; // encrypt, decrypt flags - static final int CENHOW = 10; // compression method - static final int CENTIM = 12; // modification time - static final int CENCRC = 16; // uncompressed file crc-32 value - static final int CENSIZ = 20; // compressed size - static final int CENLEN = 24; // uncompressed size - static final int CENNAM = 28; // filename length - static final int CENEXT = 30; // extra field length - static final int CENCOM = 32; // comment length - static final int CENDSK = 34; // disk number start - static final int CENATT = 36; // internal file attributes - static final int CENATX = 38; // external file attributes - static final int CENOFF = 42; // LOC header offset - - /* - * End of central directory (END) header field offsets - */ - static final int ENDSUB = 8; // number of entries on this disk - static final int ENDTOT = 10; // total number of entries - static final int ENDSIZ = 12; // central directory size in bytes - static final int ENDOFF = 16; // offset of first CEN header - static final int ENDCOM = 20; // zip file comment length - - /* - * ZIP64 constants - */ - static final long ZIP64_ENDSIG = 0x06064b50L; // "PK\006\006" - static final long ZIP64_LOCSIG = 0x07064b50L; // "PK\006\007" - static final int ZIP64_ENDHDR = 56; // ZIP64 end header size - static final int ZIP64_LOCHDR = 20; // ZIP64 end loc header size - static final int ZIP64_EXTHDR = 24; // EXT header size - static final int ZIP64_EXTID = 0x0001; // Extra field Zip64 header ID - - static final int ZIP64_MINVAL32 = 0xFFFF; - static final long ZIP64_MINVAL = 0xFFFFFFFFL; - - /* - * Zip64 End of central directory (END) header field offsets - */ - static final int ZIP64_ENDLEN = 4; // size of zip64 end of central dir - static final int ZIP64_ENDVEM = 12; // version made by - static final int ZIP64_ENDVER = 14; // version needed to extract - static final int ZIP64_ENDNMD = 16; // number of this disk - static final int ZIP64_ENDDSK = 20; // disk number of start - static final int ZIP64_ENDTOD = 24; // total number of entries on this disk - static final int ZIP64_ENDTOT = 32; // total number of entries - static final int ZIP64_ENDSIZ = 40; // central directory size in bytes - static final int ZIP64_ENDOFF = 48; // offset of first CEN header - static final int ZIP64_ENDEXT = 56; // zip64 extensible data sector - - /* - * Zip64 End of central directory locator field offsets - */ - static final int ZIP64_LOCDSK = 4; // disk number start - static final int ZIP64_LOCOFF = 8; // offset of zip64 end - static final int ZIP64_LOCTOT = 16; // total number of disks - - /* - * Zip64 Extra local (EXT) header field offsets - */ - static final int ZIP64_EXTCRC = 4; // uncompressed file crc-32 value - static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte - static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte - - /* - * Extra field header ID - */ - static final int EXTID_ZIP64 = 0x0001; // ZIP64 - static final int EXTID_NTFS = 0x000a; // NTFS - static final int EXTID_UNIX = 0x000d; // UNIX - static final int EXTID_EFS = 0x0017; // Strong Encryption - static final int EXTID_EXTT = 0x5455; // Info-ZIP Extended Timestamp - - /* - * fields access methods - */ - /////////////////////////////////////////////////////// - static final int CH(byte[] b, int n) { - return b[n] & 0xff; - } - - static final int SH(byte[] b, int n) { - return (b[n] & 0xff) | ((b[n + 1] & 0xff) << 8); - } - - static final long LG(byte[] b, int n) { - return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL; - } - - static final long LL(byte[] b, int n) { - return (LG(b, n)) | (LG(b, n + 4) << 32); - } - - static final long GETSIG(byte[] b) { - return LG(b, 0); - } - - // local file (LOC) header fields - static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature - static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract - static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags - static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method - static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time - static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data - static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size - static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size - static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length - static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length - - // extra local (EXT) header fields - static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data - static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size - static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size - - // end of central directory header (END) fields - static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk - static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries - static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size - static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset - static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of zip file comment - static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);} - - // zip64 end of central directory recoder fields - static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk - static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries - static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size - static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset - static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset - - // central directory header (CEN) fields - static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); } - static final int CENVEM(byte[] b, int pos) { return SH(b, pos + 4); } - static final int CENVER(byte[] b, int pos) { return SH(b, pos + 6); } - static final int CENFLG(byte[] b, int pos) { return SH(b, pos + 8); } - static final int CENHOW(byte[] b, int pos) { return SH(b, pos + 10);} - static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);} - static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);} - static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);} - static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);} - static final int CENNAM(byte[] b, int pos) { return SH(b, pos + 28);} - static final int CENEXT(byte[] b, int pos) { return SH(b, pos + 30);} - static final int CENCOM(byte[] b, int pos) { return SH(b, pos + 32);} - static final int CENDSK(byte[] b, int pos) { return SH(b, pos + 34);} - static final int CENATT(byte[] b, int pos) { return SH(b, pos + 36);} - static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);} - static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);} - - /* The END header is followed by a variable length comment of size < 64k. */ - static final long END_MAXLEN = 0xFFFF + ENDHDR; - static final int READBLOCKSZ = 128; -}
--- a/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipDirectoryStream.java Mon Dec 13 16:22:29 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.sun.nio.zipfs; - -import java.nio.file.DirectoryStream; -import java.nio.file.ClosedDirectoryStreamException; -import java.nio.file.NotDirectoryException; -import java.nio.file.Path; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.io.IOException; - -/** - * - * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal - */ - -public class ZipDirectoryStream implements DirectoryStream<Path> { - - private final ZipFileSystem zipfs; - private final byte[] path; - private final DirectoryStream.Filter<? super Path> filter; - private volatile boolean isClosed; - private volatile Iterator<Path> itr; - - ZipDirectoryStream(ZipPath zipPath, - DirectoryStream.Filter<? super java.nio.file.Path> filter) - throws IOException - { - this.zipfs = zipPath.getFileSystem(); - this.path = zipPath.getResolvedPath(); - this.filter = filter; - // sanity check - if (!zipfs.isDirectory(path)) - throw new NotDirectoryException(zipPath.toString()); - } - - @Override - public synchronized Iterator<Path> iterator() { - if (isClosed) - throw new ClosedDirectoryStreamException(); - if (itr != null) - throw new IllegalStateException("Iterator has already been returned"); - - try { - itr = zipfs.iteratorOf(path, filter); - } catch (IOException e) { - throw new IllegalStateException(e); - } - return new Iterator<>() { - private Path next; - @Override - public boolean hasNext() { - if (isClosed) - return false; - return itr.hasNext(); - } - - @Override - public synchronized Path next() { - if (isClosed) - throw new NoSuchElementException(); - return itr.next(); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - - @Override - public synchronized void close() throws IOException { - isClosed = true; - } - - -}
--- a/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileAttributeView.java Mon Dec 13 16:22:29 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -package com.sun.nio.zipfs; - -import java.nio.file.attribute.BasicFileAttributeView; -import java.nio.file.attribute.FileAttributeView; -import java.nio.file.attribute.FileTime; -import java.io.IOException; -import java.util.LinkedHashMap; - -/* - * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal - */ - -public class ZipFileAttributeView implements BasicFileAttributeView -{ - private static enum AttrID { - size, - creationTime, - lastAccessTime, - lastModifiedTime, - isDirectory, - isRegularFile, - isSymbolicLink, - isOther, - fileKey, - compressedSize, - crc, - method - }; - - private final ZipPath path; - private final boolean isZipView; - - private ZipFileAttributeView(ZipPath path, boolean isZipView) { - this.path = path; - this.isZipView = isZipView; - } - - static <V extends FileAttributeView> V get(ZipPath path, Class<V> type) { - if (type == null) - throw new NullPointerException(); - if (type == BasicFileAttributeView.class) - return (V)new ZipFileAttributeView(path, false); - if (type == ZipFileAttributeView.class) - return (V)new ZipFileAttributeView(path, true); - return null; - } - - static ZipFileAttributeView get(ZipPath path, String type) { - if (type == null) - throw new NullPointerException(); - if (type.equals("basic")) - return new ZipFileAttributeView(path, false); - if (type.equals("zip")) - return new ZipFileAttributeView(path, true); - return null; - } - - @Override - public String name() { - return isZipView ? "zip" : "basic"; - } - - public ZipFileAttributes readAttributes() throws IOException - { - return path.getAttributes(); - } - - @Override - public void setTimes(FileTime lastModifiedTime, - FileTime lastAccessTime, - FileTime createTime) - throws IOException - { - path.setTimes(lastModifiedTime, lastAccessTime, createTime); - } - - void setAttribute(String attribute, Object value) - throws IOException - { - try { - if (AttrID.valueOf(attribute) == AttrID.lastModifiedTime) - setTimes ((FileTime)value, null, null); - if (AttrID.valueOf(attribute) == AttrID.lastAccessTime) - setTimes (null, (FileTime)value, null); - if (AttrID.valueOf(attribute) == AttrID.creationTime) - setTimes (null, null, (FileTime)value); - return; - } catch (IllegalArgumentException x) {} - throw new UnsupportedOperationException("'" + attribute + - "' is unknown or read-only attribute"); - } - - public Object getAttribute(String attribute, boolean domap) - throws IOException - { - ZipFileAttributes zfas = readAttributes(); - if (!domap) { - try { - return attribute(AttrID.valueOf(attribute), zfas); - } catch (IllegalArgumentException x) {} - return null; - } - LinkedHashMap<String, Object> map = new LinkedHashMap<>(); - if ("*".equals(attribute)) { - for (AttrID id : AttrID.values()) { - try { - map.put(id.name(), attribute(id, zfas)); - } catch (IllegalArgumentException x) {} - } - } else { - String[] as = attribute.split(","); - for (String a : as) { - try { - map.put(a, attribute(AttrID.valueOf(a), zfas)); - } catch (IllegalArgumentException x) {} - } - } - return map; - } - - Object attribute(AttrID id, ZipFileAttributes zfas) { - switch (id) { - case size: - return zfas.size(); - case creationTime: - return zfas.creationTime(); - case lastAccessTime: - return zfas.lastAccessTime(); - case lastModifiedTime: - return zfas.lastModifiedTime(); - case isDirectory: - return zfas.isDirectory(); - case isRegularFile: - return zfas.isRegularFile(); - case isSymbolicLink: - return zfas.isSymbolicLink(); - case isOther: - return zfas.isOther(); - case fileKey: - return zfas.fileKey(); - case compressedSize: - if (isZipView) - return zfas.compressedSize(); - break; - case crc: - if (isZipView) - return zfas.crc(); - break; - case method: - if (isZipView) - return zfas.method(); - break; - } - return null; - } -}
--- a/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileAttributes.java Mon Dec 13 16:22:29 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -package com.sun.nio.zipfs; - -import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.FileTime; -import java.util.Arrays; -import java.util.Formatter; -import static com.sun.nio.zipfs.ZipUtils.*; - -/** - * - * @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal - */ - -public class ZipFileAttributes implements BasicFileAttributes - -{ - private final ZipFileSystem.Entry e; - - ZipFileAttributes(ZipFileSystem.Entry e) { - this.e = e; - } - - ///////// basic attributes /////////// - @Override - public FileTime creationTime() { - if (e.ctime != -1) - return FileTime.fromMillis(e.ctime); - return null; - } - - @Override - public boolean isDirectory() { - return e.isDir(); - } - - @Override - public boolean isOther() { - return false; - } - - @Override - public boolean isRegularFile() { - return !e.isDir(); - } - - @Override - public FileTime lastAccessTime() { - if (e.atime != -1) - return FileTime.fromMillis(e.atime); - return null; - } - - @Override - public FileTime lastModifiedTime() { - return FileTime.fromMillis(e.mtime); - } - - @Override - public long size() { - return e.size; - } - - @Override - public boolean isSymbolicLink() { - return false; - } - - @Override - public Object fileKey() { - return null; - } - - ///////// zip entry attributes /////////// - public long compressedSize() { - return e.csize; - } - - public long crc() { - return e.crc; - } - - public int method() { - return e.method; - } - - public byte[] extra() { - if (e.extra != null) - return Arrays.copyOf(e.extra, e.extra.length); - return null; - } - - public byte[] comment() { - if (e.comment != null) - return Arrays.copyOf(e.comment, e.comment.length); - return null; - } - - public String toString() { - StringBuilder sb = new StringBuilder(1024); - Formatter fm = new Formatter(sb); - if (creationTime() != null) - fm.format(" creationTime : %tc%n", creationTime().toMillis()); - else - fm.format(" creationTime : null%n"); - - if (lastAccessTime() != null) - fm.format(" lastAccessTime : %tc%n", lastAccessTime().toMillis()); - else - fm.format(" lastAccessTime : null%n"); - fm.format(" lastModifiedTime: %tc%n", lastModifiedTime().toMillis()); - fm.format(" isRegularFile : %b%n", isRegularFile()); - fm.format(" isDirectory : %b%n", isDirectory()); - fm.format(" isSymbolicLink : %b%n", isSymbolicLink()); - fm.format(" isOther : %b%n", isOther()); - fm.format(" fileKey : %s%n", fileKey()); - fm.format(" size : %d%n", size()); - fm.format(" compressedSize : %d%n", compressedSize()); - fm.format(" crc : %x%n", crc()); - fm.format(" method : %d%n", method()); - fm.close(); - return sb.toString(); - } -}
--- a/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileStore.java Mon Dec 13 16:22:29 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.sun.nio.zipfs; - -import java.io.IOException; -import java.nio.file.FileStore; -import java.nio.file.FileSystems; -import java.nio.file.Path; -import java.nio.file.attribute.FileAttributeView; -import java.nio.file.attribute.FileStoreAttributeView; -import java.nio.file.attribute.FileStoreSpaceAttributeView; -import java.nio.file.attribute.FileStoreSpaceAttributes; -import java.nio.file.attribute.Attributes; -import java.nio.file.attribute.BasicFileAttributeView; -import java.util.Formatter; - -/* - * - * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal - */ - -public class ZipFileStore extends FileStore { - - private final ZipFileSystem zfs; - - ZipFileStore(ZipPath zpath) { - this.zfs = (ZipFileSystem)zpath.getFileSystem(); - } - - @Override - public String name() { - return zfs.toString() + "/"; - } - - @Override - public String type() { - return "zipfs"; - } - - @Override - public boolean isReadOnly() { - return zfs.isReadOnly(); - } - - @Override - public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) { - return (type == BasicFileAttributeView.class || - type == ZipFileAttributeView.class); - } - - @Override - public boolean supportsFileAttributeView(String name) { - return name.equals("basic") || name.equals("zip"); - } - - @Override - @SuppressWarnings("unchecked") - public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) { - if (type == null) - throw new NullPointerException(); - if (type == FileStoreSpaceAttributeView.class) - return (V) new ZipFileStoreAttributeView(this); - return null; - } - - @Override - public Object getAttribute(String attribute) throws IOException { - if (attribute.equals("space:totalSpace")) - return new ZipFileStoreAttributeView(this).readAttributes().totalSpace(); - if (attribute.equals("space:usableSpace")) - return new ZipFileStoreAttributeView(this).readAttributes().usableSpace(); - if (attribute.equals("space:unallocatedSpace")) - return new ZipFileStoreAttributeView(this).readAttributes().unallocatedSpace(); - throw new UnsupportedOperationException("does not support the given attribute"); - } - - private static class ZipFileStoreAttributeView implements FileStoreSpaceAttributeView { - - private final ZipFileStore fileStore; - - public ZipFileStoreAttributeView(ZipFileStore fileStore) { - this.fileStore = fileStore; - } - - @Override - public String name() { - return "space"; - } - - @Override - public FileStoreSpaceAttributes readAttributes() throws IOException { - final String file = fileStore.name(); - Path path = FileSystems.getDefault().getPath(file); - final long size = Attributes.readBasicFileAttributes(path).size(); - final FileStore fstore = path.getFileStore(); - final FileStoreSpaceAttributes fstoreAttrs = - Attributes.readFileStoreSpaceAttributes(fstore); - return new FileStoreSpaceAttributes() { - public long totalSpace() { - return size; - } - - public long usableSpace() { - if (!fstore.isReadOnly()) - return fstoreAttrs.usableSpace(); - return 0; - } - - public long unallocatedSpace() { - if (!fstore.isReadOnly()) - return fstoreAttrs.unallocatedSpace(); - return 0; - } - - public String toString() { - StringBuilder sb = new StringBuilder(); - Formatter fm = new Formatter(sb); - fm.format("FileStoreSpaceAttributes[%s]%n", file); - fm.format(" totalSpace: %d%n", totalSpace()); - fm.format(" usableSpace: %d%n", usableSpace()); - fm.format(" unallocSpace: %d%n", unallocatedSpace()); - fm.close(); - return sb.toString(); - } - }; - } - } -}
--- a/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileSystem.java Mon Dec 13 16:22:29 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2367 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.sun.nio.zipfs; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.EOFException; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.MappedByteBuffer; -import java.nio.channels.*; -import java.nio.file.*; -import java.nio.file.attribute.*; -import java.nio.file.spi.*; -import java.util.*; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.regex.Pattern; -import java.util.zip.CRC32; -import java.util.zip.Inflater; -import java.util.zip.Deflater; -import java.util.zip.InflaterInputStream; -import java.util.zip.DeflaterOutputStream; -import java.util.zip.ZipException; -import java.util.zip.ZipError; -import static java.lang.Boolean.*; -import static com.sun.nio.zipfs.ZipConstants.*; -import static com.sun.nio.zipfs.ZipUtils.*; -import static java.nio.file.StandardOpenOption.*; -import static java.nio.file.StandardCopyOption.*; - -/** - * A FileSystem built on a zip file - * - * @author Xueming Shen - */ - -public class ZipFileSystem extends FileSystem { - - private final ZipFileSystemProvider provider; - private final ZipPath defaultdir; - private boolean readOnly = false; - private final Path zfpath; - private final ZipCoder zc; - - // configurable by env map - private final String defaultDir; // default dir for the file system - private final String nameEncoding; // default encoding for name/comment - private final boolean buildDirTree; // build a dir tree for directoryStream ops - private final boolean useTempFile; // use a temp file for newOS, default - // is to use BAOS for better performance - private final boolean createNew; // create a new zip if not exists - private static final boolean isWindows = - System.getProperty("os.name").startsWith("Windows"); - - ZipFileSystem(ZipFileSystemProvider provider, - Path zfpath, - Map<String, ?> env) - throws IOException - { - // configurable env setup - this.buildDirTree = TRUE.equals(env.get("buildDirTreea")); - this.useTempFile = TRUE.equals(env.get("useTempFile")); - this.createNew = TRUE.equals(env.get("createNew")); - this.nameEncoding = env.containsKey("nameEncoding") ? - (String)env.get("nameEncoding") : "UTF-8"; - this.defaultDir = env.containsKey("default.dir") ? - (String)env.get("default.dir") : "/"; - if (this.defaultDir.charAt(0) != '/') - throw new IllegalArgumentException("default dir should be absolute"); - - this.provider = provider; - this.zfpath = zfpath; - if (zfpath.notExists()) { - if (createNew) { - OutputStream os = zfpath.newOutputStream(CREATE_NEW, WRITE); - new END().write(os, 0); - os.close(); - } else { - throw new FileSystemNotFoundException(zfpath.toString()); - } - } - zfpath.checkAccess(AccessMode.READ); // sm and existence check - try { - zfpath.checkAccess(AccessMode.WRITE); - } catch (AccessDeniedException x) { - this.readOnly = true; - } - this.zc = ZipCoder.get(nameEncoding); - this.defaultdir = new ZipPath(this, getBytes(defaultDir)); - this.ch = zfpath.newByteChannel(READ); - this.cen = initCEN(); - } - - @Override - public FileSystemProvider provider() { - return provider; - } - - @Override - public String getSeparator() { - return "/"; - } - - @Override - public boolean isOpen() { - return isOpen; - } - - @Override - public boolean isReadOnly() { - return readOnly; - } - - private void checkWritable() throws IOException { - if (readOnly) - throw new ReadOnlyFileSystemException(); - } - - @Override - public Iterable<Path> getRootDirectories() { - ArrayList<Path> pathArr = new ArrayList<>(); - pathArr.add(new ZipPath(this, new byte[]{'/'})); - return pathArr; - } - - ZipPath getDefaultDir() { // package private - return defaultdir; - } - - @Override - public ZipPath getPath(String path) { - if (path.length() == 0) - throw new InvalidPathException(path, "path should not be empty"); - return new ZipPath(this, getBytes(path)); - } - - @Override - public UserPrincipalLookupService getUserPrincipalLookupService() { - throw new UnsupportedOperationException(); - } - - @Override - public WatchService newWatchService() { - throw new UnsupportedOperationException(); - } - - FileStore getFileStore(ZipPath path) { - return new ZipFileStore(path); - } - - @Override - public Iterable<FileStore> getFileStores() { - ArrayList<FileStore> list = new ArrayList<>(1); - list.add(new ZipFileStore(new ZipPath(this, new byte[]{'/'}))); - return list; - } - - private static final Set<String> supportedFileAttributeViews = - Collections.unmodifiableSet( - new HashSet<String>(Arrays.asList("basic", "zip"))); - - @Override - public Set<String> supportedFileAttributeViews() { - return supportedFileAttributeViews; - } - - @Override - public String toString() { - return zfpath.toString(); - } - - Path getZipFile() { - return zfpath; - } - - private static final String GLOB_SYNTAX = "glob"; - private static final String REGEX_SYNTAX = "regex"; - - @Override - public PathMatcher getPathMatcher(String syntaxAndInput) { - int pos = syntaxAndInput.indexOf(':'); - if (pos <= 0 || pos == syntaxAndInput.length()) { - throw new IllegalArgumentException(); - } - String syntax = syntaxAndInput.substring(0, pos); - String input = syntaxAndInput.substring(pos + 1); - String expr; - if (syntax.equals(GLOB_SYNTAX)) { - expr = toRegexPattern(input); - } else { - if (syntax.equals(REGEX_SYNTAX)) { - expr = input; - } else { - throw new UnsupportedOperationException("Syntax '" + syntax + - "' not recognized"); - } - } - // return matcher - final Pattern pattern = Pattern.compile(expr); - return new PathMatcher() { - @Override - public boolean matches(Path path) { - return pattern.matcher(path.toString()).matches(); - } - }; - } - - @Override - public void close() throws IOException { - beginWrite(); - try { - if (!isOpen) - return; - isOpen = false; // set closed - } finally { - endWrite(); - } - if (!streams.isEmpty()) { // unlock and close all remaining streams - Set<InputStream> copy = new HashSet<>(streams); - for (InputStream is: copy) - is.close(); - } - beginWrite(); // lock and sync - try { - sync(); - ch.close(); // close the ch just in case no update - } finally { // and sync dose not close the ch - endWrite(); - } - - synchronized (inflaters) { - for (Inflater inf : inflaters) - inf.end(); - } - synchronized (deflaters) { - for (Deflater def : deflaters) - def.end(); - } - - synchronized (tmppaths) { - for (Path p: tmppaths) { - try { - p.deleteIfExists(); - } catch (IOException x) { - x.printStackTrace(); - } - } - } - provider.removeFileSystem(zfpath); - } - - ZipFileAttributes getFileAttributes(byte[] path) - throws IOException - { - Entry e; - beginRead(); - try { - ensureOpen(); - e = getEntry0(path); - } finally { - endRead(); - } - if (e == null) { - if (path.length == 0) { - e = new Entry(new byte[0]); // root - } else if (buildDirTree) { - IndexNode inode = getDirs().get(IndexNode.keyOf(path)); - if (inode == null) - return null; - e = new Entry(inode.name); - } else { - return null; - } - e.method = METHOD_STORED; // STORED for dir - BasicFileAttributes bfas = Attributes.readBasicFileAttributes(zfpath); - if (bfas.lastModifiedTime() != null) - e.mtime = bfas.lastModifiedTime().toMillis(); - if (bfas.lastAccessTime() != null) - e.atime = bfas.lastAccessTime().toMillis(); - if (bfas.creationTime() != null) - e.ctime = bfas.creationTime().toMillis(); - } - return new ZipFileAttributes(e); - } - - void setTimes(byte[] path, FileTime mtime, FileTime atime, FileTime ctime) - throws IOException - { - checkWritable(); - beginWrite(); - try { - ensureOpen(); - Entry e = getEntry0(path); // ensureOpen checked - if (e == null) - throw new NoSuchFileException(getString(path)); - if (e.type == Entry.CEN) - e.type = Entry.COPY; // copy e - if (mtime != null) - e.mtime = mtime.toMillis(); - if (atime != null) - e.atime = atime.toMillis(); - if (ctime != null) - e.ctime = ctime.toMillis(); - update(e); - } finally { - endWrite(); - } - } - - boolean exists(byte[] path) - throws IOException - { - beginRead(); - try { - ensureOpen(); - return getEntry0(path) != null; - } finally { - endRead(); - } - } - - boolean isDirectory(byte[] path) - throws IOException - { - if (buildDirTree) - return getDirs().containsKey(IndexNode.keyOf(path)); - - beginRead(); - try { - Entry e = getEntry0(path); - return (e != null && e.isDir()) || path.length == 0; - } finally { - endRead(); - } - } - - private ZipPath toZipPath(byte[] path) { - // make it absolute - byte[] p = new byte[path.length + 1]; - p[0] = '/'; - System.arraycopy(path, 0, p, 1, path.length); - return new ZipPath(this, p); - } - - // returns the list of child paths of "path" - Iterator<Path> iteratorOf(byte[] path, - DirectoryStream.Filter<? super Path> filter) - throws IOException - { - beginWrite(); // iteration of inodes needs exclusive lock - try { - ensureOpen(); - if (buildDirTree) { - IndexNode inode = getDirs().get(IndexNode.keyOf(path)); - if (inode == null) - throw new NotDirectoryException(getString(path)); - List<Path> list = new ArrayList<>(); - IndexNode child = inode.child; - while (child != null) { - ZipPath zp = toZipPath(child.name); - if (filter == null || filter.accept(zp)) - list.add(zp); - child = child.sibling; - } - return list.iterator(); - } - - if (!isDirectory(path)) - throw new NotDirectoryException(getString(path)); - List<Path> list = new ArrayList<>(); - path = toDirectoryPath(path); - for (IndexNode key : inodes.keySet()) { - if (!isParentOf(path, key.name)) // is "path" the parent of "name" - continue; - int off = path.length; - while (off < key.name.length) { - if (key.name[off] == '/') - break; - off++; - } - if (off < (key.name.length - 1)) - continue; - ZipPath zp = toZipPath(key.name); - if (filter == null || filter.accept(zp)) - list.add(zp); - } - return list.iterator(); - } finally { - endWrite(); - } - } - - 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(); - } - } - - void copyFile(boolean deletesrc, byte[]src, byte[] dst, CopyOption... options) - throws IOException - { - checkWritable(); - if (Arrays.equals(src, dst)) - return; // do nothing, src and dst are the same - - beginWrite(); - try { - ensureOpen(); - Entry eSrc = getEntry0(src); // ensureOpen checked - if (eSrc == null) - throw new NoSuchFileException(getString(src)); - if (eSrc.isDir()) { // spec says to create dst dir - createDirectory(dst); - return; - } - boolean hasReplace = false; - boolean hasCopyAttrs = false; - for (CopyOption opt : options) { - if (opt == REPLACE_EXISTING) - hasReplace = true; - else if (opt == COPY_ATTRIBUTES) - hasCopyAttrs = true; - } - Entry eDst = getEntry0(dst); - if (eDst != null) { - if (!hasReplace) - throw new FileAlreadyExistsException(getString(dst)); - } else { - checkParents(dst); - } - Entry u = new Entry(eSrc, Entry.COPY); // copy eSrc entry - u.name = dst; // change name - if (eSrc.type == Entry.NEW || eSrc.type == Entry.FILECH) - { - u.type = eSrc.type; // make it the same type - if (!deletesrc) { // if it's not "rename", just take the data - if (eSrc.bytes != null) - u.bytes = Arrays.copyOf(eSrc.bytes, eSrc.bytes.length); - else if (eSrc.file != null) { - u.file = getTempPathForEntry(null); - eSrc.file.copyTo(u.file, REPLACE_EXISTING); - } - } - } - if (!hasCopyAttrs) - u.mtime = u.atime= u.ctime = System.currentTimeMillis(); - update(u); - if (deletesrc) - updateDelete(eSrc); - } finally { - endWrite(); - } - } - - // Returns an output stream for writing the contents into the specified - // entry. - OutputStream newOutputStream(byte[] path, OpenOption... options) - throws IOException - { - checkWritable(); - boolean hasCreateNew = false; - boolean hasCreate = false; - boolean hasAppend = false; - for (OpenOption opt: options) { - if (opt == READ) - throw new IllegalArgumentException("READ not allowed"); - if (opt == CREATE_NEW) - hasCreateNew = true; - if (opt == CREATE) - hasCreate = true; - if (opt == APPEND) - hasAppend = true; - } - beginRead(); // only need a readlock, the "update()" will - try { // try to obtain a writelock when the os is - ensureOpen(); // being closed. - Entry e = getEntry0(path); - if (e != null) { - 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)); - } - } finally { - endRead(); - } - } - - // Returns an input stream for reading the contents of the specified - // file entry. - InputStream newInputStream(byte[] path) throws IOException { - beginRead(); - try { - ensureOpen(); - Entry e = getEntry0(path); - if (e == null) - throw new NoSuchFileException(getString(path)); - if (e.isDir()) - throw new FileSystemException(getString(path), "is a directory", null); - return getInputStream(e); - } finally { - endRead(); - } - } - - private void checkOptions(Set<? extends OpenOption> options) { - // check for options of null type and option is an intance of StandardOpenOption - for (OpenOption option : options) { - if (option == null) - throw new NullPointerException(); - if (!(option instanceof StandardOpenOption)) - throw new IllegalArgumentException(); - } - } - - // 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, - Set<? extends OpenOption> options, - FileAttribute<?>... attrs) - throws IOException - { - 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 = getEntry0(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 = getEntry0(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 { - return rbc.read(dst); - } - - 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(); - } - } - } - - // Returns a FileChannel of the specified entry. - // - // This implementation creates a temporary file on the default file system, - // copy the entry data into it if the entry exists, and then create a - // FileChannel on top of it. - FileChannel newFileChannel(byte[] path, - Set<? extends OpenOption> options, - FileAttribute<?>... attrs) - throws IOException - { - checkOptions(options); - final boolean forWrite = (options.contains(StandardOpenOption.WRITE) || - options.contains(StandardOpenOption.APPEND)); - beginRead(); - try { - ensureOpen(); - Entry e = getEntry0(path); - if (forWrite) { - checkWritable(); - if (e == null) { - if (!options.contains(StandardOpenOption.CREATE_NEW)) - throw new NoSuchFileException(getString(path)); - } else { - if (options.contains(StandardOpenOption.CREATE_NEW)) - throw new FileAlreadyExistsException(getString(path)); - if (e.isDir()) - throw new FileAlreadyExistsException("directory <" - + getString(path) + "> exists"); - } - options.remove(StandardOpenOption.CREATE_NEW); // for tmpfile - } else if (e == null || e.isDir()) { - throw new NoSuchFileException(getString(path)); - } - - final boolean isFCH = (e != null && e.type == Entry.FILECH); - final Path tmpfile = isFCH ? e.file : getTempPathForEntry(path); - final FileChannel fch = tmpfile.getFileSystem() - .provider() - .newFileChannel(tmpfile, options, attrs); - final Entry u = isFCH ? e : new Entry(path, tmpfile, Entry.FILECH); - if (forWrite) { - u.flag = FLAG_DATADESCR; - u.method = METHOD_DEFLATED; - } - // is there a better way to hook into the FileChannel's close method? - return new FileChannel() { - public int write(ByteBuffer src) throws IOException { - return fch.write(src); - } - public long write(ByteBuffer[] srcs, int offset, int length) - throws IOException - { - return fch.write(srcs, offset, length); - } - public long position() throws IOException { - return fch.position(); - } - public FileChannel position(long newPosition) - throws IOException - { - fch.position(newPosition); - return this; - } - public long size() throws IOException { - return fch.size(); - } - public FileChannel truncate(long size) - throws IOException - { - fch.truncate(size); - return this; - } - public void force(boolean metaData) - throws IOException - { - fch.force(metaData); - } - public long transferTo(long position, long count, - WritableByteChannel target) - throws IOException - { - return fch.transferTo(position, count, target); - } - public long transferFrom(ReadableByteChannel src, - long position, long count) - throws IOException - { - return fch.transferFrom(src, position, count); - } - public int read(ByteBuffer dst) throws IOException { - return fch.read(dst); - } - public int read(ByteBuffer dst, long position) - throws IOException - { - return fch.read(dst, position); - } - public long read(ByteBuffer[] dsts, int offset, int length) - throws IOException - { - return fch.read(dsts, offset, length); - } - public int write(ByteBuffer src, long position) - throws IOException - { - return fch.write(src, position); - } - public MappedByteBuffer map(MapMode mode, - long position, long size) - throws IOException - { - throw new UnsupportedOperationException(); - } - public FileLock lock(long position, long size, boolean shared) - throws IOException - { - return fch.lock(position, size, shared); - } - public FileLock tryLock(long position, long size, boolean shared) - throws IOException - { - return fch.tryLock(position, size, shared); - } - protected void implCloseChannel() throws IOException { - fch.close(); - if (forWrite) { - u.mtime = System.currentTimeMillis(); - u.size = Attributes.readBasicFileAttributes(u.file).size(); - update(u); - } else { - if (!isFCH) // if this is a new fch for reading - removeTempPathForEntry(tmpfile); - } - } - }; - } finally { - endRead(); - } - } - - // 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 = getEntry0(path); - if (e != null) { - InputStream is = newInputStream(path); - OutputStream os = tmpPath.newOutputStream(WRITE); - try { - copyStream(is, os); - } finally { - is.close(); - os.close(); - } - } - } - return tmpPath; - } - - private void removeTempPathForEntry(Path path) throws IOException { - path.delete(); - tmppaths.remove(path); - } - - // check if all parents really exit. ZIP spec does not require - // the existence of any "parent directory". - private void checkParents(byte[] path) throws IOException { - beginRead(); - try { - while ((path = getParent(path)) != null) { - if (!inodes.containsKey(IndexNode.keyOf(path))) - throw new NoSuchFileException(getString(path)); - } - } finally { - endRead(); - } - } - - private static byte[] getParent(byte[] path) { - int off = path.length - 1; - if (off > 0 && path[off] == '/') // isDirectory - off--; - while (off > 0 && path[off] != '/') { off--; } - if (off == 0) - return null; // top entry - return Arrays.copyOf(path, off + 1); - } - - // If "starter" is the parent directory of "path" - private static boolean isParentOf(byte[] p, byte[] c) { - final int plen = p.length; - if (plen == 0) // root dir - return true; - if (plen >= c.length) - return false; - int n = 0; - while (n < plen) { - if (p[n] != c[n]) - return false; - n++; - } - if (p[n - 1] != '/' && (c[n] != '/' || n == c.length - 1)) - return false; - return true; - } - - private final void beginWrite() { - rwlock.writeLock().lock(); - } - - private final void endWrite() { - rwlock.writeLock().unlock(); - } - - private final void beginRead() { - rwlock.readLock().lock(); - } - - private final void endRead() { - rwlock.readLock().unlock(); - } - - /////////////////////////////////////////////////////////////////// - - private volatile boolean isOpen = true; - private final SeekableByteChannel ch; // channel to the zipfile - final byte[] cen; // CEN & ENDHDR - private END end; - private long locpos; // position of first LOC header (usually 0) - - private final ReadWriteLock rwlock = new ReentrantReadWriteLock(); - - // name -> pos (in cen), IndexNode itself can be used as a "key" - private LinkedHashMap<IndexNode, IndexNode> inodes; - - final byte[] getBytes(String name) { - return zc.getBytes(name); - } - - final String getString(byte[] name) { - return zc.toString(name); - } - - protected void finalize() throws IOException { - close(); - } - - private long getDataPos(Entry e) throws IOException { - if (e.locoff == -1) { - Entry e2 = getEntry0(e.name); - if (e2 == null) - throw new ZipException("invalid loc for entry <" + e.name + ">"); - e.locoff = e2.locoff; - } - byte[] buf = new byte[LOCHDR]; - if (readFullyAt(buf, 0, buf.length, e.locoff) != buf.length) - throw new ZipException("invalid loc for entry <" + e.name + ">"); - return locpos + e.locoff + LOCHDR + LOCNAM(buf) + LOCEXT(buf); - } - - // Reads len bytes of data from the specified offset into buf. - // Returns the total number of bytes read. - // Each/every byte read from here (except the cen, which is mapped). - final long readFullyAt(byte[] buf, int off, long len, long pos) - throws IOException - { - ByteBuffer bb = ByteBuffer.wrap(buf); - bb.position(off); - bb.limit((int)(off + len)); - return readFullyAt(bb, pos); - } - - private final long readFullyAt(ByteBuffer bb, long pos) - throws IOException - { - synchronized(ch) { - return ch.position(pos).read(bb); - } - } - - // Searches for end of central directory (END) header. The contents of - // the END header will be read and placed in endbuf. Returns the file - // position of the END header, otherwise returns -1 if the END header - // was not found or an error occurred. - private END findEND() throws IOException - { - byte[] buf = new byte[READBLOCKSZ]; - long ziplen = ch.size(); - long minHDR = (ziplen - END_MAXLEN) > 0 ? ziplen - END_MAXLEN : 0; - long minPos = minHDR - (buf.length - ENDHDR); - - for (long pos = ziplen - buf.length; pos >= minPos; pos -= (buf.length - ENDHDR)) - { - int off = 0; - if (pos < 0) { - // Pretend there are some NUL bytes before start of file - off = (int)-pos; - Arrays.fill(buf, 0, off, (byte)0); - } - int len = buf.length - off; - if (readFullyAt(buf, off, len, pos + off) != len) - zerror("zip END header not found"); - - // Now scan the block backwards for END header signature - for (int i = buf.length - ENDHDR; i >= 0; i--) { - if (buf[i+0] == (byte)'P' && - buf[i+1] == (byte)'K' && - buf[i+2] == (byte)'\005' && - buf[i+3] == (byte)'\006' && - (pos + i + ENDHDR + ENDCOM(buf, i) == ziplen)) { - // Found END header - buf = Arrays.copyOfRange(buf, i, i + ENDHDR); - END end = new END(); - end.endsub = ENDSUB(buf); - end.centot = ENDTOT(buf); - end.cenlen = ENDSIZ(buf); - end.cenoff = ENDOFF(buf); - end.comlen = ENDCOM(buf); - end.endpos = pos + i; - if (end.cenlen == ZIP64_MINVAL || - end.cenoff == ZIP64_MINVAL || - end.centot == ZIP64_MINVAL32) - { - // need to find the zip64 end; - byte[] loc64 = new byte[ZIP64_LOCHDR]; - if (readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR) - != loc64.length) { - return end; - } - long end64pos = ZIP64_LOCOFF(loc64); - byte[] end64buf = new byte[ZIP64_ENDHDR]; - if (readFullyAt(end64buf, 0, end64buf.length, end64pos) - != end64buf.length) { - return end; - } - // end64 found, re-calcualte everything. - end.cenlen = ZIP64_ENDSIZ(end64buf); - end.cenoff = ZIP64_ENDOFF(end64buf); - end.centot = (int)ZIP64_ENDTOT(end64buf); // assume total < 2g - end.endpos = end64pos; - } - return end; - } - } - } - zerror("zip END header not found"); - return null; //make compiler happy - } - - // Reads zip file central directory. Returns the file position of first - // CEN header, otherwise returns -1 if an error occured. If zip->msg != NULL - // then the error was a zip format error and zip->msg has the error text. - // Always pass in -1 for knownTotal; it's used for a recursive call. - private byte[] initCEN() throws IOException { - end = findEND(); - if (end.endpos == 0) { - inodes = new LinkedHashMap<>(10); - locpos = 0; - return null; // only END header present - } - if (end.cenlen > end.endpos) - zerror("invalid END header (bad central directory size)"); - long cenpos = end.endpos - end.cenlen; // position of CEN table - - // Get position of first local file (LOC) header, taking into - // account that there may be a stub prefixed to the zip file. - locpos = cenpos - end.cenoff; - if (locpos < 0) - zerror("invalid END header (bad central directory offset)"); - - // read in the CEN and END - byte[] cen = new byte[(int)(end.cenlen + ENDHDR)]; - if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) { - zerror("read CEN tables failed"); - } - // Iterate through the entries in the central directory - inodes = new LinkedHashMap<>(end.centot + 1); - int pos = 0; - int limit = cen.length - ENDHDR; - while (pos < limit) { - if (CENSIG(cen, pos) != CENSIG) - zerror("invalid CEN header (bad signature)"); - int method = CENHOW(cen, pos); - int nlen = CENNAM(cen, pos); - int elen = CENEXT(cen, pos); - int clen = CENCOM(cen, pos); - if ((CENFLG(cen, pos) & 1) != 0) - zerror("invalid CEN header (encrypted entry)"); - if (method != METHOD_STORED && method != METHOD_DEFLATED) - zerror("invalid CEN header (unsupported compression method: " + method + ")"); - if (pos + CENHDR + nlen > limit) - zerror("invalid CEN header (bad header size)"); - byte[] name = Arrays.copyOfRange(cen, pos + CENHDR, pos + CENHDR + nlen); - 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)"); - } - return cen; - } - - private void ensureOpen() throws IOException { - if (!isOpen) - throw new ClosedFileSystemException(); - } - - // Creates a new empty temporary file in the same directory as the - // specified file. A variant of File.createTempFile. - private Path createTempFileInSameDirectoryAs(Path path) - throws IOException - { - Path parent = path.toAbsolutePath().getParent(); - String dir = (parent == null)? "." : parent.toString(); - Path tmpPath = File.createTempFile("zipfstmp", null, new File(dir)).toPath(); - tmppaths.add(tmpPath); - return tmpPath; - } - - ////////////////////update & sync ////////////////////////////////////// - - private boolean hasUpdate = false; - - private void updateDelete(Entry e) { - beginWrite(); - try { - inodes.remove(IndexNode.keyOf(e.name)); //inodes.remove(e.name); - hasUpdate = true; - dirs = null; - } finally { - endWrite(); - } - } - - private void update(Entry e) { - beginWrite(); - try { - inodes.put(IndexNode.keyOf(e.name), e); //inodes.put(e, e); - hasUpdate = true; - dirs = null; - } finally { - endWrite(); - } - } - - // copy over the whole LOC entry (header if necessary, data and ext) from - // old zip to the new one. - private long copyLOCEntry(Entry e, boolean updateHeader, - OutputStream os, - long written, byte[] buf) - throws IOException - { - long locoff = e.locoff; // where to read - e.locoff = written; // update the e.locoff with new value - - // calculate the size need to write out - long size = 0; - // if there is A ext - if ((e.flag & FLAG_DATADESCR) != 0) { - if (e.size >= ZIP64_MINVAL || e.csize >= ZIP64_MINVAL) - size = 24; - else - size = 16; - } - // read loc, use the original loc.elen/nlen - if (readFullyAt(buf, 0, LOCHDR , locoff) != LOCHDR) - throw new ZipException("loc: reading failed"); - if (updateHeader) { - locoff += LOCHDR + LOCNAM(buf) + LOCEXT(buf); // skip header - size += e.csize; - written = e.writeLOC(os) + size; - } else { - os.write(buf, 0, LOCHDR); // write out the loc header - locoff += LOCHDR; - size += LOCNAM(buf) + LOCEXT(buf) + LOCSIZ(buf); - written = LOCHDR + size; - } - int n; - while (size > 0 && - (n = (int)readFullyAt(buf, 0, buf.length, locoff)) != -1) - { - if (size < n) - n = (int)size; - os.write(buf, 0, n); - size -= n; - 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(); - ecc.path.delete(); - exChClosers.remove(ecc); - } - } - } - if (!hasUpdate) - return; - Path tmpFile = createTempFileInSameDirectoryAs(zfpath); - OutputStream os = tmpFile.newOutputStream(WRITE); - ArrayList<Entry> elist = new ArrayList<>(inodes.size()); - long written = 0; - byte[] buf = new byte[8192]; - Entry e = null; - - // write loc - for (IndexNode inode : inodes.values()) { - if (inode instanceof Entry) { // an updated inode - e = (Entry)inode; - try { - if (e.type == Entry.COPY) { - // entry copy: the only thing changed is the "name" - // and "nlen" in LOC header, so we udpate/rewrite the - // LOC in new file and simply copy the rest (data and - // ext) without enflating/deflating from the old zip - // file LOC entry. - written += copyLOCEntry(e, true, os, written, buf); - } else { // NEW or FILECH - 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 - InputStream is = e.file.newInputStream(); - 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 - OutputStream os2 = new EntryOutputStream(e, os); - while ((n = is.read(buf)) != -1) { - os2.write(buf, 0, n); - } - os2.close(); - written += e.csize; - if ((e.flag & FLAG_DATADESCR) != 0) - written += e.writeEXT(os); - } - is.close(); - e.file.delete(); - tmppaths.remove(e.file); - } else { - // dir, 0-length data - } - } - elist.add(e); - } catch (IOException x) { - x.printStackTrace(); // skip any in-accurate entry - } - } else { // unchanged inode - e = Entry.readCEN(this, inode.pos); - try { - written += copyLOCEntry(e, false, os, written, buf); - elist.add(e); - } catch (IOException x) { - x.printStackTrace(); // skip any wrong entry - } - } - } - - // now write back the cen and end table - end.cenoff = written; - for (Entry entry : elist) { - written += entry.writeCEN(os); - } - end.centot = elist.size(); - end.cenlen = written - end.cenoff; - end.write(os, written); - os.close(); - - 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); - zfpath.moveTo(ecc.path, REPLACE_EXISTING); - exChClosers.add(ecc); - streams = Collections.synchronizedSet(new HashSet<InputStream>()); - } else { - ch.close(); - zfpath.delete(); - } - - tmpFile.moveTo(zfpath, REPLACE_EXISTING); - hasUpdate = false; // clear - /* - if (isOpen) { - ch = zfpath.newByteChannel(READ); // re-fresh "ch" and "cen" - cen = initCEN(); - } - */ - //System.out.printf("->sync(%s) done!%n", toString()); - } - - private Entry getEntry0(byte[] path) throws IOException { - if (path == null) - throw new NullPointerException("path"); - if (path.length == 0) - return null; - IndexNode inode = null; - IndexNode key = IndexNode.keyOf(path); - if ((inode = inodes.get(key)) == null) { - if (path[path.length -1] == '/') // already has a slash - return null; - path = Arrays.copyOf(path, path.length + 1); - path[path.length - 1] = '/'; - if ((inode = inodes.get(key.as(path))) == null) - return null; - } - if (inode instanceof Entry) - return (Entry)inode; - return Entry.readCEN(this, inode.pos); - } - - // Test if the "name" a parent directory of any entry (dir empty) - boolean isAncestor(byte[] name) { - for (Map.Entry<IndexNode, IndexNode> entry : inodes.entrySet()) { - byte[] ename = entry.getKey().name; - if (isParentOf(name, ename)) - return true; - } - return false; - } - - public void deleteFile(byte[] path, boolean failIfNotExists) - throws IOException - { - checkWritable(); - Entry e = getEntry0(path); - if (e == null) { - if (path != null && path.length == 0) - throw new ZipException("root directory </> can't not be delete"); - if (failIfNotExists) - throw new NoSuchFileException(getString(path)); - } else { - if (e.isDir() && isAncestor(path)) - throw new DirectoryNotEmptyException(getString(path)); - updateDelete(e); - } - } - - 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_EFS; - OutputStream os; - if (useTempFile) { - e.file = getTempPathForEntry(null); - os = e.file.newOutputStream(WRITE); - } else { - 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 = e.file.newInputStream(); - else - throw new ZipException("update entry data is missing"); - } else if (e.type == Entry.FILECH) { - // FILECH result is un-compressed. - eis = e.file.newInputStream(); - // TBD: wrap to hook close() - // streams.add(eis); - return eis; - } else { // untouced CEN or COPY - eis = new EntryInputStream(e, ch); - } - if (e.method == METHOD_DEFLATED) { - // MORE: Compute good size for inflater stream: - long bufSize = e.size + 2; // Inflater likes a bit of slack - if (bufSize > 65536) - bufSize = 8192; - final long size = e.size; - eis = new InflaterInputStream(eis, getInflater(), (int)bufSize) { - - private boolean isClosed = false; - public void close() throws IOException { - if (!isClosed) { - releaseInflater(inf); - this.in.close(); - isClosed = true; - streams.remove(this); - } - } - // Override fill() method to provide an extra "dummy" byte - // at the end of the input stream. This is required when - // using the "nowrap" Inflater option. (it appears the new - // zlib in 7 does not need it, but keep it for now) - protected void fill() throws IOException { - if (eof) { - throw new EOFException( - "Unexpected end of ZLIB input stream"); - } - len = this.in.read(buf, 0, buf.length); - if (len == -1) { - buf[0] = 0; - len = 1; - eof = true; - } - inf.setInput(buf, 0, len); - } - private boolean eof; - - public int available() throws IOException { - if (isClosed) - return 0; - long avail = size - inf.getBytesWritten(); - return avail > (long) Integer.MAX_VALUE ? - Integer.MAX_VALUE : (int) avail; - } - }; - } else if (e.method == METHOD_STORED) { - // TBD: wrap/ it does not seem necessary - } else { - throw new ZipException("invalid compression method"); - } - streams.add(eis); - return eis; - } - - // Inner class implementing the input stream used to read - // a (possibly compressed) zip file entry. - private class EntryInputStream extends InputStream { - private final SeekableByteChannel zfch; // local ref to zipfs's "ch". zipfs.ch might - // point to a new channel after sync() - private long pos; // current position within entry data - protected long rem; // number of remaining bytes within entry - protected final long size; // uncompressed size of this entry - - EntryInputStream(Entry e, SeekableByteChannel zfch) - throws IOException - { - this.zfch = zfch; - rem = e.csize; - size = e.size; - pos = getDataPos(e); - } - public int read(byte b[], int off, int len) throws IOException { - ensureOpen(); - if (rem == 0) { - return -1; - } - if (len <= 0) { - return 0; - } - if (len > rem) { - len = (int) rem; - } - // readFullyAt() - long n = 0; - ByteBuffer bb = ByteBuffer.wrap(b); - bb.position(off); - bb.limit(off + len); - synchronized(zfch) { - n = zfch.position(pos).read(bb); - } - if (n > 0) { - pos += n; - rem -= n; - } - if (rem == 0) { - close(); - } - return (int)n; - } - public int read() throws IOException { - byte[] b = new byte[1]; - if (read(b, 0, 1) == 1) { - return b[0] & 0xff; - } else { - return -1; - } - } - public long skip(long n) throws IOException { - ensureOpen(); - if (n > rem) - n = rem; - pos += n; - rem -= n; - if (rem == 0) { - close(); - } - return n; - } - public int available() { - return rem > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) rem; - } - - public long size() { - return size; - } - public void close() { - rem = 0; - streams.remove(this); - } - } - - class EntryOutputStream extends DeflaterOutputStream - { - private CRC32 crc; - private Entry e; - private long written; - - 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 void write(byte b[], int off, int len) throws IOException { - if (e.type != Entry.FILECH) // only from sync - ensureOpen(); - 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 void close() throws IOException { - // 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) { - throw new ZipError(msg); - } - - // Maxmum number of de/inflater we cache - private final int MAX_FLATER = 20; - // List of available Inflater objects for decompression - private final List<Inflater> inflaters = new ArrayList<>(); - - // Gets an inflater from the list of available inflaters or allocates - // a new one. - private Inflater getInflater() { - synchronized (inflaters) { - int size = inflaters.size(); - if (size > 0) { - Inflater inf = (Inflater)inflaters.remove(size - 1); - return inf; - } else { - return new Inflater(true); - } - } - } - - // Releases the specified inflater to the list of available inflaters. - private void releaseInflater(Inflater inf) { - synchronized (inflaters) { - if (inflaters.size() < MAX_FLATER) { - inf.reset(); - inflaters.add(inf); - } else { - inf.end(); - } - } - } - - // List of available Deflater objects for compression - private final List<Deflater> deflaters = new ArrayList<>(); - - // Gets an deflater from the list of available deflaters or allocates - // a new one. - private Deflater getDeflater() { - synchronized (deflaters) { - int size = deflaters.size(); - if (size > 0) { - Deflater def = (Deflater)deflaters.remove(size - 1); - return def; - } else { - return new Deflater(Deflater.DEFAULT_COMPRESSION, true); - } - } - } - - // Releases the specified inflater to the list of available inflaters. - private void releaseDeflater(Deflater def) { - synchronized (deflaters) { - if (inflaters.size() < MAX_FLATER) { - def.reset(); - deflaters.add(def); - } else { - def.end(); - } - } - } - - // End of central directory record - static class END { - int disknum; - int sdisknum; - int endsub; // endsub - int centot; // 4 bytes - long cenlen; // 4 bytes - long cenoff; // 4 bytes - int comlen; // comment length - byte[] comment; - - /* members of Zip64 end of central directory locator */ - int diskNum; - long endpos; - int disktot; - - void write(OutputStream os, long offset) throws IOException { - boolean hasZip64 = false; - long xlen = cenlen; - long xoff = cenoff; - if (xlen >= ZIP64_MINVAL) { - xlen = ZIP64_MINVAL; - hasZip64 = true; - } - if (xoff >= ZIP64_MINVAL) { - xoff = ZIP64_MINVAL; - hasZip64 = true; - } - int count = centot; - if (count >= ZIP64_MINVAL32) { - count = ZIP64_MINVAL32; - hasZip64 = true; - } - if (hasZip64) { - long off64 = offset; - //zip64 end of central directory record - writeInt(os, ZIP64_ENDSIG); // zip64 END record signature - writeLong(os, ZIP64_ENDHDR - 12); // size of zip64 end - writeShort(os, 45); // version made by - writeShort(os, 45); // version needed to extract - writeInt(os, 0); // number of this disk - writeInt(os, 0); // central directory start disk - writeLong(os, centot); // number of directory entires on disk - writeLong(os, centot); // number of directory entires - writeLong(os, cenlen); // length of central directory - writeLong(os, cenoff); // offset of central directory - - //zip64 end of central directory locator - writeInt(os, ZIP64_LOCSIG); // zip64 END locator signature - writeInt(os, 0); // zip64 END start disk - writeLong(os, off64); // offset of zip64 END - writeInt(os, 1); // total number of disks (?) - } - writeInt(os, ENDSIG); // END record signature - writeShort(os, 0); // number of this disk - writeShort(os, 0); // central directory start disk - writeShort(os, count); // number of directory entries on disk - writeShort(os, count); // total number of directory entries - writeInt(os, xlen); // length of central directory - writeInt(os, xoff); // offset of central directory - if (comment != null) { // zip file comment - writeShort(os, comment.length); - writeBytes(os, comment); - } else { - writeShort(os, 0); - } - } - } - - // Internal node that links a "name" to its pos in cen table. - // The node itself can be used as a "key" to lookup itself in - // the HashMap inodes. - static class IndexNode { - byte[] name; - int hashcode; // node is hashable/hashed by its name - int pos = -1; // postion in cen table, -1 menas the - // entry does not exists in zip file - IndexNode(byte[] name, int pos) { - as(name); - this.pos = pos; - } - - final static IndexNode keyOf(byte[] name) { // get a lookup key; - return new IndexNode(name, -1); - } - - final IndexNode as(byte[] name) { // reuse the node, mostly - this.name = name; // as a lookup "key" - this.hashcode = Arrays.hashCode(name); - return this; - } - - public boolean equals(Object other) { - if (!(other instanceof IndexNode)) - return false; - return Arrays.equals(name, ((IndexNode)other).name); - } - - public int hashCode() { - return hashcode; - } - - IndexNode() {} - IndexNode sibling; - IndexNode child; // 1st child - } - - static class Entry extends IndexNode { - - static final int CEN = 1; // entry read from cen - static final int NEW = 2; // updated contents in bytes or file - static final int FILECH = 3; // fch update in "file" - static final int COPY = 4; // copy of a CEN entry - - byte[] bytes; // updated content bytes - Path file; // use tmp file to store bytes; - int type = CEN; // default is the entry read from cen - - // entry attributes - int version; - int flag; - int method = -1; // compression method - long mtime = -1; // last modification time (in DOS time) - long atime = -1; // last access time - long ctime = -1; // create time - long crc = -1; // crc-32 of entry data - long csize = -1; // compressed size of entry data - long size = -1; // uncompressed size of entry data - byte[] extra; - - // cen - int versionMade; - int disk; - int attrs; - long attrsEx; - long locoff; - byte[] comment; - - Entry() {} - - Entry(byte[] name) { - this.name = name; - this.mtime = 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) { - this.version = e.version; - this.name = e.name; - this.ctime = e.ctime; - this.atime = e.atime; - this.mtime = e.mtime; - this.crc = e.crc; - this.size = e.size; - this.csize = e.csize; - this.method = e.method; - this.extra = e.extra; - this.versionMade = e.versionMade; - this.disk = e.disk; - this.attrs = e.attrs; - this.attrsEx = e.attrsEx; - this.locoff = e.locoff; - this.comment = e.comment; - - this.type = type; - } - - Entry (byte[] name, Path file, int type) { - this(name, type); - this.file = file; - this.method = METHOD_STORED; - } - - boolean isDir() { - return name != null && - (name.length == 0 || - name[name.length - 1] == '/'); - } - - int version() throws ZipException { - if (method == METHOD_DEFLATED) - return 20; - else if (method == METHOD_STORED) - return 10; - throw new ZipException("unsupported compression method"); - } - - ///////////////////// CEN ////////////////////// - static Entry readCEN(ZipFileSystem zipfs, int pos) - throws IOException - { - return new Entry().cen(zipfs, pos); - } - - private Entry cen(ZipFileSystem zipfs, int pos) - throws IOException - { - byte[] cen = zipfs.cen; - if (CENSIG(cen, pos) != CENSIG) - zerror("invalid CEN header (bad signature)"); - versionMade = CENVEM(cen, pos); - version = CENVER(cen, pos); - flag = CENFLG(cen, pos); - method = CENHOW(cen, pos); - mtime = dosToJavaTime(CENTIM(cen, pos)); - crc = CENCRC(cen, pos); - csize = CENSIZ(cen, pos); - size = CENLEN(cen, pos); - int nlen = CENNAM(cen, pos); - int elen = CENEXT(cen, pos); - int clen = CENCOM(cen, pos); - disk = CENDSK(cen, pos); - attrs = CENATT(cen, pos); - attrsEx = CENATX(cen, pos); - locoff = CENOFF(cen, pos); - - pos += CENHDR; - name = Arrays.copyOfRange(cen, pos, pos + nlen); - - pos += nlen; - if (elen > 0) { - extra = Arrays.copyOfRange(cen, pos, pos + elen); - pos += elen; - readExtra(zipfs); - } - if (clen > 0) { - comment = Arrays.copyOfRange(cen, pos, pos + clen); - } - return this; - } - - int writeCEN(OutputStream os) throws IOException - { - int written = CENHDR; - int version0 = version(); - - long csize0 = csize; - long size0 = size; - long locoff0 = locoff; - int elen64 = 0; // extra for ZIP64 - int elenNTFS = 0; // extra for NTFS (a/c/mtime) - int elenEXTT = 0; // extra for Extended Timestamp - - // confirm size/length - int nlen = (name != null) ? name.length : 0; - int elen = (extra != null) ? extra.length : 0; - int clen = (comment != null) ? comment.length : 0; - if (csize >= ZIP64_MINVAL) { - csize0 = ZIP64_MINVAL; - elen64 += 8; // csize(8) - } - if (size >= ZIP64_MINVAL) { - size0 = ZIP64_MINVAL; // size(8) - elen64 += 8; - } - if (locoff >= ZIP64_MINVAL) { - locoff0 = ZIP64_MINVAL; - elen64 += 8; // offset(8) - } - if (elen64 != 0) - elen64 += 4; // header and data sz 4 bytes - - if (atime != -1) { - if (isWindows) // use NTFS - elenNTFS = 36; // total 36 bytes - else // Extended Timestamp otherwise - elenEXTT = 9; // only mtime in cen - } - writeInt(os, CENSIG); // CEN header signature - if (elen64 != 0) { - writeShort(os, 45); // ver 4.5 for zip64 - writeShort(os, 45); - } else { - writeShort(os, version0); // version made by - writeShort(os, version0); // version needed to extract - } - writeShort(os, flag); // general purpose bit flag - writeShort(os, method); // compression method - // last modification time - writeInt(os, (int)javaToDosTime(mtime)); - writeInt(os, crc); // crc-32 - writeInt(os, csize0); // compressed size - writeInt(os, size0); // uncompressed size - writeShort(os, name.length); - writeShort(os, elen + elen64 + elenNTFS + elenEXTT); - - if (comment != null) { - writeShort(os, Math.min(clen, 0xffff)); - } else { - writeShort(os, 0); - } - 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); - if (elen64 != 0) { - writeShort(os, EXTID_ZIP64);// Zip64 extra - writeShort(os, elen64); // size of "this" extra block - if (size0 == ZIP64_MINVAL) - writeLong(os, size); - if (csize0 == ZIP64_MINVAL) - writeLong(os, csize); - if (locoff0 == ZIP64_MINVAL) - writeLong(os, locoff); - } - if (elenNTFS != 0) { - // System.out.println("writing NTFS:" + elenNTFS); - writeShort(os, EXTID_NTFS); - writeShort(os, elenNTFS - 4); - writeInt(os, 0); // reserved - writeShort(os, 0x0001); // NTFS attr tag - writeShort(os, 24); - writeLong(os, javaToWinTime(mtime)); - writeLong(os, javaToWinTime(atime)); - writeLong(os, javaToWinTime(ctime)); - } - if (elenEXTT != 0) { - writeShort(os, EXTID_EXTT); - writeShort(os, elenEXTT - 4); - if (ctime == -1) - os.write(0x3); // mtime and atime - else - os.write(0x7); // mtime, atime and ctime - writeInt(os, javaToUnixTime(mtime)); - } - if (extra != null) // whatever not recognized - writeBytes(os, extra); - if (comment != null) //TBD: 0, Math.min(commentBytes.length, 0xffff)); - 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 (LOCSIG(buf) != LOCSIG) - throw new ZipException("loc: wrong sig ->" - + Long.toString(LOCSIG(buf), 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]; - if (zipfs.readFullyAt(name, 0, 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.getEntry0(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 : 0; - int elen = (extra != null) ? extra.length : 0; - int elen64 = 0; - int elenEXTT = 0; - if ((flag & FLAG_DATADESCR) != 0) { - writeShort(os, version()); // version needed to extract - writeShort(os, flag); // general purpose bit flag - writeShort(os, method); // compression method - // last modification time - writeInt(os, (int)javaToDosTime(mtime)); - // store size, uncompressed size, and crc-32 in data descriptor - // immediately following compressed entry data - writeInt(os, 0); - writeInt(os, 0); - writeInt(os, 0); - } else { - if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) { - elen64 = 20; //headid(2) + size(2) + size(8) + csize(8) - writeShort(os, 45); // ver 4.5 for zip64 - } else { - writeShort(os, version()); // version needed to extract - } - writeShort(os, flag); // general purpose bit flag - writeShort(os, method); // compression method - writeInt(os, mtime); // last modification time - writeInt(os, crc); // crc-32 - if (elen64 != 0) { - writeInt(os, ZIP64_MINVAL); - writeInt(os, ZIP64_MINVAL); - } else { - writeInt(os, csize); // compressed size - writeInt(os, size); // uncompressed size - } - } - if (atime != -1 && !isWindows) { // on unix use "ext time" - if (ctime == -1) - elenEXTT = 13; - else - elenEXTT = 17; - } - writeShort(os, name.length); - writeShort(os, elen + elen64 + elenEXTT); - writeBytes(os, name); - if (elen64 != 0) { - writeShort(os, EXTID_ZIP64); - writeShort(os, 16); - writeLong(os, size); - writeLong(os, csize); - } - if (elenEXTT != 0) { - writeShort(os, EXTID_EXTT); - writeShort(os, elenEXTT - 4);// size for the folowing data block - if (ctime == -1) - os.write(0x3); // mtime and atime - else - os.write(0x7); // mtime, atime and ctime - writeInt(os, javaToUnixTime(mtime)); - writeInt(os, javaToUnixTime(atime)); - if (ctime != -1) - writeInt(os, javaToUnixTime(ctime)); - } - if (extra != null) { - writeBytes(os, extra); - } - return LOCHDR + name.length + elen + elen64 + elenEXTT; - } - - // Data Descriptior - int writeEXT(OutputStream os) - throws IOException - { - writeInt(os, EXTSIG); // EXT header signature - writeInt(os, crc); // crc-32 - if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) { - writeLong(os, csize); - writeLong(os, size); - return 24; - } else { - writeInt(os, csize); // compressed size - writeInt(os, size); // uncompressed size - return 16; - } - } - - // read NTFS, UNIX and ZIP64 data from cen.extra - void readExtra(ZipFileSystem zipfs) throws IOException { - if (extra == null) - return; - int elen = extra.length; - int off = 0; - int newOff = 0; - while (off + 4 < elen) { - // extra spec: HeaderID+DataSize+Data - int pos = off; - int tag = SH(extra, pos); - int sz = SH(extra, pos + 2); - pos += 4; - if (pos + sz > elen) // invalid data - break; - switch (tag) { - case EXTID_ZIP64 : - if (size == ZIP64_MINVAL) { - if (pos + 8 > elen) // invalid zip64 extra - break; // fields, just skip - size = LL(extra, pos); - pos += 8; - } - if (csize == ZIP64_MINVAL) { - if (pos + 8 > elen) - break; - csize = LL(extra, pos); - pos += 8; - } - if (locoff == ZIP64_MINVAL) { - if (pos + 8 > elen) - break; - locoff = LL(extra, pos); - pos += 8; - } - break; - case EXTID_NTFS: - pos += 4; // reserved 4 bytes - if (SH(extra, pos) != 0x0001) - break; - if (SH(extra, pos + 2) != 24) - break; - // override the loc field, datatime here is - // more "accurate" - mtime = winToJavaTime(LL(extra, pos + 4)); - atime = winToJavaTime(LL(extra, pos + 12)); - ctime = winToJavaTime(LL(extra, pos + 20)); - break; - case EXTID_EXTT: - // spec says the Extened timestamp in cen only has mtime - // need to read the loc to get the extra a/ctime - byte[] buf = new byte[LOCHDR]; - if (zipfs.readFullyAt(buf, 0, buf.length , locoff) - != buf.length) - throw new ZipException("loc: reading failed"); - if (LOCSIG(buf) != LOCSIG) - throw new ZipException("loc: wrong sig ->" - + Long.toString(LOCSIG(buf), 16)); - - int locElen = LOCEXT(buf); - if (locElen < 9) // EXTT is at lease 9 bytes - break; - int locNlen = LOCNAM(buf); - buf = new byte[locElen]; - if (zipfs.readFullyAt(buf, 0, buf.length , locoff + LOCHDR + locNlen) - != buf.length) - throw new ZipException("loc extra: reading failed"); - int locPos = 0; - while (locPos + 4 < buf.length) { - int locTag = SH(buf, locPos); - int locSZ = SH(buf, locPos + 2); - locPos += 4; - if (locTag != EXTID_EXTT) { - locPos += locSZ; - continue; - } - int flag = CH(buf, locPos++); - if ((flag & 0x1) != 0) { - mtime = unixToJavaTime(LG(buf, locPos)); - locPos += 4; - } - if ((flag & 0x2) != 0) { - atime = unixToJavaTime(LG(buf, locPos)); - locPos += 4; - } - if ((flag & 0x4) != 0) { - ctime = unixToJavaTime(LG(buf, locPos)); - locPos += 4; - } - break; - } - break; - default: // unknown tag - System.arraycopy(extra, off, extra, newOff, sz + 4); - newOff += (sz + 4); - } - off += (sz + 4); - } - if (newOff != 0 && newOff != extra.length) - extra = Arrays.copyOf(extra, newOff); - else - extra = null; - } - } - - 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. - // A possible solution is to build the node tree ourself as - // implemented below. - private HashMap<IndexNode, IndexNode> dirs; - private IndexNode root; - private IndexNode addToDir(IndexNode child) { - IndexNode cinode = dirs.get(child); - if (cinode != null) - return cinode; - - byte[] cname = child.name; - byte[] pname = getParent(cname); - IndexNode pinode; - - if (pname != null) - pinode = addToDir(IndexNode.keyOf(pname)); - else - pinode = root; - cinode = inodes.get(child); - if (cname[cname.length -1] != '/') { // not a dir - cinode.sibling = pinode.child; - pinode.child = cinode; - return null; - } - //cinode = dirs.get(child); - if (cinode == null) // pseudo directry entry - cinode = new IndexNode(cname, -1); - cinode.sibling = pinode.child; - pinode.child = cinode; - - dirs.put(child, cinode); - return cinode; - } - - private HashMap<IndexNode, IndexNode> getDirs() - throws IOException - { - beginWrite(); - try { - if (dirs != null) - return dirs; - dirs = new HashMap<>(); - root = new IndexNode(new byte[0], -1); - dirs.put(root, root); - for (IndexNode node : inodes.keySet()) - addToDir(node); - return dirs; - } finally { - endWrite(); - } - } -}
--- a/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileSystemProvider.java Mon Dec 13 16:22:29 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.sun.nio.zipfs; - -import java.io.IOException; -import java.nio.channels.FileChannel; -import java.nio.file.FileRef; -import java.nio.file.FileSystem; -import java.nio.file.FileSystemNotFoundException; -import java.nio.file.FileSystemAlreadyExistsException; -import java.nio.file.OpenOption; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.ProviderMismatchException; -import java.nio.file.attribute.FileAttribute; -import java.nio.file.spi.FileSystemProvider; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/* - * - * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal - */ - -public class ZipFileSystemProvider extends FileSystemProvider { - - - private final Map<Path, ZipFileSystem> filesystems = new HashMap<>(); - - public ZipFileSystemProvider() {} - - @Override - public String getScheme() { - return "zip"; - } - - protected Path uriToPath(URI uri) { - String scheme = uri.getScheme(); - if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) { - throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'"); - } - try { - return Paths.get(new URI("file", uri.getHost(), uri.getPath(), null)) - .toAbsolutePath(); - } catch (URISyntaxException e) { - throw new AssertionError(e); //never thrown - } - } - - @Override - public FileSystem newFileSystem(URI uri, Map<String, ?> env) - throws IOException - { - return newFileSystem(uriToPath(uri), env); - } - - @Override - public FileSystem newFileSystem(FileRef file, Map<String, ?> env) - throws IOException - { - if (!(file instanceof Path)) - throw new UnsupportedOperationException(); - Path path = (Path)file; - if (!path.toUri().getScheme().equalsIgnoreCase("file")) { - throw new UnsupportedOperationException(); - } - return newFileSystem(path, env); - } - - private FileSystem newFileSystem(Path path, Map<String, ?> env) - throws IOException - { - synchronized(filesystems) { - Path realPath = null; - if (path.exists()) { - realPath = path.toRealPath(true); - if (filesystems.containsKey(realPath)) - throw new FileSystemAlreadyExistsException(); - } - ZipFileSystem zipfs = new ZipFileSystem(this, path, env); - if (realPath == null) - realPath = path.toRealPath(true); - filesystems.put(realPath, zipfs); - return zipfs; - } - } - - @Override - public Path getPath(URI uri) { - FileSystem fs = getFileSystem(uri); - String fragment = uri.getFragment(); - if (fragment == null) { - throw new IllegalArgumentException("URI: " - + uri - + " does not contain path fragment ex. zip:///c:/foo.zip#/BAR"); - } - return fs.getPath(fragment); - } - - @Override - public FileChannel newFileChannel(Path path, - Set<? extends OpenOption> options, - FileAttribute<?>... attrs) - throws IOException - { - if (path == null) - throw new NullPointerException("path is null"); - if (path instanceof ZipPath) - return ((ZipPath)path).newFileChannel(options, attrs); - throw new ProviderMismatchException(); - } - - @Override - public FileSystem getFileSystem(URI uri) { - synchronized (filesystems) { - ZipFileSystem zipfs = null; - try { - zipfs = filesystems.get(uriToPath(uri).toRealPath(true)); - } catch (IOException x) { - // ignore the ioe from toRealPath(), return FSNFE - } - if (zipfs == null) - throw new FileSystemNotFoundException(); - return zipfs; - } - } - - void removeFileSystem(Path zfpath) throws IOException { - synchronized (filesystems) { - filesystems.remove(zfpath.toRealPath(true)); - } - } -}
--- a/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipInfo.java Mon Dec 13 16:22:29 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.sun.nio.zipfs; - -import java.nio.file.Paths; -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; -import com.sun.nio.zipfs.ZipFileSystem.Entry; -import static com.sun.nio.zipfs.ZipConstants.*; -import static com.sun.nio.zipfs.ZipUtils.*; - -/** - * Print all loc and cen headers of the ZIP file - * - * @author Xueming Shen - */ - -public class ZipInfo { - - public static void main(String[] args) throws Throwable { - if (args.length < 1) { - print("Usage: java ZipInfo zfname"); - } else { - Map<String, ?> env = Collections.emptyMap(); - ZipFileSystem zfs = (ZipFileSystem)(new ZipFileSystemProvider() - .newFileSystem(Paths.get(args[0]), env)); - byte[] cen = zfs.cen; - if (cen == null) { - print("zip file is empty%n"); - return; - } - int pos = 0; - byte[] buf = new byte[1024]; - int no = 1; - while (pos + CENHDR < cen.length) { - print("----------------#%d--------------------%n", no++); - printCEN(cen, pos); - - // use size CENHDR as the extra bytes to read, just in case the - // loc.extra is bigger than the cen.extra, try to avoid to read - // twice - long len = LOCHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENHDR; - if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len) - zfs.zerror("read loc header failed"); - if (LOCEXT(buf) > CENEXT(cen, pos) + CENHDR) { - // have to read the second time; - len = LOCHDR + LOCNAM(buf) + LOCEXT(buf); - if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len) - zfs.zerror("read loc header failed"); - } - printLOC(buf); - pos += CENHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENCOM(cen, pos); - } - zfs.close(); - } - } - - static void print(String fmt, Object... objs) { - System.out.printf(fmt, objs); - } - - static void printLOC(byte[] loc) { - print("%n"); - print("[Local File Header]%n"); - print(" Signature : %#010x%n", LOCSIG(loc)); - if (LOCSIG(loc) != LOCSIG) { - print(" Wrong signature!"); - return; - } - print(" Version : %#6x [%d.%d]%n", - LOCVER(loc), LOCVER(loc) / 10, LOCVER(loc) % 10); - print(" Flag : %#6x%n", LOCFLG(loc)); - print(" Method : %#6x%n", LOCHOW(loc)); - print(" LastMTime : %#10x [%tc]%n", - LOCTIM(loc), dosToJavaTime(LOCTIM(loc))); - print(" CRC : %#10x%n", LOCCRC(loc)); - print(" CSize : %#10x%n", LOCSIZ(loc)); - print(" Size : %#10x%n", LOCLEN(loc)); - print(" NameLength : %#6x [%s]%n", - LOCNAM(loc), new String(loc, LOCHDR, LOCNAM(loc))); - print(" ExtraLength : %#6x%n", LOCEXT(loc)); - if (LOCEXT(loc) != 0) - printExtra(loc, LOCHDR + LOCNAM(loc), LOCEXT(loc)); - } - - static void printCEN(byte[] cen, int off) { - print("[Central Directory Header]%n"); - print(" Signature : %#010x%n", CENSIG(cen, off)); - if (CENSIG(cen, off) != CENSIG) { - print(" Wrong signature!"); - return; - } - print(" VerMadeby : %#6x [%d, %d.%d]%n", - CENVEM(cen, off), (CENVEM(cen, off) >> 8), - (CENVEM(cen, off) & 0xff) / 10, - (CENVEM(cen, off) & 0xff) % 10); - print(" VerExtract : %#6x [%d.%d]%n", - CENVER(cen, off), CENVER(cen, off) / 10, CENVER(cen, off) % 10); - print(" Flag : %#6x%n", CENFLG(cen, off)); - print(" Method : %#6x%n", CENHOW(cen, off)); - print(" LastMTime : %#10x [%tc]%n", - CENTIM(cen, off), dosToJavaTime(CENTIM(cen, off))); - print(" CRC : %#10x%n", CENCRC(cen, off)); - print(" CSize : %#10x%n", CENSIZ(cen, off)); - print(" Size : %#10x%n", CENLEN(cen, off)); - print(" NameLen : %#6x [%s]%n", - CENNAM(cen, off), new String(cen, off + CENHDR, CENNAM(cen, off))); - print(" ExtraLen : %#6x%n", CENEXT(cen, off)); - if (CENEXT(cen, off) != 0) - printExtra(cen, off + CENHDR + CENNAM(cen, off), CENEXT(cen, off)); - print(" CommentLen : %#6x%n", CENCOM(cen, off)); - print(" DiskStart : %#6x%n", CENDSK(cen, off)); - print(" Attrs : %#6x%n", CENATT(cen, off)); - print(" AttrsEx : %#10x%n", CENATX(cen, off)); - print(" LocOff : %#10x%n", CENOFF(cen, off)); - - } - - static long locoff(byte[] cen, int pos) { - long locoff = CENOFF(cen, pos); - if (locoff == ZIP64_MINVAL) { //ZIP64 - int off = pos + CENHDR + CENNAM(cen, pos); - int end = off + CENEXT(cen, pos); - while (off + 4 < end) { - int tag = SH(cen, off); - int sz = SH(cen, off + 2); - if (tag != EXTID_ZIP64) { - off += 4 + sz; - continue; - } - off += 4; - if (CENLEN(cen, pos) == ZIP64_MINVAL) - off += 8; - if (CENSIZ(cen, pos) == ZIP64_MINVAL) - off += 8; - return LL(cen, off); - } - // should never be here - } - return locoff; - } - - static void printExtra(byte[] extra, int off, int len) { - int end = off + len; - while (off + 4 < end) { - int tag = SH(extra, off); - int sz = SH(extra, off + 2); - print(" [tag=0x%04x, sz=%d, data= ", tag, sz); - if (off + sz > end) { - print(" Error: Invalid extra data, beyond extra length"); - break; - } - off += 4; - for (int i = 0; i < sz; i++) - print("%02x ", extra[off + i]); - print("]%n"); - switch (tag) { - case EXTID_ZIP64 : - print(" ->ZIP64: "); - int pos = off; - while (pos + 8 <= off + sz) { - print(" *0x%x ", LL(extra, pos)); - pos += 8; - } - print("%n"); - break; - case EXTID_NTFS: - print(" ->PKWare NTFS%n"); - // 4 bytes reserved - if (SH(extra, off + 4) != 0x0001 || SH(extra, off + 6) != 24) - print(" Error: Invalid NTFS sub-tag or subsz"); - print(" mtime:%tc%n", - winToJavaTime(LL(extra, off + 8))); - print(" atime:%tc%n", - winToJavaTime(LL(extra, off + 16))); - print(" ctime:%tc%n", - winToJavaTime(LL(extra, off + 24))); - break; - case EXTID_EXTT: - print(" ->Inof-ZIP Extended Timestamp: flag=%x%n",extra[off]); - pos = off + 1 ; - while (pos + 4 <= off + sz) { - print(" *%tc%n", - unixToJavaTime(LG(extra, pos))); - pos += 4; - } - break; - default: - } - off += sz; - } - } -}
--- a/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipPath.java Mon Dec 13 16:22:29 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,961 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.sun.nio.zipfs; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URI; -import java.nio.channels.FileChannel; -import java.nio.channels.SeekableByteChannel; -import java.nio.file.*; -import java.nio.file.DirectoryStream.Filter; -import java.nio.file.attribute.BasicFileAttributeView; -import java.nio.file.attribute.FileAttribute; -import java.nio.file.attribute.FileAttributeView; -import java.nio.file.attribute.FileTime; -import java.util.*; -import static java.nio.file.StandardOpenOption.*; -import static java.nio.file.StandardCopyOption.*; - -/** - * - * @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal - */ - -public class ZipPath extends Path { - - private final ZipFileSystem zfs; - private final byte[] path; - private volatile int[] offsets; - private int hashcode = 0; // cached hashcode (created lazily) - - ZipPath(ZipFileSystem zfs, byte[] path) { - this(zfs, path, false); - } - - ZipPath(ZipFileSystem zfs, byte[] path, boolean normalized) - { - this.zfs = zfs; - if (normalized) - this.path = path; - else - this.path = normalize(path); - } - - @Override - public ZipPath getRoot() { - if (this.isAbsolute()) - return new ZipPath(zfs, new byte[]{path[0]}); - else - return null; - } - - @Override - public Path getName() { - initOffsets(); - int count = offsets.length; - if (count == 0) - return null; // no elements so no name - if (count == 1 && path[0] != '/') - return this; - int lastOffset = offsets[count-1]; - int len = path.length - lastOffset; - byte[] result = new byte[len]; - System.arraycopy(path, lastOffset, result, 0, len); - return new ZipPath(zfs, result); - } - - @Override - public ZipPath getParent() { - initOffsets(); - int count = offsets.length; - if (count == 0) // no elements so no parent - return null; - int len = offsets[count-1] - 1; - if (len <= 0) // parent is root only (may be null) - return getRoot(); - byte[] result = new byte[len]; - System.arraycopy(path, 0, result, 0, len); - return new ZipPath(zfs, result); - } - - @Override - public int getNameCount() { - initOffsets(); - return offsets.length; - } - - @Override - public ZipPath getName(int index) { - initOffsets(); - if (index < 0 || index >= offsets.length) - throw new IllegalArgumentException(); - int begin = offsets[index]; - int len; - if (index == (offsets.length-1)) - len = path.length - begin; - else - len = offsets[index+1] - begin - 1; - // construct result - byte[] result = new byte[len]; - System.arraycopy(path, begin, result, 0, len); - return new ZipPath(zfs, result); - } - - @Override - public ZipPath subpath(int beginIndex, int endIndex) { - initOffsets(); - if (beginIndex < 0 || - beginIndex >= offsets.length || - endIndex > offsets.length || - beginIndex >= endIndex) - throw new IllegalArgumentException(); - - // starting offset and length - int begin = offsets[beginIndex]; - int len; - if (endIndex == offsets.length) - len = path.length - begin; - else - len = offsets[endIndex] - begin - 1; - // construct result - byte[] result = new byte[len]; - System.arraycopy(path, begin, result, 0, len); - return new ZipPath(zfs, result); - } - - @Override - public ZipPath toRealPath(boolean resolveLinks) throws IOException { - ZipPath realPath = new ZipPath(zfs, getResolvedPath()); - realPath.checkAccess(); - return realPath; - } - - @Override - public boolean isHidden() { - return false; - } - - @Override - public ZipPath toAbsolutePath() { - if (isAbsolute()) { - return this; - } else { - //add / bofore the existing path - byte[] defaultdir = zfs.getDefaultDir().path; - int defaultlen = defaultdir.length; - boolean endsWith = (defaultdir[defaultlen - 1] == '/'); - byte[] t = null; - if (endsWith) - t = new byte[defaultlen + path.length]; - else - t = new byte[defaultlen + 1 + path.length]; - System.arraycopy(defaultdir, 0, t, 0, defaultlen); - if (!endsWith) - t[defaultlen++] = '/'; - System.arraycopy(path, 0, t, defaultlen, path.length); - return new ZipPath(zfs, t, true); // normalized - } - } - - @Override - public URI toUri() { - String zfPath = zfs.toString(); - if (File.separatorChar == '\\') // replace all separators by '/' - zfPath = "/" + zfPath.replace("\\", "/"); - try { - return new URI("zip", "", - zfPath, - zfs.getString(toAbsolutePath().path)); - } catch (Exception ex) { - throw new AssertionError(ex); - } - } - - private boolean equalsNameAt(ZipPath other, int index) { - int mbegin = offsets[index]; - int mlen = 0; - if (index == (offsets.length-1)) - mlen = path.length - mbegin; - else - mlen = offsets[index + 1] - mbegin - 1; - int obegin = other.offsets[index]; - int olen = 0; - if (index == (other.offsets.length - 1)) - olen = other.path.length - obegin; - else - olen = other.offsets[index + 1] - obegin - 1; - if (mlen != olen) - return false; - int n = 0; - while(n < mlen) { - if (path[mbegin + n] != other.path[obegin + n]) - return false; - n++; - } - return true; - } - - @Override - public Path relativize(Path other) { - final ZipPath o = checkPath(other); - if (o.equals(this)) - return null; - if (/* this.getFileSystem() != o.getFileSystem() || */ - this.isAbsolute() != o.isAbsolute()) { - throw new IllegalArgumentException(); - } - int mc = this.getNameCount(); - int oc = o.getNameCount(); - int n = Math.min(mc, oc); - int i = 0; - while (i < n) { - if (!equalsNameAt(o, i)) - break; - i++; - } - int dotdots = mc - i; - int len = dotdots * 3 - 1; - if (i < oc) - len += (o.path.length - o.offsets[i] + 1); - byte[] result = new byte[len]; - - int pos = 0; - while (dotdots > 0) { - result[pos++] = (byte)'.'; - result[pos++] = (byte)'.'; - if (pos < len) // no tailing slash at the end - result[pos++] = (byte)'/'; - dotdots--; - } - if (i < oc) - System.arraycopy(o.path, o.offsets[i], - result, pos, - o.path.length - o.offsets[i]); - return new ZipPath(getFileSystem(), result); - } - - @Override - public ZipFileSystem getFileSystem() { - return zfs; - } - - @Override - public boolean isAbsolute() { - return (this.path[0] == '/'); - } - - @Override - public ZipPath resolve(Path other) { - if (other == null) - return this; - final ZipPath o = checkPath(other); - if (o.isAbsolute()) - return o; - byte[] resolved = null; - if (this.path[path.length - 1] == '/') { - resolved = new byte[path.length + o.path.length]; - System.arraycopy(path, 0, resolved, 0, path.length); - System.arraycopy(o.path, 0, resolved, path.length, o.path.length); - } else { - resolved = new byte[path.length + 1 + o.path.length]; - System.arraycopy(path, 0, resolved, 0, path.length); - resolved[path.length] = '/'; - System.arraycopy(o.path, 0, resolved, path.length + 1, o.path.length); - } - return new ZipPath(zfs, resolved); - } - - @Override - public ZipPath resolve(String other) { - return resolve(getFileSystem().getPath(other)); - } - - @Override - public boolean startsWith(Path other) { - final ZipPath o = checkPath(other); - if (o.isAbsolute() != this.isAbsolute()) - return false; - final int oCount = o.getNameCount(); - if (getNameCount() < oCount) - return false; - for (int i = 0; i < oCount; i++) { - if (!o.getName(i).equals(getName(i))) - return false; - } - return true; - } - - @Override - public boolean endsWith(Path other) { - final ZipPath o = checkPath(other); - if (o.isAbsolute()) - return this.isAbsolute() ? this.equals(o) : false; - int i = o.getNameCount(); - int j = this.getNameCount(); - if (j < i) - return false; - for (--i, --j; i >= 0; i--, j--) { - if (!o.getName(i).equals(this.getName(j))) - return false; - } - return true; - } - - @Override - public Path normalize() { - byte[] resolved = getResolved(); - if (resolved == path) // no change - return this; - if (resolved.length == 0) - return null; - return new ZipPath(zfs, resolved, true); - } - - private ZipPath checkPath(Path path) { - if (path == null) - throw new NullPointerException(); - if (!(path instanceof ZipPath)) - throw new ProviderMismatchException(); - return (ZipPath) path; - } - - // create offset list if not already created - private void initOffsets() { - if (offsets == null) { - int count, index; - // count names - count = 0; - index = 0; - while (index < path.length) { - byte c = path[index++]; - if (c != '/') { - count++; - while (index < path.length && path[index] != '/') - index++; - } - } - // populate offsets - int[] result = new int[count]; - count = 0; - index = 0; - while (index < path.length) { - byte c = path[index]; - if (c == '/') { - index++; - } else { - result[count++] = index++; - while (index < path.length && path[index] != '/') - index++; - } - } - synchronized (this) { - if (offsets == null) - offsets = result; - } - } - } - - // resolved path for locating zip entry inside the zip file, - // the result path does not contain ./ and .. components - private volatile byte[] resolved = null; - byte[] getResolvedPath() { - byte[] r = resolved; - if (r == null) { - if (isAbsolute()) - r = getResolved(); - else - r = toAbsolutePath().getResolvedPath(); - if (r[0] == '/') - r = Arrays.copyOfRange(r, 1, r.length); - resolved = r; - } - return resolved; - } - - // removes redundant slashs, replace "\" to zip separator "/" - // and check for invalid characters - private byte[] normalize(byte[] path) { - if (path.length == 0) - return path; - byte prevC = 0; - for (int i = 0; i < path.length; i++) { - byte c = path[i]; - if (c == '\\') - return normalize(path, i); - if (c == (byte)'/' && prevC == '/') - return normalize(path, i - 1); - if (c == '\u0000') - throw new InvalidPathException(zfs.getString(path), - "Path: nul character not allowed"); - prevC = c; - } - return path; - } - - private byte[] normalize(byte[] path, int off) { - byte[] to = new byte[path.length]; - int n = 0; - while (n < off) { - to[n] = path[n]; - n++; - } - int m = n; - byte prevC = 0; - while (n < path.length) { - byte c = path[n++]; - if (c == (byte)'\\') - c = (byte)'/'; - if (c == (byte)'/' && prevC == (byte)'/') - continue; - if (c == '\u0000') - throw new InvalidPathException(zfs.getString(path), - "Path: nul character not allowed"); - to[m++] = c; - prevC = c; - } - if (m > 1 && to[m - 1] == '/') - m--; - return (m == to.length)? to : Arrays.copyOf(to, m); - } - - // Remove DotSlash(./) and resolve DotDot (..) components - private byte[] getResolved() { - if (path.length == 0) - return path; - for (int i = 0; i < path.length; i++) { - byte c = path[i]; - if (c == (byte)'.') - return resolve0(); - } - return path; - } - - // TBD: performance, avoid initOffsets - private byte[] resolve0() { - byte[] to = new byte[path.length]; - int nc = getNameCount(); - int[] lastM = new int[nc]; - int lastMOff = -1; - int m = 0; - for (int i = 0; i < nc; i++) { - int n = offsets[i]; - int len = (i == offsets.length - 1)? - (path.length - n):(offsets[i + 1] - n - 1); - if (len == 1 && path[n] == (byte)'.') - continue; - if (len == 2 && path[n] == '.' && path[n + 1] == '.') { - if (lastMOff >= 0) { - m = lastM[lastMOff--]; // retreat - continue; - } - if (path[0] == '/') { // "/../xyz" skip - if (m == 0) - to[m++] = '/'; - } else { // "../xyz" -> "../xyz" - if (m != 0 && to[m-1] != '/') - to[m++] = '/'; - while (len-- > 0) - to[m++] = path[n++]; - } - continue; - } - if (m == 0 && path[0] == '/' || // absolute path - m != 0 && to[m-1] != '/') { // not the first name - to[m++] = '/'; - } - lastM[++lastMOff] = m; - while (len-- > 0) - to[m++] = path[n++]; - } - if (m > 1 && to[m - 1] == '/') - m--; - return (m == to.length)? to : Arrays.copyOf(to, m); - } - - @Override - public String toString() { - return zfs.getString(path); - } - - @Override - public int hashCode() { - int h = hashcode; - if (h == 0) - hashcode = h = Arrays.hashCode(path); - return h; - } - - @Override - public boolean equals(Object obj) { - return obj != null && - obj instanceof ZipPath && - this.zfs == ((ZipPath)obj).zfs && - compareTo((Path) obj) == 0; - } - - @Override - public int compareTo(Path other) { - final ZipPath o = checkPath(other); - int len1 = this.path.length; - int len2 = o.path.length; - - int n = Math.min(len1, len2); - byte v1[] = this.path; - byte v2[] = o.path; - - int k = 0; - while (k < n) { - int c1 = v1[k] & 0xff; - int c2 = v2[k] & 0xff; - if (c1 != c2) - return c1 - c2; - k++; - } - return len1 - len2; - } - - @Override - public Path createSymbolicLink( - Path target, FileAttribute<?>... attrs) throws IOException { - throw new UnsupportedOperationException("Not supported."); - } - - @Override - public Path createLink( - Path existing) throws IOException { - throw new UnsupportedOperationException("Not supported."); - } - - @Override - public Path readSymbolicLink() throws IOException { - throw new UnsupportedOperationException("Not supported."); - } - - @Override - public Path createDirectory(FileAttribute<?>... attrs) - throws IOException - { - zfs.createDirectory(getResolvedPath(), attrs); - return this; - } - - public final Path createFile(FileAttribute<?>... attrs) - throws IOException - { - OutputStream os = newOutputStream(CREATE_NEW, WRITE); - try { - os.close(); - } catch (IOException x) {} - return this; - } - - @Override - public InputStream newInputStream(OpenOption... options) - throws IOException { - if (options.length > 0) { - for (OpenOption opt : options) { - if (opt != READ) - throw new UnsupportedOperationException("'" + opt + "' not allowed"); - } - } - return zfs.newInputStream(getResolvedPath()); - } - - private static final DirectoryStream.Filter<Path> acceptAllFilter = - new DirectoryStream.Filter<>() { - @Override public boolean accept(Path entry) { return true; } - }; - - @Override - public final DirectoryStream<Path> newDirectoryStream() throws IOException { - return newDirectoryStream(acceptAllFilter); - } - - @Override - public DirectoryStream<Path> newDirectoryStream(Filter<? super Path> filter) - throws IOException - { - return new ZipDirectoryStream(this, filter); - } - - @Override - public final DirectoryStream<Path> newDirectoryStream(String glob) - throws IOException - { - // avoid creating a matcher if all entries are required. - if (glob.equals("*")) - return newDirectoryStream(); - - // create a matcher and return a filter that uses it. - final PathMatcher matcher = getFileSystem().getPathMatcher("glob:" + glob); - DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<>() { - @Override - public boolean accept(Path entry) { - return matcher.matches(entry.getName()); - } - }; - return newDirectoryStream(filter); - } - - @Override - public final void delete() throws IOException { - zfs.deleteFile(getResolvedPath(), true); - } - - @Override - public final void deleteIfExists() throws IOException { - zfs.deleteFile(getResolvedPath(), false); - } - - ZipFileAttributes getAttributes() throws IOException - { - ZipFileAttributes zfas = zfs.getFileAttributes(getResolvedPath()); - if (zfas == null) - throw new NoSuchFileException(toString()); - return zfas; - } - - @Override - @SuppressWarnings("unchecked") - public <V extends FileAttributeView> V getFileAttributeView(Class<V> type, - LinkOption... options) - { - return (V)ZipFileAttributeView.get(this, type); - } - - @Override - public void setAttribute(String attribute, - Object value, - LinkOption... options) - throws IOException - { - String type = null; - String attr = null; - int colonPos = attribute.indexOf(':'); - if (colonPos == -1) { - type = "basic"; - attr = attribute; - } else { - type = attribute.substring(0, colonPos++); - attr = attribute.substring(colonPos); - } - ZipFileAttributeView view = ZipFileAttributeView.get(this, type); - if (view == null) - throw new UnsupportedOperationException("view <" + view + "> is not supported"); - view.setAttribute(attr, value); - } - - void setTimes(FileTime mtime, FileTime atime, FileTime ctime) - throws IOException - { - zfs.setTimes(getResolvedPath(), mtime, atime, ctime); - } - - private Object getAttributesImpl(String attribute, boolean domap) - throws IOException - { - String view = null; - String attr = null; - int colonPos = attribute.indexOf(':'); - if (colonPos == -1) { - view = "basic"; - attr = attribute; - } else { - view = attribute.substring(0, colonPos++); - attr = attribute.substring(colonPos); - } - ZipFileAttributeView zfv = ZipFileAttributeView.get(this, view); - if (zfv == null) { - throw new UnsupportedOperationException("view not supported"); - } - return zfv.getAttribute(attr, domap); - } - - @Override - public Object getAttribute(String attribute, LinkOption... options) - throws IOException - { - return getAttributesImpl(attribute, false); - } - - @Override - public Map<String,?> readAttributes(String attribute, LinkOption... options) - throws IOException - { - return (Map<String, ?>)getAttributesImpl(attribute, true); - } - - @Override - public FileStore getFileStore() throws IOException { - // each ZipFileSystem only has one root (as requested for now) - if (exists()) - return zfs.getFileStore(this); - throw new NoSuchFileException(zfs.getString(path)); - } - - @Override - public boolean isSameFile(Path other) throws IOException { - if (other == null || - this.getFileSystem() != other.getFileSystem()) - return false; - this.checkAccess(); - other.checkAccess(); - return Arrays.equals(this.getResolvedPath(), - ((ZipPath)other).getResolvedPath()); - } - - public WatchKey register( - WatchService watcher, - WatchEvent.Kind<?>[] events, - WatchEvent.Modifier... modifiers) { - if (watcher == null || events == null || modifiers == null) { - throw new NullPointerException(); - } - throw new UnsupportedOperationException(); - } - - @Override - public WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events) { - return register(watcher, events, new WatchEvent.Modifier[0]); - } - - @Override - public Iterator<Path> iterator() { - return new Iterator<>() { - private int i = 0; - - @Override - public boolean hasNext() { - return (i < getNameCount()); - } - - @Override - public Path next() { - if (i < getNameCount()) { - Path result = getName(i); - i++; - return result; - } else { - throw new NoSuchElementException(); - } - } - - @Override - public void remove() { - throw new ReadOnlyFileSystemException(); - } - }; - } - - @Override - public SeekableByteChannel newByteChannel(Set<? extends OpenOption> options, - FileAttribute<?>... attrs) - throws IOException - { - return zfs.newByteChannel(getResolvedPath(), options, attrs); - } - - - FileChannel newFileChannel(Set<? extends OpenOption> options, - FileAttribute<?>... attrs) - throws IOException - { - return zfs.newFileChannel(getResolvedPath(), options, attrs); - } - - @Override - public SeekableByteChannel newByteChannel(OpenOption... options) - throws IOException { - Set<OpenOption> set = new HashSet<>(options.length); - Collections.addAll(set, options); - return newByteChannel(set); - } - - @Override - public void checkAccess(AccessMode... modes) throws IOException { - boolean w = false; - boolean x = false; - for (AccessMode mode : modes) { - switch (mode) { - case READ: - break; - case WRITE: - w = true; - break; - case EXECUTE: - x = true; - break; - default: - throw new UnsupportedOperationException(); - } - } - ZipFileAttributes attrs = zfs.getFileAttributes(getResolvedPath()); - if (attrs == null && (path.length != 1 || path[0] != '/')) - throw new NoSuchFileException(toString()); - if (w) { - if (zfs.isReadOnly()) - throw new AccessDeniedException(toString()); - } - if (x) - throw new AccessDeniedException(toString()); - - } - - @Override - public boolean exists() { - if (path.length == 1 && path[0] == '/') - return true; - try { - return zfs.exists(getResolvedPath()); - } catch (IOException x) {} - return false; - } - - @Override - public boolean notExists() { - return !exists(); - } - - - @Override - public OutputStream newOutputStream(OpenOption... options) - throws IOException - { - if (options.length == 0) - return zfs.newOutputStream(getResolvedPath(), - CREATE_NEW, WRITE); - return zfs.newOutputStream(getResolvedPath(), options); - } - - @Override - public Path moveTo(Path target, CopyOption... options) - throws IOException - { - if (this.zfs.provider() == target.getFileSystem().provider() && - this.zfs.getZipFile().isSameFile(((ZipPath)target).zfs.getZipFile())) - { - zfs.copyFile(true, - getResolvedPath(), - ((ZipPath)target).getResolvedPath(), - options); - } else { - copyToTarget(target, options); - delete(); - } - return target; - } - - @Override - public Path copyTo(Path target, CopyOption... options) - throws IOException - { - if (this.zfs.provider() == target.getFileSystem().provider() && - this.zfs.getZipFile().isSameFile(((ZipPath)target).zfs.getZipFile())) - { - zfs.copyFile(false, - getResolvedPath(), - ((ZipPath)target).getResolvedPath(), - options); - } else { - copyToTarget(target, options); - } - return target; - } - - private void copyToTarget(Path target, CopyOption... options) - throws IOException - { - boolean replaceExisting = false; - boolean copyAttrs = false; - for (CopyOption opt : options) { - if (opt == REPLACE_EXISTING) - replaceExisting = true; - else if (opt == COPY_ATTRIBUTES) - copyAttrs = true; - } - // attributes of source file - ZipFileAttributes zfas = getAttributes(); - // check if target exists - boolean exists; - if (replaceExisting) { - try { - target.deleteIfExists(); - exists = false; - } catch (DirectoryNotEmptyException x) { - exists = true; - } - } else { - exists = target.exists(); - } - if (exists) - throw new FileAlreadyExistsException(target.toString()); - - if (zfas.isDirectory()) { - // create directory or file - target.createDirectory(); - } else { - InputStream is = zfs.newInputStream(getResolvedPath()); - try { - OutputStream os = target.newOutputStream(); - try { - byte[] buf = new byte[8192]; - int n = 0; - while ((n = is.read(buf)) != -1) { - os.write(buf, 0, n); - } - } finally { - os.close(); - } - } finally { - is.close(); - } - } - if (copyAttrs) { - BasicFileAttributeView view = - target.getFileAttributeView(BasicFileAttributeView.class); - try { - view.setTimes(zfas.lastModifiedTime(), - zfas.lastAccessTime(), - zfas.creationTime()); - } catch (IOException x) { - // rollback? - try { - target.delete(); - } catch (IOException ignore) { } - throw x; - } - } - } -}
--- a/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipUtils.java Mon Dec 13 16:22:29 2010 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,311 +0,0 @@ -/* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.sun.nio.zipfs; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Arrays; -import java.util.Date; -import java.util.regex.PatternSyntaxException; -import java.util.concurrent.TimeUnit; - -/** - * - * @author Xueming Shen - */ - -class ZipUtils { - - /* - * Writes a 16-bit short to the output stream in little-endian byte order. - */ - public static void writeShort(OutputStream os, int v) throws IOException { - os.write(v & 0xff); - os.write((v >>> 8) & 0xff); - } - - /* - * Writes a 32-bit int to the output stream in little-endian byte order. - */ - public static void writeInt(OutputStream os, long v) throws IOException { - os.write((int)(v & 0xff)); - os.write((int)((v >>> 8) & 0xff)); - os.write((int)((v >>> 16) & 0xff)); - os.write((int)((v >>> 24) & 0xff)); - } - - /* - * Writes a 64-bit int to the output stream in little-endian byte order. - */ - public static void writeLong(OutputStream os, long v) throws IOException { - os.write((int)(v & 0xff)); - os.write((int)((v >>> 8) & 0xff)); - os.write((int)((v >>> 16) & 0xff)); - os.write((int)((v >>> 24) & 0xff)); - os.write((int)((v >>> 32) & 0xff)); - os.write((int)((v >>> 40) & 0xff)); - os.write((int)((v >>> 48) & 0xff)); - os.write((int)((v >>> 56) & 0xff)); - } - - /* - * Writes an array of bytes to the output stream. - */ - public static void writeBytes(OutputStream os, byte[] b) - throws IOException - { - os.write(b, 0, b.length); - } - - /* - * Writes an array of bytes to the output stream. - */ - public static void writeBytes(OutputStream os, byte[] b, int off, int len) - throws IOException - { - os.write(b, off, len); - } - - /* - * Append a slash at the end, if it does not have one yet - */ - public static byte[] toDirectoryPath(byte[] dir) { - if (dir.length != 0 && dir[dir.length - 1] != '/') { - dir = Arrays.copyOf(dir, dir.length + 1); - dir[dir.length - 1] = '/'; - } - return dir; - } - - /* - * Converts DOS time to Java time (number of milliseconds since epoch). - */ - public static long dosToJavaTime(long dtime) { - Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80), - (int)(((dtime >> 21) & 0x0f) - 1), - (int)((dtime >> 16) & 0x1f), - (int)((dtime >> 11) & 0x1f), - (int)((dtime >> 5) & 0x3f), - (int)((dtime << 1) & 0x3e)); - return d.getTime(); - } - - /* - * Converts Java time to DOS time. - */ - public static long javaToDosTime(long time) { - Date d = new Date(time); - int year = d.getYear() + 1900; - if (year < 1980) { - return (1 << 21) | (1 << 16); - } - return (year - 1980) << 25 | (d.getMonth() + 1) << 21 | - d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 | - d.getSeconds() >> 1; - } - - - // used to adjust values between Windows and java epoch - private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L; - public static final long winToJavaTime(long wtime) { - return TimeUnit.MILLISECONDS.convert( - wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS, TimeUnit.MICROSECONDS); - } - - public static final long javaToWinTime(long time) { - return (TimeUnit.MICROSECONDS.convert(time, TimeUnit.MILLISECONDS) - - WINDOWS_EPOCH_IN_MICROSECONDS) * 10; - } - - public static final long unixToJavaTime(long utime) { - return TimeUnit.MILLISECONDS.convert(utime, TimeUnit.SECONDS); - } - - public static final long javaToUnixTime(long time) { - return TimeUnit.SECONDS.convert(time, TimeUnit.MILLISECONDS); - } - - private static final String regexMetaChars = ".^$+{[]|()"; - private static final String globMetaChars = "\\*?[{"; - private static boolean isRegexMeta(char c) { - return regexMetaChars.indexOf(c) != -1; - } - private static boolean isGlobMeta(char c) { - return globMetaChars.indexOf(c) != -1; - } - private static char EOL = 0; //TBD - private static char next(String glob, int i) { - if (i < glob.length()) { - return glob.charAt(i); - } - return EOL; - } - - /* - * Creates a regex pattern from the given glob expression. - * - * @throws PatternSyntaxException - */ - public static String toRegexPattern(String globPattern) { - boolean inGroup = false; - StringBuilder regex = new StringBuilder("^"); - - int i = 0; - while (i < globPattern.length()) { - char c = globPattern.charAt(i++); - switch (c) { - case '\\': - // escape special characters - if (i == globPattern.length()) { - throw new PatternSyntaxException("No character to escape", - globPattern, i - 1); - } - char next = globPattern.charAt(i++); - if (isGlobMeta(next) || isRegexMeta(next)) { - regex.append('\\'); - } - regex.append(next); - break; - case '/': - regex.append(c); - break; - case '[': - // don't match name separator in class - regex.append("[[^/]&&["); - if (next(globPattern, i) == '^') { - // escape the regex negation char if it appears - regex.append("\\^"); - i++; - } else { - // negation - if (next(globPattern, i) == '!') { - regex.append('^'); - i++; - } - // hyphen allowed at start - if (next(globPattern, i) == '-') { - regex.append('-'); - i++; - } - } - boolean hasRangeStart = false; - char last = 0; - while (i < globPattern.length()) { - c = globPattern.charAt(i++); - if (c == ']') { - break; - } - if (c == '/') { - throw new PatternSyntaxException("Explicit 'name separator' in class", - globPattern, i - 1); - } - // TBD: how to specify ']' in a class? - if (c == '\\' || c == '[' || - c == '&' && next(globPattern, i) == '&') { - // escape '\', '[' or "&&" for regex class - regex.append('\\'); - } - regex.append(c); - - if (c == '-') { - if (!hasRangeStart) { - throw new PatternSyntaxException("Invalid range", - globPattern, i - 1); - } - if ((c = next(globPattern, i++)) == EOL || c == ']') { - break; - } - if (c < last) { - throw new PatternSyntaxException("Invalid range", - globPattern, i - 3); - } - regex.append(c); - hasRangeStart = false; - } else { - hasRangeStart = true; - last = c; - } - } - if (c != ']') { - throw new PatternSyntaxException("Missing ']", globPattern, i - 1); - } - regex.append("]]"); - break; - case '{': - if (inGroup) { - throw new PatternSyntaxException("Cannot nest groups", - globPattern, i - 1); - } - regex.append("(?:(?:"); - inGroup = true; - break; - case '}': - if (inGroup) { - regex.append("))"); - inGroup = false; - } else { - regex.append('}'); - } - break; - case ',': - if (inGroup) { - regex.append(")|(?:"); - } else { - regex.append(','); - } - break; - case '*': - if (next(globPattern, i) == '*') { - // crosses directory boundaries - regex.append(".*"); - i++; - } else { - // within directory boundary - regex.append("[^/]*"); - } - break; - case '?': - regex.append("[^/]"); - break; - default: - if (isRegexMeta(c)) { - regex.append('\\'); - } - regex.append(c); - } - } - if (inGroup) { - throw new PatternSyntaxException("Missing '}", globPattern, i - 1); - } - return regex.append('$').toString(); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/demo/nio/zipfs/src/META-INF/services/java.nio.file.spi.FileSystemProvider Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,2 @@ +com.sun.nio.zipfs.ZipFileSystemProvider +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/JarFileSystemProvider.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Sun Microsystems nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.sun.nio.zipfs; + +import java.nio.file.*; +import java.nio.file.spi.*; +import java.nio.file.attribute.*; +import java.nio.file.spi.FileSystemProvider; + +import java.net.URI; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.channels.FileChannel; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class JarFileSystemProvider extends ZipFileSystemProvider +{ + + @Override + public String getScheme() { + return "jar"; + } + + @Override + protected Path uriToPath(URI uri) { + String scheme = uri.getScheme(); + if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) { + throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'"); + } + try { + String uristr = uri.toString(); + int end = uristr.indexOf("!/"); + uristr = uristr.substring(4, (end == -1) ? uristr.length() : end); + uri = new URI(uristr); + return Paths.get(new URI("file", uri.getHost(), uri.getPath(), null)) + .toAbsolutePath(); + } catch (URISyntaxException e) { + throw new AssertionError(e); //never thrown + } + } + + @Override + public Path getPath(URI uri) { + FileSystem fs = getFileSystem(uri); + String path = uri.getFragment(); + if (path == null) { + String uristr = uri.toString(); + int off = uristr.indexOf("!/"); + if (off != -1) + path = uristr.substring(off + 2); + } + if (path != null) + return fs.getPath(path); + throw new IllegalArgumentException("URI: " + + uri + + " does not contain path fragment ex. jar:///c:/foo.zip!/BAR"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipCoder.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sun.nio.zipfs; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; +import java.util.Arrays; + +/** + * Utility class for zipfile name and comment decoding and encoding + * + * @author Xueming Shen + */ + +final class ZipCoder { + + String toString(byte[] ba, int length) { + CharsetDecoder cd = decoder().reset(); + int len = (int)(length * cd.maxCharsPerByte()); + char[] ca = new char[len]; + if (len == 0) + return new String(ca); + ByteBuffer bb = ByteBuffer.wrap(ba, 0, length); + CharBuffer cb = CharBuffer.wrap(ca); + CoderResult cr = cd.decode(bb, cb, true); + if (!cr.isUnderflow()) + throw new IllegalArgumentException(cr.toString()); + cr = cd.flush(cb); + if (!cr.isUnderflow()) + throw new IllegalArgumentException(cr.toString()); + return new String(ca, 0, cb.position()); + } + + String toString(byte[] ba) { + return toString(ba, ba.length); + } + + byte[] getBytes(String s) { + CharsetEncoder ce = encoder().reset(); + char[] ca = s.toCharArray(); + int len = (int)(ca.length * ce.maxBytesPerChar()); + byte[] ba = new byte[len]; + if (len == 0) + return ba; + ByteBuffer bb = ByteBuffer.wrap(ba); + CharBuffer cb = CharBuffer.wrap(ca); + CoderResult cr = ce.encode(cb, bb, true); + if (!cr.isUnderflow()) + throw new IllegalArgumentException(cr.toString()); + cr = ce.flush(bb); + if (!cr.isUnderflow()) + throw new IllegalArgumentException(cr.toString()); + if (bb.position() == ba.length) // defensive copy? + return ba; + else + return Arrays.copyOf(ba, bb.position()); + } + + // assume invoked only if "this" is not utf8 + byte[] getBytesUTF8(String s) { + if (isutf8) + return getBytes(s); + if (utf8 == null) + utf8 = new ZipCoder(Charset.forName("UTF-8")); + return utf8.getBytes(s); + } + + String toStringUTF8(byte[] ba, int len) { + if (isutf8) + return toString(ba, len); + if (utf8 == null) + utf8 = new ZipCoder(Charset.forName("UTF-8")); + return utf8.toString(ba, len); + } + + boolean isUTF8() { + return isutf8; + } + + private Charset cs; + private boolean isutf8; + private ZipCoder utf8; + + private ZipCoder(Charset cs) { + this.cs = cs; + this.isutf8 = cs.name().equals("UTF-8"); + } + + static ZipCoder get(Charset charset) { + return new ZipCoder(charset); + } + + static ZipCoder get(String csn) { + try { + return new ZipCoder(Charset.forName(csn)); + } catch (Throwable t) { + t.printStackTrace(); + } + return new ZipCoder(Charset.defaultCharset()); + } + + private final ThreadLocal<CharsetDecoder> decTL = new ThreadLocal<>(); + private final ThreadLocal<CharsetEncoder> encTL = new ThreadLocal<>(); + + private CharsetDecoder decoder() { + CharsetDecoder dec = decTL.get(); + if (dec == null) { + dec = cs.newDecoder() + .onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT); + decTL.set(dec); + } + return dec; + } + + private CharsetEncoder encoder() { + CharsetEncoder enc = encTL.get(); + if (enc == null) { + enc = cs.newEncoder() + .onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT); + encTL.set(enc); + } + return enc; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipConstants.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sun.nio.zipfs; + + +/** + * + * @author Xueming Shen + */ + +class ZipConstants { + /* + * Compression methods + */ + static final int METHOD_STORED = 0; + static final int METHOD_DEFLATED = 8; + static final int METHOD_DEFLATED64 = 9; + static final int METHOD_BZIP2 = 12; + static final int METHOD_LZMA = 14; + static final int METHOD_LZ77 = 19; + static final int METHOD_AES = 99; + + /* + * General purpose big flag + */ + static final int FLAG_ENCRYPTED = 0x01; + static final int FLAG_DATADESCR = 0x08; // crc, size and csize in dd + static final int FLAG_EFS = 0x800; // If this bit is set the filename and + // comment fields for this file must be + // encoded using UTF-8. + /* + * Header signatures + */ + static long LOCSIG = 0x04034b50L; // "PK\003\004" + static long EXTSIG = 0x08074b50L; // "PK\007\008" + static long CENSIG = 0x02014b50L; // "PK\001\002" + static long ENDSIG = 0x06054b50L; // "PK\005\006" + + /* + * Header sizes in bytes (including signatures) + */ + static final int LOCHDR = 30; // LOC header size + static final int EXTHDR = 16; // EXT header size + static final int CENHDR = 46; // CEN header size + static final int ENDHDR = 22; // END header size + + /* + * Local file (LOC) header field offsets + */ + static final int LOCVER = 4; // version needed to extract + static final int LOCFLG = 6; // general purpose bit flag + static final int LOCHOW = 8; // compression method + static final int LOCTIM = 10; // modification time + static final int LOCCRC = 14; // uncompressed file crc-32 value + static final int LOCSIZ = 18; // compressed size + static final int LOCLEN = 22; // uncompressed size + static final int LOCNAM = 26; // filename length + static final int LOCEXT = 28; // extra field length + + /* + * Extra local (EXT) header field offsets + */ + static final int EXTCRC = 4; // uncompressed file crc-32 value + static final int EXTSIZ = 8; // compressed size + static final int EXTLEN = 12; // uncompressed size + + /* + * Central directory (CEN) header field offsets + */ + static final int CENVEM = 4; // version made by + static final int CENVER = 6; // version needed to extract + static final int CENFLG = 8; // encrypt, decrypt flags + static final int CENHOW = 10; // compression method + static final int CENTIM = 12; // modification time + static final int CENCRC = 16; // uncompressed file crc-32 value + static final int CENSIZ = 20; // compressed size + static final int CENLEN = 24; // uncompressed size + static final int CENNAM = 28; // filename length + static final int CENEXT = 30; // extra field length + static final int CENCOM = 32; // comment length + static final int CENDSK = 34; // disk number start + static final int CENATT = 36; // internal file attributes + static final int CENATX = 38; // external file attributes + static final int CENOFF = 42; // LOC header offset + + /* + * End of central directory (END) header field offsets + */ + static final int ENDSUB = 8; // number of entries on this disk + static final int ENDTOT = 10; // total number of entries + static final int ENDSIZ = 12; // central directory size in bytes + static final int ENDOFF = 16; // offset of first CEN header + static final int ENDCOM = 20; // zip file comment length + + /* + * ZIP64 constants + */ + static final long ZIP64_ENDSIG = 0x06064b50L; // "PK\006\006" + static final long ZIP64_LOCSIG = 0x07064b50L; // "PK\006\007" + static final int ZIP64_ENDHDR = 56; // ZIP64 end header size + static final int ZIP64_LOCHDR = 20; // ZIP64 end loc header size + static final int ZIP64_EXTHDR = 24; // EXT header size + static final int ZIP64_EXTID = 0x0001; // Extra field Zip64 header ID + + static final int ZIP64_MINVAL32 = 0xFFFF; + static final long ZIP64_MINVAL = 0xFFFFFFFFL; + + /* + * Zip64 End of central directory (END) header field offsets + */ + static final int ZIP64_ENDLEN = 4; // size of zip64 end of central dir + static final int ZIP64_ENDVEM = 12; // version made by + static final int ZIP64_ENDVER = 14; // version needed to extract + static final int ZIP64_ENDNMD = 16; // number of this disk + static final int ZIP64_ENDDSK = 20; // disk number of start + static final int ZIP64_ENDTOD = 24; // total number of entries on this disk + static final int ZIP64_ENDTOT = 32; // total number of entries + static final int ZIP64_ENDSIZ = 40; // central directory size in bytes + static final int ZIP64_ENDOFF = 48; // offset of first CEN header + static final int ZIP64_ENDEXT = 56; // zip64 extensible data sector + + /* + * Zip64 End of central directory locator field offsets + */ + static final int ZIP64_LOCDSK = 4; // disk number start + static final int ZIP64_LOCOFF = 8; // offset of zip64 end + static final int ZIP64_LOCTOT = 16; // total number of disks + + /* + * Zip64 Extra local (EXT) header field offsets + */ + static final int ZIP64_EXTCRC = 4; // uncompressed file crc-32 value + static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte + static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte + + /* + * Extra field header ID + */ + static final int EXTID_ZIP64 = 0x0001; // ZIP64 + static final int EXTID_NTFS = 0x000a; // NTFS + static final int EXTID_UNIX = 0x000d; // UNIX + static final int EXTID_EFS = 0x0017; // Strong Encryption + static final int EXTID_EXTT = 0x5455; // Info-ZIP Extended Timestamp + + /* + * fields access methods + */ + /////////////////////////////////////////////////////// + static final int CH(byte[] b, int n) { + return b[n] & 0xff; + } + + static final int SH(byte[] b, int n) { + return (b[n] & 0xff) | ((b[n + 1] & 0xff) << 8); + } + + static final long LG(byte[] b, int n) { + return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL; + } + + static final long LL(byte[] b, int n) { + return (LG(b, n)) | (LG(b, n + 4) << 32); + } + + static final long GETSIG(byte[] b) { + return LG(b, 0); + } + + // local file (LOC) header fields + static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature + static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract + static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags + static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method + static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time + static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data + static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size + static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size + static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length + static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length + + // extra local (EXT) header fields + static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data + static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size + static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size + + // end of central directory header (END) fields + static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk + static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries + static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size + static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset + static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of zip file comment + static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);} + + // zip64 end of central directory recoder fields + static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk + static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries + static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size + static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset + static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset + + // central directory header (CEN) fields + static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); } + static final int CENVEM(byte[] b, int pos) { return SH(b, pos + 4); } + static final int CENVER(byte[] b, int pos) { return SH(b, pos + 6); } + static final int CENFLG(byte[] b, int pos) { return SH(b, pos + 8); } + static final int CENHOW(byte[] b, int pos) { return SH(b, pos + 10);} + static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);} + static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);} + static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);} + static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);} + static final int CENNAM(byte[] b, int pos) { return SH(b, pos + 28);} + static final int CENEXT(byte[] b, int pos) { return SH(b, pos + 30);} + static final int CENCOM(byte[] b, int pos) { return SH(b, pos + 32);} + static final int CENDSK(byte[] b, int pos) { return SH(b, pos + 34);} + static final int CENATT(byte[] b, int pos) { return SH(b, pos + 36);} + static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);} + static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);} + + /* The END header is followed by a variable length comment of size < 64k. */ + static final long END_MAXLEN = 0xFFFF + ENDHDR; + static final int READBLOCKSZ = 128; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipDirectoryStream.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sun.nio.zipfs; + +import java.nio.file.DirectoryStream; +import java.nio.file.ClosedDirectoryStreamException; +import java.nio.file.NotDirectoryException; +import java.nio.file.Path; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.io.IOException; + +/** + * + * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal + */ + +public class ZipDirectoryStream implements DirectoryStream<Path> { + + private final ZipFileSystem zipfs; + private final byte[] path; + private final DirectoryStream.Filter<? super Path> filter; + private volatile boolean isClosed; + private volatile Iterator<Path> itr; + + ZipDirectoryStream(ZipPath zipPath, + DirectoryStream.Filter<? super java.nio.file.Path> filter) + throws IOException + { + this.zipfs = zipPath.getFileSystem(); + this.path = zipPath.getResolvedPath(); + this.filter = filter; + // sanity check + if (!zipfs.isDirectory(path)) + throw new NotDirectoryException(zipPath.toString()); + } + + @Override + public synchronized Iterator<Path> iterator() { + if (isClosed) + throw new ClosedDirectoryStreamException(); + if (itr != null) + throw new IllegalStateException("Iterator has already been returned"); + + try { + itr = zipfs.iteratorOf(path, filter); + } catch (IOException e) { + throw new IllegalStateException(e); + } + return new Iterator<>() { + private Path next; + @Override + public boolean hasNext() { + if (isClosed) + return false; + return itr.hasNext(); + } + + @Override + public synchronized Path next() { + if (isClosed) + throw new NoSuchElementException(); + return itr.next(); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Override + public synchronized void close() throws IOException { + isClosed = true; + } + + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileAttributeView.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +package com.sun.nio.zipfs; + +import java.nio.file.attribute.BasicFileAttributeView; +import java.nio.file.attribute.FileAttributeView; +import java.nio.file.attribute.FileTime; +import java.io.IOException; +import java.util.LinkedHashMap; + +/* + * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal + */ + +public class ZipFileAttributeView implements BasicFileAttributeView +{ + private static enum AttrID { + size, + creationTime, + lastAccessTime, + lastModifiedTime, + isDirectory, + isRegularFile, + isSymbolicLink, + isOther, + fileKey, + compressedSize, + crc, + method + }; + + private final ZipPath path; + private final boolean isZipView; + + private ZipFileAttributeView(ZipPath path, boolean isZipView) { + this.path = path; + this.isZipView = isZipView; + } + + static <V extends FileAttributeView> V get(ZipPath path, Class<V> type) { + if (type == null) + throw new NullPointerException(); + if (type == BasicFileAttributeView.class) + return (V)new ZipFileAttributeView(path, false); + if (type == ZipFileAttributeView.class) + return (V)new ZipFileAttributeView(path, true); + return null; + } + + static ZipFileAttributeView get(ZipPath path, String type) { + if (type == null) + throw new NullPointerException(); + if (type.equals("basic")) + return new ZipFileAttributeView(path, false); + if (type.equals("zip")) + return new ZipFileAttributeView(path, true); + return null; + } + + @Override + public String name() { + return isZipView ? "zip" : "basic"; + } + + public ZipFileAttributes readAttributes() throws IOException + { + return path.getAttributes(); + } + + @Override + public void setTimes(FileTime lastModifiedTime, + FileTime lastAccessTime, + FileTime createTime) + throws IOException + { + path.setTimes(lastModifiedTime, lastAccessTime, createTime); + } + + void setAttribute(String attribute, Object value) + throws IOException + { + try { + if (AttrID.valueOf(attribute) == AttrID.lastModifiedTime) + setTimes ((FileTime)value, null, null); + if (AttrID.valueOf(attribute) == AttrID.lastAccessTime) + setTimes (null, (FileTime)value, null); + if (AttrID.valueOf(attribute) == AttrID.creationTime) + setTimes (null, null, (FileTime)value); + return; + } catch (IllegalArgumentException x) {} + throw new UnsupportedOperationException("'" + attribute + + "' is unknown or read-only attribute"); + } + + public Object getAttribute(String attribute, boolean domap) + throws IOException + { + ZipFileAttributes zfas = readAttributes(); + if (!domap) { + try { + return attribute(AttrID.valueOf(attribute), zfas); + } catch (IllegalArgumentException x) {} + return null; + } + LinkedHashMap<String, Object> map = new LinkedHashMap<>(); + if ("*".equals(attribute)) { + for (AttrID id : AttrID.values()) { + try { + map.put(id.name(), attribute(id, zfas)); + } catch (IllegalArgumentException x) {} + } + } else { + String[] as = attribute.split(","); + for (String a : as) { + try { + map.put(a, attribute(AttrID.valueOf(a), zfas)); + } catch (IllegalArgumentException x) {} + } + } + return map; + } + + Object attribute(AttrID id, ZipFileAttributes zfas) { + switch (id) { + case size: + return zfas.size(); + case creationTime: + return zfas.creationTime(); + case lastAccessTime: + return zfas.lastAccessTime(); + case lastModifiedTime: + return zfas.lastModifiedTime(); + case isDirectory: + return zfas.isDirectory(); + case isRegularFile: + return zfas.isRegularFile(); + case isSymbolicLink: + return zfas.isSymbolicLink(); + case isOther: + return zfas.isOther(); + case fileKey: + return zfas.fileKey(); + case compressedSize: + if (isZipView) + return zfas.compressedSize(); + break; + case crc: + if (isZipView) + return zfas.crc(); + break; + case method: + if (isZipView) + return zfas.method(); + break; + } + return null; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileAttributes.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +package com.sun.nio.zipfs; + +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.util.Arrays; +import java.util.Formatter; +import static com.sun.nio.zipfs.ZipUtils.*; + +/** + * + * @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal + */ + +public class ZipFileAttributes implements BasicFileAttributes + +{ + private final ZipFileSystem.Entry e; + + ZipFileAttributes(ZipFileSystem.Entry e) { + this.e = e; + } + + ///////// basic attributes /////////// + @Override + public FileTime creationTime() { + if (e.ctime != -1) + return FileTime.fromMillis(e.ctime); + return null; + } + + @Override + public boolean isDirectory() { + return e.isDir(); + } + + @Override + public boolean isOther() { + return false; + } + + @Override + public boolean isRegularFile() { + return !e.isDir(); + } + + @Override + public FileTime lastAccessTime() { + if (e.atime != -1) + return FileTime.fromMillis(e.atime); + return null; + } + + @Override + public FileTime lastModifiedTime() { + return FileTime.fromMillis(e.mtime); + } + + @Override + public long size() { + return e.size; + } + + @Override + public boolean isSymbolicLink() { + return false; + } + + @Override + public Object fileKey() { + return null; + } + + ///////// zip entry attributes /////////// + public long compressedSize() { + return e.csize; + } + + public long crc() { + return e.crc; + } + + public int method() { + return e.method; + } + + public byte[] extra() { + if (e.extra != null) + return Arrays.copyOf(e.extra, e.extra.length); + return null; + } + + public byte[] comment() { + if (e.comment != null) + return Arrays.copyOf(e.comment, e.comment.length); + return null; + } + + public String toString() { + StringBuilder sb = new StringBuilder(1024); + Formatter fm = new Formatter(sb); + if (creationTime() != null) + fm.format(" creationTime : %tc%n", creationTime().toMillis()); + else + fm.format(" creationTime : null%n"); + + if (lastAccessTime() != null) + fm.format(" lastAccessTime : %tc%n", lastAccessTime().toMillis()); + else + fm.format(" lastAccessTime : null%n"); + fm.format(" lastModifiedTime: %tc%n", lastModifiedTime().toMillis()); + fm.format(" isRegularFile : %b%n", isRegularFile()); + fm.format(" isDirectory : %b%n", isDirectory()); + fm.format(" isSymbolicLink : %b%n", isSymbolicLink()); + fm.format(" isOther : %b%n", isOther()); + fm.format(" fileKey : %s%n", fileKey()); + fm.format(" size : %d%n", size()); + fm.format(" compressedSize : %d%n", compressedSize()); + fm.format(" crc : %x%n", crc()); + fm.format(" method : %d%n", method()); + fm.close(); + return sb.toString(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileStore.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sun.nio.zipfs; + +import java.io.IOException; +import java.nio.file.FileStore; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.attribute.FileAttributeView; +import java.nio.file.attribute.FileStoreAttributeView; +import java.nio.file.attribute.FileStoreSpaceAttributeView; +import java.nio.file.attribute.FileStoreSpaceAttributes; +import java.nio.file.attribute.Attributes; +import java.nio.file.attribute.BasicFileAttributeView; +import java.util.Formatter; + +/* + * + * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal + */ + +public class ZipFileStore extends FileStore { + + private final ZipFileSystem zfs; + + ZipFileStore(ZipPath zpath) { + this.zfs = (ZipFileSystem)zpath.getFileSystem(); + } + + @Override + public String name() { + return zfs.toString() + "/"; + } + + @Override + public String type() { + return "zipfs"; + } + + @Override + public boolean isReadOnly() { + return zfs.isReadOnly(); + } + + @Override + public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) { + return (type == BasicFileAttributeView.class || + type == ZipFileAttributeView.class); + } + + @Override + public boolean supportsFileAttributeView(String name) { + return name.equals("basic") || name.equals("zip"); + } + + @Override + @SuppressWarnings("unchecked") + public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) { + if (type == null) + throw new NullPointerException(); + if (type == FileStoreSpaceAttributeView.class) + return (V) new ZipFileStoreAttributeView(this); + return null; + } + + @Override + public Object getAttribute(String attribute) throws IOException { + if (attribute.equals("space:totalSpace")) + return new ZipFileStoreAttributeView(this).readAttributes().totalSpace(); + if (attribute.equals("space:usableSpace")) + return new ZipFileStoreAttributeView(this).readAttributes().usableSpace(); + if (attribute.equals("space:unallocatedSpace")) + return new ZipFileStoreAttributeView(this).readAttributes().unallocatedSpace(); + throw new UnsupportedOperationException("does not support the given attribute"); + } + + private static class ZipFileStoreAttributeView implements FileStoreSpaceAttributeView { + + private final ZipFileStore fileStore; + + public ZipFileStoreAttributeView(ZipFileStore fileStore) { + this.fileStore = fileStore; + } + + @Override + public String name() { + return "space"; + } + + @Override + public FileStoreSpaceAttributes readAttributes() throws IOException { + final String file = fileStore.name(); + Path path = FileSystems.getDefault().getPath(file); + final long size = Attributes.readBasicFileAttributes(path).size(); + final FileStore fstore = path.getFileStore(); + final FileStoreSpaceAttributes fstoreAttrs = + Attributes.readFileStoreSpaceAttributes(fstore); + return new FileStoreSpaceAttributes() { + public long totalSpace() { + return size; + } + + public long usableSpace() { + if (!fstore.isReadOnly()) + return fstoreAttrs.usableSpace(); + return 0; + } + + public long unallocatedSpace() { + if (!fstore.isReadOnly()) + return fstoreAttrs.unallocatedSpace(); + return 0; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + Formatter fm = new Formatter(sb); + fm.format("FileStoreSpaceAttributes[%s]%n", file); + fm.format(" totalSpace: %d%n", totalSpace()); + fm.format(" usableSpace: %d%n", usableSpace()); + fm.format(" unallocSpace: %d%n", unallocatedSpace()); + fm.close(); + return sb.toString(); + } + }; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,2369 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sun.nio.zipfs; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.*; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.nio.file.spi.*; +import java.util.*; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.regex.Pattern; +import java.util.zip.CRC32; +import java.util.zip.Inflater; +import java.util.zip.Deflater; +import java.util.zip.InflaterInputStream; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.ZipException; +import java.util.zip.ZipError; +import static java.lang.Boolean.*; +import static com.sun.nio.zipfs.ZipConstants.*; +import static com.sun.nio.zipfs.ZipUtils.*; +import static java.nio.file.StandardOpenOption.*; +import static java.nio.file.StandardCopyOption.*; + +/** + * A FileSystem built on a zip file + * + * @author Xueming Shen + */ + +public class ZipFileSystem extends FileSystem { + + private final ZipFileSystemProvider provider; + private final ZipPath defaultdir; + private boolean readOnly = false; + private final Path zfpath; + private final ZipCoder zc; + + // configurable by env map + private final String defaultDir; // default dir for the file system + private final String nameEncoding; // default encoding for name/comment + private final boolean buildDirTree; // build a dir tree for directoryStream ops + private final boolean useTempFile; // use a temp file for newOS, default + // is to use BAOS for better performance + private final boolean createNew; // create a new zip if not exists + private static final boolean isWindows = + System.getProperty("os.name").startsWith("Windows"); + + ZipFileSystem(ZipFileSystemProvider provider, + Path zfpath, + Map<String, ?> env) + throws IOException + { + // configurable env setup + this.createNew = "true".equals(env.get("create")); + this.nameEncoding = env.containsKey("encoding") ? + (String)env.get("encoding") : "UTF-8"; + this.buildDirTree = TRUE.equals(env.get("buildDirTreea")); + this.useTempFile = TRUE.equals(env.get("useTempFile")); + this.defaultDir = env.containsKey("default.dir") ? + (String)env.get("default.dir") : "/"; + if (this.defaultDir.charAt(0) != '/') + throw new IllegalArgumentException("default dir should be absolute"); + + this.provider = provider; + this.zfpath = zfpath; + if (zfpath.notExists()) { + if (createNew) { + OutputStream os = zfpath.newOutputStream(CREATE_NEW, WRITE); + new END().write(os, 0); + os.close(); + } else { + throw new FileSystemNotFoundException(zfpath.toString()); + } + } + zfpath.checkAccess(AccessMode.READ); // sm and existence check + try { + zfpath.checkAccess(AccessMode.WRITE); + } catch (AccessDeniedException x) { + this.readOnly = true; + } + this.zc = ZipCoder.get(nameEncoding); + this.defaultdir = new ZipPath(this, getBytes(defaultDir)); + this.ch = zfpath.newByteChannel(READ); + this.cen = initCEN(); + } + + @Override + public FileSystemProvider provider() { + return provider; + } + + @Override + public String getSeparator() { + return "/"; + } + + @Override + public boolean isOpen() { + return isOpen; + } + + @Override + public boolean isReadOnly() { + return readOnly; + } + + private void checkWritable() throws IOException { + if (readOnly) + throw new ReadOnlyFileSystemException(); + } + + @Override + public Iterable<Path> getRootDirectories() { + ArrayList<Path> pathArr = new ArrayList<>(); + pathArr.add(new ZipPath(this, new byte[]{'/'})); + return pathArr; + } + + ZipPath getDefaultDir() { // package private + return defaultdir; + } + + @Override + public ZipPath getPath(String path) { + if (path.length() == 0) + throw new InvalidPathException(path, "path should not be empty"); + return new ZipPath(this, getBytes(path)); + } + + @Override + public UserPrincipalLookupService getUserPrincipalLookupService() { + throw new UnsupportedOperationException(); + } + + @Override + public WatchService newWatchService() { + throw new UnsupportedOperationException(); + } + + FileStore getFileStore(ZipPath path) { + return new ZipFileStore(path); + } + + @Override + public Iterable<FileStore> getFileStores() { + ArrayList<FileStore> list = new ArrayList<>(1); + list.add(new ZipFileStore(new ZipPath(this, new byte[]{'/'}))); + return list; + } + + private static final Set<String> supportedFileAttributeViews = + Collections.unmodifiableSet( + new HashSet<String>(Arrays.asList("basic", "zip"))); + + @Override + public Set<String> supportedFileAttributeViews() { + return supportedFileAttributeViews; + } + + @Override + public String toString() { + return zfpath.toString(); + } + + Path getZipFile() { + return zfpath; + } + + private static final String GLOB_SYNTAX = "glob"; + private static final String REGEX_SYNTAX = "regex"; + + @Override + public PathMatcher getPathMatcher(String syntaxAndInput) { + int pos = syntaxAndInput.indexOf(':'); + if (pos <= 0 || pos == syntaxAndInput.length()) { + throw new IllegalArgumentException(); + } + String syntax = syntaxAndInput.substring(0, pos); + String input = syntaxAndInput.substring(pos + 1); + String expr; + if (syntax.equals(GLOB_SYNTAX)) { + expr = toRegexPattern(input); + } else { + if (syntax.equals(REGEX_SYNTAX)) { + expr = input; + } else { + throw new UnsupportedOperationException("Syntax '" + syntax + + "' not recognized"); + } + } + // return matcher + final Pattern pattern = Pattern.compile(expr); + return new PathMatcher() { + @Override + public boolean matches(Path path) { + return pattern.matcher(path.toString()).matches(); + } + }; + } + + @Override + public void close() throws IOException { + beginWrite(); + try { + if (!isOpen) + return; + isOpen = false; // set closed + } finally { + endWrite(); + } + if (!streams.isEmpty()) { // unlock and close all remaining streams + Set<InputStream> copy = new HashSet<>(streams); + for (InputStream is: copy) + is.close(); + } + beginWrite(); // lock and sync + try { + sync(); + ch.close(); // close the ch just in case no update + } finally { // and sync dose not close the ch + endWrite(); + } + + synchronized (inflaters) { + for (Inflater inf : inflaters) + inf.end(); + } + synchronized (deflaters) { + for (Deflater def : deflaters) + def.end(); + } + + synchronized (tmppaths) { + for (Path p: tmppaths) { + try { + p.deleteIfExists(); + } catch (IOException x) { + x.printStackTrace(); + } + } + } + provider.removeFileSystem(zfpath); + } + + ZipFileAttributes getFileAttributes(byte[] path) + throws IOException + { + Entry e; + beginRead(); + try { + ensureOpen(); + e = getEntry0(path); + } finally { + endRead(); + } + if (e == null) { + if (path.length == 0) { + e = new Entry(new byte[0]); // root + } else if (buildDirTree) { + IndexNode inode = getDirs().get(IndexNode.keyOf(path)); + if (inode == null) + return null; + e = new Entry(inode.name); + } else { + return null; + } + e.method = METHOD_STORED; // STORED for dir + BasicFileAttributes bfas = Attributes.readBasicFileAttributes(zfpath); + if (bfas.lastModifiedTime() != null) + e.mtime = bfas.lastModifiedTime().toMillis(); + if (bfas.lastAccessTime() != null) + e.atime = bfas.lastAccessTime().toMillis(); + if (bfas.creationTime() != null) + e.ctime = bfas.creationTime().toMillis(); + } + return new ZipFileAttributes(e); + } + + void setTimes(byte[] path, FileTime mtime, FileTime atime, FileTime ctime) + throws IOException + { + checkWritable(); + beginWrite(); + try { + ensureOpen(); + Entry e = getEntry0(path); // ensureOpen checked + if (e == null) + throw new NoSuchFileException(getString(path)); + if (e.type == Entry.CEN) + e.type = Entry.COPY; // copy e + if (mtime != null) + e.mtime = mtime.toMillis(); + if (atime != null) + e.atime = atime.toMillis(); + if (ctime != null) + e.ctime = ctime.toMillis(); + update(e); + } finally { + endWrite(); + } + } + + boolean exists(byte[] path) + throws IOException + { + beginRead(); + try { + ensureOpen(); + return getEntry0(path) != null; + } finally { + endRead(); + } + } + + boolean isDirectory(byte[] path) + throws IOException + { + if (buildDirTree) + return getDirs().containsKey(IndexNode.keyOf(path)); + + beginRead(); + try { + Entry e = getEntry0(path); + return (e != null && e.isDir()) || path.length == 0; + } finally { + endRead(); + } + } + + private ZipPath toZipPath(byte[] path) { + // make it absolute + byte[] p = new byte[path.length + 1]; + p[0] = '/'; + System.arraycopy(path, 0, p, 1, path.length); + return new ZipPath(this, p); + } + + // returns the list of child paths of "path" + Iterator<Path> iteratorOf(byte[] path, + DirectoryStream.Filter<? super Path> filter) + throws IOException + { + beginWrite(); // iteration of inodes needs exclusive lock + try { + ensureOpen(); + if (buildDirTree) { + IndexNode inode = getDirs().get(IndexNode.keyOf(path)); + if (inode == null) + throw new NotDirectoryException(getString(path)); + List<Path> list = new ArrayList<>(); + IndexNode child = inode.child; + while (child != null) { + ZipPath zp = toZipPath(child.name); + if (filter == null || filter.accept(zp)) + list.add(zp); + child = child.sibling; + } + return list.iterator(); + } + + if (!isDirectory(path)) + throw new NotDirectoryException(getString(path)); + List<Path> list = new ArrayList<>(); + path = toDirectoryPath(path); + for (IndexNode key : inodes.keySet()) { + if (!isParentOf(path, key.name)) // is "path" the parent of "name" + continue; + int off = path.length; + while (off < key.name.length) { + if (key.name[off] == '/') + break; + off++; + } + if (off < (key.name.length - 1)) + continue; + ZipPath zp = toZipPath(key.name); + if (filter == null || filter.accept(zp)) + list.add(zp); + } + return list.iterator(); + } finally { + endWrite(); + } + } + + 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(); + } + } + + void copyFile(boolean deletesrc, byte[]src, byte[] dst, CopyOption... options) + throws IOException + { + checkWritable(); + if (Arrays.equals(src, dst)) + return; // do nothing, src and dst are the same + + beginWrite(); + try { + ensureOpen(); + Entry eSrc = getEntry0(src); // ensureOpen checked + if (eSrc == null) + throw new NoSuchFileException(getString(src)); + if (eSrc.isDir()) { // spec says to create dst dir + createDirectory(dst); + return; + } + boolean hasReplace = false; + boolean hasCopyAttrs = false; + for (CopyOption opt : options) { + if (opt == REPLACE_EXISTING) + hasReplace = true; + else if (opt == COPY_ATTRIBUTES) + hasCopyAttrs = true; + } + Entry eDst = getEntry0(dst); + if (eDst != null) { + if (!hasReplace) + throw new FileAlreadyExistsException(getString(dst)); + } else { + checkParents(dst); + } + Entry u = new Entry(eSrc, Entry.COPY); // copy eSrc entry + u.name = dst; // change name + if (eSrc.type == Entry.NEW || eSrc.type == Entry.FILECH) + { + u.type = eSrc.type; // make it the same type + if (!deletesrc) { // if it's not "rename", just take the data + if (eSrc.bytes != null) + u.bytes = Arrays.copyOf(eSrc.bytes, eSrc.bytes.length); + else if (eSrc.file != null) { + u.file = getTempPathForEntry(null); + eSrc.file.copyTo(u.file, REPLACE_EXISTING); + } + } + } + if (!hasCopyAttrs) + u.mtime = u.atime= u.ctime = System.currentTimeMillis(); + update(u); + if (deletesrc) + updateDelete(eSrc); + } finally { + endWrite(); + } + } + + // Returns an output stream for writing the contents into the specified + // entry. + OutputStream newOutputStream(byte[] path, OpenOption... options) + throws IOException + { + checkWritable(); + boolean hasCreateNew = false; + boolean hasCreate = false; + boolean hasAppend = false; + for (OpenOption opt: options) { + if (opt == READ) + throw new IllegalArgumentException("READ not allowed"); + if (opt == CREATE_NEW) + hasCreateNew = true; + if (opt == CREATE) + hasCreate = true; + if (opt == APPEND) + hasAppend = true; + } + beginRead(); // only need a readlock, the "update()" will + try { // try to obtain a writelock when the os is + ensureOpen(); // being closed. + Entry e = getEntry0(path); + if (e != null) { + 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)); + } + } finally { + endRead(); + } + } + + // Returns an input stream for reading the contents of the specified + // file entry. + InputStream newInputStream(byte[] path) throws IOException { + beginRead(); + try { + ensureOpen(); + Entry e = getEntry0(path); + if (e == null) + throw new NoSuchFileException(getString(path)); + if (e.isDir()) + throw new FileSystemException(getString(path), "is a directory", null); + return getInputStream(e); + } finally { + endRead(); + } + } + + private void checkOptions(Set<? extends OpenOption> options) { + // check for options of null type and option is an intance of StandardOpenOption + for (OpenOption option : options) { + if (option == null) + throw new NullPointerException(); + if (!(option instanceof StandardOpenOption)) + throw new IllegalArgumentException(); + } + } + + // 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, + Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + 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 = getEntry0(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 = getEntry0(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 { + return rbc.read(dst); + } + + 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(); + } + } + } + + // Returns a FileChannel of the specified entry. + // + // This implementation creates a temporary file on the default file system, + // copy the entry data into it if the entry exists, and then create a + // FileChannel on top of it. + FileChannel newFileChannel(byte[] path, + Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + checkOptions(options); + final boolean forWrite = (options.contains(StandardOpenOption.WRITE) || + options.contains(StandardOpenOption.APPEND)); + beginRead(); + try { + ensureOpen(); + Entry e = getEntry0(path); + if (forWrite) { + checkWritable(); + if (e == null) { + if (!options.contains(StandardOpenOption.CREATE_NEW)) + throw new NoSuchFileException(getString(path)); + } else { + if (options.contains(StandardOpenOption.CREATE_NEW)) + throw new FileAlreadyExistsException(getString(path)); + if (e.isDir()) + throw new FileAlreadyExistsException("directory <" + + getString(path) + "> exists"); + } + options.remove(StandardOpenOption.CREATE_NEW); // for tmpfile + } else if (e == null || e.isDir()) { + throw new NoSuchFileException(getString(path)); + } + + final boolean isFCH = (e != null && e.type == Entry.FILECH); + final Path tmpfile = isFCH ? e.file : getTempPathForEntry(path); + final FileChannel fch = tmpfile.getFileSystem() + .provider() + .newFileChannel(tmpfile, options, attrs); + final Entry u = isFCH ? e : new Entry(path, tmpfile, Entry.FILECH); + if (forWrite) { + u.flag = FLAG_DATADESCR; + u.method = METHOD_DEFLATED; + } + // is there a better way to hook into the FileChannel's close method? + return new FileChannel() { + public int write(ByteBuffer src) throws IOException { + return fch.write(src); + } + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + return fch.write(srcs, offset, length); + } + public long position() throws IOException { + return fch.position(); + } + public FileChannel position(long newPosition) + throws IOException + { + fch.position(newPosition); + return this; + } + public long size() throws IOException { + return fch.size(); + } + public FileChannel truncate(long size) + throws IOException + { + fch.truncate(size); + return this; + } + public void force(boolean metaData) + throws IOException + { + fch.force(metaData); + } + public long transferTo(long position, long count, + WritableByteChannel target) + throws IOException + { + return fch.transferTo(position, count, target); + } + public long transferFrom(ReadableByteChannel src, + long position, long count) + throws IOException + { + return fch.transferFrom(src, position, count); + } + public int read(ByteBuffer dst) throws IOException { + return fch.read(dst); + } + public int read(ByteBuffer dst, long position) + throws IOException + { + return fch.read(dst, position); + } + public long read(ByteBuffer[] dsts, int offset, int length) + throws IOException + { + return fch.read(dsts, offset, length); + } + public int write(ByteBuffer src, long position) + throws IOException + { + return fch.write(src, position); + } + public MappedByteBuffer map(MapMode mode, + long position, long size) + throws IOException + { + throw new UnsupportedOperationException(); + } + public FileLock lock(long position, long size, boolean shared) + throws IOException + { + return fch.lock(position, size, shared); + } + public FileLock tryLock(long position, long size, boolean shared) + throws IOException + { + return fch.tryLock(position, size, shared); + } + protected void implCloseChannel() throws IOException { + fch.close(); + if (forWrite) { + u.mtime = System.currentTimeMillis(); + u.size = Attributes.readBasicFileAttributes(u.file).size(); + update(u); + } else { + if (!isFCH) // if this is a new fch for reading + removeTempPathForEntry(tmpfile); + } + } + }; + } finally { + endRead(); + } + } + + // 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 = getEntry0(path); + if (e != null) { + InputStream is = newInputStream(path); + OutputStream os = tmpPath.newOutputStream(WRITE); + try { + copyStream(is, os); + } finally { + is.close(); + os.close(); + } + } + } + return tmpPath; + } + + private void removeTempPathForEntry(Path path) throws IOException { + path.delete(); + tmppaths.remove(path); + } + + // check if all parents really exit. ZIP spec does not require + // the existence of any "parent directory". + private void checkParents(byte[] path) throws IOException { + beginRead(); + try { + while ((path = getParent(path)) != null) { + if (!inodes.containsKey(IndexNode.keyOf(path))) + throw new NoSuchFileException(getString(path)); + } + } finally { + endRead(); + } + } + + private static byte[] getParent(byte[] path) { + int off = path.length - 1; + if (off > 0 && path[off] == '/') // isDirectory + off--; + while (off > 0 && path[off] != '/') { off--; } + if (off == 0) + return null; // top entry + return Arrays.copyOf(path, off + 1); + } + + // If "starter" is the parent directory of "path" + private static boolean isParentOf(byte[] p, byte[] c) { + final int plen = p.length; + if (plen == 0) // root dir + return true; + if (plen >= c.length) + return false; + int n = 0; + while (n < plen) { + if (p[n] != c[n]) + return false; + n++; + } + if (p[n - 1] != '/' && (c[n] != '/' || n == c.length - 1)) + return false; + return true; + } + + private final void beginWrite() { + rwlock.writeLock().lock(); + } + + private final void endWrite() { + rwlock.writeLock().unlock(); + } + + private final void beginRead() { + rwlock.readLock().lock(); + } + + private final void endRead() { + rwlock.readLock().unlock(); + } + + /////////////////////////////////////////////////////////////////// + + private volatile boolean isOpen = true; + private final SeekableByteChannel ch; // channel to the zipfile + final byte[] cen; // CEN & ENDHDR + private END end; + private long locpos; // position of first LOC header (usually 0) + + private final ReadWriteLock rwlock = new ReentrantReadWriteLock(); + + // name -> pos (in cen), IndexNode itself can be used as a "key" + private LinkedHashMap<IndexNode, IndexNode> inodes; + + final byte[] getBytes(String name) { + return zc.getBytes(name); + } + + final String getString(byte[] name) { + return zc.toString(name); + } + + protected void finalize() throws IOException { + close(); + } + + private long getDataPos(Entry e) throws IOException { + if (e.locoff == -1) { + Entry e2 = getEntry0(e.name); + if (e2 == null) + throw new ZipException("invalid loc for entry <" + e.name + ">"); + e.locoff = e2.locoff; + } + byte[] buf = new byte[LOCHDR]; + if (readFullyAt(buf, 0, buf.length, e.locoff) != buf.length) + throw new ZipException("invalid loc for entry <" + e.name + ">"); + return locpos + e.locoff + LOCHDR + LOCNAM(buf) + LOCEXT(buf); + } + + // Reads len bytes of data from the specified offset into buf. + // Returns the total number of bytes read. + // Each/every byte read from here (except the cen, which is mapped). + final long readFullyAt(byte[] buf, int off, long len, long pos) + throws IOException + { + ByteBuffer bb = ByteBuffer.wrap(buf); + bb.position(off); + bb.limit((int)(off + len)); + return readFullyAt(bb, pos); + } + + private final long readFullyAt(ByteBuffer bb, long pos) + throws IOException + { + synchronized(ch) { + return ch.position(pos).read(bb); + } + } + + // Searches for end of central directory (END) header. The contents of + // the END header will be read and placed in endbuf. Returns the file + // position of the END header, otherwise returns -1 if the END header + // was not found or an error occurred. + private END findEND() throws IOException + { + byte[] buf = new byte[READBLOCKSZ]; + long ziplen = ch.size(); + long minHDR = (ziplen - END_MAXLEN) > 0 ? ziplen - END_MAXLEN : 0; + long minPos = minHDR - (buf.length - ENDHDR); + + for (long pos = ziplen - buf.length; pos >= minPos; pos -= (buf.length - ENDHDR)) + { + int off = 0; + if (pos < 0) { + // Pretend there are some NUL bytes before start of file + off = (int)-pos; + Arrays.fill(buf, 0, off, (byte)0); + } + int len = buf.length - off; + if (readFullyAt(buf, off, len, pos + off) != len) + zerror("zip END header not found"); + + // Now scan the block backwards for END header signature + for (int i = buf.length - ENDHDR; i >= 0; i--) { + if (buf[i+0] == (byte)'P' && + buf[i+1] == (byte)'K' && + buf[i+2] == (byte)'\005' && + buf[i+3] == (byte)'\006' && + (pos + i + ENDHDR + ENDCOM(buf, i) == ziplen)) { + // Found END header + buf = Arrays.copyOfRange(buf, i, i + ENDHDR); + END end = new END(); + end.endsub = ENDSUB(buf); + end.centot = ENDTOT(buf); + end.cenlen = ENDSIZ(buf); + end.cenoff = ENDOFF(buf); + end.comlen = ENDCOM(buf); + end.endpos = pos + i; + if (end.cenlen == ZIP64_MINVAL || + end.cenoff == ZIP64_MINVAL || + end.centot == ZIP64_MINVAL32) + { + // need to find the zip64 end; + byte[] loc64 = new byte[ZIP64_LOCHDR]; + if (readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR) + != loc64.length) { + return end; + } + long end64pos = ZIP64_LOCOFF(loc64); + byte[] end64buf = new byte[ZIP64_ENDHDR]; + if (readFullyAt(end64buf, 0, end64buf.length, end64pos) + != end64buf.length) { + return end; + } + // end64 found, re-calcualte everything. + end.cenlen = ZIP64_ENDSIZ(end64buf); + end.cenoff = ZIP64_ENDOFF(end64buf); + end.centot = (int)ZIP64_ENDTOT(end64buf); // assume total < 2g + end.endpos = end64pos; + } + return end; + } + } + } + zerror("zip END header not found"); + return null; //make compiler happy + } + + // Reads zip file central directory. Returns the file position of first + // CEN header, otherwise returns -1 if an error occured. If zip->msg != NULL + // then the error was a zip format error and zip->msg has the error text. + // Always pass in -1 for knownTotal; it's used for a recursive call. + private byte[] initCEN() throws IOException { + end = findEND(); + if (end.endpos == 0) { + inodes = new LinkedHashMap<>(10); + locpos = 0; + return null; // only END header present + } + if (end.cenlen > end.endpos) + zerror("invalid END header (bad central directory size)"); + long cenpos = end.endpos - end.cenlen; // position of CEN table + + // Get position of first local file (LOC) header, taking into + // account that there may be a stub prefixed to the zip file. + locpos = cenpos - end.cenoff; + if (locpos < 0) + zerror("invalid END header (bad central directory offset)"); + + // read in the CEN and END + byte[] cen = new byte[(int)(end.cenlen + ENDHDR)]; + if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) { + zerror("read CEN tables failed"); + } + // Iterate through the entries in the central directory + inodes = new LinkedHashMap<>(end.centot + 1); + int pos = 0; + int limit = cen.length - ENDHDR; + while (pos < limit) { + if (CENSIG(cen, pos) != CENSIG) + zerror("invalid CEN header (bad signature)"); + int method = CENHOW(cen, pos); + int nlen = CENNAM(cen, pos); + int elen = CENEXT(cen, pos); + int clen = CENCOM(cen, pos); + if ((CENFLG(cen, pos) & 1) != 0) + zerror("invalid CEN header (encrypted entry)"); + if (method != METHOD_STORED && method != METHOD_DEFLATED) + zerror("invalid CEN header (unsupported compression method: " + method + ")"); + if (pos + CENHDR + nlen > limit) + zerror("invalid CEN header (bad header size)"); + byte[] name = Arrays.copyOfRange(cen, pos + CENHDR, pos + CENHDR + nlen); + 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)"); + } + return cen; + } + + private void ensureOpen() throws IOException { + if (!isOpen) + throw new ClosedFileSystemException(); + } + + // Creates a new empty temporary file in the same directory as the + // specified file. A variant of File.createTempFile. + private Path createTempFileInSameDirectoryAs(Path path) + throws IOException + { + Path parent = path.toAbsolutePath().getParent(); + String dir = (parent == null)? "." : parent.toString(); + Path tmpPath = File.createTempFile("zipfstmp", null, new File(dir)).toPath(); + tmppaths.add(tmpPath); + return tmpPath; + } + + ////////////////////update & sync ////////////////////////////////////// + + private boolean hasUpdate = false; + + private void updateDelete(Entry e) { + beginWrite(); + try { + inodes.remove(IndexNode.keyOf(e.name)); //inodes.remove(e.name); + hasUpdate = true; + dirs = null; + } finally { + endWrite(); + } + } + + private void update(Entry e) { + beginWrite(); + try { + inodes.put(IndexNode.keyOf(e.name), e); //inodes.put(e, e); + hasUpdate = true; + dirs = null; + } finally { + endWrite(); + } + } + + // copy over the whole LOC entry (header if necessary, data and ext) from + // old zip to the new one. + private long copyLOCEntry(Entry e, boolean updateHeader, + OutputStream os, + long written, byte[] buf) + throws IOException + { + long locoff = e.locoff; // where to read + e.locoff = written; // update the e.locoff with new value + + // calculate the size need to write out + long size = 0; + // if there is A ext + if ((e.flag & FLAG_DATADESCR) != 0) { + if (e.size >= ZIP64_MINVAL || e.csize >= ZIP64_MINVAL) + size = 24; + else + size = 16; + } + // read loc, use the original loc.elen/nlen + if (readFullyAt(buf, 0, LOCHDR , locoff) != LOCHDR) + throw new ZipException("loc: reading failed"); + if (updateHeader) { + locoff += LOCHDR + LOCNAM(buf) + LOCEXT(buf); // skip header + size += e.csize; + written = e.writeLOC(os) + size; + } else { + os.write(buf, 0, LOCHDR); // write out the loc header + locoff += LOCHDR; + // use e.csize, LOCSIZ(buf) is zero if FLAG_DATADESCR is on + // size += LOCNAM(buf) + LOCEXT(buf) + LOCSIZ(buf); + size += LOCNAM(buf) + LOCEXT(buf) + e.csize; + written = LOCHDR + size; + } + int n; + while (size > 0 && + (n = (int)readFullyAt(buf, 0, buf.length, locoff)) != -1) + { + if (size < n) + n = (int)size; + os.write(buf, 0, n); + size -= n; + 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(); + ecc.path.delete(); + exChClosers.remove(ecc); + } + } + } + if (!hasUpdate) + return; + Path tmpFile = createTempFileInSameDirectoryAs(zfpath); + OutputStream os = tmpFile.newOutputStream(WRITE); + ArrayList<Entry> elist = new ArrayList<>(inodes.size()); + long written = 0; + byte[] buf = new byte[8192]; + Entry e = null; + + // write loc + for (IndexNode inode : inodes.values()) { + if (inode instanceof Entry) { // an updated inode + e = (Entry)inode; + try { + if (e.type == Entry.COPY) { + // entry copy: the only thing changed is the "name" + // and "nlen" in LOC header, so we udpate/rewrite the + // LOC in new file and simply copy the rest (data and + // ext) without enflating/deflating from the old zip + // file LOC entry. + written += copyLOCEntry(e, true, os, written, buf); + } else { // NEW or FILECH + 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 + InputStream is = e.file.newInputStream(); + 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 + OutputStream os2 = new EntryOutputStream(e, os); + while ((n = is.read(buf)) != -1) { + os2.write(buf, 0, n); + } + os2.close(); + written += e.csize; + if ((e.flag & FLAG_DATADESCR) != 0) + written += e.writeEXT(os); + } + is.close(); + e.file.delete(); + tmppaths.remove(e.file); + } else { + // dir, 0-length data + } + } + elist.add(e); + } catch (IOException x) { + x.printStackTrace(); // skip any in-accurate entry + } + } else { // unchanged inode + e = Entry.readCEN(this, inode.pos); + try { + written += copyLOCEntry(e, false, os, written, buf); + elist.add(e); + } catch (IOException x) { + x.printStackTrace(); // skip any wrong entry + } + } + } + + // now write back the cen and end table + end.cenoff = written; + for (Entry entry : elist) { + written += entry.writeCEN(os); + } + end.centot = elist.size(); + end.cenlen = written - end.cenoff; + end.write(os, written); + os.close(); + + 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); + zfpath.moveTo(ecc.path, REPLACE_EXISTING); + exChClosers.add(ecc); + streams = Collections.synchronizedSet(new HashSet<InputStream>()); + } else { + ch.close(); + zfpath.delete(); + } + + tmpFile.moveTo(zfpath, REPLACE_EXISTING); + hasUpdate = false; // clear + /* + if (isOpen) { + ch = zfpath.newByteChannel(READ); // re-fresh "ch" and "cen" + cen = initCEN(); + } + */ + //System.out.printf("->sync(%s) done!%n", toString()); + } + + private Entry getEntry0(byte[] path) throws IOException { + if (path == null) + throw new NullPointerException("path"); + if (path.length == 0) + return null; + IndexNode inode = null; + IndexNode key = IndexNode.keyOf(path); + if ((inode = inodes.get(key)) == null) { + if (path[path.length -1] == '/') // already has a slash + return null; + path = Arrays.copyOf(path, path.length + 1); + path[path.length - 1] = '/'; + if ((inode = inodes.get(key.as(path))) == null) + return null; + } + if (inode instanceof Entry) + return (Entry)inode; + return Entry.readCEN(this, inode.pos); + } + + // Test if the "name" a parent directory of any entry (dir empty) + boolean isAncestor(byte[] name) { + for (Map.Entry<IndexNode, IndexNode> entry : inodes.entrySet()) { + byte[] ename = entry.getKey().name; + if (isParentOf(name, ename)) + return true; + } + return false; + } + + public void deleteFile(byte[] path, boolean failIfNotExists) + throws IOException + { + checkWritable(); + Entry e = getEntry0(path); + if (e == null) { + if (path != null && path.length == 0) + throw new ZipException("root directory </> can't not be delete"); + if (failIfNotExists) + throw new NoSuchFileException(getString(path)); + } else { + if (e.isDir() && isAncestor(path)) + throw new DirectoryNotEmptyException(getString(path)); + updateDelete(e); + } + } + + 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_EFS; + OutputStream os; + if (useTempFile) { + e.file = getTempPathForEntry(null); + os = e.file.newOutputStream(WRITE); + } else { + 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 = e.file.newInputStream(); + else + throw new ZipException("update entry data is missing"); + } else if (e.type == Entry.FILECH) { + // FILECH result is un-compressed. + eis = e.file.newInputStream(); + // TBD: wrap to hook close() + // streams.add(eis); + return eis; + } else { // untouced CEN or COPY + eis = new EntryInputStream(e, ch); + } + if (e.method == METHOD_DEFLATED) { + // MORE: Compute good size for inflater stream: + long bufSize = e.size + 2; // Inflater likes a bit of slack + if (bufSize > 65536) + bufSize = 8192; + final long size = e.size; + eis = new InflaterInputStream(eis, getInflater(), (int)bufSize) { + + private boolean isClosed = false; + public void close() throws IOException { + if (!isClosed) { + releaseInflater(inf); + this.in.close(); + isClosed = true; + streams.remove(this); + } + } + // Override fill() method to provide an extra "dummy" byte + // at the end of the input stream. This is required when + // using the "nowrap" Inflater option. (it appears the new + // zlib in 7 does not need it, but keep it for now) + protected void fill() throws IOException { + if (eof) { + throw new EOFException( + "Unexpected end of ZLIB input stream"); + } + len = this.in.read(buf, 0, buf.length); + if (len == -1) { + buf[0] = 0; + len = 1; + eof = true; + } + inf.setInput(buf, 0, len); + } + private boolean eof; + + public int available() throws IOException { + if (isClosed) + return 0; + long avail = size - inf.getBytesWritten(); + return avail > (long) Integer.MAX_VALUE ? + Integer.MAX_VALUE : (int) avail; + } + }; + } else if (e.method == METHOD_STORED) { + // TBD: wrap/ it does not seem necessary + } else { + throw new ZipException("invalid compression method"); + } + streams.add(eis); + return eis; + } + + // Inner class implementing the input stream used to read + // a (possibly compressed) zip file entry. + private class EntryInputStream extends InputStream { + private final SeekableByteChannel zfch; // local ref to zipfs's "ch". zipfs.ch might + // point to a new channel after sync() + private long pos; // current position within entry data + protected long rem; // number of remaining bytes within entry + protected final long size; // uncompressed size of this entry + + EntryInputStream(Entry e, SeekableByteChannel zfch) + throws IOException + { + this.zfch = zfch; + rem = e.csize; + size = e.size; + pos = getDataPos(e); + } + public int read(byte b[], int off, int len) throws IOException { + ensureOpen(); + if (rem == 0) { + return -1; + } + if (len <= 0) { + return 0; + } + if (len > rem) { + len = (int) rem; + } + // readFullyAt() + long n = 0; + ByteBuffer bb = ByteBuffer.wrap(b); + bb.position(off); + bb.limit(off + len); + synchronized(zfch) { + n = zfch.position(pos).read(bb); + } + if (n > 0) { + pos += n; + rem -= n; + } + if (rem == 0) { + close(); + } + return (int)n; + } + public int read() throws IOException { + byte[] b = new byte[1]; + if (read(b, 0, 1) == 1) { + return b[0] & 0xff; + } else { + return -1; + } + } + public long skip(long n) throws IOException { + ensureOpen(); + if (n > rem) + n = rem; + pos += n; + rem -= n; + if (rem == 0) { + close(); + } + return n; + } + public int available() { + return rem > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) rem; + } + + public long size() { + return size; + } + public void close() { + rem = 0; + streams.remove(this); + } + } + + class EntryOutputStream extends DeflaterOutputStream + { + private CRC32 crc; + private Entry e; + private long written; + + 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 void write(byte b[], int off, int len) throws IOException { + if (e.type != Entry.FILECH) // only from sync + ensureOpen(); + 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 void close() throws IOException { + // 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) { + throw new ZipError(msg); + } + + // Maxmum number of de/inflater we cache + private final int MAX_FLATER = 20; + // List of available Inflater objects for decompression + private final List<Inflater> inflaters = new ArrayList<>(); + + // Gets an inflater from the list of available inflaters or allocates + // a new one. + private Inflater getInflater() { + synchronized (inflaters) { + int size = inflaters.size(); + if (size > 0) { + Inflater inf = (Inflater)inflaters.remove(size - 1); + return inf; + } else { + return new Inflater(true); + } + } + } + + // Releases the specified inflater to the list of available inflaters. + private void releaseInflater(Inflater inf) { + synchronized (inflaters) { + if (inflaters.size() < MAX_FLATER) { + inf.reset(); + inflaters.add(inf); + } else { + inf.end(); + } + } + } + + // List of available Deflater objects for compression + private final List<Deflater> deflaters = new ArrayList<>(); + + // Gets an deflater from the list of available deflaters or allocates + // a new one. + private Deflater getDeflater() { + synchronized (deflaters) { + int size = deflaters.size(); + if (size > 0) { + Deflater def = (Deflater)deflaters.remove(size - 1); + return def; + } else { + return new Deflater(Deflater.DEFAULT_COMPRESSION, true); + } + } + } + + // Releases the specified inflater to the list of available inflaters. + private void releaseDeflater(Deflater def) { + synchronized (deflaters) { + if (inflaters.size() < MAX_FLATER) { + def.reset(); + deflaters.add(def); + } else { + def.end(); + } + } + } + + // End of central directory record + static class END { + int disknum; + int sdisknum; + int endsub; // endsub + int centot; // 4 bytes + long cenlen; // 4 bytes + long cenoff; // 4 bytes + int comlen; // comment length + byte[] comment; + + /* members of Zip64 end of central directory locator */ + int diskNum; + long endpos; + int disktot; + + void write(OutputStream os, long offset) throws IOException { + boolean hasZip64 = false; + long xlen = cenlen; + long xoff = cenoff; + if (xlen >= ZIP64_MINVAL) { + xlen = ZIP64_MINVAL; + hasZip64 = true; + } + if (xoff >= ZIP64_MINVAL) { + xoff = ZIP64_MINVAL; + hasZip64 = true; + } + int count = centot; + if (count >= ZIP64_MINVAL32) { + count = ZIP64_MINVAL32; + hasZip64 = true; + } + if (hasZip64) { + long off64 = offset; + //zip64 end of central directory record + writeInt(os, ZIP64_ENDSIG); // zip64 END record signature + writeLong(os, ZIP64_ENDHDR - 12); // size of zip64 end + writeShort(os, 45); // version made by + writeShort(os, 45); // version needed to extract + writeInt(os, 0); // number of this disk + writeInt(os, 0); // central directory start disk + writeLong(os, centot); // number of directory entires on disk + writeLong(os, centot); // number of directory entires + writeLong(os, cenlen); // length of central directory + writeLong(os, cenoff); // offset of central directory + + //zip64 end of central directory locator + writeInt(os, ZIP64_LOCSIG); // zip64 END locator signature + writeInt(os, 0); // zip64 END start disk + writeLong(os, off64); // offset of zip64 END + writeInt(os, 1); // total number of disks (?) + } + writeInt(os, ENDSIG); // END record signature + writeShort(os, 0); // number of this disk + writeShort(os, 0); // central directory start disk + writeShort(os, count); // number of directory entries on disk + writeShort(os, count); // total number of directory entries + writeInt(os, xlen); // length of central directory + writeInt(os, xoff); // offset of central directory + if (comment != null) { // zip file comment + writeShort(os, comment.length); + writeBytes(os, comment); + } else { + writeShort(os, 0); + } + } + } + + // Internal node that links a "name" to its pos in cen table. + // The node itself can be used as a "key" to lookup itself in + // the HashMap inodes. + static class IndexNode { + byte[] name; + int hashcode; // node is hashable/hashed by its name + int pos = -1; // postion in cen table, -1 menas the + // entry does not exists in zip file + IndexNode(byte[] name, int pos) { + as(name); + this.pos = pos; + } + + final static IndexNode keyOf(byte[] name) { // get a lookup key; + return new IndexNode(name, -1); + } + + final IndexNode as(byte[] name) { // reuse the node, mostly + this.name = name; // as a lookup "key" + this.hashcode = Arrays.hashCode(name); + return this; + } + + public boolean equals(Object other) { + if (!(other instanceof IndexNode)) + return false; + return Arrays.equals(name, ((IndexNode)other).name); + } + + public int hashCode() { + return hashcode; + } + + IndexNode() {} + IndexNode sibling; + IndexNode child; // 1st child + } + + static class Entry extends IndexNode { + + static final int CEN = 1; // entry read from cen + static final int NEW = 2; // updated contents in bytes or file + static final int FILECH = 3; // fch update in "file" + static final int COPY = 4; // copy of a CEN entry + + byte[] bytes; // updated content bytes + Path file; // use tmp file to store bytes; + int type = CEN; // default is the entry read from cen + + // entry attributes + int version; + int flag; + int method = -1; // compression method + long mtime = -1; // last modification time (in DOS time) + long atime = -1; // last access time + long ctime = -1; // create time + long crc = -1; // crc-32 of entry data + long csize = -1; // compressed size of entry data + long size = -1; // uncompressed size of entry data + byte[] extra; + + // cen + int versionMade; + int disk; + int attrs; + long attrsEx; + long locoff; + byte[] comment; + + Entry() {} + + Entry(byte[] name) { + this.name = name; + this.mtime = 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) { + this.version = e.version; + this.name = e.name; + this.ctime = e.ctime; + this.atime = e.atime; + this.mtime = e.mtime; + this.crc = e.crc; + this.size = e.size; + this.csize = e.csize; + this.method = e.method; + this.extra = e.extra; + this.versionMade = e.versionMade; + this.disk = e.disk; + this.attrs = e.attrs; + this.attrsEx = e.attrsEx; + this.locoff = e.locoff; + this.comment = e.comment; + + this.type = type; + } + + Entry (byte[] name, Path file, int type) { + this(name, type); + this.file = file; + this.method = METHOD_STORED; + } + + boolean isDir() { + return name != null && + (name.length == 0 || + name[name.length - 1] == '/'); + } + + int version() throws ZipException { + if (method == METHOD_DEFLATED) + return 20; + else if (method == METHOD_STORED) + return 10; + throw new ZipException("unsupported compression method"); + } + + ///////////////////// CEN ////////////////////// + static Entry readCEN(ZipFileSystem zipfs, int pos) + throws IOException + { + return new Entry().cen(zipfs, pos); + } + + private Entry cen(ZipFileSystem zipfs, int pos) + throws IOException + { + byte[] cen = zipfs.cen; + if (CENSIG(cen, pos) != CENSIG) + zerror("invalid CEN header (bad signature)"); + versionMade = CENVEM(cen, pos); + version = CENVER(cen, pos); + flag = CENFLG(cen, pos); + method = CENHOW(cen, pos); + mtime = dosToJavaTime(CENTIM(cen, pos)); + crc = CENCRC(cen, pos); + csize = CENSIZ(cen, pos); + size = CENLEN(cen, pos); + int nlen = CENNAM(cen, pos); + int elen = CENEXT(cen, pos); + int clen = CENCOM(cen, pos); + disk = CENDSK(cen, pos); + attrs = CENATT(cen, pos); + attrsEx = CENATX(cen, pos); + locoff = CENOFF(cen, pos); + + pos += CENHDR; + name = Arrays.copyOfRange(cen, pos, pos + nlen); + + pos += nlen; + if (elen > 0) { + extra = Arrays.copyOfRange(cen, pos, pos + elen); + pos += elen; + readExtra(zipfs); + } + if (clen > 0) { + comment = Arrays.copyOfRange(cen, pos, pos + clen); + } + return this; + } + + int writeCEN(OutputStream os) throws IOException + { + int written = CENHDR; + int version0 = version(); + + long csize0 = csize; + long size0 = size; + long locoff0 = locoff; + int elen64 = 0; // extra for ZIP64 + int elenNTFS = 0; // extra for NTFS (a/c/mtime) + int elenEXTT = 0; // extra for Extended Timestamp + + // confirm size/length + int nlen = (name != null) ? name.length : 0; + int elen = (extra != null) ? extra.length : 0; + int clen = (comment != null) ? comment.length : 0; + if (csize >= ZIP64_MINVAL) { + csize0 = ZIP64_MINVAL; + elen64 += 8; // csize(8) + } + if (size >= ZIP64_MINVAL) { + size0 = ZIP64_MINVAL; // size(8) + elen64 += 8; + } + if (locoff >= ZIP64_MINVAL) { + locoff0 = ZIP64_MINVAL; + elen64 += 8; // offset(8) + } + if (elen64 != 0) + elen64 += 4; // header and data sz 4 bytes + + if (atime != -1) { + if (isWindows) // use NTFS + elenNTFS = 36; // total 36 bytes + else // Extended Timestamp otherwise + elenEXTT = 9; // only mtime in cen + } + writeInt(os, CENSIG); // CEN header signature + if (elen64 != 0) { + writeShort(os, 45); // ver 4.5 for zip64 + writeShort(os, 45); + } else { + writeShort(os, version0); // version made by + writeShort(os, version0); // version needed to extract + } + writeShort(os, flag); // general purpose bit flag + writeShort(os, method); // compression method + // last modification time + writeInt(os, (int)javaToDosTime(mtime)); + writeInt(os, crc); // crc-32 + writeInt(os, csize0); // compressed size + writeInt(os, size0); // uncompressed size + writeShort(os, name.length); + writeShort(os, elen + elen64 + elenNTFS + elenEXTT); + + if (comment != null) { + writeShort(os, Math.min(clen, 0xffff)); + } else { + writeShort(os, 0); + } + 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); + if (elen64 != 0) { + writeShort(os, EXTID_ZIP64);// Zip64 extra + writeShort(os, elen64); // size of "this" extra block + if (size0 == ZIP64_MINVAL) + writeLong(os, size); + if (csize0 == ZIP64_MINVAL) + writeLong(os, csize); + if (locoff0 == ZIP64_MINVAL) + writeLong(os, locoff); + } + if (elenNTFS != 0) { + // System.out.println("writing NTFS:" + elenNTFS); + writeShort(os, EXTID_NTFS); + writeShort(os, elenNTFS - 4); + writeInt(os, 0); // reserved + writeShort(os, 0x0001); // NTFS attr tag + writeShort(os, 24); + writeLong(os, javaToWinTime(mtime)); + writeLong(os, javaToWinTime(atime)); + writeLong(os, javaToWinTime(ctime)); + } + if (elenEXTT != 0) { + writeShort(os, EXTID_EXTT); + writeShort(os, elenEXTT - 4); + if (ctime == -1) + os.write(0x3); // mtime and atime + else + os.write(0x7); // mtime, atime and ctime + writeInt(os, javaToUnixTime(mtime)); + } + if (extra != null) // whatever not recognized + writeBytes(os, extra); + if (comment != null) //TBD: 0, Math.min(commentBytes.length, 0xffff)); + 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 (LOCSIG(buf) != LOCSIG) + throw new ZipException("loc: wrong sig ->" + + Long.toString(LOCSIG(buf), 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]; + if (zipfs.readFullyAt(name, 0, 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.getEntry0(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 : 0; + int elen = (extra != null) ? extra.length : 0; + int elen64 = 0; + int elenEXTT = 0; + if ((flag & FLAG_DATADESCR) != 0) { + writeShort(os, version()); // version needed to extract + writeShort(os, flag); // general purpose bit flag + writeShort(os, method); // compression method + // last modification time + writeInt(os, (int)javaToDosTime(mtime)); + // store size, uncompressed size, and crc-32 in data descriptor + // immediately following compressed entry data + writeInt(os, 0); + writeInt(os, 0); + writeInt(os, 0); + } else { + if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) { + elen64 = 20; //headid(2) + size(2) + size(8) + csize(8) + writeShort(os, 45); // ver 4.5 for zip64 + } else { + writeShort(os, version()); // version needed to extract + } + writeShort(os, flag); // general purpose bit flag + writeShort(os, method); // compression method + writeInt(os, mtime); // last modification time + writeInt(os, crc); // crc-32 + if (elen64 != 0) { + writeInt(os, ZIP64_MINVAL); + writeInt(os, ZIP64_MINVAL); + } else { + writeInt(os, csize); // compressed size + writeInt(os, size); // uncompressed size + } + } + if (atime != -1 && !isWindows) { // on unix use "ext time" + if (ctime == -1) + elenEXTT = 13; + else + elenEXTT = 17; + } + writeShort(os, name.length); + writeShort(os, elen + elen64 + elenEXTT); + writeBytes(os, name); + if (elen64 != 0) { + writeShort(os, EXTID_ZIP64); + writeShort(os, 16); + writeLong(os, size); + writeLong(os, csize); + } + if (elenEXTT != 0) { + writeShort(os, EXTID_EXTT); + writeShort(os, elenEXTT - 4);// size for the folowing data block + if (ctime == -1) + os.write(0x3); // mtime and atime + else + os.write(0x7); // mtime, atime and ctime + writeInt(os, javaToUnixTime(mtime)); + writeInt(os, javaToUnixTime(atime)); + if (ctime != -1) + writeInt(os, javaToUnixTime(ctime)); + } + if (extra != null) { + writeBytes(os, extra); + } + return LOCHDR + name.length + elen + elen64 + elenEXTT; + } + + // Data Descriptior + int writeEXT(OutputStream os) + throws IOException + { + writeInt(os, EXTSIG); // EXT header signature + writeInt(os, crc); // crc-32 + if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) { + writeLong(os, csize); + writeLong(os, size); + return 24; + } else { + writeInt(os, csize); // compressed size + writeInt(os, size); // uncompressed size + return 16; + } + } + + // read NTFS, UNIX and ZIP64 data from cen.extra + void readExtra(ZipFileSystem zipfs) throws IOException { + if (extra == null) + return; + int elen = extra.length; + int off = 0; + int newOff = 0; + while (off + 4 < elen) { + // extra spec: HeaderID+DataSize+Data + int pos = off; + int tag = SH(extra, pos); + int sz = SH(extra, pos + 2); + pos += 4; + if (pos + sz > elen) // invalid data + break; + switch (tag) { + case EXTID_ZIP64 : + if (size == ZIP64_MINVAL) { + if (pos + 8 > elen) // invalid zip64 extra + break; // fields, just skip + size = LL(extra, pos); + pos += 8; + } + if (csize == ZIP64_MINVAL) { + if (pos + 8 > elen) + break; + csize = LL(extra, pos); + pos += 8; + } + if (locoff == ZIP64_MINVAL) { + if (pos + 8 > elen) + break; + locoff = LL(extra, pos); + pos += 8; + } + break; + case EXTID_NTFS: + pos += 4; // reserved 4 bytes + if (SH(extra, pos) != 0x0001) + break; + if (SH(extra, pos + 2) != 24) + break; + // override the loc field, datatime here is + // more "accurate" + mtime = winToJavaTime(LL(extra, pos + 4)); + atime = winToJavaTime(LL(extra, pos + 12)); + ctime = winToJavaTime(LL(extra, pos + 20)); + break; + case EXTID_EXTT: + // spec says the Extened timestamp in cen only has mtime + // need to read the loc to get the extra a/ctime + byte[] buf = new byte[LOCHDR]; + if (zipfs.readFullyAt(buf, 0, buf.length , locoff) + != buf.length) + throw new ZipException("loc: reading failed"); + if (LOCSIG(buf) != LOCSIG) + throw new ZipException("loc: wrong sig ->" + + Long.toString(LOCSIG(buf), 16)); + + int locElen = LOCEXT(buf); + if (locElen < 9) // EXTT is at lease 9 bytes + break; + int locNlen = LOCNAM(buf); + buf = new byte[locElen]; + if (zipfs.readFullyAt(buf, 0, buf.length , locoff + LOCHDR + locNlen) + != buf.length) + throw new ZipException("loc extra: reading failed"); + int locPos = 0; + while (locPos + 4 < buf.length) { + int locTag = SH(buf, locPos); + int locSZ = SH(buf, locPos + 2); + locPos += 4; + if (locTag != EXTID_EXTT) { + locPos += locSZ; + continue; + } + int flag = CH(buf, locPos++); + if ((flag & 0x1) != 0) { + mtime = unixToJavaTime(LG(buf, locPos)); + locPos += 4; + } + if ((flag & 0x2) != 0) { + atime = unixToJavaTime(LG(buf, locPos)); + locPos += 4; + } + if ((flag & 0x4) != 0) { + ctime = unixToJavaTime(LG(buf, locPos)); + locPos += 4; + } + break; + } + break; + default: // unknown tag + System.arraycopy(extra, off, extra, newOff, sz + 4); + newOff += (sz + 4); + } + off += (sz + 4); + } + if (newOff != 0 && newOff != extra.length) + extra = Arrays.copyOf(extra, newOff); + else + extra = null; + } + } + + 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. + // A possible solution is to build the node tree ourself as + // implemented below. + private HashMap<IndexNode, IndexNode> dirs; + private IndexNode root; + private IndexNode addToDir(IndexNode child) { + IndexNode cinode = dirs.get(child); + if (cinode != null) + return cinode; + + byte[] cname = child.name; + byte[] pname = getParent(cname); + IndexNode pinode; + + if (pname != null) + pinode = addToDir(IndexNode.keyOf(pname)); + else + pinode = root; + cinode = inodes.get(child); + if (cname[cname.length -1] != '/') { // not a dir + cinode.sibling = pinode.child; + pinode.child = cinode; + return null; + } + //cinode = dirs.get(child); + if (cinode == null) // pseudo directry entry + cinode = new IndexNode(cname, -1); + cinode.sibling = pinode.child; + pinode.child = cinode; + + dirs.put(child, cinode); + return cinode; + } + + private HashMap<IndexNode, IndexNode> getDirs() + throws IOException + { + beginWrite(); + try { + if (dirs != null) + return dirs; + dirs = new HashMap<>(); + root = new IndexNode(new byte[0], -1); + dirs.put(root, root); + for (IndexNode node : inodes.keySet()) + addToDir(node); + return dirs; + } finally { + endWrite(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystemProvider.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sun.nio.zipfs; + +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.nio.file.FileRef; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystemAlreadyExistsException; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.ProviderMismatchException; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.spi.FileSystemProvider; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/* + * + * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal + */ + +public class ZipFileSystemProvider extends FileSystemProvider { + + + private final Map<Path, ZipFileSystem> filesystems = new HashMap<>(); + + public ZipFileSystemProvider() {} + + @Override + public String getScheme() { + return "jar"; + } + + protected Path uriToPath(URI uri) { + String scheme = uri.getScheme(); + if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) { + throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'"); + } + try { + // only support legacy JAR URL syntax jar:{uri}!/{entry} for now + String spec = uri.getSchemeSpecificPart(); + int sep = spec.indexOf("!/"); + if (sep != -1) + spec = spec.substring(0, sep); + return Paths.get(new URI(spec)).toAbsolutePath(); + } catch (URISyntaxException e) { + throw new IllegalArgumentException(e.getMessage(), e); + } + } + + @Override + public FileSystem newFileSystem(URI uri, Map<String, ?> env) + throws IOException + { + return newFileSystem(uriToPath(uri), env); + } + + @Override + public FileSystem newFileSystem(FileRef file, Map<String, ?> env) + throws IOException + { + if (!(file instanceof Path)) + throw new UnsupportedOperationException(); + Path path = (Path)file; + if (!path.toUri().getScheme().equalsIgnoreCase("file")) { + throw new UnsupportedOperationException(); + } + return newFileSystem(path, env); + } + + private FileSystem newFileSystem(Path path, Map<String, ?> env) + throws IOException + { + synchronized(filesystems) { + Path realPath = null; + if (path.exists()) { + realPath = path.toRealPath(true); + if (filesystems.containsKey(realPath)) + throw new FileSystemAlreadyExistsException(); + } + ZipFileSystem zipfs = new ZipFileSystem(this, path, env); + if (realPath == null) + realPath = path.toRealPath(true); + filesystems.put(realPath, zipfs); + return zipfs; + } + } + + @Override + public Path getPath(URI uri) { + + String spec = uri.getSchemeSpecificPart(); + int sep = spec.indexOf("!/"); + if (sep == -1) + throw new IllegalArgumentException("URI: " + + uri + + " does not contain path info ex. jar:file:/c:/foo.zip!/BAR"); + return getFileSystem(uri).getPath(spec.substring(sep + 1)); + } + + @Override + public FileChannel newFileChannel(Path path, + Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + if (path == null) + throw new NullPointerException("path is null"); + if (path instanceof ZipPath) + return ((ZipPath)path).newFileChannel(options, attrs); + throw new ProviderMismatchException(); + } + + @Override + public FileSystem getFileSystem(URI uri) { + synchronized (filesystems) { + ZipFileSystem zipfs = null; + try { + zipfs = filesystems.get(uriToPath(uri).toRealPath(true)); + } catch (IOException x) { + // ignore the ioe from toRealPath(), return FSNFE + } + if (zipfs == null) + throw new FileSystemNotFoundException(); + return zipfs; + } + } + + void removeFileSystem(Path zfpath) throws IOException { + synchronized (filesystems) { + filesystems.remove(zfpath.toRealPath(true)); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipInfo.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sun.nio.zipfs; + +import java.nio.file.Paths; +import java.util.Collections; +import java.util.Map; +import static com.sun.nio.zipfs.ZipConstants.*; +import static com.sun.nio.zipfs.ZipUtils.*; + +/** + * Print all loc and cen headers of the ZIP file + * + * @author Xueming Shen + */ + +public class ZipInfo { + + public static void main(String[] args) throws Throwable { + if (args.length < 1) { + print("Usage: java ZipInfo zfname"); + } else { + Map<String, ?> env = Collections.emptyMap(); + ZipFileSystem zfs = (ZipFileSystem)(new ZipFileSystemProvider() + .newFileSystem(Paths.get(args[0]), env)); + byte[] cen = zfs.cen; + if (cen == null) { + print("zip file is empty%n"); + return; + } + int pos = 0; + byte[] buf = new byte[1024]; + int no = 1; + while (pos + CENHDR < cen.length) { + print("----------------#%d--------------------%n", no++); + printCEN(cen, pos); + + // use size CENHDR as the extra bytes to read, just in case the + // loc.extra is bigger than the cen.extra, try to avoid to read + // twice + long len = LOCHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENHDR; + if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len) + zfs.zerror("read loc header failed"); + if (LOCEXT(buf) > CENEXT(cen, pos) + CENHDR) { + // have to read the second time; + len = LOCHDR + LOCNAM(buf) + LOCEXT(buf); + if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len) + zfs.zerror("read loc header failed"); + } + printLOC(buf); + pos += CENHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENCOM(cen, pos); + } + zfs.close(); + } + } + + static void print(String fmt, Object... objs) { + System.out.printf(fmt, objs); + } + + static void printLOC(byte[] loc) { + print("%n"); + print("[Local File Header]%n"); + print(" Signature : %#010x%n", LOCSIG(loc)); + if (LOCSIG(loc) != LOCSIG) { + print(" Wrong signature!"); + return; + } + print(" Version : %#6x [%d.%d]%n", + LOCVER(loc), LOCVER(loc) / 10, LOCVER(loc) % 10); + print(" Flag : %#6x%n", LOCFLG(loc)); + print(" Method : %#6x%n", LOCHOW(loc)); + print(" LastMTime : %#10x [%tc]%n", + LOCTIM(loc), dosToJavaTime(LOCTIM(loc))); + print(" CRC : %#10x%n", LOCCRC(loc)); + print(" CSize : %#10x%n", LOCSIZ(loc)); + print(" Size : %#10x%n", LOCLEN(loc)); + print(" NameLength : %#6x [%s]%n", + LOCNAM(loc), new String(loc, LOCHDR, LOCNAM(loc))); + print(" ExtraLength : %#6x%n", LOCEXT(loc)); + if (LOCEXT(loc) != 0) + printExtra(loc, LOCHDR + LOCNAM(loc), LOCEXT(loc)); + } + + static void printCEN(byte[] cen, int off) { + print("[Central Directory Header]%n"); + print(" Signature : %#010x%n", CENSIG(cen, off)); + if (CENSIG(cen, off) != CENSIG) { + print(" Wrong signature!"); + return; + } + print(" VerMadeby : %#6x [%d, %d.%d]%n", + CENVEM(cen, off), (CENVEM(cen, off) >> 8), + (CENVEM(cen, off) & 0xff) / 10, + (CENVEM(cen, off) & 0xff) % 10); + print(" VerExtract : %#6x [%d.%d]%n", + CENVER(cen, off), CENVER(cen, off) / 10, CENVER(cen, off) % 10); + print(" Flag : %#6x%n", CENFLG(cen, off)); + print(" Method : %#6x%n", CENHOW(cen, off)); + print(" LastMTime : %#10x [%tc]%n", + CENTIM(cen, off), dosToJavaTime(CENTIM(cen, off))); + print(" CRC : %#10x%n", CENCRC(cen, off)); + print(" CSize : %#10x%n", CENSIZ(cen, off)); + print(" Size : %#10x%n", CENLEN(cen, off)); + print(" NameLen : %#6x [%s]%n", + CENNAM(cen, off), new String(cen, off + CENHDR, CENNAM(cen, off))); + print(" ExtraLen : %#6x%n", CENEXT(cen, off)); + if (CENEXT(cen, off) != 0) + printExtra(cen, off + CENHDR + CENNAM(cen, off), CENEXT(cen, off)); + print(" CommentLen : %#6x%n", CENCOM(cen, off)); + print(" DiskStart : %#6x%n", CENDSK(cen, off)); + print(" Attrs : %#6x%n", CENATT(cen, off)); + print(" AttrsEx : %#10x%n", CENATX(cen, off)); + print(" LocOff : %#10x%n", CENOFF(cen, off)); + + } + + static long locoff(byte[] cen, int pos) { + long locoff = CENOFF(cen, pos); + if (locoff == ZIP64_MINVAL) { //ZIP64 + int off = pos + CENHDR + CENNAM(cen, pos); + int end = off + CENEXT(cen, pos); + while (off + 4 < end) { + int tag = SH(cen, off); + int sz = SH(cen, off + 2); + if (tag != EXTID_ZIP64) { + off += 4 + sz; + continue; + } + off += 4; + if (CENLEN(cen, pos) == ZIP64_MINVAL) + off += 8; + if (CENSIZ(cen, pos) == ZIP64_MINVAL) + off += 8; + return LL(cen, off); + } + // should never be here + } + return locoff; + } + + static void printExtra(byte[] extra, int off, int len) { + int end = off + len; + while (off + 4 <= end) { + int tag = SH(extra, off); + int sz = SH(extra, off + 2); + print(" [tag=0x%04x, sz=%d, data= ", tag, sz); + if (off + sz > end) { + print(" Error: Invalid extra data, beyond extra length"); + break; + } + off += 4; + for (int i = 0; i < sz; i++) + print("%02x ", extra[off + i]); + print("]%n"); + switch (tag) { + case EXTID_ZIP64 : + print(" ->ZIP64: "); + int pos = off; + while (pos + 8 <= off + sz) { + print(" *0x%x ", LL(extra, pos)); + pos += 8; + } + print("%n"); + break; + case EXTID_NTFS: + print(" ->PKWare NTFS%n"); + // 4 bytes reserved + if (SH(extra, off + 4) != 0x0001 || SH(extra, off + 6) != 24) + print(" Error: Invalid NTFS sub-tag or subsz"); + print(" mtime:%tc%n", + winToJavaTime(LL(extra, off + 8))); + print(" atime:%tc%n", + winToJavaTime(LL(extra, off + 16))); + print(" ctime:%tc%n", + winToJavaTime(LL(extra, off + 24))); + break; + case EXTID_EXTT: + print(" ->Inof-ZIP Extended Timestamp: flag=%x%n",extra[off]); + pos = off + 1 ; + while (pos + 4 <= off + sz) { + print(" *%tc%n", + unixToJavaTime(LG(extra, pos))); + pos += 4; + } + break; + default: + } + off += sz; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipPath.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,960 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sun.nio.zipfs; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.nio.channels.FileChannel; +import java.nio.channels.SeekableByteChannel; +import java.nio.file.*; +import java.nio.file.DirectoryStream.Filter; +import java.nio.file.attribute.BasicFileAttributeView; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.FileAttributeView; +import java.nio.file.attribute.FileTime; +import java.util.*; +import static java.nio.file.StandardOpenOption.*; +import static java.nio.file.StandardCopyOption.*; + +/** + * + * @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal + */ + +public class ZipPath extends Path { + + private final ZipFileSystem zfs; + private final byte[] path; + private volatile int[] offsets; + private int hashcode = 0; // cached hashcode (created lazily) + + ZipPath(ZipFileSystem zfs, byte[] path) { + this(zfs, path, false); + } + + ZipPath(ZipFileSystem zfs, byte[] path, boolean normalized) + { + this.zfs = zfs; + if (normalized) + this.path = path; + else + this.path = normalize(path); + } + + @Override + public ZipPath getRoot() { + if (this.isAbsolute()) + return new ZipPath(zfs, new byte[]{path[0]}); + else + return null; + } + + @Override + public Path getName() { + initOffsets(); + int count = offsets.length; + if (count == 0) + return null; // no elements so no name + if (count == 1 && path[0] != '/') + return this; + int lastOffset = offsets[count-1]; + int len = path.length - lastOffset; + byte[] result = new byte[len]; + System.arraycopy(path, lastOffset, result, 0, len); + return new ZipPath(zfs, result); + } + + @Override + public ZipPath getParent() { + initOffsets(); + int count = offsets.length; + if (count == 0) // no elements so no parent + return null; + int len = offsets[count-1] - 1; + if (len <= 0) // parent is root only (may be null) + return getRoot(); + byte[] result = new byte[len]; + System.arraycopy(path, 0, result, 0, len); + return new ZipPath(zfs, result); + } + + @Override + public int getNameCount() { + initOffsets(); + return offsets.length; + } + + @Override + public ZipPath getName(int index) { + initOffsets(); + if (index < 0 || index >= offsets.length) + throw new IllegalArgumentException(); + int begin = offsets[index]; + int len; + if (index == (offsets.length-1)) + len = path.length - begin; + else + len = offsets[index+1] - begin - 1; + // construct result + byte[] result = new byte[len]; + System.arraycopy(path, begin, result, 0, len); + return new ZipPath(zfs, result); + } + + @Override + public ZipPath subpath(int beginIndex, int endIndex) { + initOffsets(); + if (beginIndex < 0 || + beginIndex >= offsets.length || + endIndex > offsets.length || + beginIndex >= endIndex) + throw new IllegalArgumentException(); + + // starting offset and length + int begin = offsets[beginIndex]; + int len; + if (endIndex == offsets.length) + len = path.length - begin; + else + len = offsets[endIndex] - begin - 1; + // construct result + byte[] result = new byte[len]; + System.arraycopy(path, begin, result, 0, len); + return new ZipPath(zfs, result); + } + + @Override + public ZipPath toRealPath(boolean resolveLinks) throws IOException { + ZipPath realPath = new ZipPath(zfs, getResolvedPath()); + realPath.checkAccess(); + return realPath; + } + + @Override + public boolean isHidden() { + return false; + } + + @Override + public ZipPath toAbsolutePath() { + if (isAbsolute()) { + return this; + } else { + //add / bofore the existing path + byte[] defaultdir = zfs.getDefaultDir().path; + int defaultlen = defaultdir.length; + boolean endsWith = (defaultdir[defaultlen - 1] == '/'); + byte[] t = null; + if (endsWith) + t = new byte[defaultlen + path.length]; + else + t = new byte[defaultlen + 1 + path.length]; + System.arraycopy(defaultdir, 0, t, 0, defaultlen); + if (!endsWith) + t[defaultlen++] = '/'; + System.arraycopy(path, 0, t, defaultlen, path.length); + return new ZipPath(zfs, t, true); // normalized + } + } + + @Override + public URI toUri() { + try { + return new URI("jar", + zfs.getZipFile().toUri() + + "!" + + zfs.getString(toAbsolutePath().path), + null); + } catch (Exception ex) { + throw new AssertionError(ex); + } + } + + private boolean equalsNameAt(ZipPath other, int index) { + int mbegin = offsets[index]; + int mlen = 0; + if (index == (offsets.length-1)) + mlen = path.length - mbegin; + else + mlen = offsets[index + 1] - mbegin - 1; + int obegin = other.offsets[index]; + int olen = 0; + if (index == (other.offsets.length - 1)) + olen = other.path.length - obegin; + else + olen = other.offsets[index + 1] - obegin - 1; + if (mlen != olen) + return false; + int n = 0; + while(n < mlen) { + if (path[mbegin + n] != other.path[obegin + n]) + return false; + n++; + } + return true; + } + + @Override + public Path relativize(Path other) { + final ZipPath o = checkPath(other); + if (o.equals(this)) + return null; + if (/* this.getFileSystem() != o.getFileSystem() || */ + this.isAbsolute() != o.isAbsolute()) { + throw new IllegalArgumentException(); + } + int mc = this.getNameCount(); + int oc = o.getNameCount(); + int n = Math.min(mc, oc); + int i = 0; + while (i < n) { + if (!equalsNameAt(o, i)) + break; + i++; + } + int dotdots = mc - i; + int len = dotdots * 3 - 1; + if (i < oc) + len += (o.path.length - o.offsets[i] + 1); + byte[] result = new byte[len]; + + int pos = 0; + while (dotdots > 0) { + result[pos++] = (byte)'.'; + result[pos++] = (byte)'.'; + if (pos < len) // no tailing slash at the end + result[pos++] = (byte)'/'; + dotdots--; + } + if (i < oc) + System.arraycopy(o.path, o.offsets[i], + result, pos, + o.path.length - o.offsets[i]); + return new ZipPath(getFileSystem(), result); + } + + @Override + public ZipFileSystem getFileSystem() { + return zfs; + } + + @Override + public boolean isAbsolute() { + return (this.path[0] == '/'); + } + + @Override + public ZipPath resolve(Path other) { + if (other == null) + return this; + final ZipPath o = checkPath(other); + if (o.isAbsolute()) + return o; + byte[] resolved = null; + if (this.path[path.length - 1] == '/') { + resolved = new byte[path.length + o.path.length]; + System.arraycopy(path, 0, resolved, 0, path.length); + System.arraycopy(o.path, 0, resolved, path.length, o.path.length); + } else { + resolved = new byte[path.length + 1 + o.path.length]; + System.arraycopy(path, 0, resolved, 0, path.length); + resolved[path.length] = '/'; + System.arraycopy(o.path, 0, resolved, path.length + 1, o.path.length); + } + return new ZipPath(zfs, resolved); + } + + @Override + public ZipPath resolve(String other) { + return resolve(getFileSystem().getPath(other)); + } + + @Override + public boolean startsWith(Path other) { + final ZipPath o = checkPath(other); + if (o.isAbsolute() != this.isAbsolute()) + return false; + final int oCount = o.getNameCount(); + if (getNameCount() < oCount) + return false; + for (int i = 0; i < oCount; i++) { + if (!o.getName(i).equals(getName(i))) + return false; + } + return true; + } + + @Override + public boolean endsWith(Path other) { + final ZipPath o = checkPath(other); + if (o.isAbsolute()) + return this.isAbsolute() ? this.equals(o) : false; + int i = o.getNameCount(); + int j = this.getNameCount(); + if (j < i) + return false; + for (--i, --j; i >= 0; i--, j--) { + if (!o.getName(i).equals(this.getName(j))) + return false; + } + return true; + } + + @Override + public Path normalize() { + byte[] resolved = getResolved(); + if (resolved == path) // no change + return this; + if (resolved.length == 0) + return null; + return new ZipPath(zfs, resolved, true); + } + + private ZipPath checkPath(Path path) { + if (path == null) + throw new NullPointerException(); + if (!(path instanceof ZipPath)) + throw new ProviderMismatchException(); + return (ZipPath) path; + } + + // create offset list if not already created + private void initOffsets() { + if (offsets == null) { + int count, index; + // count names + count = 0; + index = 0; + while (index < path.length) { + byte c = path[index++]; + if (c != '/') { + count++; + while (index < path.length && path[index] != '/') + index++; + } + } + // populate offsets + int[] result = new int[count]; + count = 0; + index = 0; + while (index < path.length) { + byte c = path[index]; + if (c == '/') { + index++; + } else { + result[count++] = index++; + while (index < path.length && path[index] != '/') + index++; + } + } + synchronized (this) { + if (offsets == null) + offsets = result; + } + } + } + + // resolved path for locating zip entry inside the zip file, + // the result path does not contain ./ and .. components + private volatile byte[] resolved = null; + byte[] getResolvedPath() { + byte[] r = resolved; + if (r == null) { + if (isAbsolute()) + r = getResolved(); + else + r = toAbsolutePath().getResolvedPath(); + if (r[0] == '/') + r = Arrays.copyOfRange(r, 1, r.length); + resolved = r; + } + return resolved; + } + + // removes redundant slashs, replace "\" to zip separator "/" + // and check for invalid characters + private byte[] normalize(byte[] path) { + if (path.length == 0) + return path; + byte prevC = 0; + for (int i = 0; i < path.length; i++) { + byte c = path[i]; + if (c == '\\') + return normalize(path, i); + if (c == (byte)'/' && prevC == '/') + return normalize(path, i - 1); + if (c == '\u0000') + throw new InvalidPathException(zfs.getString(path), + "Path: nul character not allowed"); + prevC = c; + } + return path; + } + + private byte[] normalize(byte[] path, int off) { + byte[] to = new byte[path.length]; + int n = 0; + while (n < off) { + to[n] = path[n]; + n++; + } + int m = n; + byte prevC = 0; + while (n < path.length) { + byte c = path[n++]; + if (c == (byte)'\\') + c = (byte)'/'; + if (c == (byte)'/' && prevC == (byte)'/') + continue; + if (c == '\u0000') + throw new InvalidPathException(zfs.getString(path), + "Path: nul character not allowed"); + to[m++] = c; + prevC = c; + } + if (m > 1 && to[m - 1] == '/') + m--; + return (m == to.length)? to : Arrays.copyOf(to, m); + } + + // Remove DotSlash(./) and resolve DotDot (..) components + private byte[] getResolved() { + if (path.length == 0) + return path; + for (int i = 0; i < path.length; i++) { + byte c = path[i]; + if (c == (byte)'.') + return resolve0(); + } + return path; + } + + // TBD: performance, avoid initOffsets + private byte[] resolve0() { + byte[] to = new byte[path.length]; + int nc = getNameCount(); + int[] lastM = new int[nc]; + int lastMOff = -1; + int m = 0; + for (int i = 0; i < nc; i++) { + int n = offsets[i]; + int len = (i == offsets.length - 1)? + (path.length - n):(offsets[i + 1] - n - 1); + if (len == 1 && path[n] == (byte)'.') + continue; + if (len == 2 && path[n] == '.' && path[n + 1] == '.') { + if (lastMOff >= 0) { + m = lastM[lastMOff--]; // retreat + continue; + } + if (path[0] == '/') { // "/../xyz" skip + if (m == 0) + to[m++] = '/'; + } else { // "../xyz" -> "../xyz" + if (m != 0 && to[m-1] != '/') + to[m++] = '/'; + while (len-- > 0) + to[m++] = path[n++]; + } + continue; + } + if (m == 0 && path[0] == '/' || // absolute path + m != 0 && to[m-1] != '/') { // not the first name + to[m++] = '/'; + } + lastM[++lastMOff] = m; + while (len-- > 0) + to[m++] = path[n++]; + } + if (m > 1 && to[m - 1] == '/') + m--; + return (m == to.length)? to : Arrays.copyOf(to, m); + } + + @Override + public String toString() { + return zfs.getString(path); + } + + @Override + public int hashCode() { + int h = hashcode; + if (h == 0) + hashcode = h = Arrays.hashCode(path); + return h; + } + + @Override + public boolean equals(Object obj) { + return obj != null && + obj instanceof ZipPath && + this.zfs == ((ZipPath)obj).zfs && + compareTo((Path) obj) == 0; + } + + @Override + public int compareTo(Path other) { + final ZipPath o = checkPath(other); + int len1 = this.path.length; + int len2 = o.path.length; + + int n = Math.min(len1, len2); + byte v1[] = this.path; + byte v2[] = o.path; + + int k = 0; + while (k < n) { + int c1 = v1[k] & 0xff; + int c2 = v2[k] & 0xff; + if (c1 != c2) + return c1 - c2; + k++; + } + return len1 - len2; + } + + @Override + public Path createSymbolicLink( + Path target, FileAttribute<?>... attrs) throws IOException { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public Path createLink( + Path existing) throws IOException { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public Path readSymbolicLink() throws IOException { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public Path createDirectory(FileAttribute<?>... attrs) + throws IOException + { + zfs.createDirectory(getResolvedPath(), attrs); + return this; + } + + public final Path createFile(FileAttribute<?>... attrs) + throws IOException + { + OutputStream os = newOutputStream(CREATE_NEW, WRITE); + try { + os.close(); + } catch (IOException x) {} + return this; + } + + @Override + public InputStream newInputStream(OpenOption... options) + throws IOException { + if (options.length > 0) { + for (OpenOption opt : options) { + if (opt != READ) + throw new UnsupportedOperationException("'" + opt + "' not allowed"); + } + } + return zfs.newInputStream(getResolvedPath()); + } + + private static final DirectoryStream.Filter<Path> acceptAllFilter = + new DirectoryStream.Filter<>() { + @Override public boolean accept(Path entry) { return true; } + }; + + @Override + public final DirectoryStream<Path> newDirectoryStream() throws IOException { + return newDirectoryStream(acceptAllFilter); + } + + @Override + public DirectoryStream<Path> newDirectoryStream(Filter<? super Path> filter) + throws IOException + { + return new ZipDirectoryStream(this, filter); + } + + @Override + public final DirectoryStream<Path> newDirectoryStream(String glob) + throws IOException + { + // avoid creating a matcher if all entries are required. + if (glob.equals("*")) + return newDirectoryStream(); + + // create a matcher and return a filter that uses it. + final PathMatcher matcher = getFileSystem().getPathMatcher("glob:" + glob); + DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<>() { + @Override + public boolean accept(Path entry) { + return matcher.matches(entry.getName()); + } + }; + return newDirectoryStream(filter); + } + + @Override + public final void delete() throws IOException { + zfs.deleteFile(getResolvedPath(), true); + } + + @Override + public final void deleteIfExists() throws IOException { + zfs.deleteFile(getResolvedPath(), false); + } + + ZipFileAttributes getAttributes() throws IOException + { + ZipFileAttributes zfas = zfs.getFileAttributes(getResolvedPath()); + if (zfas == null) + throw new NoSuchFileException(toString()); + return zfas; + } + + @Override + @SuppressWarnings("unchecked") + public <V extends FileAttributeView> V getFileAttributeView(Class<V> type, + LinkOption... options) + { + return (V)ZipFileAttributeView.get(this, type); + } + + @Override + public void setAttribute(String attribute, + Object value, + LinkOption... options) + throws IOException + { + String type = null; + String attr = null; + int colonPos = attribute.indexOf(':'); + if (colonPos == -1) { + type = "basic"; + attr = attribute; + } else { + type = attribute.substring(0, colonPos++); + attr = attribute.substring(colonPos); + } + ZipFileAttributeView view = ZipFileAttributeView.get(this, type); + if (view == null) + throw new UnsupportedOperationException("view <" + view + "> is not supported"); + view.setAttribute(attr, value); + } + + void setTimes(FileTime mtime, FileTime atime, FileTime ctime) + throws IOException + { + zfs.setTimes(getResolvedPath(), mtime, atime, ctime); + } + + private Object getAttributesImpl(String attribute, boolean domap) + throws IOException + { + String view = null; + String attr = null; + int colonPos = attribute.indexOf(':'); + if (colonPos == -1) { + view = "basic"; + attr = attribute; + } else { + view = attribute.substring(0, colonPos++); + attr = attribute.substring(colonPos); + } + ZipFileAttributeView zfv = ZipFileAttributeView.get(this, view); + if (zfv == null) { + throw new UnsupportedOperationException("view not supported"); + } + return zfv.getAttribute(attr, domap); + } + + @Override + public Object getAttribute(String attribute, LinkOption... options) + throws IOException + { + return getAttributesImpl(attribute, false); + } + + @Override + public Map<String,?> readAttributes(String attribute, LinkOption... options) + throws IOException + { + return (Map<String, ?>)getAttributesImpl(attribute, true); + } + + @Override + public FileStore getFileStore() throws IOException { + // each ZipFileSystem only has one root (as requested for now) + if (exists()) + return zfs.getFileStore(this); + throw new NoSuchFileException(zfs.getString(path)); + } + + @Override + public boolean isSameFile(Path other) throws IOException { + if (other == null || + this.getFileSystem() != other.getFileSystem()) + return false; + this.checkAccess(); + other.checkAccess(); + return Arrays.equals(this.getResolvedPath(), + ((ZipPath)other).getResolvedPath()); + } + + public WatchKey register( + WatchService watcher, + WatchEvent.Kind<?>[] events, + WatchEvent.Modifier... modifiers) { + if (watcher == null || events == null || modifiers == null) { + throw new NullPointerException(); + } + throw new UnsupportedOperationException(); + } + + @Override + public WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events) { + return register(watcher, events, new WatchEvent.Modifier[0]); + } + + @Override + public Iterator<Path> iterator() { + return new Iterator<>() { + private int i = 0; + + @Override + public boolean hasNext() { + return (i < getNameCount()); + } + + @Override + public Path next() { + if (i < getNameCount()) { + Path result = getName(i); + i++; + return result; + } else { + throw new NoSuchElementException(); + } + } + + @Override + public void remove() { + throw new ReadOnlyFileSystemException(); + } + }; + } + + @Override + public SeekableByteChannel newByteChannel(Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + return zfs.newByteChannel(getResolvedPath(), options, attrs); + } + + + FileChannel newFileChannel(Set<? extends OpenOption> options, + FileAttribute<?>... attrs) + throws IOException + { + return zfs.newFileChannel(getResolvedPath(), options, attrs); + } + + @Override + public SeekableByteChannel newByteChannel(OpenOption... options) + throws IOException { + Set<OpenOption> set = new HashSet<>(options.length); + Collections.addAll(set, options); + return newByteChannel(set); + } + + @Override + public void checkAccess(AccessMode... modes) throws IOException { + boolean w = false; + boolean x = false; + for (AccessMode mode : modes) { + switch (mode) { + case READ: + break; + case WRITE: + w = true; + break; + case EXECUTE: + x = true; + break; + default: + throw new UnsupportedOperationException(); + } + } + ZipFileAttributes attrs = zfs.getFileAttributes(getResolvedPath()); + if (attrs == null && (path.length != 1 || path[0] != '/')) + throw new NoSuchFileException(toString()); + if (w) { + if (zfs.isReadOnly()) + throw new AccessDeniedException(toString()); + } + if (x) + throw new AccessDeniedException(toString()); + + } + + @Override + public boolean exists() { + if (path.length == 1 && path[0] == '/') + return true; + try { + return zfs.exists(getResolvedPath()); + } catch (IOException x) {} + return false; + } + + @Override + public boolean notExists() { + return !exists(); + } + + + @Override + public OutputStream newOutputStream(OpenOption... options) + throws IOException + { + if (options.length == 0) + return zfs.newOutputStream(getResolvedPath(), + CREATE_NEW, WRITE); + return zfs.newOutputStream(getResolvedPath(), options); + } + + @Override + public Path moveTo(Path target, CopyOption... options) + throws IOException + { + if (this.zfs.provider() == target.getFileSystem().provider() && + this.zfs.getZipFile().isSameFile(((ZipPath)target).zfs.getZipFile())) + { + zfs.copyFile(true, + getResolvedPath(), + ((ZipPath)target).getResolvedPath(), + options); + } else { + copyToTarget(target, options); + delete(); + } + return target; + } + + @Override + public Path copyTo(Path target, CopyOption... options) + throws IOException + { + if (this.zfs.provider() == target.getFileSystem().provider() && + this.zfs.getZipFile().isSameFile(((ZipPath)target).zfs.getZipFile())) + { + zfs.copyFile(false, + getResolvedPath(), + ((ZipPath)target).getResolvedPath(), + options); + } else { + copyToTarget(target, options); + } + return target; + } + + private void copyToTarget(Path target, CopyOption... options) + throws IOException + { + boolean replaceExisting = false; + boolean copyAttrs = false; + for (CopyOption opt : options) { + if (opt == REPLACE_EXISTING) + replaceExisting = true; + else if (opt == COPY_ATTRIBUTES) + copyAttrs = true; + } + // attributes of source file + ZipFileAttributes zfas = getAttributes(); + // check if target exists + boolean exists; + if (replaceExisting) { + try { + target.deleteIfExists(); + exists = false; + } catch (DirectoryNotEmptyException x) { + exists = true; + } + } else { + exists = target.exists(); + } + if (exists) + throw new FileAlreadyExistsException(target.toString()); + + if (zfas.isDirectory()) { + // create directory or file + target.createDirectory(); + } else { + InputStream is = zfs.newInputStream(getResolvedPath()); + try { + OutputStream os = target.newOutputStream(); + try { + byte[] buf = new byte[8192]; + int n = 0; + while ((n = is.read(buf)) != -1) { + os.write(buf, 0, n); + } + } finally { + os.close(); + } + } finally { + is.close(); + } + } + if (copyAttrs) { + BasicFileAttributeView view = + target.getFileAttributeView(BasicFileAttributeView.class); + try { + view.setTimes(zfas.lastModifiedTime(), + zfas.lastAccessTime(), + zfas.creationTime()); + } catch (IOException x) { + // rollback? + try { + target.delete(); + } catch (IOException ignore) { } + throw x; + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipUtils.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.sun.nio.zipfs; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.Date; +import java.util.regex.PatternSyntaxException; +import java.util.concurrent.TimeUnit; + +/** + * + * @author Xueming Shen + */ + +class ZipUtils { + + /* + * Writes a 16-bit short to the output stream in little-endian byte order. + */ + public static void writeShort(OutputStream os, int v) throws IOException { + os.write(v & 0xff); + os.write((v >>> 8) & 0xff); + } + + /* + * Writes a 32-bit int to the output stream in little-endian byte order. + */ + public static void writeInt(OutputStream os, long v) throws IOException { + os.write((int)(v & 0xff)); + os.write((int)((v >>> 8) & 0xff)); + os.write((int)((v >>> 16) & 0xff)); + os.write((int)((v >>> 24) & 0xff)); + } + + /* + * Writes a 64-bit int to the output stream in little-endian byte order. + */ + public static void writeLong(OutputStream os, long v) throws IOException { + os.write((int)(v & 0xff)); + os.write((int)((v >>> 8) & 0xff)); + os.write((int)((v >>> 16) & 0xff)); + os.write((int)((v >>> 24) & 0xff)); + os.write((int)((v >>> 32) & 0xff)); + os.write((int)((v >>> 40) & 0xff)); + os.write((int)((v >>> 48) & 0xff)); + os.write((int)((v >>> 56) & 0xff)); + } + + /* + * Writes an array of bytes to the output stream. + */ + public static void writeBytes(OutputStream os, byte[] b) + throws IOException + { + os.write(b, 0, b.length); + } + + /* + * Writes an array of bytes to the output stream. + */ + public static void writeBytes(OutputStream os, byte[] b, int off, int len) + throws IOException + { + os.write(b, off, len); + } + + /* + * Append a slash at the end, if it does not have one yet + */ + public static byte[] toDirectoryPath(byte[] dir) { + if (dir.length != 0 && dir[dir.length - 1] != '/') { + dir = Arrays.copyOf(dir, dir.length + 1); + dir[dir.length - 1] = '/'; + } + return dir; + } + + /* + * Converts DOS time to Java time (number of milliseconds since epoch). + */ + public static long dosToJavaTime(long dtime) { + Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80), + (int)(((dtime >> 21) & 0x0f) - 1), + (int)((dtime >> 16) & 0x1f), + (int)((dtime >> 11) & 0x1f), + (int)((dtime >> 5) & 0x3f), + (int)((dtime << 1) & 0x3e)); + return d.getTime(); + } + + /* + * Converts Java time to DOS time. + */ + public static long javaToDosTime(long time) { + Date d = new Date(time); + int year = d.getYear() + 1900; + if (year < 1980) { + return (1 << 21) | (1 << 16); + } + return (year - 1980) << 25 | (d.getMonth() + 1) << 21 | + d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 | + d.getSeconds() >> 1; + } + + + // used to adjust values between Windows and java epoch + private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L; + public static final long winToJavaTime(long wtime) { + return TimeUnit.MILLISECONDS.convert( + wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS, TimeUnit.MICROSECONDS); + } + + public static final long javaToWinTime(long time) { + return (TimeUnit.MICROSECONDS.convert(time, TimeUnit.MILLISECONDS) + - WINDOWS_EPOCH_IN_MICROSECONDS) * 10; + } + + public static final long unixToJavaTime(long utime) { + return TimeUnit.MILLISECONDS.convert(utime, TimeUnit.SECONDS); + } + + public static final long javaToUnixTime(long time) { + return TimeUnit.SECONDS.convert(time, TimeUnit.MILLISECONDS); + } + + private static final String regexMetaChars = ".^$+{[]|()"; + private static final String globMetaChars = "\\*?[{"; + private static boolean isRegexMeta(char c) { + return regexMetaChars.indexOf(c) != -1; + } + private static boolean isGlobMeta(char c) { + return globMetaChars.indexOf(c) != -1; + } + private static char EOL = 0; //TBD + private static char next(String glob, int i) { + if (i < glob.length()) { + return glob.charAt(i); + } + return EOL; + } + + /* + * Creates a regex pattern from the given glob expression. + * + * @throws PatternSyntaxException + */ + public static String toRegexPattern(String globPattern) { + boolean inGroup = false; + StringBuilder regex = new StringBuilder("^"); + + int i = 0; + while (i < globPattern.length()) { + char c = globPattern.charAt(i++); + switch (c) { + case '\\': + // escape special characters + if (i == globPattern.length()) { + throw new PatternSyntaxException("No character to escape", + globPattern, i - 1); + } + char next = globPattern.charAt(i++); + if (isGlobMeta(next) || isRegexMeta(next)) { + regex.append('\\'); + } + regex.append(next); + break; + case '/': + regex.append(c); + break; + case '[': + // don't match name separator in class + regex.append("[[^/]&&["); + if (next(globPattern, i) == '^') { + // escape the regex negation char if it appears + regex.append("\\^"); + i++; + } else { + // negation + if (next(globPattern, i) == '!') { + regex.append('^'); + i++; + } + // hyphen allowed at start + if (next(globPattern, i) == '-') { + regex.append('-'); + i++; + } + } + boolean hasRangeStart = false; + char last = 0; + while (i < globPattern.length()) { + c = globPattern.charAt(i++); + if (c == ']') { + break; + } + if (c == '/') { + throw new PatternSyntaxException("Explicit 'name separator' in class", + globPattern, i - 1); + } + // TBD: how to specify ']' in a class? + if (c == '\\' || c == '[' || + c == '&' && next(globPattern, i) == '&') { + // escape '\', '[' or "&&" for regex class + regex.append('\\'); + } + regex.append(c); + + if (c == '-') { + if (!hasRangeStart) { + throw new PatternSyntaxException("Invalid range", + globPattern, i - 1); + } + if ((c = next(globPattern, i++)) == EOL || c == ']') { + break; + } + if (c < last) { + throw new PatternSyntaxException("Invalid range", + globPattern, i - 3); + } + regex.append(c); + hasRangeStart = false; + } else { + hasRangeStart = true; + last = c; + } + } + if (c != ']') { + throw new PatternSyntaxException("Missing ']", globPattern, i - 1); + } + regex.append("]]"); + break; + case '{': + if (inGroup) { + throw new PatternSyntaxException("Cannot nest groups", + globPattern, i - 1); + } + regex.append("(?:(?:"); + inGroup = true; + break; + case '}': + if (inGroup) { + regex.append("))"); + inGroup = false; + } else { + regex.append('}'); + } + break; + case ',': + if (inGroup) { + regex.append(")|(?:"); + } else { + regex.append(','); + } + break; + case '*': + if (next(globPattern, i) == '*') { + // crosses directory boundaries + regex.append(".*"); + i++; + } else { + // within directory boundary + regex.append("[^/]*"); + } + break; + case '?': + regex.append("[^/]"); + break; + default: + if (isRegexMeta(c)) { + regex.append('\\'); + } + regex.append(c); + } + } + if (inGroup) { + throw new PatternSyntaxException("Missing '}", globPattern, i - 1); + } + return regex.append('$').toString(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/demo/zipfs Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,703 @@ +/* + * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.io.*; +import java.nio.*; +import java.nio.channels.*; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.net.*; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; + +import static java.nio.file.StandardOpenOption.*; +import static java.nio.file.StandardCopyOption.*; + +/* + * ZipFileSystem usage demo + * + * java Demo action ZipfileName [...] + * + * @author Xueming Shen + */ + +public class Demo { + + static enum Action { + rename, // <java Demo rename zipfile src dst> + // rename entry src to dst inside zipfile + + movein, // <java Demo movein zipfile src dst> + // move an external src file into zipfile + // as entry dst + + moveout, // <java Demo moveout zipfile src dst> + // move a zipfile entry src out to dst + + copy, // <java Demo copy zipfile src dst> + // copy entry src to dst inside zipfile + + copyin, // <java Demo copyin zipfile src dst> + // copy an external src file into zipfile + // as entry dst + + copyin_attrs, // <java Demo copyin_attrs zipfile src dst> + // copy an external src file into zipfile + // as entry dst, with attributes (timestamp) + + copyout, // <java Demo copyout zipfile src dst> + // copy zipfile entry src" out to file dst + + copyout_attrs, // <java Demo copyout_attrs zipfile src dst> + + zzmove, // <java Demo zzmove zfsrc zfdst path> + // move entry path/dir from zfsrc to zfdst + + zzcopy, // <java Demo zzcopy zfsrc zfdst path> + // copy path from zipfile zfsrc to zipfile + // zfdst + + attrs, // <java Demo attrs zipfile path> + // printout the attributes of entry path + + attrsspace, // <java Demo attrsspace zipfile path> + // printout the storespace attrs of entry path + + setmtime, // <java Demo setmtime zipfile "MM/dd/yy-HH:mm:ss" path...> + // set the lastModifiedTime of entry path + + setatime, // <java Demo setatime zipfile "MM/dd/yy-HH:mm:ss" path...> + setctime, // <java Demo setctime zipfile "MM/dd/yy-HH:mm:ss" path...> + + lsdir, // <java Demo lsdir zipfile dir> + // list dir's direct child files/dirs + + mkdir, // <java Demo mkdir zipfile dir> + + mkdirs, // <java Demo mkdirs zipfile dir> + + rmdirs, // <java Demo rmdirs zipfile dir> + + list, // <java Demo list zipfile [dir]> + // recursively list all entries of dir + // via DirectoryStream + + tlist, // <java Demo tlist zipfile [dir]> + // list with buildDirTree=true + + vlist, // <java Demo vlist zipfile [dir]> + // recursively verbose list all entries of + // dir via DirectoryStream + + walk, // <java Demo walk zipfile [dir]> + // recursively walk all entries of dir + // via Files.walkFileTree + + twalk, // <java Demo twalk zipfile [dir]> + // walk with buildDirTree=true + + extract, // <java Demo extract zipfile file [...]> + + update, // <java Demo extract zipfile file [...]> + + delete, // <java Demo delete zipfile file [...]> + + add, // <java Demo add zipfile file [...]> + + create, // <java Demo create zipfile file [...]> + // create a new zipfile if it doesn't exit + // and then add the file(s) into it. + + attrs2, // <java Demo attrs2 zipfile file [...]> + // test different ways to print attrs + + prof, + } + + public static void main(String[] args) throws Throwable { + + Action action = Action.valueOf(args[0]); + Map<String, Object> env = env = new HashMap<>(); + if (action == Action.create) + env.put("create", "true"); + if (action == Action.tlist || action == Action.twalk) + env.put("buildDirTree", true); + FileSystem fs = FileSystems.newFileSystem(Paths.get(args[1]), env, null); + + try { + FileSystem fs2; + Path path, src, dst; + boolean isRename = false; + switch (action) { + case rename: + src = fs.getPath(args[2]); + dst = fs.getPath(args[3]); + src.moveTo(dst); + break; + case moveout: + src = fs.getPath(args[2]); + dst = Paths.get(args[3]); + src.moveTo(dst); + break; + case movein: + src = Paths.get(args[2]); + dst = fs.getPath(args[3]); + src.moveTo(dst); + break; + case copy: + src = fs.getPath(args[2]); + dst = fs.getPath(args[3]); + src.copyTo(dst); + break; + case copyout: + src = fs.getPath(args[2]); + dst = Paths.get(args[3]); + src.copyTo(dst); + break; + case copyin: + src = Paths.get(args[2]); + dst = fs.getPath(args[3]); + src.copyTo(dst); + break; + case copyin_attrs: + src = Paths.get(args[2]); + dst = fs.getPath(args[3]); + src.copyTo(dst, COPY_ATTRIBUTES); + break; + case copyout_attrs: + src = fs.getPath(args[2]); + dst = Paths.get(args[3]); + src.copyTo(dst, COPY_ATTRIBUTES); + break; + case zzmove: + fs2 = FileSystems.newFileSystem(Paths.get(args[2]), env, null); + //sf1.getPath(args[3]).moveTo(fs2.getPath(args[3])); + z2zmove(fs, fs2, args[3]); + fs2.close(); + break; + case zzcopy: + fs2 = FileSystems.newFileSystem(Paths.get(args[2]), env, null); + //sf1.getPath(args[3]).copyTo(fs2.getPath(args[3])); + z2zcopy(fs, fs2, args[3]); + fs2.close(); + break; + case attrs: + for (int i = 2; i < args.length; i++) { + path = fs.getPath(args[i]); + System.out.println(path); + System.out.println( + Attributes.readBasicFileAttributes(path).toString()); + } + break; + case setmtime: + DateFormat df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss"); + Date newDatetime = df.parse(args[2]); + for (int i = 3; i < args.length; i++) { + path = fs.getPath(args[i]); + path.setAttribute("lastModifiedTime", + FileTime.fromMillis(newDatetime.getTime())); + System.out.println( + Attributes.readBasicFileAttributes(path).toString()); + } + break; + case setctime: + df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss"); + newDatetime = df.parse(args[2]); + for (int i = 3; i < args.length; i++) { + path = fs.getPath(args[i]); + path.setAttribute("creationTime", + FileTime.fromMillis(newDatetime.getTime())); + System.out.println( + Attributes.readBasicFileAttributes(path).toString()); + } + break; + case setatime: + df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss"); + newDatetime = df.parse(args[2]); + for (int i = 3; i < args.length; i++) { + path = fs.getPath(args[i]); + path.setAttribute("lastAccessTime", + FileTime.fromMillis(newDatetime.getTime())); + System.out.println( + Attributes.readBasicFileAttributes(path).toString()); + } + break; + case attrsspace: + path = fs.getPath("/"); + FileStore fstore = path.getFileStore(); + //System.out.println(fstore.getFileStoreAttributeView(FileStoreSpaceAttributeView.class) + // .readAttributes()); + // or + System.out.printf("filestore[%s]%n", fstore.name()); + System.out.printf(" totalSpace: %d%n", + (Long)fstore.getAttribute("space:totalSpace")); + System.out.printf(" usableSpace: %d%n", + (Long)fstore.getAttribute("space:usableSpace")); + System.out.printf(" unallocSpace: %d%n", + (Long)fstore.getAttribute("space:unallocatedSpace")); + break; + case list: + case tlist: + if (args.length < 3) + list(fs.getPath("/"), false); + else + list(fs.getPath(args[2]), false); + break; + case vlist: + if (args.length < 3) + list(fs.getPath("/"), true); + else + list(fs.getPath(args[2]), true); + break; + case twalk: + case walk: + walk(fs.getPath((args.length > 2)? args[2] : "/")); + break; + case extract: + if (args.length == 2) { + extract(fs, "/"); + } else { + for (int i = 2; i < args.length; i++) { + extract(fs, args[i]); + } + } + break; + case delete: + for (int i = 2; i < args.length; i++) + fs.getPath(args[i]).delete(); + break; + case create: + case add: + case update: + for (int i = 2; i < args.length; i++) { + update(fs, args[i]); + } + break; + case lsdir: + path = fs.getPath(args[2]); + final String fStr = (args.length > 3)?args[3]:""; + DirectoryStream<Path> ds = path.newDirectoryStream( + new DirectoryStream.Filter<Path>() { + public boolean accept(Path path) { + return path.toString().contains(fStr); + } + }); + for (Path p : ds) + System.out.println(p); + break; + case mkdir: + fs.getPath(args[2]).createDirectory(); + break; + case mkdirs: + mkdirs(fs.getPath(args[2])); + break; + case attrs2: + for (int i = 2; i < args.length; i++) { + path = fs.getPath(args[i]); + System.out.printf("%n%s%n", path); + System.out.println("-------(1)---------"); + System.out.println( + Attributes.readBasicFileAttributes(path).toString()); + System.out.println("-------(2)---------"); + Map<String, ?> map = path.readAttributes("zip:*"); + for (Map.Entry<String, ?> e : map.entrySet()) { + System.out.printf(" %s : %s%n", e.getKey(), e.getValue()); + } + System.out.println("-------(3)---------"); + map = path.readAttributes("size,lastModifiedTime,isDirectory"); + for (Map.Entry<String, ?> e : map.entrySet()) { + System.out.printf(" %s : %s%n", e.getKey(), e.getValue()); + } + } + break; + case prof: + list(fs.getPath("/"), false); + while (true) { + Thread.sleep(10000); + //list(fs.getPath("/"), true); + System.out.println("sleeping..."); + } + } + } catch (Exception x) { + x.printStackTrace(); + } finally { + if (fs != null) + fs.close(); + } + } + + private static byte[] getBytes(String name) { + return name.getBytes(); + } + + private static String getString(byte[] name) { + return new String(name); + } + + private static void walk(Path path) throws IOException + { + Files.walkFileTree( + path, + new SimpleFileVisitor<Path>() { + private int indent = 0; + private void indent() { + int n = 0; + while (n++ < indent) + System.out.printf(" "); + } + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) + { + indent(); + System.out.printf("%s%n", file.getName().toString()); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, + BasicFileAttributes attrs) + { + indent(); + System.out.printf("[%s]%n", dir.toString()); + indent += 2; + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, + IOException ioe) + { + indent -= 2; + return FileVisitResult.CONTINUE; + } + }); + } + + private static void update(FileSystem fs, String path) throws Throwable{ + Path src = FileSystems.getDefault().getPath(path); + if (Boolean.TRUE.equals(src.getAttribute("isDirectory"))) { + DirectoryStream<Path> ds = src.newDirectoryStream(); + for (Path child : ds) + update(fs, child.toString()); + ds.close(); + } else { + Path dst = fs.getPath(path); + Path parent = dst.getParent(); + if (parent != null && parent.notExists()) + mkdirs(parent); + src.copyTo(dst, REPLACE_EXISTING); + } + } + + private static void extract(FileSystem fs, String path) throws Throwable{ + Path src = fs.getPath(path); + if (Boolean.TRUE.equals(src.getAttribute("isDirectory"))) { + DirectoryStream<Path> ds = src.newDirectoryStream(); + for (Path child : ds) + extract(fs, child.toString()); + ds.close(); + } else { + if (path.startsWith("/")) + path = path.substring(1); + Path dst = FileSystems.getDefault().getPath(path); + Path parent = dst.getParent(); + if (parent.notExists()) + mkdirs(parent); + src.copyTo(dst, REPLACE_EXISTING); + } + } + + // use DirectoryStream + private static void z2zcopy(FileSystem src, FileSystem dst, String path) + throws IOException + { + Path srcPath = src.getPath(path); + Path dstPath = dst.getPath(path); + + if (Boolean.TRUE.equals(srcPath.getAttribute("isDirectory"))) { + if (!dstPath.exists()) { + try { + mkdirs(dstPath); + } catch (FileAlreadyExistsException x) {} + } + DirectoryStream<Path> ds = srcPath.newDirectoryStream(); + for (Path child : ds) { + z2zcopy(src, dst, + path + (path.endsWith("/")?"":"/") + child.getName()); + } + ds.close(); + } else { + //System.out.println("copying..." + path); + srcPath.copyTo(dstPath); + } + } + + // use TreeWalk to move + private static void z2zmove(FileSystem src, FileSystem dst, String path) + throws IOException + { + final Path srcPath = src.getPath(path).toAbsolutePath(); + final Path dstPath = dst.getPath(path).toAbsolutePath(); + + Files.walkFileTree(srcPath, new SimpleFileVisitor<Path>() { + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) + { + Path dst = srcPath.relativize(file); + dst = dstPath.resolve(dst); + try { + Path parent = dstPath.getParent(); + if (parent != null && parent.notExists()) + mkdirs(parent); + file.moveTo(dst); + } catch (IOException x) { + x.printStackTrace(); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, + BasicFileAttributes attrs) + { + Path dst = srcPath.relativize(dir); + dst = dstPath.resolve(dst); + try { + + if (dst.notExists()) + mkdirs(dst); + } catch (IOException x) { + x.printStackTrace(); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, + IOException ioe) + throws IOException + { + try { + dir.delete(); + } catch (IOException x) { + //x.printStackTrace(); + } + return FileVisitResult.CONTINUE; + } + }); + + } + + private static void mkdirs(Path path) throws IOException { + path = path.toAbsolutePath(); + Path parent = path.getParent(); + if (parent != null) { + if (parent.notExists()) + mkdirs(parent); + } + path.createDirectory(); + } + + private static void rmdirs(Path path) throws IOException { + while (path != null && path.getNameCount() != 0) { + path.delete(); + path = path.getParent(); + } + } + + private static void list(Path path, boolean verbose ) throws IOException { + if (!"/".equals(path.toString())) { + System.out.printf(" %s%n", path.toString()); + if (verbose) + System.out.println(Attributes.readBasicFileAttributes(path).toString()); + } + if (path.notExists()) + return; + if (Attributes.readBasicFileAttributes(path).isDirectory()) { + DirectoryStream<Path> ds = path.newDirectoryStream(); + for (Path child : ds) + list(child, verbose); + ds.close(); + } + } + + // check the content of two paths are equal + private static void checkEqual(Path src, Path dst) throws IOException + { + //System.out.printf("checking <%s> vs <%s>...%n", + // src.toString(), dst.toString()); + + //streams + InputStream isSrc = src.newInputStream(); + InputStream isDst = dst.newInputStream(); + byte[] bufSrc = new byte[8192]; + byte[] bufDst = new byte[8192]; + + try { + int nSrc = 0; + while ((nSrc = isSrc.read(bufSrc)) != -1) { + int nDst = 0; + while (nDst < nSrc) { + int n = isDst.read(bufDst, nDst, nSrc - nDst); + if (n == -1) { + System.out.printf("checking <%s> vs <%s>...%n", + src.toString(), dst.toString()); + throw new RuntimeException("CHECK FAILED!"); + } + nDst += n; + } + while (--nSrc >= 0) { + if (bufSrc[nSrc] != bufDst[nSrc]) { + System.out.printf("checking <%s> vs <%s>...%n", + src.toString(), dst.toString()); + throw new RuntimeException("CHECK FAILED!"); + } + nSrc--; + } + } + } finally { + isSrc.close(); + isDst.close(); + } + + // channels + SeekableByteChannel chSrc = src.newByteChannel(); + SeekableByteChannel chDst = dst.newByteChannel(); + if (chSrc.size() != chDst.size()) { + System.out.printf("src[%s].size=%d, dst[%s].size=%d%n", + chSrc.toString(), chSrc.size(), + chDst.toString(), chDst.size()); + throw new RuntimeException("CHECK FAILED!"); + } + ByteBuffer bbSrc = ByteBuffer.allocate(8192); + ByteBuffer bbDst = ByteBuffer.allocate(8192); + + try { + int nSrc = 0; + while ((nSrc = chSrc.read(bbSrc)) != -1) { + int nDst = chDst.read(bbDst); + if (nSrc != nDst) { + System.out.printf("checking <%s> vs <%s>...%n", + src.toString(), dst.toString()); + throw new RuntimeException("CHECK FAILED!"); + } + while (--nSrc >= 0) { + if (bbSrc.get(nSrc) != bbDst.get(nSrc)) { + System.out.printf("checking <%s> vs <%s>...%n", + src.toString(), dst.toString()); + throw new RuntimeException("CHECK FAILED!"); + } + nSrc--; + } + bbSrc.flip(); + bbDst.flip(); + } + } catch (IOException x) { + x.printStackTrace(); + } finally { + chSrc.close(); + chDst.close(); + } + } + + private static void fchCopy(Path src, Path dst) throws IOException + { + Set<OpenOption> read = new HashSet<>(); + read.add(READ); + Set<OpenOption> openwrite = new HashSet<>(); + openwrite.add(CREATE_NEW); + openwrite.add(WRITE); + + FileChannel srcFc = src.getFileSystem() + .provider() + .newFileChannel(src, read); + FileChannel dstFc = dst.getFileSystem() + .provider() + .newFileChannel(dst, openwrite); + + try { + ByteBuffer bb = ByteBuffer.allocate(8192); + while (srcFc.read(bb) >= 0) { + bb.flip(); + dstFc.write(bb); + bb.clear(); + } + } finally { + srcFc.close(); + dstFc.close(); + } + } + + private static void chCopy(Path src, Path dst) throws IOException + { + Set<OpenOption> read = new HashSet<>(); + read.add(READ); + Set<OpenOption> openwrite = new HashSet<>(); + openwrite.add(CREATE_NEW); + openwrite.add(WRITE); + + SeekableByteChannel srcCh = src.newByteChannel(read); + SeekableByteChannel dstCh = dst.newByteChannel(openwrite); + + try { + ByteBuffer bb = ByteBuffer.allocate(8192); + while (srcCh.read(bb) >= 0) { + bb.flip(); + dstCh.write(bb); + bb.clear(); + } + } finally { + srcCh.close(); + dstCh.close(); + } + } + + private static void streamCopy(Path src, Path dst) throws IOException + { + InputStream isSrc = src.newInputStream(); + OutputStream osDst = dst.newOutputStream(); + byte[] buf = new byte[8192]; + try { + int n = 0; + while ((n = isSrc.read(buf)) != -1) { + osDst.write(buf, 0, n); + } + } finally { + isSrc.close(); + osDst.close(); + } + } +}
--- a/src/share/native/java/io/RandomAccessFile.c Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/native/java/io/RandomAccessFile.c Mon Dec 13 16:25:26 2010 -0800 @@ -76,13 +76,13 @@ JNIEXPORT void JNICALL Java_java_io_RandomAccessFile_write(JNIEnv *env, jobject this, jint byte) { - writeSingle(env, this, byte, raf_fd); + writeSingle(env, this, byte, JNI_FALSE, raf_fd); } JNIEXPORT void JNICALL Java_java_io_RandomAccessFile_writeBytes(JNIEnv *env, jobject this, jbyteArray bytes, jint off, jint len) { - writeBytes(env, this, bytes, off, len, raf_fd); + writeBytes(env, this, bytes, off, len, JNI_FALSE, raf_fd); } JNIEXPORT jlong JNICALL
--- a/src/share/native/java/io/io_util.c Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/native/java/io/io_util.c Mon Dec 13 16:25:26 2010 -0800 @@ -127,7 +127,7 @@ } void -writeSingle(JNIEnv *env, jobject this, jint byte, jfieldID fid) { +writeSingle(JNIEnv *env, jobject this, jint byte, jboolean append, jfieldID fid) { // Discard the 24 high-order bits of byte. See OutputStream#write(int) char c = (char) byte; jint n; @@ -136,7 +136,11 @@ JNU_ThrowIOException(env, "Stream Closed"); return; } - n = IO_Write(fd, &c, 1); + if (append == JNI_TRUE) { + n = IO_Append(fd, &c, 1); + } else { + n = IO_Write(fd, &c, 1); + } if (n == JVM_IO_ERR) { JNU_ThrowIOExceptionWithLastError(env, "Write error"); } else if (n == JVM_IO_INTR) { @@ -146,7 +150,7 @@ void writeBytes(JNIEnv *env, jobject this, jbyteArray bytes, - jint off, jint len, jfieldID fid) + jint off, jint len, jboolean append, jfieldID fid) { jint n; char stackBuf[BUF_SIZE]; @@ -185,7 +189,11 @@ JNU_ThrowIOException(env, "Stream Closed"); break; } - n = IO_Write(fd, buf+off, len); + if (append == JNI_TRUE) { + n = IO_Append(fd, buf+off, len); + } else { + n = IO_Write(fd, buf+off, len); + } if (n == JVM_IO_ERR) { JNU_ThrowIOExceptionWithLastError(env, "Write error"); break;
--- a/src/share/native/java/io/io_util.h Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/native/java/io/io_util.h Mon Dec 13 16:25:26 2010 -0800 @@ -41,9 +41,9 @@ jint readSingle(JNIEnv *env, jobject this, jfieldID fid); jint readBytes(JNIEnv *env, jobject this, jbyteArray bytes, jint off, jint len, jfieldID fid); -void writeSingle(JNIEnv *env, jobject this, jint byte, jfieldID fid); +void writeSingle(JNIEnv *env, jobject this, jint byte, jboolean append, jfieldID fid); void writeBytes(JNIEnv *env, jobject this, jbyteArray bytes, jint off, - jint len, jfieldID fid); + jint len, jboolean append, jfieldID fid); void fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags); void throwFileNotFoundException(JNIEnv *env, jstring path);
--- a/src/share/native/sun/security/ec/ECC_JNI.cpp Mon Dec 13 16:22:29 2010 -0800 +++ b/src/share/native/sun/security/ec/ECC_JNI.cpp Mon Dec 13 16:25:26 2010 -0800 @@ -89,7 +89,7 @@ // Fill a new ECParams using the supplied OID if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) { /* bad curve OID */ - ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION); + ThrowException(env, (char *) INVALID_ALGORITHM_PARAMETER_EXCEPTION); goto cleanup; } @@ -101,7 +101,7 @@ // Generate the new keypair (using the supplied seed) if (EC_NewKey(ecparams, &privKey, (unsigned char *) pSeedBuffer, jSeedLength, 0) != SECSuccess) { - ThrowException(env, KEY_EXCEPTION); + ThrowException(env, (char *) KEY_EXCEPTION); goto cleanup; }
--- a/src/solaris/classes/java/lang/ProcessImpl.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/solaris/classes/java/lang/ProcessImpl.java Mon Dec 13 16:25:26 2010 -0800 @@ -111,7 +111,8 @@ else if (redirects[1] == Redirect.INHERIT) std_fds[1] = 1; else { - f1 = redirects[1].toFileOutputStream(); + f1 = new FileOutputStream(redirects[1].file(), + redirects[1].append()); std_fds[1] = fdAccess.get(f1.getFD()); } @@ -120,7 +121,8 @@ else if (redirects[2] == Redirect.INHERIT) std_fds[2] = 2; else { - f2 = redirects[2].toFileOutputStream(); + f2 = new FileOutputStream(redirects[2].file(), + redirects[2].append()); std_fds[2] = fdAccess.get(f2.getFD()); } }
--- a/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java Mon Dec 13 16:25:26 2010 -0800 @@ -35,6 +35,13 @@ init(); } + FileDispatcherImpl(boolean append) { + /* append is ignored */ + } + + FileDispatcherImpl() { + } + int read(FileDescriptor fd, long address, int len) throws IOException { return read0(fd, address, len); }
--- a/src/solaris/classes/sun/nio/ch/SctpNet.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/solaris/classes/sun/nio/ch/SctpNet.java Mon Dec 13 16:25:26 2010 -0800 @@ -43,7 +43,7 @@ /* -- Miscellaneous SCTP utilities -- */ - static boolean bindxIPv4MappedAddresses() { + private static boolean IPv4MappedAddresses() { if ("SunOS".equals(osName)) { /* Solaris supports IPv4Mapped Addresses with bindx */ return true; @@ -87,7 +87,7 @@ static void bindx(int fd, InetAddress[] addrs, int port, boolean add) throws IOException { bindx(fd, addrs, port, addrs.length, add, - bindxIPv4MappedAddresses()); + IPv4MappedAddresses()); } static Set<SocketAddress> getLocalAddresses(int fd) @@ -145,11 +145,16 @@ InetSocketAddress netAddr = (InetSocketAddress)addr; if (name.equals(SCTP_PRIMARY_ADDR)) { - setPrimAddrOption0(fd, assocId, - netAddr.getAddress(), netAddr.getPort()); + setPrimAddrOption0(fd, + assocId, + netAddr.getAddress(), + netAddr.getPort()); } else { - setPeerPrimAddrOption0(fd, assocId, - netAddr.getAddress(), netAddr.getPort()); + setPeerPrimAddrOption0(fd, + assocId, + netAddr.getAddress(), + netAddr.getPort(), + IPv4MappedAddresses()); } } else if (name.equals(SCTP_DISABLE_FRAGMENTS) || name.equals(SCTP_EXPLICIT_COMPLETE) || @@ -290,7 +295,7 @@ int port) throws IOException; static native void setPeerPrimAddrOption0(int fd, int assocId, - InetAddress ia, int port) throws IOException; + InetAddress ia, int port, boolean preferIPv6) throws IOException; static native SocketAddress getPrimAddrOption0(int fd, int assocId) throws IOException;
--- a/src/solaris/native/java/io/FileOutputStream_md.c Mon Dec 13 16:22:29 2010 -0800 +++ b/src/solaris/native/java/io/FileOutputStream_md.c Mon Dec 13 16:25:26 2010 -0800 @@ -60,14 +60,14 @@ } JNIEXPORT void JNICALL -Java_java_io_FileOutputStream_write(JNIEnv *env, jobject this, jint byte) { - writeSingle(env, this, byte, fos_fd); +Java_java_io_FileOutputStream_write(JNIEnv *env, jobject this, jint byte, jboolean append) { + writeSingle(env, this, byte, append, fos_fd); } JNIEXPORT void JNICALL Java_java_io_FileOutputStream_writeBytes(JNIEnv *env, - jobject this, jbyteArray bytes, jint off, jint len) { - writeBytes(env, this, bytes, off, len, fos_fd); + jobject this, jbyteArray bytes, jint off, jint len, jboolean append) { + writeBytes(env, this, bytes, off, len, append, fos_fd); } JNIEXPORT void JNICALL
--- a/src/solaris/native/java/io/io_util_md.h Mon Dec 13 16:22:29 2010 -0800 +++ b/src/solaris/native/java/io/io_util_md.h Mon Dec 13 16:25:26 2010 -0800 @@ -53,8 +53,9 @@ #define THIS_FD(obj) (*env)->GetIntField(env, obj, IO_fd_fdID) /* - * Route the routines through HPI + * Route the routines through VM */ +#define IO_Append JVM_Write #define IO_Write JVM_Write #define IO_Sync JVM_Sync #define IO_Read JVM_Read
--- a/src/solaris/native/sun/nio/ch/SctpNet.c Mon Dec 13 16:22:29 2010 -0800 +++ b/src/solaris/native/sun/nio/ch/SctpNet.c Mon Dec 13 16:25:26 2010 -0800 @@ -617,18 +617,18 @@ * Signature: (IILjava/net/InetAddress;I)V */ JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_setPeerPrimAddrOption0 - (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port) { + (JNIEnv *env, jclass klass, jint fd, jint assocId, + jobject iaObj, jint port, jboolean preferIPv6) { struct sctp_setpeerprim prim; - struct sockaddr_storage ss; - int ss_len = sizeof(ss); + struct sockaddr* sap = (struct sockaddr*)&prim.sspp_addr; + int sap_len; - if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&ss, - &ss_len, JNI_TRUE) != 0) { + if (NET_InetAddressToSockaddr(env, iaObj, port, sap, + &sap_len, preferIPv6) != 0) { return; } prim.sspp_assoc_id = assocId; - prim.sspp_addr = ss; if (setsockopt(fd, IPPROTO_SCTP, SCTP_SET_PEER_PRIMARY_ADDR, &prim, sizeof(prim)) < 0) {
--- a/src/windows/classes/java/lang/ProcessImpl.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/windows/classes/java/lang/ProcessImpl.java Mon Dec 13 16:25:26 2010 -0800 @@ -35,6 +35,8 @@ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.lang.ProcessBuilder.Redirect; +import java.security.AccessController; +import java.security.PrivilegedAction; /* This class is for the exclusive use of ProcessBuilder.start() to * create new processes. @@ -47,6 +49,35 @@ private static final sun.misc.JavaIOFileDescriptorAccess fdAccess = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess(); + /** + * Open a file for writing. If {@code append} is {@code true} then the file + * is opened for atomic append directly and a FileOutputStream constructed + * with the resulting handle. This is because a FileOutputStream created + * to append to a file does not open the file in a manner that guarantees + * that writes by the child process will be atomic. + */ + private static FileOutputStream newFileOutputStream(File f, boolean append) + throws IOException + { + if (append) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkWrite(f.getPath()); + long handle = openForAtomicAppend(f.getPath()); + final FileDescriptor fd = new FileDescriptor(); + fdAccess.setHandle(fd, handle); + return AccessController.doPrivileged( + new PrivilegedAction<FileOutputStream>() { + public FileOutputStream run() { + return new FileOutputStream(fd); + } + } + ); + } else { + return new FileOutputStream(f); + } + } + // System-dependent portion of ProcessBuilder.start() static Process start(String cmdarray[], java.util.Map<String,String> environment, @@ -82,7 +113,8 @@ else if (redirects[1] == Redirect.INHERIT) stdHandles[1] = fdAccess.getHandle(FileDescriptor.out); else { - f1 = redirects[1].toFileOutputStream(); + f1 = newFileOutputStream(redirects[1].file(), + redirects[1].append()); stdHandles[1] = fdAccess.getHandle(f1.getFD()); } @@ -91,7 +123,8 @@ else if (redirects[2] == Redirect.INHERIT) stdHandles[2] = fdAccess.getHandle(FileDescriptor.err); else { - f2 = redirects[2].toFileOutputStream(); + f2 = newFileOutputStream(redirects[2].file(), + redirects[2].append()); stdHandles[2] = fdAccess.getHandle(f2.getFD()); } } @@ -251,5 +284,15 @@ boolean redirectErrorStream) throws IOException; + /** + * Opens a file for atomic append. The file is created if it doesn't + * already exist. + * + * @param file the file to open or create + * @return the native HANDLE + */ + private static native long openForAtomicAppend(String path) + throws IOException; + private static native boolean closeHandle(long handle); }
--- a/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java Mon Dec 13 16:25:26 2010 -0800 @@ -35,6 +35,20 @@ Util.load(); } + /** + * Indicates if the dispatcher should first advance the file position + * to the end of file when writing. + */ + private final boolean append; + + FileDispatcherImpl(boolean append) { + this.append = append; + } + + FileDispatcherImpl() { + this(false); + } + int read(FileDescriptor fd, long address, int len) throws IOException { @@ -54,7 +68,7 @@ } int write(FileDescriptor fd, long address, int len) throws IOException { - return write0(fd, address, len); + return write0(fd, address, len, append); } int pwrite(FileDescriptor fd, long address, int len, @@ -66,7 +80,7 @@ } long writev(FileDescriptor fd, long address, int len) throws IOException { - return writev0(fd, address, len); + return writev0(fd, address, len, append); } int force(FileDescriptor fd, boolean metaData) throws IOException { @@ -116,13 +130,13 @@ static native long readv0(FileDescriptor fd, long address, int len) throws IOException; - static native int write0(FileDescriptor fd, long address, int len) + static native int write0(FileDescriptor fd, long address, int len, boolean append) throws IOException; static native int pwrite0(FileDescriptor fd, long address, int len, long position) throws IOException; - static native long writev0(FileDescriptor fd, long address, int len) + static native long writev0(FileDescriptor fd, long address, int len, boolean append) throws IOException; static native int force0(FileDescriptor fd, boolean metaData)
--- a/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java Mon Dec 13 16:25:26 2010 -0800 @@ -157,7 +157,7 @@ throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed"); FileDescriptor fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor); - return FileChannelImpl.open(fdObj, flags.read, flags.write, null); + return FileChannelImpl.open(fdObj, flags.read, flags.write, flags.append, null); } /** @@ -230,7 +230,7 @@ if (flags.read) dwDesiredAccess |= GENERIC_READ; if (flags.write) - dwDesiredAccess |= (flags.append) ? FILE_APPEND_DATA : GENERIC_WRITE; + dwDesiredAccess |= GENERIC_WRITE; int dwShareMode = 0; if (flags.shareRead)
--- a/src/windows/classes/sun/security/provider/NativeSeedGenerator.java Mon Dec 13 16:22:29 2010 -0800 +++ b/src/windows/classes/sun/security/provider/NativeSeedGenerator.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, 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 @@ -53,6 +53,7 @@ */ private static native boolean nativeGenerateSeed(byte[] result); + @Override void getSeedBytes(byte[] result) { // fill array as a side effect if (nativeGenerateSeed(result) == false) { @@ -62,9 +63,4 @@ } } - byte getSeedByte() { - byte[] b = new byte[1]; - getSeedBytes(b); - return b[0]; - } }
--- a/src/windows/native/java/io/FileOutputStream_md.c Mon Dec 13 16:22:29 2010 -0800 +++ b/src/windows/native/java/io/FileOutputStream_md.c Mon Dec 13 16:25:26 2010 -0800 @@ -61,14 +61,15 @@ } JNIEXPORT void JNICALL -Java_java_io_FileOutputStream_write(JNIEnv *env, jobject this, jint byte) { - writeSingle(env, this, byte, fos_fd); +Java_java_io_FileOutputStream_write(JNIEnv *env, jobject this, jint byte, jboolean append) { + writeSingle(env, this, byte, append, fos_fd); } JNIEXPORT void JNICALL Java_java_io_FileOutputStream_writeBytes(JNIEnv *env, - jobject this, jbyteArray bytes, jint off, jint len) { - writeBytes(env, this, bytes, off, len, fos_fd); + jobject this, jbyteArray bytes, jint off, jint len, jboolean append) +{ + writeBytes(env, this, bytes, off, len, append, fos_fd); } JNIEXPORT void JNICALL
--- a/src/windows/native/java/io/io_util_md.c Mon Dec 13 16:22:29 2010 -0800 +++ b/src/windows/native/java/io/io_util_md.c Mon Dec 13 16:25:26 2010 -0800 @@ -225,14 +225,7 @@ jlong winFileHandleOpen(JNIEnv *env, jstring path, int flags) { - /* To implement O_APPEND, we use the strategy from - http://msdn2.microsoft.com/en-us/library/aa363858.aspx - "You can get atomic append by opening a file with - FILE_APPEND_DATA access and _without_ FILE_WRITE_DATA access. - If you do this then all writes will ignore the current file - pointer and be done at the end-of file." */ const DWORD access = - (flags & O_APPEND) ? (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA) : (flags & O_WRONLY) ? GENERIC_WRITE : (flags & O_RDWR) ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ; @@ -307,7 +300,6 @@ int handleAvailable(jlong fd, jlong *pbytes) { - jlong current, end; HANDLE h = (HANDLE)fd; DWORD type = 0; @@ -327,18 +319,17 @@ } /* Handle is for regular file */ if (type == FILE_TYPE_DISK) { - long highPos = 0; - DWORD sizeLow = 0; - DWORD sizeHigh = 0; - DWORD lowPos = SetFilePointer(h, 0, &highPos, FILE_CURRENT); - if (lowPos == ((DWORD)-1)) { + jlong current, end; + + LARGE_INTEGER filesize; + current = handleLseek(fd, 0, SEEK_CUR); + if (current < 0) { return FALSE; } - current = (((jlong)highPos) << 32) | lowPos; - end = GetFileSize(h, &sizeHigh); - if (sizeLow == ((DWORD)-1)) { + if (GetFileSizeEx(h, &filesize) == 0) { return FALSE; } + end = long_to_jlong(filesize.QuadPart); *pbytes = end - current; return TRUE; } @@ -511,24 +502,42 @@ return read; } -JNIEXPORT -size_t -handleWrite(jlong fd, const void *buf, jint len) +static size_t writeInternal(jlong fd, const void *buf, jint len, jboolean append) { BOOL result = 0; DWORD written = 0; HANDLE h = (HANDLE)fd; if (h != INVALID_HANDLE_VALUE) { - result = WriteFile(h, /* File handle to write */ - buf, /* pointers to the buffers */ - len, /* number of bytes to write */ - &written, /* receives number of bytes written */ - NULL); /* no overlapped struct */ + OVERLAPPED ov; + LPOVERLAPPED lpOv; + if (append == JNI_TRUE) { + ov.Offset = (DWORD)0xFFFFFFFF; + ov.OffsetHigh = (DWORD)0xFFFFFFFF; + ov.hEvent = NULL; + lpOv = &ov; + } else { + lpOv = NULL; + } + result = WriteFile(h, /* File handle to write */ + buf, /* pointers to the buffers */ + len, /* number of bytes to write */ + &written, /* receives number of bytes written */ + lpOv); /* overlapped struct */ } if ((h == INVALID_HANDLE_VALUE) || (result == 0)) { return -1; } - return written; + return (size_t)written; +} + +JNIEXPORT +size_t handleWrite(jlong fd, const void *buf, jint len) { + return writeInternal(fd, buf, len, JNI_FALSE); +} + +JNIEXPORT +size_t handleAppend(jlong fd, const void *buf, jint len) { + return writeInternal(fd, buf, len, JNI_TRUE); } jint @@ -558,6 +567,7 @@ jlong handleLseek(jlong fd, jlong offset, jint whence) { + LARGE_INTEGER pos, distance; DWORD lowPos = 0; long highPos = 0; DWORD op = FILE_CURRENT; @@ -573,13 +583,9 @@ op = FILE_BEGIN; } - lowPos = (DWORD)offset; - highPos = (long)(offset >> 32); - lowPos = SetFilePointer(h, lowPos, &highPos, op); - if (lowPos == ((DWORD)-1)) { - if (GetLastError() != ERROR_SUCCESS) { - return -1; - } + distance.QuadPart = offset; + if (SetFilePointerEx(h, distance, &pos, op) == 0) { + return -1; } - return (((jlong)highPos) << 32) | lowPos; + return long_to_jlong(pos.QuadPart); }
--- a/src/windows/native/java/io/io_util_md.h Mon Dec 13 16:22:29 2010 -0800 +++ b/src/windows/native/java/io/io_util_md.h Mon Dec 13 16:25:26 2010 -0800 @@ -41,6 +41,7 @@ int handleSetLength(jlong fd, jlong length); JNIEXPORT size_t handleRead(jlong fd, void *buf, jint len); JNIEXPORT size_t handleWrite(jlong fd, const void *buf, jint len); +JNIEXPORT size_t handleAppend(jlong fd, const void *buf, jint len); jint handleClose(JNIEnv *env, jobject this, jfieldID fid); jlong handleLseek(jlong fd, jlong offset, jint whence); @@ -74,8 +75,9 @@ #define THIS_FD(obj) (*env)->GetLongField(env, obj, IO_handle_fdID) /* - * Route the routines away from HPI layer + * Route the routines away from VM */ +#define IO_Append handleAppend #define IO_Write handleWrite #define IO_Sync handleSync #define IO_Read handleRead
--- a/src/windows/native/java/lang/ProcessImpl_md.c Mon Dec 13 16:22:29 2010 -0800 +++ b/src/windows/native/java/lang/ProcessImpl_md.c Mon Dec 13 16:25:26 2010 -0800 @@ -315,3 +315,51 @@ { return CloseHandle((HANDLE) handle); } + +/** + * Returns a copy of the Unicode characters of a string. Fow now this + * function doesn't handle long path names and other issues. + */ +static WCHAR* getPath(JNIEnv *env, jstring ps) { + WCHAR *pathbuf = NULL; + const jchar *chars = (*(env))->GetStringChars(env, ps, NULL); + if (chars != NULL) { + size_t pathlen = wcslen(chars); + pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR)); + if (pathbuf == NULL) { + JNU_ThrowOutOfMemoryError(env, NULL); + } else { + wcscpy(pathbuf, chars); + } + (*env)->ReleaseStringChars(env, ps, chars); + } + return pathbuf; +} + +JNIEXPORT jlong JNICALL +Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path) +{ + const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA); + const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; + const DWORD disposition = OPEN_ALWAYS; + const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL; + HANDLE h; + WCHAR *pathbuf = getPath(env, path); + if (pathbuf == NULL) { + /* Exception already pending */ + return -1; + } + h = CreateFileW( + pathbuf, /* Wide char path name */ + access, /* Read and/or write permission */ + sharing, /* File sharing flags */ + NULL, /* Security attributes */ + disposition, /* creation disposition */ + flagsAndAttributes, /* flags and attributes */ + NULL); + free(pathbuf); + if (h == INVALID_HANDLE_VALUE) { + JNU_ThrowIOExceptionWithLastError(env, "CreateFileW"); + } + return ptr_to_jlong(h); +}
--- a/src/windows/native/sun/nio/ch/FileDispatcherImpl.c Mon Dec 13 16:22:29 2010 -0800 +++ b/src/windows/native/sun/nio/ch/FileDispatcherImpl.c Mon Dec 13 16:25:26 2010 -0800 @@ -184,18 +184,28 @@ JNIEXPORT jint JNICALL Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, jobject fdo, - jlong address, jint len) + jlong address, jint len, jboolean append) { BOOL result = 0; DWORD written = 0; HANDLE h = (HANDLE)(handleval(env, fdo)); if (h != INVALID_HANDLE_VALUE) { + OVERLAPPED ov; + LPOVERLAPPED lpOv; + if (append == JNI_TRUE) { + ov.Offset = (DWORD)0xFFFFFFFF; + ov.OffsetHigh = (DWORD)0xFFFFFFFF; + ov.hEvent = NULL; + lpOv = &ov; + } else { + lpOv = NULL; + } result = WriteFile(h, /* File handle to write */ (LPCVOID)address, /* pointers to the buffers */ len, /* number of bytes to write */ &written, /* receives number of bytes written */ - NULL); /* no overlapped struct */ + lpOv); /* overlapped struct */ } if ((h == INVALID_HANDLE_VALUE) || (result == 0)) { @@ -207,7 +217,7 @@ JNIEXPORT jlong JNICALL Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, jobject fdo, - jlong address, jint len) + jlong address, jint len, jboolean append) { BOOL result = 0; DWORD written = 0; @@ -219,7 +229,16 @@ int i = 0; DWORD num = 0; struct iovec *iovecp = (struct iovec *)jlong_to_ptr(address); - + OVERLAPPED ov; + LPOVERLAPPED lpOv; + if (append == JNI_TRUE) { + ov.Offset = (DWORD)0xFFFFFFFF; + ov.OffsetHigh = (DWORD)0xFFFFFFFF; + ov.hEvent = NULL; + lpOv = &ov; + } else { + lpOv = NULL; + } for(i=0; i<len; i++) { loc = (LPVOID)jlong_to_ptr(iovecp[i].iov_base); num = iovecp[i].iov_len; @@ -227,7 +246,7 @@ loc, /* pointers to the buffers */ num, /* number of bytes to write */ &written,/* receives number of bytes written */ - NULL); /* no overlapped struct */ + lpOv); /* overlapped struct */ if (written > 0) { totalWritten += written; } @@ -444,9 +463,10 @@ } JNIEXPORT jlong JNICALL -Java_sun_nio_ch_FileDispatcherImpl_duplicateHandle(JNIEnv *env, jclass this, jlong hFile) +Java_sun_nio_ch_FileDispatcherImpl_duplicateHandle(JNIEnv *env, jclass this, jlong handle) { HANDLE hProcess = GetCurrentProcess(); + HANDLE hFile = jlong_to_ptr(handle); HANDLE hResult; BOOL res = DuplicateHandle(hProcess, hFile, hProcess, &hResult, 0, FALSE, DUPLICATE_SAME_ACCESS);
--- a/test/com/sun/jndi/ldap/InvalidLdapFilters.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/com/sun/jndi/ldap/InvalidLdapFilters.java Mon Dec 13 16:25:26 2010 -0800 @@ -48,6 +48,8 @@ * @run main/othervm InvalidLdapFilters valid (sn;lang-en:dn:2.4.6.8.10:=Barney) * @run main/othervm InvalidLdapFilters valid (&(objectClass=Person)(|(sn=Jensen)(cn=Bab*))) + * @run main/othervm InvalidLdapFilters valid + (orcluserapplnprovstatus;EMAIL_email=PROVISIONING_FAILURE) * @run main/othervm InvalidLdapFilters invalid "(&(cn=Robert Dean)))" * @run main/othervm InvalidLdapFilters invalid (&|(cn=Bob)) * @run main/othervm InvalidLdapFilters invalid (&&(cn=Bob))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/com/sun/net/httpserver/Test10.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2010 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 7005016 + * @summary pit jdk7 b121 sqe test jhttp/HttpServer150013 failing + * @run main/othervm -Dsun.net.httpserver.clockTick=1000 -Dsun.net.httpserver.idleInterval=3 Test10 + */ + +import com.sun.net.httpserver.*; + +import java.io.*; +import java.net.*; +import java.util.concurrent.*; + +/* + * Test handling of empty Http headers + */ + +public class Test10 extends Test { + public static void main (String[] args) throws Exception { + System.out.print ("Test10: "); + Handler handler = new Handler(); + InetSocketAddress addr = new InetSocketAddress (0); + HttpServer server = HttpServer.create (addr, 0); + int port = server.getAddress().getPort(); + HttpContext c2 = server.createContext ("/test", handler); + + ExecutorService exec = Executors.newCachedThreadPool(); + server.setExecutor (exec); + try { + server.start (); + doClient(port); + System.out.println ("OK"); + } finally { + delay(); + if (server != null) + server.stop(2); + if (exec != null) + exec.shutdown(); + } + } + + static class Handler implements HttpHandler { + volatile int invocation = 0; + public void handle (HttpExchange t) + throws IOException + { + InputStream is = t.getRequestBody(); + while (is.read() != -1); + Headers map = t.getRequestHeaders(); + t.sendResponseHeaders (200, -1); + t.close(); + } + } + + public static void doClient (int port) throws Exception { + String s = "GET /test/1.html HTTP/1.1\r\n\r\n"; + + Socket socket = new Socket ("localhost", port); + OutputStream os = socket.getOutputStream(); + os.write (s.getBytes()); + socket.setSoTimeout (10 * 1000); + InputStream is = socket.getInputStream(); + int c; + byte[] b = new byte [1024]; + while ((c=is.read(b)) != -1) ; + is.close(); + socket.close(); + } +}
--- a/test/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java Mon Dec 13 16:25:26 2010 -0800 @@ -188,6 +188,7 @@ } check(found, "SCTP_PRIMARY_ADDR returned bogus address!"); + System.out.println("SCTP_PRIMARY_ADDR try set to: " + addrToSet); sc.setOption(SCTP_PRIMARY_ADDR, addrToSet); System.out.println("SCTP_PRIMARY_ADDR set to: " + addrToSet); primaryAddr = sc.getOption(SCTP_PRIMARY_ADDR);
--- a/test/demo/zipfs/Basic.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/demo/zipfs/Basic.java Mon Dec 13 16:25:26 2010 -0800 @@ -40,24 +40,24 @@ boolean found = false; for (FileSystemProvider provider: FileSystemProvider.installedProviders()) { - if (provider.getScheme().equalsIgnoreCase("zip")) { + if (provider.getScheme().equalsIgnoreCase("jar")) { found = true; break; } } if (!found) - throw new RuntimeException("'zip' provider not installed"); + throw new RuntimeException("'jar' provider not installed"); // Test: FileSystems#newFileSystem(FileRef) Map<String,?> env = new HashMap<String,Object>(); FileSystems.newFileSystem(zipfile, env, null).close(); // Test: FileSystems#newFileSystem(URI) - URI uri = URI.create("zip" + zipfile.toUri().toString().substring(4)); + URI uri = new URI("jar", zipfile.toUri().toString(), null); FileSystem fs = FileSystems.newFileSystem(uri, env, null); // Test: exercise toUri method - String expected = uri.toString() + "#/foo"; + String expected = uri.toString() + "!/foo"; String actual = fs.getPath("/foo").toUri().toString(); if (!actual.equals(expected)) { throw new RuntimeException("toUri returned '" + actual +
--- a/test/demo/zipfs/ZipFSTester.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/demo/zipfs/ZipFSTester.java Mon Dec 13 16:25:26 2010 -0800 @@ -58,7 +58,7 @@ // clone a fs and test on it Path tmpfsPath = getTempPath(); Map<String, Object> env = new HashMap<String, Object>(); - env.put("createNew", true); + env.put("create", "true"); FileSystem fs0 = newZipFileSystem(tmpfsPath, env); z2zcopy(fs, fs0, "/", 0); fs0.close(); // sync to file @@ -147,7 +147,7 @@ // create a new filesystem, copy everything from fs Map<String, Object> env = new HashMap<String, Object>(); - env.put("createNew", true); + env.put("create", "true"); FileSystem fs0 = newZipFileSystem(fs1Path, env); final FileSystem fs2 = newZipFileSystem(fs2Path, env); @@ -282,11 +282,7 @@ private static FileSystem newZipFileSystem(Path path, Map<String, ?> env) throws IOException { - return FileSystems.newFileSystem( - URI.create("zip" + - path.toUri().toString().substring(4)), - env, - null); + return FileSystems.newFileSystem(path, env, null); } private static Path getTempPath() throws IOException
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/io/FileInputStream/LargeFileAvailable.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2010, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6402006 + * @summary Test if available returns correct value when reading + * a large file. + */ + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import static java.nio.file.StandardOpenOption.*; + +public class LargeFileAvailable { + private static final long FILESIZE = 7405576182L; + public static void main(String args[]) throws Exception { + File file = createLargeFile(FILESIZE); + try (FileInputStream fis = new FileInputStream(file)) { + if (file.length() != FILESIZE) { + throw new RuntimeException("unexpected file size = " + file.length()); + } + + long bigSkip = 3110608882L; + long remaining = FILESIZE; + remaining -= skipBytes(fis, bigSkip, remaining); + remaining -= skipBytes(fis, 10L, remaining); + remaining -= skipBytes(fis, bigSkip, remaining); + if (fis.available() != (int) remaining) { + throw new RuntimeException("available() returns " + + fis.available() + + " but expected " + remaining); + } + } finally { + file.delete(); + } + } + + // Skip toSkip number of bytes and expect that the available() method + // returns avail number of bytes. + private static long skipBytes(InputStream is, long toSkip, long avail) + throws IOException { + long skip = is.skip(toSkip); + if (skip != toSkip) { + throw new RuntimeException("skip() returns " + skip + + " but expected " + toSkip); + } + long remaining = avail - skip; + int expected = remaining >= Integer.MAX_VALUE + ? Integer.MAX_VALUE + : (int) remaining; + + System.out.println("Skipped " + skip + " bytes " + + " available() returns " + expected + + " remaining=" + remaining); + if (is.available() != expected) { + throw new RuntimeException("available() returns " + + is.available() + " but expected " + expected); + } + return skip; + } + + private static File createLargeFile(long filesize) throws Exception { + // Create a large file as a sparse file if possible + File largefile = File.createTempFile("largefile", null); + // re-create as a sparse file + largefile.toPath().delete(); + try (FileChannel fc = + FileChannel.open(largefile.toPath(), + CREATE_NEW, WRITE, SPARSE)) { + ByteBuffer bb = ByteBuffer.allocate(1).put((byte)1); + bb.rewind(); + int rc = fc.write(bb, filesize-1); + if (rc != 1) { + throw new RuntimeException("Failed to write 1 byte to the large file"); + } + } + return largefile; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/io/Serializable/cloneArray/CloneArray.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2010, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* @test + * @bug 6990094 + * @summary Verify ObjectInputStream.cloneArray works on many kinds of arrays + * @author Stuart Marks, Joseph D. Darcy + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.Serializable; + +public class CloneArray { + static Object replacement; + + static class Resolver implements Serializable { + private Object readResolve() throws ObjectStreamException { + return replacement; + } + } + + private static void test(Object rep) + throws IOException, ClassNotFoundException { + + try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + try(ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(new Resolver()); + oos.writeObject(new Resolver()); + } + + Object o1; + Object o2; + try(ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bais)) { + replacement = rep; + o1 = ois.readUnshared(); + o2 = ois.readUnshared(); + } + + if (o1 == o2) + throw new AssertionError("o1 and o2 must not be identical"); + } + } + + public static void main(String[] args) + throws IOException, ClassNotFoundException { + Object[] replacements = { + new byte[] {1}, + new char[] {'2'}, + new short[] {3}, + new int[] {4}, + new long[] {5}, + new float[] {6.0f}, + new double[] {7.0}, + new boolean[] {true}, + new Object[] {"A string."} + }; + + for(Object replacement : replacements) { + test(replacement); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/nio/channels/FileChannel/AtomicAppend.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2010, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Check that appends are atomic + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.util.Random; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import static java.nio.file.StandardOpenOption.*; + +public class AtomicAppend { + static final Random rand = new Random(); + + // Open file for appending, returning FileChannel + static FileChannel newFileChannel(File file) throws IOException { + if (rand.nextBoolean()) { + return new FileOutputStream(file, true).getChannel(); + } else { + return FileChannel.open(file.toPath(), APPEND); + } + } + + // Open file for append, returning OutputStream + static OutputStream newOutputStream(File file) throws IOException { + if (rand.nextBoolean()) { + return new FileOutputStream(file, true); + } else { + return file.toPath().newOutputStream(APPEND); + } + } + + // write a byte to the given channel + static void write(FileChannel fc, int b) throws IOException { + ByteBuffer buf = ByteBuffer.allocate(1); + buf.put((byte)b); + buf.flip(); + if (rand.nextBoolean()) { + ByteBuffer[] bufs = new ByteBuffer[1]; + bufs[0] = buf; + fc.write(bufs); + } else { + fc.write(buf); + } + } + + public static void main(String[] args) throws Throwable { + final int nThreads = 16; + final int writes = 1000; + final File file = File.createTempFile("foo", null); + try { + ExecutorService pool = Executors.newFixedThreadPool(nThreads); + for (int i = 0; i < nThreads; i++) + pool.execute(new Runnable() { public void run() { + try { + // randomly choose FileChannel or OutputStream + if (rand.nextBoolean()) { + try (FileChannel fc = newFileChannel(file)) { + for (int j=0; j<writes; j++) write(fc, 'x'); + } + } else { + try (OutputStream out = newOutputStream(file)) { + for (int j = 0; j<writes; j++) out.write('x'); + } + } + } catch (IOException ioe) { + ioe.printStackTrace(); + } + }}); + pool.shutdown(); + pool.awaitTermination(1L, TimeUnit.MINUTES); + if (file.length() != (long) (nThreads * writes)) + throw new RuntimeException("File not expected length"); + } finally { + file.delete(); + } + } +}
--- a/test/java/nio/channels/FileChannel/Lock.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/nio/channels/FileChannel/Lock.java Mon Dec 13 16:25:26 2010 -0800 @@ -22,13 +22,13 @@ */ /* @test - * @bug 4429043 4493595 6332756 + * @bug 4429043 4493595 6332756 6709457 * @summary The FileChannel file locking */ import java.io.*; import java.nio.channels.*; -import java.nio.*; +import static java.nio.file.StandardOpenOption.*; /** * Testing FileChannel's lock method. @@ -55,6 +55,7 @@ test2(blah, true); test2(blah, false); test3(blah); + test4(blah); blah.delete(); } @@ -163,6 +164,24 @@ fc1.close(); fc2.close(); } + + /** + * Test file locking when file is opened for append + */ + static void test4(File blah) throws Exception { + try (FileChannel fc = new FileOutputStream(blah, true).getChannel()) { + fc.tryLock().release(); + fc.tryLock(0L, 1L, false).release(); + fc.lock().release(); + fc.lock(0L, 1L, false).release(); + } + try (FileChannel fc = FileChannel.open(blah.toPath(), APPEND)) { + fc.tryLock().release(); + fc.tryLock(0L, 1L, false).release(); + fc.lock().release(); + fc.lock(0L, 1L, false).release(); + } + } } class MadWriter {
--- a/test/java/nio/channels/FileChannel/Truncate.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/nio/channels/FileChannel/Truncate.java Mon Dec 13 16:25:26 2010 -0800 @@ -22,14 +22,14 @@ */ /* @test - * @bug 6191269 + * @bug 6191269 6709457 * @summary Test truncate method of FileChannel */ import java.io.*; -import java.nio.MappedByteBuffer; -import java.nio.channels.*; +import java.nio.ByteBuffer; import java.nio.channels.FileChannel; +import static java.nio.file.StandardOpenOption.*; import java.util.Random; @@ -38,43 +38,79 @@ */ public class Truncate { - - private static Random generator = new Random(); - - private static File blah; + private static final Random generator = new Random(); public static void main(String[] args) throws Exception { - blah = File.createTempFile("blah", null); + File blah = File.createTempFile("blah", null); blah.deleteOnExit(); + try { + basicTest(blah); + appendTest(blah); + } finally { + blah.delete(); + } + } + + /** + * Basic test of asserts in truncate's specification. + */ + static void basicTest(File blah) throws Exception { for(int i=0; i<100; i++) { long testSize = generator.nextInt(1000) + 10; initTestFile(blah, testSize); - RandomAccessFile fis = new RandomAccessFile(blah, "rw"); - FileChannel c = fis.getChannel(); - if (c.size() != testSize) - throw new RuntimeException("Size failed"); + FileChannel fc = (i < 50) ? + new RandomAccessFile(blah, "rw").getChannel() : + FileChannel.open(blah.toPath(), READ, WRITE); + try (fc) { + if (fc.size() != testSize) + throw new RuntimeException("Size failed"); + + long position = generator.nextInt((int)testSize); + fc.position(position); + + long newSize = generator.nextInt((int)testSize); + fc.truncate(newSize); - long position = generator.nextInt((int)testSize); - c.position(position); + if (fc.size() != newSize) + throw new RuntimeException("Truncate failed"); - long newSize = generator.nextInt((int)testSize); - c.truncate(newSize); + if (position > newSize) { + if (fc.position() != newSize) + throw new RuntimeException("Position greater than size"); + } else { + if (fc.position() != position) + throw new RuntimeException("Truncate changed position"); + }; + } + } + } - if (c.size() != newSize) - throw new RuntimeException("Truncate failed"); + /** + * Test behavior of truncate method when file is opened for append + */ + static void appendTest(File blah) throws Exception { + for (int i=0; i<10; i++) { + long testSize = generator.nextInt(1000) + 10; + initTestFile(blah, testSize); + FileChannel fc = (i < 5) ? + new FileOutputStream(blah, true).getChannel() : + FileChannel.open(blah.toPath(), APPEND); + try (fc) { + // truncate file + long newSize = generator.nextInt((int)testSize); + fc.truncate(newSize); + if (fc.size() != newSize) + throw new RuntimeException("Truncate failed"); - if (position > newSize) { - if (c.position() != newSize) - throw new RuntimeException("Position greater than size"); - } else { - if (c.position() != position) - throw new RuntimeException("Truncate changed position"); + // write one byte + ByteBuffer buf = ByteBuffer.allocate(1); + buf.put((byte)'x'); + buf.flip(); + fc.write(buf); + if (fc.size() != (newSize+1)) + throw new RuntimeException("Unexpected size"); } - - c.close(); - fis.close(); } - blah.delete(); } /**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/security/CodeSigner/Serialize.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 6799854 + * @summary CodeSigner.hashCode() does not work with serialization + */ + +import java.io.*; +import java.security.CodeSigner; +import java.security.Timestamp; +import java.security.cert.*; +import java.util.Collections; +import java.util.Date; + +public class Serialize { + + public static void main(String[] args) throws Exception { + + // Create a certpath consisting of one certificate + File f = new File(System.getProperty("test.src", "."), "cert_file"); + FileInputStream fis = new FileInputStream(f); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + Certificate c = cf.generateCertificate(fis); + fis.close(); + CertPath cp = cf.generateCertPath(Collections.singletonList(c)); + + // Create a code signer + CodeSigner cs = new CodeSigner(cp, new Timestamp(new Date(), cp)); + + // Serialize the code signer + ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(byteOut); + out.writeObject(cs); + out.close(); + + // Deserialize the code signer + byte[] data = byteOut.toByteArray(); + CodeSigner cs2 = (CodeSigner) new ObjectInputStream( + new ByteArrayInputStream(data)).readObject(); + + // Test for equality + if (!cs.equals(cs2) || cs.hashCode() != cs2.hashCode()) { + throw new Exception("CodeSigner serialization test FAILED"); + } + } +}
--- a/test/java/util/concurrent/BlockingQueue/Interrupt.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/BlockingQueue/Interrupt.java Mon Dec 13 16:25:26 2010 -0800 @@ -136,5 +136,5 @@ try {realMain(args);} catch (Throwable t) {unexpected(t);} System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} - private static abstract class Fun {abstract void f() throws Throwable;} + private abstract static class Fun {abstract void f() throws Throwable;} }
--- a/test/java/util/concurrent/BlockingQueue/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/BlockingQueue/LoopHelpers.java Mon Dec 13 16:25:26 2010 -0800 @@ -79,9 +79,9 @@ * Basically same as java.util.Random. */ public static class SimpleRandom { - private final static long multiplier = 0x5DEECE66DL; - private final static long addend = 0xBL; - private final static long mask = (1L << 48) - 1; + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; static final AtomicLong seq = new AtomicLong(1); private long seed = System.nanoTime() + seq.getAndIncrement();
--- a/test/java/util/concurrent/ConcurrentHashMap/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/ConcurrentHashMap/LoopHelpers.java Mon Dec 13 16:25:26 2010 -0800 @@ -79,9 +79,9 @@ * Basically same as java.util.Random. */ public static class SimpleRandom { - private final static long multiplier = 0x5DEECE66DL; - private final static long addend = 0xBL; - private final static long mask = (1L << 48) - 1; + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; static final AtomicLong seq = new AtomicLong(1); private long seed = System.nanoTime() + seq.getAndIncrement();
--- a/test/java/util/concurrent/ConcurrentHashMap/MapCheck.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/ConcurrentHashMap/MapCheck.java Mon Dec 13 16:25:26 2010 -0800 @@ -34,7 +34,7 @@ /* * @test * @bug 4486658 - * @compile MapCheck.java + * @compile -source 1.5 MapCheck.java * @run main/timeout=240 MapCheck * @summary Times and checks basic map operations */ @@ -64,7 +64,7 @@ if (args.length > 0) { try { mapClass = Class.forName(args[0]); - } catch(ClassNotFoundException e) { + } catch (ClassNotFoundException e) { throw new RuntimeException("Class " + args[0] + " not found."); } } @@ -102,7 +102,7 @@ try { Map m = (Map)cl.newInstance(); return m; - } catch(Exception e) { + } catch (Exception e) { throw new RuntimeException("Can't instantiate " + cl + ": " + e); } } @@ -139,7 +139,7 @@ } } timer.finish(); - reallyAssert (sum == expect * iters); + reallyAssert(sum == expect * iters); } static void t2(String nm, int n, Map s, Object[] key, int expect) { @@ -149,7 +149,7 @@ if (s.remove(key[i]) != null) ++sum; } timer.finish(); - reallyAssert (sum == expect); + reallyAssert(sum == expect); } static void t3(String nm, int n, Map s, Object[] key, int expect) { @@ -159,7 +159,7 @@ if (s.put(key[i], absent[i & absentMask]) == null) ++sum; } timer.finish(); - reallyAssert (sum == expect); + reallyAssert(sum == expect); } static void t4(String nm, int n, Map s, Object[] key, int expect) { @@ -169,7 +169,7 @@ if (s.containsKey(key[i])) ++sum; } timer.finish(); - reallyAssert (sum == expect); + reallyAssert(sum == expect); } static void t5(String nm, int n, Map s, Object[] key, int expect) { @@ -179,7 +179,7 @@ if (s.remove(key[i]) != null) ++sum; } timer.finish(); - reallyAssert (sum == expect); + reallyAssert(sum == expect); } static void t6(String nm, int n, Map s, Object[] k1, Object[] k2) { @@ -190,7 +190,7 @@ if (s.get(k2[i & absentMask]) != null) ++sum; } timer.finish(); - reallyAssert (sum == n); + reallyAssert(sum == n); } static void t7(String nm, int n, Map s, Object[] k1, Object[] k2) { @@ -201,7 +201,7 @@ if (s.containsKey(k2[i & absentMask])) ++sum; } timer.finish(); - reallyAssert (sum == n); + reallyAssert(sum == n); } static void t8(String nm, int n, Map s, Object[] key, int expect) { @@ -211,7 +211,7 @@ if (s.get(key[i]) != null) ++sum; } timer.finish(); - reallyAssert (sum == expect); + reallyAssert(sum == expect); } @@ -223,7 +223,7 @@ for (int i = 0; i < absentSize; i += step) if (s.containsValue(absent[i])) ++sum; timer.finish(); - reallyAssert (sum != 0); + reallyAssert(sum != 0); } @@ -235,7 +235,7 @@ if (ks.contains(key[i])) ++sum; } timer.finish(); - reallyAssert (sum == size); + reallyAssert(sum == size); } @@ -243,37 +243,37 @@ int sum = 0; timer.start("Iter Key ", size); for (Iterator it = s.keySet().iterator(); it.hasNext(); ) { - if(it.next() != MISSING) + if (it.next() != MISSING) ++sum; } timer.finish(); - reallyAssert (sum == size); + reallyAssert(sum == size); } static void ittest2(Map s, int size) { int sum = 0; timer.start("Iter Value ", size); for (Iterator it = s.values().iterator(); it.hasNext(); ) { - if(it.next() != MISSING) + if (it.next() != MISSING) ++sum; } timer.finish(); - reallyAssert (sum == size); + reallyAssert(sum == size); } static void ittest3(Map s, int size) { int sum = 0; timer.start("Iter Entry ", size); for (Iterator it = s.entrySet().iterator(); it.hasNext(); ) { - if(it.next() != MISSING) + if (it.next() != MISSING) ++sum; } timer.finish(); - reallyAssert (sum == size); + reallyAssert(sum == size); } static void ittest4(Map s, int size, int pos) { IdentityHashMap seen = new IdentityHashMap(size); - reallyAssert (s.size() == size); + reallyAssert(s.size() == size); int sum = 0; timer.start("Iter XEntry ", size); Iterator it = s.entrySet().iterator(); @@ -287,9 +287,9 @@ if (x != MISSING) ++sum; } - reallyAssert (s.containsKey(k)); + reallyAssert(s.containsKey(k)); it.remove(); - reallyAssert (!s.containsKey(k)); + reallyAssert(!s.containsKey(k)); while (it.hasNext()) { Map.Entry x = (Map.Entry)(it.next()); Object k2 = x.getKey(); @@ -298,12 +298,12 @@ ++sum; } - reallyAssert (s.size() == size-1); + reallyAssert(s.size() == size-1); s.put(k, v); - reallyAssert (seen.size() == size); + reallyAssert(seen.size() == size); timer.finish(); - reallyAssert (sum == size); - reallyAssert (s.size() == size); + reallyAssert(sum == size); + reallyAssert(s.size() == size); } @@ -324,7 +324,7 @@ ++sum; } timer.finish(); - reallyAssert (sum == size); + reallyAssert(sum == size); } static void entest2(Hashtable ht, int size) { @@ -335,7 +335,7 @@ ++sum; } timer.finish(); - reallyAssert (sum == size); + reallyAssert(sum == size); } @@ -349,7 +349,7 @@ ++sum; } timer.finish(); - reallyAssert (sum == size); + reallyAssert(sum == size); } static void entest4(Hashtable ht, int size) { @@ -361,7 +361,7 @@ ++sum; } timer.finish(); - reallyAssert (sum == size); + reallyAssert(sum == size); } static void entest(Map s, int size) { @@ -409,13 +409,13 @@ timer.start("Iter Equals ", size * 2); boolean eqt = s2.equals(s) && s.equals(s2); - reallyAssert (eqt); + reallyAssert(eqt); timer.finish(); timer.start("Iter HashCode ", size * 2); int shc = s.hashCode(); int s2hc = s2.hashCode(); - reallyAssert (shc == s2hc); + reallyAssert(shc == s2hc); timer.finish(); timer.start("Put (present) ", size); @@ -430,7 +430,7 @@ if (es2.contains(entry)) ++sum; } timer.finish(); - reallyAssert (sum == size); + reallyAssert(sum == size); t6("Get ", size, s2, key, absent); @@ -438,13 +438,13 @@ s2.put(key[size-1], absent[0]); timer.start("Iter Equals ", size * 2); eqt = s2.equals(s) && s.equals(s2); - reallyAssert (!eqt); + reallyAssert(!eqt); timer.finish(); timer.start("Iter HashCode ", size * 2); int s1h = s.hashCode(); int s2h = s2.hashCode(); - reallyAssert (s1h != s2h); + reallyAssert(s1h != s2h); timer.finish(); s2.put(key[size-1], hold); @@ -455,12 +455,12 @@ es.remove(s2i.next()); timer.finish(); - reallyAssert (s.isEmpty()); + reallyAssert(s.isEmpty()); timer.start("Clear ", size); s2.clear(); timer.finish(); - reallyAssert (s2.isEmpty() && s.isEmpty()); + reallyAssert(s2.isEmpty() && s.isEmpty()); } static void stest(Map s, int size) throws Exception { @@ -489,7 +489,7 @@ System.out.print(time + "ms"); if (s instanceof IdentityHashMap) return; - reallyAssert (s.equals(m)); + reallyAssert(s.equals(m)); }
--- a/test/java/util/concurrent/ConcurrentHashMap/MapLoops.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/ConcurrentHashMap/MapLoops.java Mon Dec 13 16:25:26 2010 -0800 @@ -34,7 +34,7 @@ /* * @test * @bug 4486658 - * @compile MapLoops.java + * @compile -source 1.5 MapLoops.java * @run main/timeout=1600 MapLoops * @summary Exercise multithreaded maps, by default ConcurrentHashMap. * Multithreaded hash table test. Each thread does a random walk @@ -225,7 +225,7 @@ barrier.await(); } catch (Throwable throwable) { - synchronized(System.err) { + synchronized (System.err) { System.err.println("--------------------------------"); throwable.printStackTrace(); }
--- a/test/java/util/concurrent/ConcurrentQueues/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/ConcurrentQueues/LoopHelpers.java Mon Dec 13 16:25:26 2010 -0800 @@ -79,9 +79,9 @@ * Basically same as java.util.Random. */ public static class SimpleRandom { - private final static long multiplier = 0x5DEECE66DL; - private final static long addend = 0xBL; - private final static long mask = (1L << 48) - 1; + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; static final AtomicLong seq = new AtomicLong(1); private long seed = System.nanoTime() + seq.getAndIncrement();
--- a/test/java/util/concurrent/CopyOnWriteArrayList/EqualsRace.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/CopyOnWriteArrayList/EqualsRace.java Mon Dec 13 16:25:26 2010 -0800 @@ -66,7 +66,7 @@ try {realMain(args);} catch (Throwable t) {unexpected(t);} System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} - private static abstract class CheckedThread extends Thread { + private abstract static class CheckedThread extends Thread { public abstract void realRun() throws Throwable; public void run() { try { realRun(); } catch (Throwable t) { unexpected(t); }}}
--- a/test/java/util/concurrent/CopyOnWriteArraySet/RacingCows.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/CopyOnWriteArraySet/RacingCows.java Mon Dec 13 16:25:26 2010 -0800 @@ -125,7 +125,7 @@ try {realMain(args);} catch (Throwable t) {unexpected(t);} System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} - private static abstract class CheckedThread extends Thread { + private abstract static class CheckedThread extends Thread { public abstract void realRun() throws Throwable; public void run() { try { realRun(); } catch (Throwable t) { unexpected(t); }}}
--- a/test/java/util/concurrent/CyclicBarrier/Basic.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/CyclicBarrier/Basic.java Mon Dec 13 16:25:26 2010 -0800 @@ -83,7 +83,7 @@ //---------------------------------------------------------------- // Convenience methods for creating threads that call CyclicBarrier.await //---------------------------------------------------------------- - private static abstract class Awaiter extends Thread { + private abstract static class Awaiter extends Thread { static AtomicInteger count = new AtomicInteger(1); { @@ -417,14 +417,14 @@ try {realMain(args);} catch (Throwable t) {unexpected(t);} System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} - static abstract class Fun { abstract void f() throws Throwable; } + abstract static class Fun { abstract void f() throws Throwable; } private static void THROWS(Class<? extends Throwable> k, Fun... fs) { for (Fun f : fs) try { f.f(); fail("Expected " + k.getName() + " not thrown"); } catch (Throwable t) { if (k.isAssignableFrom(t.getClass())) pass(); else unexpected(t);}} - private static abstract class CheckedThread extends Thread { + private abstract static class CheckedThread extends Thread { abstract void realRun() throws Throwable; public void run() { try {realRun();} catch (Throwable t) {unexpected(t);}}}
--- a/test/java/util/concurrent/Exchanger/ExchangeLoops.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/Exchanger/ExchangeLoops.java Mon Dec 13 16:25:26 2010 -0800 @@ -34,7 +34,7 @@ /* * @test * @bug 4486658 - * @compile ExchangeLoops.java + * @compile -source 1.5 ExchangeLoops.java * @run main/timeout=720 ExchangeLoops * @summary checks to make sure a pipeline of exchangers passes data. */ @@ -78,9 +78,9 @@ final Exchanger<Int> right; final CyclicBarrier barrier; volatile int result; - Stage (Exchanger<Int> left, - Exchanger<Int> right, - CyclicBarrier b, int iters) { + Stage(Exchanger<Int> left, + Exchanger<Int> right, + CyclicBarrier b, int iters) { this.left = left; this.right = right; barrier = b;
--- a/test/java/util/concurrent/Exchanger/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/Exchanger/LoopHelpers.java Mon Dec 13 16:25:26 2010 -0800 @@ -78,9 +78,9 @@ * Basically same as java.util.Random. */ public static class SimpleRandom { - private final static long multiplier = 0x5DEECE66DL; - private final static long addend = 0xBL; - private final static long mask = (1L << 48) - 1; + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; static final AtomicLong seq = new AtomicLong(1); private long seed = System.nanoTime() + seq.getAndIncrement();
--- a/test/java/util/concurrent/ExecutorCompletionService/ExecutorCompletionServiceLoops.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/ExecutorCompletionService/ExecutorCompletionServiceLoops.java Mon Dec 13 16:25:26 2010 -0800 @@ -34,7 +34,7 @@ /* * @test * @bug 4965960 - * @compile ExecutorCompletionServiceLoops.java + * @compile -source 1.5 ExecutorCompletionServiceLoops.java * @run main/timeout=3600 ExecutorCompletionServiceLoops * @summary Exercise ExecutorCompletionServiceLoops */
--- a/test/java/util/concurrent/ExecutorCompletionService/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/ExecutorCompletionService/LoopHelpers.java Mon Dec 13 16:25:26 2010 -0800 @@ -78,9 +78,9 @@ * Basically same as java.util.Random. */ public static class SimpleRandom { - private final static long multiplier = 0x5DEECE66DL; - private final static long addend = 0xBL; - private final static long mask = (1L << 48) - 1; + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; static final AtomicLong seq = new AtomicLong(1); private long seed = System.nanoTime() + seq.getAndIncrement();
--- a/test/java/util/concurrent/Executors/Throws.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/Executors/Throws.java Mon Dec 13 16:25:26 2010 -0800 @@ -122,7 +122,7 @@ try {realMain(args);} catch (Throwable t) {unexpected(t);} System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} - private static abstract class Fun {abstract void f() throws Throwable;} + private abstract static class Fun {abstract void f() throws Throwable;} static void THROWS(Class<? extends Throwable> k, Fun... fs) { for (Fun f : fs) try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
--- a/test/java/util/concurrent/FutureTask/BlockingTaskExecutor.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/FutureTask/BlockingTaskExecutor.java Mon Dec 13 16:25:26 2010 -0800 @@ -87,7 +87,7 @@ * A helper class with a method to wait for a notification. * * The notification is received via the - * <code>sendNotification</code> method. + * {@code sendNotification} method. */ static class NotificationReceiver { /** Has the notifiee been notified? */
--- a/test/java/util/concurrent/FutureTask/CancelledFutureLoops.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/FutureTask/CancelledFutureLoops.java Mon Dec 13 16:25:26 2010 -0800 @@ -34,7 +34,7 @@ /* * @test * @bug 4486658 - * @compile CancelledFutureLoops.java + * @compile -source 1.5 CancelledFutureLoops.java * @run main/timeout=2000 CancelledFutureLoops * @summary Checks for responsiveness of futures to cancellation. * Runs under the assumption that ITERS computations require more than @@ -64,10 +64,10 @@ try { new FutureLoop(i).test(); } - catch(BrokenBarrierException bb) { + catch (BrokenBarrierException bb) { // OK; ignore } - catch(ExecutionException ee) { + catch (ExecutionException ee) { // OK; ignore } Thread.sleep(TIMEOUT);
--- a/test/java/util/concurrent/FutureTask/Customized.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/FutureTask/Customized.java Mon Dec 13 16:25:26 2010 -0800 @@ -203,7 +203,7 @@ try {realMain(args);} catch (Throwable t) {unexpected(t);} System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} - private static abstract class Fun {abstract void f() throws Throwable;} + private abstract static class Fun {abstract void f() throws Throwable;} static void THROWS(Class<? extends Throwable> k, Fun... fs) { for (Fun f : fs) try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
--- a/test/java/util/concurrent/FutureTask/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/FutureTask/LoopHelpers.java Mon Dec 13 16:25:26 2010 -0800 @@ -78,9 +78,9 @@ * Basically same as java.util.Random. */ public static class SimpleRandom { - private final static long multiplier = 0x5DEECE66DL; - private final static long addend = 0xBL; - private final static long mask = (1L << 48) - 1; + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; static final AtomicLong seq = new AtomicLong(1); private long seed = System.nanoTime() + seq.getAndIncrement();
--- a/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java Mon Dec 13 16:25:26 2010 -0800 @@ -161,11 +161,8 @@ if (x == null ? y == null : x.equals(y)) pass(); else fail(x + " not equal to " + y);} public static void main(String[] args) throws Throwable { - Class<?> k = new Object(){}.getClass().getEnclosingClass(); - try {k.getMethod("instanceMain",String[].class) - .invoke( k.newInstance(), (Object) args);} - catch (Throwable e) {throw e.getCause();}} - public void instanceMain(String[] args) throws Throwable { + new DelayOverflow().instanceMain(args);} + void instanceMain(String[] args) throws Throwable { try {test(args);} catch (Throwable t) {unexpected(t);} System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");}
--- a/test/java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java Mon Dec 13 16:25:26 2010 -0800 @@ -36,9 +36,9 @@ import static java.util.concurrent.TimeUnit.*; public class ConfigChanges { - final static ThreadGroup tg = new ThreadGroup("pool"); + static final ThreadGroup tg = new ThreadGroup("pool"); - final static Random rnd = new Random(); + static final Random rnd = new Random(); static void report(ThreadPoolExecutor tpe) { try { @@ -241,7 +241,7 @@ try {realMain(args);} catch (Throwable t) {unexpected(t);} System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} - private static abstract class Fun {abstract void f() throws Throwable;} + private abstract static class Fun {abstract void f() throws Throwable;} static void THROWS(Class<? extends Throwable> k, Fun... fs) { for (Fun f : fs) try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
--- a/test/java/util/concurrent/ThreadPoolExecutor/Custom.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/ThreadPoolExecutor/Custom.java Mon Dec 13 16:25:26 2010 -0800 @@ -43,7 +43,7 @@ private static class CustomTask<V> extends FutureTask<V> { - public final static AtomicInteger births = new AtomicInteger(0); + public static final AtomicInteger births = new AtomicInteger(0); CustomTask(Callable<V> c) { super(c); births.getAndIncrement(); } CustomTask(Runnable r, V v) { super(r, v); births.getAndIncrement(); } } @@ -63,7 +63,7 @@ } private static class CustomSTPE extends ScheduledThreadPoolExecutor { - public final static AtomicInteger decorations = new AtomicInteger(0); + public static final AtomicInteger decorations = new AtomicInteger(0); CustomSTPE() { super(threadCount); } @@ -89,7 +89,7 @@ return count; } - private final static int threadCount = 10; + private static final int threadCount = 10; public static void main(String[] args) throws Throwable { CustomTPE tpe = new CustomTPE();
--- a/test/java/util/concurrent/ThreadPoolExecutor/ScheduledTickleService.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/ThreadPoolExecutor/ScheduledTickleService.java Mon Dec 13 16:25:26 2010 -0800 @@ -37,10 +37,10 @@ // We get intermittent ClassCastException if greater than 1 // because of calls to compareTo - private final static int concurrency = 2; + private static final int concurrency = 2; // Record when tasks are done - public final static CountDownLatch done = new CountDownLatch(concurrency); + public static final CountDownLatch done = new CountDownLatch(concurrency); public static void realMain(String... args) throws InterruptedException { // our tickle service
--- a/test/java/util/concurrent/ThreadPoolExecutor/ShutdownNowExecuteRace.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/ThreadPoolExecutor/ShutdownNowExecuteRace.java Mon Dec 13 16:25:26 2010 -0800 @@ -40,7 +40,7 @@ static volatile boolean quit = false; static volatile ThreadPoolExecutor pool = null; - final static Runnable sleeper = new Runnable() { public void run() { + static final Runnable sleeper = new Runnable() { public void run() { final long ONE_HOUR = 1000L * 60L * 60L; try { Thread.sleep(ONE_HOUR); } catch (InterruptedException ie) {} @@ -81,14 +81,14 @@ try {realMain(args);} catch (Throwable t) {unexpected(t);} System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} - private static abstract class Fun {abstract void f() throws Throwable;} + private abstract static class Fun {abstract void f() throws Throwable;} static void THROWS(Class<? extends Throwable> k, Fun... fs) { for (Fun f : fs) try { f.f(); fail("Expected " + k.getName() + " not thrown"); } catch (Throwable t) { if (k.isAssignableFrom(t.getClass())) pass(); else unexpected(t);}} - private static abstract class CheckedThread extends Thread { + private abstract static class CheckedThread extends Thread { abstract void realRun() throws Throwable; public void run() { try {realRun();} catch (Throwable t) {unexpected(t);}}}
--- a/test/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java Mon Dec 13 16:25:26 2010 -0800 @@ -35,7 +35,7 @@ import java.util.concurrent.atomic.*; public class ThrowingTasks { - final static Random rnd = new Random(); + static final Random rnd = new Random(); @SuppressWarnings("serial") static class UncaughtExceptions @@ -65,16 +65,16 @@ } } - final static UncaughtExceptions uncaughtExceptions + static final UncaughtExceptions uncaughtExceptions = new UncaughtExceptions(); - final static UncaughtExceptionsTable uncaughtExceptionsTable + static final UncaughtExceptionsTable uncaughtExceptionsTable = new UncaughtExceptionsTable(); - final static AtomicLong totalUncaughtExceptions + static final AtomicLong totalUncaughtExceptions = new AtomicLong(0); - final static CountDownLatch uncaughtExceptionsLatch + static final CountDownLatch uncaughtExceptionsLatch = new CountDownLatch(24); - final static Thread.UncaughtExceptionHandler handler + static final Thread.UncaughtExceptionHandler handler = new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread t, Throwable e) { check(! Thread.currentThread().isInterrupted()); @@ -84,19 +84,19 @@ uncaughtExceptionsLatch.countDown(); }}; - final static ThreadGroup tg = new ThreadGroup("Flaky"); + static final ThreadGroup tg = new ThreadGroup("Flaky"); - final static ThreadFactory tf = new ThreadFactory() { + static final ThreadFactory tf = new ThreadFactory() { public Thread newThread(Runnable r) { Thread t = new Thread(tg, r); t.setUncaughtExceptionHandler(handler); return t; }}; - final static RuntimeException rte = new RuntimeException(); - final static Error error = new Error(); - final static Throwable weird = new Throwable(); - final static Exception checkedException = new Exception(); + static final RuntimeException rte = new RuntimeException(); + static final Error error = new Error(); + static final Throwable weird = new Throwable(); + static final Exception checkedException = new Exception(); static class Thrower implements Runnable { Throwable t; @@ -105,13 +105,13 @@ public void run() { if (t != null) Thread.currentThread().stop(t); } } - final static Thrower noThrower = new Thrower(null); - final static Thrower rteThrower = new Thrower(rte); - final static Thrower errorThrower = new Thrower(error); - final static Thrower weirdThrower = new Thrower(weird); - final static Thrower checkedThrower = new Thrower(checkedException); + static final Thrower noThrower = new Thrower(null); + static final Thrower rteThrower = new Thrower(rte); + static final Thrower errorThrower = new Thrower(error); + static final Thrower weirdThrower = new Thrower(weird); + static final Thrower checkedThrower = new Thrower(checkedException); - final static List<Thrower> throwers = Arrays.asList( + static final List<Thrower> throwers = Arrays.asList( noThrower, rteThrower, errorThrower, weirdThrower, checkedThrower); static class Flaky implements Runnable {
--- a/test/java/util/concurrent/atomic/VMSupportsCS8.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/atomic/VMSupportsCS8.java Mon Dec 13 16:25:26 2010 -0800 @@ -24,6 +24,8 @@ /* * @test * @bug 4992443 4994819 + * @compile -source 1.5 VMSupportsCS8.java + * @run main VMSupportsCS8 * @summary Checks that the value of VMSupportsCS8 matches system properties. */
--- a/test/java/util/concurrent/locks/Lock/FlakyMutex.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/locks/Lock/FlakyMutex.java Mon Dec 13 16:25:26 2010 -0800 @@ -75,10 +75,10 @@ catch (Throwable t) { checkThrowable(t); } } - try { check (! m.tryLock()); } + try { check(! m.tryLock()); } catch (Throwable t) { checkThrowable(t); } - try { check (! m.tryLock(1, TimeUnit.MICROSECONDS)); } + try { check(! m.tryLock(1, TimeUnit.MICROSECONDS)); } catch (Throwable t) { checkThrowable(t); } m.unlock();
--- a/test/java/util/concurrent/locks/Lock/TimedAcquireLeak.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/locks/Lock/TimedAcquireLeak.java Mon Dec 13 16:25:26 2010 -0800 @@ -64,7 +64,7 @@ return outputOf(new InputStreamReader(is, "UTF-8")); } - final static ExecutorService drainers = Executors.newFixedThreadPool(12); + static final ExecutorService drainers = Executors.newFixedThreadPool(12); static Future<String> futureOutputOf(final InputStream is) { return drainers.submit( new Callable<String>() { public String call() throws IOException {
--- a/test/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java Mon Dec 13 16:25:26 2010 -0800 @@ -34,7 +34,7 @@ /* * @test * @bug 4486658 - * @compile CancelledLockLoops.java + * @compile -source 1.5 CancelledLockLoops.java * @run main/timeout=2800 CancelledLockLoops * @summary tests lockInterruptibly. * Checks for responsiveness of locks to interrupts. Runs under that @@ -64,7 +64,7 @@ try { new ReentrantLockLoop(i).test(); } - catch(BrokenBarrierException bb) { + catch (BrokenBarrierException bb) { // OK, ignore } Thread.sleep(TIMEOUT);
--- a/test/java/util/concurrent/locks/ReentrantLock/LockOncePerThreadLoops.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/locks/ReentrantLock/LockOncePerThreadLoops.java Mon Dec 13 16:25:26 2010 -0800 @@ -34,7 +34,7 @@ /* * @test * @bug 4486658 - * @compile LockOncePerThreadLoops.java + * @compile -source 1.5 LockOncePerThreadLoops.java * @run main/timeout=15000 LockOncePerThreadLoops * @summary Checks for missed signals by locking and unlocking each of an array of locks once per thread */
--- a/test/java/util/concurrent/locks/ReentrantLock/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/locks/ReentrantLock/LoopHelpers.java Mon Dec 13 16:25:26 2010 -0800 @@ -78,9 +78,9 @@ * Basically same as java.util.Random. */ public static class SimpleRandom { - private final static long multiplier = 0x5DEECE66DL; - private final static long addend = 0xBL; - private final static long mask = (1L << 48) - 1; + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; static final AtomicLong seq = new AtomicLong(1); private long seed = System.nanoTime() + seq.getAndIncrement();
--- a/test/java/util/concurrent/locks/ReentrantLock/SimpleReentrantLockLoops.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/locks/ReentrantLock/SimpleReentrantLockLoops.java Mon Dec 13 16:25:26 2010 -0800 @@ -34,7 +34,7 @@ /* * @test * @bug 4486658 - * @compile SimpleReentrantLockLoops.java + * @compile -source 1.5 SimpleReentrantLockLoops.java * @run main/timeout=4500 SimpleReentrantLockLoops * @summary multiple threads using a single lock */
--- a/test/java/util/concurrent/locks/ReentrantLock/TimeoutLockLoops.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/locks/ReentrantLock/TimeoutLockLoops.java Mon Dec 13 16:25:26 2010 -0800 @@ -34,6 +34,8 @@ /* * @test * @bug 4486658 5031862 + * @compile -source 1.5 TimeoutLockLoops.java + * @run main TimeoutLockLoops * @summary Checks for responsiveness of locks to timeouts. * Runs under the assumption that ITERS computations require more than * TIMEOUT msecs to complete, which seems to be a safe assumption for
--- a/test/java/util/concurrent/locks/ReentrantReadWriteLock/Bug6571733.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/locks/ReentrantReadWriteLock/Bug6571733.java Mon Dec 13 16:25:26 2010 -0800 @@ -45,7 +45,7 @@ Thread thread = new Thread() { public void run() { try { - check (! lock.writeLock().tryLock(0, TimeUnit.DAYS)); + check(! lock.writeLock().tryLock(0, TimeUnit.DAYS)); lock.readLock().lock(); lock.readLock().unlock();
--- a/test/java/util/concurrent/locks/ReentrantReadWriteLock/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/locks/ReentrantReadWriteLock/LoopHelpers.java Mon Dec 13 16:25:26 2010 -0800 @@ -78,9 +78,9 @@ * Basically same as java.util.Random. */ public static class SimpleRandom { - private final static long multiplier = 0x5DEECE66DL; - private final static long addend = 0xBL; - private final static long mask = (1L << 48) - 1; + private static final long multiplier = 0x5DEECE66DL; + private static final long addend = 0xBL; + private static final long mask = (1L << 48) - 1; static final AtomicLong seq = new AtomicLong(1); private long seed = System.nanoTime() + seq.getAndIncrement();
--- a/test/java/util/concurrent/locks/ReentrantReadWriteLock/MapLoops.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/locks/ReentrantReadWriteLock/MapLoops.java Mon Dec 13 16:25:26 2010 -0800 @@ -34,7 +34,7 @@ /* * @test * @bug 4486658 - * @compile MapLoops.java + * @compile -source 1.5 MapLoops.java * @run main/timeout=4700 MapLoops * @summary Exercise multithreaded maps, by default ConcurrentHashMap. * Multithreaded hash table test. Each thread does a random walk @@ -65,7 +65,7 @@ if (args.length > 0) { try { mapClass = Class.forName(args[0]); - } catch(ClassNotFoundException e) { + } catch (ClassNotFoundException e) { throw new RuntimeException("Class " + args[0] + " not found."); } }
--- a/test/java/util/concurrent/locks/ReentrantReadWriteLock/RWMap.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/java/util/concurrent/locks/ReentrantReadWriteLock/RWMap.java Mon Dec 13 16:25:26 2010 -0800 @@ -57,21 +57,33 @@ } public int size() { - rwl.readLock().lock(); try {return m.size();} finally { rwl.readLock().unlock(); } + rwl.readLock().lock(); + try { return m.size(); } + finally { rwl.readLock().unlock(); } } - public boolean isEmpty(){ - rwl.readLock().lock(); try {return m.isEmpty();} finally { rwl.readLock().unlock(); } + + public boolean isEmpty() { + rwl.readLock().lock(); + try { return m.isEmpty(); } + finally { rwl.readLock().unlock(); } } public Object get(Object key) { - rwl.readLock().lock(); try {return m.get(key);} finally { rwl.readLock().unlock(); } + rwl.readLock().lock(); + try { return m.get(key); } + finally { rwl.readLock().unlock(); } } public boolean containsKey(Object key) { - rwl.readLock().lock(); try {return m.containsKey(key);} finally { rwl.readLock().unlock(); } + rwl.readLock().lock(); + try { return m.containsKey(key); } + finally { rwl.readLock().unlock(); } } - public boolean containsValue(Object value){ - rwl.readLock().lock(); try {return m.containsValue(value);} finally { rwl.readLock().unlock(); } + + public boolean containsValue(Object value) { + rwl.readLock().lock(); + try { return m.containsValue(value); } + finally { rwl.readLock().unlock(); } } @@ -88,28 +100,45 @@ } public boolean equals(Object o) { - rwl.readLock().lock(); try {return m.equals(o);} finally { rwl.readLock().unlock(); } + rwl.readLock().lock(); + try { return m.equals(o); } + finally { rwl.readLock().unlock(); } } + public int hashCode() { - rwl.readLock().lock(); try {return m.hashCode();} finally { rwl.readLock().unlock(); } + rwl.readLock().lock(); + try { return m.hashCode(); } + finally { rwl.readLock().unlock(); } } + public String toString() { - rwl.readLock().lock(); try {return m.toString();} finally { rwl.readLock().unlock(); } + rwl.readLock().lock(); + try { return m.toString(); } + finally { rwl.readLock().unlock(); } } - + public Object put(Object key, Object value) { + rwl.writeLock().lock(); + try { return m.put(key, value); } + finally { rwl.writeLock().unlock(); } + } - public Object put(Object key, Object value) { - rwl.writeLock().lock(); try {return m.put(key, value);} finally { rwl.writeLock().unlock(); } - } public Object remove(Object key) { - rwl.writeLock().lock(); try {return m.remove(key);} finally { rwl.writeLock().unlock(); } + rwl.writeLock().lock(); + try { return m.remove(key); } + finally { rwl.writeLock().unlock(); } } + public void putAll(Map map) { - rwl.writeLock().lock(); try {m.putAll(map);} finally { rwl.writeLock().unlock(); } + rwl.writeLock().lock(); + try { m.putAll(map); } + finally { rwl.writeLock().unlock(); } } + public void clear() { - rwl.writeLock().lock(); try {m.clear();} finally { rwl.writeLock().unlock(); } + rwl.writeLock().lock(); + try { m.clear(); } + finally { rwl.writeLock().unlock(); } } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/zip/ZipFile/FinalizeInflater.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2010, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 7003462 + @summary Make sure cached Inflater does not get finalized. + */ + +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +public class FinalizeInflater { + + public static void main(String[] args) throws Throwable { + try (ZipFile zf = new ZipFile(new File(System.getProperty("test.src", "."), "input.zip"))) + { + ZipEntry ze = zf.getEntry("ReadZip.java"); + read(zf.getInputStream(ze)); + System.gc(); + System.runFinalization(); + System.gc(); + // read again + read(zf.getInputStream(ze)); + } + } + + private static void read(InputStream is) + throws IOException + { + Wrapper wrapper = new Wrapper(is); + byte[] buffer = new byte[32]; + try { + while(is.read(buffer)>0){} + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } + + static class Wrapper{ + InputStream is; + public Wrapper(InputStream is) { + this.is = is; + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + is.close(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/nio/cs/EncodingNothing.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6415373 + * @summary Encoding nothing should output nothing + */ + +import java.io.*; +import java.nio.charset.*; + +public class EncodingNothing { + + public static void main(String[] args) throws Throwable { + int failed = 0; + for (Charset cs : Charset.availableCharsets().values()) { + if (! cs.canEncode()) + continue; + System.out.printf("%s: ", cs.name()); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStreamWriter osw = new OutputStreamWriter(baos, cs); + osw.close(); + if (baos.size() != 0) { + System.out.printf(" Failed: output bytes=%d", baos.size()); + failed++; + } + System.out.println(); + } + if (failed != 0) + throw new AssertionError("Some tests failed"); + } +}
--- a/test/sun/security/krb5/tools/ktarg.sh Mon Dec 13 16:22:29 2010 -0800 +++ b/test/sun/security/krb5/tools/ktarg.sh Mon Dec 13 16:25:26 2010 -0800 @@ -56,7 +56,7 @@ rm $KEYTAB 2> /dev/null KTAB="${TESTJAVA}${FS}bin${FS}ktab -k $KEYTAB" -$KTAB -a me mine || exit 1 +$KTAB -a me@LOCAL mine || exit 1 $KTAB -hello if [ $? = 0 ]; then exit 2; fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/provider/SeedGenerator/SeedGeneratorChoice.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + * + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6998583 + * @summary NativeSeedGenerator is making 8192 byte read requests from + * entropy pool on each init. + * @run main SeedGeneratorChoice + * @run main/othervm -Djava.security.egd=file:/dev/random SeedGeneratorChoice + * @run main/othervm -Djava.security.egd=file:filename SeedGeneratorChoice + */ + +/* + * Side testcase introduced to ensure changes for 6998583 will always + * succeed in falling back to ThreadedSeedGenerator if issues are found + * with the native OS generator request. We should never see an exception + * causing exit. + * We should always fall back to the ThreadedSeedGenerator if exceptions + * are encountered with user defined source of entropy. + */ + +import java.security.SecureRandom; + +public class SeedGeneratorChoice { + + public static void main(String... arguments) throws Exception { + byte[] bytes; + SecureRandom prng = SecureRandom.getInstance("SHA1PRNG"); + bytes = prng.generateSeed(1); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/rsa/InvalidBitString.java Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2010, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @summary Validation of signatures succeed when it should fail + * @bug 6896700 + */ + +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.PublicKey; +import java.security.SignatureException; + +public class InvalidBitString { + + // Test cert for CN=CA + static String signerCertStr = + "-----BEGIN CERTIFICATE-----\n" + + "MIIBtDCCAR2gAwIBAgIEemxRHjANBgkqhkiG9w0BAQUFADANMQswCQYDVQQDEwJDQTAeFw0xMDA2\n" + + "MDMwODA2MjlaFw0xMDA5MDEwODA2MjlaMA0xCzAJBgNVBAMTAkNBMIGfMA0GCSqGSIb3DQEBAQUA\n" + + "A4GNADCBiQKBgQCp2G7pGwMOw4oM7zFFeRKrByuPLNAXClGsh+itdRiOeUgEby6OB9IAgXm93086\n" + + "Z9dWCfRYbzJbDRSnUE7FS1iQsIRIeOEuFMIMogcBK+sOf364ONwMXsI4gtYVmxn4BaaajVWt6C/g\n" + + "FBGZQxp81aORDyUIrlCkMIxhZBSsNPIJYwIDAQABoyEwHzAdBgNVHQ4EFgQUKrvzNhJmdKoqq2li\n" + + "utCzKkwA1N0wDQYJKoZIhvcNAQEFBQADgYEAEIaegsW7fWWjXk4YOMlcl893vx6tnU8ThuQSjwGI\n" + + "rIs93sBYuY7lQIpQw8+XM89WT1XuBB6R2SsnxeW+gHtsU/EE6iJJAEMeCILwEGUL02blwHBQWmpa\n" + + "i3YeGXw+IFe/4OAysPT7ZRbUb7mPt37Ht6hIjain71ShR5anXIuawVE=\n" + + "-----END CERTIFICATE-----\n"; + // Test cert for CN=A, happens to have a zero at the beginning of signature + static String normalCertStr = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB1DCCAT2gAwIBAgIEae+u1TANBgkqhkiG9w0BAQUFADANMQswCQYDVQQDEwJDQTAeFw0xMDA2\n" + + "MDMwODA2NTNaFw0xMDA5MDEwODA2NTNaMAwxCjAIBgNVBAMTAUEwgZ8wDQYJKoZIhvcNAQEBBQAD\n" + + "gY0AMIGJAoGBAKZ7C6bC8AJmXIRNwuPJcgIPW1ygN3rE5PIKPAkeK/dYnPmUJNuiSxOFPJCrLMuL\n" + + "sweQh82Dq/viu+KBb27xVzJ4pK02fbcWdJDo7cIms0Wm+HckK5myA6xmqnpmPOjb/vWCLE6pN2Xg\n" + + "pJyrdeWV77eBvqE9OiCsMTP8WgHI9zLvAgMBAAGjQjBAMB0GA1UdDgQWBBTtIKqCHnL9QeFn+YrX\n" + + "+k00NUk9mjAfBgNVHSMEGDAWgBQqu/M2EmZ0qiqraWK60LMqTADU3TANBgkqhkiG9w0BAQUFAAOB\n" + + "gQAAOcQsEruDAY/z3eXJ7OtWSZlLC0yTVNVdUVNLQ58xNqPrmKNBXNpj/72N8xrTB++ApW+DLgLy\n" + + "cwGU5PVRtsYeiV6prUkpqUf62SQgwI4guAQy1ileeP1CNQJI3cHQExMAHvQT8fJtlD0WZD3nfesq\n" + + "mmQDOpoJLkmO/73Z7IibVA==\n" + + "-----END CERTIFICATE-----\n"; + // normalCertStr with an extra zero at the beginning of signature + static String longerCertStr = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB1TCCAT2gAwIBAgIEae+u1TANBgkqhkiG9w0BAQUFADANMQswCQYDVQQDEwJDQTAeFw0xMDA2\n" + + "MDMwODA2NTNaFw0xMDA5MDEwODA2NTNaMAwxCjAIBgNVBAMTAUEwgZ8wDQYJKoZIhvcNAQEBBQAD\n" + + "gY0AMIGJAoGBAKZ7C6bC8AJmXIRNwuPJcgIPW1ygN3rE5PIKPAkeK/dYnPmUJNuiSxOFPJCrLMuL\n" + + "sweQh82Dq/viu+KBb27xVzJ4pK02fbcWdJDo7cIms0Wm+HckK5myA6xmqnpmPOjb/vWCLE6pN2Xg\n" + + "pJyrdeWV77eBvqE9OiCsMTP8WgHI9zLvAgMBAAGjQjBAMB0GA1UdDgQWBBTtIKqCHnL9QeFn+YrX\n" + + "+k00NUk9mjAfBgNVHSMEGDAWgBQqu/M2EmZ0qiqraWK60LMqTADU3TANBgkqhkiG9w0BAQUFAAOB\n" + + "ggAAADnELBK7gwGP893lyezrVkmZSwtMk1TVXVFTS0OfMTaj65ijQVzaY/+9jfMa0wfvgKVvgy4C\n" + + "8nMBlOT1UbbGHoleqa1JKalH+tkkIMCOILgEMtYpXnj9QjUCSN3B0BMTAB70E/HybZQ9FmQ9533r\n" + + "KppkAzqaCS5Jjv+92eyIm1Q=\n" + + "-----END CERTIFICATE-----\n"; + // normalCertStr without the initial zero at the beginning of signature + static String shorterCertStr = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB0zCCAT2gAwIBAgIEae+u1TANBgkqhkiG9w0BAQUFADANMQswCQYDVQQDEwJDQTAeFw0xMDA2\n" + + "MDMwODA2NTNaFw0xMDA5MDEwODA2NTNaMAwxCjAIBgNVBAMTAUEwgZ8wDQYJKoZIhvcNAQEBBQAD\n" + + "gY0AMIGJAoGBAKZ7C6bC8AJmXIRNwuPJcgIPW1ygN3rE5PIKPAkeK/dYnPmUJNuiSxOFPJCrLMuL\n" + + "sweQh82Dq/viu+KBb27xVzJ4pK02fbcWdJDo7cIms0Wm+HckK5myA6xmqnpmPOjb/vWCLE6pN2Xg\n" + + "pJyrdeWV77eBvqE9OiCsMTP8WgHI9zLvAgMBAAGjQjBAMB0GA1UdDgQWBBTtIKqCHnL9QeFn+YrX\n" + + "+k00NUk9mjAfBgNVHSMEGDAWgBQqu/M2EmZ0qiqraWK60LMqTADU3TANBgkqhkiG9w0BAQUFAAOB\n" + + "gAA5xCwSu4MBj/Pd5cns61ZJmUsLTJNU1V1RU0tDnzE2o+uYo0Fc2mP/vY3zGtMH74Clb4MuAvJz\n" + + "AZTk9VG2xh6JXqmtSSmpR/rZJCDAjiC4BDLWKV54/UI1AkjdwdATEwAe9BPx8m2UPRZkPed96yqa\n" + + "ZAM6mgkuSY7/vdnsiJtU\n" + + "-----END CERTIFICATE-----\n"; + + public static void main(String args[]) throws Exception { + + Certificate signer = generate(signerCertStr); + + // the valid certificate + Certificate normal = generate(normalCertStr); + // the invalid certificate with extra signature bits + Certificate longer = generate(longerCertStr); + // the invalid certificate without enough signature bits + Certificate shorter = generate(shorterCertStr); + + if (!test(normal, signer, " normal", true) || + !test(longer, signer, " longer", false) || + !test(shorter, signer, "shorter", false)) { + throw new Exception("Test failed."); + } + } + + private static Certificate generate(String certStr) throws Exception { + InputStream is = null; + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + is = new ByteArrayInputStream(certStr.getBytes()); + return cf.generateCertificate(is); + } finally { + if (is != null) { + is.close(); + } + } + } + + private static boolean test(Certificate target, Certificate signer, + String title, boolean expected) throws Exception { + System.out.print("Checking " + title + ": expected: " + + (expected ? " verified" : "NOT verified")); + boolean actual; + try { + PublicKey pubKey = signer.getPublicKey(); + target.verify(pubKey); + actual = true; + } catch (SignatureException se) { + actual = false; + } + System.out.println(", actual: " + + (actual ? " verified" : "NOT verified")); + return actual == expected; + } + +}
--- a/test/sun/security/rsa/TestKeyPairGenerator.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/sun/security/rsa/TestKeyPairGenerator.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, 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 @@ -85,8 +85,12 @@ sig.initVerify(kp2.getPublic()); sig.update(data); // verify needs to return false and not throw an Exception - if (sig.verify(signature)) { - throw new Exception("verification unexpectedly succeeded"); + try { + if (sig.verify(signature)) { + throw new Exception("verification unexpectedly succeeded"); + } + } catch (SignatureException se) { + // Yet another kind of failure, OK. } }
--- a/test/sun/security/tools/jarsigner/JarSigningNonAscii.java Mon Dec 13 16:22:29 2010 -0800 +++ b/test/sun/security/tools/jarsigner/JarSigningNonAscii.java Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, 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 @@ -113,7 +113,7 @@ } } - if (isSignedCount != 3) { + if (isSignedCount != 4) { throw new SecurityException("error signing JAR file"); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/tools/jarsigner/checkusage.sh Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,109 @@ +# +# Copyright (c) 2010, 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. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @bug 7004168 +# @summary jarsigner -verify checks for KeyUsage codesigning ext on all certs +# instead of just signing cert +# +# @run shell checkusage.sh +# + +if [ "${TESTJAVA}" = "" ] ; then + JAVAC_CMD=`which javac` + TESTJAVA=`dirname $JAVAC_CMD`/.. +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Windows_* ) + FS="\\" + ;; + * ) + FS="/" + ;; +esac + +KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit" +JAR=$TESTJAVA${FS}bin${FS}jar +JARSIGNER="$TESTJAVA${FS}bin${FS}jarsigner" + +rm js.jks trust.jks unrelated.jks 2> /dev/null + +echo x > x +$JAR cvf a.jar x + +################### 3 Keystores ####################### + +# Keystore js.jks: including CA and Publisher +# CA contains a non-empty KeyUsage +$KT -keystore js.jks -genkeypair -alias ca -dname CN=CA -ext KU=kCS -ext bc -validity 365 +$KT -keystore js.jks -genkeypair -alias pub -dname CN=Publisher + +# Publisher contains the correct KeyUsage +$KT -keystore js.jks -certreq -alias pub | \ + $KT -keystore js.jks -gencert -alias ca -ext KU=dig -validity 365 | \ + $KT -keystore js.jks -importcert -alias pub + +# Keystore trust.jks: including CA only +$KT -keystore js.jks -exportcert -alias ca | \ + $KT -keystore trust.jks -importcert -alias ca -noprompt + +# Keystore unrelated.jks: unrelated +$KT -keystore unrelated.jks -genkeypair -alias nothing -dname CN=Nothing -validity 365 + + +################### 4 Tests ####################### + +# Test 1: Sign should be OK + +$JARSIGNER -keystore js.jks -storepass changeit a.jar pub +RESULT=$? +echo $RESULT +#[ $RESULT = 0 ] || exit 1 + +# Test 2: Verify should be OK + +$JARSIGNER -keystore trust.jks -strict -verify a.jar +RESULT=$? +echo $RESULT +#[ $RESULT = 0 ] || exit 2 + +# Test 3: When no keystore is specified, the error is only +# "chain not validated" + +$JARSIGNER -strict -verify a.jar +RESULT=$? +echo $RESULT +#[ $RESULT = 4 ] || exit 3 + +# Test 4: When unrelated keystore is specified, the error is +# "chain not validated" and "not alias in keystore" + +$JARSIGNER -keystore unrelated.jks -strict -verify a.jar +RESULT=$? +echo $RESULT +#[ $RESULT = 36 ] || exit 4 + +exit 0
--- a/test/sun/security/tools/jarsigner/concise_jarsigner.sh Mon Dec 13 16:22:29 2010 -0800 +++ b/test/sun/security/tools/jarsigner/concise_jarsigner.sh Mon Dec 13 16:25:26 2010 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2010, 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 @@ -79,9 +79,9 @@ $JARSIGNER -verify a.jar [ $? = 0 ] || exit $LINENO -# 4(chainNotValidated)+16(hasUnsignedEntry)+32(aliasNotInStore) +# 4(chainNotValidated)+16(hasUnsignedEntry) $JARSIGNER -verify a.jar -strict -[ $? = 52 ] || exit $LINENO +[ $? = 20 ] || exit $LINENO # 16(hasUnsignedEntry) $JARSIGNER -verify a.jar -strict -keystore js.jks @@ -103,27 +103,31 @@ LINES=`$JARSIGNER -verify a.jar -verbose:grouped | grep $YEAR | wc -l` [ $LINES = 12 ] || exit $LINENO -# 3 groups: unrelated, signed, unsigned +# 4 groups: MANIFST, unrelated, signed, unsigned LINES=`$JARSIGNER -verify a.jar -verbose:summary | grep $YEAR | wc -l` -[ $LINES = 3 ] || exit $LINENO - -# 4 groups: unrelated, signed by a1/a2, signed by a2, unsigned -LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep $YEAR | wc -l` [ $LINES = 4 ] || exit $LINENO -# 2*2 for A1/A2, 2 for A3/A4 -LINES=`$JARSIGNER -verify a.jar -verbose -certs | grep "\[certificate" | wc -l` -[ $LINES = 6 ] || exit $LINENO - -# a1,a2 for A1/A2, a2 for A3/A4 -LINES=`$JARSIGNER -verify a.jar -verbose:grouped -certs | grep "\[certificate" | wc -l` +# still 4 groups, but MANIFEST group has no other file +LINES=`$JARSIGNER -verify a.jar -verbose:summary | grep "more)" | wc -l` [ $LINES = 3 ] || exit $LINENO -# a1,a2 for A1/A2, a2 for A3/A4 +# 5 groups: MANIFEST, unrelated, signed by a1/a2, signed by a2, unsigned +LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep $YEAR | wc -l` +[ $LINES = 5 ] || exit $LINENO + +# 2 for MANIFEST, 2*2 for A1/A2, 2 for A3/A4 +LINES=`$JARSIGNER -verify a.jar -verbose -certs | grep "\[certificate" | wc -l` +[ $LINES = 8 ] || exit $LINENO + +# a1,a2 for MANIFEST, a1,a2 for A1/A2, a2 for A3/A4 +LINES=`$JARSIGNER -verify a.jar -verbose:grouped -certs | grep "\[certificate" | wc -l` +[ $LINES = 5 ] || exit $LINENO + +# a1,a2 for MANIFEST, a1,a2 for A1/A2, a2 for A3/A4 LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep "\[certificate" | wc -l` -[ $LINES = 3 ] || exit $LINENO +[ $LINES = 5 ] || exit $LINENO -# 4 groups +# still 5 groups, but MANIFEST group has no other file LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep "more)" | wc -l` [ $LINES = 4 ] || exit $LINENO
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/tools/jarsigner/onlymanifest.sh Mon Dec 13 16:25:26 2010 -0800 @@ -0,0 +1,68 @@ +# +# Copyright (c) 2010, 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. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @bug 7004035 +# @summary signed jar with only META-INF/* inside is not verifiable +# + +if [ "${TESTJAVA}" = "" ] ; then + JAVAC_CMD=`which javac` + TESTJAVA=`dirname $JAVAC_CMD`/.. +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Windows_* ) + FS="\\" + ;; + * ) + FS="/" + ;; +esac + +KS=onlymanifest.jks +JFILE=onlymanifest.jar + +KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit \ + -keystore $KS" +JAR=$TESTJAVA${FS}bin${FS}jar +JARSIGNER=$TESTJAVA${FS}bin${FS}jarsigner + +rm $KS $JFILE 2> /dev/null + +# Create an empty jar file with only MANIFEST.MF + +echo "Key: Value" > manifest +$JAR cvfm $JFILE manifest + +$KT -alias a -dname CN=a -genkey -validity 300 || exit 1 +$JARSIGNER -keystore $KS -storepass changeit $JFILE a -debug -strict || exit 2 +$JARSIGNER -keystore $KS -storepass changeit -verify $JFILE a -debug -strict \ + > onlymanifest.out || exit 3 + +grep unsigned onlymanifest.out && exit 4 + +exit 0 +