mirror of
https://github.com/golang/go
synced 2024-09-30 00:04:28 -06:00
path/filepath: don't drop .. elements when cleaning invalid Windows paths
Fix a bug where Clean could improperly drop .. elements from a path on Windows, when the path contains elements containing a ':'. For example, Clean("a/../b:/../../c") now correctly returns "..\c" rather than "c". Fixes #61866 Change-Id: I97b0238953c183b2ce19ca89c14f26700008ea72 Reviewed-on: https://go-review.googlesource.com/c/go/+/517216 Run-TryBot: Damien Neil <dneil@google.com> Reviewed-by: Bryan Mills <bcmills@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Quim Muntal <quimmuntal@gmail.com>
This commit is contained in:
parent
fe1daf2e43
commit
6e43407931
@ -16,6 +16,7 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"runtime"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
@ -52,6 +53,11 @@ func (b *lazybuf) append(c byte) {
|
||||
b.w++
|
||||
}
|
||||
|
||||
func (b *lazybuf) prepend(prefix ...byte) {
|
||||
b.buf = slices.Insert(b.buf, 0, prefix...)
|
||||
b.w += len(prefix)
|
||||
}
|
||||
|
||||
func (b *lazybuf) string() string {
|
||||
if b.buf == nil {
|
||||
return b.volAndPath[:b.volLen+b.w]
|
||||
@ -150,18 +156,6 @@ func Clean(path string) string {
|
||||
if rooted && out.w != 1 || !rooted && out.w != 0 {
|
||||
out.append(Separator)
|
||||
}
|
||||
// If a ':' appears in the path element at the start of a Windows path,
|
||||
// insert a .\ at the beginning to avoid converting relative paths
|
||||
// like a/../c: into c:.
|
||||
if runtime.GOOS == "windows" && out.w == 0 && out.volLen == 0 && r != 0 {
|
||||
for i := r; i < n && !os.IsPathSeparator(path[i]); i++ {
|
||||
if path[i] == ':' {
|
||||
out.append('.')
|
||||
out.append(Separator)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// copy element
|
||||
for ; r < n && !os.IsPathSeparator(path[r]); r++ {
|
||||
out.append(path[r])
|
||||
@ -174,6 +168,21 @@ func Clean(path string) string {
|
||||
out.append('.')
|
||||
}
|
||||
|
||||
if runtime.GOOS == "windows" && out.volLen == 0 && out.buf != nil {
|
||||
// If a ':' appears in the path element at the start of a Windows path,
|
||||
// insert a .\ at the beginning to avoid converting relative paths
|
||||
// like a/../c: into c:.
|
||||
for _, c := range out.buf {
|
||||
if os.IsPathSeparator(c) {
|
||||
break
|
||||
}
|
||||
if c == ':' {
|
||||
out.prepend('.', Separator)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FromSlash(out.string())
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,7 @@ var cleantests = []PathTest{
|
||||
{"/abc/def/../../..", "/"},
|
||||
{"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
|
||||
{"/../abc", "/abc"},
|
||||
{"a/../b:/../../c", `../c`},
|
||||
|
||||
// Combinations
|
||||
{"abc/./../def", "def"},
|
||||
@ -89,6 +90,7 @@ var wincleantests = []PathTest{
|
||||
{`c:\abc\def\..\..`, `c:\`},
|
||||
{`c:\..\abc`, `c:\abc`},
|
||||
{`c:..\abc`, `c:..\abc`},
|
||||
{`c:\b:\..\..\..\d`, `c:\d`},
|
||||
{`\`, `\`},
|
||||
{`/`, `\`},
|
||||
{`\\i\..\c$`, `\\i\..\c$`},
|
||||
@ -169,6 +171,7 @@ var islocaltests = []IsLocalTest{
|
||||
{"a/", true},
|
||||
{"a/.", true},
|
||||
{"a/./b/./c", true},
|
||||
{`a/../b:/../../c`, false},
|
||||
}
|
||||
|
||||
var winislocaltests = []IsLocalTest{
|
||||
@ -380,6 +383,7 @@ var winjointests = []JoinTest{
|
||||
{[]string{`\\a`, `b`, `c`}, `\\a\b\c`},
|
||||
{[]string{`\\a\`, `b`, `c`}, `\\a\b\c`},
|
||||
{[]string{`//`, `a`}, `\\a`},
|
||||
{[]string{`a:\b\c`, `x\..\y:\..\..\z`}, `a:\b\z`},
|
||||
}
|
||||
|
||||
func TestJoin(t *testing.T) {
|
||||
|
Loading…
Reference in New Issue
Block a user