1 /*
2  * Copyright (c) 2009, 2013, 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 import java.io.*;
25 import java.nio.*;
26 import java.nio.file.*;
27 import java.nio.file.attribute.*;
28 import java.nio.file.spi.*;
29 import java.util.*;
30 import java.util.zip.*;
31 
32 import static java.nio.file.StandardCopyOption.*;
33 
34 public class LargeZip {
35      // If true, don't delete large ZIP file created for test.
36      static final boolean debug = System.getProperty("debug") != null;
37 
38      //static final int DATA_LEN = 1024 * 1024;
39      static final int DATA_LEN = 80 * 1024;
40      static final int DATA_SIZE = 8;
41 
42      static long fileSize = 6L * 1024L * 1024L * 1024L; // 6GB
43 
44      static boolean userFile = false;
45      static byte[] data;
46      static File largeFile;
47      static String lastEntryName;
48 
49      /* args can be empty, in which case check a 3 GB file which is created for
50       * this test (and then deleted).  Or it can be a number, in which case
51       * that designates the size of the file that's created for this test (and
52       * then deleted).  Or it can be the name of a file to use for the test, in
53       * which case it is *not* deleted.  Note that in this last case, the data
54       * comparison might fail.
55       */
realMain(String[] args)56      static void realMain (String[] args) throws Throwable {
57          if (args.length > 0) {
58              try {
59                  fileSize = Long.parseLong(args[0]);
60                  System.out.println("Testing with file of size " + fileSize);
61              } catch (NumberFormatException ex) {
62                  largeFile = new File(args[0]);
63                  if (!largeFile.exists()) {
64                      throw new Exception("Specified file " + args[0] + " does not exist");
65                  }
66                  userFile = true;
67                  System.out.println("Testing with user-provided file " + largeFile);
68              }
69          }
70          File testDir = null;
71          if (largeFile == null) {
72              testDir = new File(System.getProperty("test.scratch", "."),
73                                      "LargeZip");
74              if (testDir.exists()) {
75                  if (!testDir.delete()) {
76                      throw new Exception("Cannot delete already-existing test directory");
77                  }
78              }
79              check(!testDir.exists() && testDir.mkdirs());
80              largeFile = new File(testDir, "largezip.zip");
81              createLargeZip();
82          } else {
83              if (args.length > 1)
84                  updateLargeZip(args[1]); // add new entry with zfs
85          }
86          readLargeZip1();
87          readLargeZip2();
88 
89          if (!userFile && !debug) {
90              check(largeFile.delete());
91              check(testDir.delete());
92          }
93      }
94 
createLargeZip()95      static void createLargeZip() throws Throwable {
96          int iterations = DATA_LEN / DATA_SIZE;
97          ByteBuffer bb = ByteBuffer.allocate(DATA_SIZE);
98          ByteArrayOutputStream baos = new ByteArrayOutputStream();
99          for (int i = 0; i < iterations; i++) {
100              bb.putDouble(0, Math.random());
101              baos.write(bb.array(), 0, DATA_SIZE);
102          }
103          data = baos.toByteArray();
104 
105          try (FileOutputStream fos = new FileOutputStream(largeFile);
106               BufferedOutputStream bos = new BufferedOutputStream(fos);
107               ZipOutputStream zos = new ZipOutputStream(bos))
108          {
109              long length = 0;
110              while (length < fileSize) {
111                  ZipEntry ze = new ZipEntry("entry-" + length);
112                  lastEntryName = ze.getName();
113                  zos.putNextEntry(ze);
114                  zos.write(data, 0, data.length);
115                  zos.closeEntry();
116                  length = largeFile.length();
117              }
118              System.out.println("Last entry written is " + lastEntryName);
119          }
120      }
121 
122      private static byte buf[] = new byte[4096];
123 
checkEntry(ZipEntry e, InputStream is)124      static void checkEntry(ZipEntry e, InputStream is) throws Throwable {
125          long N = 0;
126          int n = 0;
127          while ((n = is.read(buf)) >= 0) {
128             N += n;
129          }
130          check(N == e.getSize());
131      }
132 
readLargeZip1()133      static void readLargeZip1() throws Throwable {
134           ZipFile zipFile = new ZipFile(largeFile);
135           ZipEntry entry = null;
136           String entryName = null;
137           int count = 0;
138           System.out.println("ZipFile:");
139           Enumeration<? extends ZipEntry> entries = zipFile.entries();
140           while (entries.hasMoreElements()) {
141                entry = entries.nextElement();
142                entryName = entry.getName();
143                System.out.println("    checking " + entryName);
144                if (!entry.isDirectory()) {
145                     try (InputStream zeis = zipFile.getInputStream(entry)) {
146                         checkEntry(entry, zeis);
147                     }
148                }
149                count++;
150           }
151           System.out.println("Number of entries read: " + count);
152           check(!entry.isDirectory());
153           if (userFile || check(entryName.equals(lastEntryName))) {
154                ByteArrayOutputStream baos = new ByteArrayOutputStream();
155                InputStream is = zipFile.getInputStream(entry);
156                int len;
157                while ((len = is.read(buf)) >= 0) {
158                     baos.write(buf, 0, len);
159                }
160                baos.close();
161                is.close();
162                if (!userFile)
163                    check(Arrays.equals(data, baos.toByteArray()));
164           }
165      }
166 
readLargeZip2()167      static void readLargeZip2() throws Throwable {
168          System.out.println("ZipInputStream:");
169          try (FileInputStream fis = new FileInputStream(largeFile);
170               BufferedInputStream bis = new BufferedInputStream(fis);
171               ZipInputStream zis = new ZipInputStream(bis))
172          {
173              ZipEntry entry = null;
174              String entryName = null;
175              int count = 0;
176              while ((entry = zis.getNextEntry()) != null) {
177                   entryName = entry.getName();
178 
179                   System.out.println("    checking " + entryName +
180                                      ", method=" + entry.getMethod());
181                   if (entryName.equals(lastEntryName)) {
182                        break;
183                   }
184                   if (!entry.isDirectory()) {
185                        checkEntry(entry, zis);
186                   }
187                   count++;
188              }
189              System.out.println("Number of entries read: " + count);
190              System.out.println("Last entry read is " + entryName);
191              if (!userFile) {
192                   check(!entry.isDirectory());
193                   ByteArrayOutputStream baos = new ByteArrayOutputStream();
194                   byte buf[] = new byte[4096];
195                   int len;
196                   while ((len = zis.read(buf)) >= 0) {
197                        baos.write(buf, 0, len);
198                   }
199                   baos.close();
200                   check(Arrays.equals(data, baos.toByteArray()));
201                   check(zis.getNextEntry() == null);
202              }
203          }
204      }
205 
updateFile(FileSystem fs, Path src)206      private static void updateFile(FileSystem fs, Path src) throws IOException {
207           Path dst = fs.getPath(src.toString());
208           Path parent = dst.getParent();
209           if (parent != null && Files.notExists(parent))
210                Files.createDirectories(parent);
211           Files.copy(src, dst, REPLACE_EXISTING);
212      }
213 
getZipFSProvider()214      private static FileSystemProvider getZipFSProvider() {
215          for (FileSystemProvider provider : FileSystemProvider.installedProviders()) {
216               if ("jar".equalsIgnoreCase(provider.getScheme()))
217                    return provider;
218          }
219          return null;
220      }
221 
updateLargeZip(String pName)222      static void updateLargeZip(String pName) throws Throwable {
223          FileSystemProvider provider = getZipFSProvider();
224          if (provider == null) {
225              System.err.println("ZIP filesystem provider is not installed");
226              System.exit(1);
227          }
228          Map<String, Object> env = env = new HashMap<>();
229          try (FileSystem fs = provider.newFileSystem(largeFile.toPath(), env)) {
230              Path path = FileSystems.getDefault().getPath(pName);
231              Files.walkFileTree(
232                  path,
233                  new SimpleFileVisitor<Path>() {
234                      @Override
235                      public FileVisitResult visitFile(Path file,
236                                                       BasicFileAttributes attrs)
237                          throws IOException
238                      {
239                          updateFile(fs, file);
240                          return FileVisitResult.CONTINUE;
241                      }
242              });
243          }
244      }
245 
246 
247      //--------------------- Infrastructure ---------------------------
248      static volatile int passed = 0, failed = 0;
pass()249      static void pass() {passed++;}
pass(String msg)250      static void pass(String msg) {System.out.println(msg); passed++;}
fail()251      static void fail() {failed++; Thread.dumpStack();}
fail(String msg)252      static void fail(String msg) {System.out.println(msg); fail();}
unexpected(Throwable t)253      static void unexpected(Throwable t) {failed++; t.printStackTrace();}
unexpected(Throwable t, String msg)254      static void unexpected(Throwable t, String msg) {
255          System.out.println(msg); failed++; t.printStackTrace();}
check(boolean cond)256      static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
equal(Object x, Object y)257      static void equal(Object x, Object y) {
258           if (x == null ? y == null : x.equals(y)) pass();
259           else fail(x + " not equal to " + y);}
main(String[] args)260      public static void main(String[] args) throws Throwable {
261           try {realMain(args);} catch (Throwable t) {unexpected(t);}
262           System.out.println("\nPassed = " + passed + " failed = " + failed);
263           if (failed > 0) throw new AssertionError("Some tests failed");}
264 }
265