From: Damien Neil Date: Wed, 30 Nov 2022 01:07:02 +0000 (-0500) Subject: path/filepath: make Join("c:", "/a") return "c:/a" again X-Git-Tag: go1.20rc1~33 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=79559c1e7e426415ea8c7920c36b2fb4ebd7dbf0;p=gostls13.git path/filepath: make Join("c:", "/a") return "c:/a" again 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 TryBot-Result: Gopher Robot Auto-Submit: Bryan Mills Reviewed-by: Roland Shoemaker Run-TryBot: Damien Neil --- diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go index 41e70c2dbe..6647444852 100644 --- a/src/path/filepath/path_test.go +++ b/src/path/filepath/path_test.go @@ -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`}, diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go index cbf57b22b4..4dca9e0f55 100644 --- a/src/path/filepath/path_windows.go +++ b/src/path/filepath/path_windows.go @@ -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 {