You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by bo...@apache.org on 2021/06/05 07:38:07 UTC

[commons-compress] branch master updated: add TarFile special case to Lister and Expander

This is an automated email from the ASF dual-hosted git repository.

bodewig 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 e0d4555  add TarFile special case to Lister and Expander
e0d4555 is described below

commit e0d455582500ad0ff70dbb89b02d875ebd70b110
Author: Stefan Bodewig <bo...@apache.org>
AuthorDate: Sat Jun 5 08:57:41 2021 +0200

    add TarFile special case to Lister and Expander
---
 .../apache/commons/compress/archivers/Lister.java  | 14 +++++++++
 .../compress/archivers/examples/Expander.java      | 31 ++++++++++++++++++--
 .../commons/compress/archivers/tar/TarFile.java    | 12 +++++++-
 .../compress/archivers/examples/ExpanderTest.java  | 34 ++++++++++++++++++++++
 4 files changed, 88 insertions(+), 3 deletions(-)

diff --git a/src/main/java/org/apache/commons/compress/archivers/Lister.java b/src/main/java/org/apache/commons/compress/archivers/Lister.java
index 0b65199..e50020f 100644
--- a/src/main/java/org/apache/commons/compress/archivers/Lister.java
+++ b/src/main/java/org/apache/commons/compress/archivers/Lister.java
@@ -25,6 +25,8 @@ import java.io.InputStream;
 import java.nio.file.Files;
 import java.util.Enumeration;
 import org.apache.commons.compress.archivers.sevenz.SevenZFile;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarFile;
 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
 import org.apache.commons.compress.archivers.zip.ZipFile;
 
@@ -55,6 +57,8 @@ public final class Lister {
             list7z(f);
         } else if ("zipfile".equals(format)) {
             listZipUsingZipFile(f);
+        } else if ("tarfile".equals(format)) {
+            listZipUsingTarFile(f);
         } else {
             listStream(f, args);
         }
@@ -106,9 +110,19 @@ public final class Lister {
         }
     }
 
+    private static void listZipUsingTarFile(final File f) throws ArchiveException, IOException {
+        try (TarFile t = new TarFile(f)) {
+            System.out.println("Created " + t.toString());
+            for (TarArchiveEntry en : t.getEntries()) {
+                System.out.println(en.getName());
+            }
+        }
+    }
+
     private static void usage() {
         System.out.println("Parameters: archive-name [archive-type]\n");
         System.out.println("the magic archive-type 'zipfile' prefers ZipFile over ZipArchiveInputStream");
+        System.out.println("the magic archive-type 'tarfile' prefers TarFile over TarArchiveInputStream");
     }
 
 }
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/Expander.java b/src/main/java/org/apache/commons/compress/archivers/examples/Expander.java
index 1902a8b..bbbae00 100644
--- a/src/main/java/org/apache/commons/compress/archivers/examples/Expander.java
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/Expander.java
@@ -29,12 +29,15 @@ import java.nio.channels.SeekableByteChannel;
 import java.nio.file.Files;
 import java.nio.file.StandardOpenOption;
 import java.util.Enumeration;
+import java.util.Iterator;
 
 import org.apache.commons.compress.archivers.ArchiveEntry;
 import org.apache.commons.compress.archivers.ArchiveException;
 import org.apache.commons.compress.archivers.ArchiveInputStream;
 import org.apache.commons.compress.archivers.ArchiveStreamFactory;
 import org.apache.commons.compress.archivers.sevenz.SevenZFile;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarFile;
 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
 import org.apache.commons.compress.archivers.zip.ZipFile;
 import org.apache.commons.compress.utils.IOUtils;
@@ -237,12 +240,14 @@ public class Expander {
         try (CloseableConsumerAdapter c = new CloseableConsumerAdapter(closeableConsumer)) {
         if (!prefersSeekableByteChannel(format)) {
             expand(format, c.track(Channels.newInputStream(archive)), targetDirectory);
+        } else if (ArchiveStreamFactory.TAR.equalsIgnoreCase(format)) {
+            expand(c.track(new TarFile(archive)), targetDirectory);
         } else if (ArchiveStreamFactory.ZIP.equalsIgnoreCase(format)) {
             expand(c.track(new ZipFile(archive)), targetDirectory);
         } else if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format)) {
             expand(c.track(new SevenZFile(archive)), targetDirectory);
         } else {
-            // never reached as prefersSeekableByteChannel only returns true for ZIP and 7z
+            // never reached as prefersSeekableByteChannel only returns true for TAR, ZIP and 7z
             throw new ArchiveException("Don't know how to handle format " + format);
         }
         }
