rmdir(2) and mkdir(2) both return EISDIR for argument "/"
Alexander Best
alexbestms at math.uni-muenster.de
Fri Nov 6 21:09:59 UTC 2009
Gary Jennejohn schrieb am 2009-11-06:
> On Fri, 06 Nov 2009 17:43:06 +0100 (CET)
> Alexander Best <alexbestms at math.uni-muenster.de> wrote:
> > Gary Jennejohn schrieb am 2009-11-06:
> > > On Fri, 06 Nov 2009 16:32:22 +0100 (CET)
> > > Alexander Best <alexbestms at math.uni-muenster.de> wrote:
> > > > Alex Dupre schrieb am 2009-11-06:
> > > > > Alexander Best ha scritto:
> > > > > > i dug up this old pr
> > > > > > http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/59739
> > > > > I think the EISDIR error is coming from kern/vfs_lookup.c,
> > > > > lookup()
> > > > > function with cn_nameptr = "":
> > > > > /*
> > > > > * Check for degenerate name (e.g. / or "")
> > > > > * which is a way of talking about a directory,
> > > > > * e.g. like "/." or ".".
> > > > > */
> > > > > if (cnp->cn_nameptr[0] == '\0') {
> > > > > ...
> > > > > if (cnp->cn_nameiop != LOOKUP) {
> > > > > error = EISDIR;
> > > > > goto bad;
> > > > > }
> > > > > ...
> > > > thanks a lot for finding the problem in the src. what do you
> > > > think
> > > > of the
> > > > patch attached to this message? after applying it the example
> > > > code
> > > > i posted in
> > > > my previous message returns the following output (instead of
> > > > EISDIR):
> > > > rmdir errno: 16 (which is EBUSY)
> > > > mkdir errno: 17 (which is EEXIST)
> > > > i don't know if these really are the correct return values, but
> > > > it's what the
> > > > originator of the PR requested.
> > > What if cn_nameiop is != LOOKUP but also neither DELETE nor
> > > CREATE,
> > > assuming that case is possible? I'd leave the original if-clause
> > > at
> > > the end to catch that.
> > > ---
> > > Gary Jennejohn
> > how about this patch?
> > 1. i've added "if (cnp->cn_nameiop != LOOKUP)" although i don't
> > think it's
> > necessary since the first blocks should cover all the possible
> > cases.
> > 2. i've used rename() to test the case (cnp->cn_nameiop != RENAME).
> > is this
> > correct or does rename() use a combo of DELETE and CREATE? problem
> > is that the
> > rename(2) manual doesn't seem to cover the case that arg 1 is a
> > mountpoint.
> > right now EBUSY gets returned if cnp->cn_nameiop != RENAME. however
> > BUSY needs
> > to be added to all manuals which use cnp->cn_nameiop != RENAME
> > (shouldn't be
> > too many). or are there any other suggestions what rename() should
> > return if
> > arg 1 is a mountpoint?
> Hmm. In rename(2) there's
> [EINVAL] The from argument is a parent directory of to, or
> an
> attempt is made to rename `.' or `..'.
> and a few lines below your patch this case is handled for ISDOTDOT
> for both RENAME and DELETE. I don't see off hand where renaming or
> deleting "." is handled.
> According to the comment above your patch the case of "/." or "." is
> being checked, which would seem to correspond to the above part of
> rename(2), i.e. perhaps EINVAL should be returned for RENAME and
> DELETE.
> ---
> Gary Jennejohn
here's a completely new patch. all the changes are in kern/vfs_syscall.c. so
kern/vfs_lookup.c now stays just the way it is (please revert any changes from
the previous patches i posted).
after applying the patch this is the output from a slightly modified version
of the test app i attached in my very first post:
rmdir errno: 16 (EBUSY) <- EBUSY is required by POSIX
mkdir errno: 17 (EEXIST)
rename errno: 22 (EINVAL)
these are the results when called with "/" as arg. the output doesn't differ
if run with or without superuser privileges.
when run with "." as arg this is the output as regular user:
rmdir errno: 22 (EINVAL)
mkdir errno: 17 (EEXIST)
rename errno: 13 (EACCES)
and as superuser:
rmdir errno: 22 (EINVAL)
mkdir errno: 17 (EEXIST)
rename errno: 22 (EINVAL)
does this look reasonable? would be nice if mkdir and rmdir would also check
privileges at first like rename, but that's a different story i guess. ;)
alex
-------------- next part --------------
--- vfs_syscalls.c 2009-11-06 22:07:08.000000000 +0100
+++ /usr/src/sys/kern/vfs_syscalls.c 2009-11-06 21:37:47.000000000 +0100
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/kern/vfs_syscalls.c 196887 2009-09-06 11:44:46Z kib $");
#include "opt_compat.h"
#include "opt_kdtrace.h"
@@ -3587,8 +3587,12 @@
AUDITVNODE1, pathseg, old, oldfd, td);
#endif
- if ((error = namei(&fromnd)) != 0)
+ if ((error = namei(&fromnd)) != 0) {
+ /* Translate error code for rename("/", "dir2"). */
+ if (error == EISDIR)
+ error = EINVAL;
return (error);
+ }
fvfslocked = NDHASGIANT(&fromnd);
tvfslocked = 0;
#ifdef MAC
@@ -3737,8 +3741,12 @@
NDINIT_AT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
segflg, path, fd, td);
nd.ni_cnd.cn_flags |= WILLBEDIR;
- if ((error = namei(&nd)) != 0)
+ if ((error = namei(&nd)) != 0) {
+ /* Translate error code for mkdir("/"). */
+ if (error == EISDIR)
+ error = EEXIST;
return (error);
+ }
vfslocked = NDHASGIANT(&nd);
vp = nd.ni_vp;
if (vp != NULL) {
@@ -3825,10 +3833,15 @@
bwillwrite();
NDINIT_AT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
pathseg, path, fd, td);
- if ((error = namei(&nd)) != 0)
+ if ((error = namei(&nd)) != 0) {
+ /* Translate error code for rmdir("/"). */
+ if (error == EISDIR)
+ error = EBUSY;
return (error);
+ }
vfslocked = NDHASGIANT(&nd);
vp = nd.ni_vp;
+ /* XXX namei() takes care of this case. */
if (vp->v_type != VDIR) {
error = ENOTDIR;
goto out;
@@ -3841,6 +3854,7 @@
goto out;
}
/*
+ * XXX namei() takes care of this case.
* The root of a mounted filesystem cannot be deleted.
*/
if (vp->v_vflag & VV_ROOT) {
More information about the freebsd-hackers
mailing list