]> Cypherpunks.ru repositories - gostls13.git/commitdiff
path/filepath: consider \\?\c: as a volume on Windows
authorDamien Neil <dneil@google.com>
Thu, 9 Nov 2023 17:53:44 +0000 (09:53 -0800)
committerDamien Neil <dneil@google.com>
Thu, 9 Nov 2023 22:45:11 +0000 (22:45 +0000)
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.

Fixes #64028

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>
src/path/filepath/path_test.go
src/path/filepath/path_windows.go

index cd9f5632c9c9704973db6681592328566a67dd63..ed3990859bfb920eecb2db255f54e578597d021f 100644 (file)
@@ -109,6 +109,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:`},
@@ -1597,10 +1599,13 @@ var volumenametests = []VolumeNameTest{
        {`//.`, `\\.`},
        {`//./`, `\\.\`},
        {`//./NUL`, `\\.\NUL`},
-       {`//?/`, `\\?`},
+       {`//?`, `\\?`},
+       {`//?/`, `\\?\`},
+       {`//?/NUL`, `\\?\NUL`},
+       {`/??`, `\??`},
+       {`/??/`, `\??\`},
+       {`/??/NUL`, `\??\NUL`},
        {`//./a/b`, `\\.\a`},
-       {`//?/`, `\\?`},
-       {`//?/`, `\\?`},
        {`//./C:`, `\\.\C:`},
        {`//./C:/`, `\\.\C:`},
        {`//./C:/a/b/c`, `\\.\C:`},
@@ -1609,8 +1614,8 @@ var volumenametests = []VolumeNameTest{
        {`//./UNC/host\`, `\\.\UNC\host\`},
        {`//./UNC`, `\\.\UNC`},
        {`//./UNC/`, `\\.\UNC\`},
-       {`\\?\x`, `\\?`},
-       {`\??\x`, `\??`},
+       {`\\?\x`, `\\?\x`},
+       {`\??\x`, `\??\x`},
 }
 
 func TestVolumeName(t *testing.T) {
index c490424f20c968b33486eb32f826f2548a9ce032..eacab0e5ced678adb364c974bf192ffb29e3e0e7 100644 (file)
@@ -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)