View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one or more
3    *  contributor license agreements.  See the NOTICE file distributed with
4    *  this work for additional information regarding copyright ownership.
5    *  The ASF licenses this file to You under the Apache License, Version 2.0
6    *  (the "License"); you may not use this file except in compliance with
7    *  the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   *
17   */
18  
19  package org.apache.commons.compress.archivers.tar;
20  
21  import static org.apache.commons.compress.AbstractTestCase.getFile;
22  import static org.apache.commons.compress.AbstractTestCase.mkdir;
23  import static org.apache.commons.compress.AbstractTestCase.rmdir;
24  import static org.junit.Assert.assertArrayEquals;
25  import static org.junit.Assert.assertEquals;
26  import static org.junit.Assert.assertTrue;
27  import static org.junit.Assert.fail;
28  
29  import java.io.ByteArrayInputStream;
30  import java.io.ByteArrayOutputStream;
31  import java.io.File;
32  import java.io.FileInputStream;
33  import java.io.FileOutputStream;
34  import java.io.IOException;
35  import java.io.InputStream;
36  import java.util.Calendar;
37  import java.util.Date;
38  import java.util.Map;
39  import java.util.TimeZone;
40  import java.util.zip.GZIPInputStream;
41  
42  import org.apache.commons.compress.utils.CharsetNames;
43  import org.apache.commons.compress.utils.IOUtils;
44  import org.junit.Test;
45  
46  public class TarArchiveInputStreamTest {
47  
48      @Test
49      public void readSimplePaxHeader() throws Exception {
50          final InputStream is = new ByteArrayInputStream(new byte[1]);
51          final TarArchiveInputStream tais = new TarArchiveInputStream(is);
52          Map<String, String> headers = tais
53              .parsePaxHeaders(new ByteArrayInputStream("30 atime=1321711775.972059463\n"
54                                                        .getBytes(CharsetNames.UTF_8)));
55          assertEquals(1, headers.size());
56          assertEquals("1321711775.972059463", headers.get("atime"));
57          tais.close();
58      }
59  
60      @Test
61      public void readPaxHeaderWithEmbeddedNewline() throws Exception {
62          final InputStream is = new ByteArrayInputStream(new byte[1]);
63          final TarArchiveInputStream tais = new TarArchiveInputStream(is);
64          Map<String, String> headers = tais
65              .parsePaxHeaders(new ByteArrayInputStream("28 comment=line1\nline2\nand3\n"
66                                                        .getBytes(CharsetNames.UTF_8)));
67          assertEquals(1, headers.size());
68          assertEquals("line1\nline2\nand3", headers.get("comment"));
69          tais.close();
70      }
71  
72      @Test
73      public void readNonAsciiPaxHeader() throws Exception {
74          String ae = "\u00e4";
75          String line = "11 path="+ ae + "\n";
76          assertEquals(11, line.getBytes(CharsetNames.UTF_8).length);
77          final InputStream is = new ByteArrayInputStream(new byte[1]);
78          final TarArchiveInputStream tais = new TarArchiveInputStream(is);
79          Map<String, String> headers = tais
80              .parsePaxHeaders(new ByteArrayInputStream(line.getBytes(CharsetNames.UTF_8)));
81          assertEquals(1, headers.size());
82          assertEquals(ae, headers.get("path"));
83          tais.close();
84      }
85  
86      @Test
87      public void workaroundForBrokenTimeHeader() throws Exception {
88          TarArchiveInputStream in = null;
89          try {
90              in = new TarArchiveInputStream(new FileInputStream(getFile("simple-aix-native-tar.tar")));
91              TarArchiveEntry tae = in.getNextTarEntry();
92              tae = in.getNextTarEntry();
93              assertEquals("sample/link-to-txt-file.lnk", tae.getName());
94              assertEquals(new Date(0), tae.getLastModifiedDate());
95              assertTrue(tae.isSymbolicLink());
96              assertTrue(tae.isCheckSumOK());
97          } finally {
98              if (in != null) {
99                  in.close();
100             }
101         }
102     }
103 
104     @Test
105     public void datePriorToEpochInGNUFormat() throws Exception {
106         datePriorToEpoch("preepoch-star.tar");
107     }
108 
109 
110     @Test
111     public void datePriorToEpochInPAXFormat() throws Exception {
112         datePriorToEpoch("preepoch-posix.tar");
113     }
114 
115     private void datePriorToEpoch(String archive) throws Exception {
116         TarArchiveInputStream in = null;
117         try {
118             in = new TarArchiveInputStream(new FileInputStream(getFile(archive)));
119             TarArchiveEntry tae = in.getNextTarEntry();
120             assertEquals("foo", tae.getName());
121             Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
122             cal.set(1969, 11, 31, 23, 59, 59);
123             cal.set(Calendar.MILLISECOND, 0);
124             assertEquals(cal.getTime(), tae.getLastModifiedDate());
125             assertTrue(tae.isCheckSumOK());
126         } finally {
127             if (in != null) {
128                 in.close();
129             }
130         }
131     }
132 
133     @Test
134     public void testCompress197() throws Exception {
135         TarArchiveInputStream tar = getTestStream("/COMPRESS-197.tar");
136         try {
137             TarArchiveEntry entry = tar.getNextTarEntry();
138             while (entry != null) {
139                 entry = tar.getNextTarEntry();
140             }
141         } catch (IOException e) {
142             fail("COMPRESS-197: " + e.getMessage());
143         } finally {
144             tar.close();
145         }
146     }
147 
148     @Test
149     public void shouldUseSpecifiedEncodingWhenReadingGNULongNames()
150         throws Exception {
151         ByteArrayOutputStream bos = new ByteArrayOutputStream();
152         String encoding = CharsetNames.UTF_16;
153         String name = "1234567890123456789012345678901234567890123456789"
154             + "01234567890123456789012345678901234567890123456789"
155             + "01234567890\u00e4";
156         TarArchiveOutputStream tos =
157             new TarArchiveOutputStream(bos, encoding);
158         tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
159         TarArchiveEntry t = new TarArchiveEntry(name);
160         t.setSize(1);
161         tos.putArchiveEntry(t);
162         tos.write(30);
163         tos.closeArchiveEntry();
164         tos.close();
165         byte[] data = bos.toByteArray();
166         ByteArrayInputStream bis = new ByteArrayInputStream(data);
167         TarArchiveInputStream tis =
168             new TarArchiveInputStream(bis, encoding);
169         t = tis.getNextTarEntry();
170         assertEquals(name, t.getName());
171         tis.close();
172     }
173 
174     @Test
175     public void shouldConsumeArchiveCompletely() throws Exception {
176         InputStream is = TarArchiveInputStreamTest.class
177             .getResourceAsStream("/archive_with_trailer.tar");
178         TarArchiveInputStream tar = new TarArchiveInputStream(is);
179         while (tar.getNextTarEntry() != null) {
180             // just consume the archive
181         }
182         byte[] expected = new byte[] {
183             'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n'
184         };
185         byte[] actual = new byte[expected.length];
186         is.read(actual);
187         assertArrayEquals(expected, actual);
188         tar.close();
189     }
190 
191     @Test
192     public void readsArchiveCompletely_COMPRESS245() throws Exception {
193         InputStream is = TarArchiveInputStreamTest.class
194             .getResourceAsStream("/COMPRESS-245.tar.gz");
195         try {
196             InputStream gin = new GZIPInputStream(is);
197             TarArchiveInputStream tar = new TarArchiveInputStream(gin);
198             int count = 0;
199             TarArchiveEntry entry = tar.getNextTarEntry();
200             while (entry != null) {
201                 count++;
202                 entry = tar.getNextTarEntry();
203             }
204             assertEquals(31, count);
205         } catch (IOException e) {
206             fail("COMPRESS-245: " + e.getMessage());
207         } finally {
208             is.close();
209         }
210     }
211 
212     @Test(expected = IOException.class)
213     public void shouldThrowAnExceptionOnTruncatedEntries() throws Exception {
214         File dir = mkdir("COMPRESS-279");
215         TarArchiveInputStream is = getTestStream("/COMPRESS-279.tar");
216         FileOutputStream out = null;
217         try {
218             TarArchiveEntry entry = is.getNextTarEntry();
219             int count = 0;
220             while (entry != null) {
221                 out = new FileOutputStream(new File(dir, String.valueOf(count)));
222                 IOUtils.copy(is, out);
223                 out.close();
224                 out = null;
225                 count++;
226                 entry = is.getNextTarEntry();
227             }
228         } finally {
229             is.close();
230             if (out != null) {
231                 out.close();
232             }
233             rmdir(dir);
234         }
235     }
236 
237     private TarArchiveInputStream getTestStream(String name) {
238         return new TarArchiveInputStream(
239                 TarArchiveInputStreamTest.class.getResourceAsStream(name));
240     }
241 
242 }