unix: implement Fstat{,at} using Statx on linux/loong64

linux/loong64 doesn't provide the fstat and fstatat syscalls in the
upstream Linux kernel. Instead, solely the statx syscall is available.
Use it to implement Fstat and Fstatat.

This follows the implementation in package syscall.

Change-Id: I69eefc863a37bd76ef2ab1e7670d1724dc147aae
Reviewed-on: https://go-review.googlesource.com/c/sys/+/411378
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/unix/syscall_linux_loong64.go b/unix/syscall_linux_loong64.go
index 28ba7b8..0b69c3e 100644
--- a/unix/syscall_linux_loong64.go
+++ b/unix/syscall_linux_loong64.go
@@ -12,8 +12,6 @@
 //sys	EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
 //sys	Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
 //sys	Fchown(fd int, uid int, gid 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, buf *Statfs_t) (err error)
 //sys	Ftruncate(fd int, length int64) (err error)
 //sysnb	Getegid() (egid int)
@@ -43,6 +41,43 @@
 //sys	Shutdown(fd int, how int) (err error)
 //sys	Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
 
+func timespecFromStatxTimestamp(x StatxTimestamp) Timespec {
+	return Timespec{
+		Sec:  x.Sec,
+		Nsec: int64(x.Nsec),
+	}
+}
+
+func Fstatat(fd int, path string, stat *Stat_t, flags int) error {
+	var r Statx_t
+	// Do it the glibc way, add AT_NO_AUTOMOUNT.
+	if err := Statx(fd, path, AT_NO_AUTOMOUNT|flags, STATX_BASIC_STATS, &r); err != nil {
+		return err
+	}
+
+	stat.Dev = Mkdev(r.Dev_major, r.Dev_minor)
+	stat.Ino = r.Ino
+	stat.Mode = uint32(r.Mode)
+	stat.Nlink = r.Nlink
+	stat.Uid = r.Uid
+	stat.Gid = r.Gid
+	stat.Rdev = Mkdev(r.Rdev_major, r.Rdev_minor)
+	// hope we don't get to process files so large to overflow these size
+	// fields...
+	stat.Size = int64(r.Size)
+	stat.Blksize = int32(r.Blksize)
+	stat.Blocks = int64(r.Blocks)
+	stat.Atim = timespecFromStatxTimestamp(r.Atime)
+	stat.Mtim = timespecFromStatxTimestamp(r.Mtime)
+	stat.Ctim = timespecFromStatxTimestamp(r.Ctime)
+
+	return nil
+}
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+	return Fstatat(fd, "", stat, AT_EMPTY_PATH)
+}
+
 func Stat(path string, stat *Stat_t) (err error) {
 	return Fstatat(AT_FDCWD, path, stat, 0)
 }
diff --git a/unix/zsyscall_linux_loong64.go b/unix/zsyscall_linux_loong64.go
index 8cdfbe7..523f2ba 100644
--- a/unix/zsyscall_linux_loong64.go
+++ b/unix/zsyscall_linux_loong64.go
@@ -83,31 +83,6 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Fstat(fd int, stat *Stat_t) (err error) {
-	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// 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, buf *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0)
 	if e1 != 0 {