diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -2285,7 +2285,7 @@ int error; error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, - &sb, NULL); + &sb); if (error) return (error); copy_ostat(&sb, &sb32); @@ -2334,7 +2334,7 @@ int error; error = kern_statat(td, uap->flag, uap->fd, uap->path, UIO_USERSPACE, - &ub, NULL); + &ub); if (error) return (error); copy_stat(&ub, &ub32); @@ -2351,7 +2351,7 @@ int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error) return (error); copy_ostat(&sb, &sb32); @@ -2470,7 +2470,7 @@ int error; error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, - &sb, NULL); + &sb); if (error != 0) return (error); error = freebsd11_cvtstat32(&sb, &sb32); @@ -2505,7 +2505,7 @@ int error; error = kern_statat(td, uap->flag, uap->fd, uap->path, UIO_USERSPACE, - &sb, NULL); + &sb); if (error != 0) return (error); error = freebsd11_cvtstat32(&sb, &sb32); @@ -2523,7 +2523,7 @@ int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error != 0) return (error); error = freebsd11_cvtstat32(&sb, &sb32); @@ -2596,7 +2596,7 @@ int error; error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, - &sb, NULL); + &sb); if (error != 0) return (error); error = freebsd11_cvtnstat32(&sb, &nsb); @@ -2614,7 +2614,7 @@ int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error != 0) return (error); error = freebsd11_cvtnstat32(&sb, &nsb); diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -667,7 +667,7 @@ if (error == EPERM) { /* Introduce POSIX noncompliant behaviour of Linux */ if (kern_statat(td, 0, AT_FDCWD, args->path, - UIO_USERSPACE, &st, NULL) == 0) { + UIO_USERSPACE, &st) == 0) { if (S_ISDIR(st.st_mode)) error = EISDIR; } @@ -691,7 +691,7 @@ if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) { /* Introduce POSIX noncompliant behaviour of Linux */ if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path, - pathseg, &st, NULL) == 0 && S_ISDIR(st.st_mode)) + pathseg, &st) == 0 && S_ISDIR(st.st_mode)) error = EISDIR; } return (error); diff --git a/sys/compat/linux/linux_stats.c b/sys/compat/linux/linux_stats.c --- a/sys/compat/linux/linux_stats.c +++ b/sys/compat/linux/linux_stats.c @@ -29,17 +29,23 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_ktrace.h" + #include #include #include #include #include #include +#include #include #include #include #include #include +#ifdef KTRACE +#include +#endif #ifdef COMPAT_LINUX32 #include @@ -57,9 +63,33 @@ linux_kern_statat(struct thread *td, int flag, int fd, const char *path, enum uio_seg pathseg, struct stat *sbp) { + struct nameidata nd; + int error; + + if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH | + AT_EMPTY_PATH)) != 0) + return (EINVAL); + + NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_RESOLVE_BENEATH | + AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH) | LOCKSHARED | LOCKLEAF | + AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights); - return (kern_statat(td, flag, fd, path, pathseg, sbp, - translate_vnhook_major_minor)); + if ((error = namei(&nd)) != 0) { + if (error == ENOTDIR && + (nd.ni_resflags & NIRES_EMPTYPATH) != 0) + error = kern_fstat(td, fd, sbp); + return (error); + } + error = VOP_STAT(nd.ni_vp, sbp, td->td_ucred, NOCRED); + if (error == 0) + translate_vnhook_major_minor(nd.ni_vp, sbp); + NDFREE_PNBUF(&nd); + vput(nd.ni_vp); +#ifdef KTRACE + if (KTRPOINT(td, KTR_STRUCT)) + ktrstat_error(sbp, error); +#endif + return (error); } #ifdef LINUX_LEGACY_SYSCALLS diff --git a/sys/kern/vfs_mountroot.c b/sys/kern/vfs_mountroot.c --- a/sys/kern/vfs_mountroot.c +++ b/sys/kern/vfs_mountroot.c @@ -594,7 +594,7 @@ free(tok, M_TEMP); /* Get file status. */ - error = kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &sb, NULL); + error = kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &sb); if (error) goto out; diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -110,7 +110,7 @@ static int kern_linkat_vp(struct thread *td, struct vnode *vp, int fd, const char *path, enum uio_seg segflag); -static uint64_t +uint64_t at2cnpflags(u_int at_flags, u_int mask) { uint64_t res; @@ -2194,7 +2194,7 @@ int error; error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, - &sb, NULL); + &sb); if (error != 0) return (error); cvtstat(&sb, &osb); @@ -2218,7 +2218,7 @@ int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error != 0) return (error); cvtstat(&sb, &osb); @@ -2337,7 +2337,7 @@ int error; error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, - &sb, NULL); + &sb); if (error != 0) return (error); error = freebsd11_cvtstat(&sb, &osb); @@ -2354,7 +2354,7 @@ int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error != 0) return (error); error = freebsd11_cvtstat(&sb, &osb); @@ -2391,7 +2391,7 @@ int error; error = kern_statat(td, uap->flag, uap->fd, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error != 0) return (error); error = freebsd11_cvtstat(&sb, &osb); @@ -2419,7 +2419,7 @@ int error; error = kern_statat(td, uap->flag, uap->fd, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error == 0) error = copyout(&sb, uap->buf, sizeof (sb)); return (error); @@ -2427,8 +2427,7 @@ int kern_statat(struct thread *td, int flag, int fd, const char *path, - enum uio_seg pathseg, struct stat *sbp, - void (*hook)(struct vnode *vp, struct stat *sbp)) + enum uio_seg pathseg, struct stat *sbp) { struct nameidata nd; int error; @@ -2441,18 +2440,9 @@ AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH) | LOCKSHARED | LOCKLEAF | AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights); - if ((error = namei(&nd)) != 0) { - if (error == ENOTDIR && - (nd.ni_resflags & NIRES_EMPTYPATH) != 0) - error = kern_fstat(td, fd, sbp); + if ((error = namei(&nd)) != 0) return (error); - } error = VOP_STAT(nd.ni_vp, sbp, td->td_ucred, NOCRED); - if (__predict_false(hook != NULL)) { - if (error == 0) { - hook(nd.ni_vp, sbp); - } - } NDFREE_PNBUF(&nd); vput(nd.ni_vp); #ifdef __STAT_TIME_T_EXT @@ -2516,7 +2506,7 @@ int error; error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, - &sb, NULL); + &sb); if (error != 0) return (error); error = freebsd11_cvtnstat(&sb, &nsb); @@ -2542,7 +2532,7 @@ int error; error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, - UIO_USERSPACE, &sb, NULL); + UIO_USERSPACE, &sb); if (error != 0) return (error); error = freebsd11_cvtnstat(&sb, &nsb); diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -81,6 +81,7 @@ mmap_check_fp_fn mr_check_fp_fn; }; +uint64_t at2cnpflags(u_int at_flags, u_int mask); int kern___getcwd(struct thread *td, char *buf, enum uio_seg bufseg, size_t buflen, size_t path_max); int kern_abort2(struct thread *td, const char *why, int nargs, @@ -319,8 +320,7 @@ union sigval *value); int kern_socket(struct thread *td, int domain, int type, int protocol); int kern_statat(struct thread *td, int flag, int fd, const char *path, - enum uio_seg pathseg, struct stat *sbp, - void (*hook)(struct vnode *vp, struct stat *sbp)); + enum uio_seg pathseg, struct stat *sbp); int kern_specialfd(struct thread *td, int type, void *arg); int kern_statfs(struct thread *td, const char *path, enum uio_seg pathseg, struct statfs *buf);