7

Following on from another user's question I've bumped into a quirk of Linux filesystem permissions that I can't easily rationalize:

sudo mkdir ~/foo ~/foo/bar
sudo touch ~/baz
mkdir ~/my_dir
chown 700 ~/my_dir
# this is fine
mv ~/baz ~/my_dir
# renaming is fine
mv ~/foo ~/bob
# Moving caused: Permission denied
mv ~/bob ~/my_dir/

For clarity foo foo/bar baz are owned by root. my_dir is owned by my own user and of course ~ is owned by my own user. I can rename and move a file owned by another user. I can rename a directory owned by another user, but I can't move a directory owned by another user.

This seems a very specific restriction and I don't understand what danger is being protected against or what underlying mechanism means that it can only work this way.

Why can other users' directories not be moved?

Stephen Kitt
  • 434,908
  • I can't see how you used ~/foo and ~/foo/bar, or why ~/baz is a directory. Or how ~/baz got renamed twice, or where ~/bob came from. – ctrl-alt-delor Jun 27 '19 at 13:37
  • @ctrl-alt-delor thanks, typo in my question, I think that's fixed now. baz is a file. it's foo then bob that is a directory. – Philip Couling Jun 27 '19 at 13:42

1 Answers1

12

This is one of the situations documented to lead to EACCES:

oldpath is a directory and does not allow write permission (needed to update the .. entry).

You can’t write inside bob, which means you can’t update bob/.. to point to its new value, my_dir.

Moving files doesn’t involve writing to them, but moving directories does.

Stephen Kitt
  • 434,908
  • I honestly never knew that .. actually existed, I always thought it was simulated by the OS. Now I'm trying to find if . actually exists. – Philip Couling Jun 27 '19 at 12:28
  • 3
    . usually exists too; that’s why directories have a link count >= 2. – Stephen Kitt Jun 27 '19 at 12:37
  • It's not April 1 so you must be being serious. This win's the prize esoteric fact of the month! I'm sure if I ask questions like "why" I'm going to get the answer "performance", or "simpler implementation". Thanks! – Philip Couling Jun 27 '19 at 12:50
  • 3
    Actually, on some fs (btrfs) dirs have a link count if 1. . and .. are emulated by the VFS on such fs. I'm not able to test now, but I'm pretty sure that it's also emulating that EACCES condition too (which is not that esoteric). –  Jun 27 '19 at 13:04
  • @pizdelect indeed. I’m pretty sure there’s a question here whose answers go into all those details (why . and .., why some FSs store them while others emulate them, etc.), but I can’t find it... (IIRC the link count of 2 or more is a POSIX requirement.) – Stephen Kitt Jun 27 '19 at 13:08
  • Is it? Then clearly Linux is not POSIX compliant because it will return a link count of 1 for dirs on some FSs. I know that from failing naive find -links usage examples. –  Jun 27 '19 at 13:23
  • 2
    @pizdelect right, /proc/sys for starters; I’m probably mis-remembering. All that I can find now is that POSIX requires that . and .. appear to exist (without defining how they’re implemented). – Stephen Kitt Jun 27 '19 at 13:36
  • @pizdelect POSIX allows . and .. to be emulated. See readdir() where it says If entries for dot or dot-dot exist, one entry shall be returned for dot and one entry shall be returned for dot-dot; otherwise, they shall not be returned. So they don't have to actually exist. – Barmar Jul 04 '19 at 01:13
  • @Barmar and that's exactly what I was saying -- if the entries don't exist, are emulated by the kernel, just as the EACCES condition. It's the extra link which is not emulated -- "leaf" dirs have a link count of 1 in some FSs like btrfs. –  Jul 10 '19 at 14:33
  • @StephenKitt Can you cite where POSIX specifies that the link count has to be emulated even if the special directory entries don't really exist? – Barmar Jul 10 '19 at 15:12
  • @Barmar see my follow-up comment above; I haven’t found the requirement in POSIX. – Stephen Kitt Jul 10 '19 at 15:21
  • Thanks, I didn't realize you were contradicting your earlier comment about the link count. – Barmar Jul 10 '19 at 15:23