10

I'm trying to emulate the process of path resolution (see man page path_resolution) in unix-like systems.

My OS is Linux with GNU coreutils 8.7.

In order to clarify the meaning of extra trailing '/' in resolution, I did following things in a shell:

mkdir this_is_dir
ln -s this_is_dir this_is_link
rm this_is_link

Everything was fine, because this_is_link is a symlink, and I just removed it away. But while trying:

mkdir this_is_dir
ln -s this_is_dir this_is_link
rm this_is_link/

It echoed rm: cannot remove 'this_is_link/': Is a directory

Well, the trailing '/' caused following of symlink, I thought. So, I tried another command: rmdir this_is_link/

And a funny result came out: rmdir: failed to remove 'this_is_link/': Not a directory

Not what I expected. So I asked my friend to confirm if the same result could be obtained on his system. He had a lower version of coreutils than I had. And the result was amazing, no matter rm or rmdir 'this_is_link/', the same error Not a directory occurs.

And another friend just tried it out on his Mac OS, the result is: rm => 'Is a directory', rmdir => the directory is successfully deleted, the link remained.

Are there any spec about the exact behavior of path resolution?

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
ymfoi
  • 363
  • 2
  • 9
  • See also [How linux handles multiple path separators (/home////username///file)](http://unix.stackexchange.com/questions/1910/how-linux-handles-multiple-path-separators-home-username-file) – Gilles 'SO- stop being evil' Jan 24 '12 at 01:04

2 Answers2

10

The POSIX/Single Unix specification specifies that a pathname with a trailing slash must refer to a directory (see base definitions §4.11 pathname resolution). foo/ is in fact defined as equivalent to foo/. (for path resolution purposes, not when manipulating file names; basename and dirname ignore trailing slashes). Most implementations respect this, but there are a few exceptions.

This explains the behavior of rm this_is_link/: it's equivalent to rm this_is_link/., where the argument is clearly a directory.

rmdir this_is_link/ should similarly refer to the directory. That it doesn't on your machine is a bug in GNU coreutils. OSX is behaving correctly here.

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
  • This is exactly what i needed, thanks guy! – ymfoi Jan 24 '12 at 03:10
  • if `path/` was equivalent to `path/.`, then `rmdir` would have to fail too, because the `rmdir` utility is supposed to "perform actions equivalent to the `rmdir()` function", and the `rmdir()` function should fail with EINVAL when "The path argument contains a last component that is dot". (The quotes are from the POSIX). Or that should not apply when the trailing `/.` is, like, imaginary? That may be. Anyways, the behaviour of the `rmdir` utility from GNU coreutils correctly reflects that of the `rmdir()` function of the system it runs on, and this answer is wrong. –  Jan 23 '21 at 11:28
  • @user414777 IIRC what you explain was reported as a defect on the POSIX specification and the semantics of a trailing slash have been modified to make this case work "intuitively". – Gilles 'SO- stop being evil' Jan 23 '21 at 17:25
  • 1
    Even if that's a bug in Linux, it's still not bug in GNU coreutils, as you claim. GNU's `rmdir` will work as you expected on OSX. –  Jan 24 '21 at 13:11
  • 1
    Coreutils > 8.32 will have more helpful error messages in this regard: https://lists.gnu.org/archive/html/coreutils/2021-02/msg00009.html Specifically `rmdir: failed to remove 'this_is_link/': Symbolic link not followed` – Pádraig Brady Feb 17 '21 at 16:44
-1

My take:

  • ''rm link/'' fails because rm looks at the last char, sees it's a slash, gives the (not really correct) diagnostic you saw;
  • ''rmdir link/'' fails alright: link is not a directory, it is a symlink
  • ''rm link'' will correctly succeed

Incidentally, path resolution has very little to do with this, it just appears to be ''rm'' cutting a corner rather than (correctly) invoking "stat" on an argument (which is what rmdir is doing).

Cheers.

Alien Life Form
  • 621
  • 5
  • 12
  • 1
    Actually, the converse seems to be true: `rm` does call stat (well, newfstatat, actually, with the `AT_SYMLINK_NOFOLLOW` option) and refuses to proceed any further, whereas rmdir actually calls rmdir(2), but gets `ENOTDIR`. – Ansgar Esztermann Jan 23 '12 at 10:47
  • @AnsgarEsztermann `AT_SYMLINK_NOFOLLOW` will prevent it from following the symlink, so rm should delete the link itself instead of printing "Not a directory" which does not match the circumstance. – ymfoi Jan 23 '12 at 11:06
  • From a brief check with stat(1), the trailing slash will override the option. The output of `stat` and `stat -L` differ only if the argument is given without a trailing slash. – Ansgar Esztermann Jan 23 '12 at 13:21
  • @AnsgarEsztermann Oh, I see...Thx. How about the different effects on different evironment? Any ideas? – ymfoi Jan 23 '12 at 14:08
  • What do you mean by "environment"? Different OSs/OS versions? Older `rm` (tried with coreutils 6.12) does not call newfstatat, but tries unlinkat immediately. Other OSs may have different implementations of syscalls, so their behaviour may differ even more. – Ansgar Esztermann Jan 23 '12 at 14:30
  • @AnsgarEsztermann Gotcha. Thx! – ymfoi Jan 23 '12 at 15:30
  • 1
    It's the opposite: on ymfoi's machine, `rm` is behaving correctly and `rmdir` isn't. The trailing `/` should force them to treat their argument as a directory, per the POSIX standard. [See my answer for references](http://unix.stackexchange.com/questions/29769/puzzled-by-path-resolution-in-unix-like-systems/29836#29836). – Gilles 'SO- stop being evil' Jan 24 '12 at 00:56
  • So if my comment was partly correct why was it (with no explanation BTW) downvoted? – Alien Life Form Jan 25 '12 at 14:31