diff options
author | Damien Neil <dneil@google.com> | 2022-11-29 20:07:02 -0500 |
---|---|---|
committer | Gopher Robot <gobot@golang.org> | 2022-12-02 19:48:47 +0000 |
commit | 79559c1e7e426415ea8c7920c36b2fb4ebd7dbf0 (patch) | |
tree | 967b1af9416a59a8f79ede5ca5bfd026295505c3 | |
parent | a79b55bb9a5f459fd8d518223022a6d307354a27 (diff) | |
download | go-79559c1e7e426415ea8c7920c36b2fb4ebd7dbf0.tar.gz go-79559c1e7e426415ea8c7920c36b2fb4ebd7dbf0.zip |
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 <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>
-rw-r--r-- | src/path/filepath/path_test.go | 3 | ||||
-rw-r--r-- | src/path/filepath/path_windows.go | 50 |
2 files changed, 30 insertions, 23 deletions
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 { |