View Javadoc
1   package org.codehaus.plexus.archiver.zip;
2   
3   import java.io.File;
4   import java.io.IOException;
5   import java.lang.reflect.Method;
6   import java.util.Arrays;
7   import java.util.HashSet;
8   import java.util.Set;
9   
10  import org.codehaus.plexus.archiver.Archiver;
11  import org.codehaus.plexus.archiver.TestSupport;
12  import org.codehaus.plexus.archiver.UnArchiver;
13  import org.codehaus.plexus.components.io.fileselectors.FileInfo;
14  import org.codehaus.plexus.components.io.fileselectors.FileSelector;
15  import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector;
16  import org.codehaus.plexus.util.FileUtils;
17  import org.junit.jupiter.api.Test;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertNotNull;
21  import static org.junit.jupiter.api.Assertions.assertTrue;
22  
23  /**
24   * @author Jason van Zyl
25   */
26  class ZipUnArchiverTest extends TestSupport {
27  
28      @Test
29      void testExtractingZipPreservesExecutableFlag() throws Exception {
30  
31          String s = "target/zip-unarchiver-tests";
32          File testZip = new File(getBasedir(), "src/test/jars/test.zip");
33          File outputDirectory = new File(getBasedir(), s);
34  
35          FileUtils.deleteDirectory(outputDirectory);
36  
37          ZipUnArchiver zu = getZipUnArchiver(testZip);
38          zu.extract("", outputDirectory);
39          File testScript = new File(outputDirectory, "test.sh");
40  
41          final Method canExecute;
42          try {
43              canExecute = File.class.getMethod("canExecute");
44              canExecute.invoke(testScript);
45              assertTrue((Boolean) canExecute.invoke(testScript));
46          } catch (NoSuchMethodException ignore) {
47          }
48      }
49  
50      @Test
51      void testZeroFileModeInZip() throws Exception {
52  
53          String s = "target/zip-unarchiver-filemode-tests";
54          File testZip = new File(getBasedir(), "src/test/resources/zeroFileMode/foobar.zip");
55          File outputDirectory = new File(getBasedir(), s);
56  
57          FileUtils.deleteDirectory(outputDirectory);
58  
59          ZipUnArchiver zu = getZipUnArchiver(testZip);
60          zu.setIgnorePermissions(false);
61          zu.extract("", outputDirectory);
62  
63          File testScript = new File(outputDirectory, "foo.txt");
64  
65          final Method canRead;
66          try {
67              canRead = File.class.getMethod("canRead");
68              canRead.invoke(testScript);
69              assertTrue((Boolean) canRead.invoke(testScript));
70          } catch (NoSuchMethodException ignore) {
71          }
72      }
73  
74      @Test
75      void testUnarchiveUtf8() throws Exception {
76          File dest = new File("target/output/unzip/utf8");
77          dest.mkdirs();
78  
79          final File zipFile = new File("target/output/unzip/utf8-default.zip");
80          final ZipArchiver zipArchiver = getZipArchiver(zipFile);
81          zipArchiver.addDirectory(new File("src/test/resources/miscUtf8"));
82          zipArchiver.createArchive();
83          final ZipUnArchiver unarchiver = getZipUnArchiver(zipFile);
84          unarchiver.setDestFile(dest);
85          unarchiver.extract();
86          assertTrue(new File(dest, "aPi\u00F1ata.txt").exists());
87          assertTrue(new File(dest, "an\u00FCmlaut.txt").exists());
88          assertTrue(new File(dest, "\u20acuro.txt").exists());
89      }
90  
91      @Test
92      void testUnarchiveUnicodePathExtra() throws Exception {
93          File dest = new File("target/output/unzip/unicodePathExtra");
94          dest.mkdirs();
95          for (String name : dest.list()) {
96              new File(dest, name).delete();
97          }
98          assertEquals(0, dest.list().length);
99  
100         final ZipUnArchiver unarchiver = getZipUnArchiver(new File("src/test/resources/unicodePathExtra/efsclear.zip"));
101         unarchiver.setDestFile(dest);
102         unarchiver.extract();
103         // a Unicode Path extra field should only be used when its CRC matches the header file name
104         assertEquals(
105                 new HashSet<>(Arrays.asList("nameonly-name", "goodextra-extra", "badextra-name")),
106                 new HashSet<>(Arrays.asList(dest.list())),
107                 "should use good extra fields but not bad ones");
108     }
109 
110     @Test
111     void testUnarchiveUnicodePathExtraSelector() throws Exception {
112         File dest = new File("target/output/unzip/unicodePathExtraSelector");
113         dest.mkdirs();
114         for (String name : dest.list()) {
115             new File(dest, name).delete();
116         }
117         assertEquals(0, dest.list().length);
118 
119         class CollectingSelector implements FileSelector {
120             public Set<String> collection = new HashSet<>();
121 
122             @Override
123             public boolean isSelected(FileInfo fileInfo) throws IOException {
124                 collection.add(fileInfo.getName());
125                 return false;
126             }
127         }
128         CollectingSelector selector = new CollectingSelector();
129 
130         final ZipUnArchiver unarchiver = getZipUnArchiver(new File("src/test/resources/unicodePathExtra/efsclear.zip"));
131         unarchiver.setDestFile(dest);
132         unarchiver.setFileSelectors(new FileSelector[] {selector});
133         unarchiver.extract();
134 
135         assertEquals(0, dest.list().length, "should not extract anything");
136         // a Unicode Path extra field should only be used when its CRC matches the header file name
137         assertEquals(
138                 new HashSet<>(Arrays.asList("nameonly-name", "goodextra-extra", "badextra-name")),
139                 selector.collection,
140                 "should use good extra fields but not bad ones");
141     }
142 
143     private void runUnarchiver(String path, FileSelector[] selectors, boolean[] results) throws Exception {
144         String s = "target/zip-unarchiver-tests";
145 
146         File testJar = new File(getBasedir(), "src/test/jars/test.jar");
147 
148         File outputDirectory = new File(getBasedir(), s);
149 
150         ZipUnArchiver zu = getZipUnArchiver(testJar);
151         zu.setFileSelectors(selectors);
152 
153         FileUtils.deleteDirectory(outputDirectory);
154 
155         zu.extract(path, outputDirectory);
156 
157         File f0 = new File(getBasedir(), s + "/resources/artifactId/test.properties");
158 
159         assertEquals(results[0], f0.exists());
160 
161         File f1 = new File(getBasedir(), s + "/resources/artifactId/directory/test.properties");
162 
163         assertEquals(results[1], f1.exists());
164 
165         File f2 = new File(getBasedir(), s + "/META-INF/MANIFEST.MF");
166 
167         assertEquals(results[2], f2.exists());
168     }
169 
170     private ZipUnArchiver getZipUnArchiver(File testJar) throws Exception {
171         ZipUnArchiver zu = (ZipUnArchiver) lookup(UnArchiver.class, "zip");
172         zu.setSourceFile(testJar);
173         return zu;
174     }
175 
176     @Test
177     void testExtractingADirectoryFromAJarFile() throws Exception {
178         runUnarchiver("resources/artifactId", null, new boolean[] {true, true, false});
179         runUnarchiver("", null, new boolean[] {true, true, true});
180     }
181 
182     @Test
183     void testSelectors() throws Exception {
184         IncludeExcludeFileSelector fileSelector = new IncludeExcludeFileSelector();
185         runUnarchiver("", new FileSelector[] {fileSelector}, new boolean[] {true, true, true});
186         fileSelector.setExcludes(new String[] {"**/test.properties"});
187         runUnarchiver("", new FileSelector[] {fileSelector}, new boolean[] {false, false, true});
188         fileSelector.setIncludes(new String[] {"**/test.properties"});
189         fileSelector.setExcludes(null);
190         runUnarchiver("", new FileSelector[] {fileSelector}, new boolean[] {true, true, false});
191         fileSelector.setExcludes(new String[] {"resources/artifactId/directory/test.properties"});
192         runUnarchiver("", new FileSelector[] {fileSelector}, new boolean[] {true, false, false});
193     }
194 
195     @Test
196     void testExtractingZipWithEntryOutsideDestDirThrowsException() throws Exception {
197         Exception ex = null;
198         String s = "target/zip-unarchiver-slip-tests";
199         File testZip = new File(getBasedir(), "src/test/zips/zip-slip.zip");
200         File outputDirectory = new File(getBasedir(), s);
201 
202         FileUtils.deleteDirectory(outputDirectory);
203 
204         try {
205             ZipUnArchiver zu = getZipUnArchiver(testZip);
206             zu.extract("", outputDirectory);
207         } catch (Exception e) {
208             ex = e;
209         }
210 
211         assertNotNull(ex);
212         assertTrue(ex.getMessage().startsWith("Entry is outside of the target directory"));
213     }
214 
215     @Test
216     void testZipOutputSizeException() throws Exception {
217         Exception ex = null;
218         String s = "target/zip-size-tests";
219         File testZip = new File(getBasedir(), "src/test/jars/test.zip");
220         File outputDirectory = new File(getBasedir(), s);
221 
222         FileUtils.deleteDirectory(outputDirectory);
223 
224         try {
225             ZipUnArchiver zu = getZipUnArchiver(testZip);
226             zu.setMaxOutputSize(10L);
227             zu.extract("", outputDirectory);
228         } catch (Exception e) {
229             ex = e;
230         }
231 
232         assertNotNull(ex);
233         assertTrue(ex.getMessage().startsWith("Maximum output size limit reached"));
234     }
235 
236     @Test
237     void testZipMaxOutputSizeEqualToExtractedFileSize() throws Exception {
238         long extractedFileSize = 11L;
239         String s = "target/zip-size-tests";
240         File testZip = new File(getBasedir(), "src/test/jars/test.zip");
241         File outputDirectory = new File(getBasedir(), s);
242 
243         FileUtils.deleteDirectory(outputDirectory);
244 
245         ZipUnArchiver zu = getZipUnArchiver(testZip);
246         zu.setMaxOutputSize(extractedFileSize);
247         zu.extract("", outputDirectory);
248 
249         File extractedFile = new File(outputDirectory, "test.sh");
250         assertEquals(extractedFileSize, extractedFile.length());
251     }
252 
253     private ZipArchiver getZipArchiver() {
254         try {
255             return (ZipArchiver) lookup(Archiver.class, "zip");
256         } catch (Exception e) {
257             throw new RuntimeException(e);
258         }
259     }
260 
261     private ZipArchiver getZipArchiver(File destFile) {
262         final ZipArchiver zipArchiver = getZipArchiver();
263         zipArchiver.setDestFile(destFile);
264         return zipArchiver;
265     }
266 }