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)