Index: sys/kern/vfs_lookup.c =================================================================== --- sys/kern/vfs_lookup.c (revision 205682) +++ 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; + 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; - } - if (cnp->cn_nameiop != LOOKUP) { - error = EISDIR; + case DELETE: + case RENAME: + error = EBUSY; goto bad; + default: + KASSERT(cnp->cn_nameiop == LOOKUP, + ("nameiop must be LOOKUP")); } if (wantparent) { ndp->ni_dvp = dp; Index: sys/kern/vfs_syscalls.c =================================================================== --- sys/kern/vfs_syscalls.c (revision 205679) +++ sys/kern/vfs_syscalls.c (working copy) @@ -1746,8 +1746,10 @@ restart: NDINIT(&nd, DELETE, LOCKPARENT | DOWHITEOUT | MPSAFE | AUDITVNODE1, UIO_USERSPACE, uap->path, td); error = namei(&nd); - if (error) - return (error); + if (error) { + /* Translate error code for undelete("/"). */ + return (error == EBUSY ? EEXIST : error); + } vfslocked = NDHASGIANT(&nd); if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { @@ -1842,7 +1844,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) { Index: sys/kern/vfs_vnops.c =================================================================== --- sys/kern/vfs_vnops.c (revision 205679) +++ sys/kern/vfs_vnops.c (working copy) @@ -127,8 +127,10 @@ restart: if (!(vn_open_flags & VN_OPEN_NOAUDIT)) ndp->ni_cnd.cn_flags |= AUDITVNODE1; bwillwrite(); - if ((error = namei(ndp)) != 0) - return (error); + if ((error = namei(ndp)) != 0) { + /* Translate error code for open("/", O_CREAT). */ + return (error == EEXIST ? EISDIR : error); + } vfslocked = NDHASGIANT(ndp); if (!mpsafe) ndp->ni_cnd.cn_flags &= ~MPSAFE; Index: lib/libc/sys/rename.2 =================================================================== --- lib/libc/sys/rename.2 (revision 205679) +++ lib/libc/sys/rename.2 (working copy) @@ -28,7 +28,7 @@ .\" @(#)rename.2 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd April 10, 2008 +.Dd March 26, 2010 .Dt RENAME 2 .Os .Sh NAME @@ -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 205679) +++ lib/libc/sys/unlink.2 (working copy) @@ -28,7 +28,7 @@ .\" @(#)unlink.2 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd April 10, 2008 +.Dd March 26, 2010 .Dt UNLINK 2 .Os .Sh NAME @@ -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. Index: share/man/man9/namei.9 =================================================================== --- share/man/man9/namei.9 (revision 205679) +++ share/man/man9/namei.9 (working copy) @@ -33,7 +33,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 21, 2005 +.Dd March 26, 2010 .Os .Dt NAMEI 9 .Sh NAME @@ -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