提交 78919f1d 编写于 作者: T tbell

Merge

...@@ -29,7 +29,6 @@ FILES_c = \ ...@@ -29,7 +29,6 @@ FILES_c = \
Deflater.c \ Deflater.c \
Inflater.c \ Inflater.c \
ZipFile.c \ ZipFile.c \
ZipEntry.c \
zadler32.c \ zadler32.c \
zcrc32.c \ zcrc32.c \
deflate.c \ deflate.c \
......
...@@ -50,15 +50,17 @@ SUNWprivate_1.1 { ...@@ -50,15 +50,17 @@ SUNWprivate_1.1 {
Java_java_util_zip_Inflater_initIDs; Java_java_util_zip_Inflater_initIDs;
Java_java_util_zip_Inflater_reset; Java_java_util_zip_Inflater_reset;
Java_java_util_zip_Inflater_setDictionary; Java_java_util_zip_Inflater_setDictionary;
Java_java_util_zip_ZipEntry_initFields;
Java_java_util_zip_ZipEntry_initIDs;
Java_java_util_zip_ZipFile_close; Java_java_util_zip_ZipFile_close;
Java_java_util_zip_ZipFile_freeEntry; Java_java_util_zip_ZipFile_freeEntry;
Java_java_util_zip_ZipFile_getCSize;
Java_java_util_zip_ZipFile_getEntry; Java_java_util_zip_ZipFile_getEntry;
Java_java_util_zip_ZipFile_getMethod; Java_java_util_zip_ZipFile_getEntryBytes;
Java_java_util_zip_ZipFile_getEntryCrc;
Java_java_util_zip_ZipFile_getEntryCSize;
Java_java_util_zip_ZipFile_getEntryFlag;
Java_java_util_zip_ZipFile_getEntryMethod;
Java_java_util_zip_ZipFile_getEntrySize;
Java_java_util_zip_ZipFile_getEntryTime;
Java_java_util_zip_ZipFile_getNextEntry; Java_java_util_zip_ZipFile_getNextEntry;
Java_java_util_zip_ZipFile_getSize;
Java_java_util_zip_ZipFile_getZipMessage; Java_java_util_zip_ZipFile_getZipMessage;
Java_java_util_zip_ZipFile_getTotal; Java_java_util_zip_ZipFile_getTotal;
Java_java_util_zip_ZipFile_initIDs; Java_java_util_zip_ZipFile_initIDs;
......
...@@ -20,12 +20,14 @@ text: .text%Java_java_util_zip_ZipFile_initIDs; ...@@ -20,12 +20,14 @@ text: .text%Java_java_util_zip_ZipFile_initIDs;
text: .text%Java_java_util_zip_ZipFile_open; text: .text%Java_java_util_zip_ZipFile_open;
text: .text%Java_java_util_zip_ZipFile_getTotal; text: .text%Java_java_util_zip_ZipFile_getTotal;
text: .text%Java_java_util_zip_ZipFile_getEntry; text: .text%Java_java_util_zip_ZipFile_getEntry;
text: .text%Java_java_util_zip_ZipEntry_initIDs;
text: .text%Java_java_util_zip_ZipEntry_initFields;
text: .text%Java_java_util_zip_ZipFile_freeEntry; text: .text%Java_java_util_zip_ZipFile_freeEntry;
text: .text%Java_java_util_zip_ZipFile_getCSize; text: .text%Java_java_util_zip_ZipFile_getEntryTime;
text: .text%Java_java_util_zip_ZipFile_getSize; text: .text%Java_java_util_zip_ZipFile_getEntryCrc;
text: .text%Java_java_util_zip_ZipFile_getMethod; text: .text%Java_java_util_zip_ZipFile_getEntryCSize;
text: .text%Java_java_util_zip_ZipFile_getEntrySize;
text: .text%Java_java_util_zip_ZipFile_getEntryFlag;
text: .text%Java_java_util_zip_ZipFile_getEntryMethod;
text: .text%Java_java_util_zip_ZipFile_getEntryBytes;
text: .text%Java_java_util_zip_Inflater_initIDs; text: .text%Java_java_util_zip_Inflater_initIDs;
text: .text%Java_java_util_zip_Inflater_init; text: .text%Java_java_util_zip_Inflater_init;
text: .text%inflateInit2_; text: .text%inflateInit2_;
......
...@@ -19,12 +19,14 @@ text: .text%Java_java_util_zip_ZipFile_initIDs; ...@@ -19,12 +19,14 @@ text: .text%Java_java_util_zip_ZipFile_initIDs;
text: .text%Java_java_util_zip_ZipFile_open; text: .text%Java_java_util_zip_ZipFile_open;
text: .text%Java_java_util_zip_ZipFile_getTotal; text: .text%Java_java_util_zip_ZipFile_getTotal;
text: .text%Java_java_util_zip_ZipFile_getEntry; text: .text%Java_java_util_zip_ZipFile_getEntry;
text: .text%Java_java_util_zip_ZipEntry_initIDs;
text: .text%Java_java_util_zip_ZipEntry_initFields;
text: .text%Java_java_util_zip_ZipFile_freeEntry; text: .text%Java_java_util_zip_ZipFile_freeEntry;
text: .text%Java_java_util_zip_ZipFile_getCSize; text: .text%Java_java_util_zip_ZipFile_getEntryTime;
text: .text%Java_java_util_zip_ZipFile_getSize; text: .text%Java_java_util_zip_ZipFile_getEntryCrc;
text: .text%Java_java_util_zip_ZipFile_getMethod; text: .text%Java_java_util_zip_ZipFile_getEntryCSize;
text: .text%Java_java_util_zip_ZipFile_getEntrySize;
text: .text%Java_java_util_zip_ZipFile_getEntryFlag;
text: .text%Java_java_util_zip_ZipFile_getEntryMethod;
text: .text%Java_java_util_zip_ZipFile_getEntryBytes;
text: .text%Java_java_util_zip_Inflater_initIDs; text: .text%Java_java_util_zip_Inflater_initIDs;
text: .text%Java_java_util_zip_Inflater_init; text: .text%Java_java_util_zip_Inflater_init;
text: .text%inflateInit2_; text: .text%inflateInit2_;
......
...@@ -20,12 +20,14 @@ text: .text%Java_java_util_zip_ZipFile_initIDs; ...@@ -20,12 +20,14 @@ text: .text%Java_java_util_zip_ZipFile_initIDs;
text: .text%Java_java_util_zip_ZipFile_open; text: .text%Java_java_util_zip_ZipFile_open;
text: .text%Java_java_util_zip_ZipFile_getTotal; text: .text%Java_java_util_zip_ZipFile_getTotal;
text: .text%Java_java_util_zip_ZipFile_getEntry; text: .text%Java_java_util_zip_ZipFile_getEntry;
text: .text%Java_java_util_zip_ZipEntry_initIDs;
text: .text%Java_java_util_zip_ZipEntry_initFields;
text: .text%Java_java_util_zip_ZipFile_freeEntry; text: .text%Java_java_util_zip_ZipFile_freeEntry;
text: .text%Java_java_util_zip_ZipFile_getCSize; text: .text%Java_java_util_zip_ZipFile_getEntryTime;
text: .text%Java_java_util_zip_ZipFile_getSize; text: .text%Java_java_util_zip_ZipFile_getEntryCrc;
text: .text%Java_java_util_zip_ZipFile_getMethod; text: .text%Java_java_util_zip_ZipFile_getEntryCSize;
text: .text%Java_java_util_zip_ZipFile_getEntrySize;
text: .text%Java_java_util_zip_ZipFile_getEntryFlag;
text: .text%Java_java_util_zip_ZipFile_getEntryMethod;
text: .text%Java_java_util_zip_ZipFile_getEntryBytes;
text: .text%Java_java_util_zip_Inflater_initIDs; text: .text%Java_java_util_zip_Inflater_initIDs;
text: .text%Java_java_util_zip_Inflater_init; text: .text%Java_java_util_zip_Inflater_init;
text: .text%inflateInit2_; text: .text%inflateInit2_;
......
...@@ -50,6 +50,12 @@ ...@@ -50,6 +50,12 @@
#define JAR_ERROR2 "Error: Unable to access jarfile %s" #define JAR_ERROR2 "Error: Unable to access jarfile %s"
#define JAR_ERROR3 "Error: Invalid or corrupt jarfile %s" #define JAR_ERROR3 "Error: Invalid or corrupt jarfile %s"
#define CLS_ERROR1 "Error: Could not find the main class %s.\n" JNI_ERROR
#define CLS_ERROR2 "Error: Failed to load Main Class: %s\n%s"
#define CLS_ERROR3 "Error: No main method found in specified class.\n" GEN_ERROR
#define CLS_ERROR4 "Error: Main method not public\n" GEN_ERROR
#define CLS_ERROR5 "Error: main-class: attribute exceeds system limits of %d bytes\n" GEN_ERROR
#define CFG_WARN1 "Warning: %s VM not supported; %s VM will be used" #define CFG_WARN1 "Warning: %s VM not supported; %s VM will be used"
#define CFG_WARN2 "Warning: No leading - on line %d of `%s'" #define CFG_WARN2 "Warning: No leading - on line %d of `%s'"
#define CFG_WARN3 "Warning: Missing VM type on line %d of `%s'" #define CFG_WARN3 "Warning: Missing VM type on line %d of `%s'"
......
...@@ -915,8 +915,14 @@ SelectVersion(int argc, char **argv, char **main_class) ...@@ -915,8 +915,14 @@ SelectVersion(int argc, char **argv, char **main_class)
* to avoid locating, expanding and parsing the manifest extra * to avoid locating, expanding and parsing the manifest extra
* times. * times.
*/ */
if (info.main_class != NULL) if (info.main_class != NULL) {
(void)JLI_StrCat(env_entry, info.main_class); if (JLI_StrLen(info.main_class) <= MAXNAMELEN) {
(void)JLI_StrCat(env_entry, info.main_class);
} else {
JLI_ReportErrorMessage(CLS_ERROR5, MAXNAMELEN);
exit(1);
}
}
(void)putenv(env_entry); (void)putenv(env_entry);
ExecJRE(jre, new_argv); ExecJRE(jre, new_argv);
JLI_FreeManifest(); JLI_FreeManifest();
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
* CA 95054 USA or visit www.sun.com if you need additional information or * CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions. * have any questions.
*/ */
package com.sun.jmx.remote.internal; package com.sun.jmx.remote.internal;
import java.io.IOException; import java.io.IOException;
...@@ -34,6 +33,7 @@ import java.util.List; ...@@ -34,6 +33,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.security.AccessControlContext;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import javax.security.auth.Subject; import javax.security.auth.Subject;
...@@ -54,7 +54,10 @@ import com.sun.jmx.remote.util.EnvHelp; ...@@ -54,7 +54,10 @@ import com.sun.jmx.remote.util.EnvHelp;
public abstract class ClientNotifForwarder { public abstract class ClientNotifForwarder {
public ClientNotifForwarder(Map<String, ?> env) {
private final AccessControlContext acc;
public ClientNotifForwarder(Map env) {
this(null, env); this(null, env);
} }
...@@ -87,6 +90,8 @@ public abstract class ClientNotifForwarder { ...@@ -87,6 +90,8 @@ public abstract class ClientNotifForwarder {
this.command = command; this.command = command;
if (thread == null) { if (thread == null) {
thread = new Thread() { thread = new Thread() {
@Override
public void run() { public void run() {
while (true) { while (true) {
Runnable r; Runnable r;
...@@ -130,6 +135,7 @@ public abstract class ClientNotifForwarder { ...@@ -130,6 +135,7 @@ public abstract class ClientNotifForwarder {
this.defaultClassLoader = defaultClassLoader; this.defaultClassLoader = defaultClassLoader;
this.executor = ex; this.executor = ex;
this.acc = AccessController.getContext();
} }
/** /**
...@@ -380,28 +386,85 @@ public abstract class ClientNotifForwarder { ...@@ -380,28 +386,85 @@ public abstract class ClientNotifForwarder {
setState(TERMINATED); setState(TERMINATED);
} }
// -------------------------------------------------
// private classes // -------------------------------------------------
// ------------------------------------------------- // private classes
// -------------------------------------------------
// //
private class NotifFetcher implements Runnable { private class NotifFetcher implements Runnable {
private volatile boolean alreadyLogged = false;
private void logOnce(String msg, SecurityException x) {
if (alreadyLogged) return;
// Log only once.
logger.config("setContextClassLoader",msg);
if (x != null) logger.fine("setContextClassLoader", x);
alreadyLogged = true;
}
// Set new context class loader, returns previous one.
private final ClassLoader setContextClassLoader(final ClassLoader loader) {
final AccessControlContext ctxt = ClientNotifForwarder.this.acc;
// if ctxt is null, log a config message and throw a
// SecurityException.
if (ctxt == null) {
logOnce("AccessControlContext must not be null.",null);
throw new SecurityException("AccessControlContext must not be null");
}
return AccessController.doPrivileged(
new PrivilegedAction<ClassLoader>() {
public ClassLoader run() {
try {
// get context class loader - may throw
// SecurityException - though unlikely.
final ClassLoader previous =
Thread.currentThread().getContextClassLoader();
// if nothing needs to be done, break here...
if (loader == previous) return previous;
// reset context class loader - may throw
// SecurityException
Thread.currentThread().setContextClassLoader(loader);
return previous;
} catch (SecurityException x) {
logOnce("Permission to set ContextClassLoader missing. " +
"Notifications will not be dispatched. " +
"Please check your Java policy configuration: " +
x, x);
throw x;
}
}
}, ctxt);
}
public void run() { public void run() {
final ClassLoader previous;
if (defaultClassLoader != null) {
previous = setContextClassLoader(defaultClassLoader);
} else {
previous = null;
}
try {
doRun();
} finally {
if (defaultClassLoader != null) {
setContextClassLoader(previous);
}
}
}
private void doRun() {
synchronized (ClientNotifForwarder.this) { synchronized (ClientNotifForwarder.this) {
currentFetchThread = Thread.currentThread(); currentFetchThread = Thread.currentThread();
if (state == STARTING) if (state == STARTING) {
setState(STARTED); setState(STARTED);
}
} }
if (defaultClassLoader != null) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
Thread.currentThread().
setContextClassLoader(defaultClassLoader);
return null;
}
});
}
NotificationResult nr = null; NotificationResult nr = null;
if (!shouldStop() && (nr = fetchNotifs()) != null) { if (!shouldStop() && (nr = fetchNotifs()) != null) {
...@@ -434,8 +497,9 @@ public abstract class ClientNotifForwarder { ...@@ -434,8 +497,9 @@ public abstract class ClientNotifForwarder {
// check if an mbean unregistration notif // check if an mbean unregistration notif
if (!listenerID.equals(mbeanRemovedNotifID)) { if (!listenerID.equals(mbeanRemovedNotifID)) {
final ClientListenerInfo li = infoList.get(listenerID); final ClientListenerInfo li = infoList.get(listenerID);
if (li != null) if (li != null) {
listeners.put(listenerID,li); listeners.put(listenerID, li);
}
continue; continue;
} }
final Notification notif = tn.getNotification(); final Notification notif = tn.getNotification();
...@@ -799,9 +863,7 @@ public abstract class ClientNotifForwarder { ...@@ -799,9 +863,7 @@ public abstract class ClientNotifForwarder {
private long clientSequenceNumber = -1; private long clientSequenceNumber = -1;
private final int maxNotifications; private final int maxNotifications;
private final long timeout; private final long timeout;
private Integer mbeanRemovedNotifID = null; private Integer mbeanRemovedNotifID = null;
private Thread currentFetchThread; private Thread currentFetchThread;
// state // state
......
...@@ -111,6 +111,22 @@ public abstract class MBeanServerAccessController ...@@ -111,6 +111,22 @@ public abstract class MBeanServerAccessController
*/ */
protected abstract void checkWrite(); protected abstract void checkWrite();
/**
* Check if the caller can create the named class. The default
* implementation of this method calls {@link #checkWrite()}.
*/
protected void checkCreate(String className) {
checkWrite();
}
/**
* Check if the caller can unregister the named MBean. The default
* implementation of this method calls {@link #checkWrite()}.
*/
protected void checkUnregister(ObjectName name) {
checkWrite();
}
//-------------------------------------------- //--------------------------------------------
//-------------------------------------------- //--------------------------------------------
// //
...@@ -148,7 +164,7 @@ public abstract class MBeanServerAccessController ...@@ -148,7 +164,7 @@ public abstract class MBeanServerAccessController
} }
/** /**
* Call <code>checkWrite()</code>, then forward this method to the * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object. * wrapped object.
*/ */
public ObjectInstance createMBean(String className, ObjectName name) public ObjectInstance createMBean(String className, ObjectName name)
...@@ -158,7 +174,7 @@ public abstract class MBeanServerAccessController ...@@ -158,7 +174,7 @@ public abstract class MBeanServerAccessController
MBeanRegistrationException, MBeanRegistrationException,
MBeanException, MBeanException,
NotCompliantMBeanException { NotCompliantMBeanException {
checkWrite(); checkCreate(className);
SecurityManager sm = System.getSecurityManager(); SecurityManager sm = System.getSecurityManager();
if (sm == null) { if (sm == null) {
Object object = getMBeanServer().instantiate(className); Object object = getMBeanServer().instantiate(className);
...@@ -170,7 +186,7 @@ public abstract class MBeanServerAccessController ...@@ -170,7 +186,7 @@ public abstract class MBeanServerAccessController
} }
/** /**
* Call <code>checkWrite()</code>, then forward this method to the * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object. * wrapped object.
*/ */
public ObjectInstance createMBean(String className, ObjectName name, public ObjectInstance createMBean(String className, ObjectName name,
...@@ -181,7 +197,7 @@ public abstract class MBeanServerAccessController ...@@ -181,7 +197,7 @@ public abstract class MBeanServerAccessController
MBeanRegistrationException, MBeanRegistrationException,
MBeanException, MBeanException,
NotCompliantMBeanException { NotCompliantMBeanException {
checkWrite(); checkCreate(className);
SecurityManager sm = System.getSecurityManager(); SecurityManager sm = System.getSecurityManager();
if (sm == null) { if (sm == null) {
Object object = getMBeanServer().instantiate(className, Object object = getMBeanServer().instantiate(className,
...@@ -196,7 +212,7 @@ public abstract class MBeanServerAccessController ...@@ -196,7 +212,7 @@ public abstract class MBeanServerAccessController
} }
/** /**
* Call <code>checkWrite()</code>, then forward this method to the * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object. * wrapped object.
*/ */
public ObjectInstance createMBean(String className, public ObjectInstance createMBean(String className,
...@@ -209,7 +225,7 @@ public abstract class MBeanServerAccessController ...@@ -209,7 +225,7 @@ public abstract class MBeanServerAccessController
MBeanException, MBeanException,
NotCompliantMBeanException, NotCompliantMBeanException,
InstanceNotFoundException { InstanceNotFoundException {
checkWrite(); checkCreate(className);
SecurityManager sm = System.getSecurityManager(); SecurityManager sm = System.getSecurityManager();
if (sm == null) { if (sm == null) {
Object object = getMBeanServer().instantiate(className, Object object = getMBeanServer().instantiate(className,
...@@ -222,7 +238,7 @@ public abstract class MBeanServerAccessController ...@@ -222,7 +238,7 @@ public abstract class MBeanServerAccessController
} }
/** /**
* Call <code>checkWrite()</code>, then forward this method to the * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object. * wrapped object.
*/ */
public ObjectInstance createMBean(String className, public ObjectInstance createMBean(String className,
...@@ -237,7 +253,7 @@ public abstract class MBeanServerAccessController ...@@ -237,7 +253,7 @@ public abstract class MBeanServerAccessController
MBeanException, MBeanException,
NotCompliantMBeanException, NotCompliantMBeanException,
InstanceNotFoundException { InstanceNotFoundException {
checkWrite(); checkCreate(className);
SecurityManager sm = System.getSecurityManager(); SecurityManager sm = System.getSecurityManager();
if (sm == null) { if (sm == null) {
Object object = getMBeanServer().instantiate(className, Object object = getMBeanServer().instantiate(className,
...@@ -394,45 +410,45 @@ public abstract class MBeanServerAccessController ...@@ -394,45 +410,45 @@ public abstract class MBeanServerAccessController
} }
/** /**
* Call <code>checkWrite()</code>, then forward this method to the * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object. * wrapped object.
*/ */
public Object instantiate(String className) public Object instantiate(String className)
throws ReflectionException, MBeanException { throws ReflectionException, MBeanException {
checkWrite(); checkCreate(className);
return getMBeanServer().instantiate(className); return getMBeanServer().instantiate(className);
} }
/** /**
* Call <code>checkWrite()</code>, then forward this method to the * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object. * wrapped object.
*/ */
public Object instantiate(String className, public Object instantiate(String className,
Object params[], Object params[],
String signature[]) String signature[])
throws ReflectionException, MBeanException { throws ReflectionException, MBeanException {
checkWrite(); checkCreate(className);
return getMBeanServer().instantiate(className, params, signature); return getMBeanServer().instantiate(className, params, signature);
} }
/** /**
* Call <code>checkWrite()</code>, then forward this method to the * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object. * wrapped object.
*/ */
public Object instantiate(String className, ObjectName loaderName) public Object instantiate(String className, ObjectName loaderName)
throws ReflectionException, MBeanException, InstanceNotFoundException { throws ReflectionException, MBeanException, InstanceNotFoundException {
checkWrite(); checkCreate(className);
return getMBeanServer().instantiate(className, loaderName); return getMBeanServer().instantiate(className, loaderName);
} }
/** /**
* Call <code>checkWrite()</code>, then forward this method to the * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object. * wrapped object.
*/ */
public Object instantiate(String className, ObjectName loaderName, public Object instantiate(String className, ObjectName loaderName,
Object params[], String signature[]) Object params[], String signature[])
throws ReflectionException, MBeanException, InstanceNotFoundException { throws ReflectionException, MBeanException, InstanceNotFoundException {
checkWrite(); checkCreate(className);
return getMBeanServer().instantiate(className, loaderName, return getMBeanServer().instantiate(className, loaderName,
params, signature); params, signature);
} }
...@@ -579,12 +595,12 @@ public abstract class MBeanServerAccessController ...@@ -579,12 +595,12 @@ public abstract class MBeanServerAccessController
} }
/** /**
* Call <code>checkWrite()</code>, then forward this method to the * Call <code>checkUnregister()</code>, then forward this method to the
* wrapped object. * wrapped object.
*/ */
public void unregisterMBean(ObjectName name) public void unregisterMBean(ObjectName name)
throws InstanceNotFoundException, MBeanRegistrationException { throws InstanceNotFoundException, MBeanRegistrationException {
checkWrite(); checkUnregister(name);
getMBeanServer().unregisterMBean(name); getMBeanServer().unregisterMBean(name);
} }
......
...@@ -31,11 +31,17 @@ import java.security.AccessControlContext; ...@@ -31,11 +31,17 @@ import java.security.AccessControlContext;
import java.security.AccessController; import java.security.AccessController;
import java.security.Principal; import java.security.Principal;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.util.Collection; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import javax.management.MBeanServer; import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.security.auth.Subject; import javax.security.auth.Subject;
/** /**
...@@ -46,7 +52,8 @@ import javax.security.auth.Subject; ...@@ -46,7 +52,8 @@ import javax.security.auth.Subject;
* not allowed; in this case the request is not forwarded to the * not allowed; in this case the request is not forwarded to the
* wrapped object.</p> * wrapped object.</p>
* *
* <p>This class implements the {@link #checkRead()} and {@link #checkWrite()} * <p>This class implements the {@link #checkRead()}, {@link #checkWrite()},
* {@link #checkCreate(String)}, and {@link #checkUnregister(ObjectName)}
* methods based on an access level properties file containing username/access * methods based on an access level properties file containing username/access
* level pairs. The set of username/access level pairs is passed either as a * level pairs. The set of username/access level pairs is passed either as a
* filename which denotes a properties file on disk, or directly as an instance * filename which denotes a properties file on disk, or directly as an instance
...@@ -56,14 +63,50 @@ import javax.security.auth.Subject; ...@@ -56,14 +63,50 @@ import javax.security.auth.Subject;
* has exactly one access level. The same access level can be shared by several * has exactly one access level. The same access level can be shared by several
* usernames.</p> * usernames.</p>
* *
* <p>The supported access level values are <i>readonly</i> and * <p>The supported access level values are {@code readonly} and
* <i>readwrite</i>.</p> * {@code readwrite}. The {@code readwrite} access level can be
* qualified by one or more <i>clauses</i>, where each clause looks
* like <code>create <i>classNamePattern</i></code> or {@code
* unregister}. For example:</p>
*
* <pre>
* monitorRole readonly
* controlRole readwrite \
* create javax.management.timer.*,javax.management.monitor.* \
* unregister
* </pre>
*
* <p>(The continuation lines with {@code \} come from the parser for
* Properties files.)</p>
*/ */
public class MBeanServerFileAccessController public class MBeanServerFileAccessController
extends MBeanServerAccessController { extends MBeanServerAccessController {
public static final String READONLY = "readonly"; static final String READONLY = "readonly";
public static final String READWRITE = "readwrite"; static final String READWRITE = "readwrite";
static final String CREATE = "create";
static final String UNREGISTER = "unregister";
private enum AccessType {READ, WRITE, CREATE, UNREGISTER};
private static class Access {
final boolean write;
final String[] createPatterns;
private boolean unregister;
Access(boolean write, boolean unregister, List<String> createPatternList) {
this.write = write;
int npats = (createPatternList == null) ? 0 : createPatternList.size();
if (npats == 0)
this.createPatterns = NO_STRINGS;
else
this.createPatterns = createPatternList.toArray(new String[npats]);
this.unregister = unregister;
}
private final String[] NO_STRINGS = new String[0];
}
/** /**
* <p>Create a new MBeanServerAccessController that forwards all the * <p>Create a new MBeanServerAccessController that forwards all the
...@@ -87,8 +130,8 @@ public class MBeanServerFileAccessController ...@@ -87,8 +130,8 @@ public class MBeanServerFileAccessController
throws IOException { throws IOException {
super(); super();
this.accessFileName = accessFileName; this.accessFileName = accessFileName;
props = propertiesFromFile(accessFileName); Properties props = propertiesFromFile(accessFileName);
checkValues(props); parseProperties(props);
} }
/** /**
...@@ -123,14 +166,14 @@ public class MBeanServerFileAccessController ...@@ -123,14 +166,14 @@ public class MBeanServerFileAccessController
* #setMBeanServer} method after doing access checks based on read and * #setMBeanServer} method after doing access checks based on read and
* write permissions.</p> * write permissions.</p>
* *
* <p>This instance is initialized from the specified properties instance. * <p>This instance is initialized from the specified properties
* This constructor makes a copy of the properties instance using its * instance. This constructor makes a copy of the properties
* <code>clone</code> method and it is the copy that is consulted to check * instance and it is the copy that is consulted to check the
* the username and access level of an incoming connection. The original * username and access level of an incoming connection. The
* properties object can be modified without affecting the copy. If the * original properties object can be modified without affecting
* {@link #refresh} method is then called, the * the copy. If the {@link #refresh} method is then called, the
* <code>MBeanServerFileAccessController</code> will make a new copy of the * <code>MBeanServerFileAccessController</code> will make a new
* properties object at that time.</p> * copy of the properties object at that time.</p>
* *
* @param accessFileProps properties list containing the username/access * @param accessFileProps properties list containing the username/access
* level entries. * level entries.
...@@ -145,8 +188,7 @@ public class MBeanServerFileAccessController ...@@ -145,8 +188,7 @@ public class MBeanServerFileAccessController
if (accessFileProps == null) if (accessFileProps == null)
throw new IllegalArgumentException("Null properties"); throw new IllegalArgumentException("Null properties");
originalProps = accessFileProps; originalProps = accessFileProps;
props = (Properties) accessFileProps.clone(); parseProperties(accessFileProps);
checkValues(props);
} }
/** /**
...@@ -155,14 +197,14 @@ public class MBeanServerFileAccessController ...@@ -155,14 +197,14 @@ public class MBeanServerFileAccessController
* #setMBeanServer} method after doing access checks based on read and * #setMBeanServer} method after doing access checks based on read and
* write permissions.</p> * write permissions.</p>
* *
* <p>This instance is initialized from the specified properties instance. * <p>This instance is initialized from the specified properties
* This constructor makes a copy of the properties instance using its * instance. This constructor makes a copy of the properties
* <code>clone</code> method and it is the copy that is consulted to check * instance and it is the copy that is consulted to check the
* the username and access level of an incoming connection. The original * username and access level of an incoming connection. The
* properties object can be modified without affecting the copy. If the * original properties object can be modified without affecting
* {@link #refresh} method is then called, the * the copy. If the {@link #refresh} method is then called, the
* <code>MBeanServerFileAccessController</code> will make a new copy of the * <code>MBeanServerFileAccessController</code> will make a new
* properties object at that time.</p> * copy of the properties object at that time.</p>
* *
* @param accessFileProps properties list containing the username/access * @param accessFileProps properties list containing the username/access
* level entries. * level entries.
...@@ -184,16 +226,36 @@ public class MBeanServerFileAccessController ...@@ -184,16 +226,36 @@ public class MBeanServerFileAccessController
* Check if the caller can do read operations. This method does * Check if the caller can do read operations. This method does
* nothing if so, otherwise throws SecurityException. * nothing if so, otherwise throws SecurityException.
*/ */
@Override
public void checkRead() { public void checkRead() {
checkAccessLevel(READONLY); checkAccess(AccessType.READ, null);
} }
/** /**
* Check if the caller can do write operations. This method does * Check if the caller can do write operations. This method does
* nothing if so, otherwise throws SecurityException. * nothing if so, otherwise throws SecurityException.
*/ */
@Override
public void checkWrite() { public void checkWrite() {
checkAccessLevel(READWRITE); checkAccess(AccessType.WRITE, null);
}
/**
* Check if the caller can create MBeans or instances of the given class.
* This method does nothing if so, otherwise throws SecurityException.
*/
@Override
public void checkCreate(String className) {
checkAccess(AccessType.CREATE, className);
}
/**
* Check if the caller can do unregister operations. This method does
* nothing if so, otherwise throws SecurityException.
*/
@Override
public void checkUnregister(ObjectName name) {
checkAccess(AccessType.UNREGISTER, null);
} }
/** /**
...@@ -218,14 +280,13 @@ public class MBeanServerFileAccessController ...@@ -218,14 +280,13 @@ public class MBeanServerFileAccessController
* @exception IllegalArgumentException if any of the supplied access * @exception IllegalArgumentException if any of the supplied access
* level values differs from "readonly" or "readwrite". * level values differs from "readonly" or "readwrite".
*/ */
public void refresh() throws IOException { public synchronized void refresh() throws IOException {
synchronized (props) { Properties props;
if (accessFileName == null) if (accessFileName == null)
props = (Properties) originalProps.clone(); props = (Properties) originalProps;
else else
props = propertiesFromFile(accessFileName); props = propertiesFromFile(accessFileName);
checkValues(props); parseProperties(props);
}
} }
private static Properties propertiesFromFile(String fname) private static Properties propertiesFromFile(String fname)
...@@ -240,7 +301,7 @@ public class MBeanServerFileAccessController ...@@ -240,7 +301,7 @@ public class MBeanServerFileAccessController
} }
} }
private void checkAccessLevel(String accessLevel) { private synchronized void checkAccess(AccessType requiredAccess, String arg) {
final AccessControlContext acc = AccessController.getContext(); final AccessControlContext acc = AccessController.getContext();
final Subject s = final Subject s =
AccessController.doPrivileged(new PrivilegedAction<Subject>() { AccessController.doPrivileged(new PrivilegedAction<Subject>() {
...@@ -249,39 +310,235 @@ public class MBeanServerFileAccessController ...@@ -249,39 +310,235 @@ public class MBeanServerFileAccessController
} }
}); });
if (s == null) return; /* security has not been enabled */ if (s == null) return; /* security has not been enabled */
final Set<Principal> principals = s.getPrincipals(); final Set principals = s.getPrincipals();
for (Principal p : principals) { String newPropertyValue = null;
String grantedAccessLevel; for (Iterator i = principals.iterator(); i.hasNext(); ) {
synchronized (props) { final Principal p = (Principal) i.next();
grantedAccessLevel = props.getProperty(p.getName()); Access access = accessMap.get(p.getName());
} if (access != null) {
if (grantedAccessLevel != null) { boolean ok;
if (accessLevel.equals(READONLY) && switch (requiredAccess) {
(grantedAccessLevel.equals(READONLY) || case READ:
grantedAccessLevel.equals(READWRITE))) ok = true; // all access entries imply read
return; break;
if (accessLevel.equals(READWRITE) && case WRITE:
grantedAccessLevel.equals(READWRITE)) ok = access.write;
break;
case UNREGISTER:
ok = access.unregister;
if (!ok && access.write)
newPropertyValue = "unregister";
break;
case CREATE:
ok = checkCreateAccess(access, arg);
if (!ok && access.write)
newPropertyValue = "create " + arg;
break;
default:
throw new AssertionError();
}
if (ok)
return; return;
} }
} }
throw new SecurityException("Access denied! Invalid access level for " + SecurityException se = new SecurityException("Access denied! Invalid " +
"requested MBeanServer operation."); "access level for requested MBeanServer operation.");
// Add some more information to help people with deployments that
// worked before we required explicit create clauses. We're not giving
// any information to the bad guys, other than that the access control
// is based on a file, which they could have worked out from the stack
// trace anyway.
if (newPropertyValue != null) {
SecurityException se2 = new SecurityException("Access property " +
"for this identity should be similar to: " + READWRITE +
" " + newPropertyValue);
se.initCause(se2);
}
throw se;
}
private static boolean checkCreateAccess(Access access, String className) {
for (String classNamePattern : access.createPatterns) {
if (classNameMatch(classNamePattern, className))
return true;
}
return false;
}
private static boolean classNameMatch(String pattern, String className) {
// We studiously avoided regexes when parsing the properties file,
// because that is done whenever the VM is started with the
// appropriate -Dcom.sun.management options, even if nobody ever
// creates an MBean. We don't want to incur the overhead of loading
// all the regex code whenever those options are specified, but if we
// get as far as here then the VM is already running and somebody is
// doing the very unusual operation of remotely creating an MBean.
// Because that operation is so unusual, we don't try to optimize
// by hand-matching or by caching compiled Pattern objects.
StringBuilder sb = new StringBuilder();
StringTokenizer stok = new StringTokenizer(pattern, "*", true);
while (stok.hasMoreTokens()) {
String tok = stok.nextToken();
if (tok.equals("*"))
sb.append("[^.]*");
else
sb.append(Pattern.quote(tok));
}
return className.matches(sb.toString());
}
private void parseProperties(Properties props) {
this.accessMap = new HashMap<String, Access>();
for (Map.Entry<Object, Object> entry : props.entrySet()) {
String identity = (String) entry.getKey();
String accessString = (String) entry.getValue();
Access access = Parser.parseAccess(identity, accessString);
accessMap.put(identity, access);
}
} }
private void checkValues(Properties props) { private static class Parser {
Collection<?> c = props.values(); private final static int EOS = -1; // pseudo-codepoint "end of string"
for (Iterator<?> i = c.iterator(); i.hasNext(); ) { static {
final String accessLevel = (String) i.next(); assert !Character.isWhitespace(EOS);
if (!accessLevel.equals(READONLY) && }
!accessLevel.equals(READWRITE)) {
throw new IllegalArgumentException( private final String identity; // just for better error messages
"Syntax error in access level entry [" + accessLevel + "]"); private final String s; // the string we're parsing
private final int len; // s.length()
private int i;
private int c;
// At any point, either c is s.codePointAt(i), or i == len and
// c is EOS. We use int rather than char because it is conceivable
// (if unlikely) that a classname in a create clause might contain
// "supplementary characters", the ones that don't fit in the original
// 16 bits for Unicode.
private Parser(String identity, String s) {
this.identity = identity;
this.s = s;
this.len = s.length();
this.i = 0;
if (i < len)
this.c = s.codePointAt(i);
else
this.c = EOS;
}
static Access parseAccess(String identity, String s) {
return new Parser(identity, s).parseAccess();
}
private Access parseAccess() {
skipSpace();
String type = parseWord();
Access access;
if (type.equals(READONLY))
access = new Access(false, false, null);
else if (type.equals(READWRITE))
access = parseReadWrite();
else {
throw syntax("Expected " + READONLY + " or " + READWRITE +
": " + type);
}
if (c != EOS)
throw syntax("Extra text at end of line");
return access;
}
private Access parseReadWrite() {
List<String> createClasses = new ArrayList<String>();
boolean unregister = false;
while (true) {
skipSpace();
if (c == EOS)
break;
String type = parseWord();
if (type.equals(UNREGISTER))
unregister = true;
else if (type.equals(CREATE))
parseCreate(createClasses);
else
throw syntax("Unrecognized keyword " + type);
} }
return new Access(true, unregister, createClasses);
}
private void parseCreate(List<String> createClasses) {
while (true) {
skipSpace();
createClasses.add(parseClassName());
skipSpace();
if (c == ',')
next();
else
break;
}
}
private String parseClassName() {
// We don't check that classname components begin with suitable
// characters (so we accept 1.2.3 for example). This means that
// there are only two states, which we can call dotOK and !dotOK
// according as a dot (.) is legal or not. Initially we're in
// !dotOK since a classname can't start with a dot; after a dot
// we're in !dotOK again; and after any other characters we're in
// dotOK. The classname is only accepted if we end in dotOK,
// so we reject an empty name or a name that ends with a dot.
final int start = i;
boolean dotOK = false;
while (true) {
if (c == '.') {
if (!dotOK)
throw syntax("Bad . in class name");
dotOK = false;
} else if (c == '*' || Character.isJavaIdentifierPart(c))
dotOK = true;
else
break;
next();
}
String className = s.substring(start, i);
if (!dotOK)
throw syntax("Bad class name " + className);
return className;
}
// Advance c and i to the next character, unless already at EOS.
private void next() {
if (c != EOS) {
i += Character.charCount(c);
if (i < len)
c = s.codePointAt(i);
else
c = EOS;
}
}
private void skipSpace() {
while (Character.isWhitespace(c))
next();
}
private String parseWord() {
skipSpace();
if (c == EOS)
throw syntax("Expected word at end of line");
final int start = i;
while (c != EOS && !Character.isWhitespace(c))
next();
String word = s.substring(start, i);
skipSpace();
return word;
}
private IllegalArgumentException syntax(String msg) {
return new IllegalArgumentException(
msg + " [" + identity + " " + s + "]");
} }
} }
private Properties props; private Map<String, Access> accessMap;
private Properties originalProps; private Properties originalProps;
private String accessFileName; private String accessFileName;
} }
...@@ -302,7 +302,16 @@ final public class LdapCtx extends ComponentDirContext ...@@ -302,7 +302,16 @@ final public class LdapCtx extends ComponentDirContext
schemaTrees = new Hashtable(11, 0.75f); schemaTrees = new Hashtable(11, 0.75f);
initEnv(); initEnv();
connect(false); try {
connect(false);
} catch (NamingException e) {
try {
close();
} catch (Exception e2) {
// Nothing
}
throw e;
}
} }
LdapCtx(LdapCtx existing, String newDN) throws NamingException { LdapCtx(LdapCtx existing, String newDN) throws NamingException {
......
/* /*
* Copyright 1999 Sun Microsystems, Inc. All Rights Reserved. * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -33,12 +33,33 @@ import java.security.PrivilegedAction; ...@@ -33,12 +33,33 @@ import java.security.PrivilegedAction;
final class VersionHelper12 extends VersionHelper { final class VersionHelper12 extends VersionHelper {
// System property to control whether classes may be loaded from an
// arbitrary URL code base.
private static final String TRUST_URL_CODEBASE_PROPERTY =
"com.sun.jndi.ldap.object.trustURLCodebase";
// Determine whether classes may be loaded from an arbitrary URL code base.
private static final String trustURLCodebase =
AccessController.doPrivileged(
new PrivilegedAction<String>() {
public String run() {
return System.getProperty(TRUST_URL_CODEBASE_PROPERTY,
"false");
}
}
);
VersionHelper12() {} // Disallow external from creating one of these. VersionHelper12() {} // Disallow external from creating one of these.
ClassLoader getURLClassLoader(String[] url) ClassLoader getURLClassLoader(String[] url)
throws MalformedURLException { throws MalformedURLException {
ClassLoader parent = getContextClassLoader(); ClassLoader parent = getContextClassLoader();
if (url != null) { /*
* Classes may only be loaded from an arbitrary URL code base when
* the system property com.sun.jndi.ldap.object.trustURLCodebase
* has been set to "true".
*/
if (url != null && "true".equalsIgnoreCase(trustURLCodebase)) {
return URLClassLoader.newInstance(getUrlArray(url), parent); return URLClassLoader.newInstance(getUrlArray(url), parent);
} else { } else {
return parent; return parent;
......
...@@ -37,6 +37,8 @@ import java.awt.geom.Rectangle2D; ...@@ -37,6 +37,8 @@ import java.awt.geom.Rectangle2D;
import java.awt.peer.FontPeer; import java.awt.peer.FontPeer;
import java.io.*; import java.io.*;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.text.AttributedCharacterIterator.Attribute; import java.text.AttributedCharacterIterator.Attribute;
import java.text.CharacterIterator; import java.text.CharacterIterator;
import java.text.StringCharacterIterator; import java.text.StringCharacterIterator;
...@@ -51,6 +53,7 @@ import sun.font.AttributeMap; ...@@ -51,6 +53,7 @@ import sun.font.AttributeMap;
import sun.font.AttributeValues; import sun.font.AttributeValues;
import sun.font.EAttribute; import sun.font.EAttribute;
import sun.font.CompositeFont; import sun.font.CompositeFont;
import sun.font.CreatedFontTracker;
import sun.font.Font2D; import sun.font.Font2D;
import sun.font.Font2DHandle; import sun.font.Font2DHandle;
import sun.font.FontManager; import sun.font.FontManager;
...@@ -575,14 +578,16 @@ public class Font implements java.io.Serializable ...@@ -575,14 +578,16 @@ public class Font implements java.io.Serializable
} }
/* used to implement Font.createFont */ /* used to implement Font.createFont */
private Font(File fontFile, int fontFormat, boolean isCopy) private Font(File fontFile, int fontFormat,
boolean isCopy, CreatedFontTracker tracker)
throws FontFormatException { throws FontFormatException {
this.createdFont = true; this.createdFont = true;
/* Font2D instances created by this method track their font file /* Font2D instances created by this method track their font file
* so that when the Font2D is GC'd it can also remove the file. * so that when the Font2D is GC'd it can also remove the file.
*/ */
this.font2DHandle = this.font2DHandle =
FontManager.createFont2D(fontFile, fontFormat, isCopy).handle; FontManager.createFont2D(fontFile, fontFormat,
isCopy, tracker).handle;
this.name = this.font2DHandle.font2D.getFontName(Locale.getDefault()); this.name = this.font2DHandle.font2D.getFontName(Locale.getDefault());
this.style = Font.PLAIN; this.style = Font.PLAIN;
this.size = 1; this.size = 1;
...@@ -787,6 +792,29 @@ public class Font implements java.io.Serializable ...@@ -787,6 +792,29 @@ public class Font implements java.io.Serializable
return new Font(attributes); return new Font(attributes);
} }
/**
* Used with the byte count tracker for fonts created from streams.
* If a thread can create temp files anyway, no point in counting
* font bytes.
*/
private static boolean hasTempPermission() {
if (System.getSecurityManager() == null) {
return true;
}
File f = null;
boolean hasPerm = false;
try {
f = File.createTempFile("+~JT", ".tmp", null);
f.delete();
f = null;
hasPerm = true;
} catch (Throwable t) {
/* inc. any kind of SecurityException */
}
return hasPerm;
}
/** /**
* Returns a new <code>Font</code> using the specified font type * Returns a new <code>Font</code> using the specified font type
* and input data. The new <code>Font</code> is * and input data. The new <code>Font</code> is
...@@ -822,58 +850,96 @@ public class Font implements java.io.Serializable ...@@ -822,58 +850,96 @@ public class Font implements java.io.Serializable
fontFormat != Font.TYPE1_FONT) { fontFormat != Font.TYPE1_FONT) {
throw new IllegalArgumentException ("font format not recognized"); throw new IllegalArgumentException ("font format not recognized");
} }
final InputStream fStream = fontStream; boolean copiedFontData = false;
Object ret = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() { try {
public Object run() { final File tFile = AccessController.doPrivileged(
File tFile = null; new PrivilegedExceptionAction<File>() {
FileOutputStream outStream = null; public File run() throws IOException {
try { return File.createTempFile("+~JF", ".tmp", null);
tFile = File.createTempFile("+~JF", ".tmp", null); }
/* Temp file deleted by font shutdown hook */ }
BufferedInputStream inStream = );
new BufferedInputStream(fStream);
outStream = new FileOutputStream(tFile); int totalSize = 0;
int bytesRead = 0; CreatedFontTracker tracker = null;
int bufSize = 8192; try {
byte [] buf = new byte[bufSize]; final OutputStream outStream =
while (bytesRead != -1) { AccessController.doPrivileged(
try { new PrivilegedExceptionAction<OutputStream>() {
bytesRead = inStream.read(buf, 0, bufSize); public OutputStream run() throws IOException {
} catch (Throwable t) { return new FileOutputStream(tFile);
throw new IOException(); }
} }
if (bytesRead != -1) { );
outStream.write(buf, 0, bytesRead); if (!hasTempPermission()) {
} tracker = CreatedFontTracker.getTracker();
} }
/* don't close the input stream */ try {
outStream.close(); byte[] buf = new byte[8192];
} catch (IOException e) { for (;;) {
if (outStream != null) { int bytesRead = fontStream.read(buf);
try { if (bytesRead < 0) {
outStream.close(); break;
} catch (Exception e1) { }
} if (tracker != null) {
} if (totalSize+bytesRead > tracker.MAX_FILE_SIZE) {
if (tFile != null) { throw new IOException("File too big.");
try { }
tFile.delete(); if (totalSize+tracker.getNumBytes() >
} catch (Exception e2) { tracker.MAX_TOTAL_BYTES)
} {
} throw new IOException("Total files too big.");
return e; }
} totalSize += bytesRead;
return tFile; tracker.addBytes(bytesRead);
} }
}); outStream.write(buf, 0, bytesRead);
}
if (ret instanceof File) { /* don't close the input stream */
return new Font((File)ret, fontFormat, true); } finally {
} else if (ret instanceof IOException) { outStream.close();
throw (IOException)ret; }
} else { /* After all references to a Font2D are dropped, the file
throw new FontFormatException("Couldn't access font stream"); * will be removed. To support long-lived AppContexts,
* we need to then decrement the byte count by the size
* of the file.
* If the data isn't a valid font, the implementation will
* delete the tmp file and decrement the byte count
* in the tracker object before returning from the
* constructor, so we can set 'copiedFontData' to true here
* without waiting for the results of that constructor.
*/
copiedFontData = true;
Font font = new Font(tFile, fontFormat, true, tracker);
return font;
} finally {
if (!copiedFontData) {
if (tracker != null) {
tracker.subBytes(totalSize);
}
AccessController.doPrivileged(
new PrivilegedExceptionAction<Void>() {
public Void run() {
tFile.delete();
return null;
}
}
);
}
}
} catch (Throwable t) {
if (t instanceof FontFormatException) {
throw (FontFormatException)t;
}
if (t instanceof IOException) {
throw (IOException)t;
}
Throwable cause = t.getCause();
if (cause instanceof FontFormatException) {
throw (FontFormatException)cause;
}
throw new IOException("Problem reading font data.");
} }
} }
...@@ -913,6 +979,9 @@ public class Font implements java.io.Serializable ...@@ -913,6 +979,9 @@ public class Font implements java.io.Serializable
*/ */
public static Font createFont(int fontFormat, File fontFile) public static Font createFont(int fontFormat, File fontFile)
throws java.awt.FontFormatException, java.io.IOException { throws java.awt.FontFormatException, java.io.IOException {
fontFile = new File(fontFile.getPath());
if (fontFormat != Font.TRUETYPE_FONT && if (fontFormat != Font.TRUETYPE_FONT &&
fontFormat != Font.TYPE1_FONT) { fontFormat != Font.TYPE1_FONT) {
throw new IllegalArgumentException ("font format not recognized"); throw new IllegalArgumentException ("font format not recognized");
...@@ -926,7 +995,7 @@ public class Font implements java.io.Serializable ...@@ -926,7 +995,7 @@ public class Font implements java.io.Serializable
if (!fontFile.canRead()) { if (!fontFile.canRead()) {
throw new IOException("Can't read " + fontFile); throw new IOException("Can't read " + fontFile);
} }
return new Font(fontFile, fontFormat, false); return new Font(fontFile, fontFormat, false, null);
} }
/** /**
......
...@@ -41,14 +41,14 @@ class NoSuchFieldError extends IncompatibleClassChangeError { ...@@ -41,14 +41,14 @@ class NoSuchFieldError extends IncompatibleClassChangeError {
private static final long serialVersionUID = -3456430195886129035L; private static final long serialVersionUID = -3456430195886129035L;
/** /**
* Constructs a <code>NoSuchFieldException</code> with no detail message. * Constructs a <code>NoSuchFieldError</code> with no detail message.
*/ */
public NoSuchFieldError() { public NoSuchFieldError() {
super(); super();
} }
/** /**
* Constructs a <code>NoSuchFieldException</code> with the specified * Constructs a <code>NoSuchFieldError</code> with the specified
* detail message. * detail message.
* *
* @param s the detail message. * @param s the detail message.
......
...@@ -196,10 +196,12 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private ...@@ -196,10 +196,12 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
if ((start < 0) || (end > len) || (start > end)) if ((start < 0) || (end > len) || (start > end))
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
int sublen = end - start; return new ByteBufferAsCharBuffer$RW$$BO$(bb,
int off = offset + ((pos + start) << $LG_BYTES_PER_VALUE$); -1,
assert (off >= 0); pos + start,
return new ByteBufferAsCharBuffer$RW$$BO$(bb, -1, 0, sublen, sublen, off); pos + end,
capacity(),
offset);
} }
#end[char] #end[char]
......
...@@ -412,10 +412,12 @@ class Direct$Type$Buffer$RW$$BO$ ...@@ -412,10 +412,12 @@ class Direct$Type$Buffer$RW$$BO$
if ((start < 0) || (end > len) || (start > end)) if ((start < 0) || (end > len) || (start > end))
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
int sublen = end - start; return new DirectCharBuffer$RW$$BO$(this,
int off = (pos + start) << $LG_BYTES_PER_VALUE$; -1,
assert (off >= 0); pos + start,
return new DirectCharBuffer$RW$$BO$(this, -1, 0, sublen, sublen, off); pos + end,
capacity(),
offset);
} }
#end[char] #end[char]
......
...@@ -572,10 +572,13 @@ class Heap$Type$Buffer$RW$ ...@@ -572,10 +572,13 @@ class Heap$Type$Buffer$RW$
|| (end > length()) || (end > length())
|| (start > end)) || (start > end))
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
int len = end - start; int pos = position();
return new HeapCharBuffer$RW$(hb, return new HeapCharBuffer$RW$(hb,
-1, 0, len, len, -1,
offset + position() + start); pos + start,
pos + end,
capacity(),
offset);
} }
#end[char] #end[char]
......
...@@ -102,10 +102,12 @@ class StringCharBuffer // package-private ...@@ -102,10 +102,12 @@ class StringCharBuffer // package-private
public final CharBuffer subSequence(int start, int end) { public final CharBuffer subSequence(int start, int end) {
try { try {
int pos = position(); int pos = position();
return new StringCharBuffer(str, -1, return new StringCharBuffer(str,
-1,
pos + checkIndex(start, pos), pos + checkIndex(start, pos),
pos + checkIndex(end, pos), pos + checkIndex(end, pos),
remaining(), offset); capacity(),
offset);
} catch (IllegalArgumentException x) { } catch (IllegalArgumentException x) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
......
...@@ -443,7 +443,7 @@ public abstract class AsynchronousDatagramChannel ...@@ -443,7 +443,7 @@ public abstract class AsynchronousDatagramChannel
* at least care must be taken to ensure that the buffer is not accessed * at least care must be taken to ensure that the buffer is not accessed
* while the channel remains open. * while the channel remains open.
* *
* <p> If there is a security manager installed and the the channel is not * <p> If there is a security manager installed and the channel is not
* connected then this method verifies that the target address and port number * connected then this method verifies that the target address and port number
* are permitted by the security manager's {@link SecurityManager#checkConnect * are permitted by the security manager's {@link SecurityManager#checkConnect
* checkConnect} method. The overhead of this security check can be avoided * checkConnect} method. The overhead of this security check can be avoided
......
...@@ -494,7 +494,7 @@ public abstract class Path ...@@ -494,7 +494,7 @@ public abstract class Path
* @throws IOException * @throws IOException
* if an I/O error occurs * if an I/O error occurs
* @throws SecurityException * @throws SecurityException
* In the case of the the default provider, and a security manager * In the case of the default provider, and a security manager
* is installed, it denies {@link LinkPermission}<tt>("symbolic")</tt> * is installed, it denies {@link LinkPermission}<tt>("symbolic")</tt>
* or its {@link SecurityManager#checkWrite(String) checkWrite} * or its {@link SecurityManager#checkWrite(String) checkWrite}
* method denies write access to the path of the symbolic link. * method denies write access to the path of the symbolic link.
...@@ -531,7 +531,7 @@ public abstract class Path ...@@ -531,7 +531,7 @@ public abstract class Path
* @throws IOException * @throws IOException
* if an I/O error occurs * if an I/O error occurs
* @throws SecurityException * @throws SecurityException
* In the case of the the default provider, and a security manager * In the case of the default provider, and a security manager
* is installed, it denies {@link LinkPermission}<tt>("hard")</tt> * is installed, it denies {@link LinkPermission}<tt>("hard")</tt>
* or its {@link SecurityManager#checkWrite(String) checkWrite} * or its {@link SecurityManager#checkWrite(String) checkWrite}
* method denies write access to both this path and the path of the * method denies write access to both this path and the path of the
...@@ -560,7 +560,7 @@ public abstract class Path ...@@ -560,7 +560,7 @@ public abstract class Path
* @throws IOException * @throws IOException
* if an I/O error occurs * if an I/O error occurs
* @throws SecurityException * @throws SecurityException
* In the case of the the default provider, and a security manager * In the case of the default provider, and a security manager
* is installed, it checks that {@code FilePermission} has been * is installed, it checks that {@code FilePermission} has been
* granted with the "{@code readlink}" action to read the link. * granted with the "{@code readlink}" action to read the link.
*/ */
...@@ -615,7 +615,7 @@ public abstract class Path ...@@ -615,7 +615,7 @@ public abstract class Path
* obtained * obtained
* *
* @throws SecurityException * @throws SecurityException
* In the case of the the default provider, and a security manager * In the case of the default provider, and a security manager
* is installed, the {@link #toAbsolutePath toAbsolutePath} method * is installed, the {@link #toAbsolutePath toAbsolutePath} method
* throws a security exception. * throws a security exception.
*/ */
...@@ -636,7 +636,7 @@ public abstract class Path ...@@ -636,7 +636,7 @@ public abstract class Path
* @throws IOError * @throws IOError
* if an I/O error occurs * if an I/O error occurs
* @throws SecurityException * @throws SecurityException
* In the case of the the default provider, and a security manager * In the case of the default provider, and a security manager
* is installed, its {@link SecurityManager#checkPropertyAccess(String) * is installed, its {@link SecurityManager#checkPropertyAccess(String)
* checkPropertyAccess} method is invoked to check access to the * checkPropertyAccess} method is invoked to check access to the
* system property {@code user.dir} * system property {@code user.dir}
...@@ -677,7 +677,7 @@ public abstract class Path ...@@ -677,7 +677,7 @@ public abstract class Path
* @throws IOException * @throws IOException
* if the file does not exist or an I/O error occurs * if the file does not exist or an I/O error occurs
* @throws SecurityException * @throws SecurityException
* In the case of the the default provider, and a security manager * In the case of the default provider, and a security manager
* is installed, its {@link SecurityManager#checkRead(String) checkRead} * is installed, its {@link SecurityManager#checkRead(String) checkRead}
* method is invoked to check read access to the file, and where * method is invoked to check read access to the file, and where
* this path is not absolute, its {@link SecurityManager#checkPropertyAccess(String) * this path is not absolute, its {@link SecurityManager#checkPropertyAccess(String)
......
...@@ -208,7 +208,7 @@ public abstract class SecureDirectoryStream ...@@ -208,7 +208,7 @@ public abstract class SecureDirectoryStream
* @throws ClosedDirectoryStreamException * @throws ClosedDirectoryStreamException
* if the directory stream is closed * if the directory stream is closed
* @throws NoSuchFileException * @throws NoSuchFileException
* if the the directory does not exist <i>(optional specific exception)</i> * if the directory does not exist <i>(optional specific exception)</i>
* @throws DirectoryNotEmptyException * @throws DirectoryNotEmptyException
* if the directory could not otherwise be deleted because it is * if the directory could not otherwise be deleted because it is
* not empty <i>(optional specific exception)</i> * not empty <i>(optional specific exception)</i>
......
...@@ -425,7 +425,7 @@ public final class AccessController { ...@@ -425,7 +425,7 @@ public final class AccessController {
* Performs the specified <code>PrivilegedExceptionAction</code> with * Performs the specified <code>PrivilegedExceptionAction</code> with
* privileges enabled and restricted by the specified * privileges enabled and restricted by the specified
* <code>AccessControlContext</code>. The action is performed with the * <code>AccessControlContext</code>. The action is performed with the
* intersection of the the permissions possessed by the caller's * intersection of the permissions possessed by the caller's
* protection domain, and those possessed by the domains represented by the * protection domain, and those possessed by the domains represented by the
* specified <code>AccessControlContext</code>. * specified <code>AccessControlContext</code>.
* <p> * <p>
......
...@@ -102,7 +102,7 @@ public abstract class AlgorithmParametersSpi { ...@@ -102,7 +102,7 @@ public abstract class AlgorithmParametersSpi {
* parameters should be returned in an instance of the * parameters should be returned in an instance of the
* <code>DSAParameterSpec</code> class. * <code>DSAParameterSpec</code> class.
* *
* @param paramSpec the the specification class in which * @param paramSpec the specification class in which
* the parameters should be returned. * the parameters should be returned.
* *
* @return the parameter specification. * @return the parameter specification.
......
...@@ -87,7 +87,7 @@ public class PrivilegedActionException extends Exception { ...@@ -87,7 +87,7 @@ public class PrivilegedActionException extends Exception {
} }
/** /**
* Returns the the cause of this exception (the exception thrown by * Returns the cause of this exception (the exception thrown by
* the privileged computation that resulted in this * the privileged computation that resulted in this
* <code>PrivilegedActionException</code>). * <code>PrivilegedActionException</code>).
* *
......
...@@ -501,7 +501,7 @@ public final class Security { ...@@ -501,7 +501,7 @@ public final class Security {
* <li> <i>&lt;crypto_service>.&lt;algorithm_or_type> * <li> <i>&lt;crypto_service>.&lt;algorithm_or_type>
* &lt;attribute_name>:&lt attribute_value></i> * &lt;attribute_name>:&lt attribute_value></i>
* <p> The cryptographic service name must not contain any dots. There * <p> The cryptographic service name must not contain any dots. There
* must be one or more space charaters between the the * must be one or more space charaters between the
* <i>&lt;algorithm_or_type></i> and the <i>&lt;attribute_name></i>. * <i>&lt;algorithm_or_type></i> and the <i>&lt;attribute_name></i>.
* <p> A provider satisfies this selection criterion iff the * <p> A provider satisfies this selection criterion iff the
* provider implements the specified algorithm or type for the specified * provider implements the specified algorithm or type for the specified
......
...@@ -118,7 +118,7 @@ import java.util.StringTokenizer; ...@@ -118,7 +118,7 @@ import java.util.StringTokenizer;
* <td>setProperty.{key}</td> * <td>setProperty.{key}</td>
* <td>Setting of the security property with the specified key</td> * <td>Setting of the security property with the specified key</td>
* <td>This could include setting a security provider or defining * <td>This could include setting a security provider or defining
* the location of the the system-wide security policy. Malicious * the location of the system-wide security policy. Malicious
* code that has permission to set a new security provider may * code that has permission to set a new security provider may
* set a rogue provider that steals confidential information such * set a rogue provider that steals confidential information such
* as cryptographic private keys. In addition, malicious code with * as cryptographic private keys. In addition, malicious code with
......
...@@ -316,7 +316,7 @@ public abstract class SignatureSpi { ...@@ -316,7 +316,7 @@ public abstract class SignatureSpi {
* overridden by a provider * overridden by a provider
* *
* @exception InvalidAlgorithmParameterException if this method is * @exception InvalidAlgorithmParameterException if this method is
* overridden by a provider and the the given parameters * overridden by a provider and the given parameters
* are inappropriate for this signature engine * are inappropriate for this signature engine
*/ */
protected void engineSetParameter(AlgorithmParameterSpec params) protected void engineSetParameter(AlgorithmParameterSpec params)
......
...@@ -460,7 +460,7 @@ public class CertificateFactory { ...@@ -460,7 +460,7 @@ public class CertificateFactory {
* {@link java.io.InputStream#reset() reset}, this method will * {@link java.io.InputStream#reset() reset}, this method will
* consume the entire input stream. Otherwise, each call to this * consume the entire input stream. Otherwise, each call to this
* method consumes one CRL and the read position of the input stream * method consumes one CRL and the read position of the input stream
* is positioned to the next available byte after the the inherent * is positioned to the next available byte after the inherent
* end-of-CRL marker. If the data in the * end-of-CRL marker. If the data in the
* input stream does not contain an inherent end-of-CRL marker (other * input stream does not contain an inherent end-of-CRL marker (other
* than EOF) and there is trailing data after the CRL is parsed, a * than EOF) and there is trailing data after the CRL is parsed, a
......
...@@ -88,7 +88,7 @@ public abstract class CertificateFactorySpi { ...@@ -88,7 +88,7 @@ public abstract class CertificateFactorySpi {
* {@link java.io.InputStream#reset() reset}, this method will * {@link java.io.InputStream#reset() reset}, this method will
* consume the entire input stream. Otherwise, each call to this * consume the entire input stream. Otherwise, each call to this
* method consumes one certificate and the read position of the input stream * method consumes one certificate and the read position of the input stream
* is positioned to the next available byte after the the inherent * is positioned to the next available byte after the inherent
* end-of-certificate marker. If the data in the * end-of-certificate marker. If the data in the
* input stream does not contain an inherent end-of-certificate marker (other * input stream does not contain an inherent end-of-certificate marker (other
* than EOF) and there is trailing data after the certificate is parsed, a * than EOF) and there is trailing data after the certificate is parsed, a
...@@ -261,7 +261,7 @@ public abstract class CertificateFactorySpi { ...@@ -261,7 +261,7 @@ public abstract class CertificateFactorySpi {
* {@link java.io.InputStream#reset() reset}, this method will * {@link java.io.InputStream#reset() reset}, this method will
* consume the entire input stream. Otherwise, each call to this * consume the entire input stream. Otherwise, each call to this
* method consumes one CRL and the read position of the input stream * method consumes one CRL and the read position of the input stream
* is positioned to the next available byte after the the inherent * is positioned to the next available byte after the inherent
* end-of-CRL marker. If the data in the * end-of-CRL marker. If the data in the
* input stream does not contain an inherent end-of-CRL marker (other * input stream does not contain an inherent end-of-CRL marker (other
* than EOF) and there is trailing data after the CRL is parsed, a * than EOF) and there is trailing data after the CRL is parsed, a
......
...@@ -41,9 +41,14 @@ package java.util; ...@@ -41,9 +41,14 @@ package java.util;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.Serializable; import java.io.Serializable;
import java.security.AccessControlContext;
import java.security.AccessController; import java.security.AccessController;
import java.security.PermissionCollection;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.DateFormatSymbols; import java.text.DateFormatSymbols;
import sun.util.BuddhistCalendar; import sun.util.BuddhistCalendar;
...@@ -2628,6 +2633,18 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca ...@@ -2628,6 +2633,18 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
} }
} }
private static class CalendarAccessControlContext {
private static final AccessControlContext INSTANCE;
static {
RuntimePermission perm = new RuntimePermission("accessClassInPackage.sun.util.calendar");
PermissionCollection perms = perm.newPermissionCollection();
perms.add(perm);
INSTANCE = new AccessControlContext(new ProtectionDomain[] {
new ProtectionDomain(null, perms)
});
}
}
/** /**
* Reconstitutes this object from a stream (i.e., deserialize it). * Reconstitutes this object from a stream (i.e., deserialize it).
*/ */
...@@ -2657,17 +2674,30 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca ...@@ -2657,17 +2674,30 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
serialVersionOnStream = currentSerialVersion; serialVersionOnStream = currentSerialVersion;
// If there's a ZoneInfo object, use it for zone. // If there's a ZoneInfo object, use it for zone.
ZoneInfo zi = null;
try { try {
ZoneInfo zi = (ZoneInfo) AccessController.doPrivileged( zi = AccessController.doPrivileged(
new PrivilegedExceptionAction() { new PrivilegedExceptionAction<ZoneInfo>() {
public Object run() throws Exception { public ZoneInfo run() throws Exception {
return input.readObject(); return (ZoneInfo) input.readObject();
} }
}); },
if (zi != null) { CalendarAccessControlContext.INSTANCE);
zone = zi; } catch (PrivilegedActionException pae) {
Exception e = pae.getException();
if (!(e instanceof OptionalDataException)) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
} else if (e instanceof IOException) {
throw (IOException) e;
} else if (e instanceof ClassNotFoundException) {
throw (ClassNotFoundException) e;
}
throw new RuntimeException(e);
} }
} catch (Exception e) { }
if (zi != null) {
zone = zi;
} }
// If the deserialized object has a SimpleTimeZone, try to // If the deserialized object has a SimpleTimeZone, try to
...@@ -2676,9 +2706,9 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca ...@@ -2676,9 +2706,9 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
// implementation as much as possible. // implementation as much as possible.
if (zone instanceof SimpleTimeZone) { if (zone instanceof SimpleTimeZone) {
String id = zone.getID(); String id = zone.getID();
TimeZone zi = TimeZone.getTimeZone(id); TimeZone tz = TimeZone.getTimeZone(id);
if (zi != null && zi.hasSameRules(zone) && zi.getID().equals(id)) { if (tz != null && tz.hasSameRules(zone) && tz.getID().equals(id)) {
zone = zi; zone = tz;
} }
} }
} }
......
/*
* Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package java.util.zip;
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
*/
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 CharsetDecoder dec;
private CharsetEncoder enc;
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);
}
private CharsetDecoder decoder() {
if (dec == null) {
dec = cs.newDecoder()
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT);
}
return dec;
}
private CharsetEncoder encoder() {
if (enc == null) {
enc = cs.newEncoder()
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT);
}
return enc;
}
}
...@@ -73,5 +73,12 @@ class ZipConstants64 { ...@@ -73,5 +73,12 @@ class ZipConstants64 {
static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte
static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte
/*
* Language encoding flag EFS
*/
static final int EFS = 0x800; // If this bit is set the filename and
// comment fields for this file must be
// encoded using UTF-8.
private ZipConstants64() {} private ZipConstants64() {}
} }
...@@ -40,6 +40,7 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -40,6 +40,7 @@ class ZipEntry implements ZipConstants, Cloneable {
long size = -1; // uncompressed size of entry data long size = -1; // uncompressed size of entry data
long csize = -1; // compressed size of entry data long csize = -1; // compressed size of entry data
int method = -1; // compression method int method = -1; // compression method
int flag = 0; // general purpose flag
byte[] extra; // optional extra field data for entry byte[] extra; // optional extra field data for entry
String comment; // optional comment string for entry String comment; // optional comment string for entry
...@@ -53,13 +54,6 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -53,13 +54,6 @@ class ZipEntry implements ZipConstants, Cloneable {
*/ */
public static final int DEFLATED = 8; public static final int DEFLATED = 8;
static {
/* Zip library is loaded from System.initializeSystemClass */
initIDs();
}
private static native void initIDs();
/** /**
* Creates a new zip entry with the specified name. * Creates a new zip entry with the specified name.
* *
...@@ -90,28 +84,15 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -90,28 +84,15 @@ class ZipEntry implements ZipConstants, Cloneable {
size = e.size; size = e.size;
csize = e.csize; csize = e.csize;
method = e.method; method = e.method;
flag = e.flag;
extra = e.extra; extra = e.extra;
comment = e.comment; comment = e.comment;
} }
/* /*
* Creates a new zip entry for the given name with fields initialized * Creates a new un-initialized zip entry
* from the specified jzentry data.
*/ */
ZipEntry(String name, long jzentry) { ZipEntry() {}
this.name = name;
initFields(jzentry);
}
private native void initFields(long jzentry);
/*
* Creates a new zip entry with fields initialized from the specified
* jzentry data.
*/
ZipEntry(long jzentry) {
initFields(jzentry);
}
/** /**
* Returns the name of the entry. * Returns the name of the entry.
...@@ -258,16 +239,16 @@ class ZipEntry implements ZipConstants, Cloneable { ...@@ -258,16 +239,16 @@ class ZipEntry implements ZipConstants, Cloneable {
/** /**
* Sets the optional comment string for the entry. * Sets the optional comment string for the entry.
*
* <p>ZIP entry comments have maximum length of 0xffff. If the length of the
* specified comment string is greater than 0xFFFF bytes after encoding, only
* the first 0xFFFF bytes are output to the ZIP file entry.
*
* @param comment the comment string * @param comment the comment string
* @exception IllegalArgumentException if the length of the specified *
* comment string is greater than 0xFFFF bytes
* @see #getComment() * @see #getComment()
*/ */
public void setComment(String comment) { public void setComment(String comment) {
if (comment != null && comment.length() > 0xffff/3
&& ZipOutputStream.getUTF8Length(comment) > 0xffff) {
throw new IllegalArgumentException("invalid entry comment length");
}
this.comment = comment; this.comment = comment;
} }
......
...@@ -29,9 +29,11 @@ import java.io.InputStream; ...@@ -29,9 +29,11 @@ import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
import java.io.EOFException; import java.io.EOFException;
import java.io.File; import java.io.File;
import java.nio.charset.Charset;
import java.util.Vector; import java.util.Vector;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import static java.util.zip.ZipConstants64.*;
/** /**
* This class is used to read entries from a zip file. * This class is used to read entries from a zip file.
...@@ -76,16 +78,19 @@ class ZipFile implements ZipConstants { ...@@ -76,16 +78,19 @@ class ZipFile implements ZipConstants {
/** /**
* Opens a zip file for reading. * Opens a zip file for reading.
* *
* <p>First, if there is a security * <p>First, if there is a security manager, its <code>checkRead</code>
* manager, its <code>checkRead</code> method * method is called with the <code>name</code> argument as its argument
* is called with the <code>name</code> argument * to ensure the read is allowed.
* as its argument to ensure the read is allowed. *
* <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
* decode the entry names and comments.
* *
* @param name the name of the zip file * @param name the name of the zip file
* @throws ZipException if a ZIP format error has occurred * @throws ZipException if a ZIP format error has occurred
* @throws IOException if an I/O error has occurred * @throws IOException if an I/O error has occurred
* @throws SecurityException if a security manager exists and its * @throws SecurityException if a security manager exists and its
* <code>checkRead</code> method doesn't allow read access to the file. * <code>checkRead</code> method doesn't allow read access to the file.
*
* @see SecurityManager#checkRead(java.lang.String) * @see SecurityManager#checkRead(java.lang.String)
*/ */
public ZipFile(String name) throws IOException { public ZipFile(String name) throws IOException {
...@@ -101,6 +106,9 @@ class ZipFile implements ZipConstants { ...@@ -101,6 +106,9 @@ class ZipFile implements ZipConstants {
* method is called with the <code>name</code> argument as its argument to * method is called with the <code>name</code> argument as its argument to
* ensure the read is allowed. * ensure the read is allowed.
* *
* <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
* decode the entry names and comments
*
* @param file the ZIP file to be opened for reading * @param file the ZIP file to be opened for reading
* @param mode the mode in which the file is to be opened * @param mode the mode in which the file is to be opened
* @throws ZipException if a ZIP format error has occurred * @throws ZipException if a ZIP format error has occurred
...@@ -115,6 +123,59 @@ class ZipFile implements ZipConstants { ...@@ -115,6 +123,59 @@ class ZipFile implements ZipConstants {
* @since 1.3 * @since 1.3
*/ */
public ZipFile(File file, int mode) throws IOException { public ZipFile(File file, int mode) throws IOException {
this(file, mode, Charset.forName("UTF-8"));
}
/**
* Opens a ZIP file for reading given the specified File object.
*
* <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
* decode the entry names and comments.
*
* @param file the ZIP file to be opened for reading
* @throws ZipException if a ZIP format error has occurred
* @throws IOException if an I/O error has occurred
*/
public ZipFile(File file) throws ZipException, IOException {
this(file, OPEN_READ);
}
private ZipCoder zc;
/**
* Opens a new <code>ZipFile</code> to read from the specified
* <code>File</code> object in the specified mode. The mode argument
* must be either <tt>OPEN_READ</tt> or <tt>OPEN_READ | OPEN_DELETE</tt>.
*
* <p>First, if there is a security manager, its <code>checkRead</code>
* method is called with the <code>name</code> argument as its argument to
* ensure the read is allowed.
*
* @param file the ZIP file to be opened for reading
* @param mode the mode in which the file is to be opened
* @param charset
* the {@link java.nio.charset.Charset {@code charset}} to
* be used to decode the ZIP entry name and comment that are not
* encoded by using UTF-8 encoding (indicated by entry's general
* purpose flag).
*
* @throws ZipException if a ZIP format error has occurred
* @throws IOException if an I/O error has occurred
*
* @throws SecurityException
* if a security manager exists and its <code>checkRead</code>
* method doesn't allow read access to the file,or its
* <code>checkDelete</code> method doesn't allow deleting the
* file when the <tt>OPEN_DELETE</tt> flag is set
*
* @throws IllegalArgumentException if the <tt>mode</tt> argument is invalid
*
* @see SecurityManager#checkRead(java.lang.String)
*
* @since 1.7
*/
public ZipFile(File file, int mode, Charset charset) throws IOException
{
if (((mode & OPEN_READ) == 0) || if (((mode & OPEN_READ) == 0) ||
((mode & ~(OPEN_READ | OPEN_DELETE)) != 0)) { ((mode & ~(OPEN_READ | OPEN_DELETE)) != 0)) {
throw new IllegalArgumentException("Illegal mode: 0x"+ throw new IllegalArgumentException("Illegal mode: 0x"+
...@@ -128,24 +189,61 @@ class ZipFile implements ZipConstants { ...@@ -128,24 +189,61 @@ class ZipFile implements ZipConstants {
sm.checkDelete(name); sm.checkDelete(name);
} }
} }
if (charset == null)
throw new NullPointerException("charset is null");
this.zc = ZipCoder.get(charset);
jzfile = open(name, mode, file.lastModified()); jzfile = open(name, mode, file.lastModified());
this.name = name; this.name = name;
this.total = getTotal(jzfile); this.total = getTotal(jzfile);
} }
private static native long open(String name, int mode, long lastModified); /**
private static native int getTotal(long jzfile); * Opens a zip file for reading.
*
* <p>First, if there is a security manager, its <code>checkRead</code>
* method is called with the <code>name</code> argument as its argument
* to ensure the read is allowed.
*
* @param name the name of the zip file
* @param charset
* the {@link java.nio.charset.Charset {@code charset}} to
* be used to decode the ZIP entry name and comment that are not
* encoded by using UTF-8 encoding (indicated by entry's general
* purpose flag).
*
* @throws ZipException if a ZIP format error has occurred
* @throws IOException if an I/O error has occurred
* @throws SecurityException
* if a security manager exists and its <code>checkRead</code>
* method doesn't allow read access to the file
*
* @see SecurityManager#checkRead(java.lang.String)
*
* @since 1.7
*/
public ZipFile(String name, Charset charset) throws IOException
{
this(new File(name), OPEN_READ, charset);
}
/** /**
* Opens a ZIP file for reading given the specified File object. * Opens a ZIP file for reading given the specified File object.
* @param file the ZIP file to be opened for reading * @param file the ZIP file to be opened for reading
* @throws ZipException if a ZIP error has occurred * @param charset
* The {@link java.nio.charset.Charset {@code charset}} to be
* used to decode the ZIP entry name and comment (ignored if
* the <a href="package-summary.html#lang_encoding"> language
* encoding bit</a> of the ZIP entry's general purpose bit
* flag is set).
*
* @throws ZipException if a ZIP format error has occurred
* @throws IOException if an I/O error has occurred * @throws IOException if an I/O error has occurred
*
* @since 1.7
*/ */
public ZipFile(File file) throws ZipException, IOException { public ZipFile(File file, Charset charset) throws IOException
this(file, OPEN_READ); {
this(file, OPEN_READ, charset);
} }
/** /**
...@@ -163,9 +261,9 @@ class ZipFile implements ZipConstants { ...@@ -163,9 +261,9 @@ class ZipFile implements ZipConstants {
long jzentry = 0; long jzentry = 0;
synchronized (this) { synchronized (this) {
ensureOpen(); ensureOpen();
jzentry = getEntry(jzfile, name, true); jzentry = getEntry(jzfile, zc.getBytes(name), true);
if (jzentry != 0) { if (jzentry != 0) {
ZipEntry ze = new ZipEntry(name, jzentry); ZipEntry ze = getZipEntry(name, jzentry);
freeEntry(jzfile, jzentry); freeEntry(jzfile, jzentry);
return ze; return ze;
} }
...@@ -173,7 +271,7 @@ class ZipFile implements ZipConstants { ...@@ -173,7 +271,7 @@ class ZipFile implements ZipConstants {
return null; return null;
} }
private static native long getEntry(long jzfile, String name, private static native long getEntry(long jzfile, byte[] name,
boolean addSlash); boolean addSlash);
// freeEntry releases the C jzentry struct. // freeEntry releases the C jzentry struct.
...@@ -194,36 +292,30 @@ class ZipFile implements ZipConstants { ...@@ -194,36 +292,30 @@ class ZipFile implements ZipConstants {
* @throws IllegalStateException if the zip file has been closed * @throws IllegalStateException if the zip file has been closed
*/ */
public InputStream getInputStream(ZipEntry entry) throws IOException { public InputStream getInputStream(ZipEntry entry) throws IOException {
return getInputStream(entry.name); if (entry == null) {
} throw new NullPointerException("entry");
/**
* Returns an input stream for reading the contents of the specified
* entry, or null if the entry was not found.
*/
private InputStream getInputStream(String name) throws IOException {
if (name == null) {
throw new NullPointerException("name");
} }
long jzentry = 0; long jzentry = 0;
ZipFileInputStream in = null; ZipFileInputStream in = null;
synchronized (this) { synchronized (this) {
ensureOpen(); ensureOpen();
jzentry = getEntry(jzfile, name, false); if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
jzentry = getEntry(jzfile, zc.getBytesUTF8(entry.name), false);
} else {
jzentry = getEntry(jzfile, zc.getBytes(entry.name), false);
}
if (jzentry == 0) { if (jzentry == 0) {
return null; return null;
} }
in = new ZipFileInputStream(jzentry); in = new ZipFileInputStream(jzentry);
} }
final ZipFileInputStream zfin = in; final ZipFileInputStream zfin = in;
switch (getMethod(jzentry)) { switch (getEntryMethod(jzentry)) {
case STORED: case STORED:
return zfin; return zfin;
case DEFLATED: case DEFLATED:
// MORE: Compute good size for inflater stream: // MORE: Compute good size for inflater stream:
long size = getSize(jzentry) + 2; // Inflater likes a bit of slack long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack
if (size > 65536) size = 8192; if (size > 65536) size = 8192;
if (size <= 0) size = 4096; if (size <= 0) size = 4096;
return new InflaterInputStream(zfin, getInflater(), (int)size) { return new InflaterInputStream(zfin, getInflater(), (int)size) {
...@@ -267,8 +359,6 @@ class ZipFile implements ZipConstants { ...@@ -267,8 +359,6 @@ class ZipFile implements ZipConstants {
} }
} }
private static native int getMethod(long jzentry);
/* /*
* Gets an inflater from the list of available inflaters or allocates * Gets an inflater from the list of available inflaters or allocates
* a new one. * a new one.
...@@ -343,7 +433,7 @@ class ZipFile implements ZipConstants { ...@@ -343,7 +433,7 @@ class ZipFile implements ZipConstants {
",\n message = " + message ",\n message = " + message
); );
} }
ZipEntry ze = new ZipEntry(jzentry); ZipEntry ze = getZipEntry(null, jzentry);
freeEntry(jzfile, jzentry); freeEntry(jzfile, jzentry);
return ze; return ze;
} }
...@@ -351,6 +441,38 @@ class ZipFile implements ZipConstants { ...@@ -351,6 +441,38 @@ class ZipFile implements ZipConstants {
}; };
} }
private ZipEntry getZipEntry(String name, long jzentry) {
ZipEntry e = new ZipEntry();
e.flag = getEntryFlag(jzentry); // get the flag first
if (name != null) {
e.name = name;
} else {
byte[] bname = getEntryBytes(jzentry, JZENTRY_NAME);
if (!zc.isUTF8() && (e.flag & EFS) != 0) {
e.name = zc.toStringUTF8(bname, bname.length);
} else {
e.name = zc.toString(bname, bname.length);
}
}
e.time = getEntryTime(jzentry);
e.crc = getEntryCrc(jzentry);
e.size = getEntrySize(jzentry);
e. csize = getEntryCSize(jzentry);
e.method = getEntryMethod(jzentry);
e.extra = getEntryBytes(jzentry, JZENTRY_EXTRA);
byte[] bcomm = getEntryBytes(jzentry, JZENTRY_COMMENT);
if (bcomm == null) {
e.comment = null;
} else {
if (!zc.isUTF8() && (e.flag & EFS) != 0) {
e.comment = zc.toStringUTF8(bcomm, bcomm.length);
} else {
e.comment = zc.toString(bcomm, bcomm.length);
}
}
return e;
}
private static native long getNextEntry(long jzfile, int i); private static native long getNextEntry(long jzfile, int i);
/** /**
...@@ -443,8 +565,8 @@ class ZipFile implements ZipConstants { ...@@ -443,8 +565,8 @@ class ZipFile implements ZipConstants {
ZipFileInputStream(long jzentry) { ZipFileInputStream(long jzentry) {
pos = 0; pos = 0;
rem = getCSize(jzentry); rem = getEntryCSize(jzentry);
size = getSize(jzentry); size = getEntrySize(jzentry);
this.jzentry = jzentry; this.jzentry = jzentry;
} }
...@@ -514,13 +636,25 @@ class ZipFile implements ZipConstants { ...@@ -514,13 +636,25 @@ class ZipFile implements ZipConstants {
} }
private static native long open(String name, int mode, long lastModified)
throws IOException;
private static native int getTotal(long jzfile);
private static native int read(long jzfile, long jzentry, private static native int read(long jzfile, long jzentry,
long pos, byte[] b, int off, int len); long pos, byte[] b, int off, int len);
private static native long getCSize(long jzentry); // access to the native zentry object
private static native long getEntryTime(long jzentry);
private static native long getEntryCrc(long jzentry);
private static native long getEntryCSize(long jzentry);
private static native long getEntrySize(long jzentry);
private static native int getEntryMethod(long jzentry);
private static native int getEntryFlag(long jzentry);
private static native long getSize(long jzentry); private static final int JZENTRY_NAME = 0;
private static final int JZENTRY_EXTRA = 1;
private static final int JZENTRY_COMMENT = 2;
private static native byte[] getEntryBytes(long jzentry, int type);
// Temporary add on for bug troubleshooting
private static native String getZipMessage(long jzfile); private static native String getZipMessage(long jzfile);
} }
...@@ -29,6 +29,7 @@ import java.io.InputStream; ...@@ -29,6 +29,7 @@ import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
import java.io.EOFException; import java.io.EOFException;
import java.io.PushbackInputStream; import java.io.PushbackInputStream;
import java.nio.charset.Charset;
import static java.util.zip.ZipConstants64.*; import static java.util.zip.ZipConstants64.*;
/** /**
...@@ -54,6 +55,8 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { ...@@ -54,6 +55,8 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
// one entry // one entry
private boolean entryEOF = false; private boolean entryEOF = false;
private ZipCoder zc;
/** /**
* Check to make sure that this stream has not been closed * Check to make sure that this stream has not been closed
*/ */
...@@ -65,14 +68,39 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { ...@@ -65,14 +68,39 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
/** /**
* Creates a new ZIP input stream. * Creates a new ZIP input stream.
*
* <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
* decode the entry names.
*
* @param in the actual input stream * @param in the actual input stream
*/ */
public ZipInputStream(InputStream in) { public ZipInputStream(InputStream in) {
this(in, Charset.forName("UTF-8"));
}
/**
* Creates a new ZIP input stream.
*
* @param in the actual input stream
*
* @param charset
* The {@link java.nio.charset.Charset {@code charset}} to be
* used to decode the ZIP entry name (ignored if the
* <a href="package-summary.html#lang_encoding"> language
* encoding bit</a> of the ZIP entry's general purpose bit
* flag is set).
*
* @since 1.7
*/
public ZipInputStream(InputStream in, Charset charset) {
super(new PushbackInputStream(in, 512), new Inflater(true), 512); super(new PushbackInputStream(in, 512), new Inflater(true), 512);
usesDefaultInflater = true; usesDefaultInflater = true;
if(in == null) { if(in == null) {
throw new NullPointerException("in is null"); throw new NullPointerException("in is null");
} }
if (charset == null)
throw new NullPointerException("charset is null");
this.zc = ZipCoder.get(charset);
} }
/** /**
...@@ -141,8 +169,8 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { ...@@ -141,8 +169,8 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
* @param len the maximum number of bytes read * @param len the maximum number of bytes read
* @return the actual number of bytes read, or -1 if the end of the * @return the actual number of bytes read, or -1 if the end of the
* entry is reached * entry is reached
* @exception NullPointerException If <code>b</code> is <code>null</code>. * @exception NullPointerException if <code>b</code> is <code>null</code>.
* @exception IndexOutOfBoundsException If <code>off</code> is negative, * @exception IndexOutOfBoundsException if <code>off</code> is negative,
* <code>len</code> is negative, or <code>len</code> is greater than * <code>len</code> is negative, or <code>len</code> is greater than
* <code>b.length - off</code> * <code>b.length - off</code>
* @exception ZipException if a ZIP file error has occurred * @exception ZipException if a ZIP file error has occurred
...@@ -252,6 +280,8 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { ...@@ -252,6 +280,8 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
if (get32(tmpbuf, 0) != LOCSIG) { if (get32(tmpbuf, 0) != LOCSIG) {
return null; return null;
} }
// get flag first, we need check EFS.
flag = get16(tmpbuf, LOCFLG);
// get the entry name and create the ZipEntry first // get the entry name and create the ZipEntry first
int len = get16(tmpbuf, LOCNAM); int len = get16(tmpbuf, LOCNAM);
int blen = b.length; int blen = b.length;
...@@ -262,9 +292,11 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { ...@@ -262,9 +292,11 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
b = new byte[blen]; b = new byte[blen];
} }
readFully(b, 0, len); readFully(b, 0, len);
ZipEntry e = createZipEntry(getUTF8String(b, 0, len)); // Force to use UTF-8 if the EFS bit is ON, even the cs is NOT UTF-8
ZipEntry e = createZipEntry(((flag & EFS) != 0)
? zc.toStringUTF8(b, len)
: zc.toString(b, len));
// now get the remaining fields for the entry // now get the remaining fields for the entry
flag = get16(tmpbuf, LOCFLG);
if ((flag & 1) == 1) { if ((flag & 1) == 1) {
throw new ZipException("encrypted ZIP entry not supported"); throw new ZipException("encrypted ZIP entry not supported");
} }
...@@ -313,71 +345,6 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants { ...@@ -313,71 +345,6 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
return e; return e;
} }
/*
* Fetches a UTF8-encoded String from the specified byte array.
*/
private static String getUTF8String(byte[] b, int off, int len) {
// First, count the number of characters in the sequence
int count = 0;
int max = off + len;
int i = off;
while (i < max) {
int c = b[i++] & 0xff;
switch (c >> 4) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
// 0xxxxxxx
count++;
break;
case 12: case 13:
// 110xxxxx 10xxxxxx
if ((b[i++] & 0xc0) != 0x80) {
throw new IllegalArgumentException();
}
count++;
break;
case 14:
// 1110xxxx 10xxxxxx 10xxxxxx
if (((b[i++] & 0xc0) != 0x80) ||
((b[i++] & 0xc0) != 0x80)) {
throw new IllegalArgumentException();
}
count++;
break;
default:
// 10xxxxxx, 1111xxxx
throw new IllegalArgumentException();
}
}
if (i != max) {
throw new IllegalArgumentException();
}
// Now decode the characters...
char[] cs = new char[count];
i = 0;
while (off < max) {
int c = b[off++] & 0xff;
switch (c >> 4) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
// 0xxxxxxx
cs[i++] = (char)c;
break;
case 12: case 13:
// 110xxxxx 10xxxxxx
cs[i++] = (char)(((c & 0x1f) << 6) | (b[off++] & 0x3f));
break;
case 14:
// 1110xxxx 10xxxxxx 10xxxxxx
int t = (b[off++] & 0x3f) << 6;
cs[i++] = (char)(((c & 0x0f) << 12) | t | (b[off++] & 0x3f));
break;
default:
// 10xxxxxx, 1111xxxx
throw new IllegalArgumentException();
}
}
return new String(cs, 0, count);
}
/** /**
* Creates a new <code>ZipEntry</code> object for the specified * Creates a new <code>ZipEntry</code> object for the specified
* entry name. * entry name.
......
...@@ -27,6 +27,7 @@ package java.util.zip; ...@@ -27,6 +27,7 @@ package java.util.zip;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Vector; import java.util.Vector;
import java.util.HashSet; import java.util.HashSet;
import static java.util.zip.ZipConstants64.*; import static java.util.zip.ZipConstants64.*;
...@@ -44,19 +45,9 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -44,19 +45,9 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
private static class XEntry { private static class XEntry {
public final ZipEntry entry; public final ZipEntry entry;
public final long offset; public final long offset;
public final int flag;
public XEntry(ZipEntry entry, long offset) { public XEntry(ZipEntry entry, long offset) {
this.entry = entry; this.entry = entry;
this.offset = offset; this.offset = offset;
this.flag = (entry.method == DEFLATED &&
(entry.size == -1 ||
entry.csize == -1 ||
entry.crc == -1))
// store size, compressed size, and crc-32 in data descriptor
// immediately following the compressed entry data
? 8
// store size, compressed size, and crc-32 in LOC header
: 0;
} }
} }
...@@ -66,12 +57,14 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -66,12 +57,14 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
private CRC32 crc = new CRC32(); private CRC32 crc = new CRC32();
private long written = 0; private long written = 0;
private long locoff = 0; private long locoff = 0;
private String comment; private byte[] comment;
private int method = DEFLATED; private int method = DEFLATED;
private boolean finished; private boolean finished;
private boolean closed = false; private boolean closed = false;
private final ZipCoder zc;
private static int version(ZipEntry e) throws ZipException { private static int version(ZipEntry e) throws ZipException {
switch (e.method) { switch (e.method) {
case DEFLATED: return 20; case DEFLATED: return 20;
...@@ -100,10 +93,31 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -100,10 +93,31 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
/** /**
* Creates a new ZIP output stream. * Creates a new ZIP output stream.
*
* <p>The UTF-8 {@link java.nio.charset.Charset charset} is used
* to encode the entry names and comments.
*
* @param out the actual output stream * @param out the actual output stream
*/ */
public ZipOutputStream(OutputStream out) { public ZipOutputStream(OutputStream out) {
this(out, Charset.forName("UTF-8"));
}
/**
* Creates a new ZIP output stream.
*
* @param out the actual output stream
*
* @param charset the {@link java.nio.charset.Charset </code>charset<code>}
* to be used to encode the entry names and comments
*
* @since 1.7
*/
public ZipOutputStream(OutputStream out, Charset charset) {
super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true)); super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
if (charset == null)
throw new NullPointerException("charset is null");
this.zc = ZipCoder.get(charset);
usesDefaultDeflater = true; usesDefaultDeflater = true;
} }
...@@ -114,11 +128,11 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -114,11 +128,11 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
* ZIP file comment is greater than 0xFFFF bytes * ZIP file comment is greater than 0xFFFF bytes
*/ */
public void setComment(String comment) { public void setComment(String comment) {
if (comment != null && comment.length() > 0xffff/3 if (comment != null) {
&& getUTF8Length(comment) > 0xffff) { this.comment = zc.getBytes(comment);
throw new IllegalArgumentException("ZIP file comment too long."); if (this.comment.length > 0xffff)
throw new IllegalArgumentException("ZIP file comment too long.");
} }
this.comment = comment;
} }
/** /**
...@@ -167,8 +181,15 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -167,8 +181,15 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
if (e.method == -1) { if (e.method == -1) {
e.method = method; // use default method e.method = method; // use default method
} }
// store size, compressed size, and crc-32 in LOC header
e.flag = 0;
switch (e.method) { switch (e.method) {
case DEFLATED: case DEFLATED:
// store size, compressed size, and crc-32 in data descriptor
// immediately following the compressed entry data
if (e.size == -1 || e.csize == -1 || e.crc == -1)
e.flag = 8;
break; break;
case STORED: case STORED:
// compressed size, uncompressed size, and crc-32 must all be // compressed size, uncompressed size, and crc-32 must all be
...@@ -192,6 +213,8 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -192,6 +213,8 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
if (! names.add(e.name)) { if (! names.add(e.name)) {
throw new ZipException("duplicate entry: " + e.name); throw new ZipException("duplicate entry: " + e.name);
} }
if (zc.isUTF8())
e.flag |= EFS;
current = new XEntry(e, written); current = new XEntry(e, written);
xentries.add(current); xentries.add(current);
writeLOC(current); writeLOC(current);
...@@ -213,7 +236,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -213,7 +236,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
while (!def.finished()) { while (!def.finished()) {
deflate(); deflate();
} }
if ((current.flag & 8) == 0) { if ((e.flag & 8) == 0) {
// verify size, compressed size, and crc-32 settings // verify size, compressed size, and crc-32 settings
if (e.size != def.getBytesRead()) { if (e.size != def.getBytesRead()) {
throw new ZipException( throw new ZipException(
...@@ -343,11 +366,11 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -343,11 +366,11 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
*/ */
private void writeLOC(XEntry xentry) throws IOException { private void writeLOC(XEntry xentry) throws IOException {
ZipEntry e = xentry.entry; ZipEntry e = xentry.entry;
int flag = xentry.flag; int flag = e.flag;
int elen = (e.extra != null) ? e.extra.length : 0; int elen = (e.extra != null) ? e.extra.length : 0;
boolean hasZip64 = false; boolean hasZip64 = false;
writeInt(LOCSIG); // LOC header signature writeInt(LOCSIG); // LOC header signature
if ((flag & 8) == 8) { if ((flag & 8) == 8) {
writeShort(version(e)); // version needed to extract writeShort(version(e)); // version needed to extract
...@@ -380,7 +403,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -380,7 +403,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeInt(e.size); // uncompressed size writeInt(e.size); // uncompressed size
} }
} }
byte[] nameBytes = getUTF8Bytes(e.name); byte[] nameBytes = zc.getBytes(e.name);
writeShort(nameBytes.length); writeShort(nameBytes.length);
writeShort(elen); writeShort(elen);
writeBytes(nameBytes, 0, nameBytes.length); writeBytes(nameBytes, 0, nameBytes.length);
...@@ -417,7 +440,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -417,7 +440,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
*/ */
private void writeCEN(XEntry xentry) throws IOException { private void writeCEN(XEntry xentry) throws IOException {
ZipEntry e = xentry.entry; ZipEntry e = xentry.entry;
int flag = xentry.flag; int flag = e.flag;
int version = version(e); int version = version(e);
long csize = e.csize; long csize = e.csize;
...@@ -454,7 +477,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -454,7 +477,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeInt(e.crc); // crc-32 writeInt(e.crc); // crc-32
writeInt(csize); // compressed size writeInt(csize); // compressed size
writeInt(size); // uncompressed size writeInt(size); // uncompressed size
byte[] nameBytes = getUTF8Bytes(e.name); byte[] nameBytes = zc.getBytes(e.name);
writeShort(nameBytes.length); writeShort(nameBytes.length);
if (hasZip64) { if (hasZip64) {
// + headid(2) + datasize(2) // + headid(2) + datasize(2)
...@@ -464,8 +487,8 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -464,8 +487,8 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
} }
byte[] commentBytes; byte[] commentBytes;
if (e.comment != null) { if (e.comment != null) {
commentBytes = getUTF8Bytes(e.comment); commentBytes = zc.getBytes(e.comment);
writeShort(commentBytes.length); writeShort(Math.min(commentBytes.length, 0xffff));
} else { } else {
commentBytes = null; commentBytes = null;
writeShort(0); writeShort(0);
...@@ -489,7 +512,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -489,7 +512,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeBytes(e.extra, 0, e.extra.length); writeBytes(e.extra, 0, e.extra.length);
} }
if (commentBytes != null) { if (commentBytes != null) {
writeBytes(commentBytes, 0, commentBytes.length); writeBytes(commentBytes, 0, Math.min(commentBytes.length, 0xffff));
} }
} }
...@@ -541,9 +564,8 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -541,9 +564,8 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeInt(xlen); // length of central directory writeInt(xlen); // length of central directory
writeInt(xoff); // offset of central directory writeInt(xoff); // offset of central directory
if (comment != null) { // zip file comment if (comment != null) { // zip file comment
byte[] b = getUTF8Bytes(comment); writeShort(comment.length);
writeShort(b.length); writeBytes(comment, 0, comment.length);
writeBytes(b, 0, b.length);
} else { } else {
writeShort(0); writeShort(0);
} }
...@@ -594,60 +616,4 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -594,60 +616,4 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
super.out.write(b, off, len); super.out.write(b, off, len);
written += len; written += len;
} }
/*
* Returns the length of String's UTF8 encoding.
*/
static int getUTF8Length(String s) {
int count = 0;
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch <= 0x7f) {
count++;
} else if (ch <= 0x7ff) {
count += 2;
} else {
count += 3;
}
}
return count;
}
/*
* Returns an array of bytes representing the UTF8 encoding
* of the specified String.
*/
private static byte[] getUTF8Bytes(String s) {
char[] c = s.toCharArray();
int len = c.length;
// Count the number of encoded bytes...
int count = 0;
for (int i = 0; i < len; i++) {
int ch = c[i];
if (ch <= 0x7f) {
count++;
} else if (ch <= 0x7ff) {
count += 2;
} else {
count += 3;
}
}
// Now return the encoded bytes...
byte[] b = new byte[count];
int off = 0;
for (int i = 0; i < len; i++) {
int ch = c[i];
if (ch <= 0x7f) {
b[off++] = (byte)ch;
} else if (ch <= 0x7ff) {
b[off++] = (byte)((ch >> 6) | 0xc0);
b[off++] = (byte)((ch & 0x3f) | 0x80);
} else {
b[off++] = (byte)((ch >> 12) | 0xe0);
b[off++] = (byte)(((ch >> 6) & 0x3f) | 0x80);
b[off++] = (byte)((ch & 0x3f) | 0x80);
}
}
return b;
}
} }
...@@ -52,6 +52,11 @@ input streams. ...@@ -52,6 +52,11 @@ input streams.
<a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT"> <a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">
PKWARE ZIP File Format Specification</a>. The ZIP64(tm) format extensions PKWARE ZIP File Format Specification</a>. The ZIP64(tm) format extensions
are used to overcome the size limitations of the original ZIP format. are used to overcome the size limitations of the original ZIP format.
<p>
<a name="lang_encoding">
<li>APPENDIX D of <a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">
PKWARE ZIP File Format Specification</a> - Language Encoding Flag (EFS) to
encode ZIP entry filename and comment fields using UTF-8.
<p> <p>
<li><a href="http://www.isi.edu/in-notes/rfc1950.txt"> <li><a href="http://www.isi.edu/in-notes/rfc1950.txt">
ZLIB Compressed Data Format Specification version 3.3</a> ZLIB Compressed Data Format Specification version 3.3</a>
......
...@@ -599,7 +599,7 @@ public class CounterMonitor extends Monitor implements CounterMonitorMBean { ...@@ -599,7 +599,7 @@ public class CounterMonitor extends Monitor implements CounterMonitorMBean {
*/ */
@Override @Override
public MBeanNotificationInfo[] getNotificationInfo() { public MBeanNotificationInfo[] getNotificationInfo() {
return notifsInfo; return notifsInfo.clone();
} }
/* /*
......
...@@ -481,7 +481,7 @@ public class GaugeMonitor extends Monitor implements GaugeMonitorMBean { ...@@ -481,7 +481,7 @@ public class GaugeMonitor extends Monitor implements GaugeMonitorMBean {
*/ */
@Override @Override
public MBeanNotificationInfo[] getNotificationInfo() { public MBeanNotificationInfo[] getNotificationInfo() {
return notifsInfo; return notifsInfo.clone();
} }
/* /*
......
...@@ -32,7 +32,10 @@ import java.io.IOException; ...@@ -32,7 +32,10 @@ import java.io.IOException;
import java.security.AccessControlContext; import java.security.AccessControlContext;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
...@@ -163,7 +166,10 @@ public abstract class Monitor ...@@ -163,7 +166,10 @@ public abstract class Monitor
/** /**
* AccessControlContext of the Monitor.start() caller. * AccessControlContext of the Monitor.start() caller.
*/ */
private AccessControlContext acc; private static final AccessControlContext noPermissionsACC =
new AccessControlContext(
new ProtectionDomain[] {new ProtectionDomain(null, null)});
private volatile AccessControlContext acc = noPermissionsACC;
/** /**
* Scheduler Service. * Scheduler Service.
...@@ -173,14 +179,20 @@ public abstract class Monitor ...@@ -173,14 +179,20 @@ public abstract class Monitor
new DaemonThreadFactory("Scheduler")); new DaemonThreadFactory("Scheduler"));
/** /**
* Maximum Pool Size * Map containing the thread pool executor per thread group.
*/ */
private static final int maximumPoolSize; private static final Map<ThreadPoolExecutor, Void> executors =
new WeakHashMap<ThreadPoolExecutor, Void>();
/**
* Lock for executors map.
*/
private static final Object executorsLock = new Object();
/** /**
* Executor Service. * Maximum Pool Size
*/ */
private static final ThreadPoolExecutor executor; private static final int maximumPoolSize;
static { static {
final String maximumPoolSizeSysProp = "jmx.x.monitor.maximum.pool.size"; final String maximumPoolSizeSysProp = "jmx.x.monitor.maximum.pool.size";
final String maximumPoolSizeStr = AccessController.doPrivileged( final String maximumPoolSizeStr = AccessController.doPrivileged(
...@@ -210,21 +222,8 @@ public abstract class Monitor ...@@ -210,21 +222,8 @@ public abstract class Monitor
maximumPoolSize = maximumPoolSizeTmp; maximumPoolSize = maximumPoolSizeTmp;
} }
} }
executor = new ThreadPoolExecutor(
maximumPoolSize,
maximumPoolSize,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(),
new DaemonThreadFactory("Executor"));
executor.allowCoreThreadTimeOut(true);
} }
/**
* Monitor task to be executed by the Executor Service.
*/
private final MonitorTask monitorTask = new MonitorTask();
/** /**
* Future associated to the current monitor task. * Future associated to the current monitor task.
*/ */
...@@ -233,7 +232,7 @@ public abstract class Monitor ...@@ -233,7 +232,7 @@ public abstract class Monitor
/** /**
* Scheduler task to be executed by the Scheduler Service. * Scheduler task to be executed by the Scheduler Service.
*/ */
private final SchedulerTask schedulerTask = new SchedulerTask(monitorTask); private final SchedulerTask schedulerTask = new SchedulerTask();
/** /**
* ScheduledFuture associated to the current scheduler task. * ScheduledFuture associated to the current scheduler task.
...@@ -719,6 +718,7 @@ public abstract class Monitor ...@@ -719,6 +718,7 @@ public abstract class Monitor
// Start the scheduler. // Start the scheduler.
// //
cleanupFutures(); cleanupFutures();
schedulerTask.setMonitorTask(new MonitorTask());
schedulerFuture = scheduler.schedule(schedulerTask, schedulerFuture = scheduler.schedule(schedulerTask,
getGranularityPeriod(), getGranularityPeriod(),
TimeUnit.MILLISECONDS); TimeUnit.MILLISECONDS);
...@@ -748,7 +748,7 @@ public abstract class Monitor ...@@ -748,7 +748,7 @@ public abstract class Monitor
// Reset the AccessControlContext. // Reset the AccessControlContext.
// //
acc = null; acc = noPermissionsACC;
// Reset the complex type attribute information // Reset the complex type attribute information
// such that it is recalculated again. // such that it is recalculated again.
...@@ -1467,7 +1467,7 @@ public abstract class Monitor ...@@ -1467,7 +1467,7 @@ public abstract class Monitor
*/ */
private class SchedulerTask implements Runnable { private class SchedulerTask implements Runnable {
private Runnable task = null; private MonitorTask task;
/* /*
* ------------------------------------------ * ------------------------------------------
...@@ -1475,7 +1475,16 @@ public abstract class Monitor ...@@ -1475,7 +1475,16 @@ public abstract class Monitor
* ------------------------------------------ * ------------------------------------------
*/ */
public SchedulerTask(Runnable task) { public SchedulerTask() {
}
/*
* ------------------------------------------
* GETTERS/SETTERS
* ------------------------------------------
*/
public void setMonitorTask(MonitorTask task) {
this.task = task; this.task = task;
} }
...@@ -1487,7 +1496,7 @@ public abstract class Monitor ...@@ -1487,7 +1496,7 @@ public abstract class Monitor
public void run() { public void run() {
synchronized (Monitor.this) { synchronized (Monitor.this) {
Monitor.this.monitorFuture = executor.submit(task); Monitor.this.monitorFuture = task.submit();
} }
} }
} }
...@@ -1500,6 +1509,8 @@ public abstract class Monitor ...@@ -1500,6 +1509,8 @@ public abstract class Monitor
*/ */
private class MonitorTask implements Runnable { private class MonitorTask implements Runnable {
private ThreadPoolExecutor executor;
/* /*
* ------------------------------------------ * ------------------------------------------
* CONSTRUCTORS * CONSTRUCTORS
...@@ -1507,6 +1518,38 @@ public abstract class Monitor ...@@ -1507,6 +1518,38 @@ public abstract class Monitor
*/ */
public MonitorTask() { public MonitorTask() {
// Find out if there's already an existing executor for the calling
// thread and reuse it. Otherwise, create a new one and store it in
// the executors map. If there is a SecurityManager, the group of
// System.getSecurityManager() is used, else the group of the thread
// instantiating this MonitorTask, i.e. the group of the thread that
// calls "Monitor.start()".
SecurityManager s = System.getSecurityManager();
ThreadGroup group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
synchronized (executorsLock) {
for (ThreadPoolExecutor e : executors.keySet()) {
DaemonThreadFactory tf =
(DaemonThreadFactory) e.getThreadFactory();
ThreadGroup tg = tf.getThreadGroup();
if (tg == group) {
executor = e;
break;
}
}
if (executor == null) {
executor = new ThreadPoolExecutor(
maximumPoolSize,
maximumPoolSize,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(),
new DaemonThreadFactory("ThreadGroup<" +
group.getName() + "> Executor", group));
executor.allowCoreThreadTimeOut(true);
executors.put(executor, null);
}
}
} }
/* /*
...@@ -1515,12 +1558,18 @@ public abstract class Monitor ...@@ -1515,12 +1558,18 @@ public abstract class Monitor
* ------------------------------------------ * ------------------------------------------
*/ */
public Future<?> submit() {
return executor.submit(this);
}
public void run() { public void run() {
final ScheduledFuture<?> sf; final ScheduledFuture<?> sf;
final AccessControlContext ac;
synchronized (Monitor.this) { synchronized (Monitor.this) {
sf = Monitor.this.schedulerFuture; sf = Monitor.this.schedulerFuture;
ac = Monitor.this.acc;
} }
AccessController.doPrivileged(new PrivilegedAction<Void>() { PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
public Void run() { public Void run() {
if (Monitor.this.isActive()) { if (Monitor.this.isActive()) {
final int an[] = alreadyNotifieds; final int an[] = alreadyNotifieds;
...@@ -1533,7 +1582,11 @@ public abstract class Monitor ...@@ -1533,7 +1582,11 @@ public abstract class Monitor
} }
return null; return null;
} }
}, Monitor.this.acc); };
if (ac == null) {
throw new SecurityException("AccessControlContext cannot be null");
}
AccessController.doPrivileged(action, ac);
synchronized (Monitor.this) { synchronized (Monitor.this) {
if (Monitor.this.isActive() && if (Monitor.this.isActive() &&
Monitor.this.schedulerFuture == sf) { Monitor.this.schedulerFuture == sf) {
...@@ -1573,6 +1626,15 @@ public abstract class Monitor ...@@ -1573,6 +1626,15 @@ public abstract class Monitor
namePrefix = "JMX Monitor " + poolName + " Pool [Thread-"; namePrefix = "JMX Monitor " + poolName + " Pool [Thread-";
} }
public DaemonThreadFactory(String poolName, ThreadGroup threadGroup) {
group = threadGroup;
namePrefix = "JMX Monitor " + poolName + " Pool [Thread-";
}
public ThreadGroup getThreadGroup() {
return group;
}
public Thread newThread(Runnable r) { public Thread newThread(Runnable r) {
Thread t = new Thread(group, Thread t = new Thread(group,
r, r,
......
...@@ -184,6 +184,7 @@ public class StringMonitor extends Monitor implements StringMonitorMBean { ...@@ -184,6 +184,7 @@ public class StringMonitor extends Monitor implements StringMonitorMBean {
* @return The derived gauge of the specified object. * @return The derived gauge of the specified object.
* *
*/ */
@Override
public synchronized String getDerivedGauge(ObjectName object) { public synchronized String getDerivedGauge(ObjectName object) {
return (String) super.getDerivedGauge(object); return (String) super.getDerivedGauge(object);
} }
...@@ -199,6 +200,7 @@ public class StringMonitor extends Monitor implements StringMonitorMBean { ...@@ -199,6 +200,7 @@ public class StringMonitor extends Monitor implements StringMonitorMBean {
* @return The derived gauge timestamp of the specified object. * @return The derived gauge timestamp of the specified object.
* *
*/ */
@Override
public synchronized long getDerivedGaugeTimeStamp(ObjectName object) { public synchronized long getDerivedGaugeTimeStamp(ObjectName object) {
return super.getDerivedGaugeTimeStamp(object); return super.getDerivedGaugeTimeStamp(object);
} }
...@@ -341,8 +343,9 @@ public class StringMonitor extends Monitor implements StringMonitorMBean { ...@@ -341,8 +343,9 @@ public class StringMonitor extends Monitor implements StringMonitorMBean {
* the Java class of the notification and the notification types sent by * the Java class of the notification and the notification types sent by
* the string monitor. * the string monitor.
*/ */
@Override
public MBeanNotificationInfo[] getNotificationInfo() { public MBeanNotificationInfo[] getNotificationInfo() {
return notifsInfo; return notifsInfo.clone();
} }
/* /*
......
...@@ -123,8 +123,10 @@ public class MediaSize extends Size2DSyntax implements Attribute { ...@@ -123,8 +123,10 @@ public class MediaSize extends Size2DSyntax implements Attribute {
if (x > y) { if (x > y) {
throw new IllegalArgumentException("X dimension > Y dimension"); throw new IllegalArgumentException("X dimension > Y dimension");
} }
mediaName = media; if (media != null && mediaMap.get(media) == null) {
mediaMap.put(mediaName, this); mediaName = media;
mediaMap.put(mediaName, this);
}
sizeVector.add(this); sizeVector.add(this);
} }
...@@ -147,8 +149,10 @@ public class MediaSize extends Size2DSyntax implements Attribute { ...@@ -147,8 +149,10 @@ public class MediaSize extends Size2DSyntax implements Attribute {
if (x > y) { if (x > y) {
throw new IllegalArgumentException("X dimension > Y dimension"); throw new IllegalArgumentException("X dimension > Y dimension");
} }
mediaName = media; if (media != null && mediaMap.get(media) == null) {
mediaMap.put(mediaName, this); mediaName = media;
mediaMap.put(mediaName, this);
}
sizeVector.add(this); sizeVector.add(this);
} }
......
...@@ -585,9 +585,16 @@ public class GifImageDecoder extends ImageDecoder { ...@@ -585,9 +585,16 @@ public class GifImageDecoder extends ImageDecoder {
System.out.print("Reading a " + width + " by " + height + " " + System.out.print("Reading a " + width + " by " + height + " " +
(interlace ? "" : "non-") + "interlaced image..."); (interlace ? "" : "non-") + "interlaced image...");
} }
int initCodeSize = ExtractByte(block, 9);
if (initCodeSize >= 12) {
if (verbose) {
System.out.println("Invalid initial code size: " +
initCodeSize);
}
return false;
}
boolean ret = parseImage(x, y, width, height, boolean ret = parseImage(x, y, width, height,
interlace, ExtractByte(block, 9), interlace, initCodeSize,
block, rasline, model); block, rasline, model);
if (!ret) { if (!ret) {
......
/* /*
* Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -23,83 +23,32 @@ ...@@ -23,83 +23,32 @@
* have any questions. * have any questions.
*/ */
/* package sun.font;
* Native method support for java.util.zip.ZipEntry
*/
#include <stdio.h>
#include <stdlib.h>
#include "jlong.h"
#include "jvm.h"
#include "jni.h"
#include "jni_util.h"
#include "zip_util.h"
#include "java_util_zip_ZipEntry.h" public class CreatedFontTracker {
#define DEFLATED 8 public static final int MAX_FILE_SIZE = 32 * 1024 * 1024;
#define STORED 0 public static final int MAX_TOTAL_BYTES = 10 * MAX_FILE_SIZE;
static jfieldID nameID;
static jfieldID timeID;
static jfieldID crcID;
static jfieldID sizeID;
static jfieldID csizeID;
static jfieldID methodID;
static jfieldID extraID;
static jfieldID commentID;
JNIEXPORT void JNICALL
Java_java_util_zip_ZipEntry_initIDs(JNIEnv *env, jclass cls)
{
nameID = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
timeID = (*env)->GetFieldID(env, cls, "time", "J");
crcID = (*env)->GetFieldID(env, cls, "crc", "J");
sizeID = (*env)->GetFieldID(env, cls, "size", "J");
csizeID = (*env)->GetFieldID(env, cls, "csize", "J");
methodID = (*env)->GetFieldID(env, cls, "method", "I");
extraID = (*env)->GetFieldID(env, cls, "extra", "[B");
commentID = (*env)->GetFieldID(env, cls, "comment", "Ljava/lang/String;");
}
JNIEXPORT void JNICALL static int numBytes;
Java_java_util_zip_ZipEntry_initFields(JNIEnv *env, jobject obj, jlong zentry) static CreatedFontTracker tracker;
{
jzentry *ze = jlong_to_ptr(zentry);
jstring name = (*env)->GetObjectField(env, obj, nameID);
if (name == 0) { public static synchronized CreatedFontTracker getTracker() {
name = (*env)->NewStringUTF(env, ze->name); if (tracker == null) {
if (name == 0) { tracker = new CreatedFontTracker();
return;
} }
(*env)->SetObjectField(env, obj, nameID, name); return tracker;
} }
(*env)->SetLongField(env, obj, timeID, (jlong)ze->time & 0xffffffffUL);
(*env)->SetLongField(env, obj, crcID, (jlong)ze->crc & 0xffffffffUL); public synchronized int getNumBytes() {
(*env)->SetLongField(env, obj, sizeID, (jlong)ze->size); return numBytes;
if (ze->csize == 0) {
(*env)->SetLongField(env, obj, csizeID, (jlong)ze->size);
(*env)->SetIntField(env, obj, methodID, STORED);
} else {
(*env)->SetLongField(env, obj, csizeID, (jlong)ze->csize);
(*env)->SetIntField(env, obj, methodID, DEFLATED);
} }
if (ze->extra != 0) {
unsigned char *bp = (unsigned char *)&ze->extra[0]; public synchronized void addBytes(int sz) {
jsize len = (bp[0] | (bp[1] << 8)); numBytes += sz;
jbyteArray extra = (*env)->NewByteArray(env, len);
if (extra == 0) {
return;
}
(*env)->SetByteArrayRegion(env, extra, 0, len, &ze->extra[2]);
(*env)->SetObjectField(env, obj, extraID, extra);
} }
if (ze->comment != 0) {
jstring comment = (*env)->NewStringUTF(env, ze->comment); public synchronized void subBytes(int sz) {
if (comment == 0) { numBytes -= sz;
return;
}
(*env)->SetObjectField(env, obj, commentID, comment);
} }
} }
/* /*
* Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -125,9 +125,9 @@ public abstract class FileFont extends PhysicalFont { ...@@ -125,9 +125,9 @@ public abstract class FileFont extends PhysicalFont {
return true; return true;
} }
void setFileToRemove(File file) { void setFileToRemove(File file, CreatedFontTracker tracker) {
Disposer.addObjectRecord(this, Disposer.addObjectRecord(this,
new CreatedFontFileDisposerRecord(file)); new CreatedFontFileDisposerRecord(file, tracker));
} }
/* This is called when a font scaler is determined to /* This is called when a font scaler is determined to
...@@ -246,12 +246,16 @@ public abstract class FileFont extends PhysicalFont { ...@@ -246,12 +246,16 @@ public abstract class FileFont extends PhysicalFont {
return getScaler().getUnitsPerEm(); return getScaler().getUnitsPerEm();
} }
private static class CreatedFontFileDisposerRecord implements DisposerRecord { private static class CreatedFontFileDisposerRecord
implements DisposerRecord {
File fontFile = null; File fontFile = null;
CreatedFontTracker tracker;
private CreatedFontFileDisposerRecord(File file) { private CreatedFontFileDisposerRecord(File file,
CreatedFontTracker tracker) {
fontFile = file; fontFile = file;
this.tracker = tracker;
} }
public void dispose() { public void dispose() {
...@@ -260,6 +264,9 @@ public abstract class FileFont extends PhysicalFont { ...@@ -260,6 +264,9 @@ public abstract class FileFont extends PhysicalFont {
public Object run() { public Object run() {
if (fontFile != null) { if (fontFile != null) {
try { try {
if (tracker != null) {
tracker.subBytes((int)fontFile.length());
}
/* REMIND: is it possible that the file is /* REMIND: is it possible that the file is
* still open? It will be closed when the * still open? It will be closed when the
* font2D is disposed but could this code * font2D is disposed but could this code
......
...@@ -2357,19 +2357,21 @@ public final class FontManager { ...@@ -2357,19 +2357,21 @@ public final class FontManager {
static Vector<File> tmpFontFiles = null; static Vector<File> tmpFontFiles = null;
public static Font2D createFont2D(File fontFile, int fontFormat, public static Font2D createFont2D(File fontFile, int fontFormat,
boolean isCopy) boolean isCopy,
CreatedFontTracker tracker)
throws FontFormatException { throws FontFormatException {
String fontFilePath = fontFile.getPath(); String fontFilePath = fontFile.getPath();
FileFont font2D = null; FileFont font2D = null;
final File fFile = fontFile; final File fFile = fontFile;
final CreatedFontTracker _tracker = tracker;
try { try {
switch (fontFormat) { switch (fontFormat) {
case Font.TRUETYPE_FONT: case Font.TRUETYPE_FONT:
font2D = new TrueTypeFont(fontFilePath, null, 0, true); font2D = new TrueTypeFont(fontFilePath, null, 0, true);
break; break;
case Font.TYPE1_FONT: case Font.TYPE1_FONT:
font2D = new Type1Font(fontFilePath, null); font2D = new Type1Font(fontFilePath, null, isCopy);
break; break;
default: default:
throw new FontFormatException("Unrecognised Font Format"); throw new FontFormatException("Unrecognised Font Format");
...@@ -2379,6 +2381,9 @@ public final class FontManager { ...@@ -2379,6 +2381,9 @@ public final class FontManager {
java.security.AccessController.doPrivileged( java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() { new java.security.PrivilegedAction() {
public Object run() { public Object run() {
if (_tracker != null) {
_tracker.subBytes((int)fFile.length());
}
fFile.delete(); fFile.delete();
return null; return null;
} }
...@@ -2387,7 +2392,7 @@ public final class FontManager { ...@@ -2387,7 +2392,7 @@ public final class FontManager {
throw(e); throw(e);
} }
if (isCopy) { if (isCopy) {
font2D.setFileToRemove(fontFile); font2D.setFileToRemove(fontFile, tracker);
synchronized (FontManager.class) { synchronized (FontManager.class) {
if (tmpFontFiles == null) { if (tmpFontFiles == null) {
......
...@@ -175,8 +175,17 @@ public class TrueTypeFont extends FileFont { ...@@ -175,8 +175,17 @@ public class TrueTypeFont extends FileFont {
super(platname, nativeNames); super(platname, nativeNames);
useJavaRasterizer = javaRasterizer; useJavaRasterizer = javaRasterizer;
fontRank = Font2D.TTF_RANK; fontRank = Font2D.TTF_RANK;
verify(); try {
init(fIndex); verify();
init(fIndex);
} catch (Throwable t) {
close();
if (t instanceof FontFormatException) {
throw (FontFormatException)t;
} else {
throw new FontFormatException("Unexpected runtime exception.");
}
}
Disposer.addObjectRecord(this, disposerRecord); Disposer.addObjectRecord(this, disposerRecord);
} }
......
...@@ -39,6 +39,7 @@ import java.nio.BufferUnderflowException; ...@@ -39,6 +39,7 @@ import java.nio.BufferUnderflowException;
import java.nio.channels.ClosedChannelException; import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import sun.java2d.Disposer; import sun.java2d.Disposer;
import sun.java2d.DisposerRecord;
import java.util.HashSet; import java.util.HashSet;
import java.util.HashMap; import java.util.HashMap;
import java.awt.Font; import java.awt.Font;
...@@ -76,6 +77,27 @@ import java.awt.Font; ...@@ -76,6 +77,27 @@ import java.awt.Font;
*/ */
public class Type1Font extends FileFont { public class Type1Font extends FileFont {
private static class T1DisposerRecord implements DisposerRecord {
String fileName = null;
T1DisposerRecord(String name) {
fileName = name;
}
public synchronized void dispose() {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
if (fileName != null) {
(new java.io.File(fileName)).delete();
}
return null;
}
});
}
}
WeakReference bufferRef = new WeakReference(null); WeakReference bufferRef = new WeakReference(null);
private String psName = null; private String psName = null;
...@@ -124,6 +146,17 @@ public class Type1Font extends FileFont { ...@@ -124,6 +146,17 @@ public class Type1Font extends FileFont {
} }
/**
* Constructs a Type1 Font.
* @param platname - Platform identifier of the font. Typically file name.
* @param nativeNames - Native names - typically XLFDs on Unix.
*/
public Type1Font(String platname, Object nativeNames)
throws FontFormatException {
this(platname, nativeNames, false);
}
/** /**
* - does basic verification of the file * - does basic verification of the file
* - reads the names (full, family). * - reads the names (full, family).
...@@ -131,12 +164,25 @@ public class Type1Font extends FileFont { ...@@ -131,12 +164,25 @@ public class Type1Font extends FileFont {
* @throws FontFormatException - if the font can't be opened * @throws FontFormatException - if the font can't be opened
* or fails verification, or there's no usable cmap * or fails verification, or there's no usable cmap
*/ */
public Type1Font(String platname, Object nativeNames) public Type1Font(String platname, Object nativeNames, boolean createdCopy)
throws FontFormatException { throws FontFormatException {
super(platname, nativeNames); super(platname, nativeNames);
fontRank = Font2D.TYPE1_RANK; fontRank = Font2D.TYPE1_RANK;
checkedNatives = true; checkedNatives = true;
verify(); try {
verify();
} catch (Throwable t) {
if (createdCopy) {
T1DisposerRecord ref = new T1DisposerRecord(platname);
Disposer.addObjectRecord(bufferRef, ref);
bufferRef = null;
}
if (t instanceof FontFormatException) {
throw (FontFormatException)t;
} else {
throw new FontFormatException("Unexpected runtime exception.");
}
}
} }
private synchronized ByteBuffer getBuffer() throws FontFormatException { private synchronized ByteBuffer getBuffer() throws FontFormatException {
......
...@@ -52,6 +52,9 @@ class Request { ...@@ -52,6 +52,9 @@ class Request {
os = rawout; os = rawout;
do { do {
startLine = readLine(); startLine = readLine();
if (startLine == null) {
return;
}
/* skip blank lines */ /* skip blank lines */
} while (startLine == null ? false : startLine.equals ("")); } while (startLine == null ? false : startLine.equals (""));
} }
......
...@@ -433,6 +433,7 @@ class ServerImpl implements TimeSource { ...@@ -433,6 +433,7 @@ class ServerImpl implements TimeSource {
rawin = sslStreams.getInputStream(); rawin = sslStreams.getInputStream();
rawout = sslStreams.getOutputStream(); rawout = sslStreams.getOutputStream();
engine = sslStreams.getSSLEngine(); engine = sslStreams.getSSLEngine();
connection.sslStreams = sslStreams;
} else { } else {
rawin = new BufferedInputStream( rawin = new BufferedInputStream(
new Request.ReadStream ( new Request.ReadStream (
...@@ -442,6 +443,8 @@ class ServerImpl implements TimeSource { ...@@ -442,6 +443,8 @@ class ServerImpl implements TimeSource {
ServerImpl.this, chan ServerImpl.this, chan
); );
} }
connection.raw = rawin;
connection.rawout = rawout;
} }
Request req = new Request (rawin, rawout); Request req = new Request (rawin, rawout);
requestLine = req.requestLine(); requestLine = req.requestLine();
......
...@@ -113,16 +113,16 @@ abstract class AsynchronousFileChannelImpl ...@@ -113,16 +113,16 @@ abstract class AsynchronousFileChannelImpl
} }
} }
final void invalidateAllLocks() { final void invalidateAllLocks() throws IOException {
if (fileLockTable != null) { if (fileLockTable != null) {
try { for (FileLock fl: fileLockTable.removeAll()) {
fileLockTable.removeAll( new FileLockTable.Releaser() { synchronized (fl) {
public void release(FileLock fl) { if (fl.isValid()) {
((FileLockImpl)fl).invalidate(); FileLockImpl fli = (FileLockImpl)fl;
implRelease(fli);
fli.invalidate();
} }
}); }
} catch (IOException e) {
throw new AssertionError(e);
} }
} }
} }
...@@ -158,7 +158,21 @@ abstract class AsynchronousFileChannelImpl ...@@ -158,7 +158,21 @@ abstract class AsynchronousFileChannelImpl
} }
/** /**
* Invoked by FileLockImpl to release lock acquired by this channel. * Releases the given file lock.
*/
protected abstract void implRelease(FileLockImpl fli) throws IOException;
/**
* Invoked by FileLockImpl to release the given file lock and remove it
* from the lock table.
*/ */
abstract void release(FileLockImpl fli) throws IOException; final void release(FileLockImpl fli) throws IOException {
try {
begin();
implRelease(fli);
removeFromFileLockTable(fli);
} finally {
end();
}
}
} }
...@@ -33,8 +33,6 @@ import java.nio.BufferPoolMXBean; ...@@ -33,8 +33,6 @@ import java.nio.BufferPoolMXBean;
import java.nio.channels.*; import java.nio.channels.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Iterator;
import java.lang.reflect.Field;
import java.security.AccessController; import java.security.AccessController;
import javax.management.ObjectName; import javax.management.ObjectName;
import javax.management.MalformedObjectNameException; import javax.management.MalformedObjectNameException;
...@@ -95,14 +93,16 @@ public class FileChannelImpl ...@@ -95,14 +93,16 @@ public class FileChannelImpl
// -- Standard channel operations -- // -- Standard channel operations --
protected void implCloseChannel() throws IOException { protected void implCloseChannel() throws IOException {
// Invalidate and release any locks that we still hold // Release and invalidate any locks that we still hold
if (fileLockTable != null) { if (fileLockTable != null) {
fileLockTable.removeAll( new FileLockTable.Releaser() { for (FileLock fl: fileLockTable.removeAll()) {
public void release(FileLock fl) throws IOException { synchronized (fl) {
((FileLockImpl)fl).invalidate(); if (fl.isValid()) {
nd.release(fd, fl.position(), fl.size()); nd.release(fd, fl.position(), fl.size());
((FileLockImpl)fl).invalidate();
}
} }
}); }
} }
nd.preClose(fd); nd.preClose(fd);
...@@ -912,32 +912,33 @@ public class FileChannelImpl ...@@ -912,32 +912,33 @@ public class FileChannelImpl
FileLockImpl fli = new FileLockImpl(this, position, size, shared); FileLockImpl fli = new FileLockImpl(this, position, size, shared);
FileLockTable flt = fileLockTable(); FileLockTable flt = fileLockTable();
flt.add(fli); flt.add(fli);
boolean i = true; boolean completed = false;
int ti = -1; int ti = -1;
try { try {
begin(); begin();
ti = threads.add(); ti = threads.add();
if (!isOpen()) if (!isOpen())
return null; return null;
int result = nd.lock(fd, true, position, size, shared); int n;
if (result == FileDispatcher.RET_EX_LOCK) { do {
assert shared; n = nd.lock(fd, true, position, size, shared);
FileLockImpl fli2 = new FileLockImpl(this, position, size, } while ((n == FileDispatcher.INTERRUPTED) && isOpen());
false); if (isOpen()) {
flt.replace(fli, fli2); if (n == FileDispatcher.RET_EX_LOCK) {
return fli2; assert shared;
} FileLockImpl fli2 = new FileLockImpl(this, position, size,
if (result == FileDispatcher.INTERRUPTED || result == FileDispatcher.NO_LOCK) { false);
flt.remove(fli); flt.replace(fli, fli2);
i = false; fli = fli2;
}
completed = true;
} }
} catch (IOException e) {
flt.remove(fli);
throw e;
} finally { } finally {
if (!completed)
flt.remove(fli);
threads.remove(ti); threads.remove(ti);
try { try {
end(i); end(completed);
} catch (ClosedByInterruptException e) { } catch (ClosedByInterruptException e) {
throw new FileLockInterruptionException(); throw new FileLockInterruptionException();
} }
...@@ -985,7 +986,6 @@ public class FileChannelImpl ...@@ -985,7 +986,6 @@ public class FileChannelImpl
} }
void release(FileLockImpl fli) throws IOException { void release(FileLockImpl fli) throws IOException {
ensureOpen();
int ti = threads.add(); int ti = threads.add();
try { try {
ensureOpen(); ensureOpen();
...@@ -1005,7 +1005,7 @@ public class FileChannelImpl ...@@ -1005,7 +1005,7 @@ public class FileChannelImpl
*/ */
private static class SimpleFileLockTable extends FileLockTable { private static class SimpleFileLockTable extends FileLockTable {
// synchronize on list for access // synchronize on list for access
private List<FileLock> lockList = new ArrayList<FileLock>(2); private final List<FileLock> lockList = new ArrayList<FileLock>(2);
public SimpleFileLockTable() { public SimpleFileLockTable() {
} }
...@@ -1034,14 +1034,11 @@ public class FileChannelImpl ...@@ -1034,14 +1034,11 @@ public class FileChannelImpl
} }
} }
public void removeAll(Releaser releaser) throws IOException { public List<FileLock> removeAll() {
synchronized(lockList) { synchronized(lockList) {
Iterator<FileLock> i = lockList.iterator(); List<FileLock> result = new ArrayList<FileLock>(lockList);
while (i.hasNext()) { lockList.clear();
FileLock fl = i.next(); return result;
releaser.release(fl);
i.remove();
}
} }
} }
......
...@@ -31,25 +31,24 @@ import java.nio.channels.*; ...@@ -31,25 +31,24 @@ import java.nio.channels.*;
public class FileLockImpl public class FileLockImpl
extends FileLock extends FileLock
{ {
boolean valid; private volatile boolean valid = true;
FileLockImpl(FileChannel channel, long position, long size, boolean shared) FileLockImpl(FileChannel channel, long position, long size, boolean shared)
{ {
super(channel, position, size, shared); super(channel, position, size, shared);
this.valid = true;
} }
FileLockImpl(AsynchronousFileChannel channel, long position, long size, boolean shared) FileLockImpl(AsynchronousFileChannel channel, long position, long size, boolean shared)
{ {
super(channel, position, size, shared); super(channel, position, size, shared);
this.valid = true;
} }
public synchronized boolean isValid() { public boolean isValid() {
return valid; return valid;
} }
synchronized void invalidate() { void invalidate() {
assert Thread.holdsLock(this);
valid = false; valid = false;
} }
...@@ -66,5 +65,4 @@ public class FileLockImpl ...@@ -66,5 +65,4 @@ public class FileLockImpl
valid = false; valid = false;
} }
} }
} }
...@@ -60,23 +60,12 @@ abstract class FileLockTable { ...@@ -60,23 +60,12 @@ abstract class FileLockTable {
*/ */
public abstract void remove(FileLock fl); public abstract void remove(FileLock fl);
/**
* An implementation of this interface releases a given file lock.
* Used with removeAll.
*/
public abstract interface Releaser {
void release(FileLock fl) throws IOException;
}
/** /**
* Removes all file locks from the table. * Removes all file locks from the table.
* <p>
* The Releaser#release method is invoked for each file lock before
* it is removed.
* *
* @throws IOException if the release method throws IOException * @return The list of file locks removed
*/ */
public abstract void removeAll(Releaser r) throws IOException; public abstract List<FileLock> removeAll();
/** /**
* Replaces an existing file lock in the table. * Replaces an existing file lock in the table.
...@@ -195,7 +184,7 @@ class SharedFileLockTable extends FileLockTable { ...@@ -195,7 +184,7 @@ class SharedFileLockTable extends FileLockTable {
FileLockReference ref = list.get(index); FileLockReference ref = list.get(index);
FileLock lock = ref.get(); FileLock lock = ref.get();
if (lock == fl) { if (lock == fl) {
assert (lock != null) && (lock.channel() == channel); assert (lock != null) && (lock.acquiredBy() == channel);
ref.clear(); ref.clear();
list.remove(index); list.remove(index);
break; break;
...@@ -206,7 +195,8 @@ class SharedFileLockTable extends FileLockTable { ...@@ -206,7 +195,8 @@ class SharedFileLockTable extends FileLockTable {
} }
@Override @Override
public void removeAll(Releaser releaser) throws IOException { public List<FileLock> removeAll() {
List<FileLock> result = new ArrayList<FileLock>();
List<FileLockReference> list = lockMap.get(fileKey); List<FileLockReference> list = lockMap.get(fileKey);
if (list != null) { if (list != null) {
synchronized (list) { synchronized (list) {
...@@ -216,13 +206,13 @@ class SharedFileLockTable extends FileLockTable { ...@@ -216,13 +206,13 @@ class SharedFileLockTable extends FileLockTable {
FileLock lock = ref.get(); FileLock lock = ref.get();
// remove locks obtained by this channel // remove locks obtained by this channel
if (lock != null && lock.channel() == channel) { if (lock != null && lock.acquiredBy() == channel) {
// invoke the releaser to invalidate/release the lock
releaser.release(lock);
// remove the lock from the list // remove the lock from the list
ref.clear(); ref.clear();
list.remove(index); list.remove(index);
// add to result
result.add(lock);
} else { } else {
index++; index++;
} }
...@@ -232,6 +222,7 @@ class SharedFileLockTable extends FileLockTable { ...@@ -232,6 +222,7 @@ class SharedFileLockTable extends FileLockTable {
removeKeyIfEmpty(fileKey, list); removeKeyIfEmpty(fileKey, list);
} }
} }
return result;
} }
@Override @Override
......
...@@ -97,6 +97,9 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -97,6 +97,9 @@ public class SimpleAsynchronousFileChannelImpl
// then it will throw ClosedChannelException // then it will throw ClosedChannelException
} }
// Invalidate and release any locks that we still hold
invalidateAllLocks();
// signal any threads blocked on this channel // signal any threads blocked on this channel
nd.preClose(fdObj); nd.preClose(fdObj);
threads.signalAndWait(); threads.signalAndWait();
...@@ -109,9 +112,6 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -109,9 +112,6 @@ public class SimpleAsynchronousFileChannelImpl
closeLock.writeLock().unlock(); closeLock.writeLock().unlock();
} }
// Invalidate and release any locks that we still hold
invalidateAllLocks();
// close file // close file
nd.close(fdObj); nd.close(fdObj);
...@@ -226,11 +226,9 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -226,11 +226,9 @@ public class SimpleAsynchronousFileChannelImpl
do { do {
n = nd.lock(fdObj, true, position, size, shared); n = nd.lock(fdObj, true, position, size, shared);
} while ((n == FileDispatcher.INTERRUPTED) && isOpen()); } while ((n == FileDispatcher.INTERRUPTED) && isOpen());
if (n == FileDispatcher.LOCKED) { if (n == FileDispatcher.LOCKED && isOpen()) {
result.setResult(fli); result.setResult(fli);
} else { } else {
if (n != FileDispatcher.INTERRUPTED)
throw new AssertionError();
throw new AsynchronousCloseException(); throw new AsynchronousCloseException();
} }
} catch (IOException x) { } catch (IOException x) {
...@@ -279,16 +277,16 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -279,16 +277,16 @@ public class SimpleAsynchronousFileChannelImpl
do { do {
n = nd.lock(fdObj, false, position, size, shared); n = nd.lock(fdObj, false, position, size, shared);
} while ((n == FileDispatcher.INTERRUPTED) && isOpen()); } while ((n == FileDispatcher.INTERRUPTED) && isOpen());
if (n != FileDispatcher.LOCKED) { if (n == FileDispatcher.LOCKED && isOpen()) {
if (n == FileDispatcher.NO_LOCK) gotLock = true;
return null; // locked by someone else return fli; // lock acquired
if (n == FileDispatcher.INTERRUPTED)
throw new AsynchronousCloseException();
// should not get here
throw new AssertionError();
} }
gotLock = true; if (n == FileDispatcher.NO_LOCK)
return fli; return null; // locked by someone else
if (n == FileDispatcher.INTERRUPTED)
throw new AsynchronousCloseException();
// should not get here
throw new AssertionError();
} finally { } finally {
if (!gotLock) if (!gotLock)
removeFromFileLockTable(fli); removeFromFileLockTable(fli);
...@@ -298,14 +296,8 @@ public class SimpleAsynchronousFileChannelImpl ...@@ -298,14 +296,8 @@ public class SimpleAsynchronousFileChannelImpl
} }
@Override @Override
void release(FileLockImpl fli) throws IOException { protected void implRelease(FileLockImpl fli) throws IOException {
try { nd.release(fdObj, fli.position(), fli.size());
begin();
nd.release(fdObj, fli.position(), fli.size());
removeFromFileLockTable(fli);
} finally {
end();
}
} }
@Override @Override
......
...@@ -736,6 +736,14 @@ public class Config { ...@@ -736,6 +736,14 @@ public class Config {
return name; return name;
} }
private static String trimmed(String s) {
s = s.trim();
if (s.charAt(0) == '"' && s.charAt(s.length()-1) == '"' ||
s.charAt(0) == '\'' && s.charAt(s.length()-1) == '\'') {
s = s.substring(1, s.length()-1).trim();
}
return s;
}
/** /**
* Parses key-value pairs under a stanza name. * Parses key-value pairs under a stanza name.
*/ */
...@@ -747,7 +755,7 @@ public class Config { ...@@ -747,7 +755,7 @@ public class Config {
for (int j = 0; j < line.length(); j++) { for (int j = 0; j < line.length(); j++) {
if (line.charAt(j) == '=') { if (line.charAt(j) == '=') {
String key = (line.substring(0, j)).trim(); String key = (line.substring(0, j)).trim();
String value = (line.substring(j + 1)).trim(); String value = trimmed(line.substring(j + 1));
table.put(key, value); table.put(key, value);
break; break;
} }
...@@ -820,7 +828,7 @@ public class Config { ...@@ -820,7 +828,7 @@ public class Config {
} else { } else {
nameVector = table.get(key); nameVector = table.get(key);
} }
nameVector.addElement((line.substring(j + 1)).trim()); nameVector.addElement(trimmed(line.substring(j + 1)));
table.put(key, nameVector); table.put(key, nameVector);
break; break;
} }
...@@ -1263,4 +1271,32 @@ public class Config { ...@@ -1263,4 +1271,32 @@ public class Config {
} }
} }
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
toStringIndented("", stanzaTable, sb);
return sb.toString();
}
private static void toStringIndented(String prefix, Object obj,
StringBuffer sb) {
if (obj instanceof String) {
sb.append(prefix);
sb.append(obj);
sb.append('\n');
} else if (obj instanceof Hashtable) {
Hashtable tab = (Hashtable)obj;
for (Object o: tab.keySet()) {
sb.append(prefix);
sb.append(o);
sb.append(" = {\n");
toStringIndented(prefix + " ", tab.get(o), sb);
sb.append(prefix + "}\n");
}
} else if (obj instanceof Vector) {
Vector v = (Vector)obj;
for (Object o: v.toArray()) {
toStringIndented(prefix + " ", o, sb);
}
}
}
} }
...@@ -274,27 +274,31 @@ public abstract class KrbKdcReq { ...@@ -274,27 +274,31 @@ public abstract class KrbKdcReq {
+ ",Attempt =" + i + ",Attempt =" + i
+ ", #bytes=" + obuf.length); + ", #bytes=" + obuf.length);
} }
/* try {
* Send the data to the kdc. /*
*/ * Send the data to the kdc.
*/
kdcClient.send(obuf); kdcClient.send(obuf);
/* /*
* And get a response. * And get a response.
*/ */
try { try {
ibuf = kdcClient.receive(); ibuf = kdcClient.receive();
break; break;
} catch (SocketTimeoutException se) { } catch (SocketTimeoutException se) {
if (DEBUG) { if (DEBUG) {
System.out.println ("SocketTimeOutException with " + System.out.println ("SocketTimeOutException with " +
"attempt: " + i); "attempt: " + i);
} }
if (i == DEFAULT_KDC_RETRY_LIMIT) { if (i == DEFAULT_KDC_RETRY_LIMIT) {
ibuf = null; ibuf = null;
throw se; throw se;
}
} }
} finally {
kdcClient.close();
} }
} }
} }
......
...@@ -93,4 +93,7 @@ public class UDPClient { ...@@ -93,4 +93,7 @@ public class UDPClient {
return data; return data;
} }
public void close() {
dgSocket.close();
}
} }
/* /*
* Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -38,6 +38,8 @@ import static sun.security.pkcs11.TemplateManager.*; ...@@ -38,6 +38,8 @@ import static sun.security.pkcs11.TemplateManager.*;
import sun.security.pkcs11.wrapper.*; import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*; import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
import sun.security.rsa.RSAKeyFactory;
/** /**
* KeyPairGenerator implementation class. This class currently supports * KeyPairGenerator implementation class. This class currently supports
* RSA, DSA, DH, and EC. * RSA, DSA, DH, and EC.
...@@ -66,7 +68,7 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { ...@@ -66,7 +68,7 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
private AlgorithmParameterSpec params; private AlgorithmParameterSpec params;
// for RSA, selected or default value of public exponent, always valid // for RSA, selected or default value of public exponent, always valid
private BigInteger rsaPublicExponent; private BigInteger rsaPublicExponent = RSAKeyGenParameterSpec.F4;
// SecureRandom instance, if specified in init // SecureRandom instance, if specified in init
private SecureRandom random; private SecureRandom random;
...@@ -88,19 +90,19 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { ...@@ -88,19 +90,19 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
public void initialize(int keySize, SecureRandom random) { public void initialize(int keySize, SecureRandom random) {
token.ensureValid(); token.ensureValid();
try { try {
checkKeySize(keySize); checkKeySize(keySize, null);
} catch (InvalidAlgorithmParameterException e) { } catch (InvalidAlgorithmParameterException e) {
throw new InvalidParameterException(e.getMessage()); throw new InvalidParameterException(e.getMessage());
} }
this.keySize = keySize; this.keySize = keySize;
this.params = null; this.params = null;
this.random = random; this.random = random;
this.rsaPublicExponent = RSAKeyGenParameterSpec.F4;
if (algorithm.equals("EC")) { if (algorithm.equals("EC")) {
params = P11ECKeyFactory.getECParameterSpec(keySize); params = P11ECKeyFactory.getECParameterSpec(keySize);
if (params == null) { if (params == null) {
throw new InvalidParameterException throw new InvalidParameterException(
("No EC parameters available for key size " + keySize + " bits"); "No EC parameters available for key size "
+ keySize + " bits");
} }
} }
} }
...@@ -115,8 +117,10 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { ...@@ -115,8 +117,10 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
("DHParameterSpec required for Diffie-Hellman"); ("DHParameterSpec required for Diffie-Hellman");
} }
DHParameterSpec dhParams = (DHParameterSpec)params; DHParameterSpec dhParams = (DHParameterSpec)params;
this.keySize = dhParams.getP().bitLength(); int tmpKeySize = dhParams.getP().bitLength();
this.params = params; checkKeySize(tmpKeySize, dhParams);
this.keySize = tmpKeySize;
this.params = dhParams;
// XXX sanity check params // XXX sanity check params
} else if (algorithm.equals("RSA")) { } else if (algorithm.equals("RSA")) {
if (params instanceof RSAKeyGenParameterSpec == false) { if (params instanceof RSAKeyGenParameterSpec == false) {
...@@ -124,7 +128,9 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { ...@@ -124,7 +128,9 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
("RSAKeyGenParameterSpec required for RSA"); ("RSAKeyGenParameterSpec required for RSA");
} }
RSAKeyGenParameterSpec rsaParams = (RSAKeyGenParameterSpec)params; RSAKeyGenParameterSpec rsaParams = (RSAKeyGenParameterSpec)params;
this.keySize = rsaParams.getKeysize(); int tmpKeySize = rsaParams.getKeysize();
checkKeySize(tmpKeySize, rsaParams);
this.keySize = tmpKeySize;
this.params = null; this.params = null;
this.rsaPublicExponent = rsaParams.getPublicExponent(); this.rsaPublicExponent = rsaParams.getPublicExponent();
// XXX sanity check params // XXX sanity check params
...@@ -134,13 +140,16 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { ...@@ -134,13 +140,16 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
("DSAParameterSpec required for DSA"); ("DSAParameterSpec required for DSA");
} }
DSAParameterSpec dsaParams = (DSAParameterSpec)params; DSAParameterSpec dsaParams = (DSAParameterSpec)params;
this.keySize = dsaParams.getP().bitLength(); int tmpKeySize = dsaParams.getP().bitLength();
this.params = params; checkKeySize(tmpKeySize, dsaParams);
this.keySize = tmpKeySize;
this.params = dsaParams;
// XXX sanity check params // XXX sanity check params
} else if (algorithm.equals("EC")) { } else if (algorithm.equals("EC")) {
ECParameterSpec ecParams; ECParameterSpec ecParams;
if (params instanceof ECParameterSpec) { if (params instanceof ECParameterSpec) {
ecParams = P11ECKeyFactory.getECParameterSpec((ECParameterSpec)params); ecParams = P11ECKeyFactory.getECParameterSpec(
(ECParameterSpec)params);
if (ecParams == null) { if (ecParams == null) {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
("Unsupported curve: " + params); ("Unsupported curve: " + params);
...@@ -156,16 +165,17 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { ...@@ -156,16 +165,17 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
("ECParameterSpec or ECGenParameterSpec required for EC"); ("ECParameterSpec or ECGenParameterSpec required for EC");
} }
this.keySize = ecParams.getCurve().getField().getFieldSize(); int tmpKeySize = ecParams.getCurve().getField().getFieldSize();
checkKeySize(tmpKeySize, ecParams);
this.keySize = tmpKeySize;
this.params = ecParams; this.params = ecParams;
} else { } else {
throw new ProviderException("Unknown algorithm: " + algorithm); throw new ProviderException("Unknown algorithm: " + algorithm);
} }
this.random = random; this.random = random;
checkKeySize(keySize);
} }
private void checkKeySize(int keySize) private void checkKeySize(int keySize, AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException { throws InvalidAlgorithmParameterException {
if (algorithm.equals("EC")) { if (algorithm.equals("EC")) {
if (keySize < 112) { if (keySize < 112) {
...@@ -178,13 +188,28 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { ...@@ -178,13 +188,28 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
("Key size must be at most 2048 bit"); ("Key size must be at most 2048 bit");
} }
return; return;
} else if (algorithm.equals("RSA")) {
BigInteger tmpExponent = rsaPublicExponent;
if (params != null) {
// Already tested for instanceof RSAKeyGenParameterSpec above
tmpExponent =
((RSAKeyGenParameterSpec)params).getPublicExponent();
}
try {
// This provider supports 64K or less.
RSAKeyFactory.checkKeyLengths(keySize, tmpExponent,
512, 64 * 1024);
} catch (InvalidKeyException e) {
throw new InvalidAlgorithmParameterException(e.getMessage());
}
return;
} }
if (keySize < 512) { if (keySize < 512) {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
("Key size must be at least 512 bit"); ("Key size must be at least 512 bit");
} }
if (algorithm.equals("RSA") || if (algorithm.equals("DH") && (params != null)) {
(algorithm.equals("DH") && (params != null))) {
// sanity check, nobody really wants keys this large // sanity check, nobody really wants keys this large
if (keySize > 64 * 1024) { if (keySize > 64 * 1024) {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
......
...@@ -80,6 +80,8 @@ import static sun.security.pkcs11.P11Util.*; ...@@ -80,6 +80,8 @@ import static sun.security.pkcs11.P11Util.*;
import sun.security.pkcs11.wrapper.*; import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*; import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
import sun.security.rsa.RSAKeyFactory;
final class P11KeyStore extends KeyStoreSpi { final class P11KeyStore extends KeyStoreSpi {
private static final CK_ATTRIBUTE ATTR_CLASS_CERT = private static final CK_ATTRIBUTE ATTR_CLASS_CERT =
...@@ -1328,6 +1330,15 @@ final class P11KeyStore extends KeyStoreSpi { ...@@ -1328,6 +1330,15 @@ final class P11KeyStore extends KeyStoreSpi {
BigInteger modulus = attrs[0].getBigInteger(); BigInteger modulus = attrs[0].getBigInteger();
keyLength = modulus.bitLength(); keyLength = modulus.bitLength();
// This check will combine our "don't care" values here
// with the system-wide min/max values.
try {
RSAKeyFactory.checkKeyLengths(keyLength, null,
-1, Integer.MAX_VALUE);
} catch (InvalidKeyException e) {
throw new KeyStoreException(e.getMessage());
}
return P11Key.privateKey(session, return P11Key.privateKey(session,
oHandle, oHandle,
keyType, keyType,
......
/* /*
* Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -35,6 +35,8 @@ import static sun.security.pkcs11.TemplateManager.*; ...@@ -35,6 +35,8 @@ import static sun.security.pkcs11.TemplateManager.*;
import sun.security.pkcs11.wrapper.*; import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*; import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
import sun.security.rsa.RSAKeyFactory;
/** /**
* RSA KeyFactory implemenation. * RSA KeyFactory implemenation.
* *
...@@ -131,6 +133,9 @@ final class P11RSAKeyFactory extends P11KeyFactory { ...@@ -131,6 +133,9 @@ final class P11RSAKeyFactory extends P11KeyFactory {
} catch (PKCS11Exception e) { } catch (PKCS11Exception e) {
throw new InvalidKeySpecException throw new InvalidKeySpecException
("Could not create RSA public key", e); ("Could not create RSA public key", e);
} catch (InvalidKeyException e) {
throw new InvalidKeySpecException
("Could not create RSA public key", e);
} }
} }
...@@ -175,11 +180,15 @@ final class P11RSAKeyFactory extends P11KeyFactory { ...@@ -175,11 +180,15 @@ final class P11RSAKeyFactory extends P11KeyFactory {
} catch (PKCS11Exception e) { } catch (PKCS11Exception e) {
throw new InvalidKeySpecException throw new InvalidKeySpecException
("Could not create RSA private key", e); ("Could not create RSA private key", e);
} catch (InvalidKeyException e) {
throw new InvalidKeySpecException
("Could not create RSA private key", e);
} }
} }
private PublicKey generatePublic(BigInteger n, BigInteger e) private PublicKey generatePublic(BigInteger n, BigInteger e)
throws PKCS11Exception { throws PKCS11Exception, InvalidKeyException {
RSAKeyFactory.checkKeyLengths(n.bitLength(), e, -1, 64 * 1024);
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA_CLASS, CKO_PUBLIC_KEY), new CK_ATTRIBUTE(CKA_CLASS, CKO_PUBLIC_KEY),
new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA), new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA),
...@@ -200,7 +209,8 @@ final class P11RSAKeyFactory extends P11KeyFactory { ...@@ -200,7 +209,8 @@ final class P11RSAKeyFactory extends P11KeyFactory {
} }
private PrivateKey generatePrivate(BigInteger n, BigInteger d) private PrivateKey generatePrivate(BigInteger n, BigInteger d)
throws PKCS11Exception { throws PKCS11Exception, InvalidKeyException {
RSAKeyFactory.checkKeyLengths(n.bitLength(), null, -1, 64 * 1024);
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY), new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY),
new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA), new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA),
...@@ -222,7 +232,9 @@ final class P11RSAKeyFactory extends P11KeyFactory { ...@@ -222,7 +232,9 @@ final class P11RSAKeyFactory extends P11KeyFactory {
private PrivateKey generatePrivate(BigInteger n, BigInteger e, private PrivateKey generatePrivate(BigInteger n, BigInteger e,
BigInteger d, BigInteger p, BigInteger q, BigInteger pe, BigInteger d, BigInteger p, BigInteger q, BigInteger pe,
BigInteger qe, BigInteger coeff) throws PKCS11Exception { BigInteger qe, BigInteger coeff) throws PKCS11Exception,
InvalidKeyException {
RSAKeyFactory.checkKeyLengths(n.bitLength(), e, -1, 64 * 1024);
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] { CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY), new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY),
new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA), new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA),
......
...@@ -120,11 +120,13 @@ public final class SunPKCS11 extends AuthProvider { ...@@ -120,11 +120,13 @@ public final class SunPKCS11 extends AuthProvider {
} }
/** /**
* @deprecated use new SunPKCS11(String) or new SunPKCS11(InputStream) instead * @deprecated use new SunPKCS11(String) or new SunPKCS11(InputStream)
* instead
*/ */
@Deprecated @Deprecated
public SunPKCS11(String configName, InputStream configStream) { public SunPKCS11(String configName, InputStream configStream) {
super("SunPKCS11-" + Config.getConfig(configName, configStream).getName(), super("SunPKCS11-" +
Config.getConfig(configName, configStream).getName(),
1.7d, Config.getConfig(configName, configStream).getDescription()); 1.7d, Config.getConfig(configName, configStream).getDescription());
this.configName = configName; this.configName = configName;
this.config = Config.removeConfig(configName); this.config = Config.removeConfig(configName);
...@@ -153,7 +155,8 @@ public final class SunPKCS11 extends AuthProvider { ...@@ -153,7 +155,8 @@ public final class SunPKCS11 extends AuthProvider {
// //
// If we are in Secmod mode and configured to use either the // If we are in Secmod mode and configured to use either the
// nssKeyStore or the nssTrustAnchors module, we automatically // nssKeyStore or the nssTrustAnchors module, we automatically
// switch to using the NSS trust attributes for trusted certs (KeyStore). // switch to using the NSS trust attributes for trusted certs
// (KeyStore).
// //
if (useSecmod) { if (useSecmod) {
...@@ -168,33 +171,40 @@ public final class SunPKCS11 extends AuthProvider { ...@@ -168,33 +171,40 @@ public final class SunPKCS11 extends AuthProvider {
if (secmod.isInitialized()) { if (secmod.isInitialized()) {
if (nssSecmodDirectory != null) { if (nssSecmodDirectory != null) {
String s = secmod.getConfigDir(); String s = secmod.getConfigDir();
if ((s != null) && (s.equals(nssSecmodDirectory) == false)) { if ((s != null) &&
(s.equals(nssSecmodDirectory) == false)) {
throw new ProviderException("Secmod directory " throw new ProviderException("Secmod directory "
+ nssSecmodDirectory + nssSecmodDirectory
+ " invalid, NSS already initialized with " + s); + " invalid, NSS already initialized with "
+ s);
} }
} }
if (nssLibraryDirectory != null) { if (nssLibraryDirectory != null) {
String s = secmod.getLibDir(); String s = secmod.getLibDir();
if ((s != null) && (s.equals(nssLibraryDirectory) == false)) { if ((s != null) &&
(s.equals(nssLibraryDirectory) == false)) {
throw new ProviderException("NSS library directory " throw new ProviderException("NSS library directory "
+ nssLibraryDirectory + nssLibraryDirectory
+ " invalid, NSS already initialized with " + s); + " invalid, NSS already initialized with "
+ s);
} }
} }
} else { } else {
if (nssDbMode != DbMode.NO_DB) { if (nssDbMode != DbMode.NO_DB) {
if (nssSecmodDirectory == null) { if (nssSecmodDirectory == null) {
throw new ProviderException("Secmod not initialized and " throw new ProviderException(
+ "nssSecmodDirectory not specified"); "Secmod not initialized and "
+ "nssSecmodDirectory not specified");
} }
} else { } else {
if (nssSecmodDirectory != null) { if (nssSecmodDirectory != null) {
throw new ProviderException throw new ProviderException(
("nssSecmodDirectory must not be specified in noDb mode"); "nssSecmodDirectory must not be "
+ "specified in noDb mode");
} }
} }
secmod.initialize(nssDbMode, nssSecmodDirectory, nssLibraryDirectory); secmod.initialize(nssDbMode, nssSecmodDirectory,
nssLibraryDirectory);
} }
} catch (IOException e) { } catch (IOException e) {
// XXX which exception to throw // XXX which exception to throw
...@@ -211,7 +221,8 @@ public final class SunPKCS11 extends AuthProvider { ...@@ -211,7 +221,8 @@ public final class SunPKCS11 extends AuthProvider {
if (nssModule != null) { if (nssModule != null) {
moduleName = "fips"; moduleName = "fips";
} else { } else {
moduleName = (nssDbMode == DbMode.NO_DB) ? "crypto" : "keystore"; moduleName = (nssDbMode == DbMode.NO_DB) ?
"crypto" : "keystore";
} }
} }
if (moduleName.equals("fips")) { if (moduleName.equals("fips")) {
...@@ -253,10 +264,12 @@ public final class SunPKCS11 extends AuthProvider { ...@@ -253,10 +264,12 @@ public final class SunPKCS11 extends AuthProvider {
+ ": only " + k + " external NSS modules available"); + ": only " + k + " external NSS modules available");
} }
} else { } else {
throw new ProviderException("Unknown NSS module: " + moduleName); throw new ProviderException(
"Unknown NSS module: " + moduleName);
} }
if (nssModule == null) { if (nssModule == null) {
throw new ProviderException("NSS module not available: " + moduleName); throw new ProviderException(
"NSS module not available: " + moduleName);
} }
if (nssModule.hasInitializedProvider()) { if (nssModule.hasInitializedProvider()) {
throw new ProviderException("Secmod module already configured"); throw new ProviderException("Secmod module already configured");
...@@ -296,8 +309,9 @@ public final class SunPKCS11 extends AuthProvider { ...@@ -296,8 +309,9 @@ public final class SunPKCS11 extends AuthProvider {
initArgs.flags = CKF_OS_LOCKING_OK; initArgs.flags = CKF_OS_LOCKING_OK;
PKCS11 tmpPKCS11; PKCS11 tmpPKCS11;
try { try {
tmpPKCS11 = PKCS11.getInstance tmpPKCS11 = PKCS11.getInstance(
(library, functionList, initArgs, config.getOmitInitialize()); library, functionList, initArgs,
config.getOmitInitialize());
} catch (PKCS11Exception e) { } catch (PKCS11Exception e) {
if (debug != null) { if (debug != null) {
debug.println("Multi-threaded initialization failed: " + e); debug.println("Multi-threaded initialization failed: " + e);
...@@ -312,8 +326,8 @@ public final class SunPKCS11 extends AuthProvider { ...@@ -312,8 +326,8 @@ public final class SunPKCS11 extends AuthProvider {
} else { } else {
initArgs.flags = 0; initArgs.flags = 0;
} }
tmpPKCS11 = PKCS11.getInstance tmpPKCS11 = PKCS11.getInstance(library,
(library, functionList, initArgs, config.getOmitInitialize()); functionList, initArgs, config.getOmitInitialize());
} }
p11 = tmpPKCS11; p11 = tmpPKCS11;
...@@ -336,8 +350,10 @@ public final class SunPKCS11 extends AuthProvider { ...@@ -336,8 +350,10 @@ public final class SunPKCS11 extends AuthProvider {
System.out.println("Slots with tokens: " + toString(slots)); System.out.println("Slots with tokens: " + toString(slots));
} }
if (slotID < 0) { if (slotID < 0) {
if ((slotListIndex < 0) || (slotListIndex >= slots.length)) { if ((slotListIndex < 0)
throw new ProviderException("slotListIndex is " + slotListIndex || (slotListIndex >= slots.length)) {
throw new ProviderException("slotListIndex is "
+ slotListIndex
+ " but token only has " + slots.length + " slots"); + " but token only has " + slots.length + " slots");
} }
slotID = slots[slotListIndex]; slotID = slots[slotListIndex];
...@@ -575,12 +591,15 @@ public final class SunPKCS11 extends AuthProvider { ...@@ -575,12 +591,15 @@ public final class SunPKCS11 extends AuthProvider {
d(KF, "DH", P11DHKeyFactory, s("DiffieHellman"), d(KF, "DH", P11DHKeyFactory, s("DiffieHellman"),
m(CKM_DH_PKCS_KEY_PAIR_GEN, CKM_DH_PKCS_DERIVE)); m(CKM_DH_PKCS_KEY_PAIR_GEN, CKM_DH_PKCS_DERIVE));
d(KF, "EC", P11DHKeyFactory, d(KF, "EC", P11DHKeyFactory,
m(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE, CKM_ECDSA, CKM_ECDSA_SHA1)); m(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE,
CKM_ECDSA, CKM_ECDSA_SHA1));
// AlgorithmParameters for EC. // AlgorithmParameters for EC.
// Only needed until we have an EC implementation in the SUN provider. // Only needed until we have an EC implementation in the SUN provider.
d(AGP, "EC", "sun.security.ec.ECParameters", s("1.2.840.10045.2.1"), d(AGP, "EC", "sun.security.ec.ECParameters",
m(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE, CKM_ECDSA, CKM_ECDSA_SHA1)); s("1.2.840.10045.2.1"),
m(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE,
CKM_ECDSA, CKM_ECDSA_SHA1));
d(KA, "DH", P11KeyAgreement, s("DiffieHellman"), d(KA, "DH", P11KeyAgreement, s("DiffieHellman"),
m(CKM_DH_PKCS_DERIVE)); m(CKM_DH_PKCS_DERIVE));
...@@ -654,12 +673,16 @@ public final class SunPKCS11 extends AuthProvider { ...@@ -654,12 +673,16 @@ public final class SunPKCS11 extends AuthProvider {
d(SIG, "SHA512withRSA", P11Signature, d(SIG, "SHA512withRSA", P11Signature,
m(CKM_SHA512_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509)); m(CKM_SHA512_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
d(KG, "SunTlsRsaPremasterSecret", "sun.security.pkcs11.P11TlsRsaPremasterSecretGenerator", d(KG, "SunTlsRsaPremasterSecret",
"sun.security.pkcs11.P11TlsRsaPremasterSecretGenerator",
m(CKM_SSL3_PRE_MASTER_KEY_GEN, CKM_TLS_PRE_MASTER_KEY_GEN)); m(CKM_SSL3_PRE_MASTER_KEY_GEN, CKM_TLS_PRE_MASTER_KEY_GEN));
d(KG, "SunTlsMasterSecret", "sun.security.pkcs11.P11TlsMasterSecretGenerator", d(KG, "SunTlsMasterSecret",
"sun.security.pkcs11.P11TlsMasterSecretGenerator",
m(CKM_SSL3_MASTER_KEY_DERIVE, CKM_TLS_MASTER_KEY_DERIVE, m(CKM_SSL3_MASTER_KEY_DERIVE, CKM_TLS_MASTER_KEY_DERIVE,
CKM_SSL3_MASTER_KEY_DERIVE_DH, CKM_TLS_MASTER_KEY_DERIVE_DH)); CKM_SSL3_MASTER_KEY_DERIVE_DH,
d(KG, "SunTlsKeyMaterial", "sun.security.pkcs11.P11TlsKeyMaterialGenerator", CKM_TLS_MASTER_KEY_DERIVE_DH));
d(KG, "SunTlsKeyMaterial",
"sun.security.pkcs11.P11TlsKeyMaterialGenerator",
m(CKM_SSL3_KEY_AND_MAC_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE)); m(CKM_SSL3_KEY_AND_MAC_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE));
d(KG, "SunTlsPrf", "sun.security.pkcs11.P11TlsPrfGenerator", d(KG, "SunTlsPrf", "sun.security.pkcs11.P11TlsPrfGenerator",
m(CKM_TLS_PRF, CKM_NSS_TLS_PRF_GENERAL)); m(CKM_TLS_PRF, CKM_NSS_TLS_PRF_GENERAL));
...@@ -773,6 +796,13 @@ public final class SunPKCS11 extends AuthProvider { ...@@ -773,6 +796,13 @@ public final class SunPKCS11 extends AuthProvider {
System.out.println(token.tokenInfo); System.out.println(token.tokenInfo);
} }
long[] supportedMechanisms = p11.C_GetMechanismList(slotID); long[] supportedMechanisms = p11.C_GetMechanismList(slotID);
// Create a map from the various Descriptors to the "most
// preferred" mechanism that was defined during the
// static initialization. For example, DES/CBC/PKCS5Padding
// could be mapped to CKM_DES_CBC_PAD or CKM_DES_CBC. Prefer
// the earliest entry. When asked for "DES/CBC/PKCS5Padding", we
// return a CKM_DES_CBC_PAD.
final Map<Descriptor,Integer> supportedAlgs = final Map<Descriptor,Integer> supportedAlgs =
new HashMap<Descriptor,Integer>(); new HashMap<Descriptor,Integer>();
for (int i = 0; i < supportedMechanisms.length; i++) { for (int i = 0; i < supportedMechanisms.length; i++) {
...@@ -807,6 +837,9 @@ public final class SunPKCS11 extends AuthProvider { ...@@ -807,6 +837,9 @@ public final class SunPKCS11 extends AuthProvider {
supportedAlgs.put(d, integerMech); supportedAlgs.put(d, integerMech);
continue; continue;
} }
// See if there is something "more preferred"
// than what we currently have in the supportedAlgs
// map.
int intOldMech = oldMech.intValue(); int intOldMech = oldMech.intValue();
for (int j = 0; j < d.mechanisms.length; j++) { for (int j = 0; j < d.mechanisms.length; j++) {
int nextMech = d.mechanisms[j]; int nextMech = d.mechanisms[j];
......
/* /*
* Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -31,6 +31,8 @@ import java.security.*; ...@@ -31,6 +31,8 @@ import java.security.*;
import java.security.interfaces.*; import java.security.interfaces.*;
import java.security.spec.*; import java.security.spec.*;
import sun.security.action.GetPropertyAction;
/** /**
* KeyFactory for RSA keys. Keys must be instances of PublicKey or PrivateKey * KeyFactory for RSA keys. Keys must be instances of PublicKey or PrivateKey
* and getAlgorithm() must return "RSA". For such keys, it supports conversion * and getAlgorithm() must return "RSA". For such keys, it supports conversion
...@@ -68,6 +70,24 @@ public final class RSAKeyFactory extends KeyFactorySpi { ...@@ -68,6 +70,24 @@ public final class RSAKeyFactory extends KeyFactorySpi {
private final static Class<?> x509KeySpecClass = X509EncodedKeySpec.class; private final static Class<?> x509KeySpecClass = X509EncodedKeySpec.class;
private final static Class<?> pkcs8KeySpecClass = PKCS8EncodedKeySpec.class; private final static Class<?> pkcs8KeySpecClass = PKCS8EncodedKeySpec.class;
public final static int MIN_MODLEN = 512;
public final static int MAX_MODLEN = 16384;
/*
* If the modulus length is above this value, restrict the size of
* the exponent to something that can be reasonably computed. We
* could simply hardcode the exp len to something like 64 bits, but
* this approach allows flexibility in case impls would like to use
* larger module and exponent values.
*/
public final static int MAX_MODLEN_RESTRICT_EXP = 3072;
public final static int MAX_RESTRICTED_EXPLEN = 64;
private static final boolean restrictExpLen =
"true".equalsIgnoreCase(AccessController.doPrivileged(
new GetPropertyAction(
"sun.security.rsa.restrictRSAExponent", "true")));
// instance used for static translateKey(); // instance used for static translateKey();
private final static RSAKeyFactory INSTANCE = new RSAKeyFactory(); private final static RSAKeyFactory INSTANCE = new RSAKeyFactory();
...@@ -76,74 +96,79 @@ public final class RSAKeyFactory extends KeyFactorySpi { ...@@ -76,74 +96,79 @@ public final class RSAKeyFactory extends KeyFactorySpi {
} }
/** /**
* Static method to convert Key into a useable instance of * Static method to convert Key into an instance of RSAPublicKeyImpl
* RSAPublicKey or RSAPrivate(Crt)Key. Check the key and convert it * or RSAPrivate(Crt)KeyImpl. If the key is not an RSA key or cannot be
* to a SunRsaSign key if necessary. If the key is not an RSA key * used, throw an InvalidKeyException.
* or cannot be used, throw an InvalidKeyException.
*
* The difference between this method and engineTranslateKey() is that
* we do not convert keys of other providers that are already an
* instance of RSAPublicKey or RSAPrivate(Crt)Key.
* *
* Used by RSASignature and RSACipher. * Used by RSASignature and RSACipher.
*/ */
public static RSAKey toRSAKey(Key key) throws InvalidKeyException { public static RSAKey toRSAKey(Key key) throws InvalidKeyException {
if (key instanceof RSAKey) { if ((key instanceof RSAPrivateKeyImpl) ||
RSAKey rsaKey = (RSAKey)key; (key instanceof RSAPrivateCrtKeyImpl) ||
checkKey(rsaKey); (key instanceof RSAPublicKeyImpl)) {
return rsaKey; return (RSAKey)key;
} else { } else {
return (RSAKey)INSTANCE.engineTranslateKey(key); return (RSAKey)INSTANCE.engineTranslateKey(key);
} }
} }
/** /*
* Check that the given RSA key is valid. * Single test entry point for all of the mechanisms in the SunRsaSign
* provider (RSA*KeyImpls). All of the tests are the same.
*
* For compatibility, we round up to the nearest byte here:
* some Key impls might pass in a value within a byte of the
* real value.
*/ */
private static void checkKey(RSAKey key) throws InvalidKeyException { static void checkRSAProviderKeyLengths(int modulusLen, BigInteger exponent)
// check for subinterfaces, omit additional checks for our keys throws InvalidKeyException {
if (key instanceof RSAPublicKey) { checkKeyLengths(((modulusLen + 7) & ~7), exponent,
if (key instanceof RSAPublicKeyImpl) { RSAKeyFactory.MIN_MODLEN, Integer.MAX_VALUE);
return;
}
} else if (key instanceof RSAPrivateKey) {
if ((key instanceof RSAPrivateCrtKeyImpl)
|| (key instanceof RSAPrivateKeyImpl)) {
return;
}
} else {
throw new InvalidKeyException("Neither a public nor a private key");
}
// RSAKey does not extend Key, so we need to do a cast
String keyAlg = ((Key)key).getAlgorithm();
if (keyAlg.equals("RSA") == false) {
throw new InvalidKeyException("Not an RSA key: " + keyAlg);
}
BigInteger modulus;
// some providers implement RSAKey for keys where the values are
// not accessible (although they should). Detect those here
// for a more graceful failure.
try {
modulus = key.getModulus();
if (modulus == null) {
throw new InvalidKeyException("Modulus is missing");
}
} catch (RuntimeException e) {
throw new InvalidKeyException(e);
}
checkKeyLength(modulus);
} }
/** /**
* Check the length of the modulus of an RSA key. We only support keys * Check the length of an RSA key modulus/exponent to make sure it
* at least 505 bits long. * is not too short or long. Some impls have their own min and
* max key sizes that may or may not match with a system defined value.
*
* @param modulusLen the bit length of the RSA modulus.
* @param exponent the RSA exponent
* @param minModulusLen if > 0, check to see if modulusLen is at
* least this long, otherwise unused.
* @param maxModulusLen caller will allow this max number of bits.
* Allow the smaller of the system-defined maximum and this param.
*
* @throws InvalidKeyException if any of the values are unacceptable.
*/ */
static void checkKeyLength(BigInteger modulus) throws InvalidKeyException { public static void checkKeyLengths(int modulusLen, BigInteger exponent,
if (modulus.bitLength() < 505) { int minModulusLen, int maxModulusLen) throws InvalidKeyException {
// some providers may generate slightly shorter keys
// accept them if the encoding is at least 64 bytes long if ((minModulusLen > 0) && (modulusLen < (minModulusLen))) {
throw new InvalidKeyException throw new InvalidKeyException( "RSA keys must be at least " +
("RSA keys must be at least 512 bits long"); minModulusLen + " bits long");
}
// Even though our policy file may allow this, we don't want
// either value (mod/exp) to be too big.
int maxLen = Math.min(maxModulusLen, MAX_MODLEN);
// If a RSAPrivateKey/RSAPublicKey, make sure the
// modulus len isn't too big.
if (modulusLen > maxLen) {
throw new InvalidKeyException(
"RSA keys must be no longer than " + maxLen + " bits");
}
// If a RSAPublicKey, make sure the exponent isn't too big.
if (restrictExpLen && (exponent != null) &&
(modulusLen > MAX_MODLEN_RESTRICT_EXP) &&
(exponent.bitLength() > MAX_RESTRICTED_EXPLEN)) {
throw new InvalidKeyException(
"RSA exponents can be no longer than " +
MAX_RESTRICTED_EXPLEN + " bits " +
" if modulus is greater than " +
MAX_MODLEN_RESTRICT_EXP + " bits");
} }
} }
......
/* /*
* Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -47,7 +47,7 @@ public final class RSAKeyPairGenerator extends KeyPairGeneratorSpi { ...@@ -47,7 +47,7 @@ public final class RSAKeyPairGenerator extends KeyPairGeneratorSpi {
// public exponent to use // public exponent to use
private BigInteger publicExponent; private BigInteger publicExponent;
// size of the key to generate, >= 512 // size of the key to generate, >= RSAKeyFactory.MIN_MODLEN
private int keySize; private int keySize;
// PRNG to use // PRNG to use
...@@ -60,15 +60,16 @@ public final class RSAKeyPairGenerator extends KeyPairGeneratorSpi { ...@@ -60,15 +60,16 @@ public final class RSAKeyPairGenerator extends KeyPairGeneratorSpi {
// initialize the generator. See JCA doc // initialize the generator. See JCA doc
public void initialize(int keySize, SecureRandom random) { public void initialize(int keySize, SecureRandom random) {
if (keySize < 512) {
throw new InvalidParameterException // do not allow unreasonably small or large key sizes,
("Key size must be at least 512 bits"); // probably user error
} try {
if (keySize > 64 * 1024) { RSAKeyFactory.checkKeyLengths(keySize, RSAKeyGenParameterSpec.F4,
// do not allow unreasonably large key sizes, probably user error 512, 64 * 1024);
throw new InvalidParameterException } catch (InvalidKeyException e) {
("Key size must be 65536 bits or less"); throw new InvalidParameterException(e.getMessage());
} }
this.keySize = keySize; this.keySize = keySize;
this.random = random; this.random = random;
this.publicExponent = RSAKeyGenParameterSpec.F4; this.publicExponent = RSAKeyGenParameterSpec.F4;
...@@ -77,35 +78,41 @@ public final class RSAKeyPairGenerator extends KeyPairGeneratorSpi { ...@@ -77,35 +78,41 @@ public final class RSAKeyPairGenerator extends KeyPairGeneratorSpi {
// second initialize method. See JCA doc. // second initialize method. See JCA doc.
public void initialize(AlgorithmParameterSpec params, SecureRandom random) public void initialize(AlgorithmParameterSpec params, SecureRandom random)
throws InvalidAlgorithmParameterException { throws InvalidAlgorithmParameterException {
if (params instanceof RSAKeyGenParameterSpec == false) { if (params instanceof RSAKeyGenParameterSpec == false) {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
("Params must be instance of RSAKeyGenParameterSpec"); ("Params must be instance of RSAKeyGenParameterSpec");
} }
RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec)params; RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec)params;
keySize = rsaSpec.getKeysize(); int tmpKeySize = rsaSpec.getKeysize();
publicExponent = rsaSpec.getPublicExponent(); BigInteger tmpPublicExponent = rsaSpec.getPublicExponent();
this.random = random;
if (keySize < 512) { if (tmpPublicExponent == null) {
throw new InvalidAlgorithmParameterException tmpPublicExponent = RSAKeyGenParameterSpec.F4;
("Key size must be at least 512 bits");
}
if (keySize > 64 * 1024) {
// do not allow unreasonably large key sizes, probably user error
throw new InvalidAlgorithmParameterException
("Key size must be 65536 bits or less");
}
if (publicExponent == null) {
publicExponent = RSAKeyGenParameterSpec.F4;
} else { } else {
if (publicExponent.compareTo(RSAKeyGenParameterSpec.F0) < 0) { if (tmpPublicExponent.compareTo(RSAKeyGenParameterSpec.F0) < 0) {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
("Public exponent must be 3 or larger"); ("Public exponent must be 3 or larger");
} }
if (publicExponent.bitLength() > keySize) { if (tmpPublicExponent.bitLength() > tmpKeySize) {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
("Public exponent must be smaller than key size"); ("Public exponent must be smaller than key size");
} }
} }
// do not allow unreasonably large key sizes, probably user error
try {
RSAKeyFactory.checkKeyLengths(tmpKeySize, tmpPublicExponent,
512, 64 * 1024);
} catch (InvalidKeyException e) {
throw new InvalidAlgorithmParameterException(
"Invalid key sizes", e);
}
this.keySize = tmpKeySize;
this.publicExponent = tmpPublicExponent;
this.random = random;
} }
// generate the keypair. See JCA doc // generate the keypair. See JCA doc
......
/* /*
* Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -89,7 +89,7 @@ public final class RSAPrivateCrtKeyImpl ...@@ -89,7 +89,7 @@ public final class RSAPrivateCrtKeyImpl
*/ */
RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException { RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException {
decode(encoded); decode(encoded);
RSAKeyFactory.checkKeyLength(n); RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
} }
/** /**
...@@ -107,7 +107,8 @@ public final class RSAPrivateCrtKeyImpl ...@@ -107,7 +107,8 @@ public final class RSAPrivateCrtKeyImpl
this.pe = pe; this.pe = pe;
this.qe = qe; this.qe = qe;
this.coeff = coeff; this.coeff = coeff;
RSAKeyFactory.checkKeyLength(n); RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
// generate the encoding // generate the encoding
algid = rsaId; algid = rsaId;
try { try {
......
/* /*
* Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -61,7 +61,7 @@ public final class RSAPrivateKeyImpl extends PKCS8Key implements RSAPrivateKey { ...@@ -61,7 +61,7 @@ public final class RSAPrivateKeyImpl extends PKCS8Key implements RSAPrivateKey {
RSAPrivateKeyImpl(BigInteger n, BigInteger d) throws InvalidKeyException { RSAPrivateKeyImpl(BigInteger n, BigInteger d) throws InvalidKeyException {
this.n = n; this.n = n;
this.d = d; this.d = d;
RSAKeyFactory.checkKeyLength(n); RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), null);
// generate the encoding // generate the encoding
algid = RSAPrivateCrtKeyImpl.rsaId; algid = RSAPrivateCrtKeyImpl.rsaId;
try { try {
......
/* /*
* Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -56,10 +56,11 @@ public final class RSAPublicKeyImpl extends X509Key implements RSAPublicKey { ...@@ -56,10 +56,11 @@ public final class RSAPublicKeyImpl extends X509Key implements RSAPublicKey {
* Construct a key from its components. Used by the * Construct a key from its components. Used by the
* RSAKeyFactory and the RSAKeyPairGenerator. * RSAKeyFactory and the RSAKeyPairGenerator.
*/ */
public RSAPublicKeyImpl(BigInteger n, BigInteger e) throws InvalidKeyException { public RSAPublicKeyImpl(BigInteger n, BigInteger e)
throws InvalidKeyException {
this.n = n; this.n = n;
this.e = e; this.e = e;
RSAKeyFactory.checkKeyLength(n); RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
// generate the encoding // generate the encoding
algid = RSAPrivateCrtKeyImpl.rsaId; algid = RSAPrivateCrtKeyImpl.rsaId;
try { try {
...@@ -80,7 +81,7 @@ public final class RSAPublicKeyImpl extends X509Key implements RSAPublicKey { ...@@ -80,7 +81,7 @@ public final class RSAPublicKeyImpl extends X509Key implements RSAPublicKey {
*/ */
public RSAPublicKeyImpl(byte[] encoded) throws InvalidKeyException { public RSAPublicKeyImpl(byte[] encoded) throws InvalidKeyException {
decode(encoded); decode(encoded);
RSAKeyFactory.checkKeyLength(n); RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
} }
// see JCA doc // see JCA doc
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
# passwords. To be functional, a role must have an entry in # passwords. To be functional, a role must have an entry in
# both the password and the access files. # both the password and the access files.
# #
# Default location of this file is $JRE/lib/management/jmxremote.access # The default location of this file is $JRE/lib/management/jmxremote.access
# You can specify an alternate location by specifying a property in # You can specify an alternate location by specifying a property in
# the management config file $JRE/lib/management/management.properties # the management config file $JRE/lib/management/management.properties
# (See that file for details) # (See that file for details)
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
# The file format for password and access files is syntactically the same # The file format for password and access files is syntactically the same
# as the Properties file format. The syntax is described in the Javadoc # as the Properties file format. The syntax is described in the Javadoc
# for java.util.Properties.load. # for java.util.Properties.load.
# Typical access file has multiple lines, where each line is blank, # A typical access file has multiple lines, where each line is blank,
# a comment (like this one), or an access control entry. # a comment (like this one), or an access control entry.
# #
# An access control entry consists of a role name, and an # An access control entry consists of a role name, and an
...@@ -29,10 +29,38 @@ ...@@ -29,10 +29,38 @@
# role can read measurements but cannot perform any action # role can read measurements but cannot perform any action
# that changes the environment of the running program. # that changes the environment of the running program.
# "readwrite" grants access to read and write attributes of MBeans, # "readwrite" grants access to read and write attributes of MBeans,
# to invoke operations on them, and to create or remove them. # to invoke operations on them, and optionally
# This access should be granted to only trusted clients, # to create or remove them. This access should be granted
# since they can potentially interfere with the smooth # only to trusted clients, since they can potentially
# operation of a running program # interfere with the smooth operation of a running program.
#
# The "readwrite" access level can optionally be followed by the "create" and/or
# "unregister" keywords. The "unregister" keyword grants access to unregister
# (delete) MBeans. The "create" keyword grants access to create MBeans of a
# particular class or of any class matching a particular pattern. Access
# should only be granted to create MBeans of known and trusted classes.
#
# For example, the following entry would grant readwrite access
# to "controlRole", as well as access to create MBeans of the class
# javax.management.monitor.CounterMonitor and to unregister any MBean:
# controlRole readwrite \
# create javax.management.monitor.CounterMonitorMBean \
# unregister
# or equivalently:
# controlRole readwrite unregister create javax.management.monitor.CounterMBean
#
# The following entry would grant readwrite access as well as access to create
# MBeans of any class in the packages javax.management.monitor and
# javax.management.timer:
# controlRole readwrite \
# create javax.management.monitor.*,javax.management.timer.* \
# unregister
#
# The \ character is defined in the Properties file syntax to allow continuation
# lines as shown here. A * in a class pattern matches a sequence of characters
# other than dot (.), so javax.management.monitor.* matches
# javax.management.monitor.CounterMonitor but not
# javax.management.monitor.foo.Bar.
# #
# A given role should have at most one entry in this file. If a role # A given role should have at most one entry in this file. If a role
# has no entry, it has no access. # has no entry, it has no access.
...@@ -42,7 +70,10 @@ ...@@ -42,7 +70,10 @@
# #
# Default access control entries: # Default access control entries:
# o The "monitorRole" role has readonly access. # o The "monitorRole" role has readonly access.
# o The "controlRole" role has readwrite access. # o The "controlRole" role has readwrite access and can create the standard
# Timer and Monitor MBeans defined by the JMX API.
monitorRole readonly monitorRole readonly
controlRole readwrite controlRole readwrite \
create javax.management.monitor.*,javax.management.timer.* \
unregister
/* /*
* Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -94,6 +94,7 @@ void band::readData(int expectedLength) { ...@@ -94,6 +94,7 @@ void band::readData(int expectedLength) {
assert(!valc->isMalloc); assert(!valc->isMalloc);
} }
xvs.init(u->rp, u->rplimit, valc); xvs.init(u->rp, u->rplimit, valc);
CHECK;
int X = xvs.getInt(); int X = xvs.getInt();
if (valc->S() != 0) { if (valc->S() != 0) {
assert(valc->min <= -256); assert(valc->min <= -256);
...@@ -117,6 +118,7 @@ void band::readData(int expectedLength) { ...@@ -117,6 +118,7 @@ void band::readData(int expectedLength) {
byte XB_byte = (byte) XB; byte XB_byte = (byte) XB;
byte* XB_ptr = &XB_byte; byte* XB_ptr = &XB_byte;
cm.init(u->rp, u->rplimit, XB_ptr, 0, defc, length, null); cm.init(u->rp, u->rplimit, XB_ptr, 0, defc, length, null);
CHECK;
} else { } else {
NOT_PRODUCT(byte* meta_rp0 = u->meta_rp); NOT_PRODUCT(byte* meta_rp0 = u->meta_rp);
assert(u->meta_rp != null); assert(u->meta_rp != null);
...@@ -215,8 +217,19 @@ int band::getIntTotal() { ...@@ -215,8 +217,19 @@ int band::getIntTotal() {
if (length == 0) return 0; if (length == 0) return 0;
if (total_memo > 0) return total_memo-1; if (total_memo > 0) return total_memo-1;
int total = getInt(); int total = getInt();
// overflow checks require that none of the addends are <0,
// and that the partial sums never overflow (wrap negative)
if (total < 0) {
abort("overflow detected");
return 0;
}
for (int k = length-1; k > 0; k--) { for (int k = length-1; k > 0; k--) {
int prev_total = total;
total += vs[0].getInt(); total += vs[0].getInt();
if (total < prev_total) {
abort("overflow detected");
return 0;
}
} }
rewind(); rewind();
total_memo = total+1; total_memo = total+1;
......
...@@ -56,7 +56,7 @@ void bytes::realloc(size_t len_) { ...@@ -56,7 +56,7 @@ void bytes::realloc(size_t len_) {
return; return;
} }
byte* oldptr = ptr; byte* oldptr = ptr;
ptr = (byte*)::realloc(ptr, len_+1); ptr = (len_ >= PSIZE_MAX) ? null : (byte*)::realloc(ptr, len_+1);
if (ptr != null) { if (ptr != null) {
mtrace('r', oldptr, 0); mtrace('r', oldptr, 0);
mtrace('m', ptr, len_+1); mtrace('m', ptr, len_+1);
...@@ -128,7 +128,7 @@ const char* bytes::string() { ...@@ -128,7 +128,7 @@ const char* bytes::string() {
// Make sure there are 'o' bytes beyond the fill pointer, // Make sure there are 'o' bytes beyond the fill pointer,
// advance the fill pointer, and return the old fill pointer. // advance the fill pointer, and return the old fill pointer.
byte* fillbytes::grow(size_t s) { byte* fillbytes::grow(size_t s) {
size_t nlen = b.len+s; size_t nlen = add_size(b.len, s);
if (nlen <= allocated) { if (nlen <= allocated) {
b.len = nlen; b.len = nlen;
return limit()-s; return limit()-s;
......
/* /*
* Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -814,6 +814,7 @@ void coding_method::init(byte* &band_rp, byte* band_limit, ...@@ -814,6 +814,7 @@ void coding_method::init(byte* &band_rp, byte* band_limit,
} }
band_rp = vs.rp; band_rp = vs.rp;
} }
CHECK;
// Get an accurate upper limit now. // Get an accurate upper limit now.
vs0.rplimit = band_rp; vs0.rplimit = band_rp;
......
/* /*
* Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -47,11 +47,13 @@ ...@@ -47,11 +47,13 @@
#define NOT_PRODUCT(xxx) #define NOT_PRODUCT(xxx)
#define assert(p) #define assert(p)
#define PRINTCR(args) #define PRINTCR(args)
#define VERSION_STRING "%s version %s\n"
#else #else
#define IF_PRODUCT(xxx) #define IF_PRODUCT(xxx)
#define NOT_PRODUCT(xxx) xxx #define NOT_PRODUCT(xxx) xxx
#define assert(p) ((p) || assert_failed(#p)) #define assert(p) ((p) || assert_failed(#p))
#define PRINTCR(args) u->verbose && u->printcr_if_verbose args #define PRINTCR(args) u->verbose && u->printcr_if_verbose args
#define VERSION_STRING "%s version non-product %s\n"
extern "C" void breakpoint(); extern "C" void breakpoint();
extern int assert_failed(const char*); extern int assert_failed(const char*);
#define BREAK (breakpoint()) #define BREAK (breakpoint())
...@@ -79,9 +81,9 @@ extern int assert_failed(const char*); ...@@ -79,9 +81,9 @@ extern int assert_failed(const char*);
#define lengthof(array) (sizeof(array)/sizeof(array[0])) #define lengthof(array) (sizeof(array)/sizeof(array[0]))
#define NEW(T, n) (T*) must_malloc((int)(sizeof(T)*(n))) #define NEW(T, n) (T*) must_malloc((int)(scale_size(n, sizeof(T))))
#define U_NEW(T, n) (T*) u->alloc(sizeof(T)*(n)) #define U_NEW(T, n) (T*) u->alloc(scale_size(n, sizeof(T)))
#define T_NEW(T, n) (T*) u->temp_alloc(sizeof(T)*(n)) #define T_NEW(T, n) (T*) u->temp_alloc(scale_size(n, sizeof(T)))
// bytes and byte arrays // bytes and byte arrays
...@@ -153,6 +155,8 @@ enum { false, true }; ...@@ -153,6 +155,8 @@ enum { false, true };
#define CHECK_NULL_(y,p) _CHECK_DO((p)==null, return y) #define CHECK_NULL_(y,p) _CHECK_DO((p)==null, return y)
#define CHECK_NULL_0(p) _CHECK_DO((p)==null, return 0) #define CHECK_NULL_0(p) _CHECK_DO((p)==null, return 0)
#define CHECK_COUNT(t) if (t < 0){abort("bad value count");} CHECK
#define STR_TRUE "true" #define STR_TRUE "true"
#define STR_FALSE "false" #define STR_FALSE "false"
......
...@@ -299,7 +299,7 @@ int unpacker::run(int argc, char **argv) { ...@@ -299,7 +299,7 @@ int unpacker::run(int argc, char **argv) {
case 'J': argp += 1; break; // skip ignored -Jxxx parameter case 'J': argp += 1; break; // skip ignored -Jxxx parameter
case 'V': case 'V':
fprintf(u.errstrm, "%s version %s\n", nbasename(argv[0]), sccsver); fprintf(u.errstrm, VERSION_STRING, nbasename(argv[0]), sccsver);
exit(0); exit(0);
case 'h': case 'h':
......
/* /*
* Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -523,15 +523,39 @@ void unpacker::read_file_header() { ...@@ -523,15 +523,39 @@ void unpacker::read_file_header() {
enum { enum {
MAGIC_BYTES = 4, MAGIC_BYTES = 4,
AH_LENGTH_0 = 3, //minver, majver, options are outside of archive_size AH_LENGTH_0 = 3, //minver, majver, options are outside of archive_size
AH_LENGTH_0_MAX = AH_LENGTH_0 + 1, // options might have 2 bytes
AH_LENGTH = 26, //maximum archive header length (w/ all fields) AH_LENGTH = 26, //maximum archive header length (w/ all fields)
// Length contributions from optional header fields: // Length contributions from optional header fields:
AH_FILE_HEADER_LEN = 5, // sizehi/lo/next/modtime/files AH_FILE_HEADER_LEN = 5, // sizehi/lo/next/modtime/files
AH_ARCHIVE_SIZE_LEN = 2, // sizehi/lo only; part of AH_FILE_HEADER_LEN
AH_CP_NUMBER_LEN = 4, // int/float/long/double AH_CP_NUMBER_LEN = 4, // int/float/long/double
AH_SPECIAL_FORMAT_LEN = 2, // layouts/band-headers AH_SPECIAL_FORMAT_LEN = 2, // layouts/band-headers
AH_LENGTH_MIN = AH_LENGTH AH_LENGTH_MIN = AH_LENGTH
-(AH_FILE_HEADER_LEN+AH_SPECIAL_FORMAT_LEN+AH_CP_NUMBER_LEN), -(AH_FILE_HEADER_LEN+AH_SPECIAL_FORMAT_LEN+AH_CP_NUMBER_LEN),
ARCHIVE_SIZE_MIN = AH_LENGTH_MIN - (AH_LENGTH_0 + AH_ARCHIVE_SIZE_LEN),
FIRST_READ = MAGIC_BYTES + AH_LENGTH_MIN FIRST_READ = MAGIC_BYTES + AH_LENGTH_MIN
}; };
assert(AH_LENGTH_MIN == 15); // # of UNSIGNED5 fields required after archive_magic
assert(ARCHIVE_SIZE_MIN == 10); // # of UNSIGNED5 fields required after archive_size
// An absolute minimum null archive is magic[4], {minver,majver,options}[3],
// archive_size[0], cp_counts[8], class_counts[4], for a total of 19 bytes.
// (Note that archive_size is optional; it may be 0..10 bytes in length.)
// The first read must capture everything up through the options field.
// This happens to work even if {minver,majver,options} is a pathological
// 15 bytes long. Legal pack files limit those three fields to 1+1+2 bytes.
assert(FIRST_READ >= MAGIC_BYTES + AH_LENGTH_0 * B_MAX);
// Up through archive_size, the largest possible archive header is
// magic[4], {minver,majver,options}[4], archive_size[10].
// (Note only the low 12 bits of options are allowed to be non-zero.)
// In order to parse archive_size, we need at least this many bytes
// in the first read. Of course, if archive_size_hi is more than
// a byte, we probably will fail to allocate the buffer, since it
// will be many gigabytes long. This is a practical, not an
// architectural limit to Pack200 archive sizes.
assert(FIRST_READ >= MAGIC_BYTES + AH_LENGTH_0_MAX + 2*B_MAX);
bool foreign_buf = (read_input_fn == null); bool foreign_buf = (read_input_fn == null);
byte initbuf[(int)FIRST_READ + (int)C_SLOP + 200]; // 200 is for JAR I/O byte initbuf[(int)FIRST_READ + (int)C_SLOP + 200]; // 200 is for JAR I/O
if (foreign_buf) { if (foreign_buf) {
...@@ -547,7 +571,7 @@ void unpacker::read_file_header() { ...@@ -547,7 +571,7 @@ void unpacker::read_file_header() {
// There is no way to tell the caller that we used only part of them. // There is no way to tell the caller that we used only part of them.
// Therefore, the caller must use only a bare minimum of read-ahead. // Therefore, the caller must use only a bare minimum of read-ahead.
if (inbytes.len > FIRST_READ) { if (inbytes.len > FIRST_READ) {
abort("too much pushback"); abort("too much read-ahead");
return; return;
} }
input.set(initbuf, sizeof(initbuf)); input.set(initbuf, sizeof(initbuf));
...@@ -557,7 +581,7 @@ void unpacker::read_file_header() { ...@@ -557,7 +581,7 @@ void unpacker::read_file_header() {
rplimit += inbytes.len; rplimit += inbytes.len;
bytes_read += inbytes.len; bytes_read += inbytes.len;
} }
// Read only 19 bytes, which is certain to contain #archive_size fields, // Read only 19 bytes, which is certain to contain #archive_options fields,
// but is certain not to overflow past the archive_header. // but is certain not to overflow past the archive_header.
input.b.len = FIRST_READ; input.b.len = FIRST_READ;
if (!ensure_input(FIRST_READ)) if (!ensure_input(FIRST_READ))
...@@ -629,26 +653,25 @@ void unpacker::read_file_header() { ...@@ -629,26 +653,25 @@ void unpacker::read_file_header() {
#undef ORBIT #undef ORBIT
if ((archive_options & ~OPTION_LIMIT) != 0) { if ((archive_options & ~OPTION_LIMIT) != 0) {
fprintf(errstrm, "Warning: Illegal archive options 0x%x\n", fprintf(errstrm, "Warning: Illegal archive options 0x%x\n",
archive_options); archive_options);
// Do not abort. If the format really changes, version numbers will bump. abort("illegal archive options");
//abort("illegal archive options"); return;
} }
if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) { if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) {
uint hi = hdr.getInt(); uint hi = hdr.getInt();
uint lo = hdr.getInt(); uint lo = hdr.getInt();
archive_size = band::makeLong(hi, lo); julong x = band::makeLong(hi, lo);
archive_size = (size_t) x;
if (archive_size != x) {
// Silly size specified; force overflow.
archive_size = PSIZE_MAX+1;
}
hdrVals += 2; hdrVals += 2;
} else { } else {
hdrValsSkipped += 2; hdrValsSkipped += 2;
} }
if (archive_size != (size_t)archive_size) {
// Silly size specified.
abort("archive too large");
return;
}
// Now we can size the whole archive. // Now we can size the whole archive.
// Read everything else into a mega-buffer. // Read everything else into a mega-buffer.
rp = hdr.rp; rp = hdr.rp;
...@@ -662,9 +685,18 @@ void unpacker::read_file_header() { ...@@ -662,9 +685,18 @@ void unpacker::read_file_header() {
abort("EOF reading fixed input buffer"); abort("EOF reading fixed input buffer");
return; return;
} }
} else if (archive_size > 0) { } else if (archive_size != 0) {
input.set(U_NEW(byte, (size_t)(header_size_0 + archive_size + C_SLOP)), if (archive_size < ARCHIVE_SIZE_MIN) {
(size_t) header_size_0 + (size_t)archive_size); abort("impossible archive size"); // bad input data
return;
}
if (archive_size < header_size_1) {
abort("too much read-ahead"); // somehow we pre-fetched too much?
return;
}
input.set(U_NEW(byte, add_size(header_size_0, archive_size, C_SLOP)),
(size_t) header_size_0 + archive_size);
CHECK;
assert(input.limit()[0] == 0); assert(input.limit()[0] == 0);
// Move all the bytes we read initially into the real buffer. // Move all the bytes we read initially into the real buffer.
input.b.copyFrom(initbuf, header_size); input.b.copyFrom(initbuf, header_size);
...@@ -673,17 +705,17 @@ void unpacker::read_file_header() { ...@@ -673,17 +705,17 @@ void unpacker::read_file_header() {
} else { } else {
// It's more complicated and painful. // It's more complicated and painful.
// A zero archive_size means that we must read until EOF. // A zero archive_size means that we must read until EOF.
assert(archive_size == 0);
input.init(CHUNK*2); input.init(CHUNK*2);
CHECK; CHECK;
input.b.len = input.allocated; input.b.len = input.allocated;
rp = rplimit = input.base(); rp = rplimit = input.base();
// Set up input buffer as if we already read the header: // Set up input buffer as if we already read the header:
input.b.copyFrom(initbuf, header_size); input.b.copyFrom(initbuf, header_size);
CHECK;
rplimit += header_size; rplimit += header_size;
while (ensure_input(input.limit() - rp)) { while (ensure_input(input.limit() - rp)) {
size_t dataSoFar = input_remaining(); size_t dataSoFar = input_remaining();
size_t nextSize = dataSoFar + CHUNK; size_t nextSize = add_size(dataSoFar, CHUNK);
input.ensureSize(nextSize); input.ensureSize(nextSize);
CHECK; CHECK;
input.b.len = input.allocated; input.b.len = input.allocated;
...@@ -715,8 +747,10 @@ void unpacker::read_file_header() { ...@@ -715,8 +747,10 @@ void unpacker::read_file_header() {
if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) { if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) {
archive_next_count = hdr.getInt(); archive_next_count = hdr.getInt();
CHECK_COUNT(archive_next_count);
archive_modtime = hdr.getInt(); archive_modtime = hdr.getInt();
file_count = hdr.getInt(); file_count = hdr.getInt();
CHECK_COUNT(file_count);
hdrVals += 3; hdrVals += 3;
} else { } else {
hdrValsSkipped += 3; hdrValsSkipped += 3;
...@@ -724,7 +758,9 @@ void unpacker::read_file_header() { ...@@ -724,7 +758,9 @@ void unpacker::read_file_header() {
if ((archive_options & AO_HAVE_SPECIAL_FORMATS) != 0) { if ((archive_options & AO_HAVE_SPECIAL_FORMATS) != 0) {
band_headers_size = hdr.getInt(); band_headers_size = hdr.getInt();
CHECK_COUNT(band_headers_size);
attr_definition_count = hdr.getInt(); attr_definition_count = hdr.getInt();
CHECK_COUNT(attr_definition_count);
hdrVals += 2; hdrVals += 2;
} else { } else {
hdrValsSkipped += 2; hdrValsSkipped += 2;
...@@ -744,13 +780,16 @@ void unpacker::read_file_header() { ...@@ -744,13 +780,16 @@ void unpacker::read_file_header() {
} }
} }
cp_counts[k] = hdr.getInt(); cp_counts[k] = hdr.getInt();
CHECK_COUNT(cp_counts[k]);
hdrVals += 1; hdrVals += 1;
} }
ic_count = hdr.getInt(); ic_count = hdr.getInt();
CHECK_COUNT(ic_count);
default_class_minver = hdr.getInt(); default_class_minver = hdr.getInt();
default_class_majver = hdr.getInt(); default_class_majver = hdr.getInt();
class_count = hdr.getInt(); class_count = hdr.getInt();
CHECK_COUNT(class_count);
hdrVals += 4; hdrVals += 4;
// done with archive_header // done with archive_header
...@@ -807,7 +846,6 @@ void unpacker::read_file_header() { ...@@ -807,7 +846,6 @@ void unpacker::read_file_header() {
bytes::of(band_headers.limit(), C_SLOP).clear(_meta_error); bytes::of(band_headers.limit(), C_SLOP).clear(_meta_error);
} }
void unpacker::finish() { void unpacker::finish() {
if (verbose >= 1) { if (verbose >= 1) {
fprintf(errstrm, fprintf(errstrm,
...@@ -973,12 +1011,12 @@ void unpacker::read_Utf8_values(entry* cpMap, int len) { ...@@ -973,12 +1011,12 @@ void unpacker::read_Utf8_values(entry* cpMap, int len) {
// First band: Read lengths of shared prefixes. // First band: Read lengths of shared prefixes.
if (len > PREFIX_SKIP_2) if (len > PREFIX_SKIP_2)
cp_Utf8_prefix.readData(len - PREFIX_SKIP_2); cp_Utf8_prefix.readData(len - PREFIX_SKIP_2);
NOT_PRODUCT(else cp_Utf8_prefix.readData(0)); // for asserts NOT_PRODUCT(else cp_Utf8_prefix.readData(0)); // for asserts
// Second band: Read lengths of unshared suffixes: // Second band: Read lengths of unshared suffixes:
if (len > SUFFIX_SKIP_1) if (len > SUFFIX_SKIP_1)
cp_Utf8_suffix.readData(len - SUFFIX_SKIP_1); cp_Utf8_suffix.readData(len - SUFFIX_SKIP_1);
NOT_PRODUCT(else cp_Utf8_suffix.readData(0)); // for asserts NOT_PRODUCT(else cp_Utf8_suffix.readData(0)); // for asserts
bytes* allsuffixes = T_NEW(bytes, len); bytes* allsuffixes = T_NEW(bytes, len);
CHECK; CHECK;
...@@ -2117,6 +2155,7 @@ void unpacker::read_classes() { ...@@ -2117,6 +2155,7 @@ void unpacker::read_classes() {
field_descr.readData(field_count); field_descr.readData(field_count);
read_attrs(ATTR_CONTEXT_FIELD, field_count); read_attrs(ATTR_CONTEXT_FIELD, field_count);
CHECK;
method_descr.readData(method_count); method_descr.readData(method_count);
read_attrs(ATTR_CONTEXT_METHOD, method_count); read_attrs(ATTR_CONTEXT_METHOD, method_count);
...@@ -2124,6 +2163,7 @@ void unpacker::read_classes() { ...@@ -2124,6 +2163,7 @@ void unpacker::read_classes() {
CHECK; CHECK;
read_attrs(ATTR_CONTEXT_CLASS, class_count); read_attrs(ATTR_CONTEXT_CLASS, class_count);
CHECK;
read_code_headers(); read_code_headers();
...@@ -2150,10 +2190,12 @@ void unpacker::read_attrs(int attrc, int obj_count) { ...@@ -2150,10 +2190,12 @@ void unpacker::read_attrs(int attrc, int obj_count) {
assert(endsWith(xxx_flags_hi.name, "_flags_hi")); assert(endsWith(xxx_flags_hi.name, "_flags_hi"));
if (haveLongFlags) if (haveLongFlags)
xxx_flags_hi.readData(obj_count); xxx_flags_hi.readData(obj_count);
CHECK;
band& xxx_flags_lo = ad.xxx_flags_lo(); band& xxx_flags_lo = ad.xxx_flags_lo();
assert(endsWith(xxx_flags_lo.name, "_flags_lo")); assert(endsWith(xxx_flags_lo.name, "_flags_lo"));
xxx_flags_lo.readData(obj_count); xxx_flags_lo.readData(obj_count);
CHECK;
// pre-scan flags, counting occurrences of each index bit // pre-scan flags, counting occurrences of each index bit
julong indexMask = ad.flagIndexMask(); // which flag bits are index bits? julong indexMask = ad.flagIndexMask(); // which flag bits are index bits?
...@@ -2176,11 +2218,13 @@ void unpacker::read_attrs(int attrc, int obj_count) { ...@@ -2176,11 +2218,13 @@ void unpacker::read_attrs(int attrc, int obj_count) {
assert(endsWith(xxx_attr_count.name, "_attr_count")); assert(endsWith(xxx_attr_count.name, "_attr_count"));
// There is one count element for each 1<<16 bit set in flags: // There is one count element for each 1<<16 bit set in flags:
xxx_attr_count.readData(ad.predefCount(X_ATTR_OVERFLOW)); xxx_attr_count.readData(ad.predefCount(X_ATTR_OVERFLOW));
CHECK;
band& xxx_attr_indexes = ad.xxx_attr_indexes(); band& xxx_attr_indexes = ad.xxx_attr_indexes();
assert(endsWith(xxx_attr_indexes.name, "_attr_indexes")); assert(endsWith(xxx_attr_indexes.name, "_attr_indexes"));
int overflowIndexCount = xxx_attr_count.getIntTotal(); int overflowIndexCount = xxx_attr_count.getIntTotal();
xxx_attr_indexes.readData(overflowIndexCount); xxx_attr_indexes.readData(overflowIndexCount);
CHECK;
// pre-scan attr indexes, counting occurrences of each value // pre-scan attr indexes, counting occurrences of each value
for (i = 0; i < overflowIndexCount; i++) { for (i = 0; i < overflowIndexCount; i++) {
idx = xxx_attr_indexes.getInt(); idx = xxx_attr_indexes.getInt();
...@@ -2211,6 +2255,7 @@ void unpacker::read_attrs(int attrc, int obj_count) { ...@@ -2211,6 +2255,7 @@ void unpacker::read_attrs(int attrc, int obj_count) {
} }
} }
ad.xxx_attr_calls().readData(backwardCounts); ad.xxx_attr_calls().readData(backwardCounts);
CHECK;
// Read built-in bands. // Read built-in bands.
// Mostly, these are hand-coded equivalents to readBandData(). // Mostly, these are hand-coded equivalents to readBandData().
...@@ -2219,42 +2264,53 @@ void unpacker::read_attrs(int attrc, int obj_count) { ...@@ -2219,42 +2264,53 @@ void unpacker::read_attrs(int attrc, int obj_count) {
count = ad.predefCount(CLASS_ATTR_SourceFile); count = ad.predefCount(CLASS_ATTR_SourceFile);
class_SourceFile_RUN.readData(count); class_SourceFile_RUN.readData(count);
CHECK;
count = ad.predefCount(CLASS_ATTR_EnclosingMethod); count = ad.predefCount(CLASS_ATTR_EnclosingMethod);
class_EnclosingMethod_RC.readData(count); class_EnclosingMethod_RC.readData(count);
class_EnclosingMethod_RDN.readData(count); class_EnclosingMethod_RDN.readData(count);
CHECK;
count = ad.predefCount(X_ATTR_Signature); count = ad.predefCount(X_ATTR_Signature);
class_Signature_RS.readData(count); class_Signature_RS.readData(count);
CHECK;
ad.readBandData(X_ATTR_RuntimeVisibleAnnotations); ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations); ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
count = ad.predefCount(CLASS_ATTR_InnerClasses); count = ad.predefCount(CLASS_ATTR_InnerClasses);
class_InnerClasses_N.readData(count); class_InnerClasses_N.readData(count);
CHECK;
count = class_InnerClasses_N.getIntTotal(); count = class_InnerClasses_N.getIntTotal();
class_InnerClasses_RC.readData(count); class_InnerClasses_RC.readData(count);
class_InnerClasses_F.readData(count); class_InnerClasses_F.readData(count);
CHECK;
// Drop remaining columns wherever flags are zero: // Drop remaining columns wherever flags are zero:
count -= class_InnerClasses_F.getIntCount(0); count -= class_InnerClasses_F.getIntCount(0);
class_InnerClasses_outer_RCN.readData(count); class_InnerClasses_outer_RCN.readData(count);
class_InnerClasses_name_RUN.readData(count); class_InnerClasses_name_RUN.readData(count);
CHECK;
count = ad.predefCount(CLASS_ATTR_ClassFile_version); count = ad.predefCount(CLASS_ATTR_ClassFile_version);
class_ClassFile_version_minor_H.readData(count); class_ClassFile_version_minor_H.readData(count);
class_ClassFile_version_major_H.readData(count); class_ClassFile_version_major_H.readData(count);
CHECK;
break; break;
case ATTR_CONTEXT_FIELD: case ATTR_CONTEXT_FIELD:
count = ad.predefCount(FIELD_ATTR_ConstantValue); count = ad.predefCount(FIELD_ATTR_ConstantValue);
field_ConstantValue_KQ.readData(count); field_ConstantValue_KQ.readData(count);
CHECK;
count = ad.predefCount(X_ATTR_Signature); count = ad.predefCount(X_ATTR_Signature);
field_Signature_RS.readData(count); field_Signature_RS.readData(count);
CHECK;
ad.readBandData(X_ATTR_RuntimeVisibleAnnotations); ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations); ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
CHECK;
break; break;
case ATTR_CONTEXT_METHOD: case ATTR_CONTEXT_METHOD:
...@@ -2266,15 +2322,18 @@ void unpacker::read_attrs(int attrc, int obj_count) { ...@@ -2266,15 +2322,18 @@ void unpacker::read_attrs(int attrc, int obj_count) {
method_Exceptions_N.readData(count); method_Exceptions_N.readData(count);
count = method_Exceptions_N.getIntTotal(); count = method_Exceptions_N.getIntTotal();
method_Exceptions_RC.readData(count); method_Exceptions_RC.readData(count);
CHECK;
count = ad.predefCount(X_ATTR_Signature); count = ad.predefCount(X_ATTR_Signature);
method_Signature_RS.readData(count); method_Signature_RS.readData(count);
CHECK;
ad.readBandData(X_ATTR_RuntimeVisibleAnnotations); ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations); ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
ad.readBandData(METHOD_ATTR_RuntimeVisibleParameterAnnotations); ad.readBandData(METHOD_ATTR_RuntimeVisibleParameterAnnotations);
ad.readBandData(METHOD_ATTR_RuntimeInvisibleParameterAnnotations); ad.readBandData(METHOD_ATTR_RuntimeInvisibleParameterAnnotations);
ad.readBandData(METHOD_ATTR_AnnotationDefault); ad.readBandData(METHOD_ATTR_AnnotationDefault);
CHECK;
break; break;
case ATTR_CONTEXT_CODE: case ATTR_CONTEXT_CODE:
...@@ -2286,8 +2345,10 @@ void unpacker::read_attrs(int attrc, int obj_count) { ...@@ -2286,8 +2345,10 @@ void unpacker::read_attrs(int attrc, int obj_count) {
return; return;
} }
code_StackMapTable_N.readData(count); code_StackMapTable_N.readData(count);
CHECK;
count = code_StackMapTable_N.getIntTotal(); count = code_StackMapTable_N.getIntTotal();
code_StackMapTable_frame_T.readData(count); code_StackMapTable_frame_T.readData(count);
CHECK;
// the rest of it depends in a complicated way on frame tags // the rest of it depends in a complicated way on frame tags
{ {
int fat_frame_count = 0; int fat_frame_count = 0;
...@@ -2321,18 +2382,23 @@ void unpacker::read_attrs(int attrc, int obj_count) { ...@@ -2321,18 +2382,23 @@ void unpacker::read_attrs(int attrc, int obj_count) {
// deal completely with fat frames: // deal completely with fat frames:
offset_count += fat_frame_count; offset_count += fat_frame_count;
code_StackMapTable_local_N.readData(fat_frame_count); code_StackMapTable_local_N.readData(fat_frame_count);
CHECK;
type_count += code_StackMapTable_local_N.getIntTotal(); type_count += code_StackMapTable_local_N.getIntTotal();
code_StackMapTable_stack_N.readData(fat_frame_count); code_StackMapTable_stack_N.readData(fat_frame_count);
type_count += code_StackMapTable_stack_N.getIntTotal(); type_count += code_StackMapTable_stack_N.getIntTotal();
CHECK;
// read the rest: // read the rest:
code_StackMapTable_offset.readData(offset_count); code_StackMapTable_offset.readData(offset_count);
code_StackMapTable_T.readData(type_count); code_StackMapTable_T.readData(type_count);
CHECK;
// (7) [RCH] // (7) [RCH]
count = code_StackMapTable_T.getIntCount(7); count = code_StackMapTable_T.getIntCount(7);
code_StackMapTable_RC.readData(count); code_StackMapTable_RC.readData(count);
CHECK;
// (8) [PH] // (8) [PH]
count = code_StackMapTable_T.getIntCount(8); count = code_StackMapTable_T.getIntCount(8);
code_StackMapTable_P.readData(count); code_StackMapTable_P.readData(count);
CHECK;
} }
count = ad.predefCount(CODE_ATTR_LineNumberTable); count = ad.predefCount(CODE_ATTR_LineNumberTable);
...@@ -2654,6 +2720,7 @@ void unpacker::read_code_headers() { ...@@ -2654,6 +2720,7 @@ void unpacker::read_code_headers() {
code_max_na_locals.readData(); code_max_na_locals.readData();
code_handler_count.readData(); code_handler_count.readData();
totalHandlerCount += code_handler_count.getIntTotal(); totalHandlerCount += code_handler_count.getIntTotal();
CHECK;
// Read handler specifications. // Read handler specifications.
// Cf. PackageReader.readCodeHandlers. // Cf. PackageReader.readCodeHandlers.
...@@ -2661,8 +2728,10 @@ void unpacker::read_code_headers() { ...@@ -2661,8 +2728,10 @@ void unpacker::read_code_headers() {
code_handler_end_PO.readData(totalHandlerCount); code_handler_end_PO.readData(totalHandlerCount);
code_handler_catch_PO.readData(totalHandlerCount); code_handler_catch_PO.readData(totalHandlerCount);
code_handler_class_RCN.readData(totalHandlerCount); code_handler_class_RCN.readData(totalHandlerCount);
CHECK;
read_attrs(ATTR_CONTEXT_CODE, totalFlagsCount); read_attrs(ATTR_CONTEXT_CODE, totalFlagsCount);
CHECK;
} }
static inline bool is_in_range(uint n, uint min, uint max) { static inline bool is_in_range(uint n, uint min, uint max) {
......
...@@ -204,7 +204,7 @@ struct unpacker { ...@@ -204,7 +204,7 @@ struct unpacker {
// archive header fields // archive header fields
int magic, minver, majver; int magic, minver, majver;
julong archive_size; size_t archive_size;
int archive_next_count, archive_options, archive_modtime; int archive_next_count, archive_options, archive_modtime;
int band_headers_size; int band_headers_size;
int file_count, attr_definition_count, ic_count, class_count; int file_count, attr_definition_count, ic_count, class_count;
......
...@@ -46,14 +46,13 @@ ...@@ -46,14 +46,13 @@
#include "unpack.h" #include "unpack.h"
void* must_malloc(int size) { void* must_malloc(size_t size) {
int msize = size; size_t msize = size;
assert(size >= 0);
#ifdef USE_MTRACE #ifdef USE_MTRACE
if (msize < sizeof(int)) if (msize >= 0 && msize < sizeof(int))
msize = sizeof(int); // see 0xbaadf00d below msize = sizeof(int); // see 0xbaadf00d below
#endif #endif
void* ptr = malloc(msize); void* ptr = (msize > PSIZE_MAX) ? null : malloc(msize);
if (ptr != null) { if (ptr != null) {
memset(ptr, 0, size); memset(ptr, 0, size);
} else { } else {
......
...@@ -25,13 +25,31 @@ ...@@ -25,13 +25,31 @@
//Definitions of our util functions //Definitions of our util functions
void* must_malloc(int size); void* must_malloc(size_t size);
#ifndef USE_MTRACE #ifndef USE_MTRACE
#define mtrace(c, ptr, size) #define mtrace(c, ptr, size)
#else #else
void mtrace(char c, void* ptr, size_t size); void mtrace(char c, void* ptr, size_t size);
#endif #endif
// overflow management
#define OVERFLOW ((size_t)-1)
#define PSIZE_MAX (OVERFLOW/2) /* normal size limit */
inline size_t scale_size(size_t size, size_t scale) {
return (size > PSIZE_MAX / scale) ? OVERFLOW : size * scale;
}
inline size_t add_size(size_t size1, size_t size2) {
return ((size1 | size2 | (size1 + size2)) > PSIZE_MAX)
? OVERFLOW
: size1 + size2;
}
inline size_t add_size(size_t size1, size_t size2, int size3) {
return add_size(add_size(size1, size2), size3);
}
// These may be expensive, because they have to go via Java TSD, // These may be expensive, because they have to go via Java TSD,
// if the optional u argument is missing. // if the optional u argument is missing.
struct unpacker; struct unpacker;
......
...@@ -141,12 +141,11 @@ Java_java_util_zip_ZipFile_close(JNIEnv *env, jclass cls, jlong zfile) ...@@ -141,12 +141,11 @@ Java_java_util_zip_ZipFile_close(JNIEnv *env, jclass cls, jlong zfile)
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_java_util_zip_ZipFile_getEntry(JNIEnv *env, jclass cls, jlong zfile, Java_java_util_zip_ZipFile_getEntry(JNIEnv *env, jclass cls, jlong zfile,
jstring name, jboolean addSlash) jbyteArray name, jboolean addSlash)
{ {
#define MAXNAME 1024 #define MAXNAME 1024
jzfile *zip = jlong_to_ptr(zfile); jzfile *zip = jlong_to_ptr(zfile);
jsize slen = (*env)->GetStringLength(env, name); jsize ulen = (*env)->GetArrayLength(env, name);
jsize ulen = (*env)->GetStringUTFLength(env, name);
char buf[MAXNAME+2], *path; char buf[MAXNAME+2], *path;
jzentry *ze; jzentry *ze;
...@@ -159,7 +158,7 @@ Java_java_util_zip_ZipFile_getEntry(JNIEnv *env, jclass cls, jlong zfile, ...@@ -159,7 +158,7 @@ Java_java_util_zip_ZipFile_getEntry(JNIEnv *env, jclass cls, jlong zfile,
} else { } else {
path = buf; path = buf;
} }
(*env)->GetStringUTFRegion(env, name, 0, slen, path); (*env)->GetByteArrayRegion(env, name, 0, ulen, (jbyte *)path);
path[ulen] = '\0'; path[ulen] = '\0';
if (addSlash == JNI_FALSE) { if (addSlash == JNI_FALSE) {
ze = ZIP_GetEntry(zip, path, 0); ze = ZIP_GetEntry(zip, path, 0);
...@@ -186,34 +185,87 @@ Java_java_util_zip_ZipFile_getNextEntry(JNIEnv *env, jclass cls, jlong zfile, ...@@ -186,34 +185,87 @@ Java_java_util_zip_ZipFile_getNextEntry(JNIEnv *env, jclass cls, jlong zfile,
jint n) jint n)
{ {
jzentry *ze = ZIP_GetNextEntry(jlong_to_ptr(zfile), n); jzentry *ze = ZIP_GetNextEntry(jlong_to_ptr(zfile), n);
return ptr_to_jlong(ze); return ptr_to_jlong(ze);
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_java_util_zip_ZipFile_getMethod(JNIEnv *env, jclass cls, jlong zentry) Java_java_util_zip_ZipFile_getEntryMethod(JNIEnv *env, jclass cls, jlong zentry)
{ {
jzentry *ze = jlong_to_ptr(zentry); jzentry *ze = jlong_to_ptr(zentry);
return ze->csize != 0 ? DEFLATED : STORED; return ze->csize != 0 ? DEFLATED : STORED;
} }
JNIEXPORT jlong JNICALL JNIEXPORT jint JNICALL
Java_java_util_zip_ZipFile_getCSize(JNIEnv *env, jclass cls, jlong zentry) Java_java_util_zip_ZipFile_getEntryFlag(JNIEnv *env, jclass cls, jlong zentry)
{ {
jzentry *ze = jlong_to_ptr(zentry); jzentry *ze = jlong_to_ptr(zentry);
return ze->flag;
}
JNIEXPORT jlong JNICALL
Java_java_util_zip_ZipFile_getEntryCSize(JNIEnv *env, jclass cls, jlong zentry)
{
jzentry *ze = jlong_to_ptr(zentry);
return ze->csize != 0 ? ze->csize : ze->size; return ze->csize != 0 ? ze->csize : ze->size;
} }
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_java_util_zip_ZipFile_getSize(JNIEnv *env, jclass cls, jlong zentry) Java_java_util_zip_ZipFile_getEntrySize(JNIEnv *env, jclass cls, jlong zentry)
{ {
jzentry *ze = jlong_to_ptr(zentry); jzentry *ze = jlong_to_ptr(zentry);
return ze->size; return ze->size;
} }
JNIEXPORT jlong JNICALL
Java_java_util_zip_ZipFile_getEntryTime(JNIEnv *env, jclass cls, jlong zentry)
{
jzentry *ze = jlong_to_ptr(zentry);
return (jlong)ze->time & 0xffffffffUL;
}
JNIEXPORT jlong JNICALL
Java_java_util_zip_ZipFile_getEntryCrc(JNIEnv *env, jclass cls, jlong zentry)
{
jzentry *ze = jlong_to_ptr(zentry);
return (jlong)ze->crc & 0xffffffffUL;
}
JNIEXPORT jbyteArray JNICALL
Java_java_util_zip_ZipFile_getEntryBytes(JNIEnv *env, jclass cls, jlong zentry, jint type)
{
jzentry *ze = jlong_to_ptr(zentry);
int len = 0;
jbyteArray jba = NULL;
switch (type) {
case java_util_zip_ZipFile_JZENTRY_NAME:
if (ze->name != 0) {
len = (int)strlen(ze->name);
if (len == 0 || (jba = (*env)->NewByteArray(env, len)) == NULL)
break;
(*env)->SetByteArrayRegion(env, jba, 0, len, (jbyte *)ze->name);
}
break;
case java_util_zip_ZipFile_JZENTRY_EXTRA:
if (ze->extra != 0) {
unsigned char *bp = (unsigned char *)&ze->extra[0];
len = (bp[0] | (bp[1] << 8));
if (len <= 0 || (jba = (*env)->NewByteArray(env, len)) == NULL)
break;
(*env)->SetByteArrayRegion(env, jba, 0, len, &ze->extra[2]);
}
break;
case java_util_zip_ZipFile_JZENTRY_COMMENT:
if (ze->comment != 0) {
len = (int)strlen(ze->comment);
if (len == 0 || (jba = (*env)->NewByteArray(env, len)) == NULL)
break;
(*env)->SetByteArrayRegion(env, jba, 0, len, (jbyte*)ze->comment);
}
break;
}
return jba;
}
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_java_util_zip_ZipFile_read(JNIEnv *env, jclass cls, jlong zfile, Java_java_util_zip_ZipFile_read(JNIEnv *env, jclass cls, jlong zfile,
jlong zentry, jlong pos, jbyteArray bytes, jlong zentry, jlong pos, jbyteArray bytes,
......
...@@ -512,7 +512,6 @@ readCEN(jzfile *zip, jint knownTotal) ...@@ -512,7 +512,6 @@ readCEN(jzfile *zip, jint knownTotal)
/* Clear previous zip error */ /* Clear previous zip error */
zip->msg = NULL; zip->msg = NULL;
/* Get position of END header */ /* Get position of END header */
if ((endpos = findEND(zip, endbuf)) == -1) if ((endpos = findEND(zip, endbuf)) == -1)
return -1; /* no END header or system error */ return -1; /* no END header or system error */
...@@ -520,7 +519,6 @@ readCEN(jzfile *zip, jint knownTotal) ...@@ -520,7 +519,6 @@ readCEN(jzfile *zip, jint knownTotal)
if (endpos == 0) return 0; /* only END header present */ if (endpos == 0) return 0; /* only END header present */
freeCEN(zip); freeCEN(zip);
/* Get position and length of central directory */ /* Get position and length of central directory */
cenlen = ENDSIZ(endbuf); cenlen = ENDSIZ(endbuf);
cenoff = ENDOFF(endbuf); cenoff = ENDOFF(endbuf);
...@@ -935,6 +933,7 @@ newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) ...@@ -935,6 +933,7 @@ newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)
ze->crc = CENCRC(cen); ze->crc = CENCRC(cen);
locoff = CENOFF(cen); locoff = CENOFF(cen);
ze->pos = -(zip->locpos + locoff); ze->pos = -(zip->locpos + locoff);
ze->flag = CENFLG(cen);
if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch; if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch;
memcpy(ze->name, cen + CENHDR, nlen); memcpy(ze->name, cen + CENHDR, nlen);
......
...@@ -168,6 +168,7 @@ typedef struct jzentry { /* Zip file entry */ ...@@ -168,6 +168,7 @@ typedef struct jzentry { /* Zip file entry */
char *comment; /* optional zip file comment */ char *comment; /* optional zip file comment */
jbyte *extra; /* optional extra data */ jbyte *extra; /* optional extra data */
jlong pos; /* position of LOC header or entry data */ jlong pos; /* position of LOC header or entry data */
jint flag; /* general purpose flag */
} jzentry; } jzentry;
/* /*
......
...@@ -191,6 +191,11 @@ Java_sun_awt_image_GifImageDecoder_parseImage(JNIEnv *env, ...@@ -191,6 +191,11 @@ Java_sun_awt_image_GifImageDecoder_parseImage(JNIEnv *env,
int passht = passinc; int passht = passinc;
int len; int len;
/* We have verified the initial code size on the java layer.
* Here we just check bounds for particular indexes. */
if (freeCode >= 4096 || maxCode >= 4096) {
return 0;
}
if (blockh == 0 || raslineh == 0 if (blockh == 0 || raslineh == 0
|| prefixh == 0 || suffixh == 0 || prefixh == 0 || suffixh == 0
|| outCodeh == 0) || outCodeh == 0)
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
/* here come some very simple macros */ /* here come some very simple macros */
/* advance a pointer p by sizeof(type)*n bytes */ /* advance a pointer p by sizeof(type)*n bytes */
#define INCPN(type,p,n) ((p) = (type*)(p)+n) #define INCPN(type,p,n) ((p) = (type*)(p)+(n))
/* advance a pointer by sizeof(type) */ /* advance a pointer by sizeof(type) */
#define INCP(type,p) INCPN(type,(p),1) #define INCP(type,p) INCPN(type,(p),1)
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册