diff options
-rw-r--r-- | luni/src/test/java/libcore/java/util/zip/ZipFileTest.java | 49 | ||||
-rwxr-xr-x | ojluni/src/main/java/java/util/zip/ZipFile.java | 8 | ||||
-rw-r--r-- | ojluni/src/main/native/java_util_zip_ZipFile.c | 7 | ||||
-rw-r--r-- | ojluni/src/main/native/zip_util.c | 33 |
4 files changed, 76 insertions, 21 deletions
diff --git a/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java b/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java index 02210ac1b0f..03fa29a032a 100644 --- a/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java +++ b/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java @@ -16,7 +16,18 @@ package libcore.java.util.zip; +import android.system.OsConstants; +import libcore.io.Libcore; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.InputStream; import java.io.OutputStream; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; public final class ZipFileTest extends AbstractZipFileTest { @@ -25,4 +36,42 @@ public final class ZipFileTest extends AbstractZipFileTest { protected ZipOutputStream createZipOutputStream(OutputStream wrapped) { return new ZipOutputStream(wrapped); } + + // http://b/30407219 + public void testZipFileOffsetNeverChangesAfterInit() throws Exception { + final File f = createTemporaryZipFile(); + writeEntries(createZipOutputStream(new BufferedOutputStream(new FileOutputStream(f))), + 2 /* number of entries */, 1024 /* entry size */, true /* setEntrySize */); + + ZipFile zipFile = new ZipFile(f); + FileDescriptor fd = new FileDescriptor(); + fd.setInt$(zipFile.getFileDescriptor()); + + long initialOffset = android.system.Os.lseek(fd, 0, OsConstants.SEEK_CUR); + + Enumeration<? extends ZipEntry> entries = zipFile.entries(); + assertOffset(initialOffset, fd); + + // Get references to the two elements in the file. + ZipEntry entry1 = entries.nextElement(); + ZipEntry entry2 = entries.nextElement(); + assertFalse(entries.hasMoreElements()); + assertOffset(initialOffset, fd); + + InputStream is1 = zipFile.getInputStream(entry1); + assertOffset(initialOffset, fd); + is1.read(new byte[256]); + assertOffset(initialOffset, fd); + is1.close(); + + assertNotNull(zipFile.getEntry(entry2.getName())); + assertOffset(initialOffset, fd); + + zipFile.close(); + } + + private static void assertOffset(long initialOffset, FileDescriptor fd) throws Exception { + long currentOffset = android.system.Os.lseek(fd, 0, OsConstants.SEEK_CUR); + assertEquals(initialOffset, currentOffset); + } } diff --git a/ojluni/src/main/java/java/util/zip/ZipFile.java b/ojluni/src/main/java/java/util/zip/ZipFile.java index e6624af50f1..9ff661af1ec 100755 --- a/ojluni/src/main/java/java/util/zip/ZipFile.java +++ b/ojluni/src/main/java/java/util/zip/ZipFile.java @@ -771,6 +771,14 @@ class ZipFile implements ZipConstants, Closeable { return locsig; } + /** @hide */ + // @VisibleForTesting + public int getFileDescriptor() { + return getFileDescriptor(jzfile); + } + + private static native int getFileDescriptor(long jzfile); + private static native long open(String name, int mode, long lastModified, boolean usemmap) throws IOException; private static native int getTotal(long jzfile); diff --git a/ojluni/src/main/native/java_util_zip_ZipFile.c b/ojluni/src/main/native/java_util_zip_ZipFile.c index 7280d9795d3..5353ff46421 100644 --- a/ojluni/src/main/native/java_util_zip_ZipFile.c +++ b/ojluni/src/main/native/java_util_zip_ZipFile.c @@ -156,6 +156,12 @@ ZipFile_close(JNIEnv *env, jclass cls, jlong zfile) ZIP_Close(jlong_to_ptr(zfile)); } +JNIEXPORT jint JNICALL +ZipFile_getFileDescriptor(JNIEnv *env, jclass cls, jlong zfile) { + jzfile *zip = jlong_to_ptr(zfile); + return zip->zfd; +} + JNIEXPORT jlong JNICALL ZipFile_getEntry(JNIEnv *env, jclass cls, jlong zfile, jbyteArray name, jboolean addSlash) @@ -390,6 +396,7 @@ JarFile_getMetaInfEntryNames(JNIEnv *env, jobject obj) } static JNINativeMethod gMethods[] = { + NATIVE_METHOD(ZipFile, getFileDescriptor, "(J)I"), NATIVE_METHOD(ZipFile, getEntry, "(J[BZ)J"), NATIVE_METHOD(ZipFile, freeEntry, "(JJ)V"), NATIVE_METHOD(ZipFile, getNextEntry, "(JI)J"), diff --git a/ojluni/src/main/native/zip_util.c b/ojluni/src/main/native/zip_util.c index a4dbe14aed6..5a2a0b8c538 100644 --- a/ojluni/src/main/native/zip_util.c +++ b/ojluni/src/main/native/zip_util.c @@ -142,7 +142,7 @@ ZFILE_Close(ZFILE zfd) { } static int -ZFILE_read(ZFILE zfd, char *buf, jint nbytes) { +ZFILE_read(ZFILE zfd, char *buf, jint nbytes, jlong offset) { #ifdef WIN32 return (int) IO_Read(zfd, buf, nbytes); #else @@ -154,7 +154,7 @@ ZFILE_read(ZFILE zfd, char *buf, jint nbytes) { * JVM_IO_INTR is tricky and could cause undesired side effect. So we decided * to simply call "read" on Solaris/Linux. See details in bug 6304463. */ - return read(zfd, buf, nbytes); + return pread(zfd, buf, nbytes, offset); #endif } @@ -183,11 +183,11 @@ InitializeZip() } /* - * Reads len bytes of data into buf. + * Reads len bytes of data from the specified offset into buf. * Returns 0 if all bytes could be read, otherwise returns -1. */ static int -readFully(ZFILE zfd, void *buf, jlong len) { +readFullyAt(ZFILE zfd, void *buf, jlong len, jlong offset) { char *bp = (char *) buf; while (len > 0) { @@ -195,9 +195,10 @@ readFully(ZFILE zfd, void *buf, jlong len) { jint count = (len < limit) ? (jint) len : (jint) limit; - jint n = ZFILE_read(zfd, bp, count); + jint n = ZFILE_read(zfd, bp, count, offset); if (n > 0) { bp += n; + offset += n; len -= n; } else if (n == JVM_IO_ERR && errno == EINTR) { /* Retry after EINTR (interrupted by signal). @@ -210,19 +211,6 @@ readFully(ZFILE zfd, void *buf, jlong len) { return 0; } -/* - * Reads len bytes of data from the specified offset into buf. - * Returns 0 if all bytes could be read, otherwise returns -1. - */ -static int -readFullyAt(ZFILE zfd, void *buf, jlong len, jlong offset) -{ - if (IO_Lseek(zfd, offset, SEEK_SET) == -1) { - return -1; /* lseek failure. */ - } - - return readFully(zfd, buf, len); -} /* * Allocates a new zip file object for the specified file name. @@ -877,14 +865,17 @@ ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, return NULL; } - // Assumption, zfd refers to start of file. Trivially, reuse errbuf. - if (readFully(zfd, errbuf, 4) != -1) { // errors will be handled later + // Trivially, reuse errbuf. + if (readFullyAt(zfd, errbuf, 4, 0 /* offset */) != -1) { // errors will be handled later if (GETSIG(errbuf) == LOCSIG) zip->locsig = JNI_TRUE; else zip->locsig = JNI_FALSE; } + // This lseek is safe because it happens during construction of the ZipFile + // object. We must take care not to perform any operations that change the + // offset after (see b/30407219). len = zip->len = IO_Lseek(zfd, 0, SEEK_END); if (len <= 0) { if (len == 0) { /* zip file is empty */ @@ -984,7 +975,7 @@ readCENHeader(jzfile *zip, jlong cenpos, jint bufsize) censize = CENSIZE(cen); if (censize <= bufsize) return cen; if ((cen = realloc(cen, censize)) == NULL) goto Catch; - if (readFully(zfd, cen+bufsize, censize-bufsize) == -1) goto Catch; + if (readFullyAt(zfd, cen+bufsize, censize-bufsize, cenpos + bufsize) == -1) goto Catch; return cen; Catch: |