1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.commons.compress.archivers.tar;
21
22 import static java.nio.charset.StandardCharsets.UTF_8;
23 import static org.apache.commons.compress.AbstractTest.getFile;
24 import static org.apache.commons.compress.AbstractTest.getPath;
25 import static org.junit.jupiter.api.Assertions.assertEquals;
26 import static org.junit.jupiter.api.Assertions.assertNotEquals;
27 import static org.junit.jupiter.api.Assertions.assertNotNull;
28 import static org.junit.jupiter.api.Assertions.assertNull;
29 import static org.junit.jupiter.api.Assertions.assertThrows;
30 import static org.junit.jupiter.api.Assertions.assertTrue;
31 import static org.junit.jupiter.api.Assumptions.assumeTrue;
32
33 import java.io.ByteArrayInputStream;
34 import java.io.ByteArrayOutputStream;
35 import java.io.File;
36 import java.io.IOException;
37 import java.nio.charset.StandardCharsets;
38 import java.nio.file.Files;
39 import java.nio.file.attribute.FileTime;
40 import java.time.Instant;
41 import java.util.Arrays;
42 import java.util.Collections;
43 import java.util.List;
44 import java.util.Random;
45
46 import org.apache.commons.compress.AbstractTest;
47 import org.apache.commons.compress.archivers.zip.ZipEncodingHelper;
48 import org.apache.commons.lang3.StringUtils;
49 import org.apache.commons.lang3.SystemProperties;
50 import org.junit.jupiter.api.Test;
51 import org.junit.jupiter.api.condition.EnabledOnOs;
52
53 class TarArchiveEntryTest implements TarConstants {
54
55 private static final String OS = StringUtils.toRootLowerCase(SystemProperties.getOsName());
56 private static final String ROOT = OS.startsWith("windows") || OS.startsWith("netware") ? "C:\\" : "/";
57
58 private void assertGnuMagic(final TarArchiveEntry t) {
59 assertEquals(MAGIC_GNU + VERSION_GNU_SPACE, readMagic(t));
60 }
61
62 private void assertPosixMagic(final TarArchiveEntry t) {
63 assertEquals(MAGIC_POSIX + VERSION_POSIX, readMagic(t));
64 }
65
66 private TarArchiveEntry createEntryForTimeTests() {
67 final TarArchiveEntry entry = new TarArchiveEntry("./times.txt");
68 entry.addPaxHeader("size", "1");
69 entry.addPaxHeader("mtime", "1647221103.5998539");
70 entry.addPaxHeader("atime", "1647221460.7069272");
71 entry.addPaxHeader("ctime", "1647221339.7005053");
72 entry.addPaxHeader("LIBARCHIVE.creationtime", "1647221340.7235090");
73 return entry;
74 }
75
76 private String readMagic(final TarArchiveEntry t) {
77 final byte[] buf = new byte[512];
78 t.writeEntryHeader(buf);
79 return new String(buf, MAGIC_OFFSET, MAGICLEN + VERSIONLEN);
80 }
81
82 @Test
83 void testExtraPaxHeaders() throws IOException {
84 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
85 TarArchiveEntry entry = new TarArchiveEntry("./weasels");
86 try (TarArchiveOutputStream tos = new TarArchiveOutputStream(bos)) {
87 entry.addPaxHeader("APACHE.mustelida", "true");
88 entry.addPaxHeader("SCHILY.xattr.user.org.apache.weasels", "maximum weasels");
89 entry.addPaxHeader("size", "1");
90 assertEquals(2, entry.getExtraPaxHeaders().size(), "extra header count");
91 assertEquals("true", entry.getExtraPaxHeader("APACHE.mustelida"), "APACHE.mustelida");
92 assertEquals("maximum weasels", entry.getExtraPaxHeader("SCHILY.xattr.user.org.apache.weasels"), "SCHILY.xattr.user.org.apache.weasels");
93 assertEquals(entry.getSize(), 1, "size");
94
95 tos.putArchiveEntry(entry);
96 tos.write('W');
97 tos.closeArchiveEntry();
98 }
99 assertNotEquals(0, entry.getExtraPaxHeaders().size(), "should have extra headers before clear");
100 entry.clearExtraPaxHeaders();
101 assertEquals(0, entry.getExtraPaxHeaders().size(), "extra headers should be empty after clear");
102 try (TarArchiveInputStream tis = new TarArchiveInputStream(new ByteArrayInputStream(bos.toByteArray()))) {
103 entry = tis.getNextTarEntry();
104 assertNotNull(entry, "couldn't get entry");
105
106 assertEquals(2, entry.getExtraPaxHeaders().size(), "extra header count");
107 assertEquals("true", entry.getExtraPaxHeader("APACHE.mustelida"), "APACHE.mustelida");
108 assertEquals("maximum weasels", entry.getExtraPaxHeader("SCHILY.xattr.user.org.apache.weasels"), "user.org.apache.weasels");
109
110 assertEquals('W', tis.read());
111 assertTrue(tis.read() < 0, "should be at end of entry");
112
113 assertNull(tis.getNextTarEntry(), "should be at end of file");
114 }
115 }
116
117
118
119
120
121
122 @Test
123 void testFileSystemRoot() {
124 final TarArchiveEntry t = new TarArchiveEntry(new File(ROOT));
125 assertEquals("/", t.getName());
126 assertEquals(TarConstants.LF_DIR, t.getLinkFlag());
127 }
128
129 @Test
130 void testGetFileFromNonFileEntry() {
131 final TarArchiveEntry entry = new TarArchiveEntry("test.txt");
132 assertNull(entry.getFile());
133 assertNull(entry.getPath());
134 }
135
136 @Test
137 void testGetOrderedSparseHeadersRejectsOverlappingStructs() throws Exception {
138 final TarArchiveEntry te = new TarArchiveEntry("test");
139 te.fillStarSparseData(Collections.singletonMap("SCHILY.realsize", "201"));
140 te.setSparseHeaders(Arrays.asList(new TarArchiveStructSparse(10, 5), new TarArchiveStructSparse(12, 1)));
141 assertThrows(IOException.class, () -> te.getOrderedSparseHeaders());
142 }
143
144 @Test
145 void testGetOrderedSparseHeadersRejectsStructsPointingBeyondOutputEntry() throws Exception {
146 final TarArchiveEntry te = new TarArchiveEntry("test");
147 te.setSparseHeaders(Arrays.asList(new TarArchiveStructSparse(200, 2)));
148 te.fillStarSparseData(Collections.singletonMap("SCHILY.realsize", "201"));
149 assertThrows(IOException.class, () -> te.getOrderedSparseHeaders());
150 }
151
152 @Test
153 void testGetOrderedSparseHeadersRejectsStructsWithReallyBigNumbers() throws Exception {
154 final TarArchiveEntry te = new TarArchiveEntry("test");
155 te.fillStarSparseData(Collections.singletonMap("SCHILY.realsize", String.valueOf(Long.MAX_VALUE)));
156 te.setSparseHeaders(Arrays.asList(new TarArchiveStructSparse(Long.MAX_VALUE, 2)));
157 assertThrows(IOException.class, () -> te.getOrderedSparseHeaders());
158 }
159
160 @Test
161 void testGetOrderedSparseHeadersSortsAndFiltersSparseStructs() throws Exception {
162 final TarArchiveEntry te = new TarArchiveEntry("test");
163
164 te.fillStarSparseData(Collections.singletonMap("SCHILY.realsize", "201"));
165 te.setSparseHeaders(Arrays.asList(new TarArchiveStructSparse(10, 2), new TarArchiveStructSparse(20, 0), new TarArchiveStructSparse(15, 1),
166 new TarArchiveStructSparse(0, 0)));
167 final List<TarArchiveStructSparse> strs = te.getOrderedSparseHeaders();
168 assertEquals(3, strs.size());
169 assertEquals(10, strs.get(0).getOffset());
170 assertEquals(15, strs.get(1).getOffset());
171 assertEquals(20, strs.get(2).getOffset());
172 }
173
174 @Test
175 void testLinkFlagConstructor() {
176 final TarArchiveEntry t = new TarArchiveEntry("/foo", LF_GNUTYPE_LONGNAME);
177 assertGnuMagic(t);
178 assertEquals("foo", t.getName());
179 assertEquals(TarConstants.LF_GNUTYPE_LONGNAME, t.getLinkFlag());
180 }
181
182 @Test
183 void testLinkFlagConstructorWithFileFlag() {
184 final TarArchiveEntry t = new TarArchiveEntry("/foo", LF_NORMAL);
185 assertPosixMagic(t);
186 assertEquals("foo", t.getName());
187 assertEquals(TarConstants.LF_NORMAL, t.getLinkFlag());
188 }
189
190 @Test
191 void testLinkFlagConstructorWithPreserve() {
192 final TarArchiveEntry t = new TarArchiveEntry("/foo", LF_GNUTYPE_LONGNAME, true);
193 assertGnuMagic(t);
194 assertEquals("/foo", t.getName());
195 assertEquals(TarConstants.LF_GNUTYPE_LONGNAME, t.getLinkFlag());
196 }
197
198 @Test
199 @EnabledOnOs(org.junit.jupiter.api.condition.OS.LINUX)
200 void testLinuxFileInformationFromFile() throws IOException {
201 final TarArchiveEntry entry = new TarArchiveEntry(getFile("test1.xml"));
202 assertNotEquals(0, entry.getLongUserId());
203 assertNotEquals(0, entry.getLongGroupId());
204 assertNotEquals("", entry.getUserName());
205 }
206
207 @Test
208 @EnabledOnOs(org.junit.jupiter.api.condition.OS.LINUX)
209 void testLinuxFileInformationFromPath() throws IOException {
210 final TarArchiveEntry entry = new TarArchiveEntry(getPath("test1.xml"));
211 assertNotEquals(0, entry.getLongUserId());
212 assertNotEquals(0, entry.getLongGroupId());
213 assertNotEquals("", entry.getUserName());
214 }
215
216 @Test
217 void testMaxFileSize() {
218 final TarArchiveEntry t = new TarArchiveEntry("");
219 t.setSize(0);
220 t.setSize(1);
221 assertThrows(IllegalArgumentException.class, () -> t.setSize(-1));
222 t.setSize(077777777777L);
223 t.setSize(0100000000000L);
224 }
225
226 @Test
227 void testNegativeOffsetInConstructorNotAllowed() {
228
229 final byte[] entryContent = (
230 "test1.xml\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
231 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
232 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
233 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
234 + "\u00000000644\u00000000765\u00000000765\u000000000001142\u000010716545626\u0000012260\u0000 0\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
235 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
236 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
237 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
238 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
239 + "\u0000ustar \u0000tcurdt\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
240 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000tcurdt\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
241 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
242 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
243 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
244 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
245 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
246 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
247 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
248 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
249 + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000").getBytes(UTF_8);
250
251 assertThrows(IllegalArgumentException.class,
252 () -> new TarArchiveEntry(entryContent, ZipEncodingHelper.getZipEncoding(StandardCharsets.ISO_8859_1.name()), false, -1));
253 }
254
255 @Test
256 void testNegativeOffsetInSetterNotAllowed() {
257 assertThrows(IllegalArgumentException.class, () -> new TarArchiveEntry("test").setDataOffset(-1));
258 }
259
260 @Test
261 void testPaxTimeFieldsForInvalidValues() {
262 final String[] headerNames = { "LIBARCHIVE.creationtime", "atime", "mtime", "ctime" };
263
264 final String[] testValues = {
265
266 new Random().nextLong() + "." + String.join("",
267 Collections.nCopies(15000, String.valueOf(Long.MAX_VALUE))),
268
269 "9e9999999",
270 "9E9999999",
271
272 String.valueOf(Long.MAX_VALUE),
273 String.valueOf(Long.MIN_VALUE)
274 };
275
276
277 final TarArchiveEntry entry = new TarArchiveEntry("test.txt");
278 for (final String name : headerNames) {
279 for (final String value : testValues) {
280 final Exception exp = assertThrows(IllegalArgumentException.class, () -> entry.addPaxHeader(name, value));
281 assertTrue(exp.getCause().getMessage().startsWith("Corrupted PAX header. Time field value is invalid"));
282 }
283 }
284 }
285
286 @Test
287 void testPreservesDriveSpecOnWindowsAndNetwareIfAskedTo() {
288 assumeTrue("C:\\".equals(ROOT));
289 TarArchiveEntry t = new TarArchiveEntry(ROOT + "foo.txt", true);
290 assertEquals("C:/foo.txt", t.getName());
291 assertEquals(TarConstants.LF_NORMAL, t.getLinkFlag());
292 t = new TarArchiveEntry(ROOT + "foo.txt", LF_GNUTYPE_LONGNAME, true);
293 assertEquals("C:/foo.txt", t.getName());
294 assertEquals(TarConstants.LF_GNUTYPE_LONGNAME, t.getLinkFlag());
295 }
296
297 @Test
298 void testShouldNotWriteTimePaxHeadersByDefault() throws IOException {
299 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
300 try (TarArchiveOutputStream tos = new TarArchiveOutputStream(bos)) {
301 final TarArchiveEntry entry = createEntryForTimeTests();
302 tos.putArchiveEntry(entry);
303 tos.write('W');
304 tos.closeArchiveEntry();
305 }
306 try (TarArchiveInputStream tis = new TarArchiveInputStream(new ByteArrayInputStream(bos.toByteArray()))) {
307 final TarArchiveEntry entry = tis.getNextTarEntry();
308 assertNotNull(entry, "couldn't get entry");
309
310 assertEquals(0, entry.getExtraPaxHeaders().size(), "extra header count");
311 assertNull(entry.getExtraPaxHeader("mtime"), "mtime");
312 assertNull(entry.getExtraPaxHeader("atime"), "atime");
313 assertNull(entry.getExtraPaxHeader("ctime"), "ctime");
314 assertNull(entry.getExtraPaxHeader("LIBARCHIVE.creationtime"), "birthtime");
315 assertEquals(toFileTime("2022-03-14T01:25:03Z"), entry.getLastModifiedTime(), "mtime");
316 assertNull(entry.getLastAccessTime(), "atime");
317 assertNull(entry.getStatusChangeTime(), "ctime");
318 assertNull(entry.getCreationTime(), "birthtime");
319
320 assertEquals('W', tis.read());
321 assertTrue(tis.read() < 0, "should be at end of entry");
322
323 assertNull(tis.getNextTarEntry(), "should be at end of file");
324 }
325 }
326
327 @Test
328 void testShouldParseTimePaxHeadersAndNotCountAsExtraPaxHeaders() {
329 final TarArchiveEntry entry = createEntryForTimeTests();
330 assertEquals(0, entry.getExtraPaxHeaders().size(), "extra header count");
331 assertNull(entry.getExtraPaxHeader("size"), "size");
332 assertNull(entry.getExtraPaxHeader("mtime"), "mtime");
333 assertNull(entry.getExtraPaxHeader("atime"), "atime");
334 assertNull(entry.getExtraPaxHeader("ctime"), "ctime");
335 assertNull(entry.getExtraPaxHeader("LIBARCHIVE.creationtime"), "birthtime");
336 assertEquals(entry.getSize(), 1, "size");
337 assertEquals(toFileTime("2022-03-14T01:25:03.599853900Z"), entry.getLastModifiedTime(), "mtime");
338 assertEquals(toFileTime("2022-03-14T01:31:00.706927200Z"), entry.getLastAccessTime(), "atime");
339 assertEquals(toFileTime("2022-03-14T01:28:59.700505300Z"), entry.getStatusChangeTime(), "ctime");
340 assertEquals(toFileTime("2022-03-14T01:29:00.723509000Z"), entry.getCreationTime(), "birthtime");
341 }
342
343 @Test
344 void testShouldWriteTimesAsPaxHeadersForPosixMode() throws IOException {
345 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
346 try (TarArchiveOutputStream tos = new TarArchiveOutputStream(bos)) {
347 final TarArchiveEntry entry = createEntryForTimeTests();
348 tos.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);
349 tos.putArchiveEntry(entry);
350 tos.write('W');
351 tos.closeArchiveEntry();
352 }
353 try (TarArchiveInputStream tis = new TarArchiveInputStream(new ByteArrayInputStream(bos.toByteArray()))) {
354 final TarArchiveEntry entry = tis.getNextTarEntry();
355 assertNotNull(entry, "couldn't get entry");
356
357 assertEquals(0, entry.getExtraPaxHeaders().size(), "extra header count");
358 assertNull(entry.getExtraPaxHeader("mtime"), "mtime");
359 assertNull(entry.getExtraPaxHeader("atime"), "atime");
360 assertNull(entry.getExtraPaxHeader("ctime"), "ctime");
361 assertNull(entry.getExtraPaxHeader("LIBARCHIVE.creationtime"), "birthtime");
362 assertEquals(toFileTime("2022-03-14T01:25:03.599853900Z"), entry.getLastModifiedTime(), "mtime");
363 assertEquals(toFileTime("2022-03-14T01:31:00.706927200Z"), entry.getLastAccessTime(), "atime");
364 assertEquals(toFileTime("2022-03-14T01:28:59.700505300Z"), entry.getStatusChangeTime(), "ctime");
365 assertEquals(toFileTime("2022-03-14T01:29:00.723509000Z"), entry.getCreationTime(), "birthtime");
366
367 assertEquals('W', tis.read());
368 assertTrue(tis.read() < 0, "should be at end of entry");
369
370 assertNull(tis.getNextTarEntry(), "should be at end of file");
371 }
372 }
373
374 @Test
375 void testShouldWriteTimesAsPaxHeadersForPosixModeAndCreationTimeShouldBeUsedAsCtime() throws IOException {
376 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
377 try (TarArchiveOutputStream tos = new TarArchiveOutputStream(bos)) {
378 final TarArchiveEntry entry = createEntryForTimeTests();
379 entry.setStatusChangeTime(null);
380 tos.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);
381 tos.putArchiveEntry(entry);
382 tos.write('W');
383 tos.closeArchiveEntry();
384 }
385 try (TarArchiveInputStream tis = new TarArchiveInputStream(new ByteArrayInputStream(bos.toByteArray()))) {
386 final TarArchiveEntry entry = tis.getNextTarEntry();
387 assertNotNull(entry, "couldn't get entry");
388
389 assertEquals(0, entry.getExtraPaxHeaders().size(), "extra header count");
390 assertNull(entry.getExtraPaxHeader("mtime"), "mtime");
391 assertNull(entry.getExtraPaxHeader("atime"), "atime");
392 assertNull(entry.getExtraPaxHeader("ctime"), "ctime");
393 assertNull(entry.getExtraPaxHeader("LIBARCHIVE.creationtime"), "birthtime");
394 assertEquals(toFileTime("2022-03-14T01:25:03.599853900Z"), entry.getLastModifiedTime(), "mtime");
395 assertEquals(toFileTime("2022-03-14T01:31:00.706927200Z"), entry.getLastAccessTime(), "atime");
396 assertEquals(toFileTime("2022-03-14T01:29:00.723509000Z"), entry.getStatusChangeTime(), "ctime");
397 assertEquals(toFileTime("2022-03-14T01:29:00.723509000Z"), entry.getCreationTime(), "birthtime");
398
399 assertEquals('W', tis.read());
400 assertTrue(tis.read() < 0, "should be at end of entry");
401
402 assertNull(tis.getNextTarEntry(), "should be at end of file");
403 }
404 }
405
406 @Test
407 void testShouldWriteTimesForStarMode() throws IOException {
408 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
409 try (TarArchiveOutputStream tos = new TarArchiveOutputStream(bos)) {
410 final TarArchiveEntry entry = createEntryForTimeTests();
411 tos.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_STAR);
412 tos.putArchiveEntry(entry);
413 tos.write('W');
414 tos.closeArchiveEntry();
415 }
416 try (TarArchiveInputStream tis = new TarArchiveInputStream(new ByteArrayInputStream(bos.toByteArray()))) {
417 final TarArchiveEntry entry = tis.getNextTarEntry();
418 assertNotNull(entry, "couldn't get entry");
419
420 assertEquals(0, entry.getExtraPaxHeaders().size(), "extra header count");
421 assertNull(entry.getExtraPaxHeader("mtime"), "mtime");
422 assertNull(entry.getExtraPaxHeader("atime"), "atime");
423 assertNull(entry.getExtraPaxHeader("ctime"), "ctime");
424 assertNull(entry.getExtraPaxHeader("LIBARCHIVE.creationtime"), "birthtime");
425 assertEquals(toFileTime("2022-03-14T01:25:03Z"), entry.getLastModifiedTime(), "mtime");
426 assertEquals(toFileTime("2022-03-14T01:31:00Z"), entry.getLastAccessTime(), "atime");
427 assertEquals(toFileTime("2022-03-14T01:28:59Z"), entry.getStatusChangeTime(), "ctime");
428 assertNull(entry.getCreationTime(), "birthtime");
429
430 assertEquals('W', tis.read());
431 assertTrue(tis.read() < 0, "should be at end of entry");
432
433 assertNull(tis.getNextTarEntry(), "should be at end of file");
434 }
435 }
436
437 @Test
438 void testTarFileWithFSRoot() throws IOException {
439 final File f = File.createTempFile("taetest", ".tar");
440 TarArchiveEntry entry = new TarArchiveEntry(new File(ROOT));
441 try {
442 try (TarArchiveOutputStream tout = new TarArchiveOutputStream(Files.newOutputStream(f.toPath()))) {
443 tout.putArchiveEntry(entry);
444 tout.closeArchiveEntry();
445 entry = new TarArchiveEntry(new File(new File(ROOT), "foo.txt"));
446 entry.setSize(6);
447 tout.putArchiveEntry(entry);
448 tout.write(new byte[] { 'h', 'e', 'l', 'l', 'o', ' ' });
449 tout.closeArchiveEntry();
450 entry = new TarArchiveEntry(new File(new File(ROOT), "bar.txt").getAbsolutePath());
451 entry.setSize(5);
452 tout.putArchiveEntry(entry);
453 tout.write(new byte[] { 'w', 'o', 'r', 'l', 'd' });
454 tout.closeArchiveEntry();
455 entry = new TarArchiveEntry("dummy");
456 entry.setName(new File(new File(ROOT), "baz.txt").getAbsolutePath());
457 entry.setSize(1);
458 tout.putArchiveEntry(entry);
459 tout.write(new byte[] { '!' });
460 tout.closeArchiveEntry();
461 }
462 try (TarArchiveInputStream tin = new TarArchiveInputStream(Files.newInputStream(f.toPath()))) {
463
464 entry = tin.getNextTarEntry();
465 assertNotNull(entry);
466 assertEquals("/", entry.getName());
467 assertEquals(TarConstants.LF_DIR, entry.getLinkFlag());
468 assertTrue(entry.isCheckSumOK());
469 assertTrue(entry.isTypeFlagUstar());
470 entry = tin.getNextTarEntry();
471 assertNotNull(entry);
472 assertEquals("foo.txt", entry.getName());
473 assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag());
474 assertTrue(entry.isCheckSumOK());
475 assertTrue(entry.isTypeFlagUstar());
476 entry = tin.getNextTarEntry();
477 assertNotNull(entry);
478 assertEquals("bar.txt", entry.getName());
479 assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag());
480 assertTrue(entry.isCheckSumOK());
481 assertTrue(entry.isTypeFlagUstar());
482 entry = tin.getNextTarEntry();
483 assertNotNull(entry);
484 assertEquals("baz.txt", entry.getName());
485 assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag());
486 assertTrue(entry.isCheckSumOK());
487 assertTrue(entry.isTypeFlagUstar());
488 }
489 } finally {
490 AbstractTest.forceDelete(f);
491 }
492 }
493
494 @Test
495 @EnabledOnOs(org.junit.jupiter.api.condition.OS.WINDOWS)
496 void testWindowsFileInformationFromFile() throws IOException {
497 final TarArchiveEntry entry = new TarArchiveEntry(getFile("test1.xml"));
498 assertNotEquals("", entry.getUserName());
499 assertTrue(entry.isTypeFlagUstar());
500 }
501
502 @Test
503 @EnabledOnOs(org.junit.jupiter.api.condition.OS.WINDOWS)
504 void testWindowsFileInformationFromPath() throws IOException {
505 final TarArchiveEntry entry = new TarArchiveEntry(getPath("test1.xml"));
506 assertNotEquals("", entry.getUserName());
507 assertTrue(entry.isTypeFlagUstar());
508 }
509
510 private FileTime toFileTime(final String text) {
511 return FileTime.from(Instant.parse(text));
512 }
513 }