unix: fix Getdirentries emulation using Getdents on netbsd, openbsd

Call Seek if basep is not nil to read the current dir offset.
Return EIO error if the offset doesn't fit into a 32-bit uintptr.
Make Getdents public.

Update golang/go#32498

Change-Id: Idfbc48d3fc3a6cc8a979242681e8882d39998285
Reviewed-on: https://go-review.googlesource.com/c/sys/+/182319
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
diff --git a/unix/syscall_netbsd.go b/unix/syscall_netbsd.go
index 5240e16..8f4c320 100644
--- a/unix/syscall_netbsd.go
+++ b/unix/syscall_netbsd.go
@@ -120,9 +120,30 @@
 	return
 }
 
-//sys getdents(fd int, buf []byte) (n int, err error)
+//sys Getdents(fd int, buf []byte) (n int, err error)
 func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
-	return getdents(fd, buf)
+	n, err = Getdents(fd, buf)
+	if err != nil || basep == nil {
+		return
+	}
+
+	var off int64
+	off, err = Seek(fd, 0, 1 /* SEEK_CUR */)
+	if err != nil {
+		*basep = ^uintptr(0)
+		return
+	}
+	*basep = uintptr(off)
+	if unsafe.Sizeof(*basep) == 8 {
+		return
+	}
+	if off>>4 != 0 {
+		// We can't stuff the offset back into a uintptr, so any
+		// future calls would be suspect. Generate an error.
+		// EIO is allowed by getdirentries.
+		err = EIO
+	}
+	return
 }
 
 const ImplementsGetwd = true
diff --git a/unix/syscall_openbsd.go b/unix/syscall_openbsd.go
index c8648ec..276c93b 100644
--- a/unix/syscall_openbsd.go
+++ b/unix/syscall_openbsd.go
@@ -89,9 +89,30 @@
 	return
 }
 
-//sys getdents(fd int, buf []byte) (n int, err error)
+//sys Getdents(fd int, buf []byte) (n int, err error)
 func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
-	return getdents(fd, buf)
+	n, err = Getdents(fd, buf)
+	if err != nil || basep == nil {
+		return
+	}
+
+	var off int64
+	off, err = Seek(fd, 0, 1 /* SEEK_CUR */)
+	if err != nil {
+		*basep = ^uintptr(0)
+		return
+	}
+	*basep = uintptr(off)
+	if unsafe.Sizeof(*basep) == 8 {
+		return
+	}
+	if off>>4 != 0 {
+		// We can't stuff the offset back into a uintptr, so any
+		// future calls would be suspect. Generate an error.
+		// EIO was allowed by getdirentries.
+		err = EIO
+	}
+	return
 }
 
 const ImplementsGetwd = true
diff --git a/unix/zsyscall_netbsd_386.go b/unix/zsyscall_netbsd_386.go
index 642db76..7e05826 100644
--- a/unix/zsyscall_netbsd_386.go
+++ b/unix/zsyscall_netbsd_386.go
@@ -389,7 +389,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getdents(fd int, buf []byte) (n int, err error) {
+func Getdents(fd int, buf []byte) (n int, err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
diff --git a/unix/zsyscall_netbsd_amd64.go b/unix/zsyscall_netbsd_amd64.go
index 59585fe..d94d076 100644
--- a/unix/zsyscall_netbsd_amd64.go
+++ b/unix/zsyscall_netbsd_amd64.go
@@ -389,7 +389,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getdents(fd int, buf []byte) (n int, err error) {
+func Getdents(fd int, buf []byte) (n int, err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
diff --git a/unix/zsyscall_netbsd_arm.go b/unix/zsyscall_netbsd_arm.go
index 6ec3143..cf5bf3d 100644
--- a/unix/zsyscall_netbsd_arm.go
+++ b/unix/zsyscall_netbsd_arm.go
@@ -389,7 +389,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getdents(fd int, buf []byte) (n int, err error) {
+func Getdents(fd int, buf []byte) (n int, err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
diff --git a/unix/zsyscall_netbsd_arm64.go b/unix/zsyscall_netbsd_arm64.go
index 603d144..243a931 100644
--- a/unix/zsyscall_netbsd_arm64.go
+++ b/unix/zsyscall_netbsd_arm64.go
@@ -389,7 +389,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getdents(fd int, buf []byte) (n int, err error) {
+func Getdents(fd int, buf []byte) (n int, err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
diff --git a/unix/zsyscall_openbsd_386.go b/unix/zsyscall_openbsd_386.go
index 6a489fa..a9532d0 100644
--- a/unix/zsyscall_openbsd_386.go
+++ b/unix/zsyscall_openbsd_386.go
@@ -387,7 +387,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getdents(fd int, buf []byte) (n int, err error) {
+func Getdents(fd int, buf []byte) (n int, err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
diff --git a/unix/zsyscall_openbsd_amd64.go b/unix/zsyscall_openbsd_amd64.go
index 30cba43..0cb9f01 100644
--- a/unix/zsyscall_openbsd_amd64.go
+++ b/unix/zsyscall_openbsd_amd64.go
@@ -387,7 +387,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getdents(fd int, buf []byte) (n int, err error) {
+func Getdents(fd int, buf []byte) (n int, err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
diff --git a/unix/zsyscall_openbsd_arm.go b/unix/zsyscall_openbsd_arm.go
index fa1beda..6fc99b5 100644
--- a/unix/zsyscall_openbsd_arm.go
+++ b/unix/zsyscall_openbsd_arm.go
@@ -387,7 +387,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getdents(fd int, buf []byte) (n int, err error) {
+func Getdents(fd int, buf []byte) (n int, err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
diff --git a/unix/zsyscall_openbsd_arm64.go b/unix/zsyscall_openbsd_arm64.go
index eb58990..27878a7 100644
--- a/unix/zsyscall_openbsd_arm64.go
+++ b/unix/zsyscall_openbsd_arm64.go
@@ -387,7 +387,7 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getdents(fd int, buf []byte) (n int, err error) {
+func Getdents(fd int, buf []byte) (n int, err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])