git: 6eefabd4ca40 - main - syscalls: improve nstat, nfstat, nlstat

From: Brooks Davis <brooks_at_FreeBSD.org>
Date: Mon, 22 Nov 2021 22:37:40 UTC
The branch main has been updated by brooks:

URL: https://cgit.FreeBSD.org/src/commit/?id=6eefabd4ca40348f0bc0ab829bceb3a308e577b7

commit 6eefabd4ca40348f0bc0ab829bceb3a308e577b7
Author:     Brooks Davis <brooks@FreeBSD.org>
AuthorDate: 2021-11-22 22:36:56 +0000
Commit:     Brooks Davis <brooks@FreeBSD.org>
CommitDate: 2021-11-22 22:36:56 +0000

    syscalls: improve nstat, nfstat, nlstat
    
    Optionally return errors when truncating dev_t, ino_t, and nlink_t.
    In the interest of code reuse, use freebsd11_cvtstat() to perform the
    truncation and error handling and then convert the resulting struct
    freebsd11_stat to struct nstat.
    
    Add missing freebsd32 compat syscalls. These syscalls require
    translation because struct nstat contains four instances of struct
    timespec which in turn contains a time_t and a long.
    
    Reviewed by:    kib
---
 sys/compat/freebsd32/freebsd32.h      | 25 ++++++++++
 sys/compat/freebsd32/freebsd32_misc.c | 87 +++++++++++++++++++++++++++++++++++
 sys/compat/freebsd32/syscalls.master  | 10 ++--
 sys/kern/kern_descrip.c               |  7 +--
 sys/kern/vfs_syscalls.c               | 56 +++++++++++++---------
 sys/sys/vnode.h                       |  2 +-
 6 files changed, 157 insertions(+), 30 deletions(-)

diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h
index e5bb253aef78..4d5cea688a21 100644
--- a/sys/compat/freebsd32/freebsd32.h
+++ b/sys/compat/freebsd32/freebsd32.h
@@ -167,6 +167,31 @@ struct ostatfs32 {
 	int32_t f_spare[2];
 };
 
