diff options
author | Ian Lance Taylor <iant@golang.org> | 2018-01-09 01:23:08 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-01-09 01:23:08 +0000 |
commit | 1a2f01efa63036a5104f203a4789e682c0e0915d (patch) | |
tree | 373e15778dc8295354584e1f86915ae493b604ff /libgo/go/path | |
parent | 8799df67f2dab88f9fda11739c501780a85575e2 (diff) | |
download | gcc-1a2f01efa63036a5104f203a4789e682c0e0915d.zip gcc-1a2f01efa63036a5104f203a4789e682c0e0915d.tar.gz gcc-1a2f01efa63036a5104f203a4789e682c0e0915d.tar.bz2 |
libgo: update to Go1.10beta1
Update the Go library to the 1.10beta1 release.
Requires a few changes to the compiler for modifications to the map
runtime code, and to handle some nowritebarrier cases in the runtime.
Reviewed-on: https://go-review.googlesource.com/86455
gotools/:
* Makefile.am (go_cmd_vet_files): New variable.
(go_cmd_buildid_files, go_cmd_test2json_files): New variables.
(s-zdefaultcc): Change from constants to functions.
(noinst_PROGRAMS): Add vet, buildid, and test2json.
(cgo$(EXEEXT)): Link against $(LIBGOTOOL).
(vet$(EXEEXT)): New target.
(buildid$(EXEEXT)): New target.
(test2json$(EXEEXT)): New target.
(install-exec-local): Install all $(noinst_PROGRAMS).
(uninstall-local): Uninstasll all $(noinst_PROGRAMS).
(check-go-tool): Depend on $(noinst_PROGRAMS). Copy down
objabi.go.
(check-runtime): Depend on $(noinst_PROGRAMS).
(check-cgo-test, check-carchive-test): Likewise.
(check-vet): New target.
(check): Depend on check-vet. Look at cmd_vet-testlog.
(.PHONY): Add check-vet.
* Makefile.in: Rebuild.
From-SVN: r256365
Diffstat (limited to 'libgo/go/path')
-rw-r--r-- | libgo/go/path/example_test.go | 4 | ||||
-rw-r--r-- | libgo/go/path/filepath/example_test.go | 22 | ||||
-rw-r--r-- | libgo/go/path/filepath/example_unix_test.go | 22 | ||||
-rw-r--r-- | libgo/go/path/filepath/path.go | 24 | ||||
-rw-r--r-- | libgo/go/path/filepath/path_test.go | 216 | ||||
-rw-r--r-- | libgo/go/path/filepath/path_windows.go | 4 | ||||
-rw-r--r-- | libgo/go/path/filepath/symlink_windows.go | 97 |
7 files changed, 221 insertions, 168 deletions
diff --git a/libgo/go/path/example_test.go b/libgo/go/path/example_test.go index 21ed1fb..5cac36c9 100644 --- a/libgo/go/path/example_test.go +++ b/libgo/go/path/example_test.go @@ -49,11 +49,15 @@ func ExampleClean() { func ExampleDir() { fmt.Println(path.Dir("/a/b/c")) fmt.Println(path.Dir("a/b/c")) + fmt.Println(path.Dir("/a/")) + fmt.Println(path.Dir("a/")) fmt.Println(path.Dir("/")) fmt.Println(path.Dir("")) // Output: // /a/b // a/b + // /a + // a // / // . } diff --git a/libgo/go/path/filepath/example_test.go b/libgo/go/path/filepath/example_test.go new file mode 100644 index 0000000..d019c26 --- /dev/null +++ b/libgo/go/path/filepath/example_test.go @@ -0,0 +1,22 @@ +// Copyright 2017 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. + +// +build ignore + +package filepath_test + +import ( + "fmt" + "path/filepath" +) + +func ExampleExt() { + fmt.Printf("No dots: %q\n", filepath.Ext("index")) + fmt.Printf("One dot: %q\n", filepath.Ext("index.js")) + fmt.Printf("Two dots: %q\n", filepath.Ext("main.test.js")) + // Output: + // No dots: "" + // One dot: ".js" + // Two dots: ".js" +} diff --git a/libgo/go/path/filepath/example_unix_test.go b/libgo/go/path/filepath/example_unix_test.go index cd8233c..40bc547 100644 --- a/libgo/go/path/filepath/example_unix_test.go +++ b/libgo/go/path/filepath/example_unix_test.go @@ -8,6 +8,7 @@ package filepath_test import ( "fmt" + "os" "path/filepath" ) @@ -79,3 +80,24 @@ func ExampleJoin() { // a/b/c // a/b/c } +func ExampleWalk() { + dir := "dir/to/walk" + subDirToSkip := "skip" // dir/to/walk/skip + + err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + fmt.Printf("prevent panic by handling failure accessing a path %q: %v\n", dir, err) + return err + } + if info.IsDir() && info.Name() == subDirToSkip { + fmt.Printf("skipping a dir without errors: %+v \n", info.Name()) + return filepath.SkipDir + } + fmt.Printf("visited file: %q\n", path) + return nil + }) + + if err != nil { + fmt.Printf("error walking the path %q: %v\n", dir, err) + } +} diff --git a/libgo/go/path/filepath/path.go b/libgo/go/path/filepath/path.go index c242143..87f8faf 100644 --- a/libgo/go/path/filepath/path.go +++ b/libgo/go/path/filepath/path.go @@ -351,23 +351,23 @@ type WalkFunc func(path string, info os.FileInfo, err error) error var lstat = os.Lstat // for testing -// walk recursively descends path, calling w. +// walk recursively descends path, calling walkFn. func walk(path string, info os.FileInfo, walkFn WalkFunc) error { - err := walkFn(path, info, nil) - if err != nil { - if info.IsDir() && err == SkipDir { - return nil - } - return err - } - if !info.IsDir() { - return nil + return walkFn(path, info, nil) } names, err := readDirNames(path) - if err != nil { - return walkFn(path, info, err) + err1 := walkFn(path, info, err) + // If err != nil, walk can't walk into this directory. + // err1 != nil means walkFn want walk to skip this directory or stop walking. + // Therefore, if one of err and err1 isn't nil, walk will return. + if err != nil || err1 != nil { + // The caller's behavior is controlled by the return value, which is decided + // by walkFn. walkFn may ignore err and return nil. + // If walkFn returns SkipDir, it will be handled by the caller. + // So walk should return whatever walkFn returns. + return err1 } for _, name := range names { diff --git a/libgo/go/path/filepath/path_test.go b/libgo/go/path/filepath/path_test.go index f2e9252..ccffdba 100644 --- a/libgo/go/path/filepath/path_test.go +++ b/libgo/go/path/filepath/path_test.go @@ -392,6 +392,12 @@ func checkMarks(t *testing.T, report bool) { // 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 { + name := info.Name() + walkTree(tree, tree.name, func(path string, n *Node) { + if n.name == name { + n.mark++ + } + }) if err != nil { *errors = append(*errors, err) if clear { @@ -399,12 +405,6 @@ func mark(info os.FileInfo, err error, errors *[]error, clear bool) error { } return err } - name := info.Name() - walkTree(tree, tree.name, func(path string, n *Node) { - if n.name == name { - n.mark++ - } - }) return nil } @@ -774,24 +774,50 @@ var EvalSymlinksTests = []EvalSymlinksTest{ {"test/linkabs", "/"}, } -// findEvalSymlinksTestDirsDest searches testDirs -// for matching path and returns correspondent dest. -func findEvalSymlinksTestDirsDest(t *testing.T, testDirs []EvalSymlinksTest, path string) string { - for _, d := range testDirs { - if d.path == path { - return d.dest - } - } - t.Fatalf("did not find %q in testDirs slice", path) - return "" -} - // simpleJoin builds a file name from the directory and path. // It does not use Join because we don't want ".." to be evaluated. func simpleJoin(dir, path string) string { return dir + string(filepath.Separator) + path } +func testEvalSymlinks(t *testing.T, path, want string) { + have, err := filepath.EvalSymlinks(path) + if err != nil { + t.Errorf("EvalSymlinks(%q) error: %v", path, err) + return + } + if filepath.Clean(have) != filepath.Clean(want) { + t.Errorf("EvalSymlinks(%q) returns %q, want %q", path, have, want) + } +} + +func testEvalSymlinksAfterChdir(t *testing.T, wd, path, want string) { + cwd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer func() { + err := os.Chdir(cwd) + if err != nil { + t.Fatal(err) + } + }() + + err = os.Chdir(wd) + if err != nil { + t.Fatal(err) + } + + have, err := filepath.EvalSymlinks(path) + if err != nil { + t.Errorf("EvalSymlinks(%q) in %q directory error: %v", path, wd, err) + return + } + if filepath.Clean(have) != filepath.Clean(want) { + t.Errorf("EvalSymlinks(%q) in %q directory returns %q, want %q", path, wd, have, want) + } +} + func TestEvalSymlinks(t *testing.T) { testenv.MustHaveSymlink(t) @@ -808,22 +834,8 @@ func TestEvalSymlinks(t *testing.T) { t.Fatal("eval symlink for tmp dir:", err) } - tests := EvalSymlinksTests - testdirs := EvalSymlinksTestDirs - if runtime.GOOS == "windows" { - if len(tmpDir) < 3 { - t.Fatalf("tmpDir path %q is too short", tmpDir) - } - if tmpDir[1] != ':' { - t.Fatalf("tmpDir path %q must have drive letter in it", tmpDir) - } - newtest := EvalSymlinksTest{"test/linkabswin", tmpDir[:3]} - tests = append(tests, newtest) - testdirs = append(testdirs, newtest) - } - // Create the symlink farm using relative paths. - for _, d := range testdirs { + for _, d := range EvalSymlinksTestDirs { var err error path := simpleJoin(tmpDir, d.path) if d.dest == "" { @@ -836,135 +848,37 @@ func TestEvalSymlinks(t *testing.T) { } } - wd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - // Evaluate the symlink farm. - for _, d := range tests { - path := simpleJoin(tmpDir, d.path) - dest := simpleJoin(tmpDir, d.dest) - if filepath.IsAbs(d.dest) || os.IsPathSeparator(d.dest[0]) { - dest = d.dest - } - if p, err := filepath.EvalSymlinks(path); err != nil { - t.Errorf("EvalSymlinks(%q) error: %v", d.path, err) - } else if filepath.Clean(p) != filepath.Clean(dest) { - t.Errorf("EvalSymlinks(%q)=%q, want %q", path, p, dest) + for _, test := range EvalSymlinksTests { + path := simpleJoin(tmpDir, test.path) + + dest := simpleJoin(tmpDir, test.dest) + if filepath.IsAbs(test.dest) || os.IsPathSeparator(test.dest[0]) { + dest = test.dest } + testEvalSymlinks(t, path, dest) // test EvalSymlinks(".") - func() { - defer func() { - err := os.Chdir(wd) - if err != nil { - t.Fatal(err) - } - }() - - err := os.Chdir(path) - if err != nil { - t.Error(err) - return - } - p, err := filepath.EvalSymlinks(".") - if err != nil { - t.Errorf(`EvalSymlinks(".") in %q directory error: %v`, d.path, err) - return - } - if p == "." { - return - } - want := filepath.Clean(findEvalSymlinksTestDirsDest(t, testdirs, d.path)) - if p == want { - return - } - t.Errorf(`EvalSymlinks(".") in %q directory returns %q, want "." or %q`, d.path, p, want) - }() + testEvalSymlinksAfterChdir(t, path, ".", ".") // test EvalSymlinks("C:.") on Windows if runtime.GOOS == "windows" { - func() { - defer func() { - err := os.Chdir(wd) - if err != nil { - t.Fatal(err) - } - }() - - err := os.Chdir(path) - if err != nil { - t.Error(err) - return - } - - volDot := filepath.VolumeName(tmpDir) + "." - - p, err := filepath.EvalSymlinks(volDot) - if err != nil { - t.Errorf(`EvalSymlinks("%s") in %q directory error: %v`, volDot, d.path, err) - return - } - if p == volDot { - return - } - want := filepath.Clean(findEvalSymlinksTestDirsDest(t, testdirs, d.path)) - if p == want { - return - } - t.Errorf(`EvalSymlinks("%s") in %q directory returns %q, want %q or %q`, volDot, d.path, p, volDot, want) - }() + volDot := filepath.VolumeName(tmpDir) + "." + testEvalSymlinksAfterChdir(t, path, volDot, volDot) } // test EvalSymlinks(".."+path) - func() { - defer func() { - err := os.Chdir(wd) - if err != nil { - t.Fatal(err) - } - }() - - err := os.Chdir(simpleJoin(tmpDir, "test")) - if err != nil { - t.Error(err) - return - } - - path := simpleJoin("..", d.path) - dest := simpleJoin("..", d.dest) - if filepath.IsAbs(d.dest) || os.IsPathSeparator(d.dest[0]) { - dest = d.dest - } + dotdotPath := simpleJoin("..", test.dest) + if filepath.IsAbs(test.dest) || os.IsPathSeparator(test.dest[0]) { + dotdotPath = test.dest + } + testEvalSymlinksAfterChdir(t, + simpleJoin(tmpDir, "test"), + simpleJoin("..", test.path), + dotdotPath) - if p, err := filepath.EvalSymlinks(path); err != nil { - t.Errorf("EvalSymlinks(%q) error: %v", d.path, err) - } else if filepath.Clean(p) != filepath.Clean(dest) { - t.Errorf("EvalSymlinks(%q)=%q, want %q", path, p, dest) - } - }() - - // test EvalSymlinks where parameter is relative path - func() { - defer func() { - err := os.Chdir(wd) - if err != nil { - t.Fatal(err) - } - }() - - err := os.Chdir(tmpDir) - if err != nil { - t.Error(err) - return - } - if p, err := filepath.EvalSymlinks(d.path); err != nil { - t.Errorf("EvalSymlinks(%q) error: %v", d.path, err) - } else if filepath.Clean(p) != filepath.Clean(d.dest) { - t.Errorf("EvalSymlinks(%q)=%q, want %q", d.path, p, d.dest) - } - }() + // test EvalSymlinks(p) where p is relative path + testEvalSymlinksAfterChdir(t, tmpDir, test.path, test.dest) } } diff --git a/libgo/go/path/filepath/path_windows.go b/libgo/go/path/filepath/path_windows.go index 0d8b620..0354255 100644 --- a/libgo/go/path/filepath/path_windows.go +++ b/libgo/go/path/filepath/path_windows.go @@ -100,9 +100,7 @@ func splitList(path string) []string { // Remove quotes. for i, s := range list { - if strings.Contains(s, `"`) { - list[i] = strings.Replace(s, `"`, ``, -1) - } + list[i] = strings.Replace(s, `"`, ``, -1) } return list diff --git a/libgo/go/path/filepath/symlink_windows.go b/libgo/go/path/filepath/symlink_windows.go index f771fe3..78cde4a 100644 --- a/libgo/go/path/filepath/symlink_windows.go +++ b/libgo/go/path/filepath/symlink_windows.go @@ -5,6 +5,9 @@ package filepath import ( + "errors" + "internal/syscall/windows" + "os" "strings" "syscall" ) @@ -106,10 +109,100 @@ func toNorm(path string, normBase func(string) (string, error)) (string, error) return volume + normPath, nil } +// evalSymlinksUsingGetFinalPathNameByHandle uses Windows +// GetFinalPathNameByHandle API to retrieve the final +// path for the specified file. +func evalSymlinksUsingGetFinalPathNameByHandle(path string) (string, error) { + err := windows.LoadGetFinalPathNameByHandle() + if err != nil { + // we must be using old version of Windows + return "", err + } + + if path == "" { + return path, nil + } + + // Use Windows I/O manager to dereference the symbolic link, as per + // https://blogs.msdn.microsoft.com/oldnewthing/20100212-00/?p=14963/ + p, err := syscall.UTF16PtrFromString(path) + if err != nil { + return "", err + } + h, err := syscall.CreateFile(p, 0, 0, nil, + syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) + if err != nil { + return "", err + } + defer syscall.CloseHandle(h) + + buf := make([]uint16, 100) + for { + n, err := windows.GetFinalPathNameByHandle(h, &buf[0], uint32(len(buf)), windows.VOLUME_NAME_DOS) + if err != nil { + return "", err + } + if n < uint32(len(buf)) { + break + } + buf = make([]uint16, n) + } + s := syscall.UTF16ToString(buf) + if len(s) > 4 && s[:4] == `\\?\` { + s = s[4:] + if len(s) > 3 && s[:3] == `UNC` { + // return path like \\server\share\... + return `\` + s[3:], nil + } + return s, nil + } + return "", errors.New("GetFinalPathNameByHandle returned unexpected path=" + s) +} + +func samefile(path1, path2 string) bool { + fi1, err := os.Lstat(path1) + if err != nil { + return false + } + fi2, err := os.Lstat(path2) + if err != nil { + return false + } + return os.SameFile(fi1, fi2) +} + func evalSymlinks(path string) (string, error) { - path, err := walkSymlinks(path) + newpath, err := walkSymlinks(path) + if err != nil { + newpath2, err2 := evalSymlinksUsingGetFinalPathNameByHandle(path) + if err2 == nil { + return toNorm(newpath2, normBase) + } + return "", err + } + newpath, err = toNorm(newpath, normBase) if err != nil { + newpath2, err2 := evalSymlinksUsingGetFinalPathNameByHandle(path) + if err2 == nil { + return toNorm(newpath2, normBase) + } return "", err } - return toNorm(path, normBase) + if strings.ToUpper(newpath) == strings.ToUpper(path) { + // walkSymlinks did not actually walk any symlinks, + // so we don't need to try GetFinalPathNameByHandle. + return newpath, nil + } + newpath2, err2 := evalSymlinksUsingGetFinalPathNameByHandle(path) + if err2 != nil { + return newpath, nil + } + newpath2, err2 = toNorm(newpath2, normBase) + if err2 != nil { + return newpath, nil + } + if samefile(newpath, newpath2) { + return newpath, nil + } + return newpath2, nil } |