aboutsummaryrefslogtreecommitdiff
path: root/src/path/filepath/path_test.go
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2022-10-19 14:41:03 -0700
committerDamien Neil <dneil@google.com>2022-11-09 22:06:00 +0000
commitbe9d78c9c5905fbc10d8cd6a4714dd4ad1c91674 (patch)
treea512b557f9b117dbfbf5ab027268e7a304131d9c /src/path/filepath/path_test.go
parent575964d42c7b3001c09f2676d0ee9d520debb5eb (diff)
downloadgo-be9d78c9c5905fbc10d8cd6a4714dd4ad1c91674.tar.xz
path/filepath: detect all forms of \\ volume paths on Windows
Previously, the volumeNameLen function checked for UNC paths starting with two slashes, a non-'.' character, and another slash. This misses volume names such as "\\.\C:\". The previous check for volume names rejects paths beginning with "\\.". This is incorrect, because while these names are not UNC paths, "\\.\C:\" is a DOS device path prefix indicating the C: device. It also misses UNC path prefixes in the form "\\.\UNC\server\share\". The previous check for UNC paths also rejects any path with an empty or missing host or share component. This leads to a number of possibly-incorrect behaviors, such as Clean(`\\a`) returning `\a`. Converting the semantically-significant `\\` prefix to a single `\` seems wrong. Consistently treat paths beginning with two separators as having a volume prefix. Update VolumeName to detect DOS device paths (`\\.\` or `\\?\`), DOS device paths linking to UNC paths (`\\.\UNC\Server\Share` or `\\?\UNC\Server\Share`), and UNC paths (`\\Server\Share\`). Clean(`\\a`) = `\\a` Join(`\\`, `a`, `b`) = `\\a\b` In addition, normalize path separators in VolumeName for consistency with other functions which Clean their result. Fixes #56336 Change-Id: Id01c33029585bfffc313dcf0ad42ff6ac7ce42fd Reviewed-on: https://go-review.googlesource.com/c/go/+/444280 Run-TryBot: Damien Neil <dneil@google.com> Reviewed-by: Quim Muntal <quimmuntal@gmail.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Roland Shoemaker <roland@golang.org>
Diffstat (limited to 'src/path/filepath/path_test.go')
-rw-r--r--src/path/filepath/path_test.go83
1 files changed, 58 insertions, 25 deletions
diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go
index 9bdc58ea35..473a89b9c5 100644
--- a/src/path/filepath/path_test.go
+++ b/src/path/filepath/path_test.go
@@ -49,9 +49,6 @@ var cleantests = []PathTest{
// Remove doubled slash
{"abc//def//ghi", "abc/def/ghi"},
- {"//abc", "/abc"},
- {"///abc", "/abc"},
- {"//abc//", "/abc"},
{"abc//", "abc"},
// Remove . elements
@@ -76,6 +73,13 @@ var cleantests = []PathTest{
{"abc/../../././../def", "../../def"},
}
+var nonwincleantests = []PathTest{
+ // Remove leading doubled slash
+ {"//abc", "/abc"},
+ {"///abc", "/abc"},
+ {"//abc//", "/abc"},
+}
+
var wincleantests = []PathTest{
{`c:`, `c:.`},
{`c:\`, `c:\`},
@@ -86,16 +90,22 @@ var wincleantests = []PathTest{
{`c:..\abc`, `c:..\abc`},
{`\`, `\`},
{`/`, `\`},
- {`\\i\..\c$`, `\c$`},
- {`\\i\..\i\c$`, `\i\c$`},
- {`\\i\..\I\c$`, `\I\c$`},
+ {`\\i\..\c$`, `\\i\..\c$`},
+ {`\\i\..\i\c$`, `\\i\..\i\c$`},
+ {`\\i\..\I\c$`, `\\i\..\I\c$`},
{`\\host\share\foo\..\bar`, `\\host\share\bar`},
{`//host/share/foo/../baz`, `\\host\share\baz`},
+ {`\\host\share\foo\..\..\..\..\bar`, `\\host\share\bar`},
+ {`\\.\C:\a\..\..\..\..\bar`, `\\.\C:\bar`},
+ {`\\.\C:\\\\a`, `\\.\C:\a`},
{`\\a\b\..\c`, `\\a\b\c`},
{`\\a\b`, `\\a\b`},
{`.\c:`, `.\c:`},
{`.\c:\foo`, `.\c:\foo`},
{`.\c:foo`, `.\c:foo`},
+ {`//abc`, `\\abc`},
+ {`///abc`, `\\\abc`},
+ {`//abc//`, `\\abc\\`},
}
func TestClean(t *testing.T) {
@@ -105,6 +115,8 @@ func TestClean(t *testing.T) {
tests[i].result = filepath.FromSlash(tests[i].result)
}
tests = append(tests, wincleantests...)
+ } else {
+ tests = append(tests, nonwincleantests...)
}
for _, test := range tests {
if s := filepath.Clean(test.path); s != test.result {
@@ -257,8 +269,9 @@ var jointests = []JoinTest{
{[]string{"/", "a"}, "/a"},
{[]string{"/", "a/b"}, "/a/b"},
{[]string{"/", ""}, "/"},
- {[]string{"//", "a"}, "/a"},
{[]string{"/a", "b"}, "/a/b"},
+ {[]string{"a", "/b"}, "a/b"},
+ {[]string{"/a", "/b"}, "/a/b"},
{[]string{"a/", "b"}, "a/b"},
{[]string{"a/", ""}, "a"},
{[]string{"", ""}, ""},
@@ -267,6 +280,10 @@ var jointests = []JoinTest{
{[]string{"/", "a", "b"}, "/a/b"},
}
+var nonwinjointests = []JoinTest{
+ {[]string{"//", "a"}, "/a"},
+}
+
var winjointests = []JoinTest{
{[]string{`directory`, `file`}, `directory\file`},
{[]string{`C:\Windows\`, `System32`}, `C:\Windows\System32`},
@@ -279,6 +296,7 @@ var winjointests = []JoinTest{
{[]string{`C:`, ``, ``, `b`}, `C:b`},
{[]string{`C:`, ``}, `C:.`},
{[]string{`C:`, ``, ``}, `C:.`},
+ {[]string{`C:`, ``, `\a`}, `C:a`},
{[]string{`C:.`, `a`}, `C:a`},
{[]string{`C:a`, `b`}, `C:a\b`},
{[]string{`C:a`, `b`, `d`}, `C:a\b\d`},
@@ -288,17 +306,20 @@ var winjointests = []JoinTest{
{[]string{`\`}, `\`},
{[]string{`\`, ``}, `\`},
{[]string{`\`, `a`}, `\a`},
- {[]string{`\\`, `a`}, `\a`},
+ {[]string{`\\`, `a`}, `\\a`},
{[]string{`\`, `a`, `b`}, `\a\b`},
- {[]string{`\\`, `a`, `b`}, `\a\b`},
+ {[]string{`\\`, `a`, `b`}, `\\a\b`},
{[]string{`\`, `\\a\b`, `c`}, `\a\b\c`},
- {[]string{`\\a`, `b`, `c`}, `\a\b\c`},
- {[]string{`\\a\`, `b`, `c`}, `\a\b\c`},
+ {[]string{`\\a`, `b`, `c`}, `\\a\b\c`},
+ {[]string{`\\a\`, `b`, `c`}, `\\a\b\c`},
+ {[]string{`//`, `a`}, `\\a`},
}
func TestJoin(t *testing.T) {
if runtime.GOOS == "windows" {
jointests = append(jointests, winjointests...)
+ } else {
+ jointests = append(jointests, nonwinjointests...)
}
for _, test := range jointests {
expected := filepath.FromSlash(test.path)
@@ -786,7 +807,6 @@ var dirtests = []PathTest{
{".", "."},
{"/.", "/"},
{"/", "/"},
- {"////", "/"},
{"/foo", "/"},
{"x/", "x"},
{"abc", "."},
@@ -796,6 +816,10 @@ var dirtests = []PathTest{
{"a/b/c.x", "a/b"},
}
+var nonwindirtests = []PathTest{
+ {"////", "/"},
+}
+
var windirtests = []PathTest{
{`c:\`, `c:\`},
{`c:.`, `c:.`},
@@ -806,6 +830,7 @@ var windirtests = []PathTest{
{`\\host\share\`, `\\host\share\`},
{`\\host\share\a`, `\\host\share\`},
{`\\host\share\a\b`, `\\host\share\a`},
+ {`\\\\`, `\\\\`},
}
func TestDir(t *testing.T) {
@@ -817,6 +842,8 @@ func TestDir(t *testing.T) {
}
// add windows specific tests
tests = append(tests, windirtests...)
+ } else {
+ tests = append(tests, nonwindirtests...)
}
for _, test := range tests {
if s := filepath.Dir(test.path); s != test.result {
@@ -1332,24 +1359,30 @@ var volumenametests = []VolumeNameTest{
{`c:`, `c:`},
{`2:`, ``},
{``, ``},
- {`\\\host`, ``},
- {`\\\host\`, ``},
- {`\\\host\share`, ``},
- {`\\\host\\share`, ``},
- {`\\host`, ``},
- {`//host`, ``},
- {`\\host\`, ``},
- {`//host/`, ``},
+ {`\\\host`, `\\\host`},
+ {`\\\host\`, `\\\host`},
+ {`\\\host\share`, `\\\host`},
+ {`\\\host\\share`, `\\\host`},
+ {`\\host`, `\\host`},
+ {`//host`, `\\host`},
+ {`\\host\`, `\\host\`},
+ {`//host/`, `\\host\`},
{`\\host\share`, `\\host\share`},
- {`//host/share`, `//host/share`},
+ {`//host/share`, `\\host\share`},
{`\\host\share\`, `\\host\share`},
- {`//host/share/`, `//host/share`},
+ {`//host/share/`, `\\host\share`},
{`\\host\share\foo`, `\\host\share`},
- {`//host/share/foo`, `//host/share`},
+ {`//host/share/foo`, `\\host\share`},
{`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`},
- {`//host/share//foo///bar////baz`, `//host/share`},
+ {`//host/share//foo///bar////baz`, `\\host\share`},
{`\\host\share\foo\..\bar`, `\\host\share`},
- {`//host/share/foo/../bar`, `//host/share`},
+ {`//host/share/foo/../bar`, `\\host\share`},
+ {`//./NUL`, `\\.\NUL`},
+ {`//?/NUL`, `\\?\NUL`},
+ {`//./C:`, `\\.\C:`},
+ {`//./C:/a/b/c`, `\\.\C:`},
+ {`//./UNC/host/share/a/b/c`, `\\.\UNC\host\share`},
+ {`//./UNC/host`, `\\.\UNC\host`},
}
func TestVolumeName(t *testing.T) {