+struct nstat32 {
+	__uint32_t st_dev;		/* inode's device */
+	__uint32_t st_ino;		/* inode's number */
+	__uint32_t st_mode;		/* inode protection mode */
+	__uint32_t st_nlink;		/* number of hard links */
+	uid_t	  st_uid;		/* user ID of the file's owner */
+	gid_t	  st_gid;		/* group ID of the file's group */
+	__uint32_t st_rdev;		/* device type */
+	struct	timespec32 st_atim;	/* time of last access */
+	struct	timespec32 st_mtim;	/* time of last data modification */
+	struct	timespec32 st_ctim;	/* time of last file status change */
+	off_t	  st_size;		/* file size, in bytes */
+	blkcnt_t st_blocks;		/* blocks allocated for file */
+	blksize_t st_blksize;		/* optimal blocksize for I/O */
+	fflags_t  st_flags;		/* user defined flags for file */
+	__uint32_t st_gen;		/* file generation number */
+	struct timespec32 st_birthtim;	/* time of file creation */
+	/*
+	 * See comment in the definition of struct freebsd11_stat
+	 * in sys/stat.h about the following padding.
+	 */
+	unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32));
+	unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec32));
+};
+
 struct iovec32 {
 	u_int32_t iov_base;
 	int	iov_len;
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index 69ae3a1cd85d..e81148d3577c 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -2473,6 +2473,93 @@ freebsd11_freebsd32_fhstat(struct thread *td,
 		error = copyout(&sb32, uap->sb, sizeof (sb32));
 	return (error);
 }
+
+static int
+freebsd11_cvtnstat32(struct stat *sb, struct nstat32 *nsb32)
+{
+	struct nstat nsb;
+	int error;
+
+	error = freebsd11_cvtnstat(sb, &nsb);
+	if (error != 0)
+		return (error);
+
+	bzero(nsb32, sizeof(*nsb32));
+	CP(nsb, *nsb32, st_dev);
+	CP(nsb, *nsb32, st_ino);
+	CP(nsb, *nsb32, st_mode);
+	CP(nsb, *nsb32, st_nlink);
+	CP(nsb, *nsb32, st_uid);
+	CP(nsb, *nsb32, st_gid);
+	CP(nsb, *nsb32, st_rdev);
+	CP(nsb, *nsb32, st_atim.tv_sec);
+	CP(nsb, *nsb32, st_atim.tv_nsec);
+	CP(nsb, *nsb32, st_mtim.tv_sec);
+	CP(nsb, *nsb32, st_mtim.tv_nsec);
+	CP(nsb, *nsb32, st_ctim.tv_sec);
+	CP(nsb, *nsb32, st_ctim.tv_nsec);
+	CP(nsb, *nsb32, st_size);
+	CP(nsb, *nsb32, st_blocks);
+	CP(nsb, *nsb32, st_blksize);
+	CP(nsb, *nsb32, st_flags);
+	CP(nsb, *nsb32, st_gen);
+	CP(nsb, *nsb32, st_birthtim.tv_sec);
+	CP(nsb, *nsb32, st_birthtim.tv_nsec);
+	return (0);
+}
+
+int
+freebsd11_freebsd32_nstat(struct thread *td,
+    struct freebsd11_freebsd32_nstat_args *uap)
+{
+	struct stat sb;
+	struct nstat32 nsb;
+	int error;
+
+	error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE,
+	    &sb, NULL);
+	if (error != 0)
+		return (error);
+	error = freebsd11_cvtnstat32(&sb, &nsb);
+	if (error != 0)
+		error = copyout(&nsb, uap->ub, sizeof (nsb));
+	return (error);
+}
+
+int
+freebsd11_freebsd32_nlstat(struct thread *td,
+    struct freebsd11_freebsd32_nlstat_args *uap)
+{
+	struct stat sb;
+	struct nstat32 nsb;
+	int error;
+
+	error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path,
+	    UIO_USERSPACE, &sb, NULL);
+	if (error != 0)
+		return (error);
+	error = freebsd11_cvtnstat32(&sb, &nsb);
+	if (error == 0)
+		error = copyout(&nsb, uap->ub, sizeof (nsb));
+	return (error);
+}
+
+int
+freebsd11_freebsd32_nfstat(struct thread *td,
+    struct freebsd11_freebsd32_nfstat_args *uap)
+{
+	struct nstat32 nub;
+	struct stat ub;
+	int error;
+
+	error = kern_fstat(td, uap->fd, &ub);
+	if (error != 0)
+		return (error);
+	error = freebsd11_cvtnstat32(&ub, &nub);
+	if (error == 0)
+		error = copyout(&nub, uap->sb, sizeof(nub));
+	return (error);
+}
 #endif
 
 int
diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master
index 2e11fdb03a17..4fd7b2235d99 100644
--- a/sys/compat/freebsd32/syscalls.master
+++ b/sys/compat/freebsd32/syscalls.master
@@ -525,11 +525,11 @@
 276	AUE_LUTIMES	STD	{ int freebsd32_lutimes(const char *path, \
 				    const struct timeval32 *tptr); }
 277	AUE_NULL	OBSOL	netbsd_msync
-278	AUE_STAT  COMPAT11|NOPROTO { int nstat(const char *path, \
-				    struct nstat *ub); }
-279	AUE_FSTAT COMPAT11|NOPROTO { int nfstat(int fd, struct nstat *sb); }
-280	AUE_LSTAT COMPAT11|NOPROTO { int nlstat(const char *path, \
-				    struct nstat *ub); }
+278	AUE_STAT  COMPAT11	{ int freebsd32_nstat(const char *path, \
+				    struct nstat32 *ub); }
+279	AUE_FSTAT COMPAT11	{ int freebsd32_nfstat(int fd, struct nstat32 *sb); }
+280	AUE_LSTAT COMPAT11	{ int freebsd32_nlstat(const char *path, \
+				    struct nstat32 *ub); }
 281	AUE_NULL	RESERVED
 282	AUE_NULL	RESERVED
 283	AUE_NULL	RESERVED
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 37d978e96de5..37fec097dcfc 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1561,10 +1561,11 @@ freebsd11_nfstat(struct thread *td, struct freebsd11_nfstat_args *uap)
 	int error;
 
 	error = kern_fstat(td, uap->fd, &ub);
