From 2466432366e53bc8d2f6c10a8cf08d7f8bd00c7d Mon Sep 17 00:00:00 2001
From: jakubs <jakubs>
Date: Mon, 3 Nov 2014 14:45:50 +0000
Subject: [PATCH] SSDM-1081 multidataset archiver

SVN: 32707
---
 .../cisd/common/filesystem/tar/Untar.java     | 121 ++++++++++++------
 1 file changed, 84 insertions(+), 37 deletions(-)

diff --git a/common/source/java/ch/systemsx/cisd/common/filesystem/tar/Untar.java b/common/source/java/ch/systemsx/cisd/common/filesystem/tar/Untar.java
index 1951fceac60..32710317984 100644
--- a/common/source/java/ch/systemsx/cisd/common/filesystem/tar/Untar.java
+++ b/common/source/java/ch/systemsx/cisd/common/filesystem/tar/Untar.java
@@ -25,6 +25,7 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.ListIterator;
+import java.util.Map;
 
 import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
 import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
@@ -41,8 +42,6 @@ public class Untar implements Closeable
 
     private final static int DEFAULT_BUFFER_SIZE = 128 * 1024;
 
-    private final List<TarArchiveEntry> dirEntries = new ArrayList<TarArchiveEntry>();
-
     private final TarArchiveInputStream in;
 
     private final byte[] buf;
@@ -69,46 +68,43 @@ public class Untar implements Closeable
      */
     public void extract(final File rootDirectory) throws IOException
     {
+        final List<TarArchiveEntry> dirEntries = new ArrayList<TarArchiveEntry>();
+
         TarArchiveEntry entry;
         while ((entry = in.getNextTarEntry()) != null)
         {
             final File entryFile = new File(rootDirectory, entry.getName());
-            if (entry.isDirectory())
-            {
-                dirEntries.add(entry);
-                entryFile.mkdirs();
-            } else if (entry.isLink())
-            {
-                if (Unix.isOperational())
-                {
-                    Unix.createHardLink(entry.getLinkName(),
-                            entryFile.getPath());
-                }
-            } else if (entry.isSymbolicLink())
-            {
-                if (Unix.isOperational())
-                {
-                    Unix.createSymbolicLink(entry.getLinkName(),
-                            entryFile.getPath());
-                }
-            } else if (entry.isFile())
+            extractEntry(entry, entryFile, dirEntries);
+        }
+        // Set directory metadata in reverse order, i.e. descendants first
+        final ListIterator<TarArchiveEntry> it = dirEntries
+                .listIterator(dirEntries.size());
+        while (it.hasPrevious())
+        {
+            entry = it.previous();
+            setFileMetadata(new File(rootDirectory, entry.getName()), entry);
+        }
+    }
+
+    /**
+     * Extracts the tar file. Each top level directory is extracted to a different location specified by the {@code locations} argument. Only part of
+     * the file is extracted. Top level directories not present in {@code locations} will be omitted.
+     * 
+     * @param locations maps top level directory names to directories where those should be extracted
+     */
+    public void extract(final Map<String, File> locations) throws IOException
+    {
+        final List<TarArchiveEntry> dirEntries = new ArrayList<TarArchiveEntry>();
+
+        TarArchiveEntry entry;
+        while ((entry = in.getNextTarEntry()) != null)
+        {
+            final File entryFile = getEntryInLocation(entry, locations);
+            if (entryFile == null)
             {
-                // We need to work around that isFile() is giving all
-                // kinds of false positives on what is a file.
-                if (entry.isBlockDevice() || entry.isCharacterDevice()
-                        || entry.isFIFO() || entry.isGNULongLinkEntry()
-                        || entry.isGNULongNameEntry() || entry.isGNUSparse()
-                        || entry.isPaxHeader() || entry.isGlobalPaxHeader())
-                {
-                    continue;
-                }
-                if (entryFile.getParentFile().exists() == false)
-                {
-                    entryFile.getParentFile().mkdirs();
-                }
-                extractFileContent(entryFile);
-                setFileMetadata(entryFile, entry);
+                continue;
             }
+            extractEntry(entry, entryFile, dirEntries);
         }
         // Set directory metadata in reverse order, i.e. descendants first
         final ListIterator<TarArchiveEntry> it = dirEntries
@@ -116,7 +112,58 @@ public class Untar implements Closeable
         while (it.hasPrevious())
         {
             entry = it.previous();
-            setFileMetadata(new File(rootDirectory, entry.getName()), entry);
+            File entryFile = getEntryInLocation(entry, locations);
+            setFileMetadata(entryFile, entry);
+        }
+    }
+
+    public File getEntryInLocation(TarArchiveEntry entry, final Map<String, File> locations)
+    {
+        String[] parts = entry.getName().split("/", 2);
+        String head = parts[0];
+        String tail = parts[1];
+
+        return new File(locations.get(head), tail);
+    }
+
+    private void extractEntry(TarArchiveEntry entry, final File entryFile, final List<TarArchiveEntry> dirEntries) throws FileNotFoundException,
+            IOException
+    {
+        if (entry.isDirectory())
+        {
+            dirEntries.add(entry);
+            entryFile.mkdirs();
+        } else if (entry.isLink())
+        {
+            if (Unix.isOperational())
+            {
+                Unix.createHardLink(entry.getLinkName(),
+                        entryFile.getPath());
+            }
+        } else if (entry.isSymbolicLink())
+        {
+            if (Unix.isOperational())
+            {
+                Unix.createSymbolicLink(entry.getLinkName(),
+                        entryFile.getPath());
+            }
+        } else if (entry.isFile())
+        {
+            // We need to work around that isFile() is giving all
+            // kinds of false positives on what is a file.
+            if (entry.isBlockDevice() || entry.isCharacterDevice()
+                    || entry.isFIFO() || entry.isGNULongLinkEntry()
+                    || entry.isGNULongNameEntry() || entry.isGNUSparse()
+                    || entry.isPaxHeader() || entry.isGlobalPaxHeader())
+            {
+                return;
+            }
+            if (entryFile.getParentFile().exists() == false)
+            {
+                entryFile.getParentFile().mkdirs();
+            }
+            extractFileContent(entryFile);
+            setFileMetadata(entryFile, entry);
         }
     }
 
-- 
GitLab