Re: rmdir of one's pwd

Alexander Viro (viro@math.psu.edu)
Mon, 15 Feb 1999 12:13:32 -0500 (EST)


On Mon, 15 Feb 1999 Andries.Brouwer@cwi.nl wrote:

> From viro@math.psu.edu Mon Feb 15 15:47:53 1999
>
> rename(): could you comment on Linux rename(2) manpage? Quote:
>
> EEXIST The new pathname contained a path prefix of the
> old.
>
> EINVAL An attempt was made to make a directory a subdi=AD
> rectory of itself.
>
> How do those cases differ?
>
> Now that you point me to this page, I changed the text into
>
> ENOTEMPTY or EEXIST
> newpath is a non-empty directory, i.e., contains
> entries other than "." and "..".
>
> EINVAL The new pathname contained a path prefix of the
> old, or, more generally, an attempt was made to
> make a directory a subdirectory of itself.
>
> (The second part of this description is required to cover
> cases involving symbolic links.)

Umm... Do we have a filesystem that would return EEXIST instead of ENOENT?
<checking> unless some *really* weird NFS server ignores the RFC and
returns NFSERR_EXIST on rmdir() of non-empty directory we should be OK.
BTW, to make rename() work on NCPFS in case when the target exists we'll
need an analog of silly-rename scheme. Oh, well...

I've looked through the rename(2) manpage again and found several
inaccuracies:

| If newpath exists but the operation fails for some reason
| or the system crashes rename guarantees to leave an
| instance of newpath in place.
+++ Notice that currently for some filesystems crash may lead to the
+++ situation when the link disappears. Example: VFAT. NFS has very
+++ good reason for doing so. For other filesystems it's a bug.

| EBUSY newpath exists and is the current working direc­
| tory or root directory of some process.
+++ Or is opened by some process. Or if the source is mountpoint
+++ or root directory of filesystem (different things, since
+++ mount over busy directories is allowed). Ditto for target
+++ (if it exists, indeed).

| EACCES Write access to the directory containing oldpath
| or newpath is not allowed for the process's effec­
| tive uid, or one of the directories in oldpath or
| newpath did not allow search (execute) permission,
| or oldpath was a directory and did not allow write
| permission (needed to update the .. entry).
+++ IMHO it needs a clarification. First of all, until now
+++ write access to the oldpath was not checked. James
+++ Griffiths spotted that out and I've included the check
+++ in the latest variant of rename patch, but *only* for
+++ cross-directory moves. I think that mentioning of
+++ changing parents is needed here.

| EPERM The directory containing oldpath has the sticky
| bit set and the process's effective uid is neither
| the uid of the file to be deleted nor that of the
| directory containing it, or the filesystem con­
| taining pathname does not support renaming of the
| type requested.
+++ EPERM also happens if you can't delete target due to
+++ sticky bit on target's parent. Root (CAP_FOWNER, actually)
+++ can override sticky bit effects.

+++ Immutable and Append-only on source, target or their parents may
+++ give EACCES or EPERM (hmm...)

+++ ENOTDIR also happens if oldpath is a directory and newpath
+++ exists and is not a directory.

D'oh. I don't know how to describe it in a compact way. Maybe we a manpage
in section 2 that would describe lookup permissions (and errors) and
link creation and removal. That would simplify (and shorten) error lists
in other manpages. Let's see...

Link removal:
ENOENT if victim doesn't exist
EROFS if filesystem is readonly.
EACCES if parent is immutable
EACCES unless we have write and execute permissions on
parent.
EPERM if parent is append-only.
EPERM if victim is append-only or immutable
EPERM if sticky bit is set on parent and we don't have right EUID
or CAP_FOWNER.
EBUSY if victim is the root of filesystem or underlying
mountpoint.

Link creation:
EEXIST if the link already exists.
EROFS if filesystem is readonly.
EACCES if parent is immutable
EACCES unless we have write and execute permissions on
parent.

Rename:
* We should be able to lookup the source and target.
* We should be able to remove the source (link).
* If the target exists we should be able to remove it.
* If the target doesn't exist we should be able to create a link in
target's parent.
* If the target exists and is not a directory source also should be
not a directory, otherwise - EISDIR.
* If the target exists and is a directory source also should be a
directory, otherwise - ENOTDIR.
* If both links point to the same file we succeed. (Ouch... so we
should move this check up...)
* Both source and target must be on the same filesystem, otherwise -
EXDEV.
* If source and target have different parents and source is a
directory we must have write permissions on it, otherwise -
EACCES.
(Question: what about execute permissions?)
* If the move would make the source its own subdirectory - EINVAL.
* If the rename() is not supported by the filesystem - EPERM.
* If the target is somebody's root or pwd or is opened by some
process - EBUSY.
* If the target is not empty - ENOTEMPTY (there is a borderline
case, if the target is not empty and somebody opened a file in
(under) it we return EBUSY).
* Any checks applied by filesystem (EMLINK, EIO, EDEADLOCK (yup.
UMSDOS...))

That's what we actually have there...
Cheers,
Al

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/