Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/vfs_syscalls.c
Show First 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
u_int64_t res; | u_int64_t res; | ||||
MPASS((at_flags & (AT_SYMLINK_FOLLOW | AT_SYMLINK_NOFOLLOW)) != | MPASS((at_flags & (AT_SYMLINK_FOLLOW | AT_SYMLINK_NOFOLLOW)) != | ||||
(AT_SYMLINK_FOLLOW | AT_SYMLINK_NOFOLLOW)); | (AT_SYMLINK_FOLLOW | AT_SYMLINK_NOFOLLOW)); | ||||
res = 0; | res = 0; | ||||
at_flags &= mask; | at_flags &= mask; | ||||
if ((at_flags & AT_BENEATH) != 0) | |||||
res |= BENEATH; | |||||
if ((at_flags & AT_RESOLVE_BENEATH) != 0) | if ((at_flags & AT_RESOLVE_BENEATH) != 0) | ||||
res |= RBENEATH; | res |= RBENEATH; | ||||
if ((at_flags & AT_SYMLINK_FOLLOW) != 0) | if ((at_flags & AT_SYMLINK_FOLLOW) != 0) | ||||
res |= FOLLOW; | res |= FOLLOW; | ||||
/* NOFOLLOW is pseudo flag */ | /* NOFOLLOW is pseudo flag */ | ||||
if ((mask & AT_SYMLINK_NOFOLLOW) != 0) { | if ((mask & AT_SYMLINK_NOFOLLOW) != 0) { | ||||
res |= (at_flags & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW : | res |= (at_flags & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW : | ||||
FOLLOW; | FOLLOW; | ||||
▲ Show 20 Lines • Show All 1,360 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 | | if ((flag & ~(AT_SYMLINK_FOLLOW | AT_RESOLVE_BENEATH)) != 0) | ||||
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, at2cnpflags(flag, AT_SYMLINK_FOLLOW | AT_BENEATH | | UIO_USERSPACE, at2cnpflags(flag, AT_SYMLINK_FOLLOW | | ||||
AT_RESOLVE_BENEATH))); | 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"); | ||||
▲ Show 20 Lines • Show All 353 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 | | ||||
at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH), | at2cnpflags(flag, 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 188 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 | AT_RESOLVE_BENEATH)) != 0) | if ((flag & ~(AT_EACCESS | 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 | at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH), | AUDITVNODE1 | at2cnpflags(flag, 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_NOTHING(&nd); | NDFREE_NOTHING(&nd); | ||||
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 | | if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH)) != 0) | ||||
AT_RESOLVE_BENEATH)) != 0) | |||||
return (EINVAL); | return (EINVAL); | ||||
NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_BENEATH | | NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_RESOLVE_BENEATH | | ||||
AT_RESOLVE_BENEATH | AT_SYMLINK_NOFOLLOW) | LOCKSHARED | LOCKLEAF | | AT_SYMLINK_NOFOLLOW) | LOCKSHARED | LOCKLEAF | AUDITVNODE1, | ||||
AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights, td); | pathseg, path, fd, &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 | | if ((uap->atflag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH)) != 0) | ||||
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 16 Lines | |||||
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; | int error; | ||||
AUDIT_ARG_FFLAGS(flags); | AUDIT_ARG_FFLAGS(flags); | ||||
NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(atflag, AT_SYMLINK_NOFOLLOW | | NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(atflag, AT_SYMLINK_NOFOLLOW | | ||||
AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd, | AT_RESOLVE_BENEATH) | 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_NOTHING(&nd); | NDFREE_NOTHING(&nd); | ||||
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 | | if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH)) != 0) | ||||
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 16 Lines | |||||
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; | int error; | ||||
AUDIT_ARG_MODE(mode); | AUDIT_ARG_MODE(mode); | ||||
NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | | NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | | ||||
AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd, | AT_RESOLVE_BENEATH) | 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_NOTHING(&nd); | NDFREE_NOTHING(&nd); | ||||
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 | | if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH)) != 0) | ||||
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; | int error; | ||||
AUDIT_ARG_OWNER(uid, gid); | AUDIT_ARG_OWNER(uid, gid); | ||||
NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | | NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | | ||||
AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd, | AT_RESOLVE_BENEATH) | 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_NOTHING(&nd); | NDFREE_NOTHING(&nd); | ||||
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 | | if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH)) != 0) | ||||
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, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | | NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | | ||||
AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, | 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 470 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 | | ||||
at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH), | at2cnpflags(flag, 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 470 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 | | if ((uap->flags & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH)) != 0) | ||||
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, UIO_USERSPACE)); | uap->fhp, UIO_USERSPACE)); | ||||
} | } | ||||
int | 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 fhseg) | enum uio_seg pathseg, fhandle_t *fhp, enum uio_seg fhseg) | ||||
{ | { | ||||
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, at2cnpflags(flags, AT_SYMLINK_NOFOLLOW | | NDINIT_AT(&nd, LOOKUP, at2cnpflags(flags, AT_SYMLINK_NOFOLLOW | | ||||
AT_BENEATH | AT_RESOLVE_BENEATH) | LOCKLEAF | AUDITVNODE1, | AT_RESOLVE_BENEATH) | LOCKLEAF | AUDITVNODE1, pathseg, path, | ||||
pathseg, path, fd, td); | fd, td); | ||||
error = namei(&nd); | error = namei(&nd); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
NDFREE_NOTHING(&nd); | NDFREE_NOTHING(&nd); | ||||
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 580 Lines • Show Last 20 Lines |