Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/vfs_syscalls.c
Show First 20 Lines • Show All 544 Lines • ▼ Show 20 Lines | else | ||||
*countp = count; | *countp = count; | ||||
return (0); | return (0); | ||||
} | } | ||||
#ifdef COMPAT_FREEBSD4 | #ifdef COMPAT_FREEBSD4 | ||||
/* | /* | ||||
* Get old format filesystem statistics. | * Get old format filesystem statistics. | ||||
*/ | */ | ||||
static void cvtstatfs(struct statfs *, struct ostatfs *); | static void freebsd4_cvtstatfs(struct statfs *, struct ostatfs *); | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct freebsd4_statfs_args { | struct freebsd4_statfs_args { | ||||
char *path; | char *path; | ||||
struct ostatfs *buf; | struct ostatfs *buf; | ||||
}; | }; | ||||
#endif | #endif | ||||
int | int | ||||
freebsd4_statfs(td, uap) | freebsd4_statfs(td, uap) | ||||
struct thread *td; | struct thread *td; | ||||
struct freebsd4_statfs_args /* { | struct freebsd4_statfs_args /* { | ||||
char *path; | char *path; | ||||
struct ostatfs *buf; | struct ostatfs *buf; | ||||
} */ *uap; | } */ *uap; | ||||
{ | { | ||||
struct ostatfs osb; | struct ostatfs osb; | ||||
struct statfs *sfp; | struct statfs *sfp; | ||||
int error; | int error; | ||||
sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); | sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); | ||||
error = kern_statfs(td, uap->path, UIO_USERSPACE, sfp); | error = kern_statfs(td, uap->path, UIO_USERSPACE, sfp); | ||||
if (error == 0) { | if (error == 0) { | ||||
cvtstatfs(sfp, &osb); | freebsd4_cvtstatfs(sfp, &osb); | ||||
error = copyout(&osb, uap->buf, sizeof(osb)); | error = copyout(&osb, uap->buf, sizeof(osb)); | ||||
} | } | ||||
free(sfp, M_STATFS); | free(sfp, M_STATFS); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Get filesystem statistics. | * Get filesystem statistics. | ||||
Show All 14 Lines | |||||
{ | { | ||||
struct ostatfs osb; | struct ostatfs osb; | ||||
struct statfs *sfp; | struct statfs *sfp; | ||||
int error; | int error; | ||||
sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); | sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); | ||||
error = kern_fstatfs(td, uap->fd, sfp); | error = kern_fstatfs(td, uap->fd, sfp); | ||||
if (error == 0) { | if (error == 0) { | ||||
cvtstatfs(sfp, &osb); | freebsd4_cvtstatfs(sfp, &osb); | ||||
error = copyout(&osb, uap->buf, sizeof(osb)); | error = copyout(&osb, uap->buf, sizeof(osb)); | ||||
} | } | ||||
free(sfp, M_STATFS); | free(sfp, M_STATFS); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Get statistics on all filesystems. | * Get statistics on all filesystems. | ||||
Show All 22 Lines | freebsd4_getfsstat(td, uap) | ||||
if (uap->bufsize < 0) | if (uap->bufsize < 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
count = uap->bufsize / sizeof(struct ostatfs); | count = uap->bufsize / sizeof(struct ostatfs); | ||||
if (count > SIZE_MAX / sizeof(struct statfs)) | if (count > SIZE_MAX / sizeof(struct statfs)) | ||||
return (EINVAL); | return (EINVAL); | ||||
size = count * sizeof(struct statfs); | size = count * sizeof(struct statfs); | ||||
error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE, | error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE, | ||||
uap->mode); | uap->mode); | ||||
if (error == 0) | |||||
td->td_retval[0] = count; | td->td_retval[0] = count; | ||||
if (size != 0) { | if (size != 0) { | ||||
ngie: Could this be committed separately? | |||||
sp = buf; | sp = buf; | ||||
while (count != 0 && error == 0) { | while (count != 0 && error == 0) { | ||||
cvtstatfs(sp, &osb); | freebsd4_cvtstatfs(sp, &osb); | ||||
error = copyout(&osb, uap->buf, sizeof(osb)); | error = copyout(&osb, uap->buf, sizeof(osb)); | ||||
sp++; | sp++; | ||||
uap->buf++; | uap->buf++; | ||||
count--; | count--; | ||||
} | } | ||||
free(buf, M_STATFS); | free(buf, M_STATFS); | ||||
} | } | ||||
return (error); | return (error); | ||||
Show All 22 Lines | freebsd4_fhstatfs(td, uap) | ||||
int error; | int error; | ||||
error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t)); | error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t)); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); | sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); | ||||
error = kern_fhstatfs(td, fh, sfp); | error = kern_fhstatfs(td, fh, sfp); | ||||
if (error == 0) { | if (error == 0) { | ||||
cvtstatfs(sfp, &osb); | freebsd4_cvtstatfs(sfp, &osb); | ||||
error = copyout(&osb, uap->buf, sizeof(osb)); | error = copyout(&osb, uap->buf, sizeof(osb)); | ||||
} | } | ||||
free(sfp, M_STATFS); | free(sfp, M_STATFS); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Convert a new format statfs structure to an old format statfs structure. | * Convert a new format statfs structure to an old format statfs structure. | ||||
*/ | */ | ||||
static void | static void | ||||
cvtstatfs(nsp, osp) | freebsd4_cvtstatfs(nsp, osp) | ||||
struct statfs *nsp; | struct statfs *nsp; | ||||
struct ostatfs *osp; | struct ostatfs *osp; | ||||
{ | { | ||||
statfs_scale_blocks(nsp, LONG_MAX); | statfs_scale_blocks(nsp, LONG_MAX); | ||||
bzero(osp, sizeof(*osp)); | bzero(osp, sizeof(*osp)); | ||||
osp->f_bsize = nsp->f_bsize; | osp->f_bsize = nsp->f_bsize; | ||||
osp->f_iosize = MIN(nsp->f_iosize, LONG_MAX); | osp->f_iosize = MIN(nsp->f_iosize, LONG_MAX); | ||||
Show All 14 Lines | freebsd4_cvtstatfs(nsp, osp) | ||||
strlcpy(osp->f_mntonname, nsp->f_mntonname, | strlcpy(osp->f_mntonname, nsp->f_mntonname, | ||||
MIN(MNAMELEN, OMNAMELEN)); | MIN(MNAMELEN, OMNAMELEN)); | ||||
strlcpy(osp->f_mntfromname, nsp->f_mntfromname, | strlcpy(osp->f_mntfromname, nsp->f_mntfromname, | ||||
MIN(MNAMELEN, OMNAMELEN)); | MIN(MNAMELEN, OMNAMELEN)); | ||||
osp->f_fsid = nsp->f_fsid; | osp->f_fsid = nsp->f_fsid; | ||||
} | } | ||||
#endif /* COMPAT_FREEBSD4 */ | #endif /* COMPAT_FREEBSD4 */ | ||||
#if defined(COMPAT_FREEBSD11) | |||||
/* | /* | ||||
* Get old format filesystem statistics. | |||||
*/ | |||||
static void freebsd11_cvtstatfs(struct statfs *, struct freebsd11_statfs *); | |||||
int | |||||
freebsd11_statfs(struct thread *td, struct freebsd11_statfs_args *uap) | |||||
{ | |||||
struct freebsd11_statfs osb; | |||||
struct statfs *sfp; | |||||
int error; | |||||
sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); | |||||
error = kern_statfs(td, uap->path, UIO_USERSPACE, sfp); | |||||
if (error == 0) { | |||||
freebsd11_cvtstatfs(sfp, &osb); | |||||
error = copyout(&osb, uap->buf, sizeof(osb)); | |||||
} | |||||
free(sfp, M_STATFS); | |||||
return (error); | |||||
} | |||||
/* | |||||
* Get filesystem statistics. | |||||
*/ | |||||
int | |||||
freebsd11_fstatfs(struct thread *td, struct freebsd11_fstatfs_args *uap) | |||||
{ | |||||
struct freebsd11_statfs osb; | |||||
struct statfs *sfp; | |||||
int error; | |||||
sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); | |||||
error = kern_fstatfs(td, uap->fd, sfp); | |||||
if (error == 0) { | |||||
freebsd11_cvtstatfs(sfp, &osb); | |||||
error = copyout(&osb, uap->buf, sizeof(osb)); | |||||
} | |||||
free(sfp, M_STATFS); | |||||
return (error); | |||||
} | |||||
/* | |||||
* Get statistics on all filesystems. | |||||
*/ | |||||
int | |||||
freebsd11_getfsstat(struct thread *td, struct freebsd11_getfsstat_args *uap) | |||||
{ | |||||
struct freebsd11_statfs osb; | |||||
struct statfs *buf, *sp; | |||||
size_t count, size; | |||||
int error; | |||||
count = uap->bufsize / sizeof(struct ostatfs); | |||||
size = count * sizeof(struct statfs); | |||||
error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE, | |||||
uap->mode); | |||||
if (error == 0) | |||||
td->td_retval[0] = count; | |||||
if (size > 0) { | |||||
sp = buf; | |||||
while (count > 0 && error == 0) { | |||||
freebsd11_cvtstatfs(sp, &osb); | |||||
error = copyout(&osb, uap->buf, sizeof(osb)); | |||||
sp++; | |||||
uap->buf++; | |||||
count--; | |||||
} | |||||
free(buf, M_STATFS); | |||||
} | |||||
return (error); | |||||
} | |||||
/* | |||||
* Implement fstatfs() for (NFS) file handles. | |||||
*/ | |||||
int | |||||
freebsd11_fhstatfs(struct thread *td, struct freebsd11_fhstatfs_args *uap) | |||||
{ | |||||
struct freebsd11_statfs osb; | |||||
struct statfs *sfp; | |||||
fhandle_t fh; | |||||
int error; | |||||
error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t)); | |||||
if (error) | |||||
return (error); | |||||
sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); | |||||
error = kern_fhstatfs(td, fh, sfp); | |||||
if (error == 0) { | |||||
freebsd11_cvtstatfs(sfp, &osb); | |||||
error = copyout(&osb, uap->buf, sizeof(osb)); | |||||
} | |||||
free(sfp, M_STATFS); | |||||
return (error); | |||||
} | |||||
/* | |||||
* Convert a new format statfs structure to an old format statfs structure. | |||||
*/ | |||||
static void | |||||
freebsd11_cvtstatfs(nsp, osp) | |||||
struct statfs *nsp; | |||||
struct freebsd11_statfs *osp; | |||||
{ | |||||
bzero(osp, sizeof(*osp)); | |||||
osp->f_version = FREEBSD11_STATFS_VERSION; | |||||
osp->f_type = nsp->f_type; | |||||
osp->f_flags = nsp->f_flags; | |||||
osp->f_bsize = nsp->f_bsize; | |||||
osp->f_iosize = nsp->f_iosize; | |||||
osp->f_blocks = nsp->f_blocks; | |||||
osp->f_bfree = nsp->f_bfree; | |||||
osp->f_bavail = nsp->f_bavail; | |||||
osp->f_files = nsp->f_files; | |||||
osp->f_ffree = nsp->f_ffree; | |||||
osp->f_syncwrites = nsp->f_syncwrites; | |||||
osp->f_asyncwrites = nsp->f_asyncwrites; | |||||
osp->f_syncreads = nsp->f_syncreads; | |||||
osp->f_asyncreads = nsp->f_asyncreads; | |||||
osp->f_namemax = nsp->f_namemax; | |||||
osp->f_owner = nsp->f_owner; | |||||
osp->f_fsid = nsp->f_fsid; | |||||
strlcpy(osp->f_fstypename, nsp->f_fstypename, | |||||
MIN(MFSNAMELEN, sizeof(osp->f_fstypename))); | |||||
strlcpy(osp->f_mntonname, nsp->f_mntonname, | |||||
MIN(MNAMELEN, sizeof(osp->f_mntonname))); | |||||
strlcpy(osp->f_mntfromname, nsp->f_mntfromname, | |||||
MIN(MNAMELEN, sizeof(osp->f_mntfromname))); | |||||
} | |||||
#endif /* COMPAT_FREEBSD11 */ | |||||
/* | |||||
* Change current working directory to a given file descriptor. | * Change current working directory to a given file descriptor. | ||||
*/ | */ | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct fchdir_args { | struct fchdir_args { | ||||
int fd; | int fd; | ||||
}; | }; | ||||
#endif | #endif | ||||
int | int | ||||
▲ Show 20 Lines • Show All 388 Lines • ▼ Show 20 Lines | return (kern_openat(td, AT_FDCWD, uap->path, UIO_USERSPACE, | ||||
O_WRONLY | O_CREAT | O_TRUNC, uap->mode)); | O_WRONLY | O_CREAT | O_TRUNC, uap->mode)); | ||||
} | } | ||||
#endif /* COMPAT_43 */ | #endif /* COMPAT_43 */ | ||||
/* | /* | ||||
* Create a special file. | * Create a special file. | ||||
*/ | */ | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct mknod_args { | struct mknodat_args { | ||||
int fd; | |||||
char *path; | char *path; | ||||
int mode; | mode_t mode; | ||||
int dev; | dev_t dev; | ||||
}; | }; | ||||
#endif | #endif | ||||
int | int | ||||
sys_mknod(td, uap) | sys_mknodat(struct thread *td, struct mknodat_args *uap) | ||||
struct thread *td; | |||||
register struct mknod_args /* { | |||||
char *path; | |||||
int mode; | |||||
int dev; | |||||
} */ *uap; | |||||
{ | { | ||||
return (kern_mknodat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode, | |||||
uap->dev)); | |||||
} | |||||
#if defined(COMPAT_FREEBSD11) | |||||
int | |||||
freebsd11_mknod(struct thread *td, | |||||
struct freebsd11_mknod_args *uap) | |||||
{ | |||||
return (kern_mknodat(td, AT_FDCWD, uap->path, UIO_USERSPACE, | return (kern_mknodat(td, AT_FDCWD, uap->path, UIO_USERSPACE, | ||||
uap->mode, uap->dev)); | uap->mode, uap->dev)); | ||||
} | } | ||||
#ifndef _SYS_SYSPROTO_H_ | |||||
struct mknodat_args { | |||||
int fd; | |||||
char *path; | |||||
mode_t mode; | |||||
dev_t dev; | |||||
}; | |||||
#endif | |||||
int | int | ||||
sys_mknodat(struct thread *td, struct mknodat_args *uap) | freebsd11_mknodat(struct thread *td, | ||||
struct freebsd11_mknodat_args *uap) | |||||
{ | { | ||||
return (kern_mknodat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode, | return (kern_mknodat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode, | ||||
uap->dev)); | uap->dev)); | ||||
} | } | ||||
#endif /* COMPAT_FREEBSD11 */ | |||||
int | int | ||||
kern_mknodat(struct thread *td, int fd, char *path, enum uio_seg pathseg, | kern_mknodat(struct thread *td, int fd, char *path, enum uio_seg pathseg, | ||||
int mode, int dev) | int mode, dev_t dev) | ||||
{ | { | ||||
struct vnode *vp; | struct vnode *vp; | ||||
struct mount *mp; | struct mount *mp; | ||||
struct vattr vattr; | struct vattr vattr; | ||||
struct nameidata nd; | struct nameidata nd; | ||||
cap_rights_t rights; | cap_rights_t rights; | ||||
int error, whiteout = 0; | int error, whiteout = 0; | ||||
▲ Show 20 Lines • Show All 902 Lines • ▼ Show 20 Lines | cvtstat(st, ost) | ||||
ost->st_ctim = st->st_ctim; | ost->st_ctim = st->st_ctim; | ||||
ost->st_blksize = st->st_blksize; | ost->st_blksize = st->st_blksize; | ||||
ost->st_blocks = st->st_blocks; | ost->st_blocks = st->st_blocks; | ||||
ost->st_flags = st->st_flags; | ost->st_flags = st->st_flags; | ||||
ost->st_gen = st->st_gen; | ost->st_gen = st->st_gen; | ||||
} | } | ||||
#endif /* COMPAT_43 */ | #endif /* COMPAT_43 */ | ||||
/* | #if defined(COMPAT_FREEBSD11) | ||||
* Get file status; this version follows links. | void | ||||
*/ | freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost) | ||||
#ifndef _SYS_SYSPROTO_H_ | { | ||||
struct stat_args { | |||||
char *path; | ost->st_dev = st->st_dev; | ||||
struct stat *ub; | ost->st_ino = st->st_ino; /* truncate */ | ||||
}; | ost->st_mode = st->st_mode; | ||||
#endif | ost->st_nlink = st->st_nlink; /* truncate */ | ||||
ost->st_uid = st->st_uid; | |||||
ost->st_gid = st->st_gid; | |||||
ost->st_rdev = st->st_rdev; | |||||
ost->st_atim = st->st_atim; | |||||
ost->st_mtim = st->st_mtim; | |||||
ost->st_ctim = st->st_ctim; | |||||
ost->st_size = st->st_size; | |||||
ost->st_blocks = st->st_blocks; | |||||
ost->st_blksize = st->st_blksize; | |||||
ost->st_flags = st->st_flags; | |||||
ost->st_gen = st->st_gen; | |||||
ost->st_lspare = 0; | |||||
ost->st_birthtim = st->st_birthtim; | |||||
bzero((char *)&ost->st_birthtim + sizeof(ost->st_birthtim), | |||||
sizeof(*ost) - offsetof(struct freebsd11_stat, | |||||
st_birthtim) - sizeof(ost->st_birthtim)); | |||||
} | |||||
int | int | ||||
sys_stat(td, uap) | freebsd11_stat(struct thread *td, struct freebsd11_stat_args* uap) | ||||
struct thread *td; | |||||
register struct stat_args /* { | |||||
char *path; | |||||
struct stat *ub; | |||||
} */ *uap; | |||||
{ | { | ||||
struct stat sb; | struct stat sb; | ||||
struct freebsd11_stat osb; | |||||
int error; | int error; | ||||
error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, | error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, | ||||
&sb, NULL); | &sb, NULL); | ||||
if (error == 0) | if (error != 0) | ||||
error = copyout(&sb, uap->ub, sizeof (sb)); | |||||
return (error); | return (error); | ||||
freebsd11_cvtstat(&sb, &osb); | |||||
error = copyout(&osb, uap->ub, sizeof(osb)); | |||||
return (error); | |||||
} | } | ||||
int | |||||
freebsd11_lstat(struct thread *td, struct freebsd11_lstat_args* uap) | |||||
{ | |||||
struct stat sb; | |||||
struct freebsd11_stat osb; | |||||
int error; | |||||
error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, | |||||
UIO_USERSPACE, &sb, NULL); | |||||
if (error != 0) | |||||
return (error); | |||||
freebsd11_cvtstat(&sb, &osb); | |||||
error = copyout(&osb, uap->ub, sizeof(osb)); | |||||
return (error); | |||||
} | |||||
int | |||||
freebsd11_fhstat(struct thread *td, struct freebsd11_fhstat_args* uap) | |||||
{ | |||||
struct fhandle fh; | |||||
struct stat sb; | |||||
struct freebsd11_stat osb; | |||||
int error; | |||||
error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t)); | |||||
if (error != 0) | |||||
return (error); | |||||
error = kern_fhstat(td, fh, &sb); | |||||
if (error != 0) | |||||
return (error); | |||||
freebsd11_cvtstat(&sb, &osb); | |||||
error = copyout(&osb, uap->sb, sizeof(osb)); | |||||
return (error); | |||||
} | |||||
int | |||||
freebsd11_fstatat(struct thread *td, struct freebsd11_fstatat_args* uap) | |||||
{ | |||||
struct stat sb; | |||||
struct freebsd11_stat osb; | |||||
int error; | |||||
error = kern_statat(td, uap->flag, uap->fd, uap->path, | |||||
UIO_USERSPACE, &sb, NULL); | |||||
if (error != 0) | |||||
return (error); | |||||
freebsd11_cvtstat(&sb, &osb); | |||||
error = copyout(&osb, uap->buf, sizeof(osb)); | |||||
return (error); | |||||
} | |||||
#endif /* COMPAT_FREEBSD11 */ | |||||
/* | |||||
* Get file status | |||||
*/ | |||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct fstatat_args { | struct fstatat_args { | ||||
int fd; | int fd; | ||||
char *path; | char *path; | ||||
struct stat *buf; | struct stat *buf; | ||||
int flag; | int flag; | ||||
} | } | ||||
#endif | #endif | ||||
Show All 36 Lines | if (S_ISREG(sb.st_mode)) | ||||
SDT_PROBE2(vfs, , stat, reg, path, pathseg); | SDT_PROBE2(vfs, , stat, reg, path, pathseg); | ||||
if (__predict_false(hook != NULL)) | if (__predict_false(hook != NULL)) | ||||
hook(nd.ni_vp, &sb); | hook(nd.ni_vp, &sb); | ||||
} | } | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
vput(nd.ni_vp); | vput(nd.ni_vp); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
#ifdef __STAT_TIME_T_EXT | |||||
sb.st_atim_ext = 0; | |||||
sb.st_mtim_ext = 0; | |||||
sb.st_ctim_ext = 0; | |||||
sb.st_btim_ext = 0; | |||||
#endif | |||||
*sbp = sb; | *sbp = sb; | ||||
#ifdef KTRACE | #ifdef KTRACE | ||||
if (KTRPOINT(td, KTR_STRUCT)) | if (KTRPOINT(td, KTR_STRUCT)) | ||||
ktrstat(&sb); | ktrstat(&sb); | ||||
#endif | #endif | ||||
return (0); | return (0); | ||||
} | } | ||||
#if defined(COMPAT_FREEBSD11) | |||||
/* | /* | ||||
* Get file status; this version does not follow links. | |||||
*/ | |||||
#ifndef _SYS_SYSPROTO_H_ | |||||
struct lstat_args { | |||||
char *path; | |||||
struct stat *ub; | |||||
}; | |||||
#endif | |||||
int | |||||
sys_lstat(td, uap) | |||||
struct thread *td; | |||||
register struct lstat_args /* { | |||||
char *path; | |||||
struct stat *ub; | |||||
} */ *uap; | |||||
{ | |||||
struct stat sb; | |||||
int error; | |||||
error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, | |||||
UIO_USERSPACE, &sb, NULL); | |||||
if (error == 0) | |||||
error = copyout(&sb, uap->ub, sizeof (sb)); | |||||
return (error); | |||||
} | |||||
/* | |||||
* Implementation of the NetBSD [l]stat() functions. | * Implementation of the NetBSD [l]stat() functions. | ||||
*/ | */ | ||||
void | void | ||||
cvtnstat(sb, nsb) | freebsd11_cvtnstat(struct stat *sb, struct nstat *nsb) | ||||
struct stat *sb; | |||||
struct nstat *nsb; | |||||
{ | { | ||||
bzero(nsb, sizeof *nsb); | bzero(nsb, sizeof(*nsb)); | ||||
nsb->st_dev = sb->st_dev; | nsb->st_dev = sb->st_dev; | ||||
nsb->st_ino = sb->st_ino; | nsb->st_ino = sb->st_ino; | ||||
nsb->st_mode = sb->st_mode; | nsb->st_mode = sb->st_mode; | ||||
nsb->st_nlink = sb->st_nlink; | nsb->st_nlink = sb->st_nlink; | ||||
nsb->st_uid = sb->st_uid; | nsb->st_uid = sb->st_uid; | ||||
nsb->st_gid = sb->st_gid; | nsb->st_gid = sb->st_gid; | ||||
nsb->st_rdev = sb->st_rdev; | nsb->st_rdev = sb->st_rdev; | ||||
nsb->st_atim = sb->st_atim; | nsb->st_atim = sb->st_atim; | ||||
nsb->st_mtim = sb->st_mtim; | nsb->st_mtim = sb->st_mtim; | ||||
nsb->st_ctim = sb->st_ctim; | nsb->st_ctim = sb->st_ctim; | ||||
nsb->st_size = sb->st_size; | nsb->st_size = sb->st_size; | ||||
nsb->st_blocks = sb->st_blocks; | nsb->st_blocks = sb->st_blocks; | ||||
nsb->st_blksize = sb->st_blksize; | nsb->st_blksize = sb->st_blksize; | ||||
nsb->st_flags = sb->st_flags; | nsb->st_flags = sb->st_flags; | ||||
nsb->st_gen = sb->st_gen; | nsb->st_gen = sb->st_gen; | ||||
nsb->st_birthtim = sb->st_birthtim; | nsb->st_birthtim = sb->st_birthtim; | ||||
} | } | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct nstat_args { | struct freebsd11_nstat_args { | ||||
char *path; | char *path; | ||||
struct nstat *ub; | struct nstat *ub; | ||||
}; | }; | ||||
#endif | #endif | ||||
int | int | ||||
sys_nstat(td, uap) | freebsd11_nstat(td, uap) | ||||
struct thread *td; | struct thread *td; | ||||
register struct nstat_args /* { | register struct freebsd11_nstat_args /* { | ||||
char *path; | char *path; | ||||
struct nstat *ub; | struct nstat *ub; | ||||
} */ *uap; | } */ *uap; | ||||
{ | { | ||||
struct stat sb; | struct stat sb; | ||||
struct nstat nsb; | struct nstat nsb; | ||||
int error; | int error; | ||||
error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, | error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, | ||||
&sb, NULL); | &sb, NULL); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
cvtnstat(&sb, &nsb); | freebsd11_cvtnstat(&sb, &nsb); | ||||
return (copyout(&nsb, uap->ub, sizeof (nsb))); | return (copyout(&nsb, uap->ub, sizeof (nsb))); | ||||
} | } | ||||
/* | /* | ||||
* NetBSD lstat. Get file status; this version does not follow links. | * NetBSD lstat. Get file status; this version does not follow links. | ||||
*/ | */ | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct lstat_args { | struct freebsd11_nlstat_args { | ||||
char *path; | char *path; | ||||
struct stat *ub; | struct stat *ub; | ||||
}; | }; | ||||
#endif | #endif | ||||
int | int | ||||
sys_nlstat(td, uap) | freebsd11_nlstat(td, uap) | ||||
struct thread *td; | struct thread *td; | ||||
register struct nlstat_args /* { | register struct freebsd11_nlstat_args /* { | ||||
char *path; | char *path; | ||||
struct nstat *ub; | struct nstat *ub; | ||||
} */ *uap; | } */ *uap; | ||||
{ | { | ||||
struct stat sb; | struct stat sb; | ||||
struct nstat nsb; | struct nstat nsb; | ||||
int error; | int error; | ||||
error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, | error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path, | ||||
UIO_USERSPACE, &sb, NULL); | UIO_USERSPACE, &sb, NULL); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
cvtnstat(&sb, &nsb); | freebsd11_cvtnstat(&sb, &nsb); | ||||
return (copyout(&nsb, uap->ub, sizeof (nsb))); | return (copyout(&nsb, uap->ub, sizeof (nsb))); | ||||
} | } | ||||
#endif /* COMPAT_FREEBSD11 */ | |||||
/* | /* | ||||
* Get configurable pathname variables. | * Get configurable pathname variables. | ||||
*/ | */ | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct pathconf_args { | struct pathconf_args { | ||||
char *path; | char *path; | ||||
int name; | int name; | ||||
▲ Show 20 Lines • Show All 1,449 Lines • ▼ Show 20 Lines | out: | ||||
vput(vp); | vput(vp); | ||||
if (nd.ni_dvp == vp) | if (nd.ni_dvp == vp) | ||||
vrele(nd.ni_dvp); | vrele(nd.ni_dvp); | ||||
else | else | ||||
vput(nd.ni_dvp); | vput(nd.ni_dvp); | ||||
return (error); | return (error); | ||||
} | } | ||||
#if defined(COMPAT_43) || defined(COMPAT_FREEBSD11) | |||||
int | |||||
freebsd11_kern_getdirentries(struct thread *td, int fd, char *ubuf, u_int count, | |||||
long *basep, void (*func)(struct freebsd11_dirent *)) | |||||
{ | |||||
struct freebsd11_dirent dstdp; | |||||
struct dirent *dp, *edp; | |||||
char *dirbuf; | |||||
off_t base; | |||||
ssize_t resid, ucount; | |||||
int error; | |||||
/* XXX arbitrary sanity limit on `count'. */ | |||||
count = min(count, 64 * 1024); | |||||
Not Done Inline ActionsCould this be tunable for folks who have potentially large directories (maybe not in the compat syscall, but maybe in the non-compat one)? ngie: Could this be tunable for folks who have potentially large directories (maybe not in the compat… | |||||
dirbuf = malloc(count, M_TEMP, M_WAITOK); | |||||
error = kern_getdirentries(td, fd, dirbuf, count, &base, &resid, | |||||
UIO_SYSSPACE); | |||||
if (error != 0) | |||||
goto done; | |||||
if (basep != NULL) | |||||
*basep = base; | |||||
ucount = 0; | |||||
for (dp = (struct dirent *)dirbuf, | |||||
edp = (struct dirent *)&dirbuf[count - resid]; | |||||
ucount < count && dp < edp; ) { | |||||
if (dp->d_reclen == 0) | |||||
break; | |||||
MPASS(dp->d_reclen >= _GENERIC_DIRLEN(0)); | |||||
if (dp->d_namlen > sizeof(dstdp.d_name) - 1) | |||||
continue; | |||||
dstdp.d_type = dp->d_type; | |||||
dstdp.d_namlen = dp->d_namlen; | |||||
dstdp.d_fileno = dp->d_fileno; /* truncate */ | |||||
dstdp.d_reclen = sizeof(dstdp) - sizeof(dstdp.d_name) + | |||||
((dp->d_namlen + 1 + 3) &~ 3); | |||||
bcopy(dp->d_name, dstdp.d_name, dstdp.d_namlen); | |||||
bzero(dstdp.d_name + dstdp.d_namlen, | |||||
dstdp.d_reclen - offsetof(struct freebsd11_dirent, d_name) - | |||||
dstdp.d_namlen); | |||||
MPASS(dstdp.d_reclen <= dp->d_reclen); | |||||
MPASS(ucount + dstdp.d_reclen <= count); | |||||
if (func != NULL) | |||||
func(&dstdp); | |||||
error = copyout(&dstdp, ubuf + ucount, dstdp.d_reclen); | |||||
if (error != 0) | |||||
break; | |||||
dp = (struct dirent *)((char *)dp + dp->d_reclen); | |||||
ucount += dstdp.d_reclen; | |||||
} | |||||
done: | |||||
free(dirbuf, M_TEMP); | |||||
if (error == 0) | |||||
td->td_retval[0] = ucount; | |||||
return (error); | |||||
} | |||||
#endif /* COMPAT */ | |||||
#ifdef COMPAT_43 | #ifdef COMPAT_43 | ||||
static void | |||||
ogetdirentries_cvt(struct freebsd11_dirent *dp) | |||||
{ | |||||
#if (BYTE_ORDER == LITTLE_ENDIAN) | |||||
/* | /* | ||||
* The expected low byte of dp->d_namlen is our dp->d_type. | |||||
* The high MBZ byte of dp->d_namlen is our dp->d_namlen. | |||||
*/ | |||||
dp->d_type = dp->d_namlen; | |||||
dp->d_namlen = 0; | |||||
#else | |||||
/* | |||||
* The dp->d_type is the high byte of the expected dp->d_namlen, | |||||
* so must be zero'ed. | |||||
*/ | |||||
dp->d_type = 0; | |||||
#endif | |||||
} | |||||
/* | |||||
* Read a block of directory entries in a filesystem independent format. | * Read a block of directory entries in a filesystem independent format. | ||||
*/ | */ | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct ogetdirentries_args { | struct ogetdirentries_args { | ||||
int fd; | int fd; | ||||
char *buf; | char *buf; | ||||
u_int count; | u_int count; | ||||
long *basep; | long *basep; | ||||
Show All 10 Lines | if (error == 0) | ||||
error = copyout(&loff, uap->basep, sizeof(long)); | error = copyout(&loff, uap->basep, sizeof(long)); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap, | kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap, | ||||
long *ploff) | long *ploff) | ||||
{ | { | ||||
struct vnode *vp; | long base; | ||||
struct file *fp; | int error; | ||||
struct uio auio, kuio; | |||||
struct iovec aiov, kiov; | |||||
struct dirent *dp, *edp; | |||||
cap_rights_t rights; | |||||
caddr_t dirbuf; | |||||
int error, eofflag, readcnt; | |||||
long loff; | |||||
off_t foffset; | |||||
/* XXX arbitrary sanity limit on `count'. */ | /* XXX arbitrary sanity limit on `count'. */ | ||||
if (uap->count > 64 * 1024) | if (uap->count > 64 * 1024) | ||||
return (EINVAL); | return (EINVAL); | ||||
error = getvnode(td, uap->fd, cap_rights_init(&rights, CAP_READ), &fp); | |||||
if (error != 0) | error = freebsd11_kern_getdirentries(td, uap->fd, uap->buf, uap->count, | ||||
&base, ogetdirentries_cvt); | |||||
if (error == 0 && uap->basep != NULL) | |||||
error = copyout(&base, uap->basep, sizeof(long)); | |||||
return (error); | return (error); | ||||
if ((fp->f_flag & FREAD) == 0) { | |||||
fdrop(fp, td); | |||||
return (EBADF); | |||||
} | } | ||||
vp = fp->f_vnode; | |||||
foffset = foffset_lock(fp, 0); | |||||
unionread: | |||||
if (vp->v_type != VDIR) { | |||||
foffset_unlock(fp, foffset, 0); | |||||
fdrop(fp, td); | |||||
return (EINVAL); | |||||
} | |||||
aiov.iov_base = uap->buf; | |||||
aiov.iov_len = uap->count; | |||||
auio.uio_iov = &aiov; | |||||
auio.uio_iovcnt = 1; | |||||
auio.uio_rw = UIO_READ; | |||||
auio.uio_segflg = UIO_USERSPACE; | |||||
auio.uio_td = td; | |||||
auio.uio_resid = uap->count; | |||||
vn_lock(vp, LK_SHARED | LK_RETRY); | |||||
loff = auio.uio_offset = foffset; | |||||
#ifdef MAC | |||||
error = mac_vnode_check_readdir(td->td_ucred, vp); | |||||
if (error != 0) { | |||||
VOP_UNLOCK(vp, 0); | |||||
foffset_unlock(fp, foffset, FOF_NOUPDATE); | |||||
fdrop(fp, td); | |||||
return (error); | |||||
} | |||||
#endif | |||||
# if (BYTE_ORDER != LITTLE_ENDIAN) | |||||
if (vp->v_mount->mnt_maxsymlinklen <= 0) { | |||||
error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, | |||||
NULL, NULL); | |||||
foffset = auio.uio_offset; | |||||
} else | |||||
# endif | |||||
{ | |||||
kuio = auio; | |||||
kuio.uio_iov = &kiov; | |||||
kuio.uio_segflg = UIO_SYSSPACE; | |||||
kiov.iov_len = uap->count; | |||||
dirbuf = malloc(uap->count, M_TEMP, M_WAITOK); | |||||
kiov.iov_base = dirbuf; | |||||
error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, | |||||
NULL, NULL); | |||||
foffset = kuio.uio_offset; | |||||
if (error == 0) { | |||||
readcnt = uap->count - kuio.uio_resid; | |||||
edp = (struct dirent *)&dirbuf[readcnt]; | |||||
for (dp = (struct dirent *)dirbuf; dp < edp; ) { | |||||
# if (BYTE_ORDER == LITTLE_ENDIAN) | |||||
/* | |||||
* The expected low byte of | |||||
* dp->d_namlen is our dp->d_type. | |||||
* The high MBZ byte of dp->d_namlen | |||||
* is our dp->d_namlen. | |||||
*/ | |||||
dp->d_type = dp->d_namlen; | |||||
dp->d_namlen = 0; | |||||
# else | |||||
/* | |||||
* The dp->d_type is the high byte | |||||
* of the expected dp->d_namlen, | |||||
* so must be zero'ed. | |||||
*/ | |||||
dp->d_type = 0; | |||||
# endif | |||||
if (dp->d_reclen > 0) { | |||||
dp = (struct dirent *) | |||||
((char *)dp + dp->d_reclen); | |||||
} else { | |||||
error = EIO; | |||||
break; | |||||
} | |||||
} | |||||
if (dp >= edp) | |||||
error = uiomove(dirbuf, readcnt, &auio); | |||||
} | |||||
free(dirbuf, M_TEMP); | |||||
} | |||||
if (error != 0) { | |||||
VOP_UNLOCK(vp, 0); | |||||
foffset_unlock(fp, foffset, 0); | |||||
fdrop(fp, td); | |||||
return (error); | |||||
} | |||||
if (uap->count == auio.uio_resid && | |||||
(vp->v_vflag & VV_ROOT) && | |||||
(vp->v_mount->mnt_flag & MNT_UNION)) { | |||||
struct vnode *tvp = vp; | |||||
vp = vp->v_mount->mnt_vnodecovered; | |||||
VREF(vp); | |||||
fp->f_vnode = vp; | |||||
fp->f_data = vp; | |||||
foffset = 0; | |||||
vput(tvp); | |||||
goto unionread; | |||||
} | |||||
VOP_UNLOCK(vp, 0); | |||||
foffset_unlock(fp, foffset, 0); | |||||
fdrop(fp, td); | |||||
td->td_retval[0] = uap->count - auio.uio_resid; | |||||
if (error == 0) | |||||
*ploff = loff; | |||||
return (error); | |||||
} | |||||
#endif /* COMPAT_43 */ | #endif /* COMPAT_43 */ | ||||
/* | #if defined(COMPAT_FREEBSD11) | ||||
* Read a block of directory entries in a filesystem independent format. | |||||
*/ | |||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct getdirentries_args { | struct freebsd11_getdirentries_args { | ||||
int fd; | int fd; | ||||
char *buf; | char *buf; | ||||
u_int count; | u_int count; | ||||
long *basep; | long *basep; | ||||
}; | }; | ||||
#endif | #endif | ||||
int | int | ||||
sys_getdirentries(td, uap) | freebsd11_getdirentries(struct thread *td, | ||||
struct thread *td; | struct freebsd11_getdirentries_args *uap) | ||||
register struct getdirentries_args /* { | |||||
int fd; | |||||
char *buf; | |||||
u_int count; | |||||
long *basep; | |||||
} */ *uap; | |||||
{ | { | ||||
long base; | long base; | ||||
int error; | int error; | ||||
error = freebsd11_kern_getdirentries(td, uap->fd, uap->buf, uap->count, | |||||
&base, NULL); | |||||
if (error == 0 && uap->basep != NULL) | |||||
error = copyout(&base, uap->basep, sizeof(long)); | |||||
return (error); | |||||
} | |||||
int | |||||
freebsd11_getdents(struct thread *td, struct freebsd11_getdents_args *uap) | |||||
{ | |||||
struct freebsd11_getdirentries_args ap; | |||||
ap.fd = uap->fd; | |||||
ap.buf = uap->buf; | |||||
ap.count = uap->count; | |||||
ap.basep = NULL; | |||||
return (freebsd11_getdirentries(td, &ap)); | |||||
} | |||||
#endif /* COMPAT_FREEBSD11 */ | |||||
/* | |||||
* Read a block of directory entries in a filesystem independent format. | |||||
*/ | |||||
int | |||||
sys_getdirentries(struct thread *td, struct getdirentries_args *uap) | |||||
{ | |||||
off_t base; | |||||
int error; | |||||
error = kern_getdirentries(td, uap->fd, uap->buf, uap->count, &base, | error = kern_getdirentries(td, uap->fd, uap->buf, uap->count, &base, | ||||
NULL, UIO_USERSPACE); | NULL, UIO_USERSPACE); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
if (uap->basep != NULL) | if (uap->basep != NULL) | ||||
error = copyout(&base, uap->basep, sizeof(long)); | error = copyout(&base, uap->basep, sizeof(off_t)); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
kern_getdirentries(struct thread *td, int fd, char *buf, u_int count, | kern_getdirentries(struct thread *td, int fd, char *buf, size_t count, | ||||
long *basep, ssize_t *residp, enum uio_seg bufseg) | off_t *basep, ssize_t *residp, enum uio_seg bufseg) | ||||
{ | { | ||||
struct vnode *vp; | struct vnode *vp; | ||||
struct file *fp; | struct file *fp; | ||||
struct uio auio; | struct uio auio; | ||||
struct iovec aiov; | struct iovec aiov; | ||||
cap_rights_t rights; | cap_rights_t rights; | ||||
long loff; | off_t loff; | ||||
int error, eofflag; | int error, eofflag; | ||||
off_t foffset; | off_t foffset; | ||||
AUDIT_ARG_FD(fd); | AUDIT_ARG_FD(fd); | ||||
if (count > IOSIZE_MAX) | if (count > IOSIZE_MAX) | ||||
return (EINVAL); | return (EINVAL); | ||||
auio.uio_resid = count; | auio.uio_resid = count; | ||||
error = getvnode(td, fd, cap_rights_init(&rights, CAP_READ), &fp); | error = getvnode(td, fd, cap_rights_init(&rights, CAP_READ), &fp); | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | #endif | ||||
*basep = loff; | *basep = loff; | ||||
if (residp != NULL) | if (residp != NULL) | ||||
*residp = auio.uio_resid; | *residp = auio.uio_resid; | ||||
td->td_retval[0] = count - auio.uio_resid; | td->td_retval[0] = count - auio.uio_resid; | ||||
fail: | fail: | ||||
foffset_unlock(fp, foffset, 0); | foffset_unlock(fp, foffset, 0); | ||||
fdrop(fp, td); | fdrop(fp, td); | ||||
return (error); | return (error); | ||||
} | |||||
#ifndef _SYS_SYSPROTO_H_ | |||||
struct getdents_args { | |||||
int fd; | |||||
char *buf; | |||||
size_t count; | |||||
}; | |||||
#endif | |||||
int | |||||
sys_getdents(td, uap) | |||||
struct thread *td; | |||||
register struct getdents_args /* { | |||||
int fd; | |||||
char *buf; | |||||
u_int count; | |||||
} */ *uap; | |||||
{ | |||||
struct getdirentries_args ap; | |||||
ap.fd = uap->fd; | |||||
ap.buf = uap->buf; | |||||
ap.count = uap->count; | |||||
ap.basep = NULL; | |||||
return (sys_getdirentries(td, &ap)); | |||||
} | } | ||||
/* | /* | ||||
* Set the mode mask for creation of filesystem nodes. | * Set the mode mask for creation of filesystem nodes. | ||||
*/ | */ | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct umask_args { | struct umask_args { | ||||
int newmask; | int newmask; | ||||
▲ Show 20 Lines • Show All 629 Lines • Show Last 20 Lines |
Could this be committed separately?