Index: sys/kern/vfs_lookup.c =================================================================== --- sys/kern/vfs_lookup.c (revision 204273) +++ sys/kern/vfs_lookup.c (working copy) @@ -565,19 +565,22 @@ dirloop: } /* - * Check for degenerate name (e.g. / or "") - * which is a way of talking about a directory, - * e.g. like "/." or ".". + * Check for "" which is a way of talking about the root directory. + * We can't provide a parent node for CREATE, DELETE and RENAME + * operations. */ if (cnp->cn_nameptr[0] == '\0') { - if (dp->v_type != VDIR) { - error = ENOTDIR; + KASSERT(dp->v_type == VDIR, ("dp is not a directory")); + switch (cnp->cn_nameiop) { + case CREATE: + error = EEXIST; goto bad; - } - if (cnp->cn_nameiop != LOOKUP) { - error = EISDIR; + case DELETE: + case RENAME: + error = EBUSY; goto bad; } + KASSERT(cnp->cn_nameiop == LOOKUP, ("nameiop must be LOOKUP")); if (wantparent) { ndp->ni_dvp = dp; VREF(dp); @@ -948,19 +951,22 @@ relookup(struct vnode *dvp, struct vnode #endif /* - * Check for degenerate name (e.g. / or "") - * which is a way of talking about a directory, - * e.g. like "/." or ".". + * Check for "" which is a way of talking about the root directory. + * We can't provide a parent node for CREATE, DELETE and RENAME + * operations. */ if (cnp->cn_nameptr[0] == '\0') { - if (cnp->cn_nameiop != LOOKUP || wantparent) { - error = EISDIR; + KASSERT(dp->v_type == VDIR, ("dp is not a directory")); + switch (cnp->cn_nameiop) { + case CREATE: + error = EEXIST; goto bad; - } - if (dp->v_type != VDIR) { - error = ENOTDIR; + case DELETE: + case RENAME: + error = EBUSY; goto bad; } + KASSERT(cnp->cn_nameiop == LOOKUP, ("nameiop must be LOOKUP")); if (!(cnp->cn_flags & LOCKLEAF)) VOP_UNLOCK(dp, 0); *vpp = dp; Index: sys/kern/vfs_syscalls.c =================================================================== --- sys/kern/vfs_syscalls.c (revision 204273) +++ sys/kern/vfs_syscalls.c (working copy) @@ -1841,7 +1841,7 @@ restart: NDINIT_AT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1, pathseg, path, fd, td); if ((error = namei(&nd)) != 0) - return (error == EINVAL ? EPERM : error); + return ((error == EINVAL || error == EBUSY) ? EPERM : error); vfslocked = NDHASGIANT(&nd); vp = nd.ni_vp; if (vp->v_type == VDIR && oldinum == 0) { @@ -3618,9 +3618,6 @@ kern_renameat(struct thread *td, int old if (fromnd.ni_vp->v_type == VDIR) tond.ni_cnd.cn_flags |= WILLBEDIR; if ((error = namei(&tond)) != 0) { - /* Translate error code for rename("dir1", "dir2/."). */ - if (error == EISDIR && fvp->v_type == VDIR) - error = EINVAL; NDFREE(&fromnd, NDF_ONLY_PNBUF); vrele(fromnd.ni_dvp); vrele(fvp); Index: lib/libc/sys/rename.2 =================================================================== --- lib/libc/sys/rename.2 (revision 204273) +++ lib/libc/sys/rename.2 (working copy) @@ -252,6 +252,12 @@ The .Fa to argument is a directory and is not empty. +.It Bq Er EBUSY +Either +.Fa from +or +.Fa to +is the root directory. .El .Pp In addition to the errors returned by the Index: lib/libc/sys/unlink.2 =================================================================== --- lib/libc/sys/unlink.2 (revision 204273) +++ lib/libc/sys/unlink.2 (working copy) @@ -114,8 +114,6 @@ succeeds unless: .Bl -tag -width Er .It Bq Er ENOTDIR A component of the path prefix is not a directory. -.It Bq Er EISDIR -The named file is a directory. .It Bq Er ENAMETOOLONG A component of a pathname exceeded 255 characters, or an entire path name exceeded 1023 characters.