diff options
Diffstat (limited to 'libgo/go/path')
-rw-r--r-- | libgo/go/path/filepath/match.go | 24 | ||||
-rw-r--r-- | libgo/go/path/filepath/match_test.go | 38 | ||||
-rw-r--r-- | libgo/go/path/filepath/path.go | 61 | ||||
-rw-r--r-- | libgo/go/path/filepath/path_test.go | 103 | ||||
-rw-r--r-- | libgo/go/path/filepath/path_windows.go | 4 | ||||
-rw-r--r-- | libgo/go/path/filepath/symlink.go | 67 | ||||
-rw-r--r-- | libgo/go/path/filepath/symlink_windows.go | 63 |
7 files changed, 250 insertions, 110 deletions
diff --git a/libgo/go/path/filepath/match.go b/libgo/go/path/filepath/match.go index 38d264fb97a..db8b0260ca8 100644 --- a/libgo/go/path/filepath/match.go +++ b/libgo/go/path/filepath/match.go @@ -7,6 +7,7 @@ package filepath import ( "errors" "os" + "runtime" "sort" "strings" "unicode/utf8" @@ -37,6 +38,9 @@ var ErrBadPattern = errors.New("syntax error in pattern") // The only possible returned error is ErrBadPattern, when pattern // is malformed. // +// On Windows, escaping is disabled. Instead, '\\' is treated as +// path separator. +// func Match(pattern, name string) (matched bool, err error) { Pattern: for len(pattern) > 0 { @@ -95,9 +99,11 @@ Scan: for i = 0; i < len(pattern); i++ { switch pattern[i] { case '\\': - // error check handled in matchChunk: bad pattern. - if i+1 < len(pattern) { - i++ + if runtime.GOOS != "windows" { + // error check handled in matchChunk: bad pattern. + if i+1 < len(pattern) { + i++ + } } case '[': inrange = true @@ -167,10 +173,12 @@ func matchChunk(chunk, s string) (rest string, ok bool, err error) { chunk = chunk[1:] case '\\': - chunk = chunk[1:] - if len(chunk) == 0 { - err = ErrBadPattern - return + if runtime.GOOS != "windows" { + chunk = chunk[1:] + if len(chunk) == 0 { + err = ErrBadPattern + return + } } fallthrough @@ -191,7 +199,7 @@ func getEsc(chunk string) (r rune, nchunk string, err error) { err = ErrBadPattern return } - if chunk[0] == '\\' { + if chunk[0] == '\\' && runtime.GOOS != "windows" { chunk = chunk[1:] if len(chunk) == 0 { err = ErrBadPattern diff --git a/libgo/go/path/filepath/match_test.go b/libgo/go/path/filepath/match_test.go index dc0fff2f5e0..e3d365881cc 100644 --- a/libgo/go/path/filepath/match_test.go +++ b/libgo/go/path/filepath/match_test.go @@ -7,6 +7,7 @@ package filepath_test import ( . "path/filepath" "runtime" + "strings" "testing" ) @@ -76,21 +77,26 @@ func errp(e error) string { } func TestMatch(t *testing.T) { - if runtime.GOOS == "windows" { - // XXX: Don't pass for windows. - return - } for _, tt := range matchTests { - ok, err := Match(tt.pattern, tt.s) + pattern := tt.pattern + s := tt.s + if runtime.GOOS == "windows" { + if strings.Index(pattern, "\\") >= 0 { + // no escape allowed on windows. + continue + } + pattern = Clean(pattern) + s = Clean(s) + } + ok, err := Match(pattern, s) if ok != tt.match || err != tt.err { - t.Errorf("Match(%#q, %#q) = %v, %q want %v, %q", tt.pattern, tt.s, ok, errp(err), tt.match, errp(tt.err)) + t.Errorf("Match(%#q, %#q) = %v, %q want %v, %q", pattern, s, ok, errp(err), tt.match, errp(tt.err)) } } } // contains returns true if vector contains the string s. func contains(vector []string, s string) bool { - s = ToSlash(s) for _, elem := range vector { if elem == s { return true @@ -110,18 +116,20 @@ var globTests = []struct { } func TestGlob(t *testing.T) { - if runtime.GOOS == "windows" { - // XXX: Don't pass for windows. - return - } for _, tt := range globTests { - matches, err := Glob(tt.pattern) + pattern := tt.pattern + result := tt.result + if runtime.GOOS == "windows" { + pattern = Clean(pattern) + result = Clean(result) + } + matches, err := Glob(pattern) if err != nil { - t.Errorf("Glob error for %q: %s", tt.pattern, err) + t.Errorf("Glob error for %q: %s", pattern, err) continue } - if !contains(matches, tt.result) { - t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result) + if !contains(matches, result) { + t.Errorf("Glob(%#q) = %#v want %v", pattern, matches, result) } } for _, pattern := range []string{"no_match", "../*/no_match"} { diff --git a/libgo/go/path/filepath/path.go b/libgo/go/path/filepath/path.go index cfe46981f13..1e748726367 100644 --- a/libgo/go/path/filepath/path.go +++ b/libgo/go/path/filepath/path.go @@ -7,10 +7,8 @@ package filepath import ( - "bytes" "errors" "os" - "runtime" "sort" "strings" ) @@ -191,64 +189,7 @@ func Ext(path string) string { // If path is relative the result will be relative to the current directory, // unless one of the components is an absolute symbolic link. func EvalSymlinks(path string) (string, error) { - if runtime.GOOS == "windows" { - // Symlinks are not supported under windows. - _, err := os.Lstat(path) - if err != nil { - return "", err - } - return Clean(path), nil - } - 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) - } - - // find next path component, p - i := strings.IndexRune(path, Separator) - var p string - if i == -1 { - p, path = path, "" - } else { - p, path = path[:i], path[i+1:] - } - - if p == "" { - if b.Len() == 0 { - // must be absolute path - b.WriteRune(Separator) - } - continue - } - - fi, err := os.Lstat(b.String() + p) - if err != nil { - return "", err - } - if fi.Mode()&os.ModeSymlink == 0 { - b.WriteString(p) - if path != "" { - b.WriteRune(Separator) - } - continue - } - - // it's a symlink, put it at the front of path - dest, err := os.Readlink(b.String() + p) - if err != nil { - return "", err - } - if IsAbs(dest) { - b.Reset() - } - path = dest + string(Separator) + path - } - return Clean(b.String()), nil + return evalSymlinks(path) } // Abs returns an absolute representation of path. diff --git a/libgo/go/path/filepath/path_test.go b/libgo/go/path/filepath/path_test.go index 93cca1e4c2b..b8766588cf5 100644 --- a/libgo/go/path/filepath/path_test.go +++ b/libgo/go/path/filepath/path_test.go @@ -10,6 +10,7 @@ import ( "path/filepath" "reflect" "runtime" + "strings" "testing" ) @@ -439,7 +440,7 @@ func TestBase(t *testing.T) { tests := basetests if runtime.GOOS == "windows" { // make unix tests work on windows - for i, _ := range tests { + for i := range tests { tests[i].result = filepath.Clean(tests[i].result) } // add windows specific tests @@ -482,7 +483,7 @@ func TestDir(t *testing.T) { tests := dirtests if runtime.GOOS == "windows" { // make unix tests work on windows - for i, _ := range tests { + for i := range tests { tests[i].result = filepath.Clean(tests[i].result) } // add windows specific tests @@ -620,6 +621,12 @@ func TestEvalSymlinks(t *testing.T) { 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) } } } else { @@ -641,35 +648,61 @@ func TestEvalSymlinks(t *testing.T) { } } -/* These tests do not work in the gccgo test environment. +// Test directories relative to temporary directory. +// The tests are run in absTestDirs[0]. +var absTestDirs = []string{ + "a", + "a/b", + "a/b/c", +} -// Test paths relative to $GOROOT/src -var abstests = []string{ - "../AUTHORS", - "pkg/../../AUTHORS", - "Make.inc", - "pkg/math", +// Test paths relative to temporary directory. $ expands to the directory. +// The tests are run in absTestDirs[0]. +// We create absTestDirs first. +var absTests = []string{ ".", - "$GOROOT/src/Make.inc", - "$GOROOT/src/../src/Make.inc", - "$GOROOT/misc/cgo", - "$GOROOT", + "b", + "../a", + "../a/b", + "../a/b/./c/../../.././a", + "$", + "$/.", + "$/a/../a/b", + "$/a/b/c/../../.././a", } func TestAbs(t *testing.T) { - t.Logf("test needs to be rewritten; disabled") - return - oldwd, err := os.Getwd() if err != nil { - t.Fatal("Getwd failed: " + err.Error()) + t.Fatal("Getwd failed: ", err) } defer os.Chdir(oldwd) - goroot := os.Getenv("GOROOT") - cwd := filepath.Join(goroot, "src") - os.Chdir(cwd) - for _, path := range abstests { - path = strings.Replace(path, "$GOROOT", goroot, -1) + + root, err := ioutil.TempDir("", "TestAbs") + if err != nil { + t.Fatal("TempDir failed: ", err) + } + defer os.RemoveAll(root) + + err = os.Chdir(root) + if err != nil { + t.Fatal("chdir failed: ", err) + } + + for _, dir := range absTestDirs { + err = os.Mkdir(dir, 0777) + if err != nil { + t.Fatal("Mkdir failed: ", err) + } + } + + err = os.Chdir(absTestDirs[0]) + if err != nil { + t.Fatal("chdir failed: ", err) + } + + for _, path := range absTests { + path = strings.Replace(path, "$", root, -1) info, err := os.Stat(path) if err != nil { t.Errorf("%s: %s", path, err) @@ -694,8 +727,6 @@ func TestAbs(t *testing.T) { } } -*/ - type RelTests struct { root, path, want string } @@ -783,6 +814,7 @@ type VolumeNameTest struct { var volumenametests = []VolumeNameTest{ {`c:/foo/bar`, `c:`}, {`c:`, `c:`}, + {`2:`, ``}, {``, ``}, {`\\\host`, ``}, {`\\\host\`, ``}, @@ -814,3 +846,26 @@ func TestVolumeName(t *testing.T) { } } } + +func TestDriveLetterInEvalSymlinks(t *testing.T) { + if runtime.GOOS != "windows" { + return + } + wd, _ := os.Getwd() + if len(wd) < 3 { + t.Errorf("Current directory path %q is too short", wd) + } + lp := strings.ToLower(wd) + up := strings.ToUpper(wd) + flp, err := filepath.EvalSymlinks(lp) + if err != nil { + t.Fatalf("EvalSymlinks(%q) failed: %q", lp, err) + } + fup, err := filepath.EvalSymlinks(up) + if err != nil { + t.Fatalf("EvalSymlinks(%q) failed: %q", up, err) + } + if flp != fup { + t.Errorf("Results of EvalSymlinks do not match: %q and %q", flp, fup) + } +} diff --git a/libgo/go/path/filepath/path_windows.go b/libgo/go/path/filepath/path_windows.go index 1d1d23bfe7c..3dcd0302195 100644 --- a/libgo/go/path/filepath/path_windows.go +++ b/libgo/go/path/filepath/path_windows.go @@ -35,9 +35,7 @@ func VolumeName(path string) (v string) { } // with drive letter c := path[0] - if path[1] == ':' && - ('0' <= c && c <= '9' || 'a' <= c && c <= 'z' || - 'A' <= c && c <= 'Z') { + if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') { return path[:2] } // is it UNC diff --git a/libgo/go/path/filepath/symlink.go b/libgo/go/path/filepath/symlink.go new file mode 100644 index 00000000000..307dd0f8fee --- /dev/null +++ b/libgo/go/path/filepath/symlink.go @@ -0,0 +1,67 @@ +// Copyright 2012 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 !windows + +package filepath + +import ( + "bytes" + "errors" + "os" + "strings" +) + +func evalSymlinks(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) + } + + // find next path component, p + i := strings.IndexRune(path, Separator) + var p string + if i == -1 { + p, path = path, "" + } else { + p, path = path[:i], path[i+1:] + } + + if p == "" { + if b.Len() == 0 { + // must be absolute path + b.WriteRune(Separator) + } + continue + } + + fi, err := os.Lstat(b.String() + p) + if err != nil { + return "", err + } + if fi.Mode()&os.ModeSymlink == 0 { + b.WriteString(p) + if path != "" { + b.WriteRune(Separator) + } + continue + } + + // it's a symlink, put it at the front of path + dest, err := os.Readlink(b.String() + p) + if err != nil { + return "", err + } + if IsAbs(dest) { + b.Reset() + } + path = dest + string(Separator) + path + } + return Clean(b.String()), nil +} diff --git a/libgo/go/path/filepath/symlink_windows.go b/libgo/go/path/filepath/symlink_windows.go new file mode 100644 index 00000000000..1ee939928e9 --- /dev/null +++ b/libgo/go/path/filepath/symlink_windows.go @@ -0,0 +1,63 @@ +// Copyright 2012 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 + +import ( + "syscall" +) + +func toShort(path string) (string, error) { + p := syscall.StringToUTF16(path) + b := p // GetShortPathName says we can reuse buffer + n, err := syscall.GetShortPathName(&p[0], &b[0], uint32(len(b))) + if err != nil { + return "", err + } + if n > uint32(len(b)) { + b = make([]uint16, n) + n, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b))) + if err != nil { + return "", err + } + } + return syscall.UTF16ToString(b), nil +} + +func toLong(path string) (string, error) { + p := syscall.StringToUTF16(path) + b := p // GetLongPathName says we can reuse buffer + n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b))) + if err != nil { + return "", err + } + if n > uint32(len(b)) { + b = make([]uint16, n) + n, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b))) + if err != nil { + return "", err + } + } + b = b[:n] + return syscall.UTF16ToString(b), nil +} + +func evalSymlinks(path string) (string, error) { + p, err := toShort(path) + if err != nil { + return "", err + } + p, err = toLong(p) + if err != nil { + return "", err + } + // syscall.GetLongPathName does not change the case of the drive letter, + // but the result of EvalSymlinks must be unique, so we have + // EvalSymlinks(`c:\a`) == EvalSymlinks(`C:\a`). + // Make drive letter upper case. + if len(p) >= 2 && p[1] == ':' && 'a' <= p[0] && p[0] <= 'z' { + p = string(p[0]+'A'-'a') + p[1:] + } + return Clean(p), nil +} |