8316391: (zipfs) ZipFileSystem.readFullyAt does not tolerate short reads
Reviewed-by: jpai, lancea
This commit is contained in:
parent
4b8f5d031a
commit
f44032969f
@ -1224,23 +1224,34 @@ class ZipFileSystem extends FileSystem {
|
||||
close();
|
||||
}
|
||||
|
||||
// Reads len bytes of data from the specified offset into buf.
|
||||
// Returns the total number of bytes read.
|
||||
// Each/every byte read from here (except the cen, which is mapped).
|
||||
final long readFullyAt(byte[] buf, int off, long len, long pos)
|
||||
throws IOException
|
||||
{
|
||||
/**
|
||||
* Reads len bytes of data at the given file position into the given byte array
|
||||
* starting at the given array offset. The method blocks until len bytes have been
|
||||
* read, end of stream is detected, or an exception is thrown. Returns the total
|
||||
* number of bytes read.
|
||||
*/
|
||||
final long readNBytesAt(byte[] buf, int off, long len, long pos) throws IOException {
|
||||
ByteBuffer bb = ByteBuffer.wrap(buf);
|
||||
bb.position(off);
|
||||
bb.limit((int)(off + len));
|
||||
return readFullyAt(bb, pos);
|
||||
|
||||
long totalRead = 0;
|
||||
while (totalRead < len) {
|
||||
int n = readAt(bb, pos);
|
||||
if (n < 0) {
|
||||
break;
|
||||
}
|
||||
pos += n;
|
||||
totalRead +=n;
|
||||
}
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
private long readFullyAt(ByteBuffer bb, long pos) throws IOException {
|
||||
if (ch instanceof FileChannel fch) {
|
||||
return fch.read(bb, pos);
|
||||
private int readAt(ByteBuffer bb, long pos) throws IOException {
|
||||
if (ch instanceof FileChannel fc) {
|
||||
return fc.read(bb, pos);
|
||||
} else {
|
||||
synchronized(ch) {
|
||||
synchronized (ch) {
|
||||
return ch.position(pos).read(bb);
|
||||
}
|
||||
}
|
||||
@ -1264,7 +1275,7 @@ class ZipFileSystem extends FileSystem {
|
||||
Arrays.fill(buf, 0, off, (byte)0);
|
||||
}
|
||||
int len = buf.length - off;
|
||||
if (readFullyAt(buf, off, len, pos + off) != len)
|
||||
if (readNBytesAt(buf, off, len, pos + off) != len)
|
||||
throw new ZipException("zip END header not found");
|
||||
|
||||
// Now scan the block backwards for END header signature
|
||||
@ -1286,14 +1297,14 @@ class ZipFileSystem extends FileSystem {
|
||||
// try if there is zip64 end;
|
||||
byte[] loc64 = new byte[ZIP64_LOCHDR];
|
||||
if (end.endpos < ZIP64_LOCHDR ||
|
||||
readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR)
|
||||
readNBytesAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR)
|
||||
!= loc64.length ||
|
||||
!locator64SigAt(loc64, 0)) {
|
||||
return end;
|
||||
}
|
||||
long end64pos = ZIP64_LOCOFF(loc64);
|
||||
byte[] end64buf = new byte[ZIP64_ENDHDR];
|
||||
if (readFullyAt(end64buf, 0, end64buf.length, end64pos)
|
||||
if (readNBytesAt(end64buf, 0, end64buf.length, end64pos)
|
||||
!= end64buf.length ||
|
||||
!end64SigAt(end64buf, 0)) {
|
||||
return end;
|
||||
@ -1557,7 +1568,7 @@ class ZipFileSystem extends FileSystem {
|
||||
|
||||
// read in the CEN and END
|
||||
byte[] cen = new byte[(int)(end.cenlen + ENDHDR)];
|
||||
if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) {
|
||||
if (readNBytesAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) {
|
||||
throw new ZipException("read CEN tables failed");
|
||||
}
|
||||
// Iterate through the entries in the central directory
|
||||
@ -1706,7 +1717,7 @@ class ZipFileSystem extends FileSystem {
|
||||
// 'name' field of the loc. if this byte is '/', which means the original
|
||||
// entry has an absolute path in original zip/jar file, the e.writeLOC()
|
||||
// is used to output the loc, in which the leading "/" will be removed
|
||||
if (readFullyAt(buf, 0, LOCHDR + 1 , locoff) != LOCHDR + 1)
|
||||
if (readNBytesAt(buf, 0, LOCHDR + 1 , locoff) != LOCHDR + 1)
|
||||
throw new ZipException("loc: reading failed");
|
||||
|
||||
if (updateHeader || LOCNAM(buf) > 0 && buf[LOCHDR] == '/') {
|
||||
@ -1723,7 +1734,7 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
int n;
|
||||
while (size > 0 &&
|
||||
(n = (int)readFullyAt(buf, 0, buf.length, locoff)) != -1)
|
||||
(n = (int)readNBytesAt(buf, 0, buf.length, locoff)) != -1)
|
||||
{
|
||||
if (size < n)
|
||||
n = (int)size;
|
||||
@ -2338,7 +2349,7 @@ class ZipFileSystem extends FileSystem {
|
||||
ByteBuffer bb = ByteBuffer.wrap(b);
|
||||
bb.position(off);
|
||||
bb.limit(off + len);
|
||||
long n = readFullyAt(bb, pos);
|
||||
long n = readAt(bb, pos);
|
||||
if (n > 0) {
|
||||
pos += n;
|
||||
rem -= n;
|
||||
@ -2383,7 +2394,7 @@ class ZipFileSystem extends FileSystem {
|
||||
if (pos <= 0) {
|
||||
pos = -pos + locpos;
|
||||
byte[] buf = new byte[LOCHDR];
|
||||
if (readFullyAt(buf, 0, buf.length, pos) != LOCHDR) {
|
||||
if (readNBytesAt(buf, 0, buf.length, pos) != LOCHDR) {
|
||||
throw new ZipException("invalid loc " + pos + " for entry reading");
|
||||
}
|
||||
pos += LOCHDR + LOCNAM(buf) + LOCEXT(buf);
|
||||
@ -3224,7 +3235,7 @@ class ZipFileSystem extends FileSystem {
|
||||
*/
|
||||
private void readLocEXTT(ZipFileSystem zipfs) throws IOException {
|
||||
byte[] buf = new byte[LOCHDR];
|
||||
if (zipfs.readFullyAt(buf, 0, buf.length , locoff)
|
||||
if (zipfs.readNBytesAt(buf, 0, buf.length , locoff)
|
||||
!= buf.length)
|
||||
throw new ZipException("loc: reading failed");
|
||||
if (!locSigAt(buf, 0))
|
||||
@ -3235,7 +3246,7 @@ class ZipFileSystem extends FileSystem {
|
||||
return;
|
||||
int locNlen = LOCNAM(buf);
|
||||
buf = new byte[locElen];
|
||||
if (zipfs.readFullyAt(buf, 0, buf.length , locoff + LOCHDR + locNlen)
|
||||
if (zipfs.readNBytesAt(buf, 0, buf.length , locoff + LOCHDR + locNlen)
|
||||
!= buf.length)
|
||||
throw new ZipException("loc extra: reading failed");
|
||||
int locPos = 0;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -65,12 +65,12 @@ public class ZipInfo {
|
||||
// loc.extra is bigger than the cen.extra, try to avoid to read
|
||||
// twice
|
||||
long len = LOCHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENHDR;
|
||||
if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len)
|
||||
if (zfs.readNBytesAt(buf, 0, len, locoff(cen, pos)) != len)
|
||||
throw new ZipException("read loc header failed");
|
||||
if (LOCEXT(buf) > CENEXT(cen, pos) + CENHDR) {
|
||||
// have to read the second time;
|
||||
len = LOCHDR + LOCNAM(buf) + LOCEXT(buf);
|
||||
if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len)
|
||||
if (zfs.readNBytesAt(buf, 0, len, locoff(cen, pos)) != len)
|
||||
throw new ZipException("read loc header failed");
|
||||
}
|
||||
printLOC(buf);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -92,18 +92,19 @@ public class LargeGatheringWrite {
|
||||
|
||||
// Write the data to a temporary file
|
||||
Path tempFile = Files.createTempFile("LargeGatheringWrite", ".dat");
|
||||
|
||||
printTime("before writing");
|
||||
System.out.printf("Writing %d bytes of data...%n", totalLength);
|
||||
try (FileChannel fcw = FileChannel.open(tempFile, CREATE, WRITE);) {
|
||||
// Print size of individual writes and total number written
|
||||
long bytesWritten = 0;
|
||||
long n;
|
||||
while ((n = fcw.write(bigBuffers)) > 0) {
|
||||
System.out.printf("Wrote %d bytes\n", n);
|
||||
bytesWritten += n;
|
||||
try {
|
||||
printTime("before writing");
|
||||
System.out.printf("Writing %d bytes of data...%n", totalLength);
|
||||
try (FileChannel fcw = FileChannel.open(tempFile, CREATE, WRITE);) {
|
||||
// Print size of individual writes and total number written
|
||||
long bytesWritten = 0;
|
||||
long n;
|
||||
while ((n = fcw.write(bigBuffers)) > 0) {
|
||||
System.out.printf("Wrote %d bytes\n", n);
|
||||
bytesWritten += n;
|
||||
}
|
||||
System.out.printf("Total of %d bytes written\n", bytesWritten);
|
||||
}
|
||||
System.out.printf("Total of %d bytes written\n", bytesWritten);
|
||||
printTime("after writing");
|
||||
|
||||
// Verify the content written
|
||||
@ -121,8 +122,13 @@ public class LargeGatheringWrite {
|
||||
ByteBuffer dst = ByteBuffer.wrap(bytes).slice(0, length);
|
||||
if (dst.remaining() != length)
|
||||
throw new RuntimeException("remaining");
|
||||
if (fcr.read(dst) != length)
|
||||
throw new RuntimeException("length");
|
||||
long totalRead = 0;
|
||||
while (totalRead < length) {
|
||||
int bytesRead = fcr.read(dst);
|
||||
if (bytesRead < 0)
|
||||
throw new RuntimeException("premature EOF");
|
||||
totalRead += bytesRead;
|
||||
}
|
||||
dst.rewind();
|
||||
|
||||
// Verify that the bytes read from the file match the buffer
|
||||
|
Loading…
x
Reference in New Issue
Block a user