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   *   https://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  
20  package org.apache.commons.compress.archivers.tar;
21  
22  import static org.junit.jupiter.api.Assertions.assertEquals;
23  import static org.junit.jupiter.api.Assertions.assertNotNull;
24  import static org.junit.jupiter.api.Assertions.assertNull;
25  import static org.junit.jupiter.api.Assertions.assertTrue;
26  
27  import java.io.BufferedInputStream;
28  import java.io.InputStream;
29  import java.nio.file.Files;
30  import java.nio.file.attribute.FileTime;
31  import java.time.Instant;
32  
33  import org.apache.commons.compress.AbstractTest;
34  import org.junit.jupiter.api.Test;
35  
36  public class FileTimesIT extends AbstractTest {
37  
38      private void assertGlobalHeaders(final TarArchiveEntry e) {
39          assertEquals(5, e.getExtraPaxHeaders().size());
40          assertEquals("exustar", e.getExtraPaxHeader("SCHILY.archtype"), "SCHILY.archtype");
41          assertEquals("1647478879.579980900", e.getExtraPaxHeader("SCHILY.volhdr.dumpdate"), "SCHILY.volhdr.dumpdate");
42          assertEquals("star 1.6 (x86_64-unknown-linux-gnu) 2019/04/01", e.getExtraPaxHeader("SCHILY.release"), "SCHILY.release");
43          assertEquals("20", e.getExtraPaxHeader("SCHILY.volhdr.blocksize"), "SCHILY.volhdr.blocksize");
44          assertEquals("1", e.getExtraPaxHeader("SCHILY.volhdr.volno"), "SCHILY.volhdr.volno");
45      }
46  
47      // Extended POSIX.1-2001 standard tar + x-header
48      // Created using s-tar 1.6
49      @Test
50      void testReadTimeFromTarEpax() throws Exception {
51          final String file = "COMPRESS-612/test-times-epax-folder.tar";
52          try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
53                  TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
54              TarArchiveEntry e = tin.getNextTarEntry();
55              assertNotNull(e);
56              assertTrue(e.getExtraPaxHeaders().isEmpty());
57              assertEquals("test/", e.getName());
58              assertEquals(TarConstants.LF_DIR, e.getLinkFlag());
59              assertTrue(e.isDirectory());
60              assertEquals(toFileTime("2022-03-17T00:24:44.147126600Z"), e.getLastModifiedTime(), "mtime");
61              assertEquals(toFileTime("2022-03-17T01:02:11.910960100Z"), e.getLastAccessTime(), "atime");
62              assertEquals(toFileTime("2022-03-17T00:24:44.147126600Z"), e.getStatusChangeTime(), "ctime");
63              assertNull(e.getCreationTime(), "birthtime");
64              e = tin.getNextTarEntry();
65              assertNotNull(e);
66              assertTrue(e.getExtraPaxHeaders().isEmpty());
67              assertEquals("test/test-times.txt", e.getName());
68              assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
69              assertTrue(e.isFile());
70              assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getLastModifiedTime(), "mtime");
71              assertEquals(toFileTime("2022-03-17T00:38:20.536752000Z"), e.getLastAccessTime(), "atime");
72              assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getStatusChangeTime(), "ctime");
73              assertNull(e.getCreationTime(), "birthtime");
74              assertNull(tin.getNextTarEntry());
75          }
76      }
77  
78      // 'xustar' format - always x-header
79      @Test
80      void testReadTimeFromTarExustar() throws Exception {
81          final String file = "COMPRESS-612/test-times-exustar-folder.tar";
82          try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
83                  TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
84              TarArchiveEntry e = tin.getNextTarEntry();
85              assertNotNull(e);
86              assertEquals("test/", e.getName());
87              assertEquals(TarConstants.LF_DIR, e.getLinkFlag());
88              assertTrue(e.isDirectory());
89              assertEquals(toFileTime("2022-03-17T00:24:44.147126600Z"), e.getLastModifiedTime(), "mtime");
90              assertEquals(toFileTime("2022-03-17T00:47:00.367783300Z"), e.getLastAccessTime(), "atime");
91              assertEquals(toFileTime("2022-03-17T00:24:44.147126600Z"), e.getStatusChangeTime(), "ctime");
92              assertNull(e.getCreationTime(), "birthtime");
93              assertGlobalHeaders(e);
94              e = tin.getNextTarEntry();
95              assertEquals("test/test-times.txt", e.getName());
96              assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
97              assertTrue(e.isFile());
98              assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getLastModifiedTime(), "mtime");
99              assertEquals(toFileTime("2022-03-17T00:38:20.536752000Z"), e.getLastAccessTime(), "atime");
100             assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getStatusChangeTime(), "ctime");
101             assertNull(e.getCreationTime(), "birthtime");
102             assertGlobalHeaders(e);
103             assertNull(tin.getNextTarEntry());
104         }
105     }
106 
107     // GNU tar format 1989 (violates POSIX)
108     // Created using GNU tar
109     @Test
110     void testReadTimeFromTarGnu() throws Exception {
111         final String file = "COMPRESS-612/test-times-gnu.tar";
112         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
113                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
114             final TarArchiveEntry e = tin.getNextTarEntry();
115             assertNotNull(e);
116             assertTrue(e.getExtraPaxHeaders().isEmpty());
117             assertEquals(toFileTime("2022-03-14T01:25:03Z"), e.getLastModifiedTime(), "mtime");
118             assertNull(e.getLastAccessTime(), "atime");
119             assertNull(e.getStatusChangeTime(), "ctime");
120             assertNull(e.getCreationTime(), "birthtime");
121             assertNull(tin.getNextTarEntry());
122         }
123     }
124 
125     // GNU tar format 1989 (violates POSIX)
126     // Created using GNU tar
127     @Test
128     void testReadTimeFromTarGnuIncremental() throws Exception {
129         final String file = "COMPRESS-612/test-times-gnu-incremental.tar";
130         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
131                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
132             TarArchiveEntry e = tin.getNextTarEntry();
133             assertNotNull(e);
134             assertTrue(e.getExtraPaxHeaders().isEmpty());
135             assertEquals("test-times.txt", e.getName());
136             assertEquals(toFileTime("2022-03-14T01:25:03Z"), e.getLastModifiedTime(), "mtime");
137             assertNull(e.getLastAccessTime(), "atime");
138             assertNull(e.getStatusChangeTime(), "ctime");
139             assertNull(e.getCreationTime(), "birthtime");
140             e = tin.getNextTarEntry();
141             assertNotNull(e);
142             assertTrue(e.getExtraPaxHeaders().isEmpty());
143             assertEquals("test-times.txt", e.getName());
144             assertEquals(toFileTime("2022-03-14T03:17:05Z"), e.getLastModifiedTime(), "mtime");
145             assertEquals(toFileTime("2022-03-14T03:17:10Z"), e.getLastAccessTime(), "atime");
146             assertEquals(toFileTime("2022-03-14T03:17:10Z"), e.getStatusChangeTime(), "ctime");
147             assertNull(e.getCreationTime(), "birthtime");
148             assertNull(tin.getNextTarEntry());
149         }
150     }
151 
152     // GNU tar format 1989 (violates POSIX)
153     // Created using s-tar 1.6, which somehow differs from GNU tar's.
154     @Test
155     void testReadTimeFromTarGnuTar() throws Exception {
156         final String file = "COMPRESS-612/test-times-gnutar.tar";
157         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
158                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
159             final TarArchiveEntry e = tin.getNextTarEntry();
160             assertNotNull(e);
161             assertTrue(e.getExtraPaxHeaders().isEmpty());
162             assertEquals(toFileTime("2022-03-17T01:52:25Z"), e.getLastModifiedTime(), "mtime");
163             assertEquals(toFileTime("2022-03-17T01:52:25Z"), e.getLastAccessTime(), "atime");
164             assertEquals(toFileTime("2022-03-17T01:52:25Z"), e.getStatusChangeTime(), "ctime");
165             assertNull(e.getCreationTime(), "birthtime");
166             assertNull(tin.getNextTarEntry());
167         }
168     }
169 
170     // Old BSD tar format
171     @Test
172     void testReadTimeFromTarOldBsdTar() throws Exception {
173         final String file = "COMPRESS-612/test-times-oldbsdtar.tar";
174         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
175                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
176             final TarArchiveEntry e = tin.getNextTarEntry();
177             assertNotNull(e);
178             assertTrue(e.getExtraPaxHeaders().isEmpty());
179             assertEquals(toFileTime("2022-03-17T01:52:25Z"), e.getLastModifiedTime(), "mtime");
180             assertNull(e.getLastAccessTime(), "atime");
181             assertNull(e.getStatusChangeTime(), "ctime");
182             assertNull(e.getCreationTime(), "birthtime");
183             assertNull(tin.getNextTarEntry());
184         }
185     }
186 
187     // Format used by GNU tar of versions prior to 1.12
188     // Created using GNU tar
189     @Test
190     void testReadTimeFromTarOldGnu() throws Exception {
191         final String file = "COMPRESS-612/test-times-oldgnu.tar";
192         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
193                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
194             final TarArchiveEntry e = tin.getNextTarEntry();
195             assertNotNull(e);
196             assertTrue(e.getExtraPaxHeaders().isEmpty());
197             assertEquals(toFileTime("2022-03-14T01:25:03Z"), e.getLastModifiedTime(), "mtime");
198             assertNull(e.getLastAccessTime(), "atime");
199             assertNull(e.getStatusChangeTime(), "ctime");
200             assertNull(e.getCreationTime(), "birthtime");
201             assertNull(tin.getNextTarEntry());
202         }
203     }
204 
205     // Format used by GNU tar of versions prior to 1.12
206     // Created using GNU tar
207     @Test
208     void testReadTimeFromTarOldGnuIncremental() throws Exception {
209         final String file = "COMPRESS-612/test-times-oldgnu-incremental.tar";
210         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
211                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
212             TarArchiveEntry e = tin.getNextTarEntry();
213             assertNotNull(e);
214             assertTrue(e.getExtraPaxHeaders().isEmpty());
215             assertEquals("test-times.txt", e.getName());
216             assertEquals(toFileTime("2022-03-14T01:25:03Z"), e.getLastModifiedTime(), "mtime");
217             assertNull(e.getLastAccessTime(), "atime");
218             assertNull(e.getStatusChangeTime(), "ctime");
219             assertNull(e.getCreationTime(), "birthtime");
220             e = tin.getNextTarEntry();
221             assertNotNull(e);
222             assertTrue(e.getExtraPaxHeaders().isEmpty());
223             assertEquals("test-times.txt", e.getName());
224             assertEquals(toFileTime("2022-03-14T03:17:05Z"), e.getLastModifiedTime(), "mtime");
225             assertEquals(toFileTime("2022-03-14T03:17:06Z"), e.getLastAccessTime(), "atime");
226             assertEquals(toFileTime("2022-03-14T03:17:05Z"), e.getStatusChangeTime(), "ctime");
227             assertNull(e.getCreationTime(), "birthtime");
228             assertNull(tin.getNextTarEntry());
229         }
230     }
231 
232     // Extended POSIX.1-2001 standard tar
233     // Created using s-tar 1.6, which somehow differs from GNU tar's.
234     @Test
235     void testReadTimeFromTarPax() throws Exception {
236         final String file = "COMPRESS-612/test-times-pax-folder.tar";
237         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
238                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
239             TarArchiveEntry e = tin.getNextTarEntry();
240             assertNotNull(e);
241             assertTrue(e.getExtraPaxHeaders().isEmpty());
242             assertEquals("test/", e.getName());
243             assertEquals(TarConstants.LF_DIR, e.getLinkFlag());
244             assertTrue(e.isDirectory());
245             assertEquals(toFileTime("2022-03-17T00:24:44.147126600Z"), e.getLastModifiedTime(), "mtime");
246             assertEquals(toFileTime("2022-03-17T01:01:53.369146300Z"), e.getLastAccessTime(), "atime");
247             assertEquals(toFileTime("2022-03-17T00:24:44.147126600Z"), e.getStatusChangeTime(), "ctime");
248             assertNull(e.getCreationTime(), "birthtime");
249             e = tin.getNextTarEntry();
250             assertNotNull(e);
251             assertTrue(e.getExtraPaxHeaders().isEmpty());
252             assertEquals("test/test-times.txt", e.getName());
253             assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
254             assertTrue(e.isFile());
255             assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getLastModifiedTime(), "mtime");
256             assertEquals(toFileTime("2022-03-17T00:38:20.536752000Z"), e.getLastAccessTime(), "atime");
257             assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getStatusChangeTime(), "ctime");
258             assertNull(e.getCreationTime(), "birthtime");
259             assertNull(tin.getNextTarEntry());
260         }
261     }
262 
263     // Extended POSIX.1-2001 standard tar
264     // Created using GNU tar
265     @Test
266     void testReadTimeFromTarPosix() throws Exception {
267         final String file = "COMPRESS-612/test-times-posix.tar";
268         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
269                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
270             final TarArchiveEntry e = tin.getNextTarEntry();
271             assertNotNull(e);
272             assertTrue(e.getExtraPaxHeaders().isEmpty());
273             assertEquals(toFileTime("2022-03-14T01:25:03.599853900Z"), e.getLastModifiedTime(), "mtime");
274             assertEquals(toFileTime("2022-03-14T01:31:00.706927200Z"), e.getLastAccessTime(), "atime");
275             assertEquals(toFileTime("2022-03-14T01:28:59.700505300Z"), e.getStatusChangeTime(), "ctime");
276             assertNull(e.getCreationTime(), "birthtime");
277             assertNull(tin.getNextTarEntry());
278         }
279     }
280 
281     // Extended POSIX.1-2001 standard tar
282     // Created using BSD tar on Windows
283     @Test
284     void testReadTimeFromTarPosixLibArchive() throws Exception {
285         final String file = "COMPRESS-612/test-times-bsd-folder.tar";
286         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
287                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
288             TarArchiveEntry e = tin.getNextTarEntry();
289             assertNotNull(e);
290             assertTrue(e.getExtraPaxHeaders().isEmpty());
291             assertEquals("test/", e.getName());
292             assertEquals(TarConstants.LF_DIR, e.getLinkFlag());
293             assertTrue(e.isDirectory());
294             assertEquals(toFileTime("2022-03-16T10:19:43.382883700Z"), e.getLastModifiedTime(), "mtime");
295             assertEquals(toFileTime("2022-03-16T10:21:01.251181000Z"), e.getLastAccessTime(), "atime");
296             assertEquals(toFileTime("2022-03-16T10:19:24.105111500Z"), e.getStatusChangeTime(), "ctime");
297             assertEquals(toFileTime("2022-03-16T10:19:24.105111500Z"), e.getCreationTime(), "birthtime");
298             e = tin.getNextTarEntry();
299             assertNotNull(e);
300             assertTrue(e.getExtraPaxHeaders().isEmpty());
301             assertEquals("test/test-times.txt", e.getName());
302             assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
303             assertTrue(e.isFile());
304             assertEquals(toFileTime("2022-03-16T10:21:00.249238500Z"), e.getLastModifiedTime(), "mtime");
305             assertEquals(toFileTime("2022-03-16T10:21:01.251181000Z"), e.getLastAccessTime(), "atime");
306             assertEquals(toFileTime("2022-03-14T01:25:03.599853900Z"), e.getStatusChangeTime(), "ctime");
307             assertEquals(toFileTime("2022-03-14T01:25:03.599853900Z"), e.getCreationTime(), "birthtime");
308             assertNull(tin.getNextTarEntry());
309         }
310     }
311 
312     // Extended POSIX.1-2001 standard tar
313     // Created using GNU tar on Linux
314     @Test
315     void testReadTimeFromTarPosixLinux() throws Exception {
316         final String file = "COMPRESS-612/test-times-posix-linux.tar";
317         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
318                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
319             final TarArchiveEntry e = tin.getNextTarEntry();
320             assertNotNull(e);
321             assertTrue(e.getExtraPaxHeaders().isEmpty());
322             assertEquals(toFileTime("2022-03-14T01:25:03.599853900Z"), e.getLastModifiedTime(), "mtime");
323             assertEquals(toFileTime("2022-03-14T01:32:13.837251500Z"), e.getLastAccessTime(), "atime");
324             assertEquals(toFileTime("2022-03-14T01:31:00.706927200Z"), e.getStatusChangeTime(), "ctime");
325             assertNull(e.getCreationTime(), "birthtime");
326             assertNull(tin.getNextTarEntry());
327         }
328     }
329 
330     // Old star format from 1985
331     @Test
332     void testReadTimeFromTarStarFolder() throws Exception {
333         final String file = "COMPRESS-612/test-times-star-folder.tar";
334         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
335                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
336             TarArchiveEntry e = tin.getNextTarEntry();
337             assertNotNull(e);
338             assertTrue(e.getExtraPaxHeaders().isEmpty());
339             assertEquals("test/", e.getName());
340             assertEquals(TarConstants.LF_DIR, e.getLinkFlag());
341             assertTrue(e.isDirectory());
342             assertEquals(toFileTime("2022-03-17T00:24:44Z"), e.getLastModifiedTime(), "mtime");
343             assertNull(e.getLastAccessTime(), "atime");
344             assertNull(e.getStatusChangeTime(), "ctime");
345             assertNull(e.getCreationTime(), "birthtime");
346             e = tin.getNextTarEntry();
347             assertTrue(e.getExtraPaxHeaders().isEmpty());
348             assertEquals("test/test-times.txt", e.getName());
349             assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
350             assertTrue(e.isFile());
351             assertEquals(toFileTime("2022-03-17T00:38:20Z"), e.getLastModifiedTime(), "mtime");
352             assertNull(e.getLastAccessTime(), "atime");
353             assertNull(e.getStatusChangeTime(), "ctime");
354             assertNull(e.getCreationTime(), "birthtime");
355             assertNull(tin.getNextTarEntry());
356         }
357     }
358 
359     // Standard POSIX.1-1988 tar format
360     @Test
361     void testReadTimeFromTarUstar() throws Exception {
362         final String file = "COMPRESS-612/test-times-ustar.tar";
363         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
364                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
365             final TarArchiveEntry e = tin.getNextTarEntry();
366             assertNotNull(e);
367             assertTrue(e.getExtraPaxHeaders().isEmpty());
368             assertEquals(toFileTime("2022-03-14T01:25:03Z"), e.getLastModifiedTime(), "mtime");
369             assertNull(e.getLastAccessTime(), "atime");
370             assertNull(e.getStatusChangeTime(), "ctime");
371             assertNull(e.getCreationTime(), "birthtime");
372             assertNull(tin.getNextTarEntry());
373         }
374     }
375 
376     // Old Unix V7 tar format
377     @Test
378     void testReadTimeFromTarV7() throws Exception {
379         final String file = "COMPRESS-612/test-times-v7.tar";
380         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
381                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
382             final TarArchiveEntry e = tin.getNextTarEntry();
383             assertNotNull(e);
384             assertTrue(e.getExtraPaxHeaders().isEmpty());
385             assertEquals(toFileTime("2022-03-14T01:25:03Z"), e.getLastModifiedTime(), "mtime");
386             assertNull(e.getLastAccessTime(), "atime");
387             assertNull(e.getStatusChangeTime(), "ctime");
388             assertNull(e.getCreationTime(), "birthtime");
389             assertNull(tin.getNextTarEntry());
390         }
391     }
392 
393     // Extended standard tar (star 1994)
394     @Test
395     void testReadTimeFromTarXstar() throws Exception {
396         final String file = "COMPRESS-612/test-times-xstar.tar";
397         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
398                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
399             final TarArchiveEntry e = tin.getNextTarEntry();
400             assertNotNull(e);
401             assertTrue(e.getExtraPaxHeaders().isEmpty());
402             assertEquals(toFileTime("2022-03-14T04:11:22Z"), e.getLastModifiedTime(), "mtime");
403             assertEquals(toFileTime("2022-03-14T04:12:48Z"), e.getLastAccessTime(), "atime");
404             assertEquals(toFileTime("2022-03-14T04:12:47Z"), e.getStatusChangeTime(), "ctime");
405             assertNull(e.getCreationTime(), "birthtime");
406             assertNull(tin.getNextTarEntry());
407         }
408     }
409 
410     // Extended standard tar (star 1994)
411     @Test
412     void testReadTimeFromTarXstarFolder() throws Exception {
413         final String file = "COMPRESS-612/test-times-xstar-folder.tar";
414         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
415                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
416             TarArchiveEntry e = tin.getNextTarEntry();
417             assertNotNull(e);
418             assertTrue(e.getExtraPaxHeaders().isEmpty());
419             assertEquals("test/", e.getName());
420             assertEquals(TarConstants.LF_DIR, e.getLinkFlag());
421             assertTrue(e.isDirectory());
422             assertEquals(toFileTime("2022-03-17T00:24:44Z"), e.getLastModifiedTime(), "mtime");
423             assertEquals(toFileTime("2022-03-17T01:01:34Z"), e.getLastAccessTime(), "atime");
424             assertEquals(toFileTime("2022-03-17T00:24:44Z"), e.getStatusChangeTime(), "ctime");
425             assertNull(e.getCreationTime(), "birthtime");
426             e = tin.getNextTarEntry();
427             assertEquals("test/test-times.txt", e.getName());
428             assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
429             assertTrue(e.isFile());
430             assertTrue(e.getExtraPaxHeaders().isEmpty());
431             assertEquals(toFileTime("2022-03-17T00:38:20Z"), e.getLastModifiedTime(), "mtime");
432             assertEquals(toFileTime("2022-03-17T00:38:20Z"), e.getLastAccessTime(), "atime");
433             assertEquals(toFileTime("2022-03-17T00:38:20Z"), e.getStatusChangeTime(), "ctime");
434             assertNull(e.getCreationTime(), "birthtime");
435             assertNull(tin.getNextTarEntry());
436         }
437     }
438 
439     // Extended standard tar (star 1994)
440     @Test
441     void testReadTimeFromTarXstarIncremental() throws Exception {
442         final String file = "COMPRESS-612/test-times-xstar-incremental.tar";
443         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
444                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
445             TarArchiveEntry e = tin.getNextTarEntry();
446             assertNotNull(e);
447             assertTrue(e.getExtraPaxHeaders().isEmpty());
448             assertEquals("test-times.txt", e.getName());
449             assertEquals(toFileTime("2022-03-14T04:03:29Z"), e.getLastModifiedTime(), "mtime");
450             assertEquals(toFileTime("2022-03-14T04:03:29Z"), e.getLastAccessTime(), "atime");
451             assertEquals(toFileTime("2022-03-14T04:03:29Z"), e.getStatusChangeTime(), "ctime");
452             assertNull(e.getCreationTime(), "birthtime");
453             e = tin.getNextTarEntry();
454             assertNotNull(e);
455             assertTrue(e.getExtraPaxHeaders().isEmpty());
456             assertEquals("test-times.txt", e.getName(), "name");
457             assertEquals(toFileTime("2022-03-14T04:11:22Z"), e.getLastModifiedTime(), "mtime");
458             assertEquals(toFileTime("2022-03-14T04:11:23Z"), e.getLastAccessTime(), "atime");
459             assertEquals(toFileTime("2022-03-14T04:11:22Z"), e.getStatusChangeTime(), "ctime");
460             assertNull(e.getCreationTime(), "birthtime");
461             assertNull(tin.getNextTarEntry());
462         }
463     }
464 
465     // 'xstar' format without tar signature
466     @Test
467     void testReadTimeFromTarXustar() throws Exception {
468         final String file = "COMPRESS-612/test-times-xustar.tar";
469         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
470                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
471             final TarArchiveEntry e = tin.getNextTarEntry();
472             assertNotNull(e);
473             assertTrue(e.getExtraPaxHeaders().isEmpty());
474             assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getLastModifiedTime(), "mtime");
475             assertEquals(toFileTime("2022-03-17T00:38:20.536752000Z"), e.getLastAccessTime(), "atime");
476             assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getStatusChangeTime(), "ctime");
477             assertNull(e.getCreationTime(), "birthtime");
478             assertNull(tin.getNextTarEntry());
479         }
480     }
481 
482     // 'xstar' format without tar signature
483     @Test
484     void testReadTimeFromTarXustarFolder() throws Exception {
485         final String file = "COMPRESS-612/test-times-xustar-folder.tar";
486         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
487                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
488             TarArchiveEntry e = tin.getNextTarEntry();
489             assertNotNull(e);
490             assertTrue(e.getExtraPaxHeaders().isEmpty());
491             assertEquals("test/", e.getName());
492             assertEquals(TarConstants.LF_DIR, e.getLinkFlag());
493             assertTrue(e.isDirectory());
494             assertEquals(toFileTime("2022-03-17T00:24:44.147126600Z"), e.getLastModifiedTime(), "mtime");
495             assertEquals(toFileTime("2022-03-17T01:01:19.581236400Z"), e.getLastAccessTime(), "atime");
496             assertEquals(toFileTime("2022-03-17T00:24:44.147126600Z"), e.getStatusChangeTime(), "ctime");
497             assertNull(e.getCreationTime(), "birthtime");
498             e = tin.getNextTarEntry();
499             assertTrue(e.getExtraPaxHeaders().isEmpty());
500             assertEquals("test/test-times.txt", e.getName());
501             assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
502             assertTrue(e.isFile());
503             assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getLastModifiedTime(), "mtime");
504             assertEquals(toFileTime("2022-03-17T00:38:20.536752000Z"), e.getLastAccessTime(), "atime");
505             assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getStatusChangeTime(), "ctime");
506             assertNull(e.getCreationTime(), "birthtime");
507             assertNull(tin.getNextTarEntry());
508         }
509     }
510 
511     // 'xstar' format without tar signature
512     @Test
513     void testReadTimeFromTarXustarIncremental() throws Exception {
514         final String file = "COMPRESS-612/test-times-xustar-incremental.tar";
515         try (InputStream in = new BufferedInputStream(Files.newInputStream(getPath(file)));
516                 TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
517             TarArchiveEntry e = tin.getNextTarEntry();
518             assertNotNull(e);
519             assertTrue(e.getExtraPaxHeaders().isEmpty());
520             assertEquals("test-times.txt", e.getName(), "name");
521             assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
522             assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getLastModifiedTime(), "mtime");
523             assertEquals(toFileTime("2022-03-17T00:38:20.536752000Z"), e.getLastAccessTime(), "atime");
524             assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getStatusChangeTime(), "ctime");
525             assertNull(e.getCreationTime(), "birthtime");
526             e = tin.getNextTarEntry();
527             assertNotNull(e);
528             assertTrue(e.getExtraPaxHeaders().isEmpty());
529             assertEquals("test-times.txt", e.getName(), "name");
530             assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
531             assertEquals(toFileTime("2022-03-17T01:52:25.592262900Z"), e.getLastModifiedTime(), "mtime");
532             assertEquals(toFileTime("2022-03-17T01:52:25.724278500Z"), e.getLastAccessTime(), "atime");
533             assertEquals(toFileTime("2022-03-17T01:52:25.592262900Z"), e.getStatusChangeTime(), "ctime");
534             assertNull(e.getCreationTime(), "birthtime");
535             assertNull(tin.getNextTarEntry());
536         }
537     }
538 
539     private FileTime toFileTime(final String text) {
540         return FileTime.from(Instant.parse(text));
541     }
542 }