Subject: bug#6960: mv refuses to move a symlink over a hard link to the same file

From: Jim Meyering <[email-masked]>
Date: Mon, 30 Jan 2012 10:04:36 +0100

Pádraig Brady wrote:
> On 01/29/2012 09:33 PM, Jim Meyering wrote:
..
>> +  /* At this point, it is normally an error (data loss) to move a symlink
>> +     onto its referent, but in at least one narrow case, it is not:
>> +     In move mode, when
>> +     src is a symlink,
>> +     dest is not a symlink,
>> +     dest has a link count of 2 or more and
>> +     dest and the referent of src are not the same entry,
>> +     then it's ok, since while we'll lose one of those hard links,
>> +     src will still point to a remaining link.
>> +
>> +     Given this,
>> +       $ touch f && ln f l && ln -s f s
>> +       $ ls -og f l s
>> +       -rw-------. 2  0 Jan  4 22:46 f
>> +       -rw-------. 2  0 Jan  4 22:46 l
>> +       lrwxrwxrwx. 1  1 Jan  4 22:46 s -> f
>> +     this must fail: mv s f
>> +     this must succeed: mv s l */
>> +  if (x->move_mode
>> +      && S_ISLNK (src_sb->st_mode)
>> +      && ! S_ISLNK (dst_sb->st_mode)
>> +      && 1 < dst_sb_link->st_nlink)
>> +    {
>> +      char *abs_src = canonicalize_file_name (src_name);
>> +      if (abs_src)
>> +        {
>> +          bool result = ! same_name (abs_src, dst_name);
>> +          free (abs_src);
>> +          return result;
>> +        }
>> +    }
>
> Well the logic follows the description at least.
> I was going to say the nlink test was redundant,
> but it's a bit clearer with that left, and also
> it's a performance improvement in the nlink=1 case.

Thanks for the review.
I'll wait a day or so more, in case Paul or anyone else has feedback.
BTW, I removed the

    x->dereference == DEREF_NEVER

test that I'd used in the first version, since
in move mode, that condition is always true.