aboutsummaryrefslogtreecommitdiff
path: root/sys/compat/linux/linux_stats.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat/linux/linux_stats.c')
-rw-r--r--sys/compat/linux/linux_stats.c409
1 files changed, 160 insertions, 249 deletions
diff --git a/sys/compat/linux/linux_stats.c b/sys/compat/linux/linux_stats.c
index 9dc7686cb963..6c032cc569f8 100644
--- a/sys/compat/linux/linux_stats.c
+++ b/sys/compat/linux/linux_stats.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1994-1995 Søren Schmidt
* All rights reserved.
@@ -26,27 +26,25 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_compat.h"
+#include "opt_ktrace.h"
#include <sys/param.h>
#include <sys/capsicum.h>
#include <sys/dirent.h>
-#include <sys/file.h>
-#include <sys/filedesc.h>
-#include <sys/proc.h>
+#include <sys/lock.h>
#include <sys/malloc.h>
-#include <sys/mount.h>
+#include <sys/mutex.h>
#include <sys/namei.h>
+#include <sys/proc.h>
#include <sys/stat.h>
#include <sys/syscallsubr.h>
-#include <sys/systm.h>
#include <sys/tty.h>
#include <sys/vnode.h>
-#include <sys/conf.h>
-#include <sys/fcntl.h>
+#ifdef KTRACE
+#include <sys/ktrace.h>
+#endif
+
+#include <security/audit/audit.h>
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
@@ -56,41 +54,68 @@ __FBSDID("$FreeBSD$");
#include <machine/../linux/linux_proto.h>
#endif
-#include <compat/linux/linux_util.h>
+#include <compat/linux/linux.h>
#include <compat/linux/linux_file.h>
+#include <compat/linux/linux_util.h>
-static void
-translate_vnhook_major_minor(struct vnode *vp, struct stat *sb)
+
+static int
+linux_kern_fstat(struct thread *td, int fd, struct stat *sbp)
{
- int major, minor;
+ struct vnode *vp;
+ struct file *fp;
+ int error;
- if (vn_isdisk(vp)) {
- sb->st_mode &= ~S_IFMT;
- sb->st_mode |= S_IFBLK;
- }
+ AUDIT_ARG_FD(fd);
- /*
- * Return the same st_dev for every devfs instance. The reason
- * for this is to work around an idiosyncrasy of glibc getttynam()
- * implementation: it checks whether st_dev returned for fd 0
- * is the same as st_dev returned for the target of /proc/self/fd/0
- * symlink, and with linux chroots having their own devfs instance,
- * the check will fail if you chroot into it.
- */
- if (rootdevmp != NULL && vp->v_mount->mnt_vfc == rootdevmp->mnt_vfc)
- sb->st_dev = rootdevmp->mnt_stat.f_fsid.val[0];
+ error = fget(td, fd, &cap_fstat_rights, &fp);
+ if (__predict_false(error != 0))
+ return (error);
- if (linux_vn_get_major_minor(vp, &major, &minor) == 0)
- sb->st_rdev = (major << 8 | minor);
+ AUDIT_ARG_FILE(td->td_proc, fp);
+
+ error = fo_stat(fp, sbp, td->td_ucred);
+ if (error == 0 && (vp = fp->f_vnode) != NULL)
+ translate_vnhook_major_minor(vp, sbp);
+ fdrop(fp, td);
+#ifdef KTRACE
+ if (KTRPOINT(td, KTR_STRUCT))
+ ktrstat_error(sbp, error);
+#endif
+ return (error);
}
static int
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;
- return (kern_statat(td, flag, fd, path, pathseg, sbp,
- translate_vnhook_major_minor));
+ 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);
+
+ if ((error = namei(&nd)) != 0) {
+ if (error == ENOTDIR &&
+ (nd.ni_resflags & NIRES_EMPTYPATH) != 0)
+ error = linux_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
@@ -112,77 +137,19 @@ linux_kern_lstat(struct thread *td, const char *path, enum uio_seg pathseg,
}
#endif
-static void
-translate_fd_major_minor(struct thread *td, int fd, struct stat *buf)
-{
- struct file *fp;
- struct vnode *vp;
- struct mount *mp;
- int major, minor;
-
- /*
- * No capability rights required here.
- */
- if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) ||
- fget(td, fd, &cap_no_rights, &fp) != 0)
- return;
- vp = fp->f_vnode;
- if (vp != NULL && vn_isdisk(vp)) {
- buf->st_mode &= ~S_IFMT;
- buf->st_mode |= S_IFBLK;
- }
- if (vp != NULL && rootdevmp != NULL) {
- mp = vp->v_mount;
- __compiler_membar();
- if (mp != NULL && mp->mnt_vfc == rootdevmp->mnt_vfc)
- buf->st_dev = rootdevmp->mnt_stat.f_fsid.val[0];
- }
- if (linux_vn_get_major_minor(vp, &major, &minor) == 0) {
- buf->st_rdev = (major << 8 | minor);
- } else if (fp->f_type == DTYPE_PTS) {
- struct tty *tp = fp->f_data;
-
- /* Convert the numbers for the slave device. */
- if (linux_driver_get_major_minor(devtoname(tp->t_dev),
- &major, &minor) == 0) {
- buf->st_rdev = (major << 8 | minor);
- }
- }
- fdrop(fp, td);
-}
-
-/*
- * l_dev_t has the same encoding as dev_t in the latter's low 16 bits, so
- * truncation of a dev_t to 16 bits gives the same result as unpacking
- * using major() and minor() and repacking in the l_dev_t format. This
- * detail is hidden in dev_to_ldev(). Overflow in conversions of dev_t's
- * are not checked for, as for other fields.
- *
- * dev_to_ldev() is only used for translating st_dev. When we convert
- * st_rdev for copying it out, it isn't really a dev_t, but has already
- * been translated to an l_dev_t in a nontrivial way. Translating it
- * again would be illogical but would have no effect since the low 16
- * bits have the same encoding.
- *
- * The nontrivial translation for st_rdev renumbers some devices, but not
- * ones that can be mounted on, so it is consistent with the translation
- * for st_dev except when the renumbering or truncation causes conflicts.
- */
-#define dev_to_ldev(d) ((uint16_t)(d))
-
static int
newstat_copyout(struct stat *buf, void *ubuf)
{
struct l_newstat tbuf;
bzero(&tbuf, sizeof(tbuf));
- tbuf.st_dev = dev_to_ldev(buf->st_dev);
+ tbuf.st_dev = linux_new_encode_dev(buf->st_dev);
tbuf.st_ino = buf->st_ino;
tbuf.st_mode = buf->st_mode;
tbuf.st_nlink = buf->st_nlink;
tbuf.st_uid = buf->st_uid;
tbuf.st_gid = buf->st_gid;
- tbuf.st_rdev = buf->st_rdev;
+ tbuf.st_rdev = linux_new_encode_dev(buf->st_rdev);
tbuf.st_size = buf->st_size;
tbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
@@ -196,55 +163,15 @@ newstat_copyout(struct stat *buf, void *ubuf)
return (copyout(&tbuf, ubuf, sizeof(tbuf)));
}
-static int
-statx_copyout(struct stat *buf, void *ubuf)
-{
- struct l_statx tbuf;
-
- bzero(&tbuf, sizeof(tbuf));
- tbuf.stx_mask = STATX_ALL;
- tbuf.stx_blksize = buf->st_blksize;
- tbuf.stx_attributes = 0;
- tbuf.stx_nlink = buf->st_nlink;
- tbuf.stx_uid = buf->st_uid;
- tbuf.stx_gid = buf->st_gid;
- tbuf.stx_mode = buf->st_mode;
- tbuf.stx_ino = buf->st_ino;
- tbuf.stx_size = buf->st_size;
- tbuf.stx_blocks = buf->st_blocks;
-
- tbuf.stx_atime.tv_sec = buf->st_atim.tv_sec;
- tbuf.stx_atime.tv_nsec = buf->st_atim.tv_nsec;
- tbuf.stx_btime.tv_sec = buf->st_birthtim.tv_sec;
- tbuf.stx_btime.tv_nsec = buf->st_birthtim.tv_nsec;
- tbuf.stx_ctime.tv_sec = buf->st_ctim.tv_sec;
- tbuf.stx_ctime.tv_nsec = buf->st_ctim.tv_nsec;
- tbuf.stx_mtime.tv_sec = buf->st_mtim.tv_sec;
- tbuf.stx_mtime.tv_nsec = buf->st_mtim.tv_nsec;
-
- tbuf.stx_rdev_major = buf->st_rdev >> 8;
- tbuf.stx_rdev_minor = buf->st_rdev & 0xff;
- tbuf.stx_dev_major = buf->st_dev >> 8;
- tbuf.stx_dev_minor = buf->st_dev & 0xff;
-
- return (copyout(&tbuf, ubuf, sizeof(tbuf)));
-}
#ifdef LINUX_LEGACY_SYSCALLS
int
linux_newstat(struct thread *td, struct linux_newstat_args *args)
{
struct stat buf;
- char *path;
int error;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
- } else {
- LCONVPATHEXIST(args->path, &path);
- error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
- LFREEPATH(path);
- }
+ error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
if (error)
return (error);
return (newstat_copyout(&buf, args->buf));
@@ -254,16 +181,9 @@ int
linux_newlstat(struct thread *td, struct linux_newlstat_args *args)
{
struct stat sb;
- char *path;
int error;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &sb);
- } else {
- LCONVPATHEXIST(args->path, &path);
- error = linux_kern_lstat(td, path, UIO_SYSSPACE, &sb);
- LFREEPATH(path);
- }
+ error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &sb);
if (error)
return (error);
return (newstat_copyout(&sb, args->buf));
@@ -276,8 +196,7 @@ linux_newfstat(struct thread *td, struct linux_newfstat_args *args)
struct stat buf;
int error;
- error = kern_fstat(td, args->fd, &buf);
- translate_fd_major_minor(td, args->fd, &buf);
+ error = linux_kern_fstat(td, args->fd, &buf);
if (!error)
error = newstat_copyout(&buf, args->buf);
@@ -285,19 +204,27 @@ linux_newfstat(struct thread *td, struct linux_newfstat_args *args)
}
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+
+static __inline uint16_t
+linux_old_encode_dev(dev_t _dev)
+{
+
+ return (_dev == NODEV ? 0 : linux_encode_dev(major(_dev), minor(_dev)));
+}
+
static int
-stat_copyout(struct stat *buf, void *ubuf)
+old_stat_copyout(struct stat *buf, void *ubuf)
{
- struct l_stat lbuf;
+ struct l_old_stat lbuf;
bzero(&lbuf, sizeof(lbuf));
- lbuf.st_dev = dev_to_ldev(buf->st_dev);
+ lbuf.st_dev = linux_old_encode_dev(buf->st_dev);
lbuf.st_ino = buf->st_ino;
lbuf.st_mode = buf->st_mode;
lbuf.st_nlink = buf->st_nlink;
lbuf.st_uid = buf->st_uid;
lbuf.st_gid = buf->st_gid;
- lbuf.st_rdev = buf->st_rdev;
+ lbuf.st_rdev = linux_old_encode_dev(buf->st_rdev);
lbuf.st_size = MIN(buf->st_size, INT32_MAX);
lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
@@ -317,40 +244,26 @@ int
linux_stat(struct thread *td, struct linux_stat_args *args)
{
struct stat buf;
- char *path;
int error;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
- } else {
- LCONVPATHEXIST(args->path, &path);
- error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
- LFREEPATH(path);
- }
+ error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
if (error) {
return (error);
}
- return (stat_copyout(&buf, args->up));
+ return (old_stat_copyout(&buf, args->up));
}
int
linux_lstat(struct thread *td, struct linux_lstat_args *args)
{
struct stat buf;
- char *path;
int error;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &buf);
- } else {
- LCONVPATHEXIST(args->path, &path);
- error = linux_kern_lstat(td, path, UIO_SYSSPACE, &buf);
- LFREEPATH(path);
- }
+ error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &buf);
if (error) {
return (error);
}
- return (stat_copyout(&buf, args->up));
+ return (old_stat_copyout(&buf, args->up));
}
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
@@ -411,33 +324,50 @@ bsd_to_linux_ftype(const char *fstypename)
}
static int
-bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
+bsd_to_linux_mnt_flags(int f_flags)
{
-#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
- uint64_t tmp;
+ int flags = LINUX_ST_VALID;
+
+ if (f_flags & MNT_RDONLY)
+ flags |= LINUX_ST_RDONLY;
+ if (f_flags & MNT_NOEXEC)
+ flags |= LINUX_ST_NOEXEC;
+ if (f_flags & MNT_NOSUID)
+ flags |= LINUX_ST_NOSUID;
+ if (f_flags & MNT_NOATIME)
+ flags |= LINUX_ST_NOATIME;
+ if (f_flags & MNT_NOSYMFOLLOW)
+ flags |= LINUX_ST_NOSYMFOLLOW;
+ if (f_flags & MNT_SYNCHRONOUS)
+ flags |= LINUX_ST_SYNCHRONOUS;
+
+ return (flags);
+}
-#define LINUX_HIBITS 0xffffffff00000000ULL
+static int
+bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
+{
- tmp = bsd_statfs->f_blocks | bsd_statfs->f_bfree | bsd_statfs->f_files |
- bsd_statfs->f_bsize;
- if ((bsd_statfs->f_bavail != -1 && (bsd_statfs->f_bavail & LINUX_HIBITS)) ||
- (bsd_statfs->f_ffree != -1 && (bsd_statfs->f_ffree & LINUX_HIBITS)) ||
- (tmp & LINUX_HIBITS))
- return (EOVERFLOW);
-#undef LINUX_HIBITS
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+ statfs_scale_blocks(bsd_statfs, INT32_MAX);
#endif
linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
linux_statfs->f_bsize = bsd_statfs->f_bsize;
linux_statfs->f_blocks = bsd_statfs->f_blocks;
linux_statfs->f_bfree = bsd_statfs->f_bfree;
linux_statfs->f_bavail = bsd_statfs->f_bavail;
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+ linux_statfs->f_ffree = MIN(bsd_statfs->f_ffree, INT32_MAX);
+ linux_statfs->f_files = MIN(bsd_statfs->f_files, INT32_MAX);
+#else
linux_statfs->f_ffree = bsd_statfs->f_ffree;
linux_statfs->f_files = bsd_statfs->f_files;
+#endif
linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
linux_statfs->f_namelen = MAXNAMLEN;
linux_statfs->f_frsize = bsd_statfs->f_bsize;
- linux_statfs->f_flags = 0;
+ linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags);
memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
return (0);
@@ -448,18 +378,10 @@ linux_statfs(struct thread *td, struct linux_statfs_args *args)
{
struct l_statfs linux_statfs;
struct statfs *bsd_statfs;
- char *path;
int error;
- if (!LUSECONVPATH(td)) {
- bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
- error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
- } else {
- LCONVPATHEXIST(args->path, &path);
- bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
- error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
- LFREEPATH(path);
- }
+ bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
if (error == 0)
error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
free(bsd_statfs, M_STATFS);
@@ -484,7 +406,7 @@ bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs
linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
linux_statfs->f_namelen = MAXNAMLEN;
linux_statfs->f_frsize = bsd_statfs->f_bsize;
- linux_statfs->f_flags = 0;
+ linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags);
memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
}
@@ -493,21 +415,13 @@ linux_statfs64(struct thread *td, struct linux_statfs64_args *args)
{
struct l_statfs64 linux_statfs;
struct statfs *bsd_statfs;
- char *path;
int error;
if (args->bufsize != sizeof(struct l_statfs64))
return (EINVAL);
- if (!LUSECONVPATH(td)) {
- bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
- error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
- } else {
- LCONVPATHEXIST(args->path, &path);
- bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
- error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
- LFREEPATH(path);
- }
+ bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
if (error == 0)
bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
free(bsd_statfs, M_STATFS);
@@ -579,13 +493,13 @@ stat64_copyout(struct stat *buf, void *ubuf)
struct l_stat64 lbuf;
bzero(&lbuf, sizeof(lbuf));
- lbuf.st_dev = dev_to_ldev(buf->st_dev);
+ lbuf.st_dev = linux_new_encode_dev(buf->st_dev);
lbuf.st_ino = buf->st_ino;
lbuf.st_mode = buf->st_mode;
lbuf.st_nlink = buf->st_nlink;
lbuf.st_uid = buf->st_uid;
lbuf.st_gid = buf->st_gid;
- lbuf.st_rdev = buf->st_rdev;
+ lbuf.st_rdev = linux_new_encode_dev(buf->st_rdev);
lbuf.st_size = buf->st_size;
lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
@@ -611,16 +525,9 @@ int
linux_stat64(struct thread *td, struct linux_stat64_args *args)
{
struct stat buf;
- char *filename;
int error;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_stat(td, args->filename, UIO_USERSPACE, &buf);
- } else {
- LCONVPATHEXIST(args->filename, &filename);
- error = linux_kern_stat(td, filename, UIO_SYSSPACE, &buf);
- LFREEPATH(filename);
- }
+ error = linux_kern_stat(td, args->filename, UIO_USERSPACE, &buf);
if (error)
return (error);
return (stat64_copyout(&buf, args->statbuf));
@@ -630,16 +537,9 @@ int
linux_lstat64(struct thread *td, struct linux_lstat64_args *args)
{
struct stat sb;
- char *filename;
int error;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_lstat(td, args->filename, UIO_USERSPACE, &sb);
- } else {
- LCONVPATHEXIST(args->filename, &filename);
- error = linux_kern_lstat(td, filename, UIO_SYSSPACE, &sb);
- LFREEPATH(filename);
- }
+ error = linux_kern_lstat(td, args->filename, UIO_USERSPACE, &sb);
if (error)
return (error);
return (stat64_copyout(&sb, args->statbuf));
@@ -651,8 +551,7 @@ linux_fstat64(struct thread *td, struct linux_fstat64_args *args)
struct stat buf;
int error;
- error = kern_fstat(td, args->fd, &buf);
- translate_fd_major_minor(td, args->fd, &buf);
+ error = linux_kern_fstat(td, args->fd, &buf);
if (!error)
error = stat64_copyout(&buf, args->statbuf);
@@ -662,7 +561,6 @@ linux_fstat64(struct thread *td, struct linux_fstat64_args *args)
int
linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
{
- char *path;
int error, dfd, flag, unsupported;
struct stat buf;
@@ -677,14 +575,8 @@ linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
AT_EMPTY_PATH : 0;
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_statat(td, flag, dfd, args->pathname,
- UIO_USERSPACE, &buf);
- } else {
- LCONVPATHEXIST_AT(args->pathname, &path, dfd);
- error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
- LFREEPATH(path);
- }
+ error = linux_kern_statat(td, flag, dfd, args->pathname,
+ UIO_USERSPACE, &buf);
if (error == 0)
error = stat64_copyout(&buf, args->statbuf);
@@ -696,7 +588,6 @@ linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
int
linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args)
{
- char *path;
int error, dfd, flag, unsupported;
struct stat buf;
@@ -712,14 +603,8 @@ linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args)
AT_EMPTY_PATH : 0;
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_statat(td, flag, dfd, args->pathname,
- UIO_USERSPACE, &buf);
- } else {
- LCONVPATHEXIST_AT(args->pathname, &path, dfd);
- error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
- LFREEPATH(path);
- }
+ error = linux_kern_statat(td, flag, dfd, args->pathname,
+ UIO_USERSPACE, &buf);
if (error == 0)
error = newstat_copyout(&buf, args->statbuf);
@@ -767,14 +652,47 @@ linux_syncfs(struct thread *td, struct linux_syncfs_args *args)
return (error);
}
+static int
+statx_copyout(struct stat *buf, void *ubuf)
+{
+ struct l_statx tbuf;
+
+ bzero(&tbuf, sizeof(tbuf));
+ tbuf.stx_mask = STATX_ALL;
+ tbuf.stx_blksize = buf->st_blksize;
+ tbuf.stx_attributes = 0;
+ tbuf.stx_nlink = buf->st_nlink;
+ tbuf.stx_uid = buf->st_uid;
+ tbuf.stx_gid = buf->st_gid;
+ tbuf.stx_mode = buf->st_mode;
+ tbuf.stx_ino = buf->st_ino;
+ tbuf.stx_size = buf->st_size;
+ tbuf.stx_blocks = buf->st_blocks;
+
+ tbuf.stx_atime.tv_sec = buf->st_atim.tv_sec;
+ tbuf.stx_atime.tv_nsec = buf->st_atim.tv_nsec;
+ tbuf.stx_btime.tv_sec = buf->st_birthtim.tv_sec;
+ tbuf.stx_btime.tv_nsec = buf->st_birthtim.tv_nsec;
+ tbuf.stx_ctime.tv_sec = buf->st_ctim.tv_sec;
+ tbuf.stx_ctime.tv_nsec = buf->st_ctim.tv_nsec;
+ tbuf.stx_mtime.tv_sec = buf->st_mtim.tv_sec;
+ tbuf.stx_mtime.tv_nsec = buf->st_mtim.tv_nsec;
+ tbuf.stx_rdev_major = linux_encode_major(buf->st_rdev);
+ tbuf.stx_rdev_minor = linux_encode_minor(buf->st_rdev);
+ tbuf.stx_dev_major = linux_encode_major(buf->st_dev);
+ tbuf.stx_dev_minor = linux_encode_minor(buf->st_dev);
+
+ return (copyout(&tbuf, ubuf, sizeof(tbuf)));
+}
+
int
linux_statx(struct thread *td, struct linux_statx_args *args)
{
- char *path;
int error, dirfd, flags, unsupported;
struct stat buf;
- unsupported = args->flags & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH);
+ unsupported = args->flags & ~(LINUX_AT_SYMLINK_NOFOLLOW |
+ LINUX_AT_EMPTY_PATH | LINUX_AT_NO_AUTOMOUNT);
if (unsupported != 0) {
linux_msg(td, "statx unsupported flags 0x%x", unsupported);
return (EINVAL);
@@ -786,17 +704,10 @@ linux_statx(struct thread *td, struct linux_statx_args *args)
AT_EMPTY_PATH : 0;
dirfd = (args->dirfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dirfd;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_statat(td, flags, dirfd, args->pathname,
- UIO_USERSPACE, &buf);
- } else {
- LCONVPATHEXIST_AT(args->pathname, &path, dirfd);
- error = linux_kern_statat(td, flags, dirfd, path, UIO_SYSSPACE, &buf);
- LFREEPATH(path);
- }
+ error = linux_kern_statat(td, flags, dirfd, args->pathname,
+ UIO_USERSPACE, &buf);
if (error == 0)
error = statx_copyout(&buf, args->statxbuf);
return (error);
}
-