--- a/jdk/make/common/shared/Defs-linux.gmk Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/make/common/shared/Defs-versions.gmk Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/make/common/shared/Sanity.gmk Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/make/docs/Makefile Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/make/java/java/FILES_java.gmk Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/make/mkdemo/nio/zipfs/Makefile Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/com/sun/jndi/ldap/BasicControl.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/com/sun/jndi/ldap/Filter.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/com/sun/security/auth/module/NTSystem.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/com/sun/security/auth/module/SolarisSystem.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/com/sun/security/auth/module/UnixSystem.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/io/FileOutputStream.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/io/ObjectInputStream.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/lang/Double.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/lang/Float.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/lang/ProcessBuilder.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/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/jdk/src/share/classes/java/lang/StrictMath.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/lang/Thread.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/nio/charset/Charset.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/security/CodeSigner.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/security/Timestamp.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/AbstractCollection.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/AbstractList.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/AbstractMap.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/ArrayList.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/Collections.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/ComparableTimSort.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/FormattableFlags.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/Random.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/Stack.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/TimSort.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/TreeMap.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/TreeSet.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/Vector.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/AbstractExecutorService.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListSet.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/CopyOnWriteArraySet.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/CountDownLatch.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/DelayQueue.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/Exchanger.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/Executor.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/ExecutorCompletionService.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/Executors.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/Future.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/FutureTask.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/RecursiveAction.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/ScheduledExecutorService.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/Semaphore.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/ThreadLocalRandom.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/TimeUnit.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/locks/LockSupport.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/locks/ReentrantLock.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/java/util/zip/ZipFile.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/javax/sql/rowset/serial/SerialBlob.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/misc/FpUtils.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/misc/VM.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/net/httpserver/Request.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/net/httpserver/SSLStreams.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/net/httpserver/ServerConfig.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/nio/cs/UTF_32Coder.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/nio/cs/UnicodeEncoder.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/security/provider/SeedGenerator.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/security/rsa/RSASignature.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/security/tools/JarSigner.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/security/tools/policytool/PolicyTool.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/security/util/ManifestEntryVerifier.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/demo/nio/zipfs/Demo.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/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/jdk/src/share/demo/nio/zipfs/README.txt Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/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/jdk/src/share/native/java/io/RandomAccessFile.c Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/native/java/io/io_util.c Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/native/java/io/io_util.h Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/share/native/sun/security/ec/ECC_JNI.cpp Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/solaris/classes/java/lang/ProcessImpl.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/solaris/classes/sun/nio/ch/SctpNet.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/solaris/native/java/io/FileOutputStream_md.c Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/solaris/native/java/io/io_util_md.h Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/solaris/native/sun/nio/ch/SctpNet.c Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/windows/classes/java/lang/ProcessImpl.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/windows/classes/sun/security/provider/NativeSeedGenerator.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/windows/native/java/io/FileOutputStream_md.c Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/windows/native/java/io/io_util_md.c Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/windows/native/java/io/io_util_md.h Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/windows/native/java/lang/ProcessImpl_md.c Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/src/windows/native/sun/nio/ch/FileDispatcherImpl.c Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/com/sun/jndi/ldap/InvalidLdapFilters.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/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/jdk/test/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/demo/zipfs/Basic.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/demo/zipfs/ZipFSTester.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/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/jdk/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/jdk/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/jdk/test/java/nio/channels/FileChannel/Lock.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/nio/channels/FileChannel/Truncate.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/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");
+ }
+ }
+}
Binary file jdk/test/java/security/CodeSigner/cert_file has changed
--- a/jdk/test/java/util/concurrent/BlockingQueue/Interrupt.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/BlockingQueue/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/ConcurrentHashMap/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/ConcurrentHashMap/MapCheck.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/ConcurrentHashMap/MapLoops.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/ConcurrentQueues/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/CopyOnWriteArrayList/EqualsRace.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/CopyOnWriteArraySet/RacingCows.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/CyclicBarrier/Basic.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/Exchanger/ExchangeLoops.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/Exchanger/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/ExecutorCompletionService/ExecutorCompletionServiceLoops.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/ExecutorCompletionService/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/Executors/Throws.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/FutureTask/BlockingTaskExecutor.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/FutureTask/CancelledFutureLoops.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/FutureTask/Customized.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/FutureTask/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/DelayOverflow.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/ThreadPoolExecutor/Custom.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/ThreadPoolExecutor/ScheduledTickleService.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/ThreadPoolExecutor/ShutdownNowExecuteRace.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/atomic/VMSupportsCS8.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/locks/Lock/FlakyMutex.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/locks/Lock/TimedAcquireLeak.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/locks/ReentrantLock/LockOncePerThreadLoops.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/locks/ReentrantLock/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/locks/ReentrantLock/SimpleReentrantLockLoops.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/locks/ReentrantLock/TimeoutLockLoops.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/locks/ReentrantReadWriteLock/Bug6571733.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/locks/ReentrantReadWriteLock/LoopHelpers.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/locks/ReentrantReadWriteLock/MapLoops.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/java/util/concurrent/locks/ReentrantReadWriteLock/RWMap.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/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/jdk/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/jdk/test/sun/security/krb5/tools/ktarg.sh Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/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/jdk/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/jdk/test/sun/security/rsa/TestKeyPairGenerator.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/test/sun/security/tools/jarsigner/JarSigningNonAscii.java Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/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/jdk/test/sun/security/tools/jarsigner/concise_jarsigner.sh Mon Dec 13 16:22:29 2010 -0800
+++ b/jdk/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/jdk/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
+