diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractMkdirTest.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractMkdirTest.java index 71d27067bd..c5a546dccd 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractMkdirTest.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/contract/AbstractContractMkdirTest.java @@ -113,18 +113,25 @@ public void testMkdirSlashHandling() throws Throwable { describe("verify mkdir slash handling"); FileSystem fs = getFileSystem(); - // No trailing slash - assertTrue(fs.mkdirs(path("testmkdir/a"))); - assertPathExists("mkdir without trailing slash failed", - path("testmkdir/a")); - - // With trailing slash - assertTrue(fs.mkdirs(path("testmkdir/b/"))); - assertPathExists("mkdir with trailing slash failed", path("testmkdir/b/")); - - // Mismatched slashes - assertPathExists("check path existence without trailing slash failed", - path("testmkdir/b")); + final Path[] paths = new Path[] { + path("testMkdirSlashHandling/a"), // w/o trailing slash + path("testMkdirSlashHandling/b/"), // w/ trailing slash + // unqualified w/o trailing slash + new Path(getContract().getTestPath() + "/testMkdirSlashHandling/c"), + // unqualified w/ trailing slash + new Path(getContract().getTestPath() + "/testMkdirSlashHandling/d/"), + // unqualified w/ multiple trailing slashes + new Path(getContract().getTestPath() + "/testMkdirSlashHandling/e///") + }; + for (Path path : paths) { + assertTrue(fs.mkdirs(path)); + assertPathExists(path + " does not exist after mkdirs", path); + assertIsDirectory(path); + if (path.toString().endsWith("/")) { + String s = path.toString().substring(0, path.toString().length() - 1); + assertIsDirectory(new Path(s)); + } + } } @Test diff --git a/hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AFileSystem.java b/hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AFileSystem.java index 25f26713b5..872dd5fd5c 100644 --- a/hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AFileSystem.java +++ b/hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AFileSystem.java @@ -1587,7 +1587,9 @@ private boolean innerMkdirs(Path f, FsPermission permission) String key = pathToKey(f); createFakeDirectory(key); - deleteUnnecessaryFakeDirectories(f.getParent()); + // this is complicated because getParent(a/b/c/) returns a/b/c, but + // we want a/b. See HADOOP-14428 for more details. + deleteUnnecessaryFakeDirectories(new Path(f.toString()).getParent()); return true; } } @@ -1971,6 +1973,7 @@ private void deleteUnnecessaryFakeDirectories(Path path) { while (!path.isRoot()) { String key = pathToKey(path); key = (key.endsWith("/")) ? key : (key + "/"); + LOG.trace("To delete unnecessary fake directory {} for {}", key, path); keysToRemove.add(new DeleteObjectsRequest.KeyVersion(key)); path = path.getParent(); }