diff -u new/src/java.base/share/classes/java/io/FilePermission.java new/src/java.base/share/classes/java/io/FilePermission.java
--- new/src/java.base/share/classes/java/io/FilePermission.java 2017-04-07 22:45:54.258437300 +0800
+++ new/src/java.base/share/classes/java/io/FilePermission.java 2017-04-08 08:33:31.913651300 +0800
@@ -684,28 +684,46 @@
*/
private static int containsPath(Path p1, Path p2) {
+ // Two paths must have the same root. For example,
+ // there is no contains relation between any two of
+ // "/x", "x", "C:/x", "C:x", and "//host/share/x".
if (!Objects.equals(p1.getRoot(), p2.getRoot())) {
return -1;
}
+ // Empty path (i.e. "." or "") is a strange beast,
+ // because its getNameCount()==1 but getName(0) is null.
+ // It's better to deal with it separately.
if (p1.equals(EMPTY_PATH)) {
if (p2.equals(EMPTY_PATH)) {
return 0;
} else if (p2.getName(0).equals(DOTDOT_PATH)) {
+ // "." contains p2 iif p2 has no "..". Since a
+ // a normalized path can only have 0 or more
+ // ".." at the beginning. We only need to look
+ // at the head.
return -1;
} else {
+ // and the distance is p2's name count. i.e.
+ // 3 between "." and "a/b/c".
return p2.getNameCount();
}
} else if (p2.equals(EMPTY_PATH)) {
int c1 = p1.getNameCount();
- for (int j = 0; j < c1; j++) {
- if (!p1.getName(j).equals(DOTDOT_PATH)) {
- return -1;
- }
+ if (!p1.getName(c1 - 1).equals(DOTDOT_PATH)) {
+ // "." is inside p1 iif p1 is 1 or more "..".
+ // For the same reason above, we only need to
+ // look at the tail.
+ return -1;
}
+ // and the distance is the count of ".."
return c1;
}
+ // Good. No more empty paths.
+
+ // Common heads are removed
+
int c1 = p1.getNameCount();
int c2 = p2.getNameCount();
@@ -717,16 +735,23 @@
i++;
}
- for (int j = i; j < c1; j++) {
- if (!p1.getName(j).equals(DOTDOT_PATH)) {
- return -1;
- }
+ // for p1 containing p2, p1 must be 0-or-more "..",
+ // and p2 cannot have "..". For the same reason, we only
+ // check tail of p1 and head of p2.
+ if (i < c1 && !p1.getName(c1 - 1).equals(DOTDOT_PATH)) {
+ return -1;
}
if (i < c2 && p2.getName(i).equals(DOTDOT_PATH)) {
return -1;
}
+ // and the distance is the name counts added (after removing
+ // the common heads).
+
+ // For example: p1 = "../../..", p2 = "../a".
+ // After removing the common heads, they become "../.." and "a",
+ // and the distance is (3-1)+(2-1) = 3.
return c1 - i + c2 - i;
}