Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/vfs_syscalls.c
Show First 20 Lines • Show All 1,745 Lines • ▼ Show 20 Lines | |||||
struct unlink_args { | struct unlink_args { | ||||
char *path; | char *path; | ||||
}; | }; | ||||
#endif | #endif | ||||
int | int | ||||
sys_unlink(struct thread *td, struct unlink_args *uap) | sys_unlink(struct thread *td, struct unlink_args *uap) | ||||
{ | { | ||||
return (kern_unlinkat(td, AT_FDCWD, uap->path, UIO_USERSPACE, 0, 0)); | return (kern_funlinkat(td, AT_FDCWD, uap->path, FD_NONE, UIO_USERSPACE, | ||||
0, 0)); | |||||
} | } | ||||
static int | |||||
kern_funlinkat_ex(struct thread *td, int dfd, const char *path, int fd, | |||||
int flag, enum uio_seg pathseg, ino_t oldinum) | |||||
{ | |||||
if ((flag & ~AT_REMOVEDIR) != 0) | |||||
return (EINVAL); | |||||
if ((flag & AT_REMOVEDIR) != 0) | |||||
return (kern_frmdirat(td, dfd, path, fd, UIO_USERSPACE, 0)); | |||||
return (kern_funlinkat(td, dfd, path, fd, UIO_USERSPACE, 0, 0)); | |||||
} | |||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct unlinkat_args { | struct unlinkat_args { | ||||
int fd; | int fd; | ||||
char *path; | char *path; | ||||
int flag; | int flag; | ||||
}; | }; | ||||
#endif | #endif | ||||
int | int | ||||
sys_unlinkat(struct thread *td, struct unlinkat_args *uap) | sys_unlinkat(struct thread *td, struct unlinkat_args *uap) | ||||
{ | { | ||||
int fd, flag; | |||||
const char *path; | |||||
flag = uap->flag; | return (kern_funlinkat_ex(td, uap->fd, uap->path, FD_NONE, uap->flag, | ||||
fd = uap->fd; | UIO_USERSPACE, 0)); | ||||
path = uap->path; | } | ||||
if ((flag & ~(AT_REMOVEDIR | AT_BENEATH)) != 0) | #ifndef _SYS_SYSPROTO_H_ | ||||
return (EINVAL); | struct funlinkat_args { | ||||
int dfd; | |||||
const char *path; | |||||
int fd; | |||||
int flag; | |||||
}; | |||||
#endif | |||||
int | |||||
sys_funlinkat(struct thread *td, struct funlinkat_args *uap) | |||||
{ | |||||
if ((uap->flag & AT_REMOVEDIR) != 0) | return (kern_funlinkat_ex(td, uap->dfd, uap->path, uap->fd, uap->flag, | ||||
return (kern_rmdirat(td, fd, path, UIO_USERSPACE, flag)); | UIO_USERSPACE, 0)); | ||||
else | |||||
return (kern_unlinkat(td, fd, path, UIO_USERSPACE, flag, 0)); | |||||
} | } | ||||
int | int | ||||
kern_unlinkat(struct thread *td, int fd, const char *path, | kern_funlinkat(struct thread *td, int dfd, const char *path, int fd, | ||||
enum uio_seg pathseg, int flag, ino_t oldinum) | enum uio_seg pathseg, int flag, ino_t oldinum) | ||||
{ | { | ||||
struct mount *mp; | struct mount *mp; | ||||
struct file *fp; | |||||
struct vnode *vp; | struct vnode *vp; | ||||
struct nameidata nd; | struct nameidata nd; | ||||
struct stat sb; | struct stat sb; | ||||
cap_rights_t rights; | |||||
int error; | int error; | ||||
fp = NULL; | |||||
if (fd != FD_NONE) { | |||||
error = getvnode(td, fd, cap_rights_init(&rights, CAP_LOOKUP), | |||||
&fp); | |||||
if (error != 0) | |||||
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), | ((flag & AT_BENEATH) != 0 ? BENEATH : 0), | ||||
pathseg, path, fd, &cap_unlinkat_rights, td); | pathseg, path, dfd, &cap_unlinkat_rights, td); | ||||
if ((error = namei(&nd)) != 0) | if ((error = namei(&nd)) != 0) { | ||||
return (error == EINVAL ? EPERM : error); | if (error == EINVAL) | ||||
error = EPERM; | |||||
goto fdout; | |||||
} | |||||
vp = nd.ni_vp; | vp = nd.ni_vp; | ||||
if (vp->v_type == VDIR && oldinum == 0) { | if (vp->v_type == VDIR && oldinum == 0) { | ||||
error = EPERM; /* POSIX */ | error = EPERM; /* POSIX */ | ||||
} else if (oldinum != 0 && | } else if (oldinum != 0 && | ||||
((error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td)) == 0) && | ((error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td)) == 0) && | ||||
sb.st_ino != oldinum) { | sb.st_ino != oldinum) { | ||||
error = EIDRM; /* Identifier removed */ | error = EIDRM; /* Identifier removed */ | ||||
} else if (fp != NULL && fp->f_vnode != vp) { | |||||
if ((fp->f_vnode->v_iflag & VI_DOOMED) != 0) | |||||
error = EBADF; | |||||
else | |||||
error = EDEADLK; | |||||
} else { | } else { | ||||
/* | /* | ||||
* The root of a mounted filesystem cannot be deleted. | * The root of a mounted filesystem cannot be deleted. | ||||
* | * | ||||
* XXX: can this only be a VDIR case? | * XXX: can this only be a VDIR case? | ||||
*/ | */ | ||||
if (vp->v_vflag & VV_ROOT) | if (vp->v_vflag & VV_ROOT) | ||||
error = EBUSY; | error = EBUSY; | ||||
} | } | ||||
if (error == 0) { | if (error == 0) { | ||||
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { | if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
vput(nd.ni_dvp); | vput(nd.ni_dvp); | ||||
if (vp == nd.ni_dvp) | if (vp == nd.ni_dvp) | ||||
vrele(vp); | vrele(vp); | ||||
else | else | ||||
vput(vp); | vput(vp); | ||||
if ((error = vn_start_write(NULL, &mp, | if ((error = vn_start_write(NULL, &mp, | ||||
V_XSLEEP | PCATCH)) != 0) | V_XSLEEP | PCATCH)) != 0) { | ||||
return (error); | goto fdout; | ||||
} | |||||
goto restart; | goto restart; | ||||
} | } | ||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_vnode_check_unlink(td->td_ucred, nd.ni_dvp, vp, | error = mac_vnode_check_unlink(td->td_ucred, nd.ni_dvp, vp, | ||||
&nd.ni_cnd); | &nd.ni_cnd); | ||||
if (error != 0) | if (error != 0) | ||||
goto out; | goto out; | ||||
#endif | #endif | ||||
vfs_notify_upper(vp, VFS_NOTIFY_UPPER_UNLINK); | vfs_notify_upper(vp, VFS_NOTIFY_UPPER_UNLINK); | ||||
error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd); | error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd); | ||||
#ifdef MAC | #ifdef MAC | ||||
out: | out: | ||||
#endif | #endif | ||||
vn_finished_write(mp); | vn_finished_write(mp); | ||||
} | } | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
vput(nd.ni_dvp); | vput(nd.ni_dvp); | ||||
if (vp == nd.ni_dvp) | if (vp == nd.ni_dvp) | ||||
vrele(vp); | vrele(vp); | ||||
else | else | ||||
vput(vp); | vput(vp); | ||||
fdout: | |||||
if (fp != NULL) | |||||
fdrop(fp, td); | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Reposition read/write file offset. | * Reposition read/write file offset. | ||||
*/ | */ | ||||
#ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||
struct lseek_args { | struct lseek_args { | ||||
▲ Show 20 Lines • Show All 1,843 Lines • ▼ Show 20 Lines | |||||
struct rmdir_args { | struct rmdir_args { | ||||
char *path; | char *path; | ||||
}; | }; | ||||
#endif | #endif | ||||
int | int | ||||
sys_rmdir(struct thread *td, struct rmdir_args *uap) | sys_rmdir(struct thread *td, struct rmdir_args *uap) | ||||
{ | { | ||||
return (kern_rmdirat(td, AT_FDCWD, uap->path, UIO_USERSPACE, 0)); | return (kern_frmdirat(td, AT_FDCWD, uap->path, FD_NONE, UIO_USERSPACE, | ||||
0)); | |||||
} | } | ||||
int | int | ||||
kern_rmdirat(struct thread *td, int fd, const char *path, enum uio_seg pathseg, | kern_frmdirat(struct thread *td, int dfd, const char *path, int fd, | ||||
int flag) | enum uio_seg pathseg, int flag) | ||||
{ | { | ||||
struct mount *mp; | struct mount *mp; | ||||
struct vnode *vp; | struct vnode *vp; | ||||
struct file *fp; | |||||
struct nameidata nd; | struct nameidata nd; | ||||
cap_rights_t rights; | |||||
int error; | int error; | ||||
fp = NULL; | |||||
if (fd != FD_NONE) { | |||||
error = getvnode(td, fd, cap_rights_init(&rights, CAP_LOOKUP), | |||||
&fp); | |||||
if (error != 0) | |||||
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), | ((flag & AT_BENEATH) != 0 ? BENEATH : 0), | ||||
pathseg, path, fd, &cap_unlinkat_rights, td); | pathseg, path, dfd, &cap_unlinkat_rights, td); | ||||
if ((error = namei(&nd)) != 0) | if ((error = namei(&nd)) != 0) | ||||
return (error); | 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; | ||||
} | } | ||||
/* | /* | ||||
* No rmdir "." please. | * No rmdir "." please. | ||||
*/ | */ | ||||
if (nd.ni_dvp == vp) { | if (nd.ni_dvp == vp) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* | /* | ||||
* The root of a mounted filesystem cannot be deleted. | * The root of a mounted filesystem cannot be deleted. | ||||
*/ | */ | ||||
if (vp->v_vflag & VV_ROOT) { | if (vp->v_vflag & VV_ROOT) { | ||||
error = EBUSY; | error = EBUSY; | ||||
goto out; | goto out; | ||||
} | } | ||||
if (fp != NULL && fp->f_vnode != vp) { | |||||
if ((fp->f_vnode->v_iflag & VI_DOOMED) != 0) | |||||
error = EBADF; | |||||
else | |||||
error = EDEADLK; | |||||
goto out; | |||||
} | |||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_vnode_check_unlink(td->td_ucred, nd.ni_dvp, vp, | error = mac_vnode_check_unlink(td->td_ucred, nd.ni_dvp, vp, | ||||
&nd.ni_cnd); | &nd.ni_cnd); | ||||
if (error != 0) | if (error != 0) | ||||
goto out; | goto out; | ||||
#endif | #endif | ||||
if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { | if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
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); | ||||
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) | if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0) | ||||
return (error); | goto fdout; | ||||
goto restart; | goto restart; | ||||
} | } | ||||
vfs_notify_upper(vp, VFS_NOTIFY_UPPER_UNLINK); | vfs_notify_upper(vp, VFS_NOTIFY_UPPER_UNLINK); | ||||
error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); | error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); | ||||
vn_finished_write(mp); | vn_finished_write(mp); | ||||
out: | out: | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
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); | ||||
fdout: | |||||
if (fp != NULL) | |||||
fdrop(fp, td); | |||||
return (error); | return (error); | ||||
} | } | ||||
#if defined(COMPAT_43) || defined(COMPAT_FREEBSD11) | #if defined(COMPAT_43) || defined(COMPAT_FREEBSD11) | ||||
int | int | ||||
freebsd11_kern_getdirentries(struct thread *td, int fd, char *ubuf, u_int count, | freebsd11_kern_getdirentries(struct thread *td, int fd, char *ubuf, u_int count, | ||||
long *basep, void (*func)(struct freebsd11_dirent *)) | long *basep, void (*func)(struct freebsd11_dirent *)) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 974 Lines • Show Last 20 Lines |