]> Cypherpunks repositories - gostls13.git/commitdiff
path/filepath: make Join("c:", "/a") return "c:/a" again
authorDamien Neil <dneil@google.com>
Wed, 30 Nov 2022 01:07:02 +0000 (20:07 -0500)
committerGopher Robot <gobot@golang.org>
Fri, 2 Dec 2022 19:48:47 +0000 (19:48 +0000)
Historically, on Windows filepath.Join("c:", elt) does not insert
a path separator between "c:" and elt, but preserves leading slashes
in elt. Restore this behavior, which was inadvertently changed by
CL 444280.

Fixes #56988

Change-Id: Id728bf311f4093264f8c067d8b801ea9ebef5b5f
Reviewed-on: https://go-review.googlesource.com/c/go/+/453497
Reviewed-by: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Bryan Mills <bcmills@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Run-TryBot: Damien Neil <dneil@google.com>

src/path/filepath/path_test.go
src/path/filepath/path_windows.go

index 41e70c2dbe5926ff627123d314ec54d79486e067..66474448526675cea863ddbadae5fd2fb693934d 100644 (file)
@@ -353,7 +353,8 @@ 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`}, `C:\a`},
        {[]string{`C:.`, `a`}, `C:a`},
        {[]string{`C:a`, `b`}, `C:a\b`},
        {[]string{`C:a`, `b`, `d`}, `C:a\b\d`},
index cbf57b22b439f313827f222f72972c2ddf59e9ec..4dca9e0f55ff404bc2bf6ab3f9caa2227f218299 100644 (file)
@@ -222,31 +222,37 @@ func abs(path string) (string, error) {
 
 func join(elem []string) string {
        var b strings.Builder
-       appendSep := false
+       var lastChar byte
        for _, e := range elem {
-               // Strip leading slashes from everything after the first element,
-               // to avoid creating a UNC path (any path starting with "\\") from
-               // non-UNC elements.
-               //
-               // The correct behavior for Join when the first element is an incomplete UNC
-               // path (for example, "\\") is underspecified. We currently join subsequent
-               // elements so Join("\\", "host", "share") produces "\\host\share".
-               for b.Len() > 0 && len(e) > 0 && isSlash(e[0]) {
-                       e = e[1:]
-               }
-               if e == "" {
-                       continue
-               }
-               if appendSep {
+               switch {
+               case b.Len() == 0:
+                       // Add the first non-empty path element unchanged.
+               case isSlash(lastChar):
+                       // If the path ends in a slash, strip any leading slashes from the next
+                       // path element to avoid creating a UNC path (any path starting with "\\")
+                       // from non-UNC elements.
+                       //
+                       // The correct behavior for Join when the first element is an incomplete UNC
+                       // path (for example, "\\") is underspecified. We currently join subsequent
+                       // elements so Join("\\", "host", "share") produces "\\host\share".
+                       for len(e) > 0 && isSlash(e[0]) {
+                               e = e[1:]
+                       }
+               case lastChar == ':':
+                       // If the path ends in a colon, keep the path relative to the current directory
+                       // on a drive and don't add a separator. Preserve leading slashes in the next
+                       // path element, which may make the path absolute.
+                       //
+                       //      Join(`C:`, `f`) = `C:f`
+                       //      Join(`C:`, `\f`) = `C:\f`
+               default:
+                       // In all other cases, add a separator between elements.
                        b.WriteByte('\\')
+                       lastChar = '\\'
                }
-               b.WriteString(e)
-               appendSep = !isSlash(e[len(e)-1])
-               if b.Len() == 2 && volumeNameLen(b.String()) == 2 {
-                       // If the string is two characters long and consists of nothing but
-                       // a volume name, this is either a drive ("C:") or the start of an
-                       // incomplete UNC path ("\\"). In either case, don't append a separator.
-                       appendSep = false
+               if len(e) > 0 {
+                       b.WriteString(e)
+                       lastChar = e[len(e)-1]
                }
        }
        if b.Len() == 0 {