Przeglądaj źródła

unix: add Getcwd to support Getwd on all BSDs

All BSDs provide the SYS___GETCWD syscall which can be used to implement
Getwd.

Also add a test based on TestChdirAndGetwd from os/os_test.go

Change-Id: I243eae3e02a40e92afad317eb1f8a28b6032c131
Reviewed-on: https://go-review.googlesource.com/83755
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Tobias Klauser 8 lat temu
rodzic
commit
1d2aa6dbde

+ 17 - 0
unix/syscall_dragonfly.go

@@ -110,6 +110,23 @@ func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
 	return
 }
 
+const ImplementsGetwd = true
+
+//sys	Getcwd(buf []byte) (n int, err error) = SYS___GETCWD
+
+func Getwd() (string, error) {
+	var buf [PathMax]byte
+	_, err := Getcwd(buf[0:])
+	if err != nil {
+		return "", err
+	}
+	n := clen(buf[:])
+	if n < 1 {
+		return "", EINVAL
+	}
+	return string(buf[:n]), nil
+}
+
 func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
 	var _p0 unsafe.Pointer
 	var bufsize uintptr

+ 17 - 0
unix/syscall_freebsd.go

@@ -105,6 +105,23 @@ func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
 	return
 }
 
+const ImplementsGetwd = true
+
+//sys	Getcwd(buf []byte) (n int, err error) = SYS___GETCWD
+
+func Getwd() (string, error) {
+	var buf [PathMax]byte
+	_, err := Getcwd(buf[0:])
+	if err != nil {
+		return "", err
+	}
+	n := clen(buf[:])
+	if n < 1 {
+		return "", EINVAL
+	}
+	return string(buf[:n]), nil
+}
+
 func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
 	var _p0 unsafe.Pointer
 	var bufsize uintptr

+ 17 - 0
unix/syscall_netbsd.go

@@ -118,6 +118,23 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	return getdents(fd, buf)
 }
 
+const ImplementsGetwd = true
+
+//sys	Getcwd(buf []byte) (n int, err error) = SYS___GETCWD
+
+func Getwd() (string, error) {
+	var buf [PathMax]byte
+	_, err := Getcwd(buf[0:])
+	if err != nil {
+		return "", err
+	}
+	n := clen(buf[:])
+	if n < 1 {
+		return "", EINVAL
+	}
+	return string(buf[:n]), nil
+}
+
 // TODO
 func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
 	return -1, ENOSYS

+ 0 - 11
unix/syscall_no_getwd.go

@@ -1,11 +0,0 @@
-// Copyright 2013 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 dragonfly freebsd netbsd openbsd
-
-package unix
-
-const ImplementsGetwd = false
-
-func Getwd() (string, error) { return "", ENOTSUP }

+ 17 - 0
unix/syscall_openbsd.go

@@ -71,6 +71,23 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	return getdents(fd, buf)
 }
 
+const ImplementsGetwd = true
+
+//sys	Getcwd(buf []byte) (n int, err error) = SYS___GETCWD
+
+func Getwd() (string, error) {
+	var buf [PathMax]byte
+	_, err := Getcwd(buf[0:])
+	if err != nil {
+		return "", err
+	}
+	n := clen(buf[:])
+	if n < 1 {
+		return "", EINVAL
+	}
+	return string(buf[:n]), nil
+}
+
 // TODO
 func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
 	return -1, ENOSYS

+ 0 - 9
unix/syscall_solaris.go

@@ -34,15 +34,6 @@ type SockaddrDatalink struct {
 	raw    RawSockaddrDatalink
 }
 
-func clen(n []byte) int {
-	for i := 0; i < len(n); i++ {
-		if n[i] == 0 {
-			return i
-		}
-	}
-	return len(n)
-}
-
 func direntIno(buf []byte) (uint64, bool) {
 	return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
 }

+ 11 - 0
unix/syscall_unix.go

@@ -50,6 +50,17 @@ func errnoErr(e syscall.Errno) error {
 	return e
 }
 
+// clen returns the index of the first NULL byte in n or len(n) if n contains no
+// NULL byte or len(n) if n contains no NULL byte
+func clen(n []byte) int {
+	for i := 0; i < len(n); i++ {
+		if n[i] == 0 {
+			return i
+		}
+	}
+	return len(n)
+}
+
 // Mmap manager, for use by operating system-specific implementations.
 
 type mmapper struct {

+ 54 - 0
unix/syscall_unix_test.go

@@ -378,6 +378,60 @@ func TestPoll(t *testing.T) {
 	}
 }
 
