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 aaa02fe3ec..d0a66be4d2 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 @@ -58,6 +58,7 @@ import org.apache.commons.collections.map.CaseInsensitiveMap; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.io.FileUtils; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.conf.Configuration; @@ -182,7 +183,7 @@ public static boolean fullyDelete(final File dir, boolean tryGrantPermissions) { return true; } // handle nonempty directory deletion - if (!fullyDeleteContents(dir, tryGrantPermissions)) { + if (!FileUtils.isSymlink(dir) && !fullyDeleteContents(dir, tryGrantPermissions)) { return false; } return deleteImpl(dir, true); 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 1ca1f241e5..3a88b7352f 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 @@ -447,6 +447,35 @@ public void testFailFullyDeleteGrantPermissions() throws IOException { validateAndSetWritablePermissions(false, ret); } + + /** + * Tests if fullyDelete deletes symlink's content when deleting unremovable dir symlink. + * @throws IOException + */ + @Test (timeout = 30000) + public void testFailFullyDeleteDirSymlinks() throws IOException { + File linkDir = new File(del, "tmpDir"); + FileUtil.setWritable(del, false); + // Since tmpDir is symlink to tmp, fullyDelete(tmpDir) should not + // delete contents of tmp. See setupDirs for details. + boolean ret = FileUtil.fullyDelete(linkDir); + // fail symlink deletion + Assert.assertFalse(ret); + Assert.assertTrue(linkDir.exists()); + Assert.assertEquals(5, del.list().length); + // tmp dir should exist + validateTmpDir(); + // simulate disk recovers and turns good + FileUtil.setWritable(del, true); + ret = FileUtil.fullyDelete(linkDir); + // success symlink deletion + Assert.assertTrue(ret); + Assert.assertFalse(linkDir.exists()); + Assert.assertEquals(4, del.list().length); + // tmp dir should exist + validateTmpDir(); + } + /** * Extend {@link File}. Same as {@link File} except for two things: (1) This * treats file1Name as a very special file which is not delete-able