6599383: Unable to open zip files more than 2GB in size
authorkevinw
Tue, 24 Feb 2009 14:22:08 +0000
changeset 2074 346a841b2dcc
parent 2073 bfd94f58ed3d
child 2075 4e3500c2a901
child 2165 98373487fcf4
child 2166 e01c813f9552
6599383: Unable to open zip files more than 2GB in size Reviewed-by: alanb
jdk/src/share/native/java/util/zip/zip_util.c
jdk/src/share/native/java/util/zip/zip_util.h
jdk/test/java/util/zip/ZipFile/LargeZipFile.java
--- a/jdk/src/share/native/java/util/zip/zip_util.c	Tue Feb 24 11:33:25 2009 +0000
+++ b/jdk/src/share/native/java/util/zip/zip_util.c	Tue Feb 24 14:22:08 2009 +0000
@@ -135,11 +135,6 @@
 #endif
 }
 
-static jlong
-ZFILE_Lseek(ZFILE zfd, off_t offset, int whence) {
-    return IO_Lseek(zfd, offset, whence);
-}
-
 static int
 ZFILE_read(ZFILE zfd, char *buf, jint nbytes) {
 #ifdef WIN32
@@ -216,7 +211,7 @@
 static int
 readFullyAt(ZFILE zfd, void *buf, jlong len, jlong offset)
 {
-    if (ZFILE_Lseek(zfd, (off_t) offset, SEEK_SET) == -1) {
+    if (IO_Lseek(zfd, offset, SEEK_SET) == -1) {
         return -1; /* lseek failure. */
     }
 
@@ -476,7 +471,7 @@
     unsigned char *cp;
 #ifdef USE_MMAP
     static jlong pagesize;
-    off_t offset;
+    jlong offset;
 #endif
     unsigned char endbuf[ENDHDR];
     jzcell *entries;
@@ -534,7 +529,7 @@
         */
         zip->mlen = cenpos - offset + cenlen + ENDHDR;
         zip->offset = offset;
-        mappedAddr = mmap(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, offset);
+        mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset);
         zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL :
             (unsigned char*)mappedAddr;
 
@@ -720,7 +715,7 @@
         return NULL;
     }
 
-    len = zip->len = ZFILE_Lseek(zfd, 0, SEEK_END);
+    len = zip->len = IO_Lseek(zfd, 0, SEEK_END);
     if (len <= 0) {
         if (len == 0) { /* zip file is empty */
             if (pmsg) {
--- a/jdk/src/share/native/java/util/zip/zip_util.h	Tue Feb 24 11:33:25 2009 +0000
+++ b/jdk/src/share/native/java/util/zip/zip_util.h	Tue Feb 24 14:22:08 2009 +0000
@@ -174,7 +174,7 @@
 #ifdef USE_MMAP
     unsigned char *maddr; /* beginning address of the CEN & ENDHDR */
     jlong mlen;           /* length (in bytes) mmaped */
-    off_t offset;         /* offset of the mmapped region from the
+    jlong offset;         /* offset of the mmapped region from the
                              start of the file. */
 #else
     cencache cencache;    /* CEN header cache */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/zip/ZipFile/LargeZipFile.java	Tue Feb 24 14:22:08 2009 +0000
@@ -0,0 +1,138 @@
+import java.io.*;
+import java.nio.*;
+import java.util.*;
+import java.util.zip.*;
+
+public class LargeZipFile {
+    // 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_SIZE = 8;
+
+    static long fileSize = 3L * 1024L * 1024L * 1024L; // 3GB
+
+    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();
+        }
+
+        readLargeZip();
+
+        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 readLargeZip() 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()));
+        }
+        try {
+          zipFile.close();
+        } catch (IOException ioe) {/* what can you do */ }
+    }
+
+    //--------------------- 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");}
+}
+