]> Cypherpunks repositories - gostls13.git/commitdiff
path/filepath: retrieve real file name in windows EvalSymlinks
authorAlex Brainman <alex.brainman@gmail.com>
Wed, 7 Mar 2012 23:00:25 +0000 (10:00 +1100)
committerAlex Brainman <alex.brainman@gmail.com>
Wed, 7 Mar 2012 23:00:25 +0000 (10:00 +1100)
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5756049

src/pkg/go/build/deps_test.go
src/pkg/path/filepath/path.go
src/pkg/path/filepath/path_test.go
src/pkg/path/filepath/symlink.go [new file with mode: 0644]
src/pkg/path/filepath/symlink_windows.go [new file with mode: 0644]
src/pkg/syscall/syscall_windows.go
src/pkg/syscall/zsyscall_windows_386.go
src/pkg/syscall/zsyscall_windows_amd64.go

index 13b9dc97bbfecff4692616cd8494428d7234c89c..4e9f32a036ff15aa9749d6b214ac6105c191a6b6 100644 (file)
@@ -120,7 +120,7 @@ var pkgDeps = map[string][]string{
        "syscall":       {"L0", "unicode/utf16"},
        "time":          {"L0", "syscall"},
        "os":            {"L1", "os", "syscall", "time"},
-       "path/filepath": {"L2", "os"},
+       "path/filepath": {"L2", "os", "syscall"},
        "io/ioutil":     {"L2", "os", "path/filepath", "time"},
        "os/exec":       {"L2", "os", "syscall"},
        "os/signal":     {"L2", "os", "syscall"},
index cfe46981f131255bd5d8f9f347772d385e2a533e..1e7487263674f3aca703f7f0272c282cdd4727e9 100644 (file)
@@ -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.
index ad053177f5376f40bbf75e41cc6c09b6b4648101..71969cdf95ff36a29dbde6e565ed9f3fe48b29df 100644 (file)
@@ -621,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 {
diff --git a/src/pkg/path/filepath/symlink.go b/src/pkg/path/filepath/symlink.go
new file mode 100644 (file)
index 0000000..307dd0f
--- /dev/null
@@ -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/src/pkg/path/filepath/symlink_windows.go b/src/pkg/path/filepath/symlink_windows.go
new file mode 100644 (file)
index 0000000..afa88bf
--- /dev/null
@@ -0,0 +1,27 @@
+// 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 evalSymlinks(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 Clean(syscall.UTF16ToString(b)), nil
+}
index 6ac98ceacb088e19f0a1ab95414ee2e7f8778804..b0c24cca698cf9ef687bc7ab0a84f98a6ca6e93e 100644 (file)
@@ -174,6 +174,7 @@ func NewCallback(fn interface{}) uintptr
 //sys  SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error)
 //sys  FlushFileBuffers(handle Handle) (err error)
 //sys  GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) = kernel32.GetFullPathNameW
+//sys  GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) = kernel32.GetLongPathNameW
 //sys  CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) = kernel32.CreateFileMappingW
 //sys  MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error)
 //sys  UnmapViewOfFile(addr uintptr) (err error)
index ac3da3f61e8d702bcbbbd3742e30fa5b541255a9..093c4768f2f0795ed9906aaba526b32942b7db4a 100644 (file)
@@ -78,6 +78,7 @@ var (
        procSetHandleInformation             = modkernel32.NewProc("SetHandleInformation")
        procFlushFileBuffers                 = modkernel32.NewProc("FlushFileBuffers")
        procGetFullPathNameW                 = modkernel32.NewProc("GetFullPathNameW")
+       procGetLongPathNameW                 = modkernel32.NewProc("GetLongPathNameW")
        procCreateFileMappingW               = modkernel32.NewProc("CreateFileMappingW")
        procMapViewOfFile                    = modkernel32.NewProc("MapViewOfFile")
        procUnmapViewOfFile                  = modkernel32.NewProc("UnmapViewOfFile")
@@ -890,6 +891,19 @@ func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (
        return
 }
 
+func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) {
+       r0, _, e1 := Syscall(procGetLongPathNameW.Addr(), 3, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(buf)), uintptr(buflen))
+       n = uint32(r0)
+       if n == 0 {
+               if e1 != 0 {
+                       err = error(e1)
+               } else {
+                       err = EINVAL
+               }
+       }
+       return
+}
+
 func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) {
        r0, _, e1 := Syscall6(procCreateFileMappingW.Addr(), 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name)))
        handle = Handle(r0)
index 1ffa1c7ff9ea4b6534e2fbd531884df68b361d68..d298b7451fd5629f2041c1749998a5f4bf48ca7c 100644 (file)
@@ -78,6 +78,7 @@ var (
        procSetHandleInformation             = modkernel32.NewProc("SetHandleInformation")
        procFlushFileBuffers                 = modkernel32.NewProc("FlushFileBuffers")
        procGetFullPathNameW                 = modkernel32.NewProc("GetFullPathNameW")
+       procGetLongPathNameW                 = modkernel32.NewProc("GetLongPathNameW")
        procCreateFileMappingW               = modkernel32.NewProc("CreateFileMappingW")
        procMapViewOfFile                    = modkernel32.NewProc("MapViewOfFile")
        procUnmapViewOfFile                  = modkernel32.NewProc("UnmapViewOfFile")
@@ -890,6 +891,19 @@ func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (
        return
 }
 
+func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) {
+       r0, _, e1 := Syscall(procGetLongPathNameW.Addr(), 3, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(buf)), uintptr(buflen))
+       n = uint32(r0)
+       if n == 0 {
+               if e1 != 0 {
+                       err = error(e1)
+               } else {
+                       err = EINVAL
+               }
+       }
+       return
+}
+
 func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) {
        r0, _, e1 := Syscall6(procCreateFileMappingW.Addr(), 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name)))
        handle = Handle(r0)