diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index a55a69f22a..1f01fd8c34 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -468,6 +468,10 @@ Release 2.6.0 - UNRELEASED HADOOP-10857. Native Libraries Guide doen't mention a dependency on openssl-development package (ozawa via cmccabe) + HADOOP-10866. RawLocalFileSystem fails to read symlink targets via the stat + command when the format of the stat command uses non-curly quotes (yzhang + via cmccabe) + Release 2.5.0 - UNRELEASED INCOMPATIBLE CHANGES diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/Stat.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/Stat.java index c2ec63c6e7..5e80a14017 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/Stat.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/Stat.java @@ -128,6 +128,8 @@ protected void parseExecResult(BufferedReader lines) throws IOException { " link " + original); } // 6,symbolic link,6,1373584236,1373584236,lrwxrwxrwx,andrew,andrew,`link' -> `target' + // OR + // 6,symbolic link,6,1373584236,1373584236,lrwxrwxrwx,andrew,andrew,'link' -> 'target' StringTokenizer tokens = new StringTokenizer(line, ","); try { long length = Long.parseLong(tokens.nextToken()); @@ -147,18 +149,17 @@ protected void parseExecResult(BufferedReader lines) throws IOException { String group = tokens.nextToken(); String symStr = tokens.nextToken(); // 'notalink' - // 'link' -> `target' + // `link' -> `target' OR 'link' -> 'target' // '' -> '' Path symlink = null; - StringTokenizer symTokens = new StringTokenizer(symStr, "`"); - symTokens.nextToken(); + String parts[] = symStr.split(" -> "); try { - String target = symTokens.nextToken(); - target = target.substring(0, target.length()-1); + String target = parts[1]; + target = target.substring(1, target.length()-1); if (!target.isEmpty()) { symlink = new Path(target); } - } catch (NoSuchElementException e) { + } catch (ArrayIndexOutOfBoundsException e) { // null if not a symlink } // Set stat diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestStat.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestStat.java index 6dadb01e1f..62650122f9 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestStat.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestStat.java @@ -45,15 +45,15 @@ private class StatOutput { final String doesNotExist; final String directory; final String file; - final String symlink; + final String[] symlinks; final String stickydir; StatOutput(String doesNotExist, String directory, String file, - String symlink, String stickydir) { + String[] symlinks, String stickydir) { this.doesNotExist = doesNotExist; this.directory = directory; this.file = file; - this.symlink = symlink; + this.symlinks = symlinks; this.stickydir = stickydir; } @@ -78,10 +78,12 @@ void test() throws Exception { status = stat.getFileStatusForTesting(); assertTrue(status.isFile()); - br = new BufferedReader(new StringReader(symlink)); - stat.parseExecResult(br); - status = stat.getFileStatusForTesting(); - assertTrue(status.isSymlink()); + for (String symlink : symlinks) { + br = new BufferedReader(new StringReader(symlink)); + stat.parseExecResult(br); + status = stat.getFileStatusForTesting(); + assertTrue(status.isSymlink()); + } br = new BufferedReader(new StringReader(stickydir)); stat.parseExecResult(br); @@ -93,22 +95,30 @@ void test() throws Exception { @Test(timeout=10000) public void testStatLinux() throws Exception { + String[] symlinks = new String[] { + "6,symbolic link,1373584236,1373584236,777,andrew,andrew,`link' -> `target'", + "6,symbolic link,1373584236,1373584236,777,andrew,andrew,'link' -> 'target'" + }; StatOutput linux = new StatOutput( "stat: cannot stat `watermelon': No such file or directory", "4096,directory,1373584236,1373586485,755,andrew,root,`.'", "0,regular empty file,1373584228,1373584228,644,andrew,andrew,`target'", - "6,symbolic link,1373584236,1373584236,777,andrew,andrew,`link' -> `target'", + symlinks, "4096,directory,1374622334,1375124212,1755,andrew,andrew,`stickydir'"); linux.test(); } @Test(timeout=10000) public void testStatFreeBSD() throws Exception { + String[] symlinks = new String[] { + "6,Symbolic Link,1373508941,1373508941,120755,awang,awang,`link' -> `target'" + }; + StatOutput freebsd = new StatOutput( "stat: symtest/link: stat: No such file or directory", "512,Directory,1373583695,1373583669,40755,awang,awang,`link' -> `'", "0,Regular File,1373508937,1373508937,100644,awang,awang,`link' -> `'", - "6,Symbolic Link,1373508941,1373508941,120755,awang,awang,`link' -> `target'", + symlinks, "512,Directory,1375139537,1375139537,41755,awang,awang,`link' -> `'"); freebsd.test(); }