| 3808 | } |
| 3809 | |
| 3810 | int |
| 3811 | kern_frmdirat(struct thread *td, int dfd, const char *path, int fd, |
| 3812 | enum uio_seg pathseg, int flag) |
| 3813 | { |
| 3814 | struct mount *mp; |
| 3815 | struct vnode *vp; |
| 3816 | struct file *fp; |
| 3817 | struct nameidata nd; |
| 3818 | cap_rights_t rights; |
| 3819 | int error; |
| 3820 | |
| 3821 | fp = NULL; |
| 3822 | if (fd != FD_NONE) { |
| 3823 | error = getvnode(td, fd, cap_rights_init_one(&rights, CAP_LOOKUP), |
| 3824 | &fp); |
| 3825 | if (error != 0) |
| 3826 | return (error); |
| 3827 | } |
| 3828 | |
| 3829 | restart: |
| 3830 | bwillwrite(); |
| 3831 | NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 | |
| 3832 | at2cnpflags(flag, AT_RESOLVE_BENEATH), |
| 3833 | pathseg, path, dfd, &cap_unlinkat_rights, td); |
| 3834 | if ((error = namei(&nd)) != 0) |
| 3835 | goto fdout; |
| 3836 | vp = nd.ni_vp; |
| 3837 | if (vp->v_type != VDIR) { |
| 3838 | error = ENOTDIR; |
| 3839 | goto out; |
| 3840 | } |
| 3841 | /* |
| 3842 | * No rmdir "." please. |
| 3843 | */ |
| 3844 | if (nd.ni_dvp == vp) { |
| 3845 | error = EINVAL; |
| 3846 | goto out; |
| 3847 | } |
| 3848 | /* |
| 3849 | * The root of a mounted filesystem cannot be deleted. |
| 3850 | */ |
| 3851 | if (vp->v_vflag & VV_ROOT) { |
| 3852 | error = EBUSY; |
| 3853 | goto out; |
| 3854 | } |
| 3855 | |
| 3856 | if (fp != NULL && fp->f_vnode != vp) { |
| 3857 | if (VN_IS_DOOMED(fp->f_vnode)) |
| 3858 | error = EBADF; |
| 3859 | else |
| 3860 | error = EDEADLK; |
| 3861 | goto out; |
| 3862 | } |
| 3863 | |
| 3864 | #ifdef MAC |
| 3865 | error = mac_vnode_check_unlink(td->td_ucred, nd.ni_dvp, vp, |
| 3866 | &nd.ni_cnd); |
| 3867 | if (error != 0) |
no test coverage detected