-	if (error == 0) {
-		freebsd11_cvtnstat(&ub, &nub);
+	if (error != 0)
+		return (error);
+	error = freebsd11_cvtnstat(&ub, &nub);
+	if (error != 0)
 		error = copyout(&nub, uap->sb, sizeof(nub));
-	}
 	return (error);
 }
 #endif /* COMPAT_FREEBSD11 */
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 1cffe903aef3..4391853337bd 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -44,6 +44,9 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#ifdef COMPAT_FREEBSD11
+#include <sys/abi_compat.h>
+#endif
 #include <sys/bio.h>
 #include <sys/buf.h>
 #include <sys/capsicum.h>
@@ -2475,27 +2478,34 @@ kern_statat(struct thread *td, int flag, int fd, const char *path,
 /*
  * Implementation of the NetBSD [l]stat() functions.
  */
-void
+int
 freebsd11_cvtnstat(struct stat *sb, struct nstat *nsb)
 {
+	struct freebsd11_stat sb11;
+	int error;
+
+	error = freebsd11_cvtstat(sb, &sb11);
+	if (error != 0)
+		return (error);
 
 	bzero(nsb, sizeof(*nsb));
-	nsb->st_dev = sb->st_dev;
-	nsb->st_ino = sb->st_ino;
-	nsb->st_mode = sb->st_mode;
-	nsb->st_nlink = sb->st_nlink;
-	nsb->st_uid = sb->st_uid;
-	nsb->st_gid = sb->st_gid;
-	nsb->st_rdev = sb->st_rdev;
-	nsb->st_atim = sb->st_atim;
-	nsb->st_mtim = sb->st_mtim;
-	nsb->st_ctim = sb->st_ctim;
-	nsb->st_size = sb->st_size;
-	nsb->st_blocks = sb->st_blocks;
-	nsb->st_blksize = sb->st_blksize;
-	nsb->st_flags = sb->st_flags;
-	nsb->st_gen = sb->st_gen;
-	nsb->st_birthtim = sb->st_birthtim;
+	CP(sb11, *nsb, st_dev);
+	CP(sb11, *nsb, st_ino);
+	CP(sb11, *nsb, st_mode);
+	CP(sb11, *nsb, st_nlink);
+	CP(sb11, *nsb, st_uid);
+	CP(sb11, *nsb, st_gid);
+	CP(sb11, *nsb, st_rdev);
+	CP(sb11, *nsb, st_atim);
+	CP(sb11, *nsb, st_mtim);
+	CP(sb11, *nsb, st_ctim);
+	CP(sb11, *nsb, st_size);
+	CP(sb11, *nsb, st_blocks);
+	CP(sb11, *nsb, st_blksize);
+	CP(sb11, *nsb, st_flags);
+	CP(sb11, *nsb, st_gen);
+	CP(sb11, *nsb, st_birthtim);
+	return (0);
 }
 
 #ifndef _SYS_SYSPROTO_H_
@@ -2515,8 +2525,10 @@ freebsd11_nstat(struct thread *td, struct freebsd11_nstat_args *uap)
 	    &sb, NULL);
 	if (error != 0)
 		return (error);
-	freebsd11_cvtnstat(&sb, &nsb);
-	return (copyout(&nsb, uap->ub, sizeof (nsb)));
+	error = freebsd11_cvtnstat(&sb, &nsb);
+	if (error == 0)
+		error = copyout(&nsb, uap->ub, sizeof (nsb));
+	return (error);
 }
 
 /*
@@ -2539,8 +2551,10 @@ freebsd11_nlstat(struct thread *td, struct freebsd11_nlstat_args *uap)
 	    UIO_USERSPACE, &sb, NULL);
 	if (error != 0)
 		return (error);
-	freebsd11_cvtnstat(&sb, &nsb);
-	return (copyout(&nsb, uap->ub, sizeof (nsb)));
+	error = freebsd11_cvtnstat(&sb, &nsb);
+	if (error == 0)
+		error = copyout(&nsb, uap->ub, sizeof (nsb));
+	return (error);
 }
 #endif /* COMPAT_FREEBSD11 */
 
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 1a202abfd4dd..3d04b6f68784 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -682,7 +682,7 @@ cache_validate(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
 void	cache_fast_lookup_enabled_recalc(void);
 int	change_dir(struct vnode *vp, struct thread *td);
 void	cvtstat(struct stat *st, struct ostat *ost);
-void	freebsd11_cvtnstat(struct stat *sb, struct nstat *nsb);
+int	freebsd11_cvtnstat(struct stat *sb, struct nstat *nsb);
 int	freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost);
 int	getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops,
 	    struct vnode **vpp);