Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/vfs_syscalls.c
Show First 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | static int kern_fhlinkat(struct thread *td, int fd, const char *path, | ||||
enum uio_seg pathseg, fhandle_t *fhp); | enum uio_seg pathseg, fhandle_t *fhp); | ||||
static int kern_getfhat(struct thread *td, int flags, int fd, | static int kern_getfhat(struct thread *td, int flags, int fd, | ||||
const char *path, enum uio_seg pathseg, fhandle_t *fhp); | const char *path, enum uio_seg pathseg, fhandle_t *fhp); | ||||
static int kern_readlink_vp(struct vnode *vp, char *buf, enum uio_seg bufseg, | static int kern_readlink_vp(struct vnode *vp, char *buf, enum uio_seg bufseg, | ||||
size_t count, struct thread *td); | size_t count, struct thread *td); | ||||
static int kern_linkat_vp(struct thread *td, struct vnode *vp, int fd, | static int kern_linkat_vp(struct thread *td, struct vnode *vp, int fd, | ||||
const char *path, enum uio_seg segflag); | const char *path, enum uio_seg segflag); | ||||
static uint64_t | |||||
markj: uint64_t | |||||
Done Inline ActionsI kept the type of ck_flags. I think this should be same even syntaxically. OTOH, I can change all of them. kib: I kept the type of ck_flags. I think this should be same even syntaxically.
OTOH, I can… | |||||
at2cnpflags(u_int at_flags, u_int mask) | |||||
Done Inline Actionsat2cnpflags() might be more clear to a casual reader. markj: at2cnpflags() might be more clear to a casual reader. | |||||
{ | |||||
u_int64_t res; | |||||
res = 0; | |||||
at_flags &= mask; | |||||
if ((at_flags & AT_BENEATH) != 0) | |||||
res |= BENEATH; | |||||
if ((at_flags & AT_RESOLVE_BENEATH) != 0) | |||||
res |= RBENEATH; | |||||
/* FOLLOW is pseudo flag */ | |||||
if ((at_flags & AT_SYMLINK_NOFOLLOW) != 0) | |||||
res |= NOFOLLOW; | |||||
if ((mask & AT_SYMLINK_FOLLOW) != 0 && | |||||
(at_flags & AT_SYMLINK_FOLLOW) == 0) | |||||
res |= NOFOLLOW; | |||||
return (res); | |||||
} | |||||
int | int | ||||
kern_sync(struct thread *td) | kern_sync(struct thread *td) | ||||
{ | { | ||||
struct mount *mp, *nmp; | struct mount *mp, *nmp; | ||||
int save; | int save; | ||||
mtx_lock(&mountlist_mtx); | mtx_lock(&mountlist_mtx); | ||||
for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { | for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { | ||||
▲ Show 20 Lines • Show All 1,008 Lines • ▼ Show 20 Lines | if (error != 0) { | ||||
/* | /* | ||||
* Handle special fdopen() case. bleh. | * Handle special fdopen() case. bleh. | ||||
* | * | ||||
* Don't do this for relative (capability) lookups; we don't | * Don't do this for relative (capability) lookups; we don't | ||||
* understand exactly what would happen, and we don't think | * understand exactly what would happen, and we don't think | ||||
* that it ever should. | * that it ever should. | ||||
*/ | */ | ||||
if ((nd.ni_lcf & NI_LCF_STRICTRELATIVE) == 0 && | if ((nd.ni_resflags & NIRES_STRICTREL) == 0 && | ||||
(error == ENODEV || error == ENXIO) && | (error == ENODEV || error == ENXIO) && | ||||
td->td_dupfd >= 0) { | td->td_dupfd >= 0) { | ||||
error = dupfdopen(td, fdp, td->td_dupfd, flags, error, | error = dupfdopen(td, fdp, td->td_dupfd, flags, error, | ||||
&indx); | &indx); | ||||
if (error == 0) | if (error == 0) | ||||
goto success; | goto success; | ||||
} | } | ||||
Show All 30 Lines | |||||
success: | success: | ||||
/* | /* | ||||
* If we haven't already installed the FD (for dupfdopen), do so now. | * If we haven't already installed the FD (for dupfdopen), do so now. | ||||
*/ | */ | ||||
if (indx == -1) { | if (indx == -1) { | ||||
struct filecaps *fcaps; | struct filecaps *fcaps; | ||||
#ifdef CAPABILITIES | #ifdef CAPABILITIES | ||||
if ((nd.ni_lcf & NI_LCF_STRICTRELATIVE) != 0) | if ((nd.ni_resflags & NIRES_STRICTREL) != 0) | ||||
fcaps = &nd.ni_filecaps; | fcaps = &nd.ni_filecaps; | ||||
else | else | ||||
#endif | #endif | ||||
fcaps = NULL; | fcaps = NULL; | ||||
error = finstall(td, fp, &indx, flags, fcaps); | error = finstall(td, fp, &indx, flags, fcaps); | ||||
/* On success finstall() consumes fcaps. */ | /* On success finstall() consumes fcaps. */ | ||||
if (error != 0) { | if (error != 0) { | ||||
filecaps_free(&nd.ni_filecaps); | filecaps_free(&nd.ni_filecaps); | ||||
▲ Show 20 Lines • Show All 284 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
#endif | #endif | ||||
int | int | ||||
sys_linkat(struct thread *td, struct linkat_args *uap) | sys_linkat(struct thread *td, struct linkat_args *uap) | ||||
{ | { | ||||
int flag; | int flag; | ||||
flag = uap->flag; | flag = uap->flag; | ||||
if ((flag & ~(AT_SYMLINK_FOLLOW | AT_BENEATH)) != 0) | if ((flag & ~(AT_SYMLINK_FOLLOW | AT_BENEATH | | ||||
AT_RESOLVE_BENEATH)) != 0) | |||||
return (EINVAL); | return (EINVAL); | ||||
return (kern_linkat(td, uap->fd1, uap->fd2, uap->path1, uap->path2, | return (kern_linkat(td, uap->fd1, uap->fd2, uap->path1, uap->path2, | ||||
UIO_USERSPACE, ((flag & AT_SYMLINK_FOLLOW) != 0 ? FOLLOW : | UIO_USERSPACE, at2cnpflags(flag, AT_SYMLINK_FOLLOW | AT_BENEATH | | ||||
NOFOLLOW) | ((flag & AT_BENEATH) != 0 ? BENEATH : 0))); | AT_RESOLVE_BENEATH))); | ||||
} | } | ||||
int hardlink_check_uid = 0; | int hardlink_check_uid = 0; | ||||
SYSCTL_INT(_security_bsd, OID_AUTO, hardlink_check_uid, CTLFLAG_RW, | SYSCTL_INT(_security_bsd, OID_AUTO, hardlink_check_uid, CTLFLAG_RW, | ||||
&hardlink_check_uid, 0, | &hardlink_check_uid, 0, | ||||
"Unprivileged processes cannot create hard links to files owned by other " | "Unprivileged processes cannot create hard links to files owned by other " | ||||
"users"); | "users"); | ||||
static int hardlink_check_gid = 0; | static int hardlink_check_gid = 0; | ||||
▲ Show 20 Lines • Show All 348 Lines • ▼ Show 20 Lines | if (fd != FD_NONE) { | ||||
error = getvnode(td, fd, &cap_no_rights, &fp); | error = getvnode(td, fd, &cap_no_rights, &fp); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
} | } | ||||
restart: | restart: | ||||
bwillwrite(); | bwillwrite(); | ||||
NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 | | NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 | | ||||
((flag & AT_BENEATH) != 0 ? BENEATH : 0), | at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH), | ||||
pathseg, path, dfd, &cap_unlinkat_rights, td); | pathseg, path, dfd, &cap_unlinkat_rights, td); | ||||
if ((error = namei(&nd)) != 0) { | if ((error = namei(&nd)) != 0) { | ||||
if (error == EINVAL) | if (error == EINVAL) | ||||
error = EPERM; | error = EPERM; | ||||
goto fdout; | goto fdout; | ||||
} | } | ||||
vp = nd.ni_vp; | vp = nd.ni_vp; | ||||
if (vp->v_type == VDIR && oldinum == 0) { | if (vp->v_type == VDIR && oldinum == 0) { | ||||
▲ Show 20 Lines • Show All 186 Lines • ▼ Show 20 Lines | |||||
kern_accessat(struct thread *td, int fd, const char *path, | kern_accessat(struct thread *td, int fd, const char *path, | ||||
enum uio_seg pathseg, int flag, int amode) | enum uio_seg pathseg, int flag, int amode) | ||||
{ | { | ||||
struct ucred *cred, *usecred; | struct ucred *cred, *usecred; | ||||
struct vnode *vp; | struct vnode *vp; | ||||
struct nameidata nd; | struct nameidata nd; | ||||
int error; | int error; | ||||
if ((flag & ~(AT_EACCESS | AT_BENEATH)) != 0) | if ((flag & ~(AT_EACCESS | AT_BENEATH | AT_RESOLVE_BENEATH)) != 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (amode != F_OK && (amode & ~(R_OK | W_OK | X_OK)) != 0) | if (amode != F_OK && (amode & ~(R_OK | W_OK | X_OK)) != 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
/* | /* | ||||
* Create and modify a temporary credential instead of one that | * Create and modify a temporary credential instead of one that | ||||
* is potentially shared (if we need one). | * is potentially shared (if we need one). | ||||
*/ | */ | ||||
cred = td->td_ucred; | cred = td->td_ucred; | ||||
if ((flag & AT_EACCESS) == 0 && | if ((flag & AT_EACCESS) == 0 && | ||||
((cred->cr_uid != cred->cr_ruid || | ((cred->cr_uid != cred->cr_ruid || | ||||
cred->cr_rgid != cred->cr_groups[0]))) { | cred->cr_rgid != cred->cr_groups[0]))) { | ||||
usecred = crdup(cred); | usecred = crdup(cred); | ||||
usecred->cr_uid = cred->cr_ruid; | usecred->cr_uid = cred->cr_ruid; | ||||
usecred->cr_groups[0] = cred->cr_rgid; | usecred->cr_groups[0] = cred->cr_rgid; | ||||
td->td_ucred = usecred; | td->td_ucred = usecred; | ||||
} else | } else | ||||
usecred = cred; | usecred = cred; | ||||
AUDIT_ARG_VALUE(amode); | AUDIT_ARG_VALUE(amode); | ||||
NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | | NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | | ||||
AUDITVNODE1 | ((flag & AT_BENEATH) != 0 ? BENEATH : 0), | AUDITVNODE1 | at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH), | ||||
pathseg, path, fd, &cap_fstat_rights, td); | pathseg, path, fd, &cap_fstat_rights, td); | ||||
if ((error = namei(&nd)) != 0) | if ((error = namei(&nd)) != 0) | ||||
goto out; | goto out; | ||||
vp = nd.ni_vp; | vp = nd.ni_vp; | ||||
error = vn_access(vp, amode, usecred, td); | error = vn_access(vp, amode, usecred, td); | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
vput(vp); | vput(vp); | ||||
▲ Show 20 Lines • Show All 274 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
kern_statat(struct thread *td, int flag, int fd, const char *path, | kern_statat(struct thread *td, int flag, int fd, const char *path, | ||||
enum uio_seg pathseg, struct stat *sbp, | enum uio_seg pathseg, struct stat *sbp, | ||||
void (*hook)(struct vnode *vp, struct stat *sbp)) | void (*hook)(struct vnode *vp, struct stat *sbp)) | ||||
{ | { | ||||
struct nameidata nd; | struct nameidata nd; | ||||
int error; | int error; | ||||
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0) | if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH | | ||||
AT_RESOLVE_BENEATH)) != 0) | |||||
return (EINVAL); | return (EINVAL); | ||||
NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) != 0 ? | NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_BENEATH | | ||||
NOFOLLOW : FOLLOW) | ((flag & AT_BENEATH) != 0 ? BENEATH : 0) | | AT_RESOLVE_BENEATH | AT_SYMLINK_NOFOLLOW) | LOCKSHARED | LOCKLEAF | | ||||
LOCKSHARED | LOCKLEAF | AUDITVNODE1, pathseg, path, fd, | AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights, td); | ||||
&cap_fstat_rights, td); | |||||
if ((error = namei(&nd)) != 0) | if ((error = namei(&nd)) != 0) | ||||
return (error); | return (error); | ||||
error = VOP_STAT(nd.ni_vp, sbp, td->td_ucred, NOCRED, td); | error = VOP_STAT(nd.ni_vp, sbp, td->td_ucred, NOCRED, td); | ||||
if (error == 0) { | if (error == 0) { | ||||
if (__predict_false(hook != NULL)) | if (__predict_false(hook != NULL)) | ||||
hook(nd.ni_vp, sbp); | hook(nd.ni_vp, sbp); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 301 Lines • ▼ Show 20 Lines | struct chflagsat_args { | ||||
u_long flags; | u_long flags; | ||||
int atflag; | int atflag; | ||||
} | } | ||||
#endif | #endif | ||||
int | int | ||||
sys_chflagsat(struct thread *td, struct chflagsat_args *uap) | sys_chflagsat(struct thread *td, struct chflagsat_args *uap) | ||||
{ | { | ||||
if ((uap->atflag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0) | if ((uap->atflag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH | | ||||
AT_RESOLVE_BENEATH)) != 0) | |||||
return (EINVAL); | return (EINVAL); | ||||
return (kern_chflagsat(td, uap->fd, uap->path, UIO_USERSPACE, | return (kern_chflagsat(td, uap->fd, uap->path, UIO_USERSPACE, | ||||
uap->flags, uap->atflag)); | uap->flags, uap->atflag)); | ||||
} | } | ||||
/* | /* | ||||
* Same as chflags() but doesn't follow symlinks. | * Same as chflags() but doesn't follow symlinks. | ||||
Show All 12 Lines | return (kern_chflagsat(td, AT_FDCWD, uap->path, UIO_USERSPACE, | ||||
uap->flags, AT_SYMLINK_NOFOLLOW)); | uap->flags, AT_SYMLINK_NOFOLLOW)); | ||||
} | } | ||||
static int | static int | ||||
kern_chflagsat(struct thread *td, int fd, const char *path, | kern_chflagsat(struct thread *td, int fd, const char *path, | ||||
enum uio_seg pathseg, u_long flags, int atflag) | enum uio_seg pathseg, u_long flags, int atflag) | ||||
{ | { | ||||
struct nameidata nd; | struct nameidata nd; | ||||
int error, follow; | int error; | ||||
AUDIT_ARG_FFLAGS(flags); | AUDIT_ARG_FFLAGS(flags); | ||||
follow = (atflag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; | NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(atflag, AT_SYMLINK_NOFOLLOW | | ||||
follow |= (atflag & AT_BENEATH) != 0 ? BENEATH : 0; | AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd, | ||||
NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd, | |||||
&cap_fchflags_rights, td); | &cap_fchflags_rights, td); | ||||
if ((error = namei(&nd)) != 0) | if ((error = namei(&nd)) != 0) | ||||
return (error); | return (error); | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
error = setfflags(td, nd.ni_vp, flags); | error = setfflags(td, nd.ni_vp, flags); | ||||
vrele(nd.ni_vp); | vrele(nd.ni_vp); | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | struct fchmodat_args { | ||||
mode_t mode; | mode_t mode; | ||||
int flag; | int flag; | ||||
} | } | ||||
#endif | #endif | ||||
int | int | ||||
sys_fchmodat(struct thread *td, struct fchmodat_args *uap) | sys_fchmodat(struct thread *td, struct fchmodat_args *uap) | ||||
{ | { | ||||
if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0) | if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH | | ||||
AT_RESOLVE_BENEATH)) != 0) | |||||
return (EINVAL); | return (EINVAL); | ||||
return (kern_fchmodat(td, uap->fd, uap->path, UIO_USERSPACE, | return (kern_fchmodat(td, uap->fd, uap->path, UIO_USERSPACE, | ||||
uap->mode, uap->flag)); | uap->mode, uap->flag)); | ||||
} | } | ||||
/* | /* | ||||
* Change mode of a file given path name (don't follow links.) | * Change mode of a file given path name (don't follow links.) | ||||
Show All 12 Lines | return (kern_fchmodat(td, AT_FDCWD, uap->path, UIO_USERSPACE, | ||||
uap->mode, AT_SYMLINK_NOFOLLOW)); | uap->mode, AT_SYMLINK_NOFOLLOW)); | ||||
} | } | ||||
int | int | ||||
kern_fchmodat(struct thread *td, int fd, const char *path, | kern_fchmodat(struct thread *td, int fd, const char *path, | ||||
enum uio_seg pathseg, mode_t mode, int flag) | enum uio_seg pathseg, mode_t mode, int flag) | ||||
{ | { | ||||
struct nameidata nd; | struct nameidata nd; | ||||
int error, follow; | int error; | ||||
AUDIT_ARG_MODE(mode); | AUDIT_ARG_MODE(mode); | ||||
follow = (flag & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW : FOLLOW; | NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | | ||||
follow |= (flag & AT_BENEATH) != 0 ? BENEATH : 0; | AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd, | ||||
NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd, | |||||
&cap_fchmod_rights, td); | &cap_fchmod_rights, td); | ||||
if ((error = namei(&nd)) != 0) | if ((error = namei(&nd)) != 0) | ||||
return (error); | return (error); | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
error = setfmode(td, td->td_ucred, nd.ni_vp, mode); | error = setfmode(td, td->td_ucred, nd.ni_vp, mode); | ||||
vrele(nd.ni_vp); | vrele(nd.ni_vp); | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | struct fchownat_args { | ||||
gid_t gid; | gid_t gid; | ||||
int flag; | int flag; | ||||
}; | }; | ||||
#endif | #endif | ||||
int | int | ||||
sys_fchownat(struct thread *td, struct fchownat_args *uap) | sys_fchownat(struct thread *td, struct fchownat_args *uap) | ||||
{ | { | ||||
if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0) | if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH | | ||||
AT_RESOLVE_BENEATH)) != 0) | |||||
return (EINVAL); | return (EINVAL); | ||||
return (kern_fchownat(td, uap->fd, uap->path, UIO_USERSPACE, uap->uid, | return (kern_fchownat(td, uap->fd, uap->path, UIO_USERSPACE, uap->uid, | ||||
uap->gid, uap->flag)); | uap->gid, uap->flag)); | ||||
} | } | ||||
int | int | ||||
kern_fchownat(struct thread *td, int fd, const char *path, | kern_fchownat(struct thread *td, int fd, const char *path, | ||||
enum uio_seg pathseg, int uid, int gid, int flag) | enum uio_seg pathseg, int uid, int gid, int flag) | ||||
{ | { | ||||
struct nameidata nd; | struct nameidata nd; | ||||
int error, follow; | int error; | ||||
AUDIT_ARG_OWNER(uid, gid); | AUDIT_ARG_OWNER(uid, gid); | ||||
follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; | NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | | ||||
follow |= (flag & AT_BENEATH) != 0 ? BENEATH : 0; | AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd, | ||||
NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd, | |||||
&cap_fchown_rights, td); | &cap_fchown_rights, td); | ||||
if ((error = namei(&nd)) != 0) | if ((error = namei(&nd)) != 0) | ||||
return (error); | return (error); | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
error = setfown(td, td->td_ucred, nd.ni_vp, uid, gid); | error = setfown(td, td->td_ucred, nd.ni_vp, uid, gid); | ||||
vrele(nd.ni_vp); | vrele(nd.ni_vp); | ||||
return (error); | return (error); | ||||
▲ Show 20 Lines • Show All 335 Lines • ▼ Show 20 Lines | |||||
kern_utimensat(struct thread *td, int fd, const char *path, | kern_utimensat(struct thread *td, int fd, const char *path, | ||||
enum uio_seg pathseg, struct timespec *tptr, enum uio_seg tptrseg, | enum uio_seg pathseg, struct timespec *tptr, enum uio_seg tptrseg, | ||||
int flag) | int flag) | ||||
{ | { | ||||
struct nameidata nd; | struct nameidata nd; | ||||
struct timespec ts[2]; | struct timespec ts[2]; | ||||
int error, flags; | int error, flags; | ||||
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0) | if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH | | ||||
AT_RESOLVE_BENEATH)) != 0) | |||||
return (EINVAL); | return (EINVAL); | ||||
if ((error = getutimens(tptr, tptrseg, ts, &flags)) != 0) | if ((error = getutimens(tptr, tptrseg, ts, &flags)) != 0) | ||||
return (error); | return (error); | ||||
NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : | NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | | ||||
FOLLOW) | ((flag & AT_BENEATH) != 0 ? BENEATH : 0) | AUDITVNODE1, | AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, | ||||
pathseg, path, fd, &cap_futimes_rights, td); | pathseg, path, fd, &cap_futimes_rights, td); | ||||
if ((error = namei(&nd)) != 0) | if ((error = namei(&nd)) != 0) | ||||
return (error); | return (error); | ||||
/* | /* | ||||
* We are allowed to call namei() regardless of 2xUTIME_OMIT. | * We are allowed to call namei() regardless of 2xUTIME_OMIT. | ||||
* POSIX states: | * POSIX states: | ||||
* "If both tv_nsec fields are UTIME_OMIT... EACCESS may be detected." | * "If both tv_nsec fields are UTIME_OMIT... EACCESS may be detected." | ||||
* "Search permission is denied by a component of the path prefix." | * "Search permission is denied by a component of the path prefix." | ||||
▲ Show 20 Lines • Show All 478 Lines • ▼ Show 20 Lines | error = getvnode(td, fd, cap_rights_init_one(&rights, CAP_LOOKUP), | ||||
&fp); | &fp); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
} | } | ||||
restart: | restart: | ||||
bwillwrite(); | bwillwrite(); | ||||
NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 | | NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 | | ||||
((flag & AT_BENEATH) != 0 ? BENEATH : 0), | at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH), | ||||
pathseg, path, dfd, &cap_unlinkat_rights, td); | pathseg, path, dfd, &cap_unlinkat_rights, td); | ||||
if ((error = namei(&nd)) != 0) | if ((error = namei(&nd)) != 0) | ||||
goto fdout; | goto fdout; | ||||
vp = nd.ni_vp; | vp = nd.ni_vp; | ||||
if (vp->v_type != VDIR) { | if (vp->v_type != VDIR) { | ||||
error = ENOTDIR; | error = ENOTDIR; | ||||
goto out; | goto out; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 469 Lines • ▼ Show 20 Lines | struct getfhat_args { | ||||
fhandle_t *fhp; | fhandle_t *fhp; | ||||
int flags; | int flags; | ||||
}; | }; | ||||
#endif | #endif | ||||
int | int | ||||
sys_getfhat(struct thread *td, struct getfhat_args *uap) | sys_getfhat(struct thread *td, struct getfhat_args *uap) | ||||
{ | { | ||||
if ((uap->flags & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0) | if ((uap->flags & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH | | ||||
AT_RESOLVE_BENEATH)) != 0) | |||||
return (EINVAL); | return (EINVAL); | ||||
return (kern_getfhat(td, uap->flags, uap->fd, uap->path, UIO_USERSPACE, | return (kern_getfhat(td, uap->flags, uap->fd, uap->path, UIO_USERSPACE, | ||||
uap->fhp)); | uap->fhp)); | ||||
} | } | ||||
static int | static int | ||||
kern_getfhat(struct thread *td, int flags, int fd, const char *path, | kern_getfhat(struct thread *td, int flags, int fd, const char *path, | ||||
enum uio_seg pathseg, fhandle_t *fhp) | enum uio_seg pathseg, fhandle_t *fhp) | ||||
{ | { | ||||
struct nameidata nd; | struct nameidata nd; | ||||
fhandle_t fh; | fhandle_t fh; | ||||
struct vnode *vp; | struct vnode *vp; | ||||
int error; | int error; | ||||
error = priv_check(td, PRIV_VFS_GETFH); | error = priv_check(td, PRIV_VFS_GETFH); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
NDINIT_AT(&nd, LOOKUP, ((flags & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW : | NDINIT_AT(&nd, LOOKUP, at2cnpflags(flags, AT_SYMLINK_NOFOLLOW | | ||||
FOLLOW) | ((flags & AT_BENEATH) != 0 ? BENEATH : 0) | LOCKLEAF | | AT_BENEATH | AT_RESOLVE_BENEATH) | LOCKLEAF | AUDITVNODE1, | ||||
AUDITVNODE1, pathseg, path, fd, td); | pathseg, path, fd, td); | ||||
error = namei(&nd); | error = namei(&nd); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
vp = nd.ni_vp; | vp = nd.ni_vp; | ||||
bzero(&fh, sizeof(fh)); | bzero(&fh, sizeof(fh)); | ||||
fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; | fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; | ||||
error = VOP_VPTOFH(vp, &fh.fh_fid); | error = VOP_VPTOFH(vp, &fh.fh_fid); | ||||
▲ Show 20 Lines • Show All 572 Lines • Show Last 20 Lines |
uint64_t