+func TestGetwd(t *testing.T) {
+	fd, err := os.Open(".")
+	if err != nil {
+		t.Fatalf("Open .: %s", err)
+	}
+	// These are chosen carefully not to be symlinks on a Mac
+	// (unlike, say, /var, /etc)
+	dirs := []string{"/", "/usr/bin"}
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			d1, err := ioutil.TempDir("", "d1")
+			if err != nil {
+				t.Fatalf("TempDir: %v", err)
+			}
+			d2, err := ioutil.TempDir("", "d2")
+			if err != nil {
+				t.Fatalf("TempDir: %v", err)
+			}
+			dirs = []string{d1, d2}
+		}
+	}
+	oldwd := os.Getenv("PWD")
+	for _, d := range dirs {
+		err = os.Chdir(d)
+		if err != nil {
+			t.Fatalf("Chdir: %v", err)
+		}
+		pwd, err1 := unix.Getwd()
+		os.Setenv("PWD", oldwd)
+		err2 := fd.Chdir()
+		if err2 != nil {
+			// We changed the current directory and cannot go back.
+			// Don't let the tests continue; they'll scribble
+			// all over some other directory.
+			fmt.Fprintf(os.Stderr, "fchdir back to dot failed: %s\n", err2)
+			os.Exit(1)
+		}
+		if err != nil {
+			fd.Close()
+			t.Fatalf("Chdir %s: %s", d, err)
+		}
+		if err1 != nil {
+			fd.Close()
+			t.Fatalf("Getwd in %s: %s", d, err1)
+		}
+		if pwd != d {
+			fd.Close()
+			t.Fatalf("Getwd returned %q want %q", pwd, d)
+		}
+	}
+	fd.Close()
+}
+
 // mktmpfifo creates a temporary FIFO and provides a cleanup function.
 func mktmpfifo(t *testing.T) (*os.File, func()) {
 	err := unix.Mkfifo("fifo", 0666)

+ 6 - 0
unix/types_dragonfly.go

@@ -127,6 +127,12 @@ type Dirent C.struct_dirent
 
 type Fsid C.struct_fsid
 
+// File system limits
+
+const (
+	PathMax = C.PATH_MAX
+)
+
 // Sockets
 
 type RawSockaddrInet4 C.struct_sockaddr_in

+ 6 - 0
unix/types_freebsd.go

@@ -216,6 +216,12 @@ type Dirent C.struct_dirent
 
 type Fsid C.struct_fsid
 
+// File system limits
+
+const (
+	PathMax = C.PATH_MAX
+)
+
 // Advice to Fadvise
 
 const (

+ 6 - 0
unix/types_netbsd.go

@@ -112,6 +112,12 @@ type Dirent C.struct_dirent
 
 type Fsid C.fsid_t
 
+// File system limits
+
+const (
+	PathMax = C.PATH_MAX
+)
+
 // Sockets
 
 type RawSockaddrInet4 C.struct_sockaddr_in

+ 6 - 0
unix/types_openbsd.go

@@ -128,6 +128,12 @@ type Dirent C.struct_dirent
 
 type Fsid C.fsid_t
 
+// File system limits
+
+const (
+	PathMax = C.PATH_MAX
+)
+
 // Sockets
 
 type RawSockaddrInet4 C.struct_sockaddr_in

+ 17 - 0
unix/zsyscall_dragonfly_amd64.go

@@ -423,6 +423,23 @@ func extpwrite(fd int, p []byte, flags int, offset int64) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Getcwd(buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func ioctl(fd int, req uint, arg uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
 	if e1 != 0 {

+ 17 - 0
unix/zsyscall_freebsd_386.go

@@ -389,6 +389,23 @@ func pipe() (r int, w int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Getcwd(buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func ioctl(fd int, req uint, arg uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
 	if e1 != 0 {

+ 17 - 0
unix/zsyscall_freebsd_amd64.go

@@ -389,6 +389,23 @@ func pipe() (r int, w int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Getcwd(buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func ioctl(fd int, req uint, arg uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
 	if e1 != 0 {

+ 17 - 0
unix/zsyscall_freebsd_arm.go

@@ -389,6 +389,23 @@ func pipe() (r int, w int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Getcwd(buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func ioctl(fd int, req uint, arg uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
 	if e1 != 0 {

+ 17 - 0
unix/zsyscall_netbsd_386.go

@@ -406,6 +406,23 @@ func getdents(fd int, buf []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Getcwd(buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func ioctl(fd int, req uint, arg uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
 	if e1 != 0 {

+ 17 - 0
unix/zsyscall_netbsd_amd64.go

@@ -406,6 +406,23 @@ func getdents(fd int, buf []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Getcwd(buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func ioctl(fd int, req uint, arg uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
 	if e1 != 0 {

+ 17 - 0
unix/zsyscall_netbsd_arm.go

@@ -406,6 +406,23 @@ func getdents(fd int, buf []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Getcwd(buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func ioctl(fd int, req uint, arg uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
 	if e1 != 0 {

+ 17 - 0
unix/zsyscall_openbsd_386.go

@@ -404,6 +404,23 @@ func getdents(fd int, buf []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Getcwd(buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func ioctl(fd int, req uint, arg uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
 	if e1 != 0 {

+ 17 - 0
unix/zsyscall_openbsd_amd64.go

@@ -404,6 +404,23 @@ func getdents(fd int, buf []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Getcwd(buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func ioctl(fd int, req uint, arg uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
 	if e1 != 0 {

+ 17 - 0
unix/zsyscall_openbsd_arm.go

@@ -404,6 +404,23 @@ func getdents(fd int, buf []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Getcwd(buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS___GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func ioctl(fd int, req uint, arg uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
 	if e1 != 0 {

+ 4 - 0
unix/ztypes_dragonfly_amd64.go

@@ -143,6 +143,10 @@ type Fsid struct {
 	Val [2]int32
 }
 
+const (
+	PathMax = 0x400
+)
+
 type RawSockaddrInet4 struct {
 	Len    uint8
 	Family uint8

+ 4 - 0
unix/ztypes_freebsd_386.go

@@ -140,6 +140,10 @@ type Fsid struct {
 	Val [2]int32
 }
 
+const (
+	PathMax = 0x400
+)
+
 const (
 	FADV_NORMAL     = 0x0
 	FADV_RANDOM     = 0x1

+ 4 - 0
unix/ztypes_freebsd_amd64.go

@@ -140,6 +140,10 @@ type Fsid struct {
 	Val [2]int32
 }
 
+const (
+	PathMax = 0x400
+)
+
 const (
 	FADV_NORMAL     = 0x0
 	FADV_RANDOM     = 0x1

+ 4 - 0
unix/ztypes_freebsd_arm.go

@@ -142,6 +142,10 @@ type Fsid struct {
 	Val [2]int32
 }
 
+const (
+	PathMax = 0x400
+)
+
 const (
 	FADV_NORMAL     = 0x0
 	FADV_RANDOM     = 0x1

+ 4 - 0
unix/ztypes_netbsd_386.go

@@ -99,6 +99,10 @@ type Fsid struct {
 	X__fsid_val [2]int32
 }
 
+const (
+	PathMax = 0x400
+)
+
 type RawSockaddrInet4 struct {
 	Len    uint8
 	Family uint8

+ 4 - 0
unix/ztypes_netbsd_amd64.go

@@ -103,6 +103,10 @@ type Fsid struct {
 	X__fsid_val [2]int32
 }
 
+const (
+	PathMax = 0x400
+)
+
 type RawSockaddrInet4 struct {
 	Len    uint8
 	Family uint8

+ 4 - 0
unix/ztypes_netbsd_arm.go

@@ -104,6 +104,10 @@ type Fsid struct {
 	X__fsid_val [2]int32
 }
 
+const (
+	PathMax = 0x400
+)
+
 type RawSockaddrInet4 struct {
 	Len    uint8
 	Family uint8

+ 4 - 0
unix/ztypes_openbsd_386.go

@@ -140,6 +140,10 @@ type Fsid struct {
 	Val [2]int32
 }
 
+const (
+	PathMax = 0x400
+)
+
 type RawSockaddrInet4 struct {
 	Len    uint8
 	Family uint8

+ 4 - 0
unix/ztypes_openbsd_amd64.go

@@ -142,6 +142,10 @@ type Fsid struct {
 	Val [2]int32
 }
 
+const (
+	PathMax = 0x400
+)
+
 type RawSockaddrInet4 struct {
 	Len    uint8
 	Family uint8

+ 4 - 0
unix/ztypes_openbsd_arm.go

@@ -140,6 +140,10 @@ type Fsid struct {
 	Val [2]int32
 }
 
+const (
+	PathMax = 0x400
+)
+
 type RawSockaddrInet4 struct {
 	Len    uint8
 	Family uint8