aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2022-11-29 20:07:02 -0500
committerGopher Robot <gobot@golang.org>2022-12-02 19:48:47 +0000
commit79559c1e7e426415ea8c7920c36b2fb4ebd7dbf0 (patch)
tree967b1af9416a59a8f79ede5ca5bfd026295505c3
parenta79b55bb9a5f459fd8d518223022a6d307354a27 (diff)
downloadgo-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.go3
-rw-r--r--src/path/filepath/path_windows.go50
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 {