This commit is contained in:
Tim Bell 2009-04-03 10:29:13 -07:00
commit df35adf83b
38 changed files with 2350 additions and 565 deletions

View file

@ -25,6 +25,8 @@
package java.lang; package java.lang;
import java.util.Properties;
/** /**
* The {@code Integer} class wraps a value of the primitive type * The {@code Integer} class wraps a value of the primitive type
* {@code int} in an object. An object of type {@code Integer} * {@code int} in an object. An object of type {@code Integer}
@ -442,6 +444,12 @@ public final class Integer extends Number implements Comparable<Integer> {
public static int parseInt(String s, int radix) public static int parseInt(String s, int radix)
throws NumberFormatException throws NumberFormatException
{ {
/*
* WARNING: This method may be invoked early during VM initialization
* before IntegerCache is initialized. Care must be taken to not use
* the valueOf method.
*/
if (s == null) { if (s == null) {
throw new NumberFormatException("null"); throw new NumberFormatException("null");
} }
@ -545,7 +553,7 @@ public final class Integer extends Number implements Comparable<Integer> {
* does not contain a parsable {@code int}. * does not contain a parsable {@code int}.
*/ */
public static Integer valueOf(String s, int radix) throws NumberFormatException { public static Integer valueOf(String s, int radix) throws NumberFormatException {
return new Integer(parseInt(s,radix)); return Integer.valueOf(parseInt(s,radix));
} }
/** /**
@ -570,20 +578,56 @@ public final class Integer extends Number implements Comparable<Integer> {
* @exception NumberFormatException if the string cannot be parsed * @exception NumberFormatException if the string cannot be parsed
* as an integer. * as an integer.
*/ */
public static Integer valueOf(String s) throws NumberFormatException public static Integer valueOf(String s) throws NumberFormatException {
{ return Integer.valueOf(parseInt(s, 10));
return new Integer(parseInt(s, 10)); }
/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. During VM initialization the
* getAndRemoveCacheProperties method may be used to get and remove any system
* properites that configure the cache size. At this time, the size of the
* cache may be controlled by the -XX:AutoBoxCacheMax=<size> option.
*/
// value of java.lang.Integer.IntegerCache.high property (obtained during VM init)
private static String integerCacheHighPropValue;
static void getAndRemoveCacheProperties() {
if (!sun.misc.VM.isBooted()) {
Properties props = System.getProperties();
integerCacheHighPropValue =
(String)props.remove("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null)
System.setProperties(props); // remove from system props
}
} }
private static class IntegerCache { private static class IntegerCache {
private IntegerCache(){} static final int low = -128;
static final int high;
static final Integer cache[] = new Integer[-(-128) + 127 + 1]; static final Integer cache[];
static { static {
for(int i = 0; i < cache.length; i++) // high value may be configured by property
cache[i] = new Integer(i - 128); int h = 127;
if (integerCacheHighPropValue != null) {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low));
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
} }
private IntegerCache() {}
} }
/** /**
@ -599,10 +643,9 @@ public final class Integer extends Number implements Comparable<Integer> {
* @since 1.5 * @since 1.5
*/ */
public static Integer valueOf(int i) { public static Integer valueOf(int i) {
final int offset = 128; assert IntegerCache.high >= 127;
if (i >= -128 && i <= 127) { // must cache if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + offset]; return IntegerCache.cache[i + (-IntegerCache.low)];
}
return new Integer(i); return new Integer(i);
} }
@ -806,7 +849,7 @@ public final class Integer extends Number implements Comparable<Integer> {
*/ */
public static Integer getInteger(String nm, int val) { public static Integer getInteger(String nm, int val) {
Integer result = getInteger(nm, null); Integer result = getInteger(nm, null);
return (result == null) ? new Integer(val) : result; return (result == null) ? Integer.valueOf(val) : result;
} }
/** /**
@ -938,7 +981,7 @@ public final class Integer extends Number implements Comparable<Integer> {
try { try {
result = Integer.valueOf(nm.substring(index), radix); result = Integer.valueOf(nm.substring(index), radix);
result = negative ? new Integer(-result.intValue()) : result; result = negative ? Integer.valueOf(-result.intValue()) : result;
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
// If number is Integer.MIN_VALUE, we'll end up here. The next line // If number is Integer.MIN_VALUE, we'll end up here. The next line
// handles this case, and causes any genuine format error to be // handles this case, and causes any genuine format error to be

View file

@ -510,7 +510,7 @@ public final class Long extends Number implements Comparable<Long> {
* contain a parsable {@code long}. * contain a parsable {@code long}.
*/ */
public static Long valueOf(String s, int radix) throws NumberFormatException { public static Long valueOf(String s, int radix) throws NumberFormatException {
return new Long(parseLong(s, radix)); return Long.valueOf(parseLong(s, radix));
} }
/** /**
@ -537,7 +537,7 @@ public final class Long extends Number implements Comparable<Long> {
*/ */
public static Long valueOf(String s) throws NumberFormatException public static Long valueOf(String s) throws NumberFormatException
{ {
return new Long(parseLong(s, 10)); return Long.valueOf(parseLong(s, 10));
} }
private static class LongCache { private static class LongCache {
@ -650,7 +650,7 @@ public final class Long extends Number implements Comparable<Long> {
try { try {
result = Long.valueOf(nm.substring(index), radix); result = Long.valueOf(nm.substring(index), radix);
result = negative ? new Long(-result.longValue()) : result; result = negative ? Long.valueOf(-result.longValue()) : result;
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
// If number is Long.MIN_VALUE, we'll end up here. The next line // If number is Long.MIN_VALUE, we'll end up here. The next line
// handles this case, and causes any genuine format error to be // handles this case, and causes any genuine format error to be
@ -869,7 +869,7 @@ public final class Long extends Number implements Comparable<Long> {
*/ */
public static Long getLong(String nm, long val) { public static Long getLong(String nm, long val) {
Long result = Long.getLong(nm, null); Long result = Long.getLong(nm, null);
return (result == null) ? new Long(val) : result; return (result == null) ? Long.valueOf(val) : result;
} }
/** /**

View file

@ -1105,6 +1105,13 @@ public final class System {
props = new Properties(); props = new Properties();
initProperties(props); initProperties(props);
sun.misc.Version.init(); sun.misc.Version.init();
// Gets and removes system properties that configure the Integer
// cache used to support the object identity semantics of autoboxing.
// At this time, the size of the cache may be controlled by the
// -XX:AutoBoxCacheMax=<size> option.
Integer.getAndRemoveCacheProperties();
FileInputStream fdIn = new FileInputStream(FileDescriptor.in); FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out); FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err); FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);

View file

@ -261,7 +261,10 @@ public abstract class DatagramChannel
* *
* <p> This method may be invoked at any time. It will not have any effect * <p> This method may be invoked at any time. It will not have any effect
* on read or write operations that are already in progress at the moment * on read or write operations that are already in progress at the moment
* that it is invoked. </p> * that it is invoked. If this channel's socket is not bound then this method
* will first cause the socket to be bound to an address that is assigned
* automatically, as if invoking the {@link #bind bind} method with a
* parameter of {@code null}. </p>
* *
* @param remote * @param remote
* The remote address to which this channel is to be connected * The remote address to which this channel is to be connected
@ -356,7 +359,10 @@ public abstract class DatagramChannel
* <p> This method may be invoked at any time. If another thread has * <p> This method may be invoked at any time. If another thread has
* already initiated a read operation upon this channel, however, then an * already initiated a read operation upon this channel, however, then an
* invocation of this method will block until the first operation is * invocation of this method will block until the first operation is
* complete. </p> * complete. If this channel's socket is not bound then this method will
* first cause the socket to be bound to an address that is assigned
* automatically, as if invoking the {@link #bind bind} method with a
* parameter of {@code null}. </p>
* *
* @param dst * @param dst
* The buffer into which the datagram is to be transferred * The buffer into which the datagram is to be transferred
@ -413,7 +419,10 @@ public abstract class DatagramChannel
* <p> This method may be invoked at any time. If another thread has * <p> This method may be invoked at any time. If another thread has
* already initiated a write operation upon this channel, however, then an * already initiated a write operation upon this channel, however, then an
* invocation of this method will block until the first operation is * invocation of this method will block until the first operation is
* complete. </p> * complete. If this channel's socket is not bound then this method will
* first cause the socket to be bound to an address that is assigned
* automatically, as if by invoking the {@link #bind bind) method with a
* parameter of {@code null}. </p>
* *
* @param src * @param src
* The buffer containing the datagram to be sent * The buffer containing the datagram to be sent

View file

@ -1068,14 +1068,14 @@ public class TreeMap<K,V>
} }
public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
E toElement, boolean toInclusive) { E toElement, boolean toInclusive) {
return new TreeSet<E>(m.subMap(fromElement, fromInclusive, return new KeySet<E>(m.subMap(fromElement, fromInclusive,
toElement, toInclusive)); toElement, toInclusive));
} }
public NavigableSet<E> headSet(E toElement, boolean inclusive) { public NavigableSet<E> headSet(E toElement, boolean inclusive) {
return new TreeSet<E>(m.headMap(toElement, inclusive)); return new KeySet<E>(m.headMap(toElement, inclusive));
} }
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) { public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
return new TreeSet<E>(m.tailMap(fromElement, inclusive)); return new KeySet<E>(m.tailMap(fromElement, inclusive));
} }
public SortedSet<E> subSet(E fromElement, E toElement) { public SortedSet<E> subSet(E fromElement, E toElement) {
return subSet(fromElement, true, toElement, false); return subSet(fromElement, true, toElement, false);
@ -1087,7 +1087,7 @@ public class TreeMap<K,V>
return tailSet(fromElement, true); return tailSet(fromElement, true);
} }
public NavigableSet<E> descendingSet() { public NavigableSet<E> descendingSet() {
return new TreeSet(m.descendingMap()); return new KeySet(m.descendingMap());
} }
} }

View file

@ -2394,15 +2394,14 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
boolean fromInclusive, boolean fromInclusive,
E toElement, E toElement,
boolean toInclusive) { boolean toInclusive) {
return new ConcurrentSkipListSet<E> return new KeySet<E>(m.subMap(fromElement, fromInclusive,
(m.subMap(fromElement, fromInclusive, toElement, toInclusive));
toElement, toInclusive));
} }
public NavigableSet<E> headSet(E toElement, boolean inclusive) { public NavigableSet<E> headSet(E toElement, boolean inclusive) {
return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive)); return new KeySet<E>(m.headMap(toElement, inclusive));
} }
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) { public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive)); return new KeySet<E>(m.tailMap(fromElement, inclusive));
} }
public NavigableSet<E> subSet(E fromElement, E toElement) { public NavigableSet<E> subSet(E fromElement, E toElement) {
return subSet(fromElement, true, toElement, false); return subSet(fromElement, true, toElement, false);
@ -2414,7 +2413,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
return tailSet(fromElement, true); return tailSet(fromElement, true);
} }
public NavigableSet<E> descendingSet() { public NavigableSet<E> descendingSet() {
return new ConcurrentSkipListSet(m.descendingMap()); return new KeySet(m.descendingMap());
} }
} }

View file

@ -166,6 +166,11 @@ public abstract class AbstractQueuedLongSynchronizer
static final int SIGNAL = -1; static final int SIGNAL = -1;
/** waitStatus value to indicate thread is waiting on condition */ /** waitStatus value to indicate thread is waiting on condition */
static final int CONDITION = -2; static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
static final int PROPAGATE = -3;
/** /**
* Status field, taking on only the values: * Status field, taking on only the values:
@ -180,10 +185,16 @@ public abstract class AbstractQueuedLongSynchronizer
* Nodes never leave this state. In particular, * Nodes never leave this state. In particular,
* a thread with cancelled node never again blocks. * a thread with cancelled node never again blocks.
* CONDITION: This node is currently on a condition queue. * CONDITION: This node is currently on a condition queue.
* It will not be used as a sync queue node until * It will not be used as a sync queue node
* transferred. (Use of this value here * until transferred, at which time the status
* has nothing to do with the other uses * will be set to 0. (Use of this value here has
* of the field, but simplifies mechanics.) * nothing to do with the other uses of the
* field, but simplifies mechanics.)
* PROPAGATE: A releaseShared should be propagated to other
* nodes. This is set (for head node only) in
* doReleaseShared to ensure propagation
* continues, even if other operations have
* since intervened.
* 0: None of the above * 0: None of the above
* *
* The values are arranged numerically to simplify use. * The values are arranged numerically to simplify use.
@ -403,10 +414,13 @@ public abstract class AbstractQueuedLongSynchronizer
*/ */
private void unparkSuccessor(Node node) { private void unparkSuccessor(Node node) {
/* /*
* Try to clear status in anticipation of signalling. It is * If status is negative (i.e., possibly needing signal) try
* OK if this fails or if status is changed by waiting thread. * to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/ */
compareAndSetWaitStatus(node, Node.SIGNAL, 0); int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/* /*
* Thread to unpark is held in successor, which is normally * Thread to unpark is held in successor, which is normally
@ -425,24 +439,71 @@ public abstract class AbstractQueuedLongSynchronizer
LockSupport.unpark(s.thread); LockSupport.unpark(s.thread);
} }
/**
* Release action for shared mode -- signal successor and ensure
* propagation. (Note: For exclusive mode, release just amounts
* to calling unparkSuccessor of head if it needs signal.)
*/
private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
/** /**
* Sets head of queue, and checks if successor may be waiting * Sets head of queue, and checks if successor may be waiting
* in shared mode, if so propagating if propagate > 0. * in shared mode, if so propagating if either propagate > 0 or
* PROPAGATE status was set.
* *
* @param pred the node holding waitStatus for node
* @param node the node * @param node the node
* @param propagate the return value from a tryAcquireShared * @param propagate the return value from a tryAcquireShared
*/ */
private void setHeadAndPropagate(Node node, long propagate) { private void setHeadAndPropagate(Node node, long propagate) {
Node h = head; // Record old head for check below
setHead(node); setHead(node);
if (propagate > 0 && node.waitStatus != 0) { /*
/* * Try to signal next queued node if:
* Don't bother fully figuring out successor. If it * Propagation was indicated by caller,
* looks null, call unparkSuccessor anyway to be safe. * or was recorded (as h.waitStatus) by a previous operation
*/ * (note: this uses sign-check of waitStatus because
* PROPAGATE status may transition to SIGNAL.)
* and
* The next node is waiting in shared mode,
* or we don't know, because it appears null
*
* The conservatism in both of these checks may cause
* unnecessary wake-ups, but only when there are multiple
* racing acquires/releases, so most need signals now or soon
* anyway.
*/
if (propagate > 0 || h == null || h.waitStatus < 0) {
Node s = node.next; Node s = node.next;
if (s == null || s.isShared()) if (s == null || s.isShared())
unparkSuccessor(node); doReleaseShared();
} }
} }
@ -465,23 +526,27 @@ public abstract class AbstractQueuedLongSynchronizer
while (pred.waitStatus > 0) while (pred.waitStatus > 0)
node.prev = pred = pred.prev; node.prev = pred = pred.prev;
// Getting this before setting waitStatus ensures staleness // predNext is the apparent node to unsplice. CASes below will
// fail if not, in which case, we lost race vs another cancel
// or signal, so no further action is necessary.
Node predNext = pred.next; Node predNext = pred.next;
// Can use unconditional write instead of CAS here // Can use unconditional write instead of CAS here.
// After this atomic step, other Nodes can skip past us.
// Before, we are free of interference from other threads.
node.waitStatus = Node.CANCELLED; node.waitStatus = Node.CANCELLED;
// If we are the tail, remove ourselves // If we are the tail, remove ourselves.
if (node == tail && compareAndSetTail(node, pred)) { if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null); compareAndSetNext(pred, predNext, null);
} else { } else {
// If "active" predecessor found... // If successor needs signal, try to set pred's next-link
if (pred != head // so it will get one. Otherwise wake it up to propagate.
&& (pred.waitStatus == Node.SIGNAL int ws;
|| compareAndSetWaitStatus(pred, 0, Node.SIGNAL)) if (pred != head &&
&& pred.thread != null) { ((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
// If successor is active, set predecessor's next link pred.thread != null) {
Node next = node.next; Node next = node.next;
if (next != null && next.waitStatus <= 0) if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next); compareAndSetNext(pred, predNext, next);
@ -503,14 +568,14 @@ public abstract class AbstractQueuedLongSynchronizer
* @return {@code true} if thread should block * @return {@code true} if thread should block
*/ */
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int s = pred.waitStatus; int ws = pred.waitStatus;
if (s < 0) if (ws == Node.SIGNAL)
/* /*
* This node has already set status asking a release * This node has already set status asking a release
* to signal it, so it can safely park. * to signal it, so it can safely park.
*/ */
return true; return true;
if (s > 0) { if (ws > 0) {
/* /*
* Predecessor was cancelled. Skip over predecessors and * Predecessor was cancelled. Skip over predecessors and
* indicate retry. * indicate retry.
@ -519,14 +584,14 @@ public abstract class AbstractQueuedLongSynchronizer
node.prev = pred = pred.prev; node.prev = pred = pred.prev;
} while (pred.waitStatus > 0); } while (pred.waitStatus > 0);
pred.next = node; pred.next = node;
} } else {
else
/* /*
* Indicate that we need a signal, but don't park yet. Caller * waitStatus must be 0 or PROPAGATE. Indicate that we
* will need to retry to make sure it cannot acquire before * need a signal, but don't park yet. Caller will need to
* parking. * retry to make sure it cannot acquire before parking.
*/ */
compareAndSetWaitStatus(pred, 0, Node.SIGNAL); compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false; return false;
} }
@ -1046,9 +1111,7 @@ public abstract class AbstractQueuedLongSynchronizer
*/ */
public final boolean releaseShared(long arg) { public final boolean releaseShared(long arg) {
if (tryReleaseShared(arg)) { if (tryReleaseShared(arg)) {
Node h = head; doReleaseShared();
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true; return true;
} }
return false; return false;
@ -1390,8 +1453,8 @@ public abstract class AbstractQueuedLongSynchronizer
* case the waitStatus can be transiently and harmlessly wrong). * case the waitStatus can be transiently and harmlessly wrong).
*/ */
Node p = enq(node); Node p = enq(node);
int c = p.waitStatus; int ws = p.waitStatus;
if (c > 0 || !compareAndSetWaitStatus(p, c, Node.SIGNAL)) if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread); LockSupport.unpark(node.thread);
return true; return true;
} }

View file

@ -389,6 +389,11 @@ public abstract class AbstractQueuedSynchronizer
static final int SIGNAL = -1; static final int SIGNAL = -1;
/** waitStatus value to indicate thread is waiting on condition */ /** waitStatus value to indicate thread is waiting on condition */
static final int CONDITION = -2; static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
static final int PROPAGATE = -3;
/** /**
* Status field, taking on only the values: * Status field, taking on only the values:
@ -403,10 +408,16 @@ public abstract class AbstractQueuedSynchronizer
* Nodes never leave this state. In particular, * Nodes never leave this state. In particular,
* a thread with cancelled node never again blocks. * a thread with cancelled node never again blocks.
* CONDITION: This node is currently on a condition queue. * CONDITION: This node is currently on a condition queue.
* It will not be used as a sync queue node until * It will not be used as a sync queue node
* transferred. (Use of this value here * until transferred, at which time the status
* has nothing to do with the other uses * will be set to 0. (Use of this value here has
* of the field, but simplifies mechanics.) * nothing to do with the other uses of the
* field, but simplifies mechanics.)
* PROPAGATE: A releaseShared should be propagated to other
* nodes. This is set (for head node only) in
* doReleaseShared to ensure propagation
* continues, even if other operations have
* since intervened.
* 0: None of the above * 0: None of the above
* *
* The values are arranged numerically to simplify use. * The values are arranged numerically to simplify use.
@ -626,10 +637,13 @@ public abstract class AbstractQueuedSynchronizer
*/ */
private void unparkSuccessor(Node node) { private void unparkSuccessor(Node node) {
/* /*
* Try to clear status in anticipation of signalling. It is * If status is negative (i.e., possibly needing signal) try
* OK if this fails or if status is changed by waiting thread. * to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/ */
compareAndSetWaitStatus(node, Node.SIGNAL, 0); int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/* /*
* Thread to unpark is held in successor, which is normally * Thread to unpark is held in successor, which is normally
@ -648,24 +662,71 @@ public abstract class AbstractQueuedSynchronizer
LockSupport.unpark(s.thread); LockSupport.unpark(s.thread);
} }
/**
* Release action for shared mode -- signal successor and ensure
* propagation. (Note: For exclusive mode, release just amounts
* to calling unparkSuccessor of head if it needs signal.)
*/
private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
/** /**
* Sets head of queue, and checks if successor may be waiting * Sets head of queue, and checks if successor may be waiting
* in shared mode, if so propagating if propagate > 0. * in shared mode, if so propagating if either propagate > 0 or
* PROPAGATE status was set.
* *
* @param pred the node holding waitStatus for node
* @param node the node * @param node the node
* @param propagate the return value from a tryAcquireShared * @param propagate the return value from a tryAcquireShared
*/ */
private void setHeadAndPropagate(Node node, int propagate) { private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Record old head for check below
setHead(node); setHead(node);
if (propagate > 0 && node.waitStatus != 0) { /*
/* * Try to signal next queued node if:
* Don't bother fully figuring out successor. If it * Propagation was indicated by caller,
* looks null, call unparkSuccessor anyway to be safe. * or was recorded (as h.waitStatus) by a previous operation
*/ * (note: this uses sign-check of waitStatus because
* PROPAGATE status may transition to SIGNAL.)
* and
* The next node is waiting in shared mode,
* or we don't know, because it appears null
*
* The conservatism in both of these checks may cause
* unnecessary wake-ups, but only when there are multiple
* racing acquires/releases, so most need signals now or soon
* anyway.
*/
if (propagate > 0 || h == null || h.waitStatus < 0) {
Node s = node.next; Node s = node.next;
if (s == null || s.isShared()) if (s == null || s.isShared())
unparkSuccessor(node); doReleaseShared();
} }
} }
@ -688,23 +749,27 @@ public abstract class AbstractQueuedSynchronizer
while (pred.waitStatus > 0) while (pred.waitStatus > 0)
node.prev = pred = pred.prev; node.prev = pred = pred.prev;
// Getting this before setting waitStatus ensures staleness // predNext is the apparent node to unsplice. CASes below will
// fail if not, in which case, we lost race vs another cancel
// or signal, so no further action is necessary.
Node predNext = pred.next; Node predNext = pred.next;
// Can use unconditional write instead of CAS here // Can use unconditional write instead of CAS here.
// After this atomic step, other Nodes can skip past us.
// Before, we are free of interference from other threads.
node.waitStatus = Node.CANCELLED; node.waitStatus = Node.CANCELLED;
// If we are the tail, remove ourselves // If we are the tail, remove ourselves.
if (node == tail && compareAndSetTail(node, pred)) { if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null); compareAndSetNext(pred, predNext, null);
} else { } else {
// If "active" predecessor found... // If successor needs signal, try to set pred's next-link
if (pred != head // so it will get one. Otherwise wake it up to propagate.
&& (pred.waitStatus == Node.SIGNAL int ws;
|| compareAndSetWaitStatus(pred, 0, Node.SIGNAL)) if (pred != head &&
&& pred.thread != null) { ((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
// If successor is active, set predecessor's next link pred.thread != null) {
Node next = node.next; Node next = node.next;
if (next != null && next.waitStatus <= 0) if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next); compareAndSetNext(pred, predNext, next);
@ -726,14 +791,14 @@ public abstract class AbstractQueuedSynchronizer
* @return {@code true} if thread should block * @return {@code true} if thread should block
*/ */
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int s = pred.waitStatus; int ws = pred.waitStatus;
if (s < 0) if (ws == Node.SIGNAL)
/* /*
* This node has already set status asking a release * This node has already set status asking a release
* to signal it, so it can safely park. * to signal it, so it can safely park.
*/ */
return true; return true;
if (s > 0) { if (ws > 0) {
/* /*
* Predecessor was cancelled. Skip over predecessors and * Predecessor was cancelled. Skip over predecessors and
* indicate retry. * indicate retry.
@ -742,14 +807,14 @@ public abstract class AbstractQueuedSynchronizer
node.prev = pred = pred.prev; node.prev = pred = pred.prev;
} while (pred.waitStatus > 0); } while (pred.waitStatus > 0);
pred.next = node; pred.next = node;
} } else {
else
/* /*
* Indicate that we need a signal, but don't park yet. Caller * waitStatus must be 0 or PROPAGATE. Indicate that we
* will need to retry to make sure it cannot acquire before * need a signal, but don't park yet. Caller will need to
* parking. * retry to make sure it cannot acquire before parking.
*/ */
compareAndSetWaitStatus(pred, 0, Node.SIGNAL); compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false; return false;
} }
@ -1269,9 +1334,7 @@ public abstract class AbstractQueuedSynchronizer
*/ */
public final boolean releaseShared(int arg) { public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) { if (tryReleaseShared(arg)) {
Node h = head; doReleaseShared();
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true; return true;
} }
return false; return false;
@ -1613,8 +1676,8 @@ public abstract class AbstractQueuedSynchronizer
* case the waitStatus can be transiently and harmlessly wrong). * case the waitStatus can be transiently and harmlessly wrong).
*/ */
Node p = enq(node); Node p = enq(node);
int c = p.waitStatus; int ws = p.waitStatus;
if (c > 0 || !compareAndSetWaitStatus(p, c, Node.SIGNAL)) if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread); LockSupport.unpark(node.thread);
return true; return true;
} }

View file

@ -276,7 +276,7 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
* Maintained as a ThreadLocal; cached in cachedHoldCounter * Maintained as a ThreadLocal; cached in cachedHoldCounter
*/ */
static final class HoldCounter { static final class HoldCounter {
int count; int count = 0;
// Use id, not reference, to avoid garbage retention // Use id, not reference, to avoid garbage retention
final long tid = Thread.currentThread().getId(); final long tid = Thread.currentThread().getId();
} }
@ -293,8 +293,9 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
} }
/** /**
* The number of read locks held by current thread. * The number of reentrant read locks held by current thread.
* Initialized only in constructor and readObject. * Initialized only in constructor and readObject.
* Removed whenever a thread's read hold count drops to 0.
*/ */
private transient ThreadLocalHoldCounter readHolds; private transient ThreadLocalHoldCounter readHolds;
@ -304,17 +305,35 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
* where the next thread to release is the last one to * where the next thread to release is the last one to
* acquire. This is non-volatile since it is just used * acquire. This is non-volatile since it is just used
* as a heuristic, and would be great for threads to cache. * as a heuristic, and would be great for threads to cache.
*
* <p>Can outlive the Thread for which it is caching the read
* hold count, but avoids garbage retention by not retaining a
* reference to the Thread.
*
* <p>Accessed via a benign data race; relies on the memory
* model's final field and out-of-thin-air guarantees.
*/ */
private transient HoldCounter cachedHoldCounter; private transient HoldCounter cachedHoldCounter;
/** /**
* firstReader is the first thread to have acquired the read lock. * firstReader is the first thread to have acquired the read lock.
* firstReaderHoldCount is firstReader's hold count. * firstReaderHoldCount is firstReader's hold count.
* This allows tracking of read holds for uncontended read *
* <p>More precisely, firstReader is the unique thread that last
* changed the shared count from 0 to 1, and has not released the
* read lock since then; null if there is no such thread.
*
* <p>Cannot cause garbage retention unless the thread terminated
* without relinquishing its read locks, since tryReleaseShared
* sets it to null.
*
* <p>Accessed via a benign data race; relies on the memory
* model's out-of-thin-air guarantees for references.
*
* <p>This allows tracking of read holds for uncontended read
* locks to be very cheap. * locks to be very cheap.
*/ */
private final static long INVALID_THREAD_ID = -1; private transient Thread firstReader = null;
private transient long firstReader = INVALID_THREAD_ID;
private transient int firstReaderHoldCount; private transient int firstReaderHoldCount;
Sync() { Sync() {
@ -393,16 +412,16 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
} }
protected final boolean tryReleaseShared(int unused) { protected final boolean tryReleaseShared(int unused) {
long tid = Thread.currentThread().getId(); Thread current = Thread.currentThread();
if (firstReader == tid) { if (firstReader == current) {
// assert firstReaderHoldCount > 0; // assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1) if (firstReaderHoldCount == 1)
firstReader = INVALID_THREAD_ID; firstReader = null;
else else
firstReaderHoldCount--; firstReaderHoldCount--;
} else { } else {
HoldCounter rh = cachedHoldCounter; HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != tid) if (rh == null || rh.tid != current.getId())
rh = readHolds.get(); rh = readHolds.get();
int count = rh.count; int count = rh.count;
if (count <= 1) { if (count <= 1) {
@ -416,6 +435,9 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
int c = getState(); int c = getState();
int nextc = c - SHARED_UNIT; int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc)) if (compareAndSetState(c, nextc))
// Releasing the read lock has no effect on readers,
// but it may allow waiting writers to proceed if
// both read and write locks are now free.
return nextc == 0; return nextc == 0;
} }
} }
@ -450,15 +472,14 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
if (!readerShouldBlock() && if (!readerShouldBlock() &&
r < MAX_COUNT && r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) { compareAndSetState(c, c + SHARED_UNIT)) {
long tid = current.getId();
if (r == 0) { if (r == 0) {
firstReader = tid; firstReader = current;
firstReaderHoldCount = 1; firstReaderHoldCount = 1;
} else if (firstReader == tid) { } else if (firstReader == current) {
firstReaderHoldCount++; firstReaderHoldCount++;
} else { } else {
HoldCounter rh = cachedHoldCounter; HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != tid) if (rh == null || rh.tid != current.getId())
cachedHoldCounter = rh = readHolds.get(); cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0) else if (rh.count == 0)
readHolds.set(rh); readHolds.set(rh);
@ -485,19 +506,17 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
int c = getState(); int c = getState();
if (exclusiveCount(c) != 0) { if (exclusiveCount(c) != 0) {
if (getExclusiveOwnerThread() != current) if (getExclusiveOwnerThread() != current)
//if (removeNeeded) readHolds.remove();
return -1; return -1;
// else we hold the exclusive lock; blocking here // else we hold the exclusive lock; blocking here
// would cause deadlock. // would cause deadlock.
} else if (readerShouldBlock()) { } else if (readerShouldBlock()) {
// Make sure we're not acquiring read lock reentrantly // Make sure we're not acquiring read lock reentrantly
long tid = current.getId(); if (firstReader == current) {
if (firstReader == tid) {
// assert firstReaderHoldCount > 0; // assert firstReaderHoldCount > 0;
} else { } else {
if (rh == null) { if (rh == null) {
rh = cachedHoldCounter; rh = cachedHoldCounter;
if (rh == null || rh.tid != tid) { if (rh == null || rh.tid != current.getId()) {
rh = readHolds.get(); rh = readHolds.get();
if (rh.count == 0) if (rh.count == 0)
readHolds.remove(); readHolds.remove();
@ -510,25 +529,20 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
if (sharedCount(c) == MAX_COUNT) if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded"); throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) { if (compareAndSetState(c, c + SHARED_UNIT)) {
long tid = current.getId();
if (sharedCount(c) == 0) { if (sharedCount(c) == 0) {
firstReader = tid; firstReader = current;
firstReaderHoldCount = 1; firstReaderHoldCount = 1;
} else if (firstReader == tid) { } else if (firstReader == current) {
firstReaderHoldCount++; firstReaderHoldCount++;
} else { } else {
if (rh == null) { if (rh == null)
rh = cachedHoldCounter; rh = cachedHoldCounter;
if (rh != null && rh.tid == tid) { if (rh == null || rh.tid != current.getId())
if (rh.count == 0) rh = readHolds.get();
readHolds.set(rh); else if (rh.count == 0)
} else {
rh = readHolds.get();
}
} else if (rh.count == 0)
readHolds.set(rh); readHolds.set(rh);
cachedHoldCounter = rh; // cache for release
rh.count++; rh.count++;
cachedHoldCounter = rh; // cache for release
} }
return 1; return 1;
} }
@ -572,15 +586,14 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
if (r == MAX_COUNT) if (r == MAX_COUNT)
throw new Error("Maximum lock count exceeded"); throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) { if (compareAndSetState(c, c + SHARED_UNIT)) {
long tid = current.getId();
if (r == 0) { if (r == 0) {
firstReader = tid; firstReader = current;
firstReaderHoldCount = 1; firstReaderHoldCount = 1;
} else if (firstReader == tid) { } else if (firstReader == current) {
firstReaderHoldCount++; firstReaderHoldCount++;
} else { } else {
HoldCounter rh = cachedHoldCounter; HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != tid) if (rh == null || rh.tid != current.getId())
cachedHoldCounter = rh = readHolds.get(); cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0) else if (rh.count == 0)
readHolds.set(rh); readHolds.set(rh);
@ -626,12 +639,12 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
if (getReadLockCount() == 0) if (getReadLockCount() == 0)
return 0; return 0;
long tid = Thread.currentThread().getId(); Thread current = Thread.currentThread();
if (firstReader == tid) if (firstReader == current)
return firstReaderHoldCount; return firstReaderHoldCount;
HoldCounter rh = cachedHoldCounter; HoldCounter rh = cachedHoldCounter;
if (rh != null && rh.tid == tid) if (rh != null && rh.tid == current.getId())
return rh.count; return rh.count;
int count = readHolds.get().count; int count = readHolds.get().count;
@ -647,7 +660,6 @@ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializab
throws java.io.IOException, ClassNotFoundException { throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject(); s.defaultReadObject();
readHolds = new ThreadLocalHoldCounter(); readHolds = new ThreadLocalHoldCounter();
firstReader = INVALID_THREAD_ID;
setState(0); // reset to unlocked state setState(0); // reset to unlocked state
} }

View file

@ -0,0 +1,77 @@
/*
* Copyright 1995-1996 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;
/*
* This class defines the constants that are used by the classes
* which manipulate Zip64 files.
*/
class ZipConstants64 {
/*
* ZIP64 constants
*/
static final long ZIP64_ENDSIG = 0x06064b50L; // "PK\006\006"
static final long ZIP64_LOCSIG = 0x07064b50L; // "PK\006\007"
static final int ZIP64_ENDHDR = 56; // ZIP64 end header size
static final int ZIP64_LOCHDR = 20; // ZIP64 end loc header size
static final int ZIP64_EXTHDR = 24; // EXT header size
static final int ZIP64_EXTID = 0x0001; // Extra field Zip64 header ID
static final int ZIP64_MAGICCOUNT = 0xFFFF;
static final long ZIP64_MAGICVAL = 0xFFFFFFFFL;
/*
* Zip64 End of central directory (END) header field offsets
*/
static final int ZIP64_ENDLEN = 4; // size of zip64 end of central dir
static final int ZIP64_ENDVEM = 12; // version made by
static final int ZIP64_ENDVER = 14; // version needed to extract
static final int ZIP64_ENDNMD = 16; // number of this disk
static final int ZIP64_ENDDSK = 20; // disk number of start
static final int ZIP64_ENDTOD = 24; // total number of entries on this disk
static final int ZIP64_ENDTOT = 32; // total number of entries
static final int ZIP64_ENDSIZ = 40; // central directory size in bytes
static final int ZIP64_ENDOFF = 48; // offset of first CEN header
static final int ZIP64_ENDEXT = 56; // zip64 extensible data sector
/*
* Zip64 End of central directory locator field offsets
*/
static final int ZIP64_LOCDSK = 4; // disk number start
static final int ZIP64_LOCOFF = 8; // offset of zip64 end
static final int ZIP64_LOCTOT = 16; // total number of disks
/*
* Zip64 Extra local (EXT) header field offsets
*/
static final int ZIP64_EXTCRC = 4; // uncompressed file crc-32 value
static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte
static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte
private ZipConstants64() {}
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 1995-2005 Sun Microsystems, Inc. All Rights Reserved. * Copyright 1995-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
@ -144,11 +144,13 @@ class ZipEntry implements ZipConstants, Cloneable {
* Sets the uncompressed size of the entry data. * Sets the uncompressed size of the entry data.
* @param size the uncompressed size in bytes * @param size the uncompressed size in bytes
* @exception IllegalArgumentException if the specified size is less * @exception IllegalArgumentException if the specified size is less
* than 0 or greater than 0xFFFFFFFF bytes * than 0, is greater than 0xFFFFFFFF when
* <a href="package-summary.html#zip64">ZIP64 format</a> is not supported,
* or is less than 0 when ZIP64 is supported
* @see #getSize() * @see #getSize()
*/ */
public void setSize(long size) { public void setSize(long size) {
if (size < 0 || size > 0xFFFFFFFFL) { if (size < 0) {
throw new IllegalArgumentException("invalid entry size"); throw new IllegalArgumentException("invalid entry size");
} }
this.size = size; this.size = size;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 1996-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
@ -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 static java.util.zip.ZipConstants64.*;
/** /**
* This class implements an input stream filter for reading files in the * This class implements an input stream filter for reading files in the
@ -285,6 +286,29 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
byte[] bb = new byte[len]; byte[] bb = new byte[len];
readFully(bb, 0, len); readFully(bb, 0, len);
e.setExtra(bb); e.setExtra(bb);
// extra fields are in "HeaderID(2)DataSize(2)Data... format
if (e.csize == ZIP64_MAGICVAL || e.size == ZIP64_MAGICVAL) {
int off = 0;
while (off + 4 < len) {
int sz = get16(bb, off + 2);
if (get16(bb, off) == ZIP64_EXTID) {
off += 4;
// LOC extra zip64 entry MUST include BOTH original and
// compressed file size fields
if (sz < 16 || (off + sz) > len ) {
// Invalid zip64 extra fields, simply skip. Even it's
// rare, it's possible the entry size happens to be
// the magic value and it "accidnetly" has some bytes
// in extra match the id.
return e;
}
e.size = get64(bb, off);
e.csize = get64(bb, off + 8);
break;
}
off += (sz + 4);
}
}
} }
return e; return e;
} }
@ -375,18 +399,36 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
} }
if ((flag & 8) == 8) { if ((flag & 8) == 8) {
/* "Data Descriptor" present */ /* "Data Descriptor" present */
readFully(tmpbuf, 0, EXTHDR); if (inf.getBytesWritten() > ZIP64_MAGICVAL ||
long sig = get32(tmpbuf, 0); inf.getBytesRead() > ZIP64_MAGICVAL) {
if (sig != EXTSIG) { // no EXTSIG present // ZIP64 format
e.crc = sig; readFully(tmpbuf, 0, ZIP64_EXTHDR);
e.csize = get32(tmpbuf, EXTSIZ - EXTCRC); long sig = get32(tmpbuf, 0);
e.size = get32(tmpbuf, EXTLEN - EXTCRC); if (sig != EXTSIG) { // no EXTSIG present
((PushbackInputStream)in).unread( e.crc = sig;
tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC); e.csize = get64(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC);
e.size = get64(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC);
((PushbackInputStream)in).unread(
tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC - 1, ZIP64_EXTCRC);
} else {
e.crc = get32(tmpbuf, ZIP64_EXTCRC);
e.csize = get64(tmpbuf, ZIP64_EXTSIZ);
e.size = get64(tmpbuf, ZIP64_EXTLEN);
}
} else { } else {
e.crc = get32(tmpbuf, EXTCRC); readFully(tmpbuf, 0, EXTHDR);
e.csize = get32(tmpbuf, EXTSIZ); long sig = get32(tmpbuf, 0);
e.size = get32(tmpbuf, EXTLEN); if (sig != EXTSIG) { // no EXTSIG present
e.crc = sig;
e.csize = get32(tmpbuf, EXTSIZ - EXTCRC);
e.size = get32(tmpbuf, EXTLEN - EXTCRC);
((PushbackInputStream)in).unread(
tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC);
} else {
e.crc = get32(tmpbuf, EXTCRC);
e.csize = get32(tmpbuf, EXTSIZ);
e.size = get32(tmpbuf, EXTLEN);
}
} }
} }
if (e.size != inf.getBytesWritten()) { if (e.size != inf.getBytesWritten()) {
@ -433,6 +475,14 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
* The bytes are assumed to be in Intel (little-endian) byte order. * The bytes are assumed to be in Intel (little-endian) byte order.
*/ */
private static final long get32(byte b[], int off) { private static final long get32(byte b[], int off) {
return get16(b, off) | ((long)get16(b, off+2) << 16); return (get16(b, off) | ((long)get16(b, off+2) << 16)) & 0xffffffffL;
}
/*
* Fetches signed 64-bit value from byte array at specified offset.
* The bytes are assumed to be in Intel (little-endian) byte order.
*/
private static final long get64(byte b[], int off) {
return get32(b, off) | (get32(b, off+4) << 32);
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright 1996-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
@ -29,6 +29,7 @@ import java.io.OutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Vector; import java.util.Vector;
import java.util.HashSet; import java.util.HashSet;
import static java.util.zip.ZipConstants64.*;
/** /**
* This class implements an output stream filter for writing files in the * This class implements an output stream filter for writing files in the
@ -343,26 +344,52 @@ 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 = xentry.flag;
int elen = (e.extra != null) ? e.extra.length : 0;
boolean hasZip64 = false;
writeInt(LOCSIG); // LOC header signature writeInt(LOCSIG); // LOC header signature
writeShort(version(e)); // version needed to extract
writeShort(flag); // general purpose bit flag
writeShort(e.method); // compression method
writeInt(e.time); // last modification time
if ((flag & 8) == 8) { if ((flag & 8) == 8) {
writeShort(version(e)); // version needed to extract
writeShort(flag); // general purpose bit flag
writeShort(e.method); // compression method
writeInt(e.time); // last modification time
// store size, uncompressed size, and crc-32 in data descriptor // store size, uncompressed size, and crc-32 in data descriptor
// immediately following compressed entry data // immediately following compressed entry data
writeInt(0); writeInt(0);
writeInt(0); writeInt(0);
writeInt(0); writeInt(0);
} else { } else {
writeInt(e.crc); // crc-32 if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
writeInt(e.csize); // compressed size hasZip64 = true;
writeInt(e.size); // uncompressed size writeShort(45); // ver 4.5 for zip64
} else {
writeShort(version(e)); // version needed to extract
}
writeShort(flag); // general purpose bit flag
writeShort(e.method); // compression method
writeInt(e.time); // last modification time
writeInt(e.crc); // crc-32
if (hasZip64) {
writeInt(ZIP64_MAGICVAL);
writeInt(ZIP64_MAGICVAL);
elen += 20; //headid(2) + size(2) + size(8) + csize(8)
} else {
writeInt(e.csize); // compressed size
writeInt(e.size); // uncompressed size
}
} }
byte[] nameBytes = getUTF8Bytes(e.name); byte[] nameBytes = getUTF8Bytes(e.name);
writeShort(nameBytes.length); writeShort(nameBytes.length);
writeShort(e.extra != null ? e.extra.length : 0); writeShort(elen);
writeBytes(nameBytes, 0, nameBytes.length); writeBytes(nameBytes, 0, nameBytes.length);
if (hasZip64) {
writeShort(ZIP64_EXTID);
writeShort(16);
writeLong(e.size);
writeLong(e.csize);
}
if (e.extra != null) { if (e.extra != null) {
writeBytes(e.extra, 0, e.extra.length); writeBytes(e.extra, 0, e.extra.length);
} }
@ -375,8 +402,13 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
private void writeEXT(ZipEntry e) throws IOException { private void writeEXT(ZipEntry e) throws IOException {
writeInt(EXTSIG); // EXT header signature writeInt(EXTSIG); // EXT header signature
writeInt(e.crc); // crc-32 writeInt(e.crc); // crc-32
writeInt(e.csize); // compressed size if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
writeInt(e.size); // uncompressed size writeLong(e.csize);
writeLong(e.size);
} else {
writeInt(e.csize); // compressed size
writeInt(e.size); // uncompressed size
}
} }
/* /*
@ -387,18 +419,49 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
ZipEntry e = xentry.entry; ZipEntry e = xentry.entry;
int flag = xentry.flag; int flag = xentry.flag;
int version = version(e); int version = version(e);
long csize = e.csize;
long size = e.size;
long offset = xentry.offset;
int e64len = 0;
boolean hasZip64 = false;
if (e.csize >= ZIP64_MAGICVAL) {
csize = ZIP64_MAGICVAL;
e64len += 8; // csize(8)
hasZip64 = true;
}
if (e.size >= ZIP64_MAGICVAL) {
size = ZIP64_MAGICVAL; // size(8)
e64len += 8;
hasZip64 = true;
}
if (xentry.offset >= ZIP64_MAGICVAL) {
offset = ZIP64_MAGICVAL;
e64len += 8; // offset(8)
hasZip64 = true;
}
writeInt(CENSIG); // CEN header signature writeInt(CENSIG); // CEN header signature
writeShort(version); // version made by if (hasZip64) {
writeShort(version); // version needed to extract writeShort(45); // ver 4.5 for zip64
writeShort(45);
} else {
writeShort(version); // version made by
writeShort(version); // version needed to extract
}
writeShort(flag); // general purpose bit flag writeShort(flag); // general purpose bit flag
writeShort(e.method); // compression method writeShort(e.method); // compression method
writeInt(e.time); // last modification time writeInt(e.time); // last modification time
writeInt(e.crc); // crc-32 writeInt(e.crc); // crc-32
writeInt(e.csize); // compressed size writeInt(csize); // compressed size
writeInt(e.size); // uncompressed size writeInt(size); // uncompressed size
byte[] nameBytes = getUTF8Bytes(e.name); byte[] nameBytes = getUTF8Bytes(e.name);
writeShort(nameBytes.length); writeShort(nameBytes.length);
writeShort(e.extra != null ? e.extra.length : 0); if (hasZip64) {
// + headid(2) + datasize(2)
writeShort(e64len + 4 + (e.extra != null ? e.extra.length : 0));
} else {
writeShort(e.extra != null ? e.extra.length : 0);
}
byte[] commentBytes; byte[] commentBytes;
if (e.comment != null) { if (e.comment != null) {
commentBytes = getUTF8Bytes(e.comment); commentBytes = getUTF8Bytes(e.comment);
@ -410,8 +473,18 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeShort(0); // starting disk number writeShort(0); // starting disk number
writeShort(0); // internal file attributes (unused) writeShort(0); // internal file attributes (unused)
writeInt(0); // external file attributes (unused) writeInt(0); // external file attributes (unused)
writeInt(xentry.offset); // relative offset of local header writeInt(offset); // relative offset of local header
writeBytes(nameBytes, 0, nameBytes.length); writeBytes(nameBytes, 0, nameBytes.length);
if (hasZip64) {
writeShort(ZIP64_EXTID);// Zip64 extra
writeShort(e64len);
if (size == ZIP64_MAGICVAL)
writeLong(e.size);
if (csize == ZIP64_MAGICVAL)
writeLong(e.csize);
if (offset == ZIP64_MAGICVAL)
writeLong(xentry.offset);
}
if (e.extra != null) { if (e.extra != null) {
writeBytes(e.extra, 0, e.extra.length); writeBytes(e.extra, 0, e.extra.length);
} }
@ -424,15 +497,50 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
* Writes end of central directory (END) header. * Writes end of central directory (END) header.
*/ */
private void writeEND(long off, long len) throws IOException { private void writeEND(long off, long len) throws IOException {
boolean hasZip64 = false;
long xlen = len;
long xoff = off;
if (xlen >= ZIP64_MAGICVAL) {
xlen = ZIP64_MAGICVAL;
hasZip64 = true;
}
if (xoff >= ZIP64_MAGICVAL) {
xoff = ZIP64_MAGICVAL;
hasZip64 = true;
}
int count = xentries.size(); int count = xentries.size();
writeInt(ENDSIG); // END record signature if (count >= ZIP64_MAGICCOUNT) {
writeShort(0); // number of this disk count = ZIP64_MAGICCOUNT;
writeShort(0); // central directory start disk hasZip64 = true;
writeShort(count); // number of directory entries on disk }
writeShort(count); // total number of directory entries if (hasZip64) {
writeInt(len); // length of central directory long off64 = written;
writeInt(off); // offset of central directory //zip64 end of central directory record
if (comment != null) { // zip file comment writeInt(ZIP64_ENDSIG); // zip64 END record signature
writeLong(ZIP64_ENDHDR - 12); // size of zip64 end
writeShort(45); // version made by
writeShort(45); // version needed to extract
writeInt(0); // number of this disk
writeInt(0); // central directory start disk
writeLong(xentries.size()); // number of directory entires on disk
writeLong(xentries.size()); // number of directory entires
writeLong(len); // length of central directory
writeLong(off); // offset of central directory
//zip64 end of central directory locator
writeInt(ZIP64_LOCSIG); // zip64 END locator signature
writeInt(0); // zip64 END start disk
writeLong(off64); // offset of zip64 END
writeInt(1); // total number of disks (?)
}
writeInt(ENDSIG); // END record signature
writeShort(0); // number of this disk
writeShort(0); // central directory start disk
writeShort(count); // number of directory entries on disk
writeShort(count); // total number of directory entries
writeInt(xlen); // length of central directory
writeInt(xoff); // offset of central directory
if (comment != null) { // zip file comment
byte[] b = getUTF8Bytes(comment); byte[] b = getUTF8Bytes(comment);
writeShort(b.length); writeShort(b.length);
writeBytes(b, 0, b.length); writeBytes(b, 0, b.length);
@ -463,6 +571,22 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
written += 4; written += 4;
} }
/*
* Writes a 64-bit int to the output stream in little-endian byte order.
*/
private void writeLong(long v) throws IOException {
OutputStream out = this.out;
out.write((int)((v >>> 0) & 0xff));
out.write((int)((v >>> 8) & 0xff));
out.write((int)((v >>> 16) & 0xff));
out.write((int)((v >>> 24) & 0xff));
out.write((int)((v >>> 32) & 0xff));
out.write((int)((v >>> 40) & 0xff));
out.write((int)((v >>> 48) & 0xff));
out.write((int)((v >>> 56) & 0xff));
written += 8;
}
/* /*
* Writes an array of bytes to the output stream. * Writes an array of bytes to the output stream.
*/ */

View file

@ -45,6 +45,13 @@ input streams.
Info-ZIP Application Note 970311 Info-ZIP Application Note 970311
</a> - a detailed description of the Info-ZIP format upon which </a> - a detailed description of the Info-ZIP format upon which
the <code>java.util.zip</code> classes are based. the <code>java.util.zip</code> classes are based.
<p>
<a name="zip64">
<li>An implementation may optionally support the ZIP64(tm) format extensions
defined by the
<a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">
PKWARE ZIP File Format Specification</a>. The ZIP64(tm) format extensions
are used to overcome the size limitations of the original ZIP format.
<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>
@ -70,7 +77,6 @@ input streams.
<li>CRC-32 checksum is described in RFC 1952 (above) <li>CRC-32 checksum is described in RFC 1952 (above)
<p> <p>
<li>Adler-32 checksum is described in RFC 1950 (above) <li>Adler-32 checksum is described in RFC 1950 (above)
</ul> </ul>

View file

@ -78,7 +78,6 @@ public class DefaultProxySelector extends ProxySelector {
}; };
private static boolean hasSystemProxies = false; private static boolean hasSystemProxies = false;
private static Properties defprops = new Properties();
static { static {
final String key = "java.net.useSystemProxies"; final String key = "java.net.useSystemProxies";
@ -107,6 +106,9 @@ public class DefaultProxySelector extends ProxySelector {
RegexpPool hostsPool; RegexpPool hostsPool;
String property; String property;
static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null);
static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null);
NonProxyInfo(String p, String s, RegexpPool pool) { NonProxyInfo(String p, String s, RegexpPool pool) {
property = p; property = p;
hostsSource = s; hostsSource = s;
@ -114,8 +116,6 @@ public class DefaultProxySelector extends ProxySelector {
} }
} }
private static NonProxyInfo ftpNonProxyInfo = new NonProxyInfo("ftp.nonProxyHosts", null, null);
private static NonProxyInfo httpNonProxyInfo = new NonProxyInfo("http.nonProxyHosts", null, null);
/** /**
* select() method. Where all the hard work is done. * select() method. Where all the hard work is done.
@ -175,13 +175,13 @@ public class DefaultProxySelector extends ProxySelector {
NonProxyInfo pinfo = null; NonProxyInfo pinfo = null;
if ("http".equalsIgnoreCase(protocol)) { if ("http".equalsIgnoreCase(protocol)) {
pinfo = httpNonProxyInfo; pinfo = NonProxyInfo.httpNonProxyInfo;
} else if ("https".equalsIgnoreCase(protocol)) { } else if ("https".equalsIgnoreCase(protocol)) {
// HTTPS uses the same property as HTTP, for backward // HTTPS uses the same property as HTTP, for backward
// compatibility // compatibility
pinfo = httpNonProxyInfo; pinfo = NonProxyInfo.httpNonProxyInfo;
} else if ("ftp".equalsIgnoreCase(protocol)) { } else if ("ftp".equalsIgnoreCase(protocol)) {
pinfo = ftpNonProxyInfo; pinfo = NonProxyInfo.ftpNonProxyInfo;
} }
/** /**
@ -334,7 +334,6 @@ public class DefaultProxySelector extends ProxySelector {
} }
} }
private static final Pattern p6 = Pattern.compile("::1|(0:){7}1|(0:){1,6}:1");
private boolean isLoopback(String host) { private boolean isLoopback(String host) {
if (host == null || host.length() == 0) if (host == null || host.length() == 0)
return false; return false;
@ -364,6 +363,7 @@ public class DefaultProxySelector extends ProxySelector {
} }
if (host.endsWith(":1")) { if (host.endsWith(":1")) {
final Pattern p6 = Pattern.compile("::1|(0:){7}1|(0:){1,6}:1");
return p6.matcher(host).matches(); return p6.matcher(host).matches();
} }
return false; return false;

View file

@ -313,11 +313,9 @@ class DatagramChannelImpl
throw new NullPointerException(); throw new NullPointerException();
synchronized (readLock) { synchronized (readLock) {
ensureOpen(); ensureOpen();
// If socket is not bound then behave as if nothing received // Socket was not bound before attempting receive
// Will be fixed by 6621699 if (localAddress() == null)
if (localAddress() == null) { bind(null);
return null;
}
int n = 0; int n = 0;
ByteBuffer bb = null; ByteBuffer bb = null;
try { try {

View file

@ -25,6 +25,7 @@
package sun.nio.ch; package sun.nio.ch;
import java.nio.channels.Channel;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.IOException; import java.io.IOException;
@ -35,7 +36,7 @@ import java.io.IOException;
* @since 1.4 * @since 1.4
*/ */
interface SelChImpl { interface SelChImpl extends Channel {
FileDescriptor getFD(); FileDescriptor getFD();

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2000-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
@ -54,8 +54,8 @@ public class JarSignerResources extends java.util.ListResourceBundle {
"If keystore is not password protected, then -storepass and -keypass must not be specified"}, "If keystore is not password protected, then -storepass and -keypass must not be specified"},
{"Usage: jarsigner [options] jar-file alias", {"Usage: jarsigner [options] jar-file alias",
"Usage: jarsigner [options] jar-file alias"}, "Usage: jarsigner [options] jar-file alias"},
{" jarsigner -verify [options] jar-file", {" jarsigner -verify [options] jar-file [alias...]",
" jarsigner -verify [options] jar-file"}, " jarsigner -verify [options] jar-file [alias...]"},
{"[-keystore <url>] keystore location", {"[-keystore <url>] keystore location",
"[-keystore <url>] keystore location"}, "[-keystore <url>] keystore location"},
{"[-storepass <password>] password for keystore integrity", {"[-storepass <password>] password for keystore integrity",
@ -64,6 +64,8 @@ public class JarSignerResources extends java.util.ListResourceBundle {
"[-storetype <type>] keystore type"}, "[-storetype <type>] keystore type"},
{"[-keypass <password>] password for private key (if different)", {"[-keypass <password>] password for private key (if different)",
"[-keypass <password>] password for private key (if different)"}, "[-keypass <password>] password for private key (if different)"},
{"[-certchain <file>] name of alternative certchain file",
"[-certchain <file>] name of alternative certchain file"},
{"[-sigfile <file>] name of .SF/.DSA file", {"[-sigfile <file>] name of .SF/.DSA file",
"[-sigfile <file>] name of .SF/.DSA file"}, "[-sigfile <file>] name of .SF/.DSA file"},
{"[-signedjar <file>] name of signed JAR file", {"[-signedjar <file>] name of signed JAR file",
@ -74,8 +76,10 @@ public class JarSignerResources extends java.util.ListResourceBundle {
"[-sigalg <algorithm>] name of signature algorithm"}, "[-sigalg <algorithm>] name of signature algorithm"},
{"[-verify] verify a signed JAR file", {"[-verify] verify a signed JAR file",
"[-verify] verify a signed JAR file"}, "[-verify] verify a signed JAR file"},
{"[-verbose] verbose output when signing/verifying", {"[-verbose[:suboptions]] verbose output when signing/verifying.",
"[-verbose] verbose output when signing/verifying"}, "[-verbose[:suboptions]] verbose output when signing/verifying."},
{" suboptions can be all, grouped or summary",
" suboptions can be all, grouped or summary"},
{"[-certs] display certificates when verbose and verifying", {"[-certs] display certificates when verbose and verifying",
"[-certs] display certificates when verbose and verifying"}, "[-certs] display certificates when verbose and verifying"},
{"[-tsa <url>] location of the Timestamping Authority", {"[-tsa <url>] location of the Timestamping Authority",
@ -98,10 +102,22 @@ public class JarSignerResources extends java.util.ListResourceBundle {
"[-providerClass <class> name of cryptographic service provider's"}, "[-providerClass <class> name of cryptographic service provider's"},
{" [-providerArg <arg>]] ... master class file and constructor argument", {" [-providerArg <arg>]] ... master class file and constructor argument",
" [-providerArg <arg>]] ... master class file and constructor argument"}, " [-providerArg <arg>]] ... master class file and constructor argument"},
{"[-strict] treat warnings as errors",
"[-strict] treat warnings as errors"},
{"Option lacks argument", "Option lacks argument"},
{"Please type jarsigner -help for usage", "Please type jarsigner -help for usage"},
{"Please specify jarfile name", "Please specify jarfile name"},
{"Please specify alias name", "Please specify alias name"},
{"Only one alias can be specified", "Only one alias can be specified"},
{"This jar contains signed entries which is not signed by the specified alias(es).",
"This jar contains signed entries which is not signed by the specified alias(es)."},
{"This jar contains signed entries that's not signed by alias in this keystore.",
"This jar contains signed entries that's not signed by alias in this keystore."},
{"s", "s"}, {"s", "s"},
{"m", "m"}, {"m", "m"},
{"k", "k"}, {"k", "k"},
{"i", "i"}, {"i", "i"},
{"(and %d more)", "(and %d more)"},
{" s = signature was verified ", {" s = signature was verified ",
" s = signature was verified "}, " s = signature was verified "},
{" m = entry is listed in manifest", {" m = entry is listed in manifest",
@ -110,7 +126,11 @@ public class JarSignerResources extends java.util.ListResourceBundle {
" k = at least one certificate was found in keystore"}, " k = at least one certificate was found in keystore"},
{" i = at least one certificate was found in identity scope", {" i = at least one certificate was found in identity scope",
" i = at least one certificate was found in identity scope"}, " i = at least one certificate was found in identity scope"},
{" X = not signed by specified alias(es)",
" X = not signed by specified alias(es)"},
{"no manifest.", "no manifest."}, {"no manifest.", "no manifest."},
{"(Signature related entries)","(Signature related entries)"},
{"(Unsigned entries)", "(Unsigned entries)"},
{"jar is unsigned. (signatures missing or not parsable)", {"jar is unsigned. (signatures missing or not parsable)",
"jar is unsigned. (signatures missing or not parsable)"}, "jar is unsigned. (signatures missing or not parsable)"},
{"jar verified.", "jar verified."}, {"jar verified.", "jar verified."},
@ -134,6 +154,12 @@ public class JarSignerResources extends java.util.ListResourceBundle {
"unable to instantiate keystore class: "}, "unable to instantiate keystore class: "},
{"Certificate chain not found for: alias. alias must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain.", {"Certificate chain not found for: alias. alias must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain.",
"Certificate chain not found for: {0}. {1} must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain."}, "Certificate chain not found for: {0}. {1} must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain."},
{"File specified by -certchain does not exist",
"File specified by -certchain does not exist"},
{"Cannot restore certchain from file specified",
"Cannot restore certchain from file specified"},
{"Certificate chain not found in the file specified.",
"Certificate chain not found in the file specified."},
{"found non-X.509 certificate in signer's chain", {"found non-X.509 certificate in signer's chain",
"found non-X.509 certificate in signer's chain"}, "found non-X.509 certificate in signer's chain"},
{"incomplete certificate chain", "incomplete certificate chain"}, {"incomplete certificate chain", "incomplete certificate chain"},
@ -149,6 +175,7 @@ public class JarSignerResources extends java.util.ListResourceBundle {
{"certificate is not valid until", {"certificate is not valid until",
"certificate is not valid until {0}"}, "certificate is not valid until {0}"},
{"certificate will expire on", "certificate will expire on {0}"}, {"certificate will expire on", "certificate will expire on {0}"},
{"[CertPath not validated: ", "[CertPath not validated: "},
{"requesting a signature timestamp", {"requesting a signature timestamp",
"requesting a signature timestamp"}, "requesting a signature timestamp"},
{"TSA location: ", "TSA location: "}, {"TSA location: ", "TSA location: "},
@ -189,14 +216,18 @@ public class JarSignerResources extends java.util.ListResourceBundle {
"The signer certificate's ExtendedKeyUsage extension doesn't allow code signing."}, "The signer certificate's ExtendedKeyUsage extension doesn't allow code signing."},
{"The signer certificate's NetscapeCertType extension doesn't allow code signing.", {"The signer certificate's NetscapeCertType extension doesn't allow code signing.",
"The signer certificate's NetscapeCertType extension doesn't allow code signing."}, "The signer certificate's NetscapeCertType extension doesn't allow code signing."},
{"This jar contains entries whose signer certificate's KeyUsage extension doesn't allow code signing.", {"This jar contains entries whose signer certificate's KeyUsage extension doesn't allow code signing.",
"This jar contains entries whose signer certificate's KeyUsage extension doesn't allow code signing."}, "This jar contains entries whose signer certificate's KeyUsage extension doesn't allow code signing."},
{"This jar contains entries whose signer certificate's ExtendedKeyUsage extension doesn't allow code signing.", {"This jar contains entries whose signer certificate's ExtendedKeyUsage extension doesn't allow code signing.",
"This jar contains entries whose signer certificate's ExtendedKeyUsage extension doesn't allow code signing."}, "This jar contains entries whose signer certificate's ExtendedKeyUsage extension doesn't allow code signing."},
{"This jar contains entries whose signer certificate's NetscapeCertType extension doesn't allow code signing.", {"This jar contains entries whose signer certificate's NetscapeCertType extension doesn't allow code signing.",
"This jar contains entries whose signer certificate's NetscapeCertType extension doesn't allow code signing."}, "This jar contains entries whose signer certificate's NetscapeCertType extension doesn't allow code signing."},
{"[{0} extension does not support code signing]", {"[{0} extension does not support code signing]",
"[{0} extension does not support code signing]"}, "[{0} extension does not support code signing]"},
{"The signer's certificate chain is not validated.",
"The signer's certificate chain is not validated."},
{"This jar contains entries whose certificate chain is not validated.",
"This jar contains entries whose certificate chain is not validated."},
}; };
/** /**

View file

@ -2545,7 +2545,19 @@ public final class KeyTool {
* Returns true if the certificate is self-signed, false otherwise. * Returns true if the certificate is self-signed, false otherwise.
*/ */
private boolean isSelfSigned(X509Certificate cert) { private boolean isSelfSigned(X509Certificate cert) {
return cert.getSubjectDN().equals(cert.getIssuerDN()); return signedBy(cert, cert);
}
private boolean signedBy(X509Certificate end, X509Certificate ca) {
if (!ca.getSubjectDN().equals(end.getIssuerDN())) {
return false;
}
try {
end.verify(ca.getPublicKey());
return true;
} catch (Exception e) {
return false;
}
} }
/** /**
@ -2869,20 +2881,18 @@ public final class KeyTool {
Certificate tmpCert = replyCerts[0]; Certificate tmpCert = replyCerts[0];
replyCerts[0] = replyCerts[i]; replyCerts[0] = replyCerts[i];
replyCerts[i] = tmpCert; replyCerts[i] = tmpCert;
Principal issuer = ((X509Certificate)replyCerts[0]).getIssuerDN();
X509Certificate thisCert = (X509Certificate)replyCerts[0];
for (i=1; i < replyCerts.length-1; i++) { for (i=1; i < replyCerts.length-1; i++) {
// find a cert in the reply whose "subject" is the same as the // find a cert in the reply who signs thisCert
// given "issuer"
int j; int j;
for (j=i; j<replyCerts.length; j++) { for (j=i; j<replyCerts.length; j++) {
Principal subject; if (signedBy(thisCert, (X509Certificate)replyCerts[j])) {
subject = ((X509Certificate)replyCerts[j]).getSubjectDN();
if (subject.equals(issuer)) {
tmpCert = replyCerts[i]; tmpCert = replyCerts[i];
replyCerts[i] = replyCerts[j]; replyCerts[i] = replyCerts[j];
replyCerts[j] = tmpCert; replyCerts[j] = tmpCert;
issuer = ((X509Certificate)replyCerts[i]).getIssuerDN(); thisCert = (X509Certificate)replyCerts[i];
break; break;
} }
} }
@ -2892,18 +2902,6 @@ public final class KeyTool {
} }
} }
// now verify each cert in the ordered chain
for (i=0; i<replyCerts.length-1; i++) {
PublicKey pubKey = replyCerts[i+1].getPublicKey();
try {
replyCerts[i].verify(pubKey);
} catch (Exception e) {
throw new Exception(rb.getString
("Certificate chain in reply does not verify: ") +
e.getMessage());
}
}
if (noprompt) { if (noprompt) {
return replyCerts; return replyCerts;
} }
@ -3035,9 +3033,8 @@ public final class KeyTool {
private boolean buildChain(X509Certificate certToVerify, private boolean buildChain(X509Certificate certToVerify,
Vector<Certificate> chain, Vector<Certificate> chain,
Hashtable<Principal, Vector<Certificate>> certs) { Hashtable<Principal, Vector<Certificate>> certs) {
Principal subject = certToVerify.getSubjectDN();
Principal issuer = certToVerify.getIssuerDN(); Principal issuer = certToVerify.getIssuerDN();
if (subject.equals(issuer)) { if (isSelfSigned(certToVerify)) {
// reached self-signed root cert; // reached self-signed root cert;
// no verification needed because it's trusted. // no verification needed because it's trusted.
chain.addElement(certToVerify); chain.addElement(certToVerify);
@ -3108,7 +3105,7 @@ public final class KeyTool {
/** /**
* Returns the keystore with the configured CA certificates. * Returns the keystore with the configured CA certificates.
*/ */
private KeyStore getCacertsKeyStore() public static KeyStore getCacertsKeyStore()
throws Exception throws Exception
{ {
String sep = File.separator; String sep = File.separator;

View file

@ -44,8 +44,6 @@ public class ManifestEntryVerifier {
private static final Debug debug = Debug.getInstance("jar"); private static final Debug debug = Debug.getInstance("jar");
private static final Provider digestProvider = Providers.getSunProvider();
/** the created digest objects */ /** the created digest objects */
HashMap<String, MessageDigest> createdDigests; HashMap<String, MessageDigest> createdDigests;
@ -127,7 +125,7 @@ public class ManifestEntryVerifier {
try { try {
digest = MessageDigest.getInstance digest = MessageDigest.getInstance
(algorithm, digestProvider); (algorithm, Providers.getSunProvider());
createdDigests.put(algorithm, digest); createdDigests.put(algorithm, digest);
} catch (NoSuchAlgorithmException nsae) { } catch (NoSuchAlgorithmException nsae) {
// ignore // ignore

View file

@ -312,6 +312,38 @@ findEND(jzfile *zip, void *endbuf)
return -1; /* END header not found */ return -1; /* END header not found */
} }
/*
* Searches for the ZIP64 end of central directory (END) header. The
* contents of the ZIP64 END header will be read and placed in end64buf.
* Returns the file position of the ZIP64 END header, otherwise returns
* -1 if the END header was not found or an error occurred.
*
* The ZIP format specifies the "position" of each related record as
* ...
* [central directory]
* [zip64 end of central directory record]
* [zip64 end of central directory locator]
* [end of central directory record]
*
* The offset of zip64 end locator can be calculated from endpos as
* "endpos - ZIP64_LOCHDR".
* The "offset" of zip64 end record is stored in zip64 end locator.
*/
static jlong
findEND64(jzfile *zip, void *end64buf, jlong endpos)
{
char loc64[ZIP64_LOCHDR];
jlong end64pos;
if (readFullyAt(zip->zfd, loc64, ZIP64_LOCHDR, endpos - ZIP64_LOCHDR) == -1) {
return -1; // end64 locator not found
}
end64pos = ZIP64_LOCOFF(loc64);
if (readFullyAt(zip->zfd, end64buf, ZIP64_ENDHDR, end64pos) == -1) {
return -1; // end64 record not found
}
return end64pos;
}
/* /*
* Returns a hash code value for a C-style NUL-terminated string. * Returns a hash code value for a C-style NUL-terminated string.
*/ */
@ -463,7 +495,7 @@ static jlong
readCEN(jzfile *zip, jint knownTotal) readCEN(jzfile *zip, jint knownTotal)
{ {
/* Following are unsigned 32-bit */ /* Following are unsigned 32-bit */
jlong endpos, cenpos, cenlen; jlong endpos, end64pos, cenpos, cenlen, cenoff;
/* Following are unsigned 16-bit */ /* Following are unsigned 16-bit */
jint total, tablelen, i, j; jint total, tablelen, i, j;
unsigned char *cenbuf = NULL; unsigned char *cenbuf = NULL;
@ -474,6 +506,7 @@ readCEN(jzfile *zip, jint knownTotal)
jlong offset; jlong offset;
#endif #endif
unsigned char endbuf[ENDHDR]; unsigned char endbuf[ENDHDR];
jint endhdrlen = ENDHDR;
jzcell *entries; jzcell *entries;
jint *table; jint *table;
@ -490,13 +523,27 @@ readCEN(jzfile *zip, jint knownTotal)
/* Get position and length of central directory */ /* Get position and length of central directory */
cenlen = ENDSIZ(endbuf); cenlen = ENDSIZ(endbuf);
cenoff = ENDOFF(endbuf);
total = ENDTOT(endbuf);
if (cenlen == ZIP64_MAGICVAL || cenoff == ZIP64_MAGICVAL ||
total == ZIP64_MAGICCOUNT) {
unsigned char end64buf[ZIP64_ENDHDR];
if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) {
cenlen = ZIP64_ENDSIZ(end64buf);
cenoff = ZIP64_ENDOFF(end64buf);
total = (jint)ZIP64_ENDTOT(end64buf);
endpos = end64pos;
endhdrlen = ZIP64_ENDHDR;
}
}
if (cenlen > endpos) if (cenlen > endpos)
ZIP_FORMAT_ERROR("invalid END header (bad central directory size)"); ZIP_FORMAT_ERROR("invalid END header (bad central directory size)");
cenpos = endpos - cenlen; cenpos = endpos - cenlen;
/* Get position of first local file (LOC) header, taking into /* Get position of first local file (LOC) header, taking into
* account that there may be a stub prefixed to the zip file. */ * account that there may be a stub prefixed to the zip file. */
zip->locpos = cenpos - ENDOFF(endbuf); zip->locpos = cenpos - cenoff;
if (zip->locpos < 0) if (zip->locpos < 0)
ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)"); ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)");
@ -527,7 +574,7 @@ readCEN(jzfile *zip, jint knownTotal)
out the page size in order to make offset to be multiples of out the page size in order to make offset to be multiples of
page size. page size.
*/ */
zip->mlen = cenpos - offset + cenlen + ENDHDR; zip->mlen = cenpos - offset + cenlen + endhdrlen;
zip->offset = offset; zip->offset = offset;
mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset); mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset);
zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL : zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL :
@ -551,8 +598,13 @@ readCEN(jzfile *zip, jint knownTotal)
* is a 2-byte field, but we (and other zip implementations) * is a 2-byte field, but we (and other zip implementations)
* support approx. 2**31 entries, we do not trust ENDTOT, but * support approx. 2**31 entries, we do not trust ENDTOT, but
* treat it only as a strong hint. When we call ourselves * treat it only as a strong hint. When we call ourselves
* recursively, knownTotal will have the "true" value. */ * recursively, knownTotal will have the "true" value.
total = (knownTotal != -1) ? knownTotal : ENDTOT(endbuf); *
* Keep this path alive even with the Zip64 END support added, just
* for zip files that have more than 0xffff entries but don't have
* the Zip64 enabled.
*/
total = (knownTotal != -1) ? knownTotal : total;
entries = zip->entries = calloc(total, sizeof(entries[0])); entries = zip->entries = calloc(total, sizeof(entries[0]));
tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions
table = zip->table = malloc(tablelen * sizeof(table[0])); table = zip->table = malloc(tablelen * sizeof(table[0]));
@ -854,6 +906,7 @@ typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint;
static jzentry * static jzentry *
newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint) newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)
{ {
jlong locoff;
jint nlen, elen, clen; jint nlen, elen, clen;
jzentry *ze; jzentry *ze;
char *cen; char *cen;
@ -880,18 +933,55 @@ newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)
ze->size = CENLEN(cen); ze->size = CENLEN(cen);
ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen); ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen);
ze->crc = CENCRC(cen); ze->crc = CENCRC(cen);
ze->pos = -(zip->locpos + CENOFF(cen)); locoff = CENOFF(cen);
ze->pos = -(zip->locpos + locoff);
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);
ze->name[nlen] = '\0'; ze->name[nlen] = '\0';
if (elen > 0) { if (elen > 0) {
char *extra = cen + CENHDR + nlen;
/* This entry has "extra" data */ /* This entry has "extra" data */
if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch; if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch;
ze->extra[0] = (unsigned char) elen; ze->extra[0] = (unsigned char) elen;
ze->extra[1] = (unsigned char) (elen >> 8); ze->extra[1] = (unsigned char) (elen >> 8);
memcpy(ze->extra+2, cen + CENHDR + nlen, elen); memcpy(ze->extra+2, extra, elen);
if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL ||
locoff == ZIP64_MAGICVAL) {
jint off = 0;
while ((off + 4) < elen) { // spec: HeaderID+DataSize+Data
jint sz = SH(extra, off + 2);
if (SH(extra, off) == ZIP64_EXTID) {
off += 4;
if (ze->size == ZIP64_MAGICVAL) {
// if invalid zip64 extra fields, just skip
if (sz < 8 || (off + 8) > elen)
break;
ze->size = LL(extra, off);
sz -= 8;
off += 8;
}
if (ze->csize == ZIP64_MAGICVAL) {
if (sz < 8 || (off + 8) > elen)
break;
ze->csize = LL(extra, off);
sz -= 8;
off += 8;
}
if (locoff == ZIP64_MAGICVAL) {
if (sz < 8 || (off + 8) > elen)
break;
ze->pos = -(zip->locpos + LL(extra, off));
sz -= 8;
off += 8;
}
break;
}
off += (sz + 4);
}
}
} }
if (clen > 0) { if (clen > 0) {

View file

@ -38,9 +38,13 @@
#define CENSIG 0x02014b50L /* "PK\001\002" */ #define CENSIG 0x02014b50L /* "PK\001\002" */
#define ENDSIG 0x06054b50L /* "PK\005\006" */ #define ENDSIG 0x06054b50L /* "PK\005\006" */
#define ZIP64_ENDSIG 0x06064b50L /* "PK\006\006" */
#define ZIP64_LOCSIG 0x07064b50L /* "PK\006\007" */
/* /*
* Header sizes including signatures * Header sizes including signatures
*/ */
#ifdef USE_MMAP #ifdef USE_MMAP
#define SIGSIZ 4 #define SIGSIZ 4
#endif #endif
@ -49,12 +53,22 @@
#define CENHDR 46 #define CENHDR 46
#define ENDHDR 22 #define ENDHDR 22
#define ZIP64_ENDHDR 56 // ZIP64 end header size
#define ZIP64_LOCHDR 20 // ZIP64 end loc header size
#define ZIP64_EXTHDR 24 // EXT header size
#define ZIP64_EXTID 1 // Extra field Zip64 header ID
#define ZIP64_MAGICVAL 0xffffffffLL
#define ZIP64_MAGICCOUNT 0xffff
/* /*
* Header field access macros * Header field access macros
*/ */
#define CH(b, n) (((unsigned char *)(b))[n]) #define CH(b, n) (((unsigned char *)(b))[n])
#define SH(b, n) (CH(b, n) | (CH(b, n+1) << 8)) #define SH(b, n) (CH(b, n) | (CH(b, n+1) << 8))
#define LG(b, n) (SH(b, n) | (SH(b, n+2) << 16)) #define LG(b, n) ((SH(b, n) | (SH(b, n+2) << 16)) &0xffffffffUL)
#define LL(b, n) (((jlong)LG(b, n)) | (((jlong)LG(b, n+4)) << 32))
#define GETSIG(b) LG(b, 0) #define GETSIG(b) LG(b, 0)
/* /*
@ -105,6 +119,26 @@
#define ENDOFF(b) LG(b, 16) /* central directory offset */ #define ENDOFF(b) LG(b, 16) /* central directory offset */
#define ENDCOM(b) SH(b, 20) /* size of zip file comment */ #define ENDCOM(b) SH(b, 20) /* size of zip file comment */
/*
* Macros for getting Zip64 end of central directory header fields
*/
#define ZIP64_ENDLEN(b) LL(b, 4) /* size of zip64 end of central dir */
#define ZIP64_ENDVEM(b) SH(b, 12) /* version made by */
#define ZIP64_ENDVER(b) SH(b, 14) /* version needed to extract */
#define ZIP64_ENDNMD(b) LG(b, 16) /* number of this disk */
#define ZIP64_ENDDSK(b) LG(b, 20) /* disk number of start */
#define ZIP64_ENDTOD(b) LL(b, 24) /* total number of entries on this disk */
#define ZIP64_ENDTOT(b) LL(b, 32) /* total number of entries */
#define ZIP64_ENDSIZ(b) LL(b, 40) /* central directory size in bytes */
#define ZIP64_ENDOFF(b) LL(b, 48) /* offset of first CEN header */
/*
* Macros for getting Zip64 end of central directory locator fields
*/
#define ZIP64_LOCDSK(b) LG(b, 4) /* disk number start */
#define ZIP64_LOCOFF(b) LL(b, 8) /* offset of zip64 end */
#define ZIP64_LOCTOT(b) LG(b, 16) /* total number of disks */
/* /*
* Supported compression methods * Supported compression methods
*/ */
@ -145,7 +179,7 @@ typedef struct jzentry { /* Zip file entry */
*/ */
typedef struct jzcell { typedef struct jzcell {
unsigned int hash; /* 32 bit hashcode on name */ unsigned int hash; /* 32 bit hashcode on name */
unsigned int cenpos; /* Offset of central directory file header */ jlong cenpos; /* Offset of central directory file header */
unsigned int next; /* hash chain: index into jzfile->entries */ unsigned int next; /* hash chain: index into jzfile->entries */
} jzcell; } jzcell;

View file

@ -106,11 +106,11 @@ struct internal_state;
typedef struct z_stream_s { typedef struct z_stream_s {
Bytef *next_in; /* next input byte */ Bytef *next_in; /* next input byte */
uInt avail_in; /* number of bytes available at next_in */ uInt avail_in; /* number of bytes available at next_in */
uLong total_in; /* total nb of input bytes read so far */ long long total_in; /* total nb of input bytes read so far */
Bytef *next_out; /* next output byte should be put there */ Bytef *next_out; /* next output byte should be put there */
uInt avail_out; /* remaining free space at next_out */ uInt avail_out; /* remaining free space at next_out */
uLong total_out; /* total nb of bytes output so far */ long long total_out; /* total nb of bytes output so far */
char *msg; /* last error message, NULL if no error */ char *msg; /* last error message, NULL if no error */
struct internal_state FAR *state; /* not visible by applications */ struct internal_state FAR *state; /* not visible by applications */

View file

@ -78,8 +78,8 @@ class EPollArrayWrapper {
// Base address of the native pollArray // Base address of the native pollArray
private final long pollArrayAddress; private final long pollArrayAddress;
// Set of "idle" file descriptors // Set of "idle" channels
private final HashSet<Integer> idleSet; private final HashSet<SelChImpl> idleSet;
EPollArrayWrapper() { EPollArrayWrapper() {
// creates the epoll file descriptor // creates the epoll file descriptor
@ -96,19 +96,22 @@ class EPollArrayWrapper {
} }
// create idle set // create idle set
idleSet = new HashSet<Integer>(); idleSet = new HashSet<SelChImpl>();
} }
// Used to update file description registrations // Used to update file description registrations
private static class Updator { private static class Updator {
SelChImpl channel;
int opcode; int opcode;
int fd;
int events; int events;
Updator(int opcode, int fd, int events) { Updator(SelChImpl channel, int opcode, int events) {
this.channel = channel;
this.opcode = opcode; this.opcode = opcode;
this.fd = fd;
this.events = events; this.events = events;
} }
Updator(SelChImpl channel, int opcode) {
this(channel, opcode, 0);
}
} }
private LinkedList<Updator> updateList = new LinkedList<Updator>(); private LinkedList<Updator> updateList = new LinkedList<Updator>();
@ -163,60 +166,54 @@ class EPollArrayWrapper {
} }
/** /**
* Update the events for a given file descriptor. * Update the events for a given channel.
*/ */
void setInterest(int fd, int mask) { void setInterest(SelChImpl channel, int mask) {
synchronized (updateList) { synchronized (updateList) {
// if the interest events are 0 then add to idle set, and delete
// from epoll if registered (or pending)
if (mask == 0) {
if (idleSet.add(fd)) {
updateList.add(new Updator(EPOLL_CTL_DEL, fd, 0));
}
return;
}
// if file descriptor is idle then add to epoll
if (!idleSet.isEmpty() && idleSet.remove(fd)) {
updateList.add(new Updator(EPOLL_CTL_ADD, fd, mask));
return;
}
// if the previous pending operation is to add this file descriptor // if the previous pending operation is to add this file descriptor
// to epoll then update its event set // to epoll then update its event set
if (updateList.size() > 0) { if (updateList.size() > 0) {
Updator last = updateList.getLast(); Updator last = updateList.getLast();
if (last.fd == fd && last.opcode == EPOLL_CTL_ADD) { if (last.channel == channel && last.opcode == EPOLL_CTL_ADD) {
last.events = mask; last.events = mask;
return; return;
} }
} }
// update existing registration // update existing registration
updateList.add(new Updator(EPOLL_CTL_MOD, fd, mask)); updateList.add(new Updator(channel, EPOLL_CTL_MOD, mask));
} }
} }
/** /**
* Add a new file descriptor to epoll * Add a channel's file descriptor to epoll
*/ */
void add(int fd) { void add(SelChImpl channel) {
synchronized (updateList) { synchronized (updateList) {
updateList.add(new Updator(EPOLL_CTL_ADD, fd, 0)); updateList.add(new Updator(channel, EPOLL_CTL_ADD));
} }
} }
/** /**
* Remove a file descriptor from epoll * Remove a channel's file descriptor from epoll
*/ */
void release(int fd) { void release(SelChImpl channel) {
synchronized (updateList) { synchronized (updateList) {
// if file descriptor is idle then remove from idle set, otherwise // flush any pending updates
// delete from epoll int i = 0;
if (!idleSet.remove(fd)) { while (i < updateList.size()) {
updateList.add(new Updator(EPOLL_CTL_DEL, fd, 0)); if (updateList.get(i).channel == channel) {
updateList.remove(i);
} else {
i++;
}
} }
// remove from the idle set (if present)
idleSet.remove(channel);
// remove from epoll (if registered)
epollCtl(epfd, EPOLL_CTL_DEL, channel.getFDVal(), 0);
} }
} }
@ -248,7 +245,26 @@ class EPollArrayWrapper {
synchronized (updateList) { synchronized (updateList) {
Updator u = null; Updator u = null;
while ((u = updateList.poll()) != null) { while ((u = updateList.poll()) != null) {
epollCtl(epfd, u.opcode, u.fd, u.events); SelChImpl ch = u.channel;
if (!ch.isOpen())
continue;
// if the events are 0 then file descriptor is put into "idle
// set" to prevent it being polled
if (u.events == 0) {
boolean added = idleSet.add(u.channel);
// if added to idle set then remove from epoll if registered
if (added && (u.opcode == EPOLL_CTL_MOD))
epollCtl(epfd, EPOLL_CTL_DEL, ch.getFDVal(), 0);
} else {
// events are specified. If file descriptor was in idle set
// it must be re-registered (by converting opcode to ADD)
boolean idle = false;
if (!idleSet.isEmpty())
idle = idleSet.remove(u.channel);
int opcode = (idle) ? EPOLL_CTL_ADD : u.opcode;
epollCtl(epfd, opcode, ch.getFDVal(), u.events);
}
} }
} }
} }

View file

@ -139,7 +139,6 @@ class EPollSelectorImpl
FileDispatcherImpl.closeIntFD(fd0); FileDispatcherImpl.closeIntFD(fd0);
FileDispatcherImpl.closeIntFD(fd1); FileDispatcherImpl.closeIntFD(fd1);
pollWrapper.release(fd0);
pollWrapper.closeEPollFD(); pollWrapper.closeEPollFD();
// it is possible // it is possible
selectedKeys = null; selectedKeys = null;
@ -162,17 +161,18 @@ class EPollSelectorImpl
protected void implRegister(SelectionKeyImpl ski) { protected void implRegister(SelectionKeyImpl ski) {
if (closed) if (closed)
throw new ClosedSelectorException(); throw new ClosedSelectorException();
int fd = IOUtil.fdVal(ski.channel.getFD()); SelChImpl ch = ski.channel;
fdToKey.put(Integer.valueOf(fd), ski); fdToKey.put(Integer.valueOf(ch.getFDVal()), ski);
pollWrapper.add(fd); pollWrapper.add(ch);
keys.add(ski); keys.add(ski);
} }
protected void implDereg(SelectionKeyImpl ski) throws IOException { protected void implDereg(SelectionKeyImpl ski) throws IOException {
assert (ski.getIndex() >= 0); assert (ski.getIndex() >= 0);
int fd = ski.channel.getFDVal(); SelChImpl ch = ski.channel;
int fd = ch.getFDVal();
fdToKey.remove(Integer.valueOf(fd)); fdToKey.remove(Integer.valueOf(fd));
pollWrapper.release(fd); pollWrapper.release(ch);
ski.setIndex(-1); ski.setIndex(-1);
keys.remove(ski); keys.remove(ski);
selectedKeys.remove(ski); selectedKeys.remove(ski);
@ -185,8 +185,7 @@ class EPollSelectorImpl
void putEventOps(SelectionKeyImpl sk, int ops) { void putEventOps(SelectionKeyImpl sk, int ops) {
if (closed) if (closed)
throw new ClosedSelectorException(); throw new ClosedSelectorException();
int fd = IOUtil.fdVal(sk.channel.getFD()); pollWrapper.setInterest(sk.channel, ops);
pollWrapper.setInterest(fd, ops);
} }
public Selector wakeup() { public Selector wakeup() {

View file

@ -28,6 +28,7 @@
#include "jvm.h" #include "jvm.h"
#include "jlong.h" #include "jlong.h"
#include "sun_nio_ch_DevPollArrayWrapper.h" #include "sun_nio_ch_DevPollArrayWrapper.h"
#include "java_lang_Integer.h"
#include <sys/poll.h> #include <sys/poll.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <unistd.h> #include <unistd.h>
@ -192,7 +193,11 @@ Java_sun_nio_ch_DevPollArrayWrapper_fdLimit(JNIEnv *env, jclass this)
JNU_ThrowIOExceptionWithLastError(env, JNU_ThrowIOExceptionWithLastError(env,
"getrlimit failed"); "getrlimit failed");
} }
return (jint)rlp.rlim_max; if (rlp.rlim_max < 0 || rlp.rlim_max > java_lang_Integer_MAX_VALUE) {
return java_lang_Integer_MAX_VALUE;
} else {
return (jint)rlp.rlim_max;
}
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL

View file

@ -309,12 +309,13 @@ Java_java_io_WinNTFileSystem_getLastModifiedTime(JNIEnv *env, jobject this,
/* No template file */ /* No template file */
NULL); NULL);
if (h != INVALID_HANDLE_VALUE) { if (h != INVALID_HANDLE_VALUE) {
GetFileTime(h, NULL, NULL, &t); if (GetFileTime(h, NULL, NULL, &t)) {
modTime.LowPart = (DWORD) t.dwLowDateTime;
modTime.HighPart = (LONG) t.dwHighDateTime;
rv = modTime.QuadPart / 10000;
rv -= 11644473600000;
}
CloseHandle(h); CloseHandle(h);
modTime.LowPart = (DWORD) t.dwLowDateTime;
modTime.HighPart = (LONG) t.dwHighDateTime;
rv = modTime.QuadPart / 10000;
rv -= 11644473600000;
} }
free(pathbuf); free(pathbuf);
return rv; return rv;

View file

@ -717,6 +717,7 @@ GetJavaProperties(JNIEnv* env)
* Windows Vista family 6 0 * Windows Vista family 6 0
* Windows 2008 6 0 * Windows 2008 6 0
* where ((&ver.wServicePackMinor) + 2) = 1 * where ((&ver.wServicePackMinor) + 2) = 1
* Windows 7 6 1
* *
* This mapping will presumably be augmented as new Windows * This mapping will presumably be augmented as new Windows
* versions are released. * versions are released.
@ -773,13 +774,18 @@ GetJavaProperties(JNIEnv* env)
* and Windows Vista are identical, you must also test * and Windows Vista are identical, you must also test
* whether the wProductType member is VER_NT_WORKSTATION. * whether the wProductType member is VER_NT_WORKSTATION.
* If wProductType is VER_NT_WORKSTATION, the operating * If wProductType is VER_NT_WORKSTATION, the operating
* system is Windows Vista; otherwise, it is Windows * system is Windows Vista or 7; otherwise, it is Windows
* Server 2008." * Server 2008."
*/ */
if (ver.wProductType == VER_NT_WORKSTATION) if (ver.wProductType == VER_NT_WORKSTATION) {
sprops.os_name = "Windows Vista"; switch (ver.dwMinorVersion) {
else case 0: sprops.os_name = "Windows Vista"; break;
case 1: sprops.os_name = "Windows 7"; break;
default: sprops.os_name = "Windows NT (unknown)";
}
} else {
sprops.os_name = "Windows Server 2008"; sprops.os_name = "Windows Server 2008";
}
} else { } else {
sprops.os_name = "Windows NT (unknown)"; sprops.os_name = "Windows NT (unknown)";
} }

View file

@ -0,0 +1,55 @@
/*
* 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.
*
* 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.
*/
/**
* @test
* @bug 6807702
* @summary Basic test for Integer.valueOf
* @run main ValueOf
* @run main/othervm -esa -XX:+AggressiveOpts ValueOf
*/
public class ValueOf {
// test Integer.valueOf over this range (inclusive)
private static final int TEST_LOW = -1024;
private static final int TEST_HIGH = 24576;
public static void main(String[] args) {
int i = TEST_LOW;
while (i <= TEST_HIGH) {
// check that valueOf stores i
if (Integer.valueOf(i).intValue() != i)
throw new RuntimeException();
// check that the same object is returned for integral values
// in the range -128 to 127 (inclusive)
if (i >= -128 && i <= 127) {
if (Integer.valueOf(i) != Integer.valueOf(i))
throw new RuntimeException();
}
i++;
}
}
}

View file

@ -22,27 +22,110 @@
*/ */
/* @test /* @test
* @bug 4512723 * @bug 4512723 6621689
* @summary Unit test for datagram-socket-channel adaptors * @summary Test that connect/send/receive with unbound DatagramChannel causes
* the channel's socket to be bound to a local address
*/ */
import java.net.*; import java.net.*;
import java.nio.*; import java.nio.ByteBuffer;
import java.nio.channels.*; import java.nio.channels.DatagramChannel;
import java.io.IOException;
class NotBound { public class NotBound {
public static void main(String[] args) throws Exception {
test1(false); static void checkBound(DatagramChannel dc) throws IOException {
test1(true); if (dc.getLocalAddress() == null)
throw new RuntimeException("Not bound??");
} }
static void test1(boolean blocking) throws Exception { // starts a thread to send a datagram to the given channel once the channel
ByteBuffer bb = ByteBuffer.allocateDirect(256); // is bound to a local address
DatagramChannel dc1 = DatagramChannel.open(); static void wakeupWhenBound(final DatagramChannel dc) {
dc1.configureBlocking(false); Runnable wakeupTask = new Runnable() {
SocketAddress isa = dc1.receive(bb); public void run() {
if (isa != null) try {
throw new Exception("Unbound dc returned non-null"); // poll for local address
dc1.close(); InetSocketAddress local;
do {
Thread.sleep(50);
local = (InetSocketAddress)dc.getLocalAddress();
} while (local == null);
// send message to channel to wakeup receiver
DatagramChannel sender = DatagramChannel.open();
try {
ByteBuffer bb = ByteBuffer.wrap("hello".getBytes());
InetAddress lh = InetAddress.getLocalHost();
SocketAddress target =
new InetSocketAddress(lh, local.getPort());
sender.send(bb, target);
} finally {
sender.close();
}
} catch (Exception x) {
x.printStackTrace();
}
}};
new Thread(wakeupTask).start();
}
public static void main(String[] args) throws IOException {
DatagramChannel dc;
// connect
dc = DatagramChannel.open();
try {
DatagramChannel peer = DatagramChannel.open()
.bind(new InetSocketAddress(0));
int peerPort = ((InetSocketAddress)(peer.getLocalAddress())).getPort();
try {
dc.connect(new InetSocketAddress(InetAddress.getLocalHost(), peerPort));
checkBound(dc);
} finally {
peer.close();
}
} finally {
dc.close();
}
// send
dc = DatagramChannel.open();
try {
ByteBuffer bb = ByteBuffer.wrap("ignore this".getBytes());
SocketAddress target =
new InetSocketAddress(InetAddress.getLocalHost(), 5000);
dc.send(bb, target);
checkBound(dc);
} finally {
dc.close();
}
// receive (blocking)
dc = DatagramChannel.open();
try {
ByteBuffer bb = ByteBuffer.allocateDirect(128);
wakeupWhenBound(dc);
SocketAddress sender = dc.receive(bb);
if (sender == null)
throw new RuntimeException("Sender should not be null");
checkBound(dc);
} finally {
dc.close();
}
// receive (non-blocking)
dc = DatagramChannel.open();
try {
dc.configureBlocking(false);
ByteBuffer bb = ByteBuffer.allocateDirect(128);
SocketAddress sender = dc.receive(bb);
if (sender != null)
throw new RuntimeException("Sender should be null");
checkBound(dc);
} finally {
dc.close();
}
} }
} }

View file

@ -0,0 +1,127 @@
/*
* 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.
*
* 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.
*/
/* @test
* @bug 6693490
* @summary Pre-close file descriptor may inadvertently get registered with
* epoll during close
*/
import java.net.*;
import java.nio.channels.*;
import java.util.concurrent.*;
import java.util.*;
import java.io.IOException;
public class RegAfterPreClose {
static volatile boolean done;
/**
* A task that continuously connects to a given address and immediately
* closes the connection.
*/
static class Connector implements Runnable {
private final SocketAddress sa;
Connector(int port) throws IOException {
InetAddress lh = InetAddress.getLocalHost();
this.sa = new InetSocketAddress(lh, port);
}
public void run() {
while (!done) {
try {
SocketChannel.open(sa).close();
} catch (IOException x) {
// back-off as probably resource related
try {
Thread.sleep(10);
} catch (InterruptedException ignore) { }
}
}
}
}
/**
* A task that closes a channel.
*/
static class Closer implements Runnable {
private final Channel channel;
Closer(Channel sc) {
this.channel = sc;
}
public void run() {
try {
channel.close();
} catch (IOException ignore) { }
}
}
public static void main(String[] args) throws Exception {
// create listener
InetSocketAddress isa = new InetSocketAddress(0);
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.socket().bind(isa);
// register with Selector
final Selector sel = Selector.open();
ssc.configureBlocking(false);
SelectionKey key = ssc.register(sel, SelectionKey.OP_ACCEPT);
ThreadFactory factory = new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
};
// schedule test to run for 1 minute
Executors.newScheduledThreadPool(1, factory).schedule(new Runnable() {
public void run() {
done = true;
sel.wakeup();
}}, 1, TimeUnit.MINUTES);
// create Executor that handles tasks that closes channels
// "asynchronously" - this creates the conditions to provoke the bug.
Executor executor = Executors.newFixedThreadPool(2, factory);
// submit task that connects to listener
executor.execute(new Connector(ssc.socket().getLocalPort()));
// loop accepting connections until done (or an IOException is thrown)
while (!done) {
sel.select();
if (key.isAcceptable()) {
SocketChannel sc = ssc.accept();
if (sc != null) {
sc.configureBlocking(false);
sc.register(sel, SelectionKey.OP_READ);
executor.execute(new Closer(sc));
}
}
sel.selectedKeys().clear();
}
}
}

View file

@ -555,6 +555,7 @@ public class MOAT {
NavigableMap<Integer,Integer> nm = NavigableMap<Integer,Integer> nm =
(NavigableMap<Integer,Integer>) m; (NavigableMap<Integer,Integer>) m;
testNavigableMapRemovers(nm);
testNavigableMap(nm); testNavigableMap(nm);
testNavigableMap(nm.headMap(6, false)); testNavigableMap(nm.headMap(6, false));
testNavigableMap(nm.headMap(5, true)); testNavigableMap(nm.headMap(5, true));
@ -742,6 +743,97 @@ public class MOAT {
equal(it.next(), expected); equal(it.next(), expected);
} }
static void equalMaps(Map m1, Map m2) {
equal(m1, m2);
equal(m2, m1);
equal(m1.size(), m2.size());
equal(m1.isEmpty(), m2.isEmpty());
equal(m1.toString(), m2.toString());
check(Arrays.equals(m1.entrySet().toArray(), m2.entrySet().toArray()));
}
@SuppressWarnings({"unchecked", "rawtypes"})
static void testNavigableMapRemovers(NavigableMap m)
{
final Map emptyMap = new HashMap();
final Map singletonMap = new HashMap();
singletonMap.put(1, 2);
abstract class NavigableMapView {
abstract NavigableMap view(NavigableMap m);
}
NavigableMapView[] views = {
new NavigableMapView() { NavigableMap view(NavigableMap m) {
return m; }},
new NavigableMapView() { NavigableMap view(NavigableMap m) {
return m.headMap(99, true); }},
new NavigableMapView() { NavigableMap view(NavigableMap m) {
return m.tailMap(-99, false); }},
new NavigableMapView() { NavigableMap view(NavigableMap m) {
return m.subMap(-99, true, 99, false); }},
};
abstract class Remover {
abstract void remove(NavigableMap m, Object k, Object v);
}
Remover[] removers = {
new Remover() { void remove(NavigableMap m, Object k, Object v) {
equal(m.remove(k), v); }},
new Remover() { void remove(NavigableMap m, Object k, Object v) {
equal(m.descendingMap().remove(k), v); }},
new Remover() { void remove(NavigableMap m, Object k, Object v) {
equal(m.descendingMap().headMap(-86, false).remove(k), v); }},
new Remover() { void remove(NavigableMap m, Object k, Object v) {
equal(m.descendingMap().tailMap(86, true).remove(k), v); }},
new Remover() { void remove(NavigableMap m, Object k, Object v) {
equal(m.headMap(86, true).remove(k), v); }},
new Remover() { void remove(NavigableMap m, Object k, Object v) {
equal(m.tailMap(-86, true).remove(k), v); }},
new Remover() { void remove(NavigableMap m, Object k, Object v) {
equal(m.subMap(-86, false, 86, true).remove(k), v); }},
new Remover() { void remove(NavigableMap m, Object k, Object v) {
check(m.keySet().remove(k)); }},
new Remover() { void remove(NavigableMap m, Object k, Object v) {
check(m.navigableKeySet().remove(k)); }},
new Remover() { void remove(NavigableMap m, Object k, Object v) {
check(m.navigableKeySet().headSet(86, true).remove(k)); }},
new Remover() { void remove(NavigableMap m, Object k, Object v) {
check(m.navigableKeySet().tailSet(-86, false).remove(k)); }},
new Remover() { void remove(NavigableMap m, Object k, Object v) {
check(m.navigableKeySet().subSet(-86, true, 86, false)
.remove(k)); }},
new Remover() { void remove(NavigableMap m, Object k, Object v) {
check(m.descendingKeySet().headSet(-86, false).remove(k)); }},
new Remover() { void remove(NavigableMap m, Object k, Object v) {
check(m.descendingKeySet().tailSet(86, true).remove(k)); }},
new Remover() { void remove(NavigableMap m, Object k, Object v) {
check(m.descendingKeySet().subSet(86, true, -86, false)
.remove(k)); }},
};
for (NavigableMapView view : views) {
for (Remover remover : removers) {
try {
m.clear();
equalMaps(m, emptyMap);
equal(m.put(1, 2), null);
equalMaps(m, singletonMap);
NavigableMap v = view.view(m);
remover.remove(v, 1, 2);
equalMaps(m, emptyMap);
} catch (Throwable t) { unexpected(t); }
}
}
}
private static void testNavigableMap(NavigableMap<Integer,Integer> m) private static void testNavigableMap(NavigableMap<Integer,Integer> m)
{ {
clear(m); clear(m);

View file

@ -0,0 +1,116 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact 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.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/licenses/publicdomain
*/
/*
* @test
* @bug 6801020 6803402
* @summary Try to tickle race conditions in
* AbstractQueuedSynchronizer "shared" code
*/
import java.util.concurrent.Semaphore;
public class RacingReleases {
/** Increase this for better chance of tickling races */
static final int iterations = 1000;
public static void test(final boolean fair,
final boolean interruptibly)
throws Throwable {
for (int i = 0; i < iterations; i++) {
final Semaphore sem = new Semaphore(0, fair);
final Throwable[] badness = new Throwable[1];
Runnable blocker = interruptibly ?
new Runnable() {
public void run() {
try {
sem.acquire();
} catch (Throwable t) {
badness[0] = t;
throw new Error(t);
}}}
:
new Runnable() {
public void run() {
try {
sem.acquireUninterruptibly();
} catch (Throwable t) {
badness[0] = t;
throw new Error(t);
}}};
Thread b1 = new Thread(blocker);
Thread b2 = new Thread(blocker);
Runnable signaller = new Runnable() {
public void run() {
try {
sem.release();
} catch (Throwable t) {
badness[0] = t;
throw new Error(t);
}}};
Thread s1 = new Thread(signaller);
Thread s2 = new Thread(signaller);
Thread[] threads = { b1, b2, s1, s2 };
java.util.Collections.shuffle(java.util.Arrays.asList(threads));
for (Thread thread : threads)
thread.start();
for (Thread thread : threads) {
thread.join(60 * 1000);
if (thread.isAlive())
throw new Error
(String.format
("Semaphore stuck: permits %d, thread waiting %s%n",
sem.availablePermits(),
sem.hasQueuedThreads() ? "true" : "false"));
}
if (badness[0] != null)
throw new Error(badness[0]);
if (sem.availablePermits() != 0)
throw new Error(String.valueOf(sem.availablePermits()));
if (sem.hasQueuedThreads())
throw new Error(String.valueOf(sem.hasQueuedThreads()));
if (sem.getQueueLength() != 0)
throw new Error(String.valueOf(sem.getQueueLength()));
if (sem.isFair() != fair)
throw new Error(String.valueOf(sem.isFair()));
}
}
public static void main(String[] args) throws Throwable {
for (boolean fair : new boolean[] { true, false })
for (boolean interruptibly : new boolean[] { true, false })
test(fair, interruptibly);
}
}

View file

@ -0,0 +1,193 @@
/*
* 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.
*/
import java.io.*;
import java.nio.*;
import java.util.*;
import java.util.zip.*;
public class LargeZip {
// If true, don't delete large ZIP file created for test.
static final boolean debug = System.getProperty("debug") != null;
//static final int DATA_LEN = 1024 * 1024;
static final int DATA_LEN = 80 * 1024;
static final int DATA_SIZE = 8;
static long fileSize = 6L * 1024L * 1024L * 1024L; // 6GB
static boolean userFile = false;
static byte[] data;
static File largeFile;
static String lastEntryName;
/* args can be empty, in which case check a 3 GB file which is created for
* this test (and then deleted). Or it can be a number, in which case
* that designates the size of the file that's created for this test (and
* then deleted). Or it can be the name of a file to use for the test, in
* which case it is *not* deleted. Note that in this last case, the data
* comparison might fail.
*/
static void realMain (String[] args) throws Throwable {
if (args.length > 0) {
try {
fileSize = Long.parseLong(args[0]);
System.out.println("Testing with file of size " + fileSize);
} catch (NumberFormatException ex) {
largeFile = new File(args[0]);
if (!largeFile.exists()) {
throw new Exception("Specified file " + args[0] + " does not exist");
}
userFile = true;
System.out.println("Testing with user-provided file " + largeFile);
}
}
File testDir = null;
if (largeFile == null) {
testDir = new File(System.getProperty("test.scratch", "."),
"LargeZip");
if (testDir.exists()) {
if (!testDir.delete()) {
throw new Exception("Cannot delete already-existing test directory");
}
}
check(!testDir.exists() && testDir.mkdirs());
largeFile = new File(testDir, "largezip.zip");
createLargeZip();
}
readLargeZip1();
readLargeZip2();
if (!userFile && !debug) {
check(largeFile.delete());
check(testDir.delete());
}
}
static void createLargeZip() throws Throwable {
int iterations = DATA_LEN / DATA_SIZE;
ByteBuffer bb = ByteBuffer.allocate(DATA_SIZE);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (int i = 0; i < iterations; i++) {
bb.putDouble(0, Math.random());
baos.write(bb.array(), 0, DATA_SIZE);
}
data = baos.toByteArray();
ZipOutputStream zos = new ZipOutputStream(
new BufferedOutputStream(new FileOutputStream(largeFile)));
long length = 0;
while (length < fileSize) {
ZipEntry ze = new ZipEntry("entry-" + length);
lastEntryName = ze.getName();
zos.putNextEntry(ze);
zos.write(data, 0, data.length);
zos.closeEntry();
length = largeFile.length();
}
System.out.println("Last entry written is " + lastEntryName);
zos.close();
}
static void readLargeZip1() throws Throwable {
ZipFile zipFile = new ZipFile(largeFile);
ZipEntry entry = null;
String entryName = null;
int count = 0;
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
entry = entries.nextElement();
entryName = entry.getName();
count++;
}
System.out.println("Number of entries read: " + count);
System.out.println("Last entry read is " + entryName);
check(!entry.isDirectory());
if (check(entryName.equals(lastEntryName))) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = zipFile.getInputStream(entry);
byte buf[] = new byte[4096];
int len;
while ((len = is.read(buf)) >= 0) {
baos.write(buf, 0, len);
}
baos.close();
is.close();
check(Arrays.equals(data, baos.toByteArray()));
}
}
static void readLargeZip2() throws Throwable {
ZipInputStream zis = new ZipInputStream(
new BufferedInputStream(new FileInputStream(largeFile)));
ZipEntry entry = null;
String entryName = null;
int count = 0;
while ((entry = zis.getNextEntry()) != null) {
entryName = entry.getName();
if (entryName.equals(lastEntryName)) {
break;
}
count++;
}
System.out.println("Number of entries read: " + count);
System.out.println("Last entry read is " + entryName);
check(!entry.isDirectory());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte buf[] = new byte[4096];
int len;
while ((len = zis.read(buf)) >= 0) {
baos.write(buf, 0, len);
}
baos.close();
check(Arrays.equals(data, baos.toByteArray()));
check(zis.getNextEntry() == null);
zis.close();
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static void pass() {passed++;}
static void pass(String msg) {System.out.println(msg); passed++;}
static void fail() {failed++; Thread.dumpStack();}
static void fail(String msg) {System.out.println(msg); fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static void unexpected(Throwable t, String msg) {
System.out.println(msg); failed++; t.printStackTrace();}
static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.println("\nPassed = " + passed + " failed = " + failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -158,4 +158,3 @@ public class LargeZipFile {
System.out.println("\nPassed = " + passed + " failed = " + failed); System.out.println("\nPassed = " + passed + " failed = " + failed);
if (failed > 0) throw new AssertionError("Some tests failed");} if (failed > 0) throw new AssertionError("Some tests failed");}
} }

View file

@ -0,0 +1,200 @@
#
# 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.
#
# 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.
#
# @test
# @bug 6802846
# @summary jarsigner needs enhanced cert validation(options)
#
# @run shell concise_jarsigner.sh
#
if [ "${TESTJAVA}" = "" ] ; then
JAVAC_CMD=`which javac`
TESTJAVA=`dirname $JAVAC_CMD`/..
fi
# set platform-dependent variables
OS=`uname -s`
case "$OS" in
Windows_* )
FS="\\"
;;
* )
FS="/"
;;
esac
KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit -keystore js.jks"
JAR=$TESTJAVA${FS}bin${FS}jar
JARSIGNER=$TESTJAVA${FS}bin${FS}jarsigner
JAVAC=$TESTJAVA${FS}bin${FS}javac
rm js.jks
echo class A1 {} > A1.java
echo class A2 {} > A2.java
echo class A3 {} > A3.java
echo class A4 {} > A4.java
echo class A5 {} > A5.java
echo class A6 {} > A6.java
$JAVAC A1.java A2.java A3.java A4.java A5.java A6.java
YEAR=`date +%Y`
# ==========================================================
# First part: output format
# ==========================================================
$KT -genkeypair -alias a1 -dname CN=a1 -validity 365
$KT -genkeypair -alias a2 -dname CN=a2 -validity 365
# a.jar includes 8 unsigned, 2 signed by a1 and a2, 2 signed by a3
$JAR cvf a.jar A1.class A2.class
$JARSIGNER -keystore js.jks -storepass changeit a.jar a1
$JAR uvf a.jar A3.class A4.class
$JARSIGNER -keystore js.jks -storepass changeit a.jar a2
$JAR uvf a.jar A5.class A6.class
# Verify OK
$JARSIGNER -verify a.jar
[ $? = 0 ] || exit $LINENO
# 4(chainNotValidated)+16(hasUnsignedEntry)+32(aliasNotInStore)
$JARSIGNER -verify a.jar -strict
[ $? = 52 ] || exit $LINENO
# 16(hasUnsignedEntry)
$JARSIGNER -verify a.jar -strict -keystore js.jks
[ $? = 16 ] || exit $LINENO
# 16(hasUnsignedEntry)+32(notSignedByAlias)
$JARSIGNER -verify a.jar a1 -strict -keystore js.jks
[ $? = 48 ] || exit $LINENO
# 16(hasUnsignedEntry)
$JARSIGNER -verify a.jar a1 a2 -strict -keystore js.jks
[ $? = 16 ] || exit $LINENO
# 12 entries all together
LINES=`$JARSIGNER -verify a.jar -verbose | grep $YEAR | wc -l`
[ $LINES = 12 ] || exit $LINENO
# 12 entries all listed
LINES=`$JARSIGNER -verify a.jar -verbose:grouped | grep $YEAR | wc -l`
[ $LINES = 12 ] || exit $LINENO
# 3 groups: unrelated, signed, unsigned
LINES=`$JARSIGNER -verify a.jar -verbose:summary | grep $YEAR | wc -l`
[ $LINES = 3 ] || exit $LINENO
# 4 groups: unrelated, signed by a1/a2, signed by a2, unsigned
LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep $YEAR | wc -l`
[ $LINES = 4 ] || exit $LINENO
# 2*2 for A1/A2, 2 for A3/A4
LINES=`$JARSIGNER -verify a.jar -verbose -certs | grep "\[certificate" | wc -l`
[ $LINES = 6 ] || exit $LINENO
# a1,a2 for A1/A2, a2 for A3/A4
LINES=`$JARSIGNER -verify a.jar -verbose:grouped -certs | grep "\[certificate" | wc -l`
[ $LINES = 3 ] || exit $LINENO
# a1,a2 for A1/A2, a2 for A3/A4
LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep "\[certificate" | wc -l`
[ $LINES = 3 ] || exit $LINENO
# 4 groups
LINES=`$JARSIGNER -verify a.jar -verbose:summary -certs | grep "more)" | wc -l`
[ $LINES = 4 ] || exit $LINENO
# ==========================================================
# Second part: exit code 2, 4, 8
# 16 and 32 already covered in the first part
# ==========================================================
$KT -genkeypair -alias expiring -dname CN=expiring -startdate -1m
$KT -genkeypair -alias expired -dname CN=expired -startdate -10m
$KT -genkeypair -alias notyetvalid -dname CN=notyetvalid -startdate +1m
$KT -genkeypair -alias badku -dname CN=badku -ext KU=cRLSign -validity 365
$KT -genkeypair -alias badeku -dname CN=badeku -ext EKU=sa -validity 365
$KT -genkeypair -alias goodku -dname CN=goodku -ext KU=dig -validity 365
$KT -genkeypair -alias goodeku -dname CN=goodeku -ext EKU=codesign -validity 365
# badchain signed by ca, but ca is removed later
$KT -genkeypair -alias badchain -dname CN=badchain -validity 365
$KT -genkeypair -alias ca -dname CN=ca -ext bc -validity 365
$KT -certreq -alias badchain | $KT -gencert -alias ca -validity 365 | \
$KT -importcert -alias badchain
$KT -delete -alias ca
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar expiring
[ $? = 2 ] || exit $LINENO
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar expired
[ $? = 4 ] || exit $LINENO
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar notyetvalid
[ $? = 4 ] || exit $LINENO
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar badku
[ $? = 8 ] || exit $LINENO
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar badeku
[ $? = 8 ] || exit $LINENO
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar goodku
[ $? = 0 ] || exit $LINENO
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar goodeku
[ $? = 0 ] || exit $LINENO
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar badchain
[ $? = 4 ] || exit $LINENO
$JARSIGNER -verify a.jar
[ $? = 0 ] || exit $LINENO
# ==========================================================
# Third part: -certchain test
# ==========================================================
# altchain signed by ca2, but ca2 is removed later
$KT -genkeypair -alias altchain -dname CN=altchain -validity 365
$KT -genkeypair -alias ca2 -dname CN=ca2 -ext bc -validity 365
$KT -certreq -alias altchain | $KT -gencert -alias ca2 -validity 365 -rfc > certchain
$KT -exportcert -alias ca2 -rfc >> certchain
$KT -delete -alias ca2
# Now altchain is still self-signed
$JARSIGNER -strict -keystore js.jks -storepass changeit a.jar altchain
[ $? = 0 ] || exit $LINENO
# If -certchain is used, then it's bad
$JARSIGNER -strict -keystore js.jks -storepass changeit -certchain certchain a.jar altchain
[ $? = 4 ] || exit $LINENO
$JARSIGNER -verify a.jar
[ $? = 0 ] || exit $LINENO
echo OK
exit 0

View file

@ -0,0 +1,69 @@
#
# 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.
#
# 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.
#
# @test
# @bug 6825352
# @summary support self-issued certificate in keytool
#
# @run shell selfissued.sh
#
if [ "${TESTJAVA}" = "" ] ; then
JAVAC_CMD=`which javac`
TESTJAVA=`dirname $JAVAC_CMD`/..
fi
# set platform-dependent variables
OS=`uname -s`
case "$OS" in
Windows_* )
FS="\\"
;;
* )
FS="/"
;;
esac
KS=selfsigned.jks
KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit -keystore $KS"
rm $KS
$KT -alias ca -dname CN=CA -genkeypair
$KT -alias me -dname CN=CA -genkeypair
$KT -alias e1 -dname CN=E1 -genkeypair
$KT -alias e2 -dname CN=E2 -genkeypair
# me signed by ca, self-issued
$KT -alias me -certreq | $KT -alias ca -gencert | $KT -alias me -importcert
# Import e1 signed by me, should add me and ca
$KT -alias e1 -certreq | $KT -alias me -gencert | $KT -alias e1 -importcert
$KT -alias e1 -list -v | grep '\[3\]' || { echo Bad E1; exit 1; }
# Import (e2 signed by me,ca,me), should reorder to (e2,me,ca)
( $KT -alias e2 -certreq | $KT -alias me -gencert; $KT -exportcert -alias ca; $KT -exportcert -alias me ) | $KT -alias e2 -importcert
$KT -alias e2 -list -v | grep '\[3\]' || { echo Bad E2; exit 1; }
echo Good