From 66036d61d7a3f0af2ed4e550b626e0f4a5689acf Mon Sep 17 00:00:00 2001 From: Uma Maheswara Rao G Date: Sat, 6 Jun 2020 22:44:35 -0700 Subject: [PATCH 1/5] HADOOP-17060. listStatus and getFileStatus behave inconsistent in the case of ViewFs implementation for isDirectory --- .../java/org/apache/hadoop/fs/FileStatus.java | 6 ------ .../hadoop/fs/viewfs/ViewFileSystem.java | 19 +++++++++---------- .../org/apache/hadoop/fs/viewfs/ViewFs.java | 18 ++++++++++-------- .../hadoop/fs/viewfs/ViewFsBaseTest.java | 7 ++++++- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileStatus.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileStatus.java index d7ca8f172f8e2..8527fee6e6a26 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileStatus.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileStatus.java @@ -170,12 +170,6 @@ public FileStatus(long length, boolean isdir, int block_replication, this.symlink = symlink; this.path = path; this.attr = attr; - - // The variables isdir and symlink indicate the type: - // 1. isdir implies directory, in which case symlink must be null. - // 2. !isdir implies a file or symlink, symlink != null implies a - // symlink, otherwise it's a file. - assert (isdir && symlink == null) || !isdir; } /** diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java index 2711bff0ff2f1..2e6b5d9b3c3b1 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java @@ -1202,19 +1202,18 @@ public FileStatus[] listStatus(Path f) throws AccessControlException, INodeLink link = (INodeLink) inode; try { String linkedPath = link.getTargetFileSystem().getUri().getPath(); - if("".equals(linkedPath)) { + if ("".equals(linkedPath)) { linkedPath = "/"; } FileStatus status = - ((ChRootedFileSystem)link.getTargetFileSystem()) - .getMyFs().getFileStatus(new Path(linkedPath)); - result[i++] = new FileStatus(status.getLen(), false, - status.getReplication(), status.getBlockSize(), - status.getModificationTime(), status.getAccessTime(), - status.getPermission(), status.getOwner(), status.getGroup(), - link.getTargetLink(), - new Path(inode.fullPath).makeQualified( - myUri, null)); + ((ChRootedFileSystem) link.getTargetFileSystem()).getMyFs() + .getFileStatus(new Path(linkedPath)); + result[i++] = new FileStatus(status.getLen(), status.isDirectory(), + status.getReplication(), status.getBlockSize(), + status.getModificationTime(), status.getAccessTime(), + status.getPermission(), status.getOwner(), status.getGroup(), + link.getTargetLink(), + new Path(inode.fullPath).makeQualified(myUri, null)); } catch (FileNotFoundException ex) { result[i++] = new FileStatus(0, false, 0, 0, creationTime, creationTime, PERMISSION_555, diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java index df10dce50b78f..90a176bcb08a8 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java @@ -992,15 +992,17 @@ public FileStatus[] listStatus(final Path f) throws AccessControlException, try { String linkedPath = link.getTargetFileSystem().getUri().getPath(); - FileStatus status = ((ChRootedFs)link.getTargetFileSystem()) + if ("".equals(linkedPath)) { + linkedPath = "/"; + } + FileStatus status = ((ChRootedFs) link.getTargetFileSystem()) .getMyFs().getFileStatus(new Path(linkedPath)); - result[i++] = new FileStatus(status.getLen(), false, - status.getReplication(), status.getBlockSize(), - status.getModificationTime(), status.getAccessTime(), - status.getPermission(), status.getOwner(), status.getGroup(), - link.getTargetLink(), - new Path(inode.fullPath).makeQualified( - myUri, null)); + result[i++] = new FileStatus(status.getLen(), status.isDirectory(), + status.getReplication(), status.getBlockSize(), + status.getModificationTime(), status.getAccessTime(), + status.getPermission(), status.getOwner(), status.getGroup(), + link.getTargetLink(), + new Path(inode.fullPath).makeQualified(myUri, null)); } catch (FileNotFoundException ex) { result[i++] = new FileStatus(0, false, 0, 0, creationTime, creationTime, PERMISSION_555, diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java index d96cdb172b702..782a5078054e3 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java @@ -486,6 +486,9 @@ public void testListOnInternalDirsOfMountTable() throws IOException { fs = fileContextTestHelper.containsPath(fcView, "/user", dirPaths); Assert.assertNotNull(fs); Assert.assertTrue("A mount should appear as symlink", fs.isSymlink()); + Assert.assertTrue( + "A mount link should appear as directory if target is directory", + fs.isDirectory()); fs = fileContextTestHelper.containsPath(fcView, "/data", dirPaths); Assert.assertNotNull(fs); Assert.assertTrue("A mount should appear as symlink", fs.isSymlink()); @@ -498,7 +501,9 @@ public void testListOnInternalDirsOfMountTable() throws IOException { fs = fileContextTestHelper.containsPath(fcView, "/linkToAFile", dirPaths); Assert.assertNotNull(fs); Assert.assertTrue("A mount should appear as symlink", fs.isSymlink()); - + Assert.assertFalse( + "A mount should appear as non dir if target link is a file", + fs.isDirectory()); // list on internal dir From 32f0c7fe440d44364299bfe012c8c332c2726ca7 Mon Sep 17 00:00:00 2001 From: Uma Maheswara Rao G Date: Sun, 7 Jun 2020 15:25:03 -0700 Subject: [PATCH 2/5] Checkstyle fixes --- .../org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java index 782a5078054e3..648055da78750 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java @@ -486,9 +486,8 @@ public void testListOnInternalDirsOfMountTable() throws IOException { fs = fileContextTestHelper.containsPath(fcView, "/user", dirPaths); Assert.assertNotNull(fs); Assert.assertTrue("A mount should appear as symlink", fs.isSymlink()); - Assert.assertTrue( - "A mount link should appear as directory if target is directory", - fs.isDirectory()); + // When target is a dir, mount link also should appear as dir + Assert.assertTrue("A mount should appear as dir", fs.isDirectory()); fs = fileContextTestHelper.containsPath(fcView, "/data", dirPaths); Assert.assertNotNull(fs); Assert.assertTrue("A mount should appear as symlink", fs.isSymlink()); @@ -501,10 +500,8 @@ public void testListOnInternalDirsOfMountTable() throws IOException { fs = fileContextTestHelper.containsPath(fcView, "/linkToAFile", dirPaths); Assert.assertNotNull(fs); Assert.assertTrue("A mount should appear as symlink", fs.isSymlink()); - Assert.assertFalse( - "A mount should appear as non dir if target link is a file", - fs.isDirectory()); - + // When target is a file, mount link also should appear as non dir + Assert.assertFalse("A mount should appear as file", fs.isDirectory()); // list on internal dir dirPaths = fcView.util().listStatus(new Path("/internalDir")); From 2bc0eb4f672ef65036af34f95466d16145c95709 Mon Sep 17 00:00:00 2001 From: Uma Maheswara Rao G Date: Tue, 9 Jun 2020 23:31:42 -0700 Subject: [PATCH 3/5] Revert "Checkstyle fixes" This reverts commit 32f0c7fe440d44364299bfe012c8c332c2726ca7. --- .../org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java index 648055da78750..782a5078054e3 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java @@ -486,8 +486,9 @@ public void testListOnInternalDirsOfMountTable() throws IOException { fs = fileContextTestHelper.containsPath(fcView, "/user", dirPaths); Assert.assertNotNull(fs); Assert.assertTrue("A mount should appear as symlink", fs.isSymlink()); - // When target is a dir, mount link also should appear as dir - Assert.assertTrue("A mount should appear as dir", fs.isDirectory()); + Assert.assertTrue( + "A mount link should appear as directory if target is directory", + fs.isDirectory()); fs = fileContextTestHelper.containsPath(fcView, "/data", dirPaths); Assert.assertNotNull(fs); Assert.assertTrue("A mount should appear as symlink", fs.isSymlink()); @@ -500,8 +501,10 @@ public void testListOnInternalDirsOfMountTable() throws IOException { fs = fileContextTestHelper.containsPath(fcView, "/linkToAFile", dirPaths); Assert.assertNotNull(fs); Assert.assertTrue("A mount should appear as symlink", fs.isSymlink()); - // When target is a file, mount link also should appear as non dir - Assert.assertFalse("A mount should appear as file", fs.isDirectory()); + Assert.assertFalse( + "A mount should appear as non dir if target link is a file", + fs.isDirectory()); + // list on internal dir dirPaths = fcView.util().listStatus(new Path("/internalDir")); From 6d4e1d1986487b26587b3b49a7d08b1f6a3a2a2f Mon Sep 17 00:00:00 2001 From: Uma Maheswara Rao G Date: Tue, 9 Jun 2020 23:35:43 -0700 Subject: [PATCH 4/5] Revert "HADOOP-17060. listStatus and getFileStatus behave inconsistent in the case of ViewFs implementation for isDirectory" This reverts commit 66036d61d7a3f0af2ed4e550b626e0f4a5689acf. --- .../java/org/apache/hadoop/fs/FileStatus.java | 6 ++++++ .../hadoop/fs/viewfs/ViewFileSystem.java | 19 ++++++++++--------- .../org/apache/hadoop/fs/viewfs/ViewFs.java | 18 ++++++++---------- .../hadoop/fs/viewfs/ViewFsBaseTest.java | 7 +------ 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileStatus.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileStatus.java index 8527fee6e6a26..d7ca8f172f8e2 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileStatus.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileStatus.java @@ -170,6 +170,12 @@ public FileStatus(long length, boolean isdir, int block_replication, this.symlink = symlink; this.path = path; this.attr = attr; + + // The variables isdir and symlink indicate the type: + // 1. isdir implies directory, in which case symlink must be null. + // 2. !isdir implies a file or symlink, symlink != null implies a + // symlink, otherwise it's a file. + assert (isdir && symlink == null) || !isdir; } /** diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java index 2e6b5d9b3c3b1..2711bff0ff2f1 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java @@ -1202,18 +1202,19 @@ public FileStatus[] listStatus(Path f) throws AccessControlException, INodeLink link = (INodeLink) inode; try { String linkedPath = link.getTargetFileSystem().getUri().getPath(); - if ("".equals(linkedPath)) { + if("".equals(linkedPath)) { linkedPath = "/"; } FileStatus status = - ((ChRootedFileSystem) link.getTargetFileSystem()).getMyFs() - .getFileStatus(new Path(linkedPath)); - result[i++] = new FileStatus(status.getLen(), status.isDirectory(), - status.getReplication(), status.getBlockSize(), - status.getModificationTime(), status.getAccessTime(), - status.getPermission(), status.getOwner(), status.getGroup(), - link.getTargetLink(), - new Path(inode.fullPath).makeQualified(myUri, null)); + ((ChRootedFileSystem)link.getTargetFileSystem()) + .getMyFs().getFileStatus(new Path(linkedPath)); + result[i++] = new FileStatus(status.getLen(), false, + status.getReplication(), status.getBlockSize(), + status.getModificationTime(), status.getAccessTime(), + status.getPermission(), status.getOwner(), status.getGroup(), + link.getTargetLink(), + new Path(inode.fullPath).makeQualified( + myUri, null)); } catch (FileNotFoundException ex) { result[i++] = new FileStatus(0, false, 0, 0, creationTime, creationTime, PERMISSION_555, diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java index 90a176bcb08a8..df10dce50b78f 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java @@ -992,17 +992,15 @@ public FileStatus[] listStatus(final Path f) throws AccessControlException, try { String linkedPath = link.getTargetFileSystem().getUri().getPath(); - if ("".equals(linkedPath)) { - linkedPath = "/"; - } - FileStatus status = ((ChRootedFs) link.getTargetFileSystem()) + FileStatus status = ((ChRootedFs)link.getTargetFileSystem()) .getMyFs().getFileStatus(new Path(linkedPath)); - result[i++] = new FileStatus(status.getLen(), status.isDirectory(), - status.getReplication(), status.getBlockSize(), - status.getModificationTime(), status.getAccessTime(), - status.getPermission(), status.getOwner(), status.getGroup(), - link.getTargetLink(), - new Path(inode.fullPath).makeQualified(myUri, null)); + result[i++] = new FileStatus(status.getLen(), false, + status.getReplication(), status.getBlockSize(), + status.getModificationTime(), status.getAccessTime(), + status.getPermission(), status.getOwner(), status.getGroup(), + link.getTargetLink(), + new Path(inode.fullPath).makeQualified( + myUri, null)); } catch (FileNotFoundException ex) { result[i++] = new FileStatus(0, false, 0, 0, creationTime, creationTime, PERMISSION_555, diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java index 782a5078054e3..d96cdb172b702 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/ViewFsBaseTest.java @@ -486,9 +486,6 @@ public void testListOnInternalDirsOfMountTable() throws IOException { fs = fileContextTestHelper.containsPath(fcView, "/user", dirPaths); Assert.assertNotNull(fs); Assert.assertTrue("A mount should appear as symlink", fs.isSymlink()); - Assert.assertTrue( - "A mount link should appear as directory if target is directory", - fs.isDirectory()); fs = fileContextTestHelper.containsPath(fcView, "/data", dirPaths); Assert.assertNotNull(fs); Assert.assertTrue("A mount should appear as symlink", fs.isSymlink()); @@ -501,9 +498,7 @@ public void testListOnInternalDirsOfMountTable() throws IOException { fs = fileContextTestHelper.containsPath(fcView, "/linkToAFile", dirPaths); Assert.assertNotNull(fs); Assert.assertTrue("A mount should appear as symlink", fs.isSymlink()); - Assert.assertFalse( - "A mount should appear as non dir if target link is a file", - fs.isDirectory()); + // list on internal dir From 6960825f72b63ec8fb4982293650826a2fe9fdf7 Mon Sep 17 00:00:00 2001 From: Uma Maheswara Rao G Date: Wed, 10 Jun 2020 01:20:43 -0700 Subject: [PATCH 5/5] HADOOP-17060. listStatus and getFileStatus behave inconsistent in the case of ViewFs implementation for isDirectory --- .../hadoop/fs/viewfs/ViewFileSystem.java | 36 ++++++++++++++----- .../org/apache/hadoop/fs/viewfs/ViewFs.java | 24 +++++++++++++ .../main/java/org/apache/hadoop/fs/Hdfs.java | 22 ++++++++++++ .../hadoop/hdfs/DistributedFileSystem.java | 25 ++++++++++--- 4 files changed, 94 insertions(+), 13 deletions(-) diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java index 2711bff0ff2f1..9fd86a1130e4e 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java @@ -488,6 +488,14 @@ private static FileStatus wrapLocalFileStatus(FileStatus orig, : new ViewFsFileStatus(orig, qualified); } + /** + * {@inheritDoc} + * + * If the given path is a symlink(mount link), the path will be resolved to a + * target path and it will get the resolved path's FileStatus object. It will + * not be represented as a symlink and isDirectory API returns true if the + * resolved path is a directory, false otherwise. + */ @Override public FileStatus getFileStatus(final Path f) throws AccessControlException, FileNotFoundException, IOException { @@ -505,6 +513,25 @@ public void access(Path path, FsAction mode) throws AccessControlException, res.targetFileSystem.access(res.remainingPath, mode); } + /** + * {@inheritDoc} + * + * Note: listStatus on root("/") considers listing from fallbackLink if + * available. If the same directory name is present in configured mount path + * as well as in fallback link, then only the configured mount path will be + * listed in the returned result. + * + * If any of the the immediate children of the given path f is a symlink(mount + * link), the returned FileStatus object of that children would be represented + * as a symlink. It will not be resolved to the target path and will not get + * the target path FileStatus object. The target path will be available via + * getSymlink on that children's FileStatus object. Since it represents as + * symlink, isDirectory on that children's FileStatus will return false. + * + * If you want to get the FileStatus of target path for that children, you may + * want to use GetFileStatus API with that children's symlink path. Please see + * {@link ViewFileSystem#getFileStatus(Path f)} + */ @Override public FileStatus[] listStatus(final Path f) throws AccessControlException, FileNotFoundException, IOException { @@ -1174,20 +1201,11 @@ public FileStatus getFileStatus(Path f) throws IOException { checkPathIsSlash(f); return new FileStatus(0, true, 0, 0, creationTime, creationTime, PERMISSION_555, ugi.getShortUserName(), ugi.getPrimaryGroupName(), - new Path(theInternalDir.fullPath).makeQualified( myUri, ROOT_PATH)); } - /** - * {@inheritDoc} - * - * Note: listStatus on root("/") considers listing from fallbackLink if - * available. If the same directory name is present in configured mount - * path as well as in fallback link, then only the configured mount path - * will be listed in the returned result. - */ @Override public FileStatus[] listStatus(Path f) throws AccessControlException, FileNotFoundException, IOException { diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java index df10dce50b78f..4578a4c353e40 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFs.java @@ -351,6 +351,14 @@ public FileChecksum getFileChecksum(final Path f) return res.targetFileSystem.getFileChecksum(res.remainingPath); } + /** + * {@inheritDoc} + * + * If the given path is a symlink(mount link), the path will be resolved to a + * target path and it will get the resolved path's FileStatus object. It will + * not be represented as a symlink and isDirectory API returns true if the + * resolved path is a directory, false otherwise. + */ @Override public FileStatus getFileStatus(final Path f) throws AccessControlException, FileNotFoundException, UnresolvedLinkException, IOException { @@ -436,6 +444,22 @@ public LocatedFileStatus getViewFsFileStatus(LocatedFileStatus stat, }; } + /** + * {@inheritDoc} + * + * If any of the the immediate children of the given path f is a symlink(mount + * link), the returned FileStatus object of that children would be represented + * as a symlink. It will not be resolved to the target path and will not get + * the target path FileStatus object. The target path will be available via + * getSymlink on that children's FileStatus object. Since it represents as + * symlink, isDirectory on that children's FileStatus will return false. + * + * If you want to get the FileStatus of target path for that children, you may + * want to use GetFileStatus API with that children's symlink path. Please see + * {@link ViewFs#getFileStatus(Path f)} + * + * Note: In ViewFs, the mount links are represented as symlinks. + */ @Override public FileStatus[] listStatus(final Path f) throws AccessControlException, FileNotFoundException, UnresolvedLinkException, IOException { diff --git a/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/fs/Hdfs.java b/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/fs/Hdfs.java index 290f2c0e6766f..4162b198fb124 100644 --- a/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/fs/Hdfs.java +++ b/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/fs/Hdfs.java @@ -135,6 +135,14 @@ public FileChecksum getFileChecksum(Path f) return dfs.getFileChecksumWithCombineMode(getUriPath(f), Long.MAX_VALUE); } + /** + * {@inheritDoc} + * + * If the given path is a symlink, the path will be resolved to a target path + * and it will get the resolved path's FileStatus object. It will not be + * represented as a symlink and isDirectory API returns true if the resolved + * path is a directory, false otherwise. + */ @Override public FileStatus getFileStatus(Path f) throws IOException, UnresolvedLinkException { @@ -269,6 +277,20 @@ public HdfsFileStatus getNext() throws IOException { } } + /** + * {@inheritDoc} + * + * If any of the the immediate children of the given path f is a symlink, the + * returned FileStatus object of that children would be represented as a + * symlink. It will not be resolved to the target path and will not get the + * target path FileStatus object. The target path will be available via + * getSymlink on that children's FileStatus object. Since it represents as + * symlink, isDirectory on that children's FileStatus will return false. + * + * If you want to get the FileStatus of target path for that children, you may + * want to use GetFileStatus API with that children's symlink path. Please see + * {@link Hdfs#getFileStatus(Path f)} + */ @Override public FileStatus[] listStatus(Path f) throws IOException, UnresolvedLinkException { diff --git a/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/DistributedFileSystem.java b/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/DistributedFileSystem.java index b4a932ef142f8..55e228d34ebb8 100644 --- a/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/DistributedFileSystem.java +++ b/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/DistributedFileSystem.java @@ -1143,10 +1143,21 @@ private FileStatus[] listStatusInternal(Path p) throws IOException { /** * List all the entries of a directory * - * Note that this operation is not atomic for a large directory. - * The entries of a directory may be fetched from NameNode multiple times. - * It only guarantees that each name occurs once if a directory - * undergoes changes between the calls. + * Note that this operation is not atomic for a large directory. The entries + * of a directory may be fetched from NameNode multiple times. It only + * guarantees that each name occurs once if a directory undergoes changes + * between the calls. + * + * If any of the the immediate children of the given path f is a symlink, the + * returned FileStatus object of that children would be represented as a + * symlink. It will not be resolved to the target path and will not get the + * target path FileStatus object. The target path will be available via + * getSymlink on that children's FileStatus object. Since it represents as + * symlink, isDirectory on that children's FileStatus will return false. + * + * If you want to get the FileStatus of target path for that children, you may + * want to use GetFileStatus API with that children's symlink path. Please see + * {@link DistributedFileSystem#getFileStatus(Path f)} */ @Override public FileStatus[] listStatus(Path p) throws IOException { @@ -1712,6 +1723,12 @@ public FsServerDefaults getServerDefaults() throws IOException { /** * Returns the stat information about the file. + * + * If the given path is a symlink, the path will be resolved to a target path + * and it will get the resolved path's FileStatus object. It will not be + * represented as a symlink and isDirectory API returns true if the resolved + * path is a directory, false otherwise. + * * @throws FileNotFoundException if the file does not exist. */ @Override