Subject: mv: moving hardlink of a softlink to the softlink does nothing

From: Bernhard Voelker <[email-masked]>
Date: Wed, 01 Feb 2012 09:21:09 +0100

Playing around with the latest mv checkin,
I noticed another corner case:

Create a file 'f', a symlink 'l' to it, and
then a hardlink 's' to that symlink:

  $ touch f && ln -s f l && ln l s && ls -ogi
  total 0
  6444 -rw-r--r-- 1 0 Feb  1 08:52 f
  6462 lrwxrwxrwx 2 1 Feb  1 08:52 l -> f
  6462 lrwxrwxrwx 2 1 Feb  1 08:52 s -> f

Trying to mv the hardlink over the symlink seems to succeed:

  $ ~/git/coreutils/src/mv s l

... but the name 's' was not unlinked:

  $ ls -ogi
  total 0
  6444 -rw-r--r-- 1 0 Feb  1 08:52 f
  6462 lrwxrwxrwx 2 1 Feb  1 08:52 l -> f
  6462 lrwxrwxrwx 2 1 Feb  1 08:52 s -> f

Using the -v option looks also normal, but is a nop:

  $ ~/git/coreutils/src/mv -v s l
  ‘s’ -> ‘l’
  $ ls -ogi
  total 0
  6444 -rw-r--r-- 1 0 Feb  1 08:52 f
  6462 lrwxrwxrwx 2 1 Feb  1 08:52 l -> f
  6462 lrwxrwxrwx 2 1 Feb  1 08:52 s -> f

The strace only shows the rename():

  stat("l", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
  lstat("s", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
  lstat("l", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
  rename("s", "l")                        = 0

I'd have expected either
a) the name 's' to be unlinked, or
b) an error message that something was wrong (well, whatever).
I'd prefer a) of course.

That behaviour didn't change at least since version 7.1
(on openSuSE-11.3), but back in the earlier days in 5.93
(SLES-10.3), 's' disappeared as expected:

  stat("l", {st_mode=S_IFREG|0640, st_size=0, ...}) = 0
  lstat("s", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
  lstat("l", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
  unlink("l")                             = 0
  rename("s", "l")                        = 0

Does mv now work as specified? Is this a kernel or
a coreutils (or a user) issue?

Have a nice day,
Berny