Why rm Can Delete a File You Cannot Write To, and When It Can't
A file with mode 0444, owned by you, read-only, can be deleted without any fuss. Meanwhile a file with mode 0666, which anyone can write, can refuse to go away. That looks backwards until you notice that deleting a file never touches the file.
Deleting edits the directory, not the file
A directory is a table of names pointing at inodes. rm calls unlink(2), which removes one entry from that table. The file's own contents and mode are not involved at all.
So the permission check is on the directory. You need both:
- write permission on the directory, to change the table;
- execute permission on the directory, to look names up in it.
The file's permission bits are not consulted. Try it:
mkdir demo && cd demo
echo hi > precious.txt
chmod 0444 precious.txt
rm -f precious.txt # works: you own the directory
ls # empty
The prompt is rm being polite, not the kernel
Without -f, on a terminal, you get rm: remove write-protected regular file 'precious.txt'?. That is rm itself checking the mode and asking. The kernel has no opinion; if you answer y the unlink goes straight through.
Pipe it or run it from a script with no tty and the prompt vanishes, because rm only asks when standard input is a terminal.
Flip it: writable file, cannot delete
sudo mkdir /srv/locked
sudo touch /srv/locked/open.txt
sudo chmod 0666 /srv/locked/open.txt
echo ok > /srv/locked/open.txt # fine, you can write it
rm /srv/locked/open.txt # Permission denied
The directory is owned by root with mode 0755, so you have no write bit on it. You can change what is inside the file, but you cannot remove the name. The same applies to mv, since renaming is also a directory edit.
No execute bit on the directory
With write but no execute on a directory, rm dir/file still fails with "Permission denied". Without execute the kernel will not resolve the name, so there is nothing to unlink. This one catches people who chmod 0600 a directory thinking read and write is enough.
Quick detour: the sticky bit on /tmp
Everyone has write on /tmp, so by the rules above anyone could delete anyone's files. The sticky bit (the t in drwxrwxrwt) is the exception. In a sticky directory you may only unlink an entry if you own the file, own the directory, or are root.
That is why rm /tmp/someone-elses-file fails despite the world-writable directory. Back to the main thread.
Other reasons rm says no
If the directory permissions look fine and it still fails, check the error text, then these:
Operation not permitted(EPERM): the file has the immutable or append-only attribute. Check withlsattr file; clear withsudo chattr -i file. Even root is stopped until you do.Read-only file system(EROFS): the mount is read-only, perhaps after the kernel remounted it following disk errors. Checkfindmnt.Device or resource busy(EBUSY): you are trying to remove a mount point, or a bind-mounted path.Directory not empty: plainrmwill not remove directories at all;rmdirneeds it empty, andrm -rhas to empty it first, which needs write on that directory too.- A Mandatory Access Control policy (SELinux, AppArmor) or an NFS server with root squashing denying what the plain mode bits would allow.
A fast way to find the culprit
namei -l prints the permissions of every component in a path, which makes the missing bit on a parent directory obvious:
namei -l /srv/locked/open.txt
lsattr -d /srv/locked /srv/locked/open.txt
If both look sane, run strace -e unlink,unlinkat rm file and read the errno. It is the kernel's actual answer, and it maps directly to the list above.
One consequence worth remembering: deleting a file only drops a name. If other hard links or open file descriptors exist, the data stays until the last one goes, so "deleted" and "gone from disk" are not the same event.