diff options
author | Ian Lance Taylor <iant@google.com> | 2016-02-03 21:58:02 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-02-03 21:58:02 +0000 |
commit | f98dd1a338867a408f7c72d73fbad7fe7fc93e3a (patch) | |
tree | 2f8da9862a9c1fe0df138917f997b03439c02773 /libgo/go/path | |
parent | b081ed4efc144da0c45a6484aebfd10e0eb9fda3 (diff) | |
download | gcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.zip gcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.tar.gz gcc-f98dd1a338867a408f7c72d73fbad7fe7fc93e3a.tar.bz2 |
libgo: Update to go1.6rc1.
Reviewed-on: https://go-review.googlesource.com/19200
From-SVN: r233110
Diffstat (limited to 'libgo/go/path')
-rw-r--r-- | libgo/go/path/filepath/example_unix_test.go | 2 | ||||
-rw-r--r-- | libgo/go/path/filepath/match_test.go | 2 | ||||
-rw-r--r-- | libgo/go/path/filepath/path.go | 10 | ||||
-rw-r--r-- | libgo/go/path/filepath/path_plan9.go | 4 | ||||
-rw-r--r-- | libgo/go/path/filepath/path_test.go | 193 | ||||
-rw-r--r-- | libgo/go/path/filepath/path_unix.go | 4 | ||||
-rw-r--r-- | libgo/go/path/filepath/path_windows.go | 9 | ||||
-rw-r--r-- | libgo/go/path/filepath/symlink.go | 135 | ||||
-rw-r--r-- | libgo/go/path/filepath/symlink_windows.go | 1 | ||||
-rw-r--r-- | libgo/go/path/path.go | 2 |
10 files changed, 280 insertions, 82 deletions
diff --git a/libgo/go/path/filepath/example_unix_test.go b/libgo/go/path/filepath/example_unix_test.go index 27d85d1..893be1b 100644 --- a/libgo/go/path/filepath/example_unix_test.go +++ b/libgo/go/path/filepath/example_unix_test.go @@ -35,7 +35,7 @@ func ExampleRel() { // On Unix: // "/a/b/c": "b/c" <nil> // "/b/c": "../b/c" <nil> - // "./b/c": "" Rel: can't make b/c relative to /a + // "./b/c": "" Rel: can't make ./b/c relative to /a } func ExampleSplit() { diff --git a/libgo/go/path/filepath/match_test.go b/libgo/go/path/filepath/match_test.go index c29f93f..209c67f 100644 --- a/libgo/go/path/filepath/match_test.go +++ b/libgo/go/path/filepath/match_test.go @@ -168,7 +168,7 @@ var globSymlinkTests = []struct { func TestGlobSymlink(t *testing.T) { switch runtime.GOOS { - case "nacl", "plan9": + case "android", "nacl", "plan9": t.Skipf("skipping on %s", runtime.GOOS) case "windows": if !supportsSymlinks { diff --git a/libgo/go/path/filepath/path.go b/libgo/go/path/filepath/path.go index 5dc5cfd..dd6f3e7 100644 --- a/libgo/go/path/filepath/path.go +++ b/libgo/go/path/filepath/path.go @@ -258,7 +258,7 @@ func Rel(basepath, targpath string) (string, error) { targVol := VolumeName(targpath) base := Clean(basepath) targ := Clean(targpath) - if targ == base { + if sameWord(targ, base) { return ".", nil } base = base[len(baseVol):] @@ -269,8 +269,8 @@ func Rel(basepath, targpath string) (string, error) { // Can't use IsAbs - `\a` and `a` are both relative in Windows. baseSlashed := len(base) > 0 && base[0] == Separator targSlashed := len(targ) > 0 && targ[0] == Separator - if baseSlashed != targSlashed || baseVol != targVol { - return "", errors.New("Rel: can't make " + targ + " relative to " + base) + if baseSlashed != targSlashed || !sameWord(baseVol, targVol) { + return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath) } // Position base[b0:bi] and targ[t0:ti] at the first differing elements. bl := len(base) @@ -283,7 +283,7 @@ func Rel(basepath, targpath string) (string, error) { for ti < tl && targ[ti] != Separator { ti++ } - if targ[t0:ti] != base[b0:bi] { + if !sameWord(targ[t0:ti], base[b0:bi]) { break } if bi < bl { @@ -296,7 +296,7 @@ func Rel(basepath, targpath string) (string, error) { t0 = ti } if base[b0:bi] == ".." { - return "", errors.New("Rel: can't make " + targ + " relative to " + base) + return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath) } if b0 != bl { // Base elements left. Must go up before going down. diff --git a/libgo/go/path/filepath/path_plan9.go b/libgo/go/path/filepath/path_plan9.go index 962774e..60d46d9 100644 --- a/libgo/go/path/filepath/path_plan9.go +++ b/libgo/go/path/filepath/path_plan9.go @@ -42,3 +42,7 @@ func join(elem []string) string { } return "" } + +func sameWord(a, b string) bool { + return a == b +} diff --git a/libgo/go/path/filepath/path_test.go b/libgo/go/path/filepath/path_test.go index b2536cb..10ea795 100644 --- a/libgo/go/path/filepath/path_test.go +++ b/libgo/go/path/filepath/path_test.go @@ -270,7 +270,12 @@ var winjointests = []JoinTest{ {[]string{`C:\Windows\`, `System32`}, `C:\Windows\System32`}, {[]string{`C:\Windows\`, ``}, `C:\Windows`}, {[]string{`C:\`, `Windows`}, `C:\Windows`}, - {[]string{`C:`, `Windows`}, `C:\Windows`}, + {[]string{`C:`, `a`}, `C:a`}, + {[]string{`C:`, `a\b`}, `C:a\b`}, + {[]string{`C:`, `a`, `b`}, `C:a\b`}, + {[]string{`C:.`, `a`}, `C:a`}, + {[]string{`C:a`, `b`}, `C:a\b`}, + {[]string{`C:a`, `b`, `d`}, `C:a\b\d`}, {[]string{`\\host\share`, `foo`}, `\\host\share\foo`}, {[]string{`\\host\share\foo`}, `\\host\share\foo`}, {[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`}, @@ -405,18 +410,18 @@ func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool) func chtmpdir(t *testing.T) (restore func()) { oldwd, err := os.Getwd() if err != nil { - t.Fatal("chtmpdir: %v", err) + t.Fatalf("chtmpdir: %v", err) } d, err := ioutil.TempDir("", "test") if err != nil { - t.Fatal("chtmpdir: %v", err) + t.Fatalf("chtmpdir: %v", err) } if err := os.Chdir(d); err != nil { - t.Fatal("chtmpdir: %v", err) + t.Fatalf("chtmpdir: %v", err) } return func() { if err := os.Chdir(oldwd); err != nil { - t.Fatal("chtmpdir: %v", err) + t.Fatalf("chtmpdir: %v", err) } os.RemoveAll(d) } @@ -755,8 +760,16 @@ var EvalSymlinksTests = []EvalSymlinksTest{ {"test/linkabs", "/"}, } -var EvalSymlinksAbsWindowsTests = []EvalSymlinksTest{ - {`c:\`, `c:\`}, +// 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. @@ -767,9 +780,12 @@ func simpleJoin(dir, path string) string { func TestEvalSymlinks(t *testing.T) { switch runtime.GOOS { - case "nacl", "plan9": + case "android", "nacl", "plan9": t.Skipf("skipping on %s", runtime.GOOS) } + if !supportsSymlinks { + t.Skip("skipping because symlinks are not supported") + } tmpDir, err := ioutil.TempDir("", "evalsymlink") if err != nil { @@ -784,38 +800,37 @@ 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 EvalSymlinksTestDirs { + for _, d := range testdirs { var err error path := simpleJoin(tmpDir, d.path) if d.dest == "" { err = os.Mkdir(path, 0755) } else { - if supportsSymlinks { - err = os.Symlink(d.dest, path) - } + err = os.Symlink(d.dest, path) } if err != nil { t.Fatal(err) } } - var tests []EvalSymlinksTest - if supportsSymlinks { - tests = EvalSymlinksTests - } else { - for _, d := range EvalSymlinksTests { - if d.path == d.dest { - // will test only real files and directories - tests = append(tests, d) - // test "canonical" names - d2 := EvalSymlinksTest{ - path: strings.ToUpper(d.path), - dest: d.dest, - } - tests = append(tests, d2) - } - } + wd, err := os.Getwd() + if err != nil { + t.Fatal(err) } // Evaluate the symlink farm. @@ -830,6 +845,125 @@ func TestEvalSymlinks(t *testing.T) { } else if filepath.Clean(p) != filepath.Clean(dest) { t.Errorf("Clean(%q)=%q, want %q", path, p, 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) + }() + + // 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("Clean(%q)=%q, want %q", d.path, p, d.dest) + } + }() + } +} + +func TestIssue13582(t *testing.T) { + switch runtime.GOOS { + case "android", "nacl", "plan9": + t.Skipf("skipping on %s", runtime.GOOS) + } + if !supportsSymlinks { + t.Skip("skipping because symlinks are not supported") + } + + tmpDir, err := ioutil.TempDir("", "issue13582") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) + + dir := filepath.Join(tmpDir, "dir") + err = os.Mkdir(dir, 0755) + if err != nil { + t.Fatal(err) + } + linkToDir := filepath.Join(tmpDir, "link_to_dir") + err = os.Symlink(dir, linkToDir) + if err != nil { + t.Fatal(err) + } + file := filepath.Join(linkToDir, "file") + err = ioutil.WriteFile(file, nil, 0644) + if err != nil { + t.Fatal(err) + } + link1 := filepath.Join(linkToDir, "link1") + err = os.Symlink(file, link1) + if err != nil { + t.Fatal(err) + } + link2 := filepath.Join(linkToDir, "link2") + err = os.Symlink(link1, link2) + if err != nil { + t.Fatal(err) + } + + // /tmp may itself be a symlink! + realTmpDir, err := filepath.EvalSymlinks(tmpDir) + if err != nil { + t.Fatal(err) + } + realDir := filepath.Join(realTmpDir, "dir") + realFile := filepath.Join(realDir, "file") + + tests := []struct { + path, want string + }{ + {dir, realDir}, + {linkToDir, realDir}, + {file, realFile}, + {link1, realFile}, + {link2, realFile}, + } + for i, test := range tests { + have, err := filepath.EvalSymlinks(test.path) + if err != nil { + t.Fatal(err) + } + if have != test.want { + t.Errorf("test#%d: EvalSymlinks(%q) returns %q, want %q", i, test.path, have, test.want) + } } } @@ -976,6 +1110,9 @@ var winreltests = []RelTests{ {`C:a\b\c`, `C:a/b/d`, `..\d`}, {`C:\`, `D:\`, `err`}, {`C:`, `D:`, `err`}, + {`C:\Projects`, `c:\projects\src`, `src`}, + {`C:\Projects`, `c:\projects`, `.`}, + {`C:\Projects\a\..`, `c:\projects`, `.`}, } func TestRel(t *testing.T) { diff --git a/libgo/go/path/filepath/path_unix.go b/libgo/go/path/filepath/path_unix.go index d241d78..2d242cc 100644 --- a/libgo/go/path/filepath/path_unix.go +++ b/libgo/go/path/filepath/path_unix.go @@ -44,3 +44,7 @@ func join(elem []string) string { } return "" } + +func sameWord(a, b string) bool { + return a == b +} diff --git a/libgo/go/path/filepath/path_windows.go b/libgo/go/path/filepath/path_windows.go index bcfe0a3..ef6e7ca 100644 --- a/libgo/go/path/filepath/path_windows.go +++ b/libgo/go/path/filepath/path_windows.go @@ -120,6 +120,11 @@ func join(elem []string) string { // joinNonEmpty is like join, but it assumes that the first element is non-empty. func joinNonEmpty(elem []string) string { + if len(elem[0]) == 2 && elem[0][1] == ':' { + // First element is drive leter without terminating slash. + // Keep path relative to current directory on that drive. + return Clean(elem[0] + strings.Join(elem[1:], string(Separator))) + } // The following logic prevents Join from inadvertently creating a // UNC path on Windows. Unless the first element is a UNC path, Join // shouldn't create a UNC path. See golang.org/issue/9167. @@ -145,3 +150,7 @@ func joinNonEmpty(elem []string) string { func isUNC(path string) bool { return volumeNameLen(path) > 2 } + +func sameWord(a, b string) bool { + return strings.EqualFold(a, b) +} diff --git a/libgo/go/path/filepath/symlink.go b/libgo/go/path/filepath/symlink.go index df0a9e0..bc287c5 100644 --- a/libgo/go/path/filepath/symlink.go +++ b/libgo/go/path/filepath/symlink.go @@ -5,68 +5,113 @@ package filepath import ( - "bytes" "errors" "os" + "runtime" ) -const utf8RuneSelf = 0x80 +// isRoot returns true if path is root of file system +// (`/` on unix and `/`, `\`, `c:\` or `c:/` on windows). +func isRoot(path string) bool { + if runtime.GOOS != "windows" { + return path == "/" + } + switch len(path) { + case 1: + return os.IsPathSeparator(path[0]) + case 3: + return path[1] == ':' && os.IsPathSeparator(path[2]) + } + return false +} -func walkSymlinks(path string) (string, error) { - const maxIter = 255 - originalPath := path - // consume path by taking each frontmost path element, - // expanding it if it's a symlink, and appending it to b - var b bytes.Buffer - for n := 0; path != ""; n++ { - if n > maxIter { - return "", errors.New("EvalSymlinks: too many links in " + originalPath) - } +// isDriveLetter returns true if path is Windows drive letter (like "c:"). +func isDriveLetter(path string) bool { + if runtime.GOOS != "windows" { + return false + } + return len(path) == 2 && path[1] == ':' +} - // find next path component, p - var i = -1 - for j, c := range path { - if c < utf8RuneSelf && os.IsPathSeparator(uint8(c)) { - i = j - break - } - } - var p string - if i == -1 { - p, path = path, "" - } else { - p, path = path[:i], path[i+1:] - } +func walkLink(path string, linksWalked *int) (newpath string, islink bool, err error) { + if *linksWalked > 255 { + return "", false, errors.New("EvalSymlinks: too many links") + } + fi, err := os.Lstat(path) + if err != nil { + return "", false, err + } + if fi.Mode()&os.ModeSymlink == 0 { + return path, false, nil + } + newpath, err = os.Readlink(path) + if err != nil { + return "", false, err + } + *linksWalked++ + return newpath, true, nil +} - if p == "" { - if b.Len() == 0 { - // must be absolute path - b.WriteRune(Separator) +func walkLinks(path string, linksWalked *int) (string, error) { + switch dir, file := Split(path); { + case dir == "": + newpath, _, err := walkLink(file, linksWalked) + return newpath, err + case file == "": + if isDriveLetter(dir) { + return dir, nil + } + if os.IsPathSeparator(dir[len(dir)-1]) { + if isRoot(dir) { + return dir, nil } - continue + return walkLinks(dir[:len(dir)-1], linksWalked) } - - fi, err := os.Lstat(b.String() + p) + newpath, _, err := walkLink(dir, linksWalked) + return newpath, err + default: + newdir, err := walkLinks(dir, linksWalked) if err != nil { return "", err } - if fi.Mode()&os.ModeSymlink == 0 { - b.WriteString(p) - if path != "" || (b.Len() == 2 && len(p) == 2 && p[1] == ':') { - b.WriteRune(Separator) - } - continue + newpath, islink, err := walkLink(Join(newdir, file), linksWalked) + if err != nil { + return "", err + } + if !islink { + return newpath, nil } + if IsAbs(newpath) || os.IsPathSeparator(newpath[0]) { + return newpath, nil + } + return Join(newdir, newpath), nil + } +} - // it's a symlink, put it at the front of path - dest, err := os.Readlink(b.String() + p) +func walkSymlinks(path string) (string, error) { + if path == "" { + return path, nil + } + var linksWalked int // to protect against cycles + for { + i := linksWalked + newpath, err := walkLinks(path, &linksWalked) if err != nil { return "", err } - if IsAbs(dest) || os.IsPathSeparator(dest[0]) { - b.Reset() + if runtime.GOOS == "windows" { + // walkLinks(".", ...) always retuns "." on unix. + // But on windows it returns symlink target, if current + // directory is a symlink. Stop the walk, if symlink + // target is not absolute path, and return "." + // to the caller (just like unix does). + if path == "." && !IsAbs(newpath) { + return ".", nil + } + } + if i == linksWalked { + return Clean(newpath), nil } - path = dest + string(Separator) + path + path = newpath } - return Clean(b.String()), nil } diff --git a/libgo/go/path/filepath/symlink_windows.go b/libgo/go/path/filepath/symlink_windows.go index 4b38f6f..eb48367 100644 --- a/libgo/go/path/filepath/symlink_windows.go +++ b/libgo/go/path/filepath/symlink_windows.go @@ -51,7 +51,6 @@ func evalSymlinks(path string) (string, error) { if err != nil { return "", err } - p, err := toShort(path) if err != nil { return "", err diff --git a/libgo/go/path/path.go b/libgo/go/path/path.go index 77f2185..01071a9 100644 --- a/libgo/go/path/path.go +++ b/libgo/go/path/path.go @@ -136,7 +136,7 @@ func Clean(path string) string { // Split splits path immediately following the final slash, // separating it into a directory and file name component. -// If there is no slash path, Split returns an empty dir and +// If there is no slash in path, Split returns an empty dir and // file set to path. // The returned values have the property that path = dir+file. func Split(path string) (dir, file string) { |