mirror of
https://github.com/golang/go.git
synced 2025-05-16 04:44:39 +00:00
path/filepath: make Join handle UNC paths on Windows
Unless the first element is a Universal Naming Convention (UNC)[0] path, Join shouldn't create a UNC path on Windows. For example, Join inadvertently creates a UNC path on Windows when told to join at least three non-empty path elements, where the first element is `\` or `/`. This CL prevents creation of a UNC path prefix when the first path element isn't a UNC path. Since this introduces some amount of Windows-specific logic, Join is moved to a per GOOS implementation. Fixes #9167. [0]: http://msdn.microsoft.com/en-us/library/gg465305.aspx Change-Id: Ib6eda597106cb025137673b33c4828df1367f75b Reviewed-on: https://go-review.googlesource.com/2211 Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
This commit is contained in:
parent
4e0618c992
commit
8128b0116d
@ -196,13 +196,10 @@ func Split(path string) (dir, file string) {
|
|||||||
// Join joins any number of path elements into a single path, adding
|
// Join joins any number of path elements into a single path, adding
|
||||||
// a Separator if necessary. The result is Cleaned, in particular
|
// a Separator if necessary. The result is Cleaned, in particular
|
||||||
// all empty strings are ignored.
|
// all empty strings are ignored.
|
||||||
|
// On Windows, the result is a UNC path if and only if the first path
|
||||||
|
// element is a UNC path.
|
||||||
func Join(elem ...string) string {
|
func Join(elem ...string) string {
|
||||||
for i, e := range elem {
|
return join(elem)
|
||||||
if e != "" {
|
|
||||||
return Clean(strings.Join(elem[i:], string(Separator)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ext returns the file name extension used by path.
|
// Ext returns the file name extension used by path.
|
||||||
|
@ -32,3 +32,13 @@ func splitList(path string) []string {
|
|||||||
func abs(path string) (string, error) {
|
func abs(path string) (string, error) {
|
||||||
return unixAbs(path)
|
return unixAbs(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func join(elem []string) string {
|
||||||
|
// If there's a bug here, fix the logic in ./path_unix.go too.
|
||||||
|
for i, e := range elem {
|
||||||
|
if e != "" {
|
||||||
|
return Clean(strings.Join(elem[i:], string(Separator)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
@ -242,6 +242,7 @@ var jointests = []JoinTest{
|
|||||||
|
|
||||||
// one parameter
|
// one parameter
|
||||||
{[]string{""}, ""},
|
{[]string{""}, ""},
|
||||||
|
{[]string{"/"}, "/"},
|
||||||
{[]string{"a"}, "a"},
|
{[]string{"a"}, "a"},
|
||||||
|
|
||||||
// two parameters
|
// two parameters
|
||||||
@ -249,10 +250,16 @@ var jointests = []JoinTest{
|
|||||||
{[]string{"a", ""}, "a"},
|
{[]string{"a", ""}, "a"},
|
||||||
{[]string{"", "b"}, "b"},
|
{[]string{"", "b"}, "b"},
|
||||||
{[]string{"/", "a"}, "/a"},
|
{[]string{"/", "a"}, "/a"},
|
||||||
|
{[]string{"/", "a/b"}, "/a/b"},
|
||||||
{[]string{"/", ""}, "/"},
|
{[]string{"/", ""}, "/"},
|
||||||
|
{[]string{"//", "a"}, "/a"},
|
||||||
|
{[]string{"/a", "b"}, "/a/b"},
|
||||||
{[]string{"a/", "b"}, "a/b"},
|
{[]string{"a/", "b"}, "a/b"},
|
||||||
{[]string{"a/", ""}, "a"},
|
{[]string{"a/", ""}, "a"},
|
||||||
{[]string{"", ""}, ""},
|
{[]string{"", ""}, ""},
|
||||||
|
|
||||||
|
// three parameters
|
||||||
|
{[]string{"/", "a", "b"}, "/a/b"},
|
||||||
}
|
}
|
||||||
|
|
||||||
var winjointests = []JoinTest{
|
var winjointests = []JoinTest{
|
||||||
@ -262,13 +269,17 @@ var winjointests = []JoinTest{
|
|||||||
{[]string{`C:\`, `Windows`}, `C:\Windows`},
|
{[]string{`C:\`, `Windows`}, `C:\Windows`},
|
||||||
{[]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`}, `\\host\share\foo`},
|
||||||
{[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`},
|
{[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`},
|
||||||
}
|
{[]string{`\`}, `\`},
|
||||||
|
{[]string{`\`, ``}, `\`},
|
||||||
// join takes a []string and passes it to Join.
|
{[]string{`\`, `a`}, `\a`},
|
||||||
func join(elem []string, args ...string) string {
|
{[]string{`\\`, `a`}, `\a`},
|
||||||
args = elem
|
{[]string{`\`, `a`, `b`}, `\a\b`},
|
||||||
return filepath.Join(args...)
|
{[]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) {
|
func TestJoin(t *testing.T) {
|
||||||
@ -276,8 +287,9 @@ func TestJoin(t *testing.T) {
|
|||||||
jointests = append(jointests, winjointests...)
|
jointests = append(jointests, winjointests...)
|
||||||
}
|
}
|
||||||
for _, test := range jointests {
|
for _, test := range jointests {
|
||||||
if p := join(test.elem); p != filepath.FromSlash(test.path) {
|
expected := filepath.FromSlash(test.path)
|
||||||
t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
|
if p := filepath.Join(test.elem...); p != expected {
|
||||||
|
t.Errorf("join(%q) = %q, want %q", test.elem, p, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,3 +34,13 @@ func splitList(path string) []string {
|
|||||||
func abs(path string) (string, error) {
|
func abs(path string) (string, error) {
|
||||||
return unixAbs(path)
|
return unixAbs(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func join(elem []string) string {
|
||||||
|
// If there's a bug here, fix the logic in ./path_plan9.go too.
|
||||||
|
for i, e := range elem {
|
||||||
|
if e != "" {
|
||||||
|
return Clean(strings.Join(elem[i:], string(Separator)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
@ -108,3 +108,40 @@ func splitList(path string) []string {
|
|||||||
func abs(path string) (string, error) {
|
func abs(path string) (string, error) {
|
||||||
return syscall.FullPath(path)
|
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
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user