summaryrefslogtreecommitdiff
path: root/libgo/go/path
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/path')
-rw-r--r--libgo/go/path/filepath/match.go24
-rw-r--r--libgo/go/path/filepath/match_test.go38
-rw-r--r--libgo/go/path/filepath/path.go61
-rw-r--r--libgo/go/path/filepath/path_test.go103
-rw-r--r--libgo/go/path/filepath/path_windows.go4
-rw-r--r--libgo/go/path/filepath/symlink.go67
-rw-r--r--libgo/go/path/filepath/symlink_windows.go63
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
+}