Permissions – Are Non-Empty Subdirectories Safe from Deletion?

permissionsrm

In the following situation ls -alh

total 0
drwxrwx--- 1 user http  20 Nov 30 08:08 .
drwxrws--- 1 user http 310 Nov 30 08:07 ..
drwx------ 1 http http  10 Nov 30 08:08 empty-subdir
drwx------ 1 http http  12 Nov 30 08:08 non-empty-subdir

where two subdirectories (not owned by me) exist, which I list as:

sudo ls empty-subdir -alh
total 0
drwx------ 1 http http 10 Nov 30 08:08 .
drwxrwx--- 1 user http 20 Nov 30 08:08 ..

sudo ls non-empty-subdir -alh
total 0
drwx------ 1 http http 12 Nov 30 08:08 .
drwxrwx--- 1 user http 20 Nov 30 08:08 ..
drwx------ 1 http http  0 Nov 30 08:08 subdir

The difference between the two subdirectories being that the non-empty non-empty-subdir contains a folder.

My question is whether it is by design that trying to rm -rf remove the subdirectories I get results:

$ rm empty-subdir -rf
$ rm non-empty-subdir -rf
rm: cannot remove 'non-empty-subdir': Permission denied
$ ls -alh
total 0
drwxrwx---+ 1 user http  10 Nov 30 08:14 .
drwxrws---+ 1 user http 310 Nov 30 08:07 ..
drwx------+ 1 http http  12 Nov 30 08:08 non-empty-subdir

It seems that the user with write permissions to a directory is allowed to remove an entry for a file, or an empty subdirectory of some other user, but not a non-empty subdirectory.

An ideal answer to this question would provide information such as:

  • a confirmation that the outlined behaviour is reproducible on other machines (and not mere quirks of my screwed up box)
  • a rationale to explain that behaviour (e.g. are there use cases?)
  • an overview if there are differences between systems (BSD, Linux….)

Update:
With respect to the comment by Ipor Sircer, I did retest the scenario, without any ACL features and it is the same. I therefore modified the question to remove the +es from the listings as not to give rise to an idea that the behaviour mightbe related to ACLs.

Best Answer

One can only remove a directory (with the rmdir() system call) if it's empty.

rm -r dir removes the directory and all the files in it, starting with the leaves of the directory tree and walking its way up to the root (dir).

To remove a file (with rmdir() for directories and unlink() for other types of files, or *at() variants), what matters it not the permission of the file itself but those of the directory you're removing the file from (beware the t bit in the permissions, like for /tmp, adds further complications to that).

Before all, you're not really removing the file, you're unlinking it from a directory (and when it's the last link that you're removing, the file ends up being deleted as a consequence), that is, you're modifying the directory, so you need modifying (write) permissions to that directory.

The reason you can't remove non-empty-dir is that you can't unlink subdir from it first, as you don't have the right to modify non-empty-dir. You would have the right to unlink non-empty-dir from your home directory as you have write/modification permission to that one, only you can't remove a directory that is not empty.

In your case, as noted by @PeterCordes in comments, the rmdir() system call fails with a ENOTEMPTY (Directory not empty) error code, but since you don't have read permission to the directory, rm cannot even find out which files and directories (including subdir) it would need to unlink from it to be able to empty it (not that it could unlink them if it knew, as it doesn't have write permissions).

You can also get into situations where rm could remove a directory if only it could find out which files are in it, like in the case of a write-only directory:

$ mkdir dir
$ touch dir/file
$ chmod a=,u=wx dir
$ ls -ld dir
d-wx------ 2 me me 4096 Nov 30 19:43 dir/
$ rm -rf dir
rm: cannot remove 'dir': Permission denied

Still, I am able to remove it as I happen to know it only contains one file file:

$ rm dir/file
$ rmdir dir
$

Also note that with modern Unices you could rename that non-empty-dir, but on some like Linux or FreeBSD (but not Solaris), not move it to a different directory, even if you also had write permission to that directory, as (I think and for Linux, as suggested by the comment for the relevant code) doing so would involve modifying non-empty-dir (the .. entry in it would point to a different directory).

One could argue that removing your empty-dir also involves removing the .. and . entries in it, so modifying it, but still, the system lets you do that.

Related Question