瀏覽代碼

lib/fs: Improve IsParent (#5658)

Simon Frei 6 年之前
父節點
當前提交
e302ccf4b4
共有 2 個文件被更改,包括 81 次插入3 次删除
  1. 64 0
      lib/fs/filesystem_test.go
  2. 17 3
      lib/fs/util.go

+ 64 - 0
lib/fs/filesystem_test.go

@@ -8,6 +8,7 @@ package fs
 
 import (
 	"path/filepath"
+	"runtime"
 	"testing"
 )
 
@@ -106,3 +107,66 @@ func TestFileModeString(t *testing.T) {
 		t.Fatalf("Got %v, expected %v", fm.String(), exp)
 	}
 }
+
+func TestIsParent(t *testing.T) {
+	test := func(path, parent string, expected bool) {
+		t.Helper()
+		path = filepath.FromSlash(path)
+		parent = filepath.FromSlash(parent)
+		if res := IsParent(path, parent); res != expected {
+			t.Errorf(`Unexpected result: IsParent("%v", "%v"): %v should be %v`, path, parent, res, expected)
+		}
+	}
+	testBoth := func(path, parent string, expected bool) {
+		t.Helper()
+		test(path, parent, expected)
+		if runtime.GOOS == "windows" {
+			test("C:/"+path, "C:/"+parent, expected)
+		} else {
+			test("/"+path, "/"+parent, expected)
+		}
+	}
+
+	// rel - abs
+	for _, parent := range []string{"/", "/foo", "/foo/bar"} {
+		for _, path := range []string{"", ".", "foo", "foo/bar", "bas", "bas/baz"} {
+			if runtime.GOOS == "windows" {
+				parent = "C:/" + parent
+			}
+			test(parent, path, false)
+			test(path, parent, false)
+		}
+	}
+
+	// equal
+	for i, path := range []string{"/", "/foo", "/foo/bar", "", ".", "foo", "foo/bar"} {
+		if i < 3 && runtime.GOOS == "windows" {
+			path = "C:" + path
+		}
+		test(path, path, false)
+	}
+
+	test("", ".", false)
+	test(".", "", false)
+	for _, parent := range []string{"", "."} {
+		for _, path := range []string{"foo", "foo/bar"} {
+			test(path, parent, true)
+			test(parent, path, false)
+		}
+	}
+	for _, parent := range []string{"foo", "foo/bar"} {
+		for _, path := range []string{"bar", "bar/foo"} {
+			testBoth(path, parent, false)
+			testBoth(parent, path, false)
+		}
+	}
+	for _, parent := range []string{"foo", "foo/bar"} {
+		for _, path := range []string{"foo/bar/baz", "foo/bar/baz/bas"} {
+			testBoth(path, parent, true)
+			testBoth(parent, path, false)
+			if runtime.GOOS == "windows" {
+				test("C:/"+path, "D:/"+parent, false)
+			}
+		}
+	}
+}

+ 17 - 3
lib/fs/util.go

@@ -78,11 +78,25 @@ func WindowsInvalidFilename(name string) bool {
 	return strings.ContainsAny(name, windowsDisallowedCharacters)
 }
 
+// IsParent compares paths purely lexicographically, meaning it returns false
+// if path and parent aren't both absolute or relative.
 func IsParent(path, parent string) bool {
-	if len(parent) == 0 {
+	if parent == path {
+		// Twice the same root on windows would not be caught at the end.
+		return false
+	}
+	if filepath.IsAbs(path) != filepath.IsAbs(parent) {
+		return false
+	}
+	if parent == "" || parent == "." {
 		// The empty string is the parent of everything except the empty
-		// string. (Avoids panic in the next step.)
-		return len(path) > 0
+		// string and ".". (Avoids panic in the last step.)
+		return path != "" && path != "."
+	}
+	if parent == "/" {
+		// The root is the parent of everything except itself, which would
+		// not be caught below.
+		return path != "/"
 	}
 	if parent[len(parent)-1] != PathSeparator {
 		parent += string(PathSeparator)