unix: add Fstatat on OpenBSD

Also enable TestFstatat for all Unices now that they all implement
Fstatat.

Change-Id: I9722437042d5fc0df4a27d3a6a2be3d124c60057
Reviewed-on: https://go-review.googlesource.com/100617
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/unix/syscall_linux_test.go b/unix/syscall_linux_test.go
index 8746fe8..423f004 100644
--- a/unix/syscall_linux_test.go
+++ b/unix/syscall_linux_test.go
@@ -7,7 +7,6 @@
 package unix_test
 
 import (
-	"io/ioutil"
 	"os"
 	"runtime"
 	"runtime/debug"
@@ -256,47 +255,6 @@
 	}
 }
 
-func TestFstatat(t *testing.T) {
-	defer chtmpdir(t)()
-
-	touch(t, "file1")
-
-	var st1 unix.Stat_t
-	err := unix.Stat("file1", &st1)
-	if err != nil {
-		t.Fatalf("Stat: %v", err)
-	}
-
-	var st2 unix.Stat_t
-	err = unix.Fstatat(unix.AT_FDCWD, "file1", &st2, 0)
-	if err != nil {
-		t.Fatalf("Fstatat: %v", err)
-	}
-
-	if st1 != st2 {
-		t.Errorf("Fstatat: returned stat does not match Stat")
-	}
-
-	err = os.Symlink("file1", "symlink1")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	err = unix.Lstat("symlink1", &st1)
-	if err != nil {
-		t.Fatalf("Lstat: %v", err)
-	}
-
-	err = unix.Fstatat(unix.AT_FDCWD, "symlink1", &st2, unix.AT_SYMLINK_NOFOLLOW)
-	if err != nil {
-		t.Fatalf("Fstatat: %v", err)
-	}
-
-	if st1 != st2 {
-		t.Errorf("Fstatat: returned stat does not match Lstat")
-	}
-}
-
 func TestSchedSetaffinity(t *testing.T) {
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
@@ -442,37 +400,3 @@
 		t.Errorf("Statx: returned stat mtime does not match Lstat")
 	}
 }
-
-// utilities taken from os/os_test.go
-
-func touch(t *testing.T, name string) {
-	f, err := os.Create(name)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err := f.Close(); err != nil {
-		t.Fatal(err)
-	}
-}
-
-// chtmpdir changes the working directory to a new temporary directory and
-// provides a cleanup function. Used when PWD is read-only.
-func chtmpdir(t *testing.T) func() {
-	oldwd, err := os.Getwd()
-	if err != nil {
-		t.Fatalf("chtmpdir: %v", err)
-	}
-	d, err := ioutil.TempDir("", "test")
-	if err != nil {
-		t.Fatalf("chtmpdir: %v", err)
-	}
-	if err := os.Chdir(d); err != nil {
-		t.Fatalf("chtmpdir: %v", err)
-	}
-	return func() {
-		if err := os.Chdir(oldwd); err != nil {
-			t.Fatalf("chtmpdir: %v", err)
-		}
-		os.RemoveAll(d)
-	}
-}
diff --git a/unix/syscall_openbsd.go b/unix/syscall_openbsd.go
index 37556e7..cef3d41 100644
--- a/unix/syscall_openbsd.go
+++ b/unix/syscall_openbsd.go
@@ -208,6 +208,7 @@
 //sys	Flock(fd int, how int) (err error)
 //sys	Fpathconf(fd int, name int) (val int, err error)
 //sys	Fstat(fd int, stat *Stat_t) (err error)
+//sys	Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
 //sys	Fstatfs(fd int, stat *Statfs_t) (err error)
 //sys	Fsync(fd int) (err error)
 //sys	Ftruncate(fd int, length int64) (err error)
diff --git a/unix/syscall_unix_test.go b/unix/syscall_unix_test.go
index 496e471..c337887 100644
--- a/unix/syscall_unix_test.go
+++ b/unix/syscall_unix_test.go
@@ -426,6 +426,47 @@
 	}
 }
 
+func TestFstatat(t *testing.T) {
+	defer chtmpdir(t)()
+
+	touch(t, "file1")
+
+	var st1 unix.Stat_t
+	err := unix.Stat("file1", &st1)
+	if err != nil {
+		t.Fatalf("Stat: %v", err)
+	}
+
+	var st2 unix.Stat_t
+	err = unix.Fstatat(unix.AT_FDCWD, "file1", &st2, 0)
+	if err != nil {
+		t.Fatalf("Fstatat: %v", err)
+	}
+
+	if st1 != st2 {
+		t.Errorf("Fstatat: returned stat does not match Stat")
+	}
+
+	err = os.Symlink("file1", "symlink1")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = unix.Lstat("symlink1", &st1)
+	if err != nil {
+		t.Fatalf("Lstat: %v", err)
+	}
+
+	err = unix.Fstatat(unix.AT_FDCWD, "symlink1", &st2, unix.AT_SYMLINK_NOFOLLOW)
+	if err != nil {
+		t.Fatalf("Fstatat: %v", err)
+	}
+
+	if st1 != st2 {
+		t.Errorf("Fstatat: returned stat does not match Lstat")
+	}
+}
+
 // mktmpfifo creates a temporary FIFO and provides a cleanup function.
 func mktmpfifo(t *testing.T) (*os.File, func()) {
 	err := unix.Mkfifo("fifo", 0666)
@@ -444,3 +485,37 @@
 		os.Remove("fifo")
 	}
 }
+
+// utilities taken from os/os_test.go
+
+func touch(t *testing.T, name string) {
+	f, err := os.Create(name)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := f.Close(); err != nil {
+		t.Fatal(err)
+	}
+}
+
+// chtmpdir changes the working directory to a new temporary directory and
+// provides a cleanup function. Used when PWD is read-only.
+func chtmpdir(t *testing.T) func() {
+	oldwd, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("chtmpdir: %v", err)
+	}
+	d, err := ioutil.TempDir("", "test")
+	if err != nil {
+		t.Fatalf("chtmpdir: %v", err)
+	}
+	if err := os.Chdir(d); err != nil {
+		t.Fatalf("chtmpdir: %v", err)
+	}
+	return func() {
+		if err := os.Chdir(oldwd); err != nil {
+			t.Fatalf("chtmpdir: %v", err)
+		}
+		os.RemoveAll(d)
+	}
+}
diff --git a/unix/zsyscall_openbsd_386.go b/unix/zsyscall_openbsd_386.go
index 003f820..91e38bd 100644
--- a/unix/zsyscall_openbsd_386.go
+++ b/unix/zsyscall_openbsd_386.go
@@ -640,6 +640,21 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
diff --git a/unix/zsyscall_openbsd_amd64.go b/unix/zsyscall_openbsd_amd64.go
index ba0e8f3..eebf200 100644
--- a/unix/zsyscall_openbsd_amd64.go
+++ b/unix/zsyscall_openbsd_amd64.go
@@ -640,6 +640,21 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
diff --git a/unix/zsyscall_openbsd_arm.go b/unix/zsyscall_openbsd_arm.go
index 2ce02c7..6a7fe67 100644
--- a/unix/zsyscall_openbsd_arm.go
+++ b/unix/zsyscall_openbsd_arm.go
@@ -640,6 +640,21 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {