Skip to content

Commit 196c20c

Browse files
author
Xueming Shen
committed
8034802: (zipfs) newFileSystem throws UOE when the zip file is located in a custom file system
Reviewed-by: xiaofeya, clanger
1 parent 9ed646a commit 196c20c

File tree

4 files changed

+753
-345
lines changed

4 files changed

+753
-345
lines changed
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
/*
2+
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package jdk.nio.zipfs;
27+
28+
import java.io.IOException;
29+
import java.nio.ByteBuffer;
30+
import java.nio.channels.ClosedChannelException;
31+
import java.nio.channels.NonWritableChannelException;
32+
import java.nio.channels.SeekableByteChannel;
33+
import java.util.Arrays;
34+
import java.util.concurrent.locks.ReadWriteLock;
35+
import java.util.concurrent.locks.ReentrantReadWriteLock;
36+
37+
public class ByteArrayChannel implements SeekableByteChannel {
38+
39+
private final ReadWriteLock rwlock = new ReentrantReadWriteLock();
40+
private byte buf[];
41+
42+
/*
43+
* The current position of this channel.
44+
*/
45+
private int pos;
46+
47+
/*
48+
* The index that is one greater than the last valid byte in the channel.
49+
*/
50+
private int last;
51+
52+
private boolean closed;
53+
private boolean readonly;
54+
55+
/*
56+
* Creates a {@code ByteArrayChannel} with size {@code sz}.
57+
*/
58+
ByteArrayChannel(int sz, boolean readonly) {
59+
this.buf = new byte[sz];
60+
this.pos = this.last = 0;
61+
this.readonly = readonly;
62+
}
63+
64+
/*
65+
* Creates a ByteArrayChannel with its 'pos' at 0 and its 'last' at buf's end.
66+
* Note: no defensive copy of the 'buf', used directly.
67+
*/
68+
ByteArrayChannel(byte[] buf, boolean readonly) {
69+
this.buf = buf;
70+
this.pos = 0;
71+
this.last = buf.length;
72+
this.readonly = readonly;
73+
}
74+
75+
@Override
76+
public boolean isOpen() {
77+
return !closed;
78+
}
79+
80+
@Override
81+
public long position() throws IOException {
82+
beginRead();
83+
try {
84+
ensureOpen();
85+
return pos;
86+
} finally {
87+
endRead();
88+
}
89+
}
90+
91+
@Override
92+
public SeekableByteChannel position(long pos) throws IOException {
93+
beginWrite();
94+
try {
95+
ensureOpen();
96+
if (pos < 0 || pos >= Integer.MAX_VALUE)
97+
throw new IllegalArgumentException("Illegal position " + pos);
98+
this.pos = Math.min((int)pos, last);
99+
return this;
100+
} finally {
101+
endWrite();
102+
}
103+
}
104+
105+
@Override
106+
public int read(ByteBuffer dst) throws IOException {
107+
beginWrite();
108+
try {
109+
ensureOpen();
110+
if (pos == last)
111+
return -1;
112+
int n = Math.min(dst.remaining(), last - pos);
113+
dst.put(buf, pos, n);
114+
pos += n;
115+
return n;
116+
} finally {
117+
endWrite();
118+
}
119+
}
120+
121+
@Override
122+
public SeekableByteChannel truncate(long size) throws IOException {
123+
if (readonly)
124+
throw new NonWritableChannelException();
125+
ensureOpen();
126+
throw new UnsupportedOperationException();
127+
}
128+
129+
@Override
130+
public int write(ByteBuffer src) throws IOException {
131+
if (readonly)
132+
throw new NonWritableChannelException();
133+
beginWrite();
134+
try {
135+
ensureOpen();
136+
int n = src.remaining();
137+
ensureCapacity(pos + n);
138+
src.get(buf, pos, n);
139+
pos += n;
140+
if (pos > last) {
141+
last = pos;
142+
}
143+
return n;
144+
} finally {
145+
endWrite();
146+
}
147+
}
148+
149+
@Override
150+
public long size() throws IOException {
151+
beginRead();
152+
try {
153+
ensureOpen();
154+
return last;
155+
} finally {
156+
endRead();
157+
}
158+
}
159+
160+
@Override
161+
public void close() throws IOException {
162+
if (closed)
163+
return;
164+
beginWrite();
165+
try {
166+
closed = true;
167+
buf = null;
168+
pos = 0;
169+
last = 0;
170+
} finally {
171+
endWrite();
172+
}
173+
}
174+
175+
/**
176+
* Creates a newly allocated byte array. Its size is the current
177+
* size of this channel and the valid contents of the buffer
178+
* have been copied into it.
179+
*
180+
* @return the current contents of this channel, as a byte array.
181+
*/
182+
public byte[] toByteArray() {
183+
beginRead();
184+
try {
185+
// avoid copy if last == bytes.length?
186+
return Arrays.copyOf(buf, last);
187+
} finally {
188+
endRead();
189+
}
190+
}
191+
192+
private void ensureOpen() throws IOException {
193+
if (closed)
194+
throw new ClosedChannelException();
195+
}
196+
197+
private final void beginWrite() {
198+
rwlock.writeLock().lock();
199+
}
200+
201+
private final void endWrite() {
202+
rwlock.writeLock().unlock();
203+
}
204+
205+
private final void beginRead() {
206+
rwlock.readLock().lock();
207+
}
208+
209+
private final void endRead() {
210+
rwlock.readLock().unlock();
211+
}
212+
213+
private void ensureCapacity(int minCapacity) {
214+
// overflow-conscious code
215+
if (minCapacity - buf.length > 0) {
216+
grow(minCapacity);
217+
}
218+
}
219+
220+
/**
221+
* The maximum size of array to allocate.
222+
* Some VMs reserve some header words in an array.
223+
* Attempts to allocate larger arrays may result in
224+
* OutOfMemoryError: Requested array size exceeds VM limit
225+
*/
226+
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
227+
228+
/**
229+
* Increases the capacity to ensure that it can hold at least the
230+
* number of elements specified by the minimum capacity argument.
231+
*
232+
* @param minCapacity the desired minimum capacity
233+
*/
234+
private void grow(int minCapacity) {
235+
// overflow-conscious code
236+
int oldCapacity = buf.length;
237+
int newCapacity = oldCapacity << 1;
238+
if (newCapacity - minCapacity < 0)
239+
newCapacity = minCapacity;
240+
if (newCapacity - MAX_ARRAY_SIZE > 0)
241+
newCapacity = hugeCapacity(minCapacity);
242+
buf = Arrays.copyOf(buf, newCapacity);
243+
}
244+
245+
private static int hugeCapacity(int minCapacity) {
246+
if (minCapacity < 0) // overflow
247+
throw new OutOfMemoryError();
248+
return (minCapacity > MAX_ARRAY_SIZE) ?
249+
Integer.MAX_VALUE :
250+
MAX_ARRAY_SIZE;
251+
}
252+
}

0 commit comments

Comments
 (0)