From 8a39ee361feb9bf46d728ff1ba4f07ca1d9610b1 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Thu, 19 Jun 2014 09:22:53 +0200 Subject: Imported Upstream version 1.3 --- src/pkg/path/filepath/export_test.go | 7 ++++ src/pkg/path/filepath/match.go | 2 +- src/pkg/path/filepath/match_test.go | 53 ++++++++++++++++++++++++- src/pkg/path/filepath/path.go | 38 +++++++++--------- src/pkg/path/filepath/path_test.go | 63 +++++++++++++++++++++++++++++- src/pkg/path/filepath/path_unix.go | 2 +- src/pkg/path/filepath/path_windows_test.go | 4 ++ 7 files changed, 146 insertions(+), 23 deletions(-) create mode 100644 src/pkg/path/filepath/export_test.go (limited to 'src/pkg/path') diff --git a/src/pkg/path/filepath/export_test.go b/src/pkg/path/filepath/export_test.go new file mode 100644 index 000000000..0cf9e3bca --- /dev/null +++ b/src/pkg/path/filepath/export_test.go @@ -0,0 +1,7 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package filepath + +var LstatP = &lstat diff --git a/src/pkg/path/filepath/match.go b/src/pkg/path/filepath/match.go index 3d84145d7..a9bcc103c 100644 --- a/src/pkg/path/filepath/match.go +++ b/src/pkg/path/filepath/match.go @@ -230,7 +230,7 @@ func getEsc(chunk string) (r rune, nchunk string, err error) { // func Glob(pattern string) (matches []string, err error) { if !hasMeta(pattern) { - if _, err = os.Stat(pattern); err != nil { + if _, err = os.Lstat(pattern); err != nil { return nil, nil } return []string{pattern}, nil diff --git a/src/pkg/path/filepath/match_test.go b/src/pkg/path/filepath/match_test.go index 13108ce1e..382692eaa 100644 --- a/src/pkg/path/filepath/match_test.go +++ b/src/pkg/path/filepath/match_test.go @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package filepath +package filepath_test import ( + "io/ioutil" + "os" + . "path/filepath" "runtime" "strings" "testing" @@ -153,3 +156,51 @@ func TestGlobError(t *testing.T) { t.Error("expected error for bad pattern; got none") } } + +var globSymlinkTests = []struct { + path, dest string + brokenLink bool +}{ + {"test1", "link1", false}, + {"test2", "link2", true}, +} + +func TestGlobSymlink(t *testing.T) { + switch runtime.GOOS { + case "nacl", "plan9", "windows": + t.Skipf("skipping on %s", runtime.GOOS) + } + + tmpDir, err := ioutil.TempDir("", "globsymlink") + if err != nil { + t.Fatal("creating temp dir:", err) + } + defer os.RemoveAll(tmpDir) + + for _, tt := range globSymlinkTests { + path := Join(tmpDir, tt.path) + dest := Join(tmpDir, tt.dest) + f, err := os.Create(path) + if err != nil { + t.Fatal(err) + } + if err := f.Close(); err != nil { + t.Fatal(err) + } + err = os.Symlink(path, dest) + if err != nil { + t.Fatal(err) + } + if tt.brokenLink { + // Break the symlink. + os.Remove(path) + } + matches, err := Glob(dest) + if err != nil { + t.Errorf("GlobSymlink error for %q: %s", dest, err) + } + if !contains(matches, dest) { + t.Errorf("Glob(%#q) = %#v want %v", dest, matches, dest) + } + } +} diff --git a/src/pkg/path/filepath/path.go b/src/pkg/path/filepath/path.go index f8c7e4b2f..71603cc59 100644 --- a/src/pkg/path/filepath/path.go +++ b/src/pkg/path/filepath/path.go @@ -67,7 +67,7 @@ const ( // along with the non-.. element that precedes it. // 4. Eliminate .. elements that begin a rooted path: // that is, replace "/.." by "/" at the beginning of a path, -// assuming Separator is '/'. +// assuming Separator is '/'. // // The returned path ends in a slash only if it represents a root directory, // such as "/" on Unix or `C:\` on Windows. @@ -336,6 +336,8 @@ var SkipDir = errors.New("skip this directory") // the next file. type WalkFunc func(path string, info os.FileInfo, err error) error +var lstat = os.Lstat // for testing + // walk recursively descends path, calling w. func walk(path string, info os.FileInfo, walkFn WalkFunc) error { err := walkFn(path, info, nil) @@ -350,17 +352,25 @@ func walk(path string, info os.FileInfo, walkFn WalkFunc) error { return nil } - list, err := readDir(path) + names, err := readDirNames(path) if err != nil { return walkFn(path, info, err) } - for _, fileInfo := range list { - err = walk(Join(path, fileInfo.Name()), fileInfo, walkFn) + for _, name := range names { + filename := Join(path, name) + fileInfo, err := lstat(filename) if err != nil { - if !fileInfo.IsDir() || err != SkipDir { + if err := walkFn(filename, fileInfo, err); err != nil && err != SkipDir { return err } + } else { + err = walk(filename, fileInfo, walkFn) + if err != nil { + if !fileInfo.IsDir() || err != SkipDir { + return err + } + } } } return nil @@ -380,30 +390,22 @@ func Walk(root string, walkFn WalkFunc) error { return walk(root, info, walkFn) } -// readDir reads the directory named by dirname and returns +// readDirNames reads the directory named by dirname and returns // a sorted list of directory entries. -// Copied from io/ioutil to avoid the circular import. -func readDir(dirname string) ([]os.FileInfo, error) { +func readDirNames(dirname string) ([]string, error) { f, err := os.Open(dirname) if err != nil { return nil, err } - list, err := f.Readdir(-1) + names, err := f.Readdirnames(-1) f.Close() if err != nil { return nil, err } - sort.Sort(byName(list)) - return list, nil + sort.Strings(names) + return names, nil } -// byName implements sort.Interface. -type byName []os.FileInfo - -func (f byName) Len() int { return len(f) } -func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() } -func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] } - // Base returns the last element of path. // Trailing path separators are removed before extracting the last element. // If the path is empty, Base returns ".". diff --git a/src/pkg/path/filepath/path_test.go b/src/pkg/path/filepath/path_test.go index d32b70d6e..819bd217c 100644 --- a/src/pkg/path/filepath/path_test.go +++ b/src/pkg/path/filepath/path_test.go @@ -5,6 +5,7 @@ package filepath_test import ( + "errors" "io/ioutil" "os" "path/filepath" @@ -458,6 +459,63 @@ func TestWalk(t *testing.T) { } } +func touch(t *testing.T, name string) { + f, err := os.Create(name) + if err != nil { + t.Fatal(err) + } + if err := f.Close(); err != nil { + t.Fatal(err) + } +} + +func TestWalkFileError(t *testing.T) { + td, err := ioutil.TempDir("", "walktest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(td) + + touch(t, filepath.Join(td, "foo")) + touch(t, filepath.Join(td, "bar")) + dir := filepath.Join(td, "dir") + if err := os.MkdirAll(filepath.Join(td, "dir"), 0755); err != nil { + t.Fatal(err) + } + touch(t, filepath.Join(dir, "baz")) + touch(t, filepath.Join(dir, "stat-error")) + defer func() { + *filepath.LstatP = os.Lstat + }() + statErr := errors.New("some stat error") + *filepath.LstatP = func(path string) (os.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 { + rel, _ := filepath.Rel(td, path) + got[filepath.ToSlash(rel)] = err + return nil + }) + if err != nil { + t.Errorf("Walk error: %v", err) + } + want := map[string]error{ + ".": nil, + "foo": nil, + "bar": nil, + "dir": nil, + "dir/baz": nil, + "dir/stat-error": statErr, + } + if !reflect.DeepEqual(got, want) { + t.Errorf("Walked %#v; want %#v", got, want) + } +} + var basetests = []PathTest{ {"", "."}, {".", "."}, @@ -633,8 +691,9 @@ func simpleJoin(dir, path string) string { } func TestEvalSymlinks(t *testing.T) { - if runtime.GOOS == "plan9" { - t.Skip("Skipping test: symlinks don't exist under Plan 9") + switch runtime.GOOS { + case "nacl", "plan9": + t.Skipf("skipping on %s", runtime.GOOS) } tmpDir, err := ioutil.TempDir("", "evalsymlink") diff --git a/src/pkg/path/filepath/path_unix.go b/src/pkg/path/filepath/path_unix.go index d927b342b..7aba0ab5b 100644 --- a/src/pkg/path/filepath/path_unix.go +++ b/src/pkg/path/filepath/path_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux netbsd openbsd +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris package filepath diff --git a/src/pkg/path/filepath/path_windows_test.go b/src/pkg/path/filepath/path_windows_test.go index d8926adde..8a9be8e89 100644 --- a/src/pkg/path/filepath/path_windows_test.go +++ b/src/pkg/path/filepath/path_windows_test.go @@ -1,3 +1,7 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package filepath_test import ( -- cgit v1.2.3