This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-compress.git
The following commit(s) were added to refs/heads/master by this push: new c6b958f0f [COMPRESS-700] Add org.apache.commons.compress.archivers.tar.Compress700Test.testFirstTarArchiveEntry() c6b958f0f is described below commit c6b958f0f5815f5dd5c44d147c8cbd883dd24407 Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Sun Jun 1 09:02:04 2025 -0400 [COMPRESS-700] Add org.apache.commons.compress.archivers.tar.Compress700Test.testFirstTarArchiveEntry() Add org.apache.commons.compress.archivers.tar.Compress700Test.testListEntries() --- .../compress/archivers/tar/TarArchiveEntry.java | 32 +++++ .../compress/archivers/tar/Compress700Test.java | 154 ++++++++++++++++++++- .../archivers/tar/TarArchiveEntryTest.java | 70 +++++----- .../archivers/tar/TarArchiveInputStreamTest.java | 2 + 4 files changed, 224 insertions(+), 34 deletions(-) diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java index c3389bde6..6856e261b 100644 --- a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java +++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java @@ -1367,6 +1367,28 @@ public boolean isSymbolicLink() { return linkFlag == LF_SYMLINK; } + /** + * Tests whether the <a href="https://www.mkssoftware.com/docs/man4/tar.4.asp">type flag</a> contains a valid USTAR value. + * + * <pre> + * Type Flag File Type + * 0 or null Regular file + * 1 Link to another file already archived + * 2 Symbolic link + * 3 Character special device + * 4 Block special device + * 5 Directory + * 6 FIFO special file + * 7 Reserved + * A-Z Available for custom usage + * </pre> + * + * @return whether the type flag contains a valid USTAR value. + */ + boolean isTypeFlagUstar() { + return linkFlag == 0 || linkFlag >= '0' && linkFlag <= '7' || linkFlag >= 'A' && linkFlag <= 'Z'; + } + /** * Tests whether the given header is in XSTAR / XUSTAR format. * @@ -1935,6 +1957,16 @@ public void setUserName(final String userName) { this.userName = userName; } + /** + * Converts this instance to a String useful for debugging. + * + * @since 1.28.0 + */ + @Override + public String toString() { + return getClass().getSimpleName() + "[" + name + "]"; + } + /** * Update the entry using a map of pax headers. * diff --git a/src/test/java/org/apache/commons/compress/archivers/tar/Compress700Test.java b/src/test/java/org/apache/commons/compress/archivers/tar/Compress700Test.java index 69cb90df7..edf561b8c 100644 --- a/src/test/java/org/apache/commons/compress/archivers/tar/Compress700Test.java +++ b/src/test/java/org/apache/commons/compress/archivers/tar/Compress700Test.java @@ -20,11 +20,22 @@ package org.apache.commons.compress.archivers.tar; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.BufferedInputStream; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.attribute.FileTime; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; import org.apache.commons.compress.archivers.ArchiveStreamFactory; import org.junit.Ignore; @@ -36,12 +47,151 @@ */ public class Compress700Test { + private static final Path PATH = Paths.get("src/test/resources/org/apache/commons/compress/COMPRESS-700/flutter_awesome_buttons-0.1.0-fail.tar"); + + @Test + public void testFirstTarArchiveEntry() throws Exception { + try (TarArchiveInputStream inputStream = new TarArchiveInputStream(new BufferedInputStream(Files.newInputStream(PATH)))) { + final TarArchiveEntry entry = inputStream.getNextEntry(); + assertNull(entry.getCreationTime()); + assertEquals(-1, entry.getDataOffset()); + assertEquals(0, entry.getDevMajor()); + assertEquals(0, entry.getDevMinor()); + assertEquals(Collections.emptyMap(), entry.getExtraPaxHeaders()); + assertEquals(0, entry.getGroupId()); + assertEquals("", entry.getGroupName()); + assertNull(entry.getLastAccessTime()); + assertEquals(Date.parse("Tue Dec 03 05:08:42 EST 2019"), entry.getLastModifiedDate().getTime()); + assertEquals(FileTime.from(Instant.parse("2019-12-03T10:08:42Z")), entry.getLastModifiedTime()); + assertEquals(48, entry.getLinkFlag()); + assertEquals("", entry.getLinkName()); + assertEquals(0, entry.getLongGroupId()); + assertEquals(0, entry.getLongUserId()); + assertEquals(33279, entry.getMode()); + assertEquals(Date.parse("Tue Dec 03 05:08:42 EST 2019"), entry.getModTime().getTime()); + assertEquals("build/app.dill", entry.getName()); + assertNull(entry.getPath()); + assertEquals(0, entry.getRealSize()); + assertEquals(0, entry.getSize()); + assertNull(entry.getStatusChangeTime()); + assertEquals(0, entry.getUserId()); + assertEquals("", entry.getUserName()); + assertTrue(entry.isFile()); + assertFalse(entry.isBlockDevice()); + assertFalse(entry.isCharacterDevice()); + assertTrue(entry.isCheckSumOK()); + assertFalse(entry.isDirectory()); + assertFalse(entry.isExtended()); + assertFalse(entry.isFIFO()); + assertFalse(entry.isGlobalPaxHeader()); + assertFalse(entry.isGNULongLinkEntry()); + assertFalse(entry.isGNULongNameEntry()); + assertFalse(entry.isGNUSparse()); + assertFalse(entry.isLink()); + assertFalse(entry.isOldGNUSparse()); + assertFalse(entry.isPaxGNU1XSparse()); + assertFalse(entry.isPaxGNUSparse()); + assertFalse(entry.isPaxHeader()); + assertFalse(entry.isSparse()); + assertFalse(entry.isStarSparse()); + assertTrue(entry.isStreamContiguous()); + assertFalse(entry.isSymbolicLink()); + assertTrue(entry.isTypeFlagUstar()); + } + } + + @Test + public void testListEntries() throws IOException { + // @formatter:off + final List<String> names = Arrays.asList( + "build/app.dill", + "CHANGELOG.md", + "example/android/app/build.gradle", + "example/android/app/src/debug/AndroidManifest.xml", + "example/android/app/src/main/AndroidManifest.xml", + "example/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java", + "example/android/app/src/main/kotlin/com/example/test_package/MainActivity.kt", + "example/android/app/src/main/res/drawable/launch_background.xml", + "example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png", + "example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png", + "example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png", + "example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png", + "example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png", + "example/android/app/src/main/res/values/styles.xml", + "example/android/app/src/profile/AndroidManifest.xml", + "example/android/build.gradle", + "example/android/gradle.properties", + "example/android/gradlew", + "example/android/gradlew.bat", + "example/android/gradle/wrapper/gradle-wrapper.jar", + "example/android/gradle/wrapper/gradle-wrapper.properties", + "example/android/local.properties", + "example/android/settings.gradle", + "example/android/test_package_android.iml", + "example/ios/Flutter/AppFrameworkInfo.plist", + "example/ios/Flutter/Debug.xcconfig", + "example/ios/Flutter/flutter_export_environment.sh", + "example/ios/Flutter/Generated.xcconfig", + "example/ios/Flutter/Release.xcconfig", + "example/ios/Runner.xcodeproj/project.pbxproj", + "example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata", + "example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme", + "example/ios/Runner.xcworkspace/contents.xcworkspacedata", + "example/ios/Runner/AppDelegate.swift", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-1024x1...@1x.png", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-20...@1x.png", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-20...@2x.png", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-20...@3x.png", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-29...@1x.png", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-29...@2x.png", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-29...@3x.png", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-40...@1x.png", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-40...@2x.png", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-40...@3x.png", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-60...@2x.png", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-60...@3x.png", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-76...@1x.png", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-76...@2x.png", + "example/ios/Runner/Assets.xcassets/AppIcon.appiconset/icon-app-83.5x8...@2x.png", + "example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json", + "example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png", + "example/ios/Runner/Assets.xcassets/LaunchImage.imageset/launchim...@2x.png", + "example/ios/Runner/Assets.xcassets/LaunchImage.imageset/launchim...@3x.png", + "example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md", + "example/ios/Runner/Base.lproj/LaunchScreen.storyboard", + "example/ios/Runner/Base.lproj/Main.storyboard", + "example/ios/Runner/GeneratedPluginRegistrant.h", + "example/ios/Runner/GeneratedPluginRegistrant.m", + "example/ios/Runner/Info.plist", + "example/ios/Runner/Runner-Bridging-Header.h", + "example/lib/main.dart", + "example/pubspec.yaml", + "example/README.md", + "example/test/widget_test.dart", + "example/test_package.iml", + "flutter_buttons.iml", + "lib/flutter_awesome_buttons.dart", + "LICENSE", + "pubspec.yaml", + "README.md", + "test/flutter_buttons_test.dart"); + // @formatter:on + try (TarArchiveInputStream inputStream = new TarArchiveInputStream(new BufferedInputStream(Files.newInputStream(PATH)))) { + for (final String name : names) { + final TarArchiveEntry entry = inputStream.getNextEntry(); + assertNotNull(entry, entry.getName()); + // System.out.println(entry); + assertEquals(name, entry.getName()); + } + } + } + @Disabled @Ignore @Test public void testTarArchive() throws Exception { - final Path fileToTest = Paths.get("src/test/resources/org/apache/commons/compress/COMPRESS-700/flutter_awesome_buttons-0.1.0-fail.tar"); - try (BufferedInputStream fileInputStream = new BufferedInputStream(Files.newInputStream(fileToTest))) { + try (BufferedInputStream fileInputStream = new BufferedInputStream(Files.newInputStream(PATH))) { assertEquals(ArchiveStreamFactory.TAR, ArchiveStreamFactory.detect(fileInputStream)); } } diff --git a/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveEntryTest.java b/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveEntryTest.java index 6ac7f87e9..2d525c4ba 100644 --- a/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveEntryTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveEntryTest.java @@ -437,50 +437,54 @@ public void testShouldWriteTimesForStarMode() throws IOException { @Test public void testTarFileWithFSRoot() throws IOException { final File f = File.createTempFile("taetest", ".tar"); - TarArchiveEntry t = new TarArchiveEntry(new File(ROOT)); + TarArchiveEntry entry = new TarArchiveEntry(new File(ROOT)); try { try (TarArchiveOutputStream tout = new TarArchiveOutputStream(Files.newOutputStream(f.toPath()))) { - tout.putArchiveEntry(t); + tout.putArchiveEntry(entry); tout.closeArchiveEntry(); - t = new TarArchiveEntry(new File(new File(ROOT), "foo.txt")); - t.setSize(6); - tout.putArchiveEntry(t); + entry = new TarArchiveEntry(new File(new File(ROOT), "foo.txt")); + entry.setSize(6); + tout.putArchiveEntry(entry); tout.write(new byte[] { 'h', 'e', 'l', 'l', 'o', ' ' }); tout.closeArchiveEntry(); - t = new TarArchiveEntry(new File(new File(ROOT), "bar.txt").getAbsolutePath()); - t.setSize(5); - tout.putArchiveEntry(t); + entry = new TarArchiveEntry(new File(new File(ROOT), "bar.txt").getAbsolutePath()); + entry.setSize(5); + tout.putArchiveEntry(entry); tout.write(new byte[] { 'w', 'o', 'r', 'l', 'd' }); tout.closeArchiveEntry(); - t = new TarArchiveEntry("dummy"); - t.setName(new File(new File(ROOT), "baz.txt").getAbsolutePath()); - t.setSize(1); - tout.putArchiveEntry(t); + entry = new TarArchiveEntry("dummy"); + entry.setName(new File(new File(ROOT), "baz.txt").getAbsolutePath()); + entry.setSize(1); + tout.putArchiveEntry(entry); tout.write(new byte[] { '!' }); tout.closeArchiveEntry(); } try (TarArchiveInputStream tin = new TarArchiveInputStream(Files.newInputStream(f.toPath()))) { // tin.setDebug(true); - t = tin.getNextTarEntry(); - assertNotNull(t); - assertEquals("/", t.getName()); - assertEquals(TarConstants.LF_DIR, t.getLinkFlag()); - assertTrue(t.isCheckSumOK()); - t = tin.getNextTarEntry(); - assertNotNull(t); - assertEquals("foo.txt", t.getName()); - assertEquals(TarConstants.LF_NORMAL, t.getLinkFlag()); - assertTrue(t.isCheckSumOK()); - t = tin.getNextTarEntry(); - assertNotNull(t); - assertEquals("bar.txt", t.getName()); - assertEquals(TarConstants.LF_NORMAL, t.getLinkFlag()); - assertTrue(t.isCheckSumOK()); - t = tin.getNextTarEntry(); - assertNotNull(t); - assertEquals("baz.txt", t.getName()); - assertEquals(TarConstants.LF_NORMAL, t.getLinkFlag()); - assertTrue(t.isCheckSumOK()); + entry = tin.getNextTarEntry(); + assertNotNull(entry); + assertEquals("/", entry.getName()); + assertEquals(TarConstants.LF_DIR, entry.getLinkFlag()); + assertTrue(entry.isCheckSumOK()); + assertTrue(entry.isTypeFlagUstar()); + entry = tin.getNextTarEntry(); + assertNotNull(entry); + assertEquals("foo.txt", entry.getName()); + assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag()); + assertTrue(entry.isCheckSumOK()); + assertTrue(entry.isTypeFlagUstar()); + entry = tin.getNextTarEntry(); + assertNotNull(entry); + assertEquals("bar.txt", entry.getName()); + assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag()); + assertTrue(entry.isCheckSumOK()); + assertTrue(entry.isTypeFlagUstar()); + entry = tin.getNextTarEntry(); + assertNotNull(entry); + assertEquals("baz.txt", entry.getName()); + assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag()); + assertTrue(entry.isCheckSumOK()); + assertTrue(entry.isTypeFlagUstar()); } } finally { AbstractTest.forceDelete(f); @@ -492,6 +496,7 @@ public void testTarFileWithFSRoot() throws IOException { public void testWindowsFileInformationFromFile() throws IOException { final TarArchiveEntry entry = new TarArchiveEntry(getFile("test1.xml")); assertNotEquals("", entry.getUserName()); + assertTrue(entry.isTypeFlagUstar()); } @Test @@ -499,6 +504,7 @@ public void testWindowsFileInformationFromFile() throws IOException { public void testWindowsFileInformationFromPath() throws IOException { final TarArchiveEntry entry = new TarArchiveEntry(getPath("test1.xml")); assertNotEquals("", entry.getUserName()); + assertTrue(entry.isTypeFlagUstar()); } private FileTime toFileTime(final String text) { diff --git a/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java b/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java index 1a951565e..3477ffbf6 100644 --- a/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java @@ -92,7 +92,9 @@ private TarArchiveInputStream getTestStream(final String name) { public void testCompress197() throws IOException { try (TarArchiveInputStream tar = getTestStream("/COMPRESS-197.tar")) { TarArchiveEntry entry = tar.getNextTarEntry(); + assertNotNull(entry); while (entry != null) { + assertTrue(entry.isTypeFlagUstar()); entry = tar.getNextTarEntry(); } }