@@ -274,6 +279,26 @@ public class Expander {
      * @param targetDirectory the directory to write to
      * @throws IOException if an I/O error occurs
      * @throws ArchiveException if the archive cannot be read for other reasons
+     * @since 1.21
+     */
+    public void expand(final TarFile archive, final File targetDirectory)
+        throws IOException, ArchiveException {
+        final Iterator<TarArchiveEntry> entryIterator = archive.getEntries().iterator();
+        expand(() -> entryIterator.hasNext() ? entryIterator.next() : null,
+            (entry, out) -> {
+            try (InputStream in = archive.getInputStream((TarArchiveEntry) entry)) {
+                IOUtils.copy(in, out);
+            }
+        }, targetDirectory);
+    }
+
+    /**
+     * Expands {@code archive} into {@code targetDirectory}.
+     *
+     * @param archive the file to expand
+     * @param targetDirectory the directory to write to
+     * @throws IOException if an I/O error occurs
+     * @throws ArchiveException if the archive cannot be read for other reasons
      */
     public void expand(final ZipFile archive, final File targetDirectory)
         throws IOException, ArchiveException {
@@ -311,7 +336,9 @@ public class Expander {
     }
 
     private boolean prefersSeekableByteChannel(final String format) {
-        return ArchiveStreamFactory.ZIP.equalsIgnoreCase(format) || ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format);
+        return ArchiveStreamFactory.TAR.equalsIgnoreCase(format)
+            || ArchiveStreamFactory.ZIP.equalsIgnoreCase(format)
+            || ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format);
     }
 
     private void expand(final ArchiveEntrySupplier supplier, final EntryWriter writer, final File targetDirectory)
diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarFile.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarFile.java
index 148d573..15adb18 100644
--- a/src/main/java/org/apache/commons/compress/archivers/tar/TarFile.java
+++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarFile.java
@@ -89,7 +89,7 @@ public class TarFile implements Closeable {
      * @throws IOException when reading the tar archive fails
      */
     public TarFile(final byte[] content) throws IOException {
-        this(new SeekableInMemoryByteChannel(content), TarConstants.DEFAULT_BLKSIZE, TarConstants.DEFAULT_RCDSIZE, null, false);
+        this(new SeekableInMemoryByteChannel(content));
     }
 
     /**
@@ -187,6 +187,16 @@ public class TarFile implements Closeable {
     /**
      * Constructor for TarFile.
      *
+     * @param content the content to use
+     * @throws IOException when reading the tar archive fails
+     */
+    public TarFile(final SeekableByteChannel content) throws IOException {
+        this(content, TarConstants.DEFAULT_BLKSIZE, TarConstants.DEFAULT_RCDSIZE, null, false);
+    }
+
+    /**
+     * Constructor for TarFile.
+     *
      * @param archive    the seekable byte channel to use
      * @param blockSize  the blocks size to use
      * @param recordSize the record size to use
diff --git a/src/test/java/org/apache/commons/compress/archivers/examples/ExpanderTest.java b/src/test/java/org/apache/commons/compress/archivers/examples/ExpanderTest.java
index e3aa0dd..1a9cf30 100644
--- a/src/test/java/org/apache/commons/compress/archivers/examples/ExpanderTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/examples/ExpanderTest.java
@@ -36,6 +36,7 @@ import org.apache.commons.compress.archivers.ArchiveStreamFactory;
 import org.apache.commons.compress.archivers.StreamingNotSupportedException;
 import org.apache.commons.compress.archivers.sevenz.SevenZFile;
 import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile;
+import org.apache.commons.compress.archivers.tar.TarFile;
 import org.apache.commons.compress.archivers.zip.ZipFile;
 import org.apache.commons.compress.utils.IOUtils;
 import org.junit.Assert;
@@ -147,6 +148,15 @@ public class ExpanderTest extends AbstractTestCase {
         }
     }
 
+    @Test
+    public void tarFileVersion() throws IOException, ArchiveException {
+        setupTar();
+        try (TarFile f = new TarFile(archive)) {
+            new Expander().expand(f, resultDir);
+        }
+        verifyTargetDir();
+    }
+
     private void setup7z() throws IOException, ArchiveException {
         archive = new File(dir, "test.7z");
         final File dummy = new File(dir, "x");
@@ -194,6 +204,30 @@ public class ExpanderTest extends AbstractTestCase {
         }
     }
 
+    private void setupTar() throws IOException, ArchiveException {
+        archive = new File(dir, "test.tar");
+        final File dummy = new File(dir, "x");
+        try (OutputStream o = Files.newOutputStream(dummy.toPath())) {
+            o.write(new byte[14]);
+        }
+        try (ArchiveOutputStream aos = ArchiveStreamFactory.DEFAULT
+             .createArchiveOutputStream("tar", Files.newOutputStream(archive.toPath()))) {
+            aos.putArchiveEntry(aos.createArchiveEntry(dir, "a"));
+            aos.closeArchiveEntry();
+            aos.putArchiveEntry(aos.createArchiveEntry(dir, "a/b"));
+            aos.closeArchiveEntry();
+            aos.putArchiveEntry(aos.createArchiveEntry(dir, "a/b/c"));
+            aos.closeArchiveEntry();
+            aos.putArchiveEntry(aos.createArchiveEntry(dummy, "a/b/d.txt"));
+            aos.write("Hello, world 1".getBytes(StandardCharsets.UTF_8));
+            aos.closeArchiveEntry();
+            aos.putArchiveEntry(aos.createArchiveEntry(dummy, "a/b/c/e.txt"));
+            aos.write("Hello, world 2".getBytes(StandardCharsets.UTF_8));
+            aos.closeArchiveEntry();
+            aos.finish();
+        }
+    }
+
     private void setupZip(final String entry) throws IOException, ArchiveException {
         archive = new File(dir, "test.zip");
         final File dummy = new File(dir, "x");