summaryrefslogtreecommitdiff
path: root/src/path/filepath
diff options
context:
space:
mode:
Diffstat (limited to 'src/path/filepath')
-rw-r--r--src/path/filepath/example_unix_walk_test.go3
-rw-r--r--src/path/filepath/match.go61
-rw-r--r--src/path/filepath/match_test.go12
-rw-r--r--src/path/filepath/path.go7
-rw-r--r--src/path/filepath/path_test.go19
-rw-r--r--src/path/filepath/path_windows_test.go6
-rw-r--r--src/path/filepath/symlink.go3
-rw-r--r--src/path/filepath/symlink_windows.go2
8 files changed, 69 insertions, 44 deletions
diff --git a/src/path/filepath/example_unix_walk_test.go b/src/path/filepath/example_unix_walk_test.go
index fa8b8e393b..66dc7f6b53 100644
--- a/src/path/filepath/example_unix_walk_test.go
+++ b/src/path/filepath/example_unix_walk_test.go
@@ -8,6 +8,7 @@ package filepath_test
import (
"fmt"
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -40,7 +41,7 @@ func ExampleWalk() {
subDirToSkip := "skip"
fmt.Println("On Unix:")
- err = filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
+ err = filepath.Walk(".", func(path string, info fs.FileInfo, err error) error {
if err != nil {
fmt.Printf("prevent panic by handling failure accessing a path %q: %v\n", path, err)
return err
diff --git a/src/path/filepath/match.go b/src/path/filepath/match.go
index 20a334805b..c77a26952a 100644
--- a/src/path/filepath/match.go
+++ b/src/path/filepath/match.go
@@ -122,25 +122,28 @@ Scan:
// If so, it returns the remainder of s (after the match).
// Chunk is all single-character operators: literals, char classes, and ?.
func matchChunk(chunk, s string) (rest string, ok bool, err error) {
+ // failed records whether the match has failed.
+ // After the match fails, the loop continues on processing chunk,
+ // checking that the pattern is well-formed but no longer reading s.
+ failed := false
for len(chunk) > 0 {
- if len(s) == 0 {
- return
+ if !failed && len(s) == 0 {
+ failed = true
}
switch chunk[0] {
case '[':
// character class
- r, n := utf8.DecodeRuneInString(s)
- s = s[n:]
- chunk = chunk[1:]
- // We can't end right after '[', we're expecting at least
- // a closing bracket and possibly a caret.
- if len(chunk) == 0 {
- err = ErrBadPattern
- return
+ var r rune
+ if !failed {
+ var n int
+ r, n = utf8.DecodeRuneInString(s)
+ s = s[n:]
}
+ chunk = chunk[1:]
// possibly negated
- negated := chunk[0] == '^'
- if negated {
+ negated := false
+ if len(chunk) > 0 && chunk[0] == '^' {
+ negated = true
chunk = chunk[1:]
}
// parse all ranges
@@ -153,12 +156,12 @@ func matchChunk(chunk, s string) (rest string, ok bool, err error) {
}
var lo, hi rune
if lo, chunk, err = getEsc(chunk); err != nil {
- return
+ return "", false, err
}
hi = lo
if chunk[0] == '-' {
if hi, chunk, err = getEsc(chunk[1:]); err != nil {
- return
+ return "", false, err
}
}
if lo <= r && r <= hi {
@@ -167,35 +170,41 @@ func matchChunk(chunk, s string) (rest string, ok bool, err error) {
nrange++
}
if match == negated {
- return
+ failed = true
}
case '?':
- if s[0] == Separator {
- return
+ if !failed {
+ if s[0] == Separator {
+ failed = true
+ }
+ _, n := utf8.DecodeRuneInString(s)
+ s = s[n:]
}
- _, n := utf8.DecodeRuneInString(s)
- s = s[n:]
chunk = chunk[1:]
case '\\':
if runtime.GOOS != "windows" {
chunk = chunk[1:]
if len(chunk) == 0 {
- err = ErrBadPattern
- return
+ return "", false, ErrBadPattern
}
}
fallthrough
default:
- if chunk[0] != s[0] {
- return
+ if !failed {
+ if chunk[0] != s[0] {
+ failed = true
+ }
+ s = s[1:]
}
- s = s[1:]
chunk = chunk[1:]
}
}
+ if failed {
+ return "", false, nil
+ }
return s, true, nil
}
@@ -232,6 +241,10 @@ func getEsc(chunk string) (r rune, nchunk string, err error) {
// The only possible returned error is ErrBadPattern, when pattern
// is malformed.
func Glob(pattern string) (matches []string, err error) {
+ // Check pattern is well-formed.
+ if _, err := Match(pattern, ""); err != nil {
+ return nil, err
+ }
if !hasMeta(pattern) {
if _, err = os.Lstat(pattern); err != nil {
return nil, nil
diff --git a/src/path/filepath/match_test.go b/src/path/filepath/match_test.go
index b8657626bc..1c3b567fa3 100644
--- a/src/path/filepath/match_test.go
+++ b/src/path/filepath/match_test.go
@@ -75,8 +75,10 @@ var matchTests = []MatchTest{
{"[", "a", false, ErrBadPattern},
{"[^", "a", false, ErrBadPattern},
{"[^bc", "a", false, ErrBadPattern},
- {"a[", "a", false, nil},
+ {"a[", "a", false, ErrBadPattern},
{"a[", "ab", false, ErrBadPattern},
+ {"a[", "x", false, ErrBadPattern},
+ {"a/b[", "x", false, ErrBadPattern},
{"*x", "xxx", true, nil},
}
@@ -155,9 +157,11 @@ func TestGlob(t *testing.T) {
}
func TestGlobError(t *testing.T) {
- _, err := Glob("[]")
- if err == nil {
- t.Error("expected error for bad pattern; got none")
+ bad := []string{`[]`, `nonexist/[]`}
+ for _, pattern := range bad {
+ if _, err := Glob(pattern); err != ErrBadPattern {
+ t.Errorf("Glob(%#q) returned err=%v, want ErrBadPattern", pattern, err)
+ }
}
}
diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go
index 26f1833189..dffd27db14 100644
--- a/src/path/filepath/path.go
+++ b/src/path/filepath/path.go
@@ -13,6 +13,7 @@ package filepath
import (
"errors"
+ "io/fs"
"os"
"sort"
"strings"
@@ -339,7 +340,7 @@ var SkipDir = errors.New("skip this directory")
// visited by Walk. The path argument contains the argument to Walk as a
// prefix; that is, if Walk is called with "dir", which is a directory
// containing the file "a", the walk function will be called with argument
-// "dir/a". The info argument is the os.FileInfo for the named path.
+// "dir/a". The info argument is the fs.FileInfo for the named path.
//
// If there was a problem walking to the file or directory named by path, the
// incoming error will describe the problem and the function can decide how
@@ -350,12 +351,12 @@ var SkipDir = errors.New("skip this directory")
// Walk skips the directory's contents entirely. If the function returns SkipDir
// when invoked on a non-directory file, Walk skips the remaining files in the
// containing directory.
-type WalkFunc func(path string, info os.FileInfo, err error) error
+type WalkFunc func(path string, info fs.FileInfo, err error) error
var lstat = os.Lstat // for testing
// walk recursively descends path, calling walkFn.
-func walk(path string, info os.FileInfo, walkFn WalkFunc) error {
+func walk(path string, info fs.FileInfo, walkFn WalkFunc) error {
if !info.IsDir() {
return walkFn(path, info, nil)
}
diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go
index ca100ff071..7dc8b60c28 100644
--- a/src/path/filepath/path_test.go
+++ b/src/path/filepath/path_test.go
@@ -8,6 +8,7 @@ import (
"errors"
"fmt"
"internal/testenv"
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -393,7 +394,7 @@ func checkMarks(t *testing.T, report bool) {
// Assumes that each node name is unique. Good enough for a test.
// If clear is true, any incoming error is cleared before return. The errors
// are always accumulated, though.
-func mark(info os.FileInfo, err error, errors *[]error, clear bool) error {
+func mark(info fs.FileInfo, err error, errors *[]error, clear bool) error {
name := info.Name()
walkTree(tree, tree.name, func(path string, n *Node) {
if n.name == name {
@@ -431,7 +432,7 @@ func chtmpdir(t *testing.T) (restore func()) {
}
func TestWalk(t *testing.T) {
- if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64" {
+ if runtime.GOOS == "ios" {
restore := chtmpdir(t)
defer restore()
}
@@ -454,7 +455,7 @@ func TestWalk(t *testing.T) {
makeTree(t)
errors := make([]error, 0, 10)
clear := true
- markFn := func(path string, info os.FileInfo, err error) error {
+ markFn := func(path string, info fs.FileInfo, err error) error {
return mark(info, err, &errors, clear)
}
// Expect no errors.
@@ -543,7 +544,7 @@ func TestWalkSkipDirOnFile(t *testing.T) {
touch(t, filepath.Join(td, "dir/foo2"))
sawFoo2 := false
- walker := func(path string, info os.FileInfo, err error) error {
+ walker := func(path string, info fs.FileInfo, err error) error {
if strings.HasSuffix(path, "foo2") {
sawFoo2 = true
}
@@ -589,14 +590,14 @@ func TestWalkFileError(t *testing.T) {
*filepath.LstatP = os.Lstat
}()
statErr := errors.New("some stat error")
- *filepath.LstatP = func(path string) (os.FileInfo, error) {
+ *filepath.LstatP = func(path string) (fs.FileInfo, error) {
if strings.HasSuffix(path, "stat-error") {
return nil, statErr
}
return os.Lstat(path)
}
got := map[string]error{}
- err = filepath.Walk(td, func(path string, fi os.FileInfo, err error) error {
+ err = filepath.Walk(td, func(path string, fi fs.FileInfo, err error) error {
rel, _ := filepath.Rel(td, path)
got[filepath.ToSlash(rel)] = err
return nil
@@ -1278,7 +1279,7 @@ func TestDriveLetterInEvalSymlinks(t *testing.T) {
}
func TestBug3486(t *testing.T) { // https://golang.org/issue/3486
- if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64" {
+ if runtime.GOOS == "ios" {
t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
}
root, err := filepath.EvalSymlinks(runtime.GOROOT() + "/test")
@@ -1289,7 +1290,7 @@ func TestBug3486(t *testing.T) { // https://golang.org/issue/3486
ken := filepath.Join(root, "ken")
seenBugs := false
seenKen := false
- err = filepath.Walk(root, func(pth string, info os.FileInfo, err error) error {
+ err = filepath.Walk(root, func(pth string, info fs.FileInfo, err error) error {
if err != nil {
t.Fatal(err)
}
@@ -1338,7 +1339,7 @@ func testWalkSymlink(t *testing.T, mklink func(target, link string) error) {
}
var visited []string
- err = filepath.Walk(tmpdir, func(path string, info os.FileInfo, err error) error {
+ err = filepath.Walk(tmpdir, func(path string, info fs.FileInfo, err error) error {
if err != nil {
t.Fatal(err)
}
diff --git a/src/path/filepath/path_windows_test.go b/src/path/filepath/path_windows_test.go
index f7c454bf65..9309a7dc4d 100644
--- a/src/path/filepath/path_windows_test.go
+++ b/src/path/filepath/path_windows_test.go
@@ -8,6 +8,7 @@ import (
"flag"
"fmt"
"internal/testenv"
+ "io/fs"
"io/ioutil"
"os"
"os/exec"
@@ -34,7 +35,7 @@ func testWinSplitListTestIsValid(t *testing.T, ti int, tt SplitListTest,
const (
cmdfile = `printdir.cmd`
- perm os.FileMode = 0700
+ perm fs.FileMode = 0700
)
tmp, err := ioutil.TempDir("", "testWinSplitListTestIsValid")
@@ -412,6 +413,9 @@ func TestToNorm(t *testing.T) {
{`{{tmp}}\test`, `.\foo\bar`, `foo\bar`},
{`{{tmp}}\test`, `foo\..\foo\bar`, `foo\bar`},
{`{{tmp}}\test`, `FOO\BAR`, `foo\bar`},
+
+ // test UNC paths
+ {".", `\\localhost\c$`, `\\localhost\c$`},
}
tmp, err := ioutil.TempDir("", "testToNorm")
diff --git a/src/path/filepath/symlink.go b/src/path/filepath/symlink.go
index 335b315a20..6fefd15977 100644
--- a/src/path/filepath/symlink.go
+++ b/src/path/filepath/symlink.go
@@ -6,6 +6,7 @@ package filepath
import (
"errors"
+ "io/fs"
"os"
"runtime"
"syscall"
@@ -85,7 +86,7 @@ func walkSymlinks(path string) (string, error) {
return "", err
}
- if fi.Mode()&os.ModeSymlink == 0 {
+ if fi.Mode()&fs.ModeSymlink == 0 {
if !fi.Mode().IsDir() && end < len(path) {
return "", syscall.ENOTDIR
}
diff --git a/src/path/filepath/symlink_windows.go b/src/path/filepath/symlink_windows.go
index a799488c18..d72279e2bb 100644
--- a/src/path/filepath/symlink_windows.go
+++ b/src/path/filepath/symlink_windows.go
@@ -68,7 +68,7 @@ func toNorm(path string, normBase func(string) (string, error)) (string, error)
path = path[len(volume):]
// skip special cases
- if path == "." || path == `\` {
+ if path == "" || path == "." || path == `\` {
return volume + path, nil
}