View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.archivers.examples;
20  
21  import static java.nio.charset.StandardCharsets.UTF_8;
22  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
23  import static org.junit.jupiter.api.Assertions.assertFalse;
24  import static org.junit.jupiter.api.Assertions.assertThrows;
25  import static org.junit.jupiter.api.Assertions.assertTrue;
26  import static org.junit.jupiter.api.Assumptions.assumeFalse;
27  import static org.junit.jupiter.api.Assumptions.assumeTrue;
28  
29  import java.io.BufferedInputStream;
30  import java.io.File;
31  import java.io.IOException;
32  import java.io.InputStream;
33  import java.io.OutputStream;
34  import java.nio.channels.FileChannel;
35  import java.nio.channels.SeekableByteChannel;
36  import java.nio.file.Files;
37  import java.nio.file.StandardOpenOption;
38  
39  import org.apache.commons.compress.AbstractTest;
40  import org.apache.commons.compress.archivers.ArchiveEntry;
41  import org.apache.commons.compress.archivers.ArchiveException;
42  import org.apache.commons.compress.archivers.ArchiveOutputStream;
43  import org.apache.commons.compress.archivers.ArchiveStreamFactory;
44  import org.apache.commons.compress.archivers.StreamingNotSupportedException;
45  import org.apache.commons.compress.archivers.sevenz.SevenZFile;
46  import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile;
47  import org.apache.commons.compress.archivers.tar.TarFile;
48  import org.apache.commons.compress.archivers.zip.ZipFile;
49  import org.junit.jupiter.api.Test;
50  
51  public class ExpanderTest extends AbstractTest {
52  
53      private File archive;
54  
55      private void assertHelloWorld(final String fileName, final String suffix) throws IOException {
56          assertTrue(new File(tempResultDir, fileName).isFile(), fileName + " does not exist");
57          final byte[] expected = ("Hello, world " + suffix).getBytes(UTF_8);
58          final byte[] actual = Files.readAllBytes(tempResultDir.toPath().resolve(fileName));
59          assertArrayEquals(expected, actual);
60      }
61  
62      private void setup7z() throws IOException {
63          archive = newTempFile("test.7z");
64          final File dummy = newTempFile("x");
65          try (OutputStream o = Files.newOutputStream(dummy.toPath())) {
66              o.write(new byte[14]);
67          }
68          try (SevenZOutputFile aos = new SevenZOutputFile(archive)) {
69              aos.putArchiveEntry(aos.createArchiveEntry(getTempDirFile(), "a"));
70              aos.closeArchiveEntry();
71              aos.putArchiveEntry(aos.createArchiveEntry(getTempDirFile(), "a/b"));
72              aos.closeArchiveEntry();
73              aos.putArchiveEntry(aos.createArchiveEntry(getTempDirFile(), "a/b/c"));
74              aos.closeArchiveEntry();
75              aos.putArchiveEntry(aos.createArchiveEntry(dummy, "a/b/d.txt"));
76              aos.write("Hello, world 1".getBytes(UTF_8));
77              aos.closeArchiveEntry();
78              aos.putArchiveEntry(aos.createArchiveEntry(dummy, "a/b/c/e.txt"));
79              aos.write("Hello, world 2".getBytes(UTF_8));
80              aos.closeArchiveEntry();
81              aos.finish();
82          }
83      }
84  
85      private void setupTar() throws IOException, ArchiveException {
86          archive = newTempFile("test.tar");
87          final File dummy = newTempFile("x");
88          try (OutputStream o = Files.newOutputStream(dummy.toPath())) {
89              o.write(new byte[14]);
90          }
91          try (@SuppressWarnings("resource") // Files.newOutputStream result closed by ArchiveOutputStream
92          ArchiveOutputStream<ArchiveEntry> aos = ArchiveStreamFactory.DEFAULT.createArchiveOutputStream("tar", Files.newOutputStream(archive.toPath()))) {
93              aos.putArchiveEntry(aos.createArchiveEntry(getTempDirFile(), "a"));
94              aos.closeArchiveEntry();
95              aos.putArchiveEntry(aos.createArchiveEntry(getTempDirFile(), "a/b"));
96              aos.closeArchiveEntry();
97              aos.putArchiveEntry(aos.createArchiveEntry(getTempDirFile(), "a/b/c"));
98              aos.closeArchiveEntry();
99              aos.putArchiveEntry(aos.createArchiveEntry(dummy, "a/b/d.txt"));
100             aos.write("Hello, world 1".getBytes(UTF_8));
101             aos.closeArchiveEntry();
102             aos.putArchiveEntry(aos.createArchiveEntry(dummy, "a/b/c/e.txt"));
103             aos.write("Hello, world 2".getBytes(UTF_8));
104             aos.closeArchiveEntry();
105             aos.finish();
106         }
107     }
108 
109     private void setupTarForCompress603() throws IOException, ArchiveException {
110         archive = newTempFile("test.tar");
111         final File dummy = newTempFile("x");
112         try (OutputStream o = Files.newOutputStream(dummy.toPath())) {
113             o.write(new byte[14]);
114         }
115         try (@SuppressWarnings("resource") // Files.newOutputStream result closed by ArchiveOutputStream
116         ArchiveOutputStream<ArchiveEntry> aos = ArchiveStreamFactory.DEFAULT.createArchiveOutputStream("tar", Files.newOutputStream(archive.toPath()))) {
117             aos.putArchiveEntry(aos.createArchiveEntry(getTempDirFile(), "./"));
118             aos.closeArchiveEntry();
119             aos.putArchiveEntry(aos.createArchiveEntry(getTempDirFile(), "./a"));
120             aos.closeArchiveEntry();
121             aos.putArchiveEntry(aos.createArchiveEntry(getTempDirFile(), "./a/b"));
122             aos.closeArchiveEntry();
123             aos.putArchiveEntry(aos.createArchiveEntry(getTempDirFile(), "./a/b/c"));
124             aos.closeArchiveEntry();
125             aos.putArchiveEntry(aos.createArchiveEntry(dummy, "./a/b/d.txt"));
126             aos.write("Hello, world 1".getBytes(UTF_8));
127             aos.closeArchiveEntry();
128             aos.putArchiveEntry(aos.createArchiveEntry(dummy, "./a/b/c/e.txt"));
129             aos.write("Hello, world 2".getBytes(UTF_8));
130             aos.closeArchiveEntry();
131             aos.finish();
132         }
133     }
134 
135     private void setupZip() throws IOException, ArchiveException {
136         archive = newTempFile("test.zip");
137         final File dummy = newTempFile("x");
138         try (OutputStream o = Files.newOutputStream(dummy.toPath())) {
139             o.write(new byte[14]);
140         }
141         try (@SuppressWarnings("resource") // // Files.newOutputStream result closed by ArchiveOutputStream
142         ArchiveOutputStream<ArchiveEntry> aos = ArchiveStreamFactory.DEFAULT.createArchiveOutputStream("zip", Files.newOutputStream(archive.toPath()))) {
143             aos.putArchiveEntry(aos.createArchiveEntry(getTempDirFile(), "a"));
144             aos.closeArchiveEntry();
145             aos.putArchiveEntry(aos.createArchiveEntry(getTempDirFile(), "a/b"));
146             aos.closeArchiveEntry();
147             aos.putArchiveEntry(aos.createArchiveEntry(getTempDirFile(), "a/b/c"));
148             aos.closeArchiveEntry();
149             aos.putArchiveEntry(aos.createArchiveEntry(dummy, "a/b/d.txt"));
150             aos.write("Hello, world 1".getBytes(UTF_8));
151             aos.closeArchiveEntry();
152             aos.putArchiveEntry(aos.createArchiveEntry(dummy, "a/b/c/e.txt"));
153             aos.write("Hello, world 2".getBytes(UTF_8));
154             aos.closeArchiveEntry();
155             aos.finish();
156         }
157     }
158 
159     private void setupZip(final String entry) throws IOException, ArchiveException {
160         archive = newTempFile("test.zip");
161         final File dummy = newTempFile("x");
162         try (OutputStream o = Files.newOutputStream(dummy.toPath())) {
163             o.write(new byte[14]);
164         }
165         try (@SuppressWarnings("resource") // Files.newOutputStream result closed by ArchiveOutputStream
166         ArchiveOutputStream<ArchiveEntry> aos = ArchiveStreamFactory.DEFAULT.createArchiveOutputStream("zip", Files.newOutputStream(archive.toPath()))) {
167             aos.putArchiveEntry(aos.createArchiveEntry(dummy, entry));
168             aos.write("Hello, world 1".getBytes(UTF_8));
169             aos.closeArchiveEntry();
170             aos.finish();
171         }
172     }
173 
174     @Test
175     public void testCompress603Tar() throws IOException, ArchiveException {
176         setupTarForCompress603();
177         try (TarFile f = new TarFile(archive)) {
178             new Expander().expand(f, tempResultDir);
179         }
180         verifyTargetDir();
181     }
182 
183     @Test
184     public void testFileCantEscapeDoubleDotPath() throws IOException, ArchiveException {
185         setupZip("../foo");
186         try (ZipFile f = ZipFile.builder().setFile(archive).get()) {
187             assertThrows(IOException.class, () -> new Expander().expand(f, tempResultDir));
188         }
189     }
190 
191     @Test
192     public void testFileCantEscapeDoubleDotPathWithSimilarSibling() throws IOException, ArchiveException {
193         final String sibling = tempResultDir.getName() + "x";
194         final File s = new File(tempResultDir.getParentFile(), sibling);
195         assumeFalse(s.exists());
196         s.mkdirs();
197         assumeTrue(s.exists());
198         setupZip("../" + sibling + "/a");
199         try (ZipFile f = ZipFile.builder().setFile(archive).get()) {
200             assertThrows(IOException.class, () -> new Expander().expand(f, tempResultDir));
201         }
202     }
203 
204     @Test
205     public void testFileCantEscapeViaAbsolutePath() throws IOException, ArchiveException {
206         setupZip("/tmp/foo");
207         try (ZipFile f = ZipFile.builder().setFile(archive).get()) {
208             assertThrows(IOException.class, () -> new Expander().expand(f, tempResultDir));
209         }
210         assertFalse(new File(tempResultDir, "tmp/foo").isFile());
211     }
212 
213     @Test
214     public void testSevenZChannelVersion() throws IOException, ArchiveException {
215         setup7z();
216         try (SeekableByteChannel c = FileChannel.open(archive.toPath(), StandardOpenOption.READ)) {
217             new Expander().expand("7z", c, tempResultDir);
218         }
219         verifyTargetDir();
220     }
221 
222     @Test
223     public void testSevenZFileVersion() throws IOException {
224         setup7z();
225         try (SevenZFile file = SevenZFile.builder().setFile(archive).get()) {
226             new Expander().expand(file, tempResultDir);
227         }
228         verifyTargetDir();
229     }
230 
231     @Test
232     public void testSevenZInputStreamVersion() throws IOException {
233         setup7z();
234         try (InputStream i = new BufferedInputStream(Files.newInputStream(archive.toPath()))) {
235             assertThrows(StreamingNotSupportedException.class, () -> new Expander().expand("7z", i, tempResultDir));
236         }
237     }
238 
239     @Test
240     public void testSevenZInputStreamVersionWithAutoDetection() throws IOException {
241         setup7z();
242         try (InputStream i = new BufferedInputStream(Files.newInputStream(archive.toPath()))) {
243             assertThrows(StreamingNotSupportedException.class, () -> new Expander().expand(i, tempResultDir));
244         }
245     }
246 
247     @Test
248     public void testSevenZTwoFileVersion() throws IOException, ArchiveException {
249         setup7z();
250         new Expander().expand("7z", archive, tempResultDir);
251         verifyTargetDir();
252     }
253 
254     @Test
255     public void testSevenZTwoFileVersionWithAutoDetection() throws IOException, ArchiveException {
256         setup7z();
257         new Expander().expand(archive, tempResultDir);
258         verifyTargetDir();
259     }
260 
261     @Test
262     public void testTarFileVersion() throws IOException, ArchiveException {
263         setupTar();
264         try (TarFile f = new TarFile(archive)) {
265             new Expander().expand(f, tempResultDir);
266         }
267         verifyTargetDir();
268     }
269 
270     @Test
271     public void testZipFileVersion() throws IOException, ArchiveException {
272         setupZip();
273         try (ZipFile f = ZipFile.builder().setFile(archive).get()) {
274             new Expander().expand(f, tempResultDir);
275         }
276         verifyTargetDir();
277     }
278 
279     private void verifyTargetDir() throws IOException {
280         assertTrue(new File(tempResultDir, "a").isDirectory(), "a has not been created");
281         assertTrue(new File(tempResultDir, "a/b").isDirectory(), "a/b has not been created");
282         assertTrue(new File(tempResultDir, "a/b/c").isDirectory(), "a/b/c has not been created");
283         assertHelloWorld("a/b/d.txt", "1");
284         assertHelloWorld("a/b/c/e.txt", "2");
285     }
286 
287 }