From 9cda28ef0dec95df3ea5ae7d3d064d5673566be7 Mon Sep 17 00:00:00 2001 From: Chris Nauroth Date: Wed, 16 Oct 2013 20:15:09 +0000 Subject: [PATCH] HADOOP-9897. Merging change r1532880 from trunk to branch-2. git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1532883 13f79535-47bb-0310-9956-ffa450edef68 --- .../hadoop-common/CHANGES.txt | 3 ++ .../main/java/org/apache/hadoop/fs/Path.java | 42 +++++++++++-------- .../java/org/apache/hadoop/fs/TestPath.java | 19 +++++++++ 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index a41943f71c6..1474dfc0b48 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -70,6 +70,9 @@ Release 2.3.0 - UNRELEASED HADOOP-9494. Excluded auto-generated and examples code from clover reports (Andrey Klochkov via jeagles) + HADOOP-9897. Add method to get path start position without drive specifier in + o.a.h.fs.Path. (Binglin Chang via cnauroth) + OPTIMIZATIONS HADOOP-9748. Reduce blocking on UGI.ensureInitialized (daryn) diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/Path.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/Path.java index 2d3acd0f8bb..54ddedaff1d 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/Path.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/Path.java @@ -218,10 +218,13 @@ public class Path implements Comparable { */ public static Path mergePaths(Path path1, Path path2) { String path2Str = path2.toUri().getPath(); - if(hasWindowsDrive(path2Str)) { - path2Str = path2Str.substring(path2Str.indexOf(':')+1); - } - return new Path(path1 + path2Str); + path2Str = path2Str.substring(startPositionWithoutWindowsDrive(path2Str)); + // Add path components explicitly, because simply concatenating two path + // string is not safe, for example: + // "/" + "/foo" yields "//foo", which will be parsed as authority in Path + return new Path(path1.toUri().getScheme(), + path1.toUri().getAuthority(), + path1.toUri().getPath() + path2Str); } /** @@ -247,8 +250,8 @@ public class Path implements Comparable { } // trim trailing slash from non-root path (ignoring windows drive) - int minLength = hasWindowsDrive(path) ? 4 : 1; - if (path.length() > minLength && path.endsWith("/")) { + int minLength = startPositionWithoutWindowsDrive(path) + 1; + if (path.length() > minLength && path.endsWith(SEPARATOR)) { path = path.substring(0, path.length()-1); } @@ -259,6 +262,14 @@ public class Path implements Comparable { return (WINDOWS && hasDriveLetterSpecifier.matcher(path).find()); } + private static int startPositionWithoutWindowsDrive(String path) { + if (hasWindowsDrive(path)) { + return path.charAt(0) == SEPARATOR_CHAR ? 3 : 2; + } else { + return 0; + } + } + /** * Determine whether a given path string represents an absolute path on * Windows. e.g. "C:/a/b" is an absolute path. "C:a/b" is not. @@ -270,13 +281,11 @@ public class Path implements Comparable { */ public static boolean isWindowsAbsolutePath(final String pathString, final boolean slashed) { - int start = (slashed ? 1 : 0); - - return - hasWindowsDrive(pathString) && - pathString.length() >= (start + 3) && - ((pathString.charAt(start + 2) == SEPARATOR_CHAR) || - (pathString.charAt(start + 2) == '\\')); + int start = startPositionWithoutWindowsDrive(pathString); + return start > 0 + && pathString.length() > start + && ((pathString.charAt(start) == SEPARATOR_CHAR) || + (pathString.charAt(start) == '\\')); } /** Convert this to a URI. */ @@ -300,7 +309,7 @@ public class Path implements Comparable { * True if the path component (i.e. directory) of this URI is absolute. */ public boolean isUriPathAbsolute() { - int start = hasWindowsDrive(uri.getPath()) ? 3 : 0; + int start = startPositionWithoutWindowsDrive(uri.getPath()); return uri.getPath().startsWith(SEPARATOR, start); } @@ -334,7 +343,7 @@ public class Path implements Comparable { public Path getParent() { String path = uri.getPath(); int lastSlash = path.lastIndexOf('/'); - int start = hasWindowsDrive(path) ? 3 : 0; + int start = startPositionWithoutWindowsDrive(path); if ((path.length() == start) || // empty path (lastSlash == start && path.length() == start+1)) { // at root return null; @@ -343,8 +352,7 @@ public class Path implements Comparable { if (lastSlash==-1) { parent = CUR_DIR; } else { - int end = hasWindowsDrive(path) ? 3 : 0; - parent = path.substring(0, lastSlash==end?end+1:lastSlash); + parent = path.substring(0, lastSlash==start?start+1:lastSlash); } return new Path(uri.getScheme(), uri.getAuthority(), parent); } diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestPath.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestPath.java index f0a457b4127..2504edf421b 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestPath.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestPath.java @@ -460,6 +460,13 @@ public class TestPath extends TestCase { Path.mergePaths(new Path("/C:/foo"), new Path("/C:/bar"))); + assertEquals(new Path(Shell.WINDOWS ? "/C:/bar" : "/C:/C:/bar"), + Path.mergePaths(new Path("/C:/"), + new Path("/C:/bar"))); + + assertEquals(new Path("/bar"), + Path.mergePaths(new Path("/"), new Path("/bar"))); + assertEquals(new Path("viewfs:///foo/bar"), Path.mergePaths(new Path("viewfs:///foo"), new Path("file:///bar"))); @@ -468,4 +475,16 @@ public class TestPath extends TestCase { Path.mergePaths(new Path("viewfs://vfsauthority/foo"), new Path("file://fileauthority/bar"))); } + + @Test (timeout = 30000) + public void testIsWindowsAbsolutePath() { + if (!Shell.WINDOWS) return; + assertTrue(Path.isWindowsAbsolutePath("C:\\test", false)); + assertTrue(Path.isWindowsAbsolutePath("C:/test", false)); + assertTrue(Path.isWindowsAbsolutePath("/C:/test", true)); + assertFalse(Path.isWindowsAbsolutePath("/test", false)); + assertFalse(Path.isWindowsAbsolutePath("/test", true)); + assertFalse(Path.isWindowsAbsolutePath("C:test", false)); + assertFalse(Path.isWindowsAbsolutePath("/C:test", true)); + } }