Index: sys/kern/vfs_lookup.c =================================================================== --- sys/kern/vfs_lookup.c (revision 204620) +++ sys/kern/vfs_lookup.c (working copy) @@ -565,18 +565,26 @@ dirloop: } /* - * Check for degenerate name (e.g. / or "") - * which is a way of talking about a directory, - * e.g. like "/." or ".". + * Check for "" which represents the root directory after slash + * removal. */ if (cnp->cn_nameptr[0] == '\0') { - if (dp->v_type != VDIR) { - error = ENOTDIR; - goto bad; - } - if (cnp->cn_nameiop != LOOKUP) { - error = EISDIR; - goto bad; + KASSERT(dp->v_type == VDIR, ("dp is not a directory")); + /* + * We can't provide a parent node for CREATE, + * DELETE and RENAME operations. + */ + switch (cnp->cn_nameiop) { + case CREATE: + error = EEXIST; + goto bad; + case DELETE: + case RENAME: + error = EBUSY; + goto bad; + default: + KASSERT(cnp->cn_nameiop == LOOKUP, + ("nameiop must be LOOKUP")); } if (wantparent) { ndp->ni_dvp = dp; @@ -948,19 +956,17 @@ 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 represents the root directory after slash + * removal. */ if (cnp->cn_nameptr[0] == '\0') { - if (cnp->cn_nameiop != LOOKUP || wantparent) { - error = EISDIR; - goto bad; - } - if (dp->v_type != VDIR) { - error = ENOTDIR; - goto bad; - } + KASSERT(dp->v_type == VDIR, ("dp is not a directory")); + /* + * Support only LOOKUP for "/" because lookup() + * can't succeed for CREATE, DELETE and RENAME. + */ + 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 204620) +++ 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) { @@ -3617,9 +3617,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: share/man/man9/namei.9 =================================================================== --- share/man/man9/namei.9 (revision 204620) +++ share/man/man9/namei.9 (working copy) @@ -338,8 +338,17 @@ An attempt is made to access a file in a permissions. .It Bq Er ELOOP Too many symbolic links were encountered in translating the pathname. -.It Bq Er EISDIR -An attempt is made to open a directory with write mode specified. +.It Bq Er EINVAL +The last component of the pathname specified for the RENAME operation is +.Ql \&. . +.It Bq Er EEXIST +The root directory +.Pq Ql / +was specified for the CREATE operation. +.It Bq Er EBUSY +The root directory +.Pq Ql / +was specified for the DELETE operation. .It Bq Er EROFS An attempt is made to modify a file or directory on a read-only file system. .El Index: lib/libc/sys/rename.2 =================================================================== --- lib/libc/sys/rename.2 (revision 204620) +++ 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 204620) +++ 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.