aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/path
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2018-01-09 01:23:08 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2018-01-09 01:23:08 +0000
commit1a2f01efa63036a5104f203a4789e682c0e0915d (patch)
tree373e15778dc8295354584e1f86915ae493b604ff /libgo/go/path
parent8799df67f2dab88f9fda11739c501780a85575e2 (diff)
downloadgcc-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.go4
-rw-r--r--libgo/go/path/filepath/example_test.go22
-rw-r--r--libgo/go/path/filepath/example_unix_test.go22
-rw-r--r--libgo/go/path/filepath/path.go24
-rw-r--r--libgo/go/path/filepath/path_test.go216
-rw-r--r--libgo/go/path/filepath/path_windows.go4
-rw-r--r--libgo/go/path/filepath/symlink_windows.go97
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
}