Skip to content

Commit 45b98bf

Browse files
neildcagedmantis
authored andcommitted
[release-branch.go1.21] 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". For #61866. Fixes #61868. Change-Id: I97b0238953c183b2ce19ca89c14f26700008ea72 Reviewed-on: https://go-review.googlesource.com/c/go/+/517216 Run-TryBot: Damien Neil <[email protected]> Reviewed-by: Bryan Mills <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Quim Muntal <[email protected]> (cherry picked from commit 6e43407) Reviewed-on: https://go-review.googlesource.com/c/go/+/519655 Reviewed-by: Damien Neil <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Run-TryBot: Dmitri Shuralyov <[email protected]>
1 parent bac083a commit 45b98bf

File tree

2 files changed

+24
-12
lines changed

2 files changed

+24
-12
lines changed

src/path/filepath/path.go

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ func (b *lazybuf) append(c byte) {
5252
b.w++
5353
}
5454

55+
func (b *lazybuf) prepend(prefix ...byte) {
56+
b.buf = append(prefix, b.buf...)
57+
b.w += len(prefix)
58+
}
59+
5560
func (b *lazybuf) string() string {
5661
if b.buf == nil {
5762
return b.volAndPath[:b.volLen+b.w]
@@ -150,18 +155,6 @@ func Clean(path string) string {
150155
if rooted && out.w != 1 || !rooted && out.w != 0 {
151156
out.append(Separator)
152157
}
153-
// If a ':' appears in the path element at the start of a Windows path,
154-
// insert a .\ at the beginning to avoid converting relative paths
155-
// like a/../c: into c:.
156-
if runtime.GOOS == "windows" && out.w == 0 && out.volLen == 0 && r != 0 {
157-
for i := r; i < n && !os.IsPathSeparator(path[i]); i++ {
158-
if path[i] == ':' {
159-
out.append('.')
160-
out.append(Separator)
161-
break
162-
}
163-
}
164-
}
165158
// copy element
166159
for ; r < n && !os.IsPathSeparator(path[r]); r++ {
167160
out.append(path[r])
@@ -174,6 +167,21 @@ func Clean(path string) string {
174167
out.append('.')
175168
}
176169

170+
if runtime.GOOS == "windows" && out.volLen == 0 && out.buf != nil {
171+
// If a ':' appears in the path element at the start of a Windows path,
172+
// insert a .\ at the beginning to avoid converting relative paths
173+
// like a/../c: into c:.
174+
for _, c := range out.buf {
175+
if os.IsPathSeparator(c) {
176+
break
177+
}
178+
if c == ':' {
179+
out.prepend('.', Separator)
180+
break
181+
}
182+
}
183+
}
184+
177185
return FromSlash(out.string())
178186
}
179187

src/path/filepath/path_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ var cleantests = []PathTest{
6767
{"/abc/def/../../..", "/"},
6868
{"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
6969
{"/../abc", "/abc"},
70+
{"a/../b:/../../c", `../c`},
7071

7172
// Combinations
7273
{"abc/./../def", "def"},
@@ -89,6 +90,7 @@ var wincleantests = []PathTest{
8990
{`c:\abc\def\..\..`, `c:\`},
9091
{`c:\..\abc`, `c:\abc`},
9192
{`c:..\abc`, `c:..\abc`},
93+
{`c:\b:\..\..\..\d`, `c:\d`},
9294
{`\`, `\`},
9395
{`/`, `\`},
9496
{`\\i\..\c$`, `\\i\..\c$`},
@@ -169,6 +171,7 @@ var islocaltests = []IsLocalTest{
169171
{"a/", true},
170172
{"a/.", true},
171173
{"a/./b/./c", true},
174+
{`a/../b:/../../c`, false},
172175
}
173176

174177
var winislocaltests = []IsLocalTest{
@@ -380,6 +383,7 @@ var winjointests = []JoinTest{
380383
{[]string{`\\a`, `b`, `c`}, `\\a\b\c`},
381384
{[]string{`\\a\`, `b`, `c`}, `\\a\b\c`},
382385
{[]string{`//`, `a`}, `\\a`},
386+
{[]string{`a:\b\c`, `x\..\y:\..\..\z`}, `a:\b\z`},
383387
}
384388

385389
func TestJoin(t *testing.T) {

0 commit comments

Comments
 (0)