瀏覽代碼

HADOOP-18136. Verify FileUtils.unTar() handling of missing .tar files.

Contributed by Steve Loughran

Change-Id: I5bca6bd3e7baa6384f634315c32cf5cdd2efc370
Steve Loughran 3 年之前
父節點
當前提交
4313bec40a

+ 17 - 12
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileUtil.java

@@ -691,36 +691,41 @@ public class FileUtil {
       unTarUsingTar(inFile, untarDir, gzipped);
     }
   }
-  
+
   private static void unTarUsingTar(File inFile, File untarDir,
       boolean gzipped) throws IOException {
     StringBuffer untarCommand = new StringBuffer();
+    // not using canonical path here; this postpones relative path
+    // resolution until bash is executed.
+    final String source = "'" + FileUtil.makeShellPath(inFile) + "'";
     if (gzipped) {
-      untarCommand.append(" gzip -dc '");
-      untarCommand.append(FileUtil.makeShellPath(inFile));
-      untarCommand.append("' | (");
-    } 
+      untarCommand.append(" gzip -dc ")
+          .append(source)
+          .append(" | (");
+    }
     untarCommand.append("cd '");
-    untarCommand.append(FileUtil.makeShellPath(untarDir)); 
+    untarCommand.append(FileUtil.makeShellPath(untarDir));
     untarCommand.append("' ; ");
     untarCommand.append("tar -xf ");
 
     if (gzipped) {
       untarCommand.append(" -)");
     } else {
-      untarCommand.append(FileUtil.makeShellPath(inFile));
+      untarCommand.append(source);
     }
-    String[] shellCmd = { "bash", "-c", untarCommand.toString() };
+    LOG.debug("executing [{}]", untarCommand);
+    String[] shellCmd = {"bash", "-c", untarCommand.toString()};
     ShellCommandExecutor shexec = new ShellCommandExecutor(shellCmd);
     shexec.execute();
     int exitcode = shexec.getExitCode();
     if (exitcode != 0) {
-      throw new IOException("Error untarring file " + inFile + 
-                  ". Tar process exited with exit code " + exitcode);
+      throw new IOException("Error untarring file " + inFile +
+          ". Tar process exited with exit code " + exitcode
+          + " from command " + untarCommand);
     }
   }
-  
-  private static void unTarUsingJava(File inFile, File untarDir,
+
+  static void unTarUsingJava(File inFile, File untarDir,
       boolean gzipped) throws IOException {
     InputStream inputStream = null;
     TarArchiveInputStream tis = null;

+ 46 - 0
hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFileUtil.java

@@ -17,6 +17,7 @@
  */
 package org.apache.hadoop.fs;
 
+import static org.apache.hadoop.test.LambdaTestUtils.intercept;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -43,6 +44,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.Callable;
 import java.util.jar.Attributes;
 import java.util.jar.JarFile;
 import java.util.jar.Manifest;
@@ -1062,6 +1064,50 @@ public class TestFileUtil {
     doUntarAndVerify(new File(tarFileName), untarDir);
   }
 
+  /**
+   * Verify we can't unTar a file which isn't there.
+   * This will test different codepaths on Windows from unix,
+   * but both MUST throw an IOE of some kind.
+   */
+  @Test(timeout = 30000)
+  public void testUntarMissingFile() throws Throwable {
+    final File dataDir = GenericTestUtils.getTestDir();
+    final File tarFile = new File(dataDir, "missing; true");
+    final File untarDir = new File(dataDir, "untarDir");
+    intercept(IOException.class,
+        new Callable<Void>() {
+          @Override
+          public Void call() throws Exception {
+            FileUtil.unTar(tarFile, untarDir);
+            return null;
+          }
+        });
+  }
+
+  /**
+   * Verify we can't unTar a file which isn't there
+   * through the java untar code.
+   * This is how {@code FileUtil.unTar(File, File}
+   * will behave on Windows,
+   */
+  @Test(timeout = 30000)
+  public void testUntarMissingFileThroughJava() throws Throwable {
+    final File dataDir = GenericTestUtils.getTestDir();
+    final File tarFile = new File(dataDir, "missing; true");
+    final File untarDir = new File(dataDir, "untarDir");
+    // java8 on unix throws java.nio.file.NoSuchFileException here;
+    // leaving as an IOE intercept in case windows throws something
+    // else.
+    intercept(IOException.class,
+        new Callable<Void>() {
+          @Override
+          public Void call() throws Exception {
+            FileUtil.unTarUsingJava(tarFile, untarDir, false);
+            return null;
+          }
+        });
+  }
+
   @Test (timeout = 30000)
   public void testCreateJarWithClassPath() throws Exception {
     // setup test directory for files