1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.compress.archivers.tar;
19
20 import static java.nio.charset.StandardCharsets.UTF_8;
21 import static org.junit.jupiter.api.Assertions.assertEquals;
22 import static org.junit.jupiter.api.Assertions.assertFalse;
23 import static org.junit.jupiter.api.Assertions.assertThrows;
24 import static org.junit.jupiter.api.Assertions.assertTrue;
25
26 import java.io.ByteArrayInputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.UncheckedIOException;
30 import java.nio.charset.StandardCharsets;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36
37 import org.apache.commons.compress.AbstractTest;
38 import org.apache.commons.compress.archivers.zip.ZipEncoding;
39 import org.apache.commons.compress.archivers.zip.ZipEncodingHelper;
40 import org.apache.commons.compress.utils.ByteUtils;
41 import org.junit.jupiter.api.Test;
42
43 public class TarUtilsTest extends AbstractTest {
44
45 private void checkName(final String string) {
46 final byte[] buff = new byte[100];
47 final int len = TarUtils.formatNameBytes(string, buff, 0, buff.length);
48 assertEquals(string, TarUtils.parseName(buff, 0, len));
49 }
50
51 private void checkRoundTripOctal(final long value) {
52 checkRoundTripOctal(value, TarConstants.SIZELEN);
53 }
54
55 private void checkRoundTripOctal(final long value, final int bufsize) {
56 final byte[] buffer = new byte[bufsize];
57 long parseValue;
58 TarUtils.formatLongOctalBytes(value, buffer, 0, buffer.length);
59 parseValue = TarUtils.parseOctal(buffer, 0, buffer.length);
60 assertEquals(value, parseValue);
61 }
62
63 private void checkRoundTripOctalOrBinary(final long value, final int bufsize) {
64 final byte[] buffer = new byte[bufsize];
65 long parseValue;
66 TarUtils.formatLongOctalOrBinaryBytes(value, buffer, 0, buffer.length);
67 parseValue = TarUtils.parseOctalOrBinary(buffer, 0, buffer.length);
68 assertEquals(value, parseValue);
69 }
70
71 @Test
72 public void testName() {
73 byte[] buff = new byte[20];
74 final String sb1 = "abcdefghijklmnopqrstuvwxyz";
75 int off = TarUtils.formatNameBytes(sb1, buff, 1, buff.length - 1);
76 assertEquals(off, 20);
77 String sb2 = TarUtils.parseName(buff, 1, 10);
78 assertEquals(sb2, sb1.substring(0, 10));
79 sb2 = TarUtils.parseName(buff, 1, 19);
80 assertEquals(sb2, sb1.substring(0, 19));
81 buff = new byte[30];
82 off = TarUtils.formatNameBytes(sb1, buff, 1, buff.length - 1);
83 assertEquals(off, 30);
84 sb2 = TarUtils.parseName(buff, 1, buff.length - 1);
85 assertEquals(sb1, sb2);
86 buff = new byte[] { 0, 1, 0 };
87 sb2 = TarUtils.parseName(buff, 0, 3);
88 assertEquals("", sb2);
89 }
90
91 @Test
92 public void testNegative() {
93 final byte[] buffer = new byte[22];
94 TarUtils.formatUnsignedOctalString(-1, buffer, 0, buffer.length);
95 assertEquals("1777777777777777777777", new String(buffer, UTF_8));
96 }
97
98 @Test
99 public void testOverflow() {
100 final byte[] buffer = new byte[8 - 1];
101 TarUtils.formatUnsignedOctalString(07777777L, buffer, 0, buffer.length);
102 assertEquals("7777777", new String(buffer, UTF_8));
103 assertThrows(IllegalArgumentException.class, () -> TarUtils.formatUnsignedOctalString(017777777L, buffer, 0, buffer.length),
104 "Should have cause IllegalArgumentException");
105 }
106
107 @Test
108 public void testParseFromPAX01SparseHeaders() throws Exception {
109 final String map = "0,10,20,0,20,5";
110 final List<TarArchiveStructSparse> sparse = TarUtils.parseFromPAX01SparseHeaders(map);
111 assertEquals(3, sparse.size());
112 assertEquals(0, sparse.get(0).getOffset());
113 assertEquals(10, sparse.get(0).getNumbytes());
114 assertEquals(20, sparse.get(1).getOffset());
115 assertEquals(0, sparse.get(1).getNumbytes());
116 assertEquals(20, sparse.get(2).getOffset());
117 assertEquals(5, sparse.get(2).getNumbytes());
118 }
119
120 @Test
121 public void testParseFromPAX01SparseHeadersRejectsNegativeNumbytes() throws Exception {
122 assertThrows(IOException.class, () -> TarUtils.parseFromPAX01SparseHeaders("0,10,20,0,20,-5"));
123 }
124
125 @Test
126 public void testParseFromPAX01SparseHeadersRejectsNegativeOffset() throws Exception {
127 assertThrows(IOException.class, () -> TarUtils.parseFromPAX01SparseHeaders("0,10,20,0,-2,5"));
128 }
129
130 @Test
131 public void testParseFromPAX01SparseHeadersRejectsNonNumericNumbytes() throws Exception {
132 assertThrows(IOException.class, () -> TarUtils.parseFromPAX01SparseHeaders("0,10,20,0,20,b"));
133 }
134
135 @Test
136 public void testParseFromPAX01SparseHeadersRejectsNonNumericOffset() throws Exception {
137 assertThrows(IOException.class, () -> TarUtils.parseFromPAX01SparseHeaders("0,10,20,0,2a,5"));
138 }
139
140 @Test
141 public void testParseFromPAX01SparseHeadersRejectsOddNumberOfEntries() throws Exception {
142 final String map = "0,10,20,0,20";
143 assertThrows(IOException.class, () -> TarUtils.parseFromPAX01SparseHeaders(map));
144 }
145
146 @Test
147 public void testParseOctal() {
148 long value;
149 byte[] buffer;
150 final long MAX_OCTAL = 077777777777L;
151 final long MAX_OCTAL_OVERFLOW = 0777777777777L;
152 final String maxOctal = "777777777777";
153 buffer = maxOctal.getBytes(UTF_8);
154 value = TarUtils.parseOctal(buffer, 0, buffer.length);
155 assertEquals(MAX_OCTAL_OVERFLOW, value);
156 buffer[buffer.length - 1] = ' ';
157 value = TarUtils.parseOctal(buffer, 0, buffer.length);
158 assertEquals(MAX_OCTAL, value);
159 buffer[buffer.length - 1] = 0;
160 value = TarUtils.parseOctal(buffer, 0, buffer.length);
161 assertEquals(MAX_OCTAL, value);
162 buffer = new byte[] { 0, 0 };
163 value = TarUtils.parseOctal(buffer, 0, buffer.length);
164 assertEquals(0, value);
165 buffer = new byte[] { 0, ' ' };
166 value = TarUtils.parseOctal(buffer, 0, buffer.length);
167 assertEquals(0, value);
168 buffer = new byte[] { ' ', 0 };
169 value = TarUtils.parseOctal(buffer, 0, buffer.length);
170 assertEquals(0, value);
171 }
172
173 @Test
174 public void testParseOctalCompress330() {
175 final long expected = 0100000;
176 final byte[] buffer = { 32, 32, 32, 32, 32, 49, 48, 48, 48, 48, 48, 32 };
177 assertEquals(expected, TarUtils.parseOctalOrBinary(buffer, 0, buffer.length));
178 }
179
180 @Test
181 public void testParseOctalEmbeddedSpace() {
182 final byte[] buffer4 = " 0 07 ".getBytes(UTF_8);
183 assertThrows(IllegalArgumentException.class, () -> TarUtils.parseOctal(buffer4, 0, buffer4.length),
184 "Expected IllegalArgumentException - embedded space");
185 }
186
187 @Test
188 public void testParseOctalInvalid() {
189 final byte[] buffer1 = ByteUtils.EMPTY_BYTE_ARRAY;
190 assertThrows(IllegalArgumentException.class, () -> TarUtils.parseOctal(buffer1, 0, buffer1.length),
191 "Expected IllegalArgumentException - should be at least 2 bytes long");
192
193 final byte[] buffer2 = { 0 };
194 assertThrows(IllegalArgumentException.class, () -> TarUtils.parseOctal(buffer2, 0, buffer2.length),
195 "Expected IllegalArgumentException - should be at least 2 bytes long");
196
197 final byte[] buffer3 = "abcdef ".getBytes(UTF_8);
198 assertThrows(IllegalArgumentException.class, () -> TarUtils.parseOctal(buffer3, 0, buffer3.length), "Expected IllegalArgumentException");
199
200 final byte[] buffer5 = " 0\00007 ".getBytes(UTF_8);
201 assertThrows(IllegalArgumentException.class, () -> TarUtils.parseOctal(buffer5, 0, buffer5.length), "Expected IllegalArgumentException - embedded NUL");
202 }
203
204 @Test
205 public void testParsePAX01SparseHeadersRejectsOddNumberOfEntries() {
206 final String map = "0,10,20,0,20";
207 assertThrows(UncheckedIOException.class, () -> TarUtils.parsePAX01SparseHeaders(map));
208 }
209
210 @Test
211 public void testParsePAX1XSparseHeaders() throws Exception {
212 final byte[] header = ("1\n" + "0\n" + "20\n").getBytes();
213 final byte[] block = new byte[512];
214 System.arraycopy(header, 0, block, 0, header.length);
215 try (ByteArrayInputStream in = new ByteArrayInputStream(block)) {
216 final List<TarArchiveStructSparse> sparse = TarUtils.parsePAX1XSparseHeaders(in, 512);
217 assertEquals(1, sparse.size());
218 assertEquals(0, sparse.get(0).getOffset());
219 assertEquals(20, sparse.get(0).getNumbytes());
220 assertEquals(-1, in.read());
221 }
222 }
223
224 @Test
225 public void testParsePAX1XSparseHeadersRejectsIncompleteLastLine() throws Exception {
226 final byte[] header = ("1\n" + "0\n" + "20").getBytes();
227 try (ByteArrayInputStream in = new ByteArrayInputStream(header)) {
228 assertThrows(IOException.class, () -> TarUtils.parsePAX1XSparseHeaders(in, 512));
229 }
230 }
231
232 @Test
233 public void testParsePAX1XSparseHeadersRejectsNegativeNumberOfEntries() throws Exception {
234 final byte[] header = ("111111111111111111111111111111111111111111111111111111111111111\n" + "0\n" + "20\n").getBytes();
235 final byte[] block = new byte[512];
236 System.arraycopy(header, 0, block, 0, header.length);
237 try (ByteArrayInputStream in = new ByteArrayInputStream(block)) {
238 assertThrows(IOException.class, () -> TarUtils.parsePAX1XSparseHeaders(in, 512));
239 }
240 }
241
242 @Test
243 public void testParsePAX1XSparseHeadersRejectsNegativeNumbytes() throws Exception {
244 final byte[] header = ("1\n" + "0\n" + "111111111111111111111111111111111111111111111111111111111111111\n").getBytes();
245 final byte[] block = new byte[512];
246 System.arraycopy(header, 0, block, 0, header.length);
247 try (ByteArrayInputStream in = new ByteArrayInputStream(block)) {
248 assertThrows(IOException.class, () -> TarUtils.parsePAX1XSparseHeaders(in, 512));
249 }
250 }
251
252 @Test
253 public void testParsePAX1XSparseHeadersRejectsNegativeOffset() throws Exception {
254 final byte[] header = ("1\n" + "111111111111111111111111111111111111111111111111111111111111111\n" + "20\n").getBytes();
255 final byte[] block = new byte[512];
256 System.arraycopy(header, 0, block, 0, header.length);
257 try (ByteArrayInputStream in = new ByteArrayInputStream(block)) {
258 assertThrows(IOException.class, () -> TarUtils.parsePAX1XSparseHeaders(in, 512));
259 }
260 }
261
262 @Test
263 public void testParsePAX1XSparseHeadersRejectsNonNumericNumberOfEntries() throws Exception {
264 final byte[] header = ("x\n" + "0\n" + "20\n").getBytes();
265 final byte[] block = new byte[512];
266 System.arraycopy(header, 0, block, 0, header.length);
267 try (ByteArrayInputStream in = new ByteArrayInputStream(block)) {
268 assertThrows(IOException.class, () -> TarUtils.parsePAX1XSparseHeaders(in, 512));
269 }
270 }
271
272 @Test
273 public void testParsePAX1XSparseHeadersRejectsNonNumericNumbytes() throws Exception {
274 final byte[] header = ("1\n" + "0\n" + "2x\n").getBytes();
275 final byte[] block = new byte[512];
276 System.arraycopy(header, 0, block, 0, header.length);
277 try (ByteArrayInputStream in = new ByteArrayInputStream(block)) {
278 assertThrows(IOException.class, () -> TarUtils.parsePAX1XSparseHeaders(in, 512));
279 }
280 }
281
282 @Test
283 public void testParsePAX1XSparseHeadersRejectsNonNumericOffset() throws Exception {
284 final byte[] header = ("1\n" + "x\n" + "20\n").getBytes();
285 final byte[] block = new byte[512];
286 System.arraycopy(header, 0, block, 0, header.length);
287 try (ByteArrayInputStream in = new ByteArrayInputStream(block)) {
288 assertThrows(IOException.class, () -> TarUtils.parsePAX1XSparseHeaders(in, 512));
289 }
290 }
291
292 @Test
293 public void testParseSparse() {
294 final long expectedOffset = 0100000;
295 final long expectedNumbytes = 0111000;
296 final byte[] buffer = { ' ', ' ', ' ', ' ', ' ', '0', '1', '0', '0', '0', '0', '0',
297 ' ', ' ', ' ', ' ', ' ', '0', '1', '1', '1', '0', '0', '0' };
298 final TarArchiveStructSparse sparse = TarUtils.parseSparse(buffer, 0);
299 assertEquals(sparse.getOffset(), expectedOffset);
300 assertEquals(sparse.getNumbytes(), expectedNumbytes);
301 }
302
303 @Test
304 public void testParseTarWithSpecialPaxHeaders() throws IOException {
305 try (InputStream in = newInputStream("COMPRESS-530-fail.tar");
306 TarArchiveInputStream archive = new TarArchiveInputStream(in)) {
307 assertThrows(IOException.class, () -> archive.getNextEntry());
308
309 }
310 }
311
312 @Test
313 public void testPaxHeaderEntryWithEmptyValueRemovesKey() throws Exception {
314 final Map<String, String> headers = TarUtils.parsePaxHeaders(new ByteArrayInputStream("11 foo=bar\n7 foo=\n".getBytes(UTF_8)), null, new HashMap<>());
315 assertEquals(0, headers.size());
316 }
317
318 @Test
319 public void testReadNegativeBinary12Byte() {
320 final byte[] b = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
321 (byte) 0xf1, (byte) 0xef, };
322 assertEquals(-3601L, TarUtils.parseOctalOrBinary(b, 0, 12));
323 }
324
325 @Test
326 public void testReadNegativeBinary8Byte() {
327 final byte[] b = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xf1, (byte) 0xef, };
328 assertEquals(-3601L, TarUtils.parseOctalOrBinary(b, 0, 8));
329 }
330
331 @Test
332 public void testReadNonAsciiPaxHeader() throws Exception {
333 final String ae = "\u00e4";
334 final String line = "11 path=" + ae + "\n";
335 assertEquals(11, line.getBytes(UTF_8).length);
336 final Map<String, String> headers = TarUtils.parsePaxHeaders(new ByteArrayInputStream(line.getBytes(UTF_8)), null, new HashMap<>());
337 assertEquals(1, headers.size());
338 assertEquals(ae, headers.get("path"));
339 }
340
341 @Test
342 public void testReadPax00SparseHeader() throws Exception {
343 final String header = "23 GNU.sparse.offset=0\n26 GNU.sparse.numbytes=10\n";
344 final List<TarArchiveStructSparse> sparseHeaders = new ArrayList<>();
345 TarUtils.parsePaxHeaders(new ByteArrayInputStream(header.getBytes(UTF_8)), sparseHeaders, Collections.emptyMap());
346 assertEquals(1, sparseHeaders.size());
347 assertEquals(0, sparseHeaders.get(0).getOffset());
348 assertEquals(10, sparseHeaders.get(0).getNumbytes());
349 }
350
351 @Test
352 public void testReadPax00SparseHeaderMakesNumbytesOptional() throws Exception {
353 final String header = "23 GNU.sparse.offset=0\n24 GNU.sparse.offset=10\n";
354 final List<TarArchiveStructSparse> sparseHeaders = new ArrayList<>();
355 TarUtils.parsePaxHeaders(new ByteArrayInputStream(header.getBytes(UTF_8)), sparseHeaders, Collections.emptyMap());
356 assertEquals(2, sparseHeaders.size());
357 assertEquals(0, sparseHeaders.get(0).getOffset());
358 assertEquals(0, sparseHeaders.get(0).getNumbytes());
359 assertEquals(10, sparseHeaders.get(1).getOffset());
360 assertEquals(0, sparseHeaders.get(1).getNumbytes());
361 }
362
363 @Test
364 public void testReadPax00SparseHeaderRejectsNegativeNumbytes() throws Exception {
365 final String header = "23 GNU.sparse.offset=0\n26 GNU.sparse.numbytes=-1\n";
366 assertThrows(IOException.class, () -> TarUtils.parsePaxHeaders(new ByteArrayInputStream(header.getBytes(UTF_8)), null, Collections.emptyMap()));
367 }
368
369 @Test
370 public void testReadPax00SparseHeaderRejectsNegativeOffset() throws Exception {
371 final String header = "24 GNU.sparse.offset=-1\n26 GNU.sparse.numbytes=10\n";
372 assertThrows(IOException.class, () -> TarUtils.parsePaxHeaders(new ByteArrayInputStream(header.getBytes(UTF_8)), null, Collections.emptyMap()));
373 }
374
375 @Test
376 public void testReadPax00SparseHeaderRejectsNonNumericNumbytes() throws Exception {
377 final String header = "23 GNU.sparse.offset=0\n26 GNU.sparse.numbytes=1a\n";
378 assertThrows(IOException.class, () -> TarUtils.parsePaxHeaders(new ByteArrayInputStream(header.getBytes(UTF_8)), null, Collections.emptyMap()));
379 }
380
381 @Test
382 public void testReadPax00SparseHeaderRejectsNonNumericOffset() throws Exception {
383 final String header = "23 GNU.sparse.offset=a\n26 GNU.sparse.numbytes=10\n";
384 assertThrows(IOException.class, () -> TarUtils.parsePaxHeaders(new ByteArrayInputStream(header.getBytes(UTF_8)), null, Collections.emptyMap()));
385 }
386
387 @Test
388 public void testReadPaxHeaderWithEmbeddedNewline() throws Exception {
389 final Map<String, String> headers = TarUtils.parsePaxHeaders(new ByteArrayInputStream("28 comment=line1\nline2\nand3\n".getBytes(UTF_8)), null,
390 new HashMap<>());
391 assertEquals(1, headers.size());
392 assertEquals("line1\nline2\nand3", headers.get("comment"));
393 }
394
395 @Test
396 public void testReadPaxHeaderWithoutTrailingNewline() throws Exception {
397 assertThrows(IOException.class,
398 () -> TarUtils.parsePaxHeaders(new ByteArrayInputStream("30 atime=1321711775.9720594634".getBytes(UTF_8)), null, Collections.emptyMap()));
399 }
400
401 @Test
402 public void testReadSimplePaxHeader() throws Exception {
403 final Map<String, String> headers = TarUtils.parsePaxHeaders(new ByteArrayInputStream("30 atime=1321711775.972059463\n".getBytes(UTF_8)), null,
404 new HashMap<>());
405 assertEquals(1, headers.size());
406 assertEquals("1321711775.972059463", headers.get("atime"));
407 }
408
409 @Test
410 public void testReadSparseStructsBinary() throws Exception {
411 final byte[] header = { (byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, };
412 assertEquals(24, header.length);
413 final List<TarArchiveStructSparse> sparse = TarUtils.readSparseStructs(header, 0, 1);
414 assertEquals(1, sparse.size());
415 assertEquals(0, sparse.get(0).getOffset());
416 assertEquals(7, sparse.get(0).getNumbytes());
417 }
418
419 @Test
420 public void testReadSparseStructsOctal() throws Exception {
421 final byte[] header = "00000000000 00000000007 ".getBytes();
422 assertEquals(24, header.length);
423 final List<TarArchiveStructSparse> sparse = TarUtils.readSparseStructs(header, 0, 1);
424 assertEquals(1, sparse.size());
425 assertEquals(0, sparse.get(0).getOffset());
426 assertEquals(7, sparse.get(0).getNumbytes());
427 }
428
429 @Test
430 public void testReadSparseStructsRejectsNegativeNumbytes() throws Exception {
431 final byte[] header = { (byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
432 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, };
433 assertThrows(IOException.class, () -> TarUtils.readSparseStructs(header, 0, 1));
434 }
435
436 @Test
437 public void testReadSparseStructsRejectsNegativeOffset() throws Exception {
438 final byte[] header = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
439 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, };
440 assertThrows(IOException.class, () -> TarUtils.readSparseStructs(header, 0, 1));
441 }
442
443 @Test
444 public void testReadSparseStructsRejectsNonNumericNumbytes() throws Exception {
445 final byte[] header = "00000000000 0000000000x ".getBytes();
446 assertThrows(IOException.class, () -> TarUtils.readSparseStructs(header, 0, 1));
447 }
448
449 @Test
450 public void testReadSparseStructsRejectsNonNumericOffset() throws Exception {
451 final byte[] header = "0000000000x 00000000007 ".getBytes();
452 assertThrows(IOException.class, () -> TarUtils.readSparseStructs(header, 0, 1));
453 }
454
455 @Test
456 public void testRoundEncoding() throws Exception {
457
458 final ZipEncoding enc = ZipEncodingHelper.getZipEncoding(StandardCharsets.ISO_8859_1.name());
459
460 final String s = "0302-0601-3\u00b1\u00b1\u00b1F06\u00b1W220\u00b1ZB\u00b1LALALA\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1CAN"
461 + "\u00b1\u00b1DC\u00b1\u00b1\u00b104\u00b1060302\u00b1MOE.model";
462
463 final byte[] buff = new byte[100];
464 final int len = TarUtils.formatNameBytes(s, buff, 0, buff.length, enc);
465 assertEquals(s, TarUtils.parseName(buff, 0, len, enc));
466 }
467
468 @Test
469 public void testRoundTripNames() {
470 checkName("");
471 checkName("The quick brown fox\n");
472 checkName("\177");
473
474 }
475
476 @Test
477 public void testRoundTripOctal() {
478 checkRoundTripOctal(0);
479 checkRoundTripOctal(1);
480
481 checkRoundTripOctal(TarConstants.MAXSIZE);
482
483
484 checkRoundTripOctal(0, TarConstants.UIDLEN);
485 checkRoundTripOctal(1, TarConstants.UIDLEN);
486 checkRoundTripOctal(TarConstants.MAXID, 8);
487 }
488
489 private void testRoundTripOctalOrBinary(final int length) {
490 checkRoundTripOctalOrBinary(0, length);
491 checkRoundTripOctalOrBinary(1, length);
492 checkRoundTripOctalOrBinary(TarConstants.MAXSIZE, length);
493 checkRoundTripOctalOrBinary(-1, length);
494 checkRoundTripOctalOrBinary(0xffffffffffffffL, length);
495 checkRoundTripOctalOrBinary(-0xffffffffffffffL, length);
496 }
497
498 @Test
499 public void testRoundTripOctalOrBinary12() {
500 testRoundTripOctalOrBinary(12);
501 checkRoundTripOctalOrBinary(Long.MAX_VALUE, 12);
502 checkRoundTripOctalOrBinary(Long.MIN_VALUE + 1, 12);
503 }
504
505 @Test
506 public void testRoundTripOctalOrBinary8() {
507 testRoundTripOctalOrBinary(8);
508 }
509
510 @Test
511 public void testRoundTripOctalOrBinary8_ValueTooBigForBinary() {
512 final IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> checkRoundTripOctalOrBinary(Long.MAX_VALUE, 8),
513 "Should throw exception - value is too long to fit buffer of this len");
514 assertEquals("Value 9223372036854775807 is too large for 8 byte field.", e.getMessage());
515 }
516
517 @Test
518 public void testSecondEntryWinsWhenPaxHeaderContainsDuplicateKey() throws Exception {
519 final Map<String, String> headers = TarUtils.parsePaxHeaders(new ByteArrayInputStream("11 foo=bar\n11 foo=baz\n".getBytes(UTF_8)), null,
520 new HashMap<>());
521 assertEquals(1, headers.size());
522 assertEquals("baz", headers.get("foo"));
523 }
524
525
526 @Test
527 public void testTrailers() {
528 final byte[] buffer = new byte[12];
529 TarUtils.formatLongOctalBytes(123, buffer, 0, buffer.length);
530 assertEquals(' ', buffer[buffer.length - 1]);
531 assertEquals('3', buffer[buffer.length - 2]);
532 TarUtils.formatOctalBytes(123, buffer, 0, buffer.length);
533 assertEquals(0, buffer[buffer.length - 1]);
534 assertEquals(' ', buffer[buffer.length - 2]);
535 assertEquals('3', buffer[buffer.length - 3]);
536 TarUtils.formatCheckSumOctalBytes(123, buffer, 0, buffer.length);
537 assertEquals(' ', buffer[buffer.length - 1]);
538 assertEquals(0, buffer[buffer.length - 2]);
539 assertEquals('3', buffer[buffer.length - 3]);
540 }
541
542
543 @Test
544 public void testVerifyHeaderCheckSum() {
545 final byte[] valid = {
546 116, 101, 115, 116, 49, 46, 120, 109, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
547 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
548 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 54, 52, 52, 0, 48, 48, 48, 48, 55, 54, 53, 0, 48, 48, 48, 48, 55, 54, 53, 0, 48, 48, 48, 48, 48, 48,
549 48, 49, 49, 52, 50, 0, 49, 48, 55, 49, 54, 53, 52, 53, 54, 50, 54, 0, 48, 49, 50, 50, 54, 48, 0, 32, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
550 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
551 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 117, 115, 116, 97, 114, 32,
552 32, 0, 116, 99, 117, 114, 100, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 99, 117, 114, 100, 116,
553 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
554 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
555 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
556 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
557 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
558 assertTrue(TarUtils.verifyCheckSum(valid));
559
560 final byte[] compress117 = {
561 (byte) 0x37, (byte) 0x7a, (byte) 0x43, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
562 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
563 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0x31, (byte) 0x30, (byte) 0x30, (byte) 0x37,
564 (byte) 0x37, (byte) 0x37, (byte) 0x20, (byte) 0x00, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x30, (byte) 0x20,
565 (byte) 0x00, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x30, (byte) 0x20, (byte) 0x00, (byte) 0x20, (byte) 0x20,
566 (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x31, (byte) 0x33, (byte) 0x30, (byte) 0x33, (byte) 0x33, (byte) 0x20, (byte) 0x31,
567 (byte) 0x31, (byte) 0x31, (byte) 0x31, (byte) 0x35, (byte) 0x31, (byte) 0x36, (byte) 0x36, (byte) 0x30, (byte) 0x31, (byte) 0x36, (byte) 0x20,
568 (byte) 0x20, (byte) 0x20, (byte) 0x35, (byte) 0x34, (byte) 0x31, (byte) 0x37, (byte) 0x20, (byte) 0x00, (byte) 0x30, (byte) 0x00, 0, 0, 0, 0, 0,
569 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
570 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
571 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
572 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
573 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
574 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
575 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
576 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
577 assertTrue(TarUtils.verifyCheckSum(compress117));
578
579 final byte[] invalid = {
580 70, 79, 82, 77, 0, 0, 15, 46, 65, 73, 70, 70, 67, 79, 77, 77, 0, 0, 0, 18, 0, 2, 0, 0, 3, -64, 0, 16, 64, 14, -84, 68, 0, 0, 0, 0, 0, 0, 83, 83,
581 78, 68, 0, 0, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 0, 0, 0, -1, -1, 0, 2, -1, -2,
582 0, 2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 1, -1, -2, 0, 1, -1, -1, 0, 1, 0, 0,
583 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -1, 0, 0, 0, 1, -1, -1, 0, 1, -1, -1, 0, 0, 0, 0, 0, 0, 0,
584 0, 0, 1, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0, 0, 1, -1, -1, 0, 0, 0, 1, -1, -1, 0, 0, 0, 1, -1, -2, 0, 2, -1, -1, 0, 0, 0, 0, 0, 0, -1, -1, 0, 1,
585 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 1, -1, -1, 0, 2, -1, -2, 0, 2, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
586 -1, -2, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -1, 0, 0, 0, 0, 0, 0, -1,
587 -1, 0, 1, -1, -1, 0, 1, -1, -1, 0, 2, -1, -2, 0, 1, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
588 0, 0, 1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 2, -1, -1,
589 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -2, 0,
590 2, -1, -1, 0, 0, 0, 0, -1, -1, 0, 1, -1, -1, 0, 1, -1, -1, 0, 1, -1, -1, 0, 1, -1, -1, 0, 1, 0, 0, 0, 0, -1, -1, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0,
591 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
592 assertFalse(TarUtils.verifyCheckSum(invalid));
593 }
594
595 @Test
596 public void testWriteNegativeBinary8Byte() {
597 final byte[] b = { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xf1, (byte) 0xef, };
598 assertEquals(-3601L, TarUtils.parseOctalOrBinary(b, 0, 8));
599 }
600
601 }