aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2023-11-09 09:53:44 -0800
committerGopher Robot <gobot@golang.org>2023-11-28 16:59:25 +0000
commit1b59b017db1ac4a63ed08173c00d7f08d47530be (patch)
tree148ab9fde759f4c2b53bcb7649b398baf2c6e02c
parent46bc33819ac86a9596b8059235842f0e0c7469bd (diff)
downloadgo-1b59b017db1ac4a63ed08173c00d7f08d47530be.tar.gz
go-1b59b017db1ac4a63ed08173c00d7f08d47530be.zip
[release-branch.go1.20] path/filepath: consider \\?\c: as a volume on Windows
While fixing several bugs in path handling on Windows, beginning with \\?\. Prior to #540277, VolumeName considered the first path component after the \\?\ prefix to be part of the volume name. After, it considered only the \\? prefix to be the volume name. Restore the previous behavior. For #64028. Fixes #64040. Change-Id: I6523789e61776342800bd607fb3f29d496257e68 Reviewed-on: https://go-review.googlesource.com/c/go/+/541175 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Roland Shoemaker <roland@golang.org> (cherry picked from commit eda42f7c60adab26ed1a340414c726c4bf46b1f7) Reviewed-on: https://go-review.googlesource.com/c/go/+/541520 Auto-Submit: Dmitri Shuralyov <dmitshur@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org> Reviewed-by: Damien Neil <dneil@google.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
-rw-r--r--src/path/filepath/path_test.go15
-rw-r--r--src/path/filepath/path_windows.go20
2 files changed, 17 insertions, 18 deletions
diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go
index 0a2286648f..3077ffb6c7 100644
--- a/src/path/filepath/path_test.go
+++ b/src/path/filepath/path_test.go
@@ -108,6 +108,8 @@ var wincleantests = []PathTest{
{`//abc`, `\\abc`},
{`///abc`, `\\\abc`},
{`//abc//`, `\\abc\\`},
+ {`\\?\C:\`, `\\?\C:\`},
+ {`\\?\C:\a`, `\\?\C:\a`},
// Don't allow cleaning to move an element with a colon to the start of the path.
{`a/../c:`, `.\c:`},
@@ -1472,10 +1474,13 @@ var volumenametests = []VolumeNameTest{
{`//.`, `\\.`},
{`//./`, `\\.\`},
{`//./NUL`, `\\.\NUL`},
- {`//?/`, `\\?`},
+ {`//?`, `\\?`},
+ {`//?/`, `\\?\`},
+ {`//?/NUL`, `\\?\NUL`},
+ {`/??`, `\??`},
+ {`/??/`, `\??\`},
+ {`/??/NUL`, `\??\NUL`},
{`//./a/b`, `\\.\a`},
- {`//?/`, `\\?`},
- {`//?/`, `\\?`},
{`//./C:`, `\\.\C:`},
{`//./C:/`, `\\.\C:`},
{`//./C:/a/b/c`, `\\.\C:`},
@@ -1484,8 +1489,8 @@ var volumenametests = []VolumeNameTest{
{`//./UNC/host\`, `\\.\UNC\host\`},
{`//./UNC`, `\\.\UNC`},
{`//./UNC/`, `\\.\UNC\`},
- {`\\?\x`, `\\?`},
- {`\??\x`, `\??`},
+ {`\\?\x`, `\\?\x`},
+ {`\??\x`, `\??\x`},
}
func TestVolumeName(t *testing.T) {
diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go
index c490424f20..eacab0e5ce 100644
--- a/src/path/filepath/path_windows.go
+++ b/src/path/filepath/path_windows.go
@@ -102,12 +102,14 @@ func volumeNameLen(path string) int {
// \\.\unc\a\b\..\c into \\.\unc\a\c.
return uncLen(path, len(`\\.\UNC\`))
- case pathHasPrefixFold(path, `\\.`):
- // Path starts with \\., and is a Local Device path.
+ case pathHasPrefixFold(path, `\\.`) ||
+ pathHasPrefixFold(path, `\\?`) || pathHasPrefixFold(path, `\??`):
+ // Path starts with \\.\, and is a Local Device path; or
+ // path starts with \\?\ or \??\ and is a Root Local Device path.
//
- // We currently treat the next component after the \\.\ prefix
- // as part of the volume name, although there doesn't seem to be
- // a principled reason to do this.
+ // We treat the next component after the \\.\ prefix as
+ // part of the volume name, which means Clean(`\\?\c:\`)
+ // won't remove the trailing \. (See #64028.)
if len(path) == 3 {
return 3 // exactly \\.
}
@@ -117,14 +119,6 @@ func volumeNameLen(path string) int {
}
return len(path) - len(rest) - 1
- case pathHasPrefixFold(path, `\\?`) || pathHasPrefixFold(path, `\??`):
- // Path starts with \\?\ or \??\, and is a Root Local Device path.
- //
- // While Windows usually treats / and \ as equivalent,
- // /??/ does not seem to be recognized as a Root Local Device path.
- // We treat it as one anyway here to be safe.
- return 3
-
case len(path) >= 2 && isSlash(path[1]):
// Path starts with \\, and is a UNC path.
return uncLen(path, 2)