// one parameter
{[]string{""}, ""},
+ {[]string{"/"}, "/"},
{[]string{"a"}, "a"},
// two parameters
{[]string{"a", ""}, "a"},
{[]string{"", "b"}, "b"},
{[]string{"/", "a"}, "/a"},
+ {[]string{"/", "a/b"}, "/a/b"},
{[]string{"/", ""}, "/"},
+ {[]string{"//", "a"}, "/a"},
+ {[]string{"/a", "b"}, "/a/b"},
{[]string{"a/", "b"}, "a/b"},
{[]string{"a/", ""}, "a"},
{[]string{"", ""}, ""},
+
+ // three parameters
+ {[]string{"/", "a", "b"}, "/a/b"},
}
var winjointests = []JoinTest{
{[]string{`C:\`, `Windows`}, `C:\Windows`},
{[]string{`C:`, `Windows`}, `C:\Windows`},
{[]string{`\\host\share`, `foo`}, `\\host\share\foo`},
+ {[]string{`\\host\share\foo`}, `\\host\share\foo`},
{[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`},
-}
-
-// join takes a []string and passes it to Join.
-func join(elem []string, args ...string) string {
- args = elem
- return filepath.Join(args...)
+ {[]string{`\`}, `\`},
+ {[]string{`\`, ``}, `\`},
+ {[]string{`\`, `a`}, `\a`},
+ {[]string{`\\`, `a`}, `\a`},
+ {[]string{`\`, `a`, `b`}, `\a\b`},
+ {[]string{`\\`, `a`, `b`}, `\a\b`},
+ {[]string{`\`, `\\a\b`, `c`}, `\a\b\c`},
+ {[]string{`\\a`, `b`, `c`}, `\a\b\c`},
+ {[]string{`\\a\`, `b`, `c`}, `\a\b\c`},
}
func TestJoin(t *testing.T) {
jointests = append(jointests, winjointests...)
}
for _, test := range jointests {
- if p := join(test.elem); p != filepath.FromSlash(test.path) {
- t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
+ expected := filepath.FromSlash(test.path)
+ if p := filepath.Join(test.elem...); p != expected {
+ t.Errorf("join(%q) = %q, want %q", test.elem, p, expected)
}
}
}
func abs(path string) (string, error) {
return syscall.FullPath(path)
}
+
+func join(elem []string) string {
+ for i, e := range elem {
+ if e != "" {
+ return joinNonEmpty(elem[i:])
+ }
+ }
+ return ""
+}
+
+// joinNonEmpty is like join, but it assumes that the first element is non-empty.
+func joinNonEmpty(elem []string) string {
+ // The following logic prevents Join from inadvertently creating a
+ // UNC path on Windows. Unless the first element is a UNC path, Join
+ // shouldn't create a UNC path. See golang.org/issue/9167.
+ p := Clean(strings.Join(elem, string(Separator)))
+ if !isUNC(p) {
+ return p
+ }
+ // p == UNC only allowed when the first element is a UNC path.
+ head := Clean(elem[0])
+ if isUNC(head) {
+ return p
+ }
+ // head + tail == UNC, but joining two non-UNC paths should not result
+ // in a UNC path. Undo creation of UNC path.
+ tail := Clean(strings.Join(elem[1:], string(Separator)))
+ if head[len(head)-1] == Separator {
+ return head + tail
+ }
+ return head + string(Separator) + tail
+}
+
+// isUNC returns true if path is a UNC path.
+func isUNC(path string) bool {
+ return volumeNameLen(path) > 2
+}