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.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertFalse;
23  import static org.junit.Assert.assertTrue;
24  import static org.junit.Assert.fail;
25  
26  import org.apache.commons.compress.archivers.zip.ZipEncoding;
27  import org.apache.commons.compress.archivers.zip.ZipEncodingHelper;
28  import org.apache.commons.compress.utils.CharsetNames;
29  import org.junit.Test;
30  
31  public class TarUtilsTest {
32  
33  
34      @Test
35      public void testName(){
36          byte [] buff = new byte[20];
37          String sb1 = "abcdefghijklmnopqrstuvwxyz";
38          int off = TarUtils.formatNameBytes(sb1, buff, 1, buff.length-1);
39          assertEquals(off, 20);
40          String sb2 = TarUtils.parseName(buff, 1, 10);
41          assertEquals(sb2,sb1.substring(0,10));
42          sb2 = TarUtils.parseName(buff, 1, 19);
43          assertEquals(sb2,sb1.substring(0,19));
44          buff = new byte[30];
45          off = TarUtils.formatNameBytes(sb1, buff, 1, buff.length-1);
46          assertEquals(off, 30);
47          sb2 = TarUtils.parseName(buff, 1, buff.length-1);
48          assertEquals(sb1, sb2);
49      }
50  
51      @Test
52      public void testParseOctal() throws Exception{
53          long value; 
54          byte [] buffer;
55          final long MAX_OCTAL  = 077777777777L; // Allowed 11 digits
56          final long MAX_OCTAL_OVERFLOW  = 0777777777777L; // in fact 12 for some implementations
57          final String maxOctal = "777777777777"; // Maximum valid octal
58          buffer = maxOctal.getBytes(CharsetNames.UTF_8);
59          value = TarUtils.parseOctal(buffer,0, buffer.length);
60          assertEquals(MAX_OCTAL_OVERFLOW, value);
61          buffer[buffer.length - 1] = ' ';
62          value = TarUtils.parseOctal(buffer,0, buffer.length);
63          assertEquals(MAX_OCTAL, value);
64          buffer[buffer.length-1]=0;
65          value = TarUtils.parseOctal(buffer,0, buffer.length);
66          assertEquals(MAX_OCTAL, value);
67          buffer=new byte[]{0,0};
68          value = TarUtils.parseOctal(buffer,0, buffer.length);
69          assertEquals(0, value);
70          buffer=new byte[]{0,' '};
71          value = TarUtils.parseOctal(buffer,0, buffer.length);
72          assertEquals(0, value);
73          buffer=new byte[]{' ',0};
74          value = TarUtils.parseOctal(buffer,0, buffer.length);
75          assertEquals(0, value);
76      }
77  
78      @Test
79      public void testParseOctalInvalid() throws Exception{
80          byte [] buffer;
81          buffer=new byte[0]; // empty byte array
82          try {
83              TarUtils.parseOctal(buffer,0, buffer.length);
84              fail("Expected IllegalArgumentException - should be at least 2 bytes long");
85          } catch (IllegalArgumentException expected) {
86          }
87          buffer=new byte[]{0}; // 1-byte array
88          try {
89              TarUtils.parseOctal(buffer,0, buffer.length);
90              fail("Expected IllegalArgumentException - should be at least 2 bytes long");
91          } catch (IllegalArgumentException expected) {
92          }
93          buffer = "abcdef ".getBytes(CharsetNames.UTF_8); // Invalid input
94          try {
95              TarUtils.parseOctal(buffer,0, buffer.length);
96              fail("Expected IllegalArgumentException");
97          } catch (IllegalArgumentException expected) {
98          }
99          buffer = " 0 07 ".getBytes(CharsetNames.UTF_8); // Invalid - embedded space
100         try {
101             TarUtils.parseOctal(buffer,0, buffer.length);
102             fail("Expected IllegalArgumentException - embedded space");
103         } catch (IllegalArgumentException expected) {
104         }
105         buffer = " 0\00007 ".getBytes(CharsetNames.UTF_8); // Invalid - embedded NUL
106         try {
107             TarUtils.parseOctal(buffer,0, buffer.length);
108             fail("Expected IllegalArgumentException - embedded NUL");
109         } catch (IllegalArgumentException expected) {
110         }
111     }
112 
113     private void checkRoundTripOctal(final long value, final int bufsize) {
114         byte [] buffer = new byte[bufsize];
115         long parseValue;
116         TarUtils.formatLongOctalBytes(value, buffer, 0, buffer.length);
117         parseValue = TarUtils.parseOctal(buffer,0, buffer.length);
118         assertEquals(value,parseValue);
119     }
120 
121     private void checkRoundTripOctal(final long value) {
122         checkRoundTripOctal(value, TarConstants.SIZELEN);
123     }
124 
125     @Test
126     public void testRoundTripOctal() {
127         checkRoundTripOctal(0);
128         checkRoundTripOctal(1);
129 //        checkRoundTripOctal(-1); // TODO What should this do?
130         checkRoundTripOctal(TarConstants.MAXSIZE);
131 //        checkRoundTripOctal(0100000000000L); // TODO What should this do?
132 
133         checkRoundTripOctal(0, TarConstants.UIDLEN);
134         checkRoundTripOctal(1, TarConstants.UIDLEN);
135         checkRoundTripOctal(TarConstants.MAXID, 8);
136     }
137 
138     private void checkRoundTripOctalOrBinary(final long value, final int bufsize) {
139         byte [] buffer = new byte[bufsize];
140         long parseValue;
141         TarUtils.formatLongOctalOrBinaryBytes(value, buffer, 0, buffer.length);
142         parseValue = TarUtils.parseOctalOrBinary(buffer,0, buffer.length);
143         assertEquals(value,parseValue);
144     }
145 
146     @Test
147     public void testRoundTripOctalOrBinary8() {
148         testRoundTripOctalOrBinary(8);
149     }
150 
151     @Test
152     public void testRoundTripOctalOrBinary12() {
153         testRoundTripOctalOrBinary(12);
154         checkRoundTripOctalOrBinary(Long.MAX_VALUE, 12);
155         checkRoundTripOctalOrBinary(Long.MIN_VALUE + 1, 12);
156     }
157 
158     private void testRoundTripOctalOrBinary(int length) {
159         checkRoundTripOctalOrBinary(0, length);
160         checkRoundTripOctalOrBinary(1, length);
161         checkRoundTripOctalOrBinary(TarConstants.MAXSIZE, length); // will need binary format
162         checkRoundTripOctalOrBinary(-1, length); // will need binary format
163         checkRoundTripOctalOrBinary(0xff00000000000001l, length);
164     }
165 
166     // Check correct trailing bytes are generated
167     @Test
168     public void testTrailers() {
169         byte [] buffer = new byte[12];
170         TarUtils.formatLongOctalBytes(123, buffer, 0, buffer.length);
171         assertEquals(' ', buffer[buffer.length-1]);
172         assertEquals('3', buffer[buffer.length-2]); // end of number
173         TarUtils.formatOctalBytes(123, buffer, 0, buffer.length);
174         assertEquals(0  , buffer[buffer.length-1]);
175         assertEquals(' ', buffer[buffer.length-2]);
176         assertEquals('3', buffer[buffer.length-3]); // end of number
177         TarUtils.formatCheckSumOctalBytes(123, buffer, 0, buffer.length);
178         assertEquals(' ', buffer[buffer.length-1]);
179         assertEquals(0  , buffer[buffer.length-2]);
180         assertEquals('3', buffer[buffer.length-3]); // end of number
181     }
182 
183     @Test
184     public void testNegative() throws Exception {
185         byte [] buffer = new byte[22];
186         TarUtils.formatUnsignedOctalString(-1, buffer, 0, buffer.length);
187         assertEquals("1777777777777777777777", new String(buffer, CharsetNames.UTF_8));
188     }
189 
190     @Test
191     public void testOverflow() throws Exception {
192         byte [] buffer = new byte[8-1]; // a lot of the numbers have 8-byte buffers (nul term)
193         TarUtils.formatUnsignedOctalString(07777777L, buffer, 0, buffer.length);
194         assertEquals("7777777", new String(buffer, CharsetNames.UTF_8));
195         try {
196             TarUtils.formatUnsignedOctalString(017777777L, buffer, 0, buffer.length);
197             fail("Should have cause IllegalArgumentException");
198         } catch (IllegalArgumentException expected) {
199         }
200     }
201 
202     @Test
203     public void testRoundTripNames(){
204         checkName("");
205         checkName("The quick brown fox\n");
206         checkName("\177");
207         // checkName("\0"); // does not work, because NUL is ignored
208     }
209 
210     @Test
211     public void testRoundEncoding() throws Exception {
212         // COMPRESS-114
213         ZipEncoding enc = ZipEncodingHelper.getZipEncoding(CharsetNames.ISO_8859_1);
214         String s = "0302-0601-3\u00b1\u00b1\u00b1F06\u00b1W220\u00b1ZB\u00b1LALALA\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1CAN\u00b1\u00b1DC\u00b1\u00b1\u00b104\u00b1060302\u00b1MOE.model";
215         byte buff[] = new byte[100];
216         int len = TarUtils.formatNameBytes(s, buff, 0, buff.length, enc);
217         assertEquals(s, TarUtils.parseName(buff, 0, len, enc));
218     }
219 
220     private void checkName(String string) {
221         byte buff[] = new byte[100];
222         int len = TarUtils.formatNameBytes(string, buff, 0, buff.length);
223         assertEquals(string, TarUtils.parseName(buff, 0, len));
224     }
225 
226     @Test
227     public void testReadNegativeBinary8Byte() {
228         byte[] b = new byte[] {
229             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
230             (byte) 0xff, (byte) 0xff, (byte) 0xf1, (byte) 0xef,
231         };
232         assertEquals(-3601l, TarUtils.parseOctalOrBinary(b, 0, 8));
233     }
234 
235     @Test
236     public void testReadNegativeBinary12Byte() {
237         byte[] b = new byte[] {
238             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
239             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
240             (byte) 0xff, (byte) 0xff, (byte) 0xf1, (byte) 0xef,
241         };
242         assertEquals(-3601l, TarUtils.parseOctalOrBinary(b, 0, 12));
243     }
244 
245 
246     @Test
247     public void testWriteNegativeBinary8Byte() {
248         byte[] b = new byte[] {
249             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
250             (byte) 0xff, (byte) 0xff, (byte) 0xf1, (byte) 0xef,
251         };
252         assertEquals(-3601l, TarUtils.parseOctalOrBinary(b, 0, 8));
253     }
254 
255     // https://issues.apache.org/jira/browse/COMPRESS-191
256     @Test
257     public void testVerifyHeaderCheckSum() {
258         byte[] valid = { // from bla.tar
259                 116, 101, 115, 116, 49, 46, 120, 109, 108, 0, 0, 0, 0, 0, 0,
260                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
261                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
262                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
263                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
264                 0, 48, 48, 48, 48, 54, 52, 52, 0, 48, 48, 48, 48, 55, 54, 53,
265                 0, 48, 48, 48, 48, 55, 54, 53, 0, 48, 48, 48, 48, 48, 48, 48,
266                 49, 49, 52, 50, 0, 49, 48, 55, 49, 54, 53, 52, 53, 54, 50, 54,
267                 0, 48, 49, 50, 50, 54, 48, 0, 32, 48, 0, 0, 0, 0, 0, 0, 0, 0,
268                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
269                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
270                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
271                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
272                 0, 0, 0, 0, 0, 0, 0, 0, 117, 115, 116, 97, 114, 32, 32, 0,
273                 116, 99, 117, 114, 100, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
274                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 99, 117,
275                 114, 100, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
276                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
277                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
278                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
279                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
280                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
281                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
282                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
283                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
284                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
285                 0, 0, 0, 0 };
286         assertTrue(TarUtils.verifyCheckSum(valid));
287 
288         byte[] compress117 = { // from COMPRESS-117
289                 116, 101, 115, 116, 49, 46, 120, 109, 108, 0, 0, 0, 0, 0, 0,
290                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
291                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
292                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
293                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
294                 0, 48, 48, 48, 48, 54, 52, 52, 0, 48, 48, 48, 48, 55, 54, 53,
295                 0, 48, 48, 48, 48, 55, 54, 53, 0, 48, 48, 48, 48, 48, 48, 48,
296                 49, 49, 52, 50, 0, 49, 48, 55, 49, 54, 53, 52, 53, 54, 50, 54,
297                 0, 48, 49, 50, 50, 54, 48, 0, 32, 48, 0, 0, 0, 0, 0, 0, 0, 0,
298                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
299                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
300                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
301                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
302                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
303                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
304                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
305                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
306                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
307                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
308                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
309                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
310                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
311                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
312                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
313                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
314                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
315         assertTrue(TarUtils.verifyCheckSum(compress117));
316 
317         byte[] invalid = { // from the testAIFF.aif file in Tika
318                 70, 79, 82, 77, 0, 0, 15, 46, 65, 73, 70, 70, 67, 79, 77, 77,
319                 0, 0, 0, 18, 0, 2, 0, 0, 3, -64, 0, 16, 64, 14, -84, 68, 0, 0,
320                 0, 0, 0, 0, 83, 83, 78, 68, 0, 0, 15, 8, 0, 0, 0, 0, 0, 0, 0,
321                 0, 0, 1, -1, -1, 0, 1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1,
322                 0, 0, 0, 0, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -1, 0, 0, 0,
323                 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0,
324                 0, 0, 0, 1, -1, -1, 0, 1, -1, -2, 0, 1, -1, -1, 0, 1, 0, 0, 0,
325                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0,
326                 2, -1, -2, 0, 2, -1, -1, 0, 0, 0, 1, -1, -1, 0, 1, -1, -1, 0,
327                 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0,
328                 0, 1, -1, -1, 0, 0, 0, 1, -1, -1, 0, 0, 0, 1, -1, -2, 0, 2,
329                 -1, -1, 0, 0, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
330                 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 1, -1, -1, 0, 2, -1, -2,
331                 0, 2, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, -1,
332                 -2, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
333                 -1, -1, 0, 1, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -1, 0, 0,
334                 0, 0, 0, 0, -1, -1, 0, 1, -1, -1, 0, 1, -1, -1, 0, 2, -1, -2,
335                 0, 1, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0, 0,
336                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0,
337                 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 0, 0, 0,
338                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 2, -1, -1, 0,
339                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 1, 0, 0, 0, 0, 0,
340                 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 2, -1, -2,
341                 0, 2, -1, -2, 0, 2, -1, -1, 0, 0, 0, 0, -1, -1, 0, 1, -1, -1,
342                 0, 1, -1, -1, 0, 1, -1, -1, 0, 1, -1, -1, 0, 1, 0, 0, 0, 0,
343                 -1, -1, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
344                 1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
345                 0, 0, 0, 0, 0, 1 };
346         assertFalse(TarUtils.verifyCheckSum(invalid));
347     }
348 
349 }