GNU bug report logs - #43959
`cp --archive --symbolic-link` non-reproducible and creates hardlinks between symbolic links that dereference to the same inode

Previous Next

Package: coreutils;

Reported by: "Martin Ramsdale (mramsdal)" <mramsdal <at> cisco.com>

Date: Mon, 12 Oct 2020 14:22:02 UTC

Severity: normal

To reply to this bug, email your comments to 43959 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-coreutils <at> gnu.org:
bug#43959; Package coreutils. (Mon, 12 Oct 2020 14:22:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to "Martin Ramsdale (mramsdal)" <mramsdal <at> cisco.com>:
New bug report received and forwarded. Copy sent to bug-coreutils <at> gnu.org. (Mon, 12 Oct 2020 14:22:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: "Martin Ramsdale (mramsdal)" <mramsdal <at> cisco.com>
To: "bug-coreutils <at> gnu.org" <bug-coreutils <at> gnu.org>
Subject: RE: `cp --archive --symbolic-link` non-reproducible and creates
 hardlinks between symbolic links that dereference to the same inode
Date: Mon, 12 Oct 2020 13:00:13 +0000
[Message part 1 (text/plain, inline)]
Self-reply, following some discussion with my colleague.

It is possible that, strictly speaking, -s doesn't make sense alongside -a:
By using `cp -as` we're asking to preserve hardlinks AND create symbolic
links instead of copying
 
From the man page:
       -a, --archive
              same as -dR --preserve=all
.
       -d     same as --no-dereference --preserve=links
.
       --preserve[=ATTR_LIST]
              preserve the specified attributes (default:
mode,ownership,timestamps), if possible additional attributes: context,
links, xattr, all
.
       -s, --symbolic-link
              make symbolic links instead of copying

As an alternative invocation to get the "expected" behaviour:
  $ cp -RPs --preserve=all --no-preserve=links "$(pwd)"/copy_from/ copy_to
  $ ls -l copy_to/file*
  copy_to/file1 -> /gnu_cp_bug/copy_from/file1
  copy_to/file2 -> /gnu_cp_bug/copy_from/file2

So, if the combination of -a/-s doesn't make sense - can this be better
documented?
Otherwise, please consider fixing the default behaviour (e.g. via my
previous tentative diff; or perhaps -s should always imply
--no-preseive=links)

Kind Regards,
Martin

-----Original Message-----
From: Martin Ramsdale (mramsdal) 
Sent: 12 October 2020 11:45
To: bug-coreutils <at> gnu.org
Subject: `cp --archive --symbolic-link` non-reproducible and creates
hardlinks between symbolic links that dereference to the same inode

Dear coreutils maintainers,

I've encountered, what I consider, a bug in GNU cp: If you do a recursive
copy, then any files with identical inodes from the source will be created
with new-identical inodes in the destination. For example:
  $ mkdir copy_from
  $ echo aaa > copy_from/file1
  $ ln copy_from/file1 copy_from/file2
  $ cp -as "$(pwd)"/copy_from/ copy_to
  $ stat -c '%n %i' copy_to/file*
  copy_to/file1 42615790
  copy_to/file2 42615790
  $ ls -l copy_to/file*
  copy_to/file1 -> /gnu_cp_bug/copy_from/file1
  copy_to/file2 -> /gnu_cp_bug/copy_from/file1

Whereas the expected result is:
  $ ls -l copy_to/file*
  copy_to/file1 -> /gnu_cp_bug/copy_from/file1
  copy_to/file2 -> /gnu_cp_bug/copy_from/file2

Issues this can cause include:
  1) Incorrect file usage:
    Whilst initially any usage of copy_to/file[1,2] is as expected, if any
of copy_from/file[1,2] is *replaced* (rather than modified), then usage of
copy_to/file[1,2] will yield unexpected results. For example:
      $ rm copy_from/file2
      $ echo bbb > copy_from/file2
      $ cat copy_from/file*
      aaa
      bbb
      $ cat copy_to/file*
      aaa
      aaa

  2) Non-reproducible behaviour: symlinks created may point to any of the
original inodes, and so for the same input directory the output of `copy
-as` may differ. For example invocations on different systems could yield
either:
    > ls -l copy_to/file*
    copy_to/file1 -> /gnu_cp_bug/copy_from/file1
    copy_to/file2 -> /gnu_cp_bug/copy_from/file1
   OR
    > ls -l copy_to/file*
    copy_to/file1 -> /gnu_cp_bug/copy_from/file2
    copy_to/file2 -> /gnu_cp_bug/copy_from/file2

From brief code inspection, I believe this issue to orginiate from
earlier_file lookup in copy_internal(). I haven't had the opportunity to
build/validate this as a fix, but propose the following for consideration:
  diff --git a/src/copy.c b/src/copy.c
  index 4050f6953..74c1e7499 100644
  --- a/src/copy.c
  +++ b/src/copy.c
  @@ -2513,6 +2513,8 @@ copy_internal (char const *src_name, char const
*dst_name,
       {
         if (command_line_arg)
           earlier_file = remember_copied (dst_name, src_sb.st_ino,
src_sb.st_dev);
  +      else if (x->symbolic_link)
  +        earlier_file = NULL;
         else
           earlier_file = src_to_dest_lookup (src_sb.st_ino, src_sb.st_dev);
       }

Kind Regards,
Martin
[smime.p7s (application/pkcs7-signature, attachment)]

This bug report was last modified 4 years and 253 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.