}
func TestFileChdir(t *testing.T) {
- // TODO(brainman): file.Chdir() is not implemented on windows.
- if runtime.GOOS == "windows" {
- return
- }
-
wd, err := Getwd()
if err != nil {
t.Fatalf("Getwd: %s", err)
if err != nil {
t.Fatalf("Getwd: %s", err)
}
- if wdNew != wd {
+ if !equal(wdNew, wd) {
t.Fatalf("fd.Chdir failed, got %s, want %s", wdNew, wd)
}
}
func TestChdirAndGetwd(t *testing.T) {
- // TODO(brainman): file.Chdir() is not implemented on windows.
- if runtime.GOOS == "windows" {
- return
- }
fd, err := Open(".")
if err != nil {
t.Fatalf("Open .: %s", err)
dirs = []string{"/system/bin"}
case "plan9":
dirs = []string{"/", "/usr"}
- case "ios":
+ case "ios", "windows":
dirs = nil
- for _, d := range []string{"d1", "d2"} {
- dir, err := MkdirTemp("", d)
- if err != nil {
- t.Fatalf("TempDir: %v", err)
- }
+ for _, dir := range []string{t.TempDir(), t.TempDir()} {
// Expand symlinks so path equality tests work.
dir, err = filepath.EvalSymlinks(dir)
if err != nil {
fd.Close()
t.Fatalf("Getwd in %s: %s", d, err1)
}
- if pwd != d {
+ if !equal(pwd, d) {
fd.Close()
t.Fatalf("Getwd returned %q want %q", pwd, d)
}
}
const (
+ _ERROR_NOT_ENOUGH_MEMORY = Errno(8)
_ERROR_NOT_SUPPORTED = Errno(50)
_ERROR_BAD_NETPATH = Errno(53)
_ERROR_CALL_NOT_IMPLEMENTED = Errno(120)
//sys initializeProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, attrcount uint32, flags uint32, size *uintptr) (err error) = InitializeProcThreadAttributeList
//sys deleteProcThreadAttributeList(attrlist *_PROC_THREAD_ATTRIBUTE_LIST) = DeleteProcThreadAttributeList
//sys updateProcThreadAttribute(attrlist *_PROC_THREAD_ATTRIBUTE_LIST, flags uint32, attr uintptr, value unsafe.Pointer, size uintptr, prevvalue unsafe.Pointer, returnedsize *uintptr) (err error) = UpdateProcThreadAttribute
+//sys getFinalPathNameByHandle(file Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) [n == 0 || n >= filePathSize] = kernel32.GetFinalPathNameByHandleW
// syscall interface implementation for other packages
return int(pe.ParentProcessID)
}
+func fdpath(fd Handle, buf []uint16) ([]uint16, error) {
+ const (
+ FILE_NAME_NORMALIZED = 0
+ VOLUME_NAME_DOS = 0
+ )
+ for {
+ n, err := getFinalPathNameByHandle(fd, &buf[0], uint32(len(buf)), FILE_NAME_NORMALIZED|VOLUME_NAME_DOS)
+ if err == nil {
+ buf = buf[:n]
+ break
+ }
+ if err != _ERROR_NOT_ENOUGH_MEMORY {
+ return nil, err
+ }
+ buf = append(buf, make([]uint16, n-uint32(len(buf)))...)
+ }
+ return buf, nil
+}
+
+func Fchdir(fd Handle) (err error) {
+ var buf [MAX_PATH + 1]uint16
+ path, err := fdpath(fd, buf[:])
+ if err != nil {
+ return err
+ }
+ // When using VOLUME_NAME_DOS, the path is always pefixed by "\\?\".
+ // That prefix tells the Windows APIs to disable all string parsing and to send
+ // the string that follows it straight to the file system.
+ // Although SetCurrentDirectory and GetCurrentDirectory do support the "\\?\" prefix,
+ // some other Windows APIs don't. If the prefix is not removed here, it will leak
+ // to Getwd, and we don't want such a general-purpose function to always return a
+ // path with the "\\?\" prefix after Fchdir is called.
+ // The downside is that APIs that do support it will parse the path and try to normalize it,
+ // when it's already normalized.
+ if len(path) >= 4 && path[0] == '\\' && path[1] == '\\' && path[2] == '?' && path[3] == '\\' {
+ path = path[4:]
+ }
+ return SetCurrentDirectory(&path[0])
+}
+
// TODO(brainman): fix all needed for os
-func Fchdir(fd Handle) (err error) { return EWINDOWS }
func Link(oldpath, newpath string) (err error) { return EWINDOWS }
func Symlink(path, link string) (err error) { return EWINDOWS }
procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW")
procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle")
procGetFileType = modkernel32.NewProc("GetFileType")
+ procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW")
procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
procGetLastError = modkernel32.NewProc("GetLastError")
procGetLongPathNameW = modkernel32.NewProc("GetLongPathNameW")
return
}
+func getFinalPathNameByHandle(file Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) {
+ r0, _, e1 := Syscall6(procGetFinalPathNameByHandleW.Addr(), 4, uintptr(file), uintptr(unsafe.Pointer(filePath)), uintptr(filePathSize), uintptr(flags), 0, 0)
+ n = uint32(r0)
+ if n == 0 || n >= filePathSize {
+ err = errnoErr(e1)
+ }
+ return
+}
+
func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) {
r0, _, e1 := Syscall6(procGetFullPathNameW.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(buflen), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(fname)), 0, 0)
n = uint32(r0)