From 10a7270f438751697fbd8dca66fae697bda557b5 Mon Sep 17 00:00:00 2001 From: Steve Loughran Date: Mon, 21 Feb 2022 17:08:22 +0000 Subject: [PATCH] HADOOP-18136. Verify FileUtils.unTar() handling of missing .tar files. Contributed by Steve Loughran Change-Id: I767e11bc3b2133aa4aa36d837162673930e1e7e1 --- .../java/org/apache/hadoop/fs/FileUtil.java | 15 ++++++--- .../org/apache/hadoop/fs/TestFileUtil.java | 33 +++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileUtil.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileUtil.java index 61c30aa4d22..bdac26aa3a6 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileUtil.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileUtil.java @@ -887,10 +887,13 @@ public class FileUtil { 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.makeSecureShellPath(inFile) + "'"; if (gzipped) { - untarCommand.append(" gzip -dc '"); - untarCommand.append(FileUtil.makeSecureShellPath(inFile)); - untarCommand.append("' | ("); + untarCommand.append(" gzip -dc ") + .append(source) + .append(" | ("); } untarCommand.append("cd '"); untarCommand.append(FileUtil.makeSecureShellPath(untarDir)); @@ -900,15 +903,17 @@ public class FileUtil { if (gzipped) { untarCommand.append(" -)"); } else { - untarCommand.append(FileUtil.makeSecureShellPath(inFile)); + untarCommand.append(source); } + 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); + ". Tar process exited with exit code " + exitcode + + " from command " + untarCommand); } } diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFileUtil.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFileUtil.java index c38faea632a..5e27ba70c4b 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestFileUtil.java +++ b/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.apache.hadoop.test.PlatformAssumptions.assumeNotWindows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -1008,6 +1009,38 @@ 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 { + File dataDir = GenericTestUtils.getTestDir(); + File tarFile = new File(dataDir, "missing; true"); + File untarDir = new File(dataDir, "untarDir"); + intercept(IOException.class, () -> + FileUtil.unTar(tarFile, untarDir)); + } + + /** + * 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 { + File dataDir = GenericTestUtils.getTestDir(); + File tarFile = new File(dataDir, "missing; true"); + 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, () -> + FileUtil.unTarUsingJava(tarFile, untarDir, false)); + } + @Test (timeout = 30000) public void testCreateJarWithClassPath() throws Exception { // setup test directory for files