mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-04-20 02:36:16 +02:00
cp -up: preserve all hard links
* src/copy.c (copy_internal): With --update (-u), this function would return early once it found that the destination is not older than the source, *without* recording the source-dev/ino--to--dest_name mapping. That mapping is required in order to preserve src hard links in the destination tree, so when using cp with --update and --preserve=links (perhaps via -p or -a), cp could fail to preserve one hard link per inode when at least one of the hard-linked names already exists in the destination tree. Reported by Odd Harry Mannsverk in http://debbugs.gnu.org/8419. * tests/cp/preserve-link: New file. Exercise the flaw/fix. * tests/Makefile.am (TESTS): Add it. * NEWS (Bug fixes): Mention it.
This commit is contained in:
6
NEWS
6
NEWS
@@ -8,6 +8,12 @@ GNU coreutils NEWS -*- outline -*-
|
||||
I.E. for skipped files, the original ownership is output, not the new one.
|
||||
[bug introduced in sh-utils-2.0g]
|
||||
|
||||
cp -u -p would fail to preserve one hard link for each up-to-date copy
|
||||
of a src-hard-linked name in the destination tree. I.e., if s/a and s/b
|
||||
are hard-linked and dst/s/a is up to date, "cp -up s dst" would copy s/b
|
||||
to dst/s/b rather than simply linking dst/s/b to dst/s/a.
|
||||
[This bug appears to have been present in "the beginning".]
|
||||
|
||||
printf '%d' '"' no longer accesses out-of-bounds memory in the diagnostic.
|
||||
[bug introduced in sh-utils-1.16]
|
||||
|
||||
|
||||
12
src/copy.c
12
src/copy.c
@@ -1628,6 +1628,17 @@ copy_internal (char const *src_name, char const *dst_name,
|
||||
end up removing the source file. */
|
||||
if (rename_succeeded)
|
||||
*rename_succeeded = true;
|
||||
|
||||
/* However, we still must record that we've processed
|
||||
this src/dest pair, in case this source file is
|
||||
hard-linked to another one. In that case, we'll use
|
||||
the mapping information to link the corresponding
|
||||
destination names. */
|
||||
earlier_file = remember_copied (dst_name, src_sb.st_ino,
|
||||
src_sb.st_dev);
|
||||
if (earlier_file)
|
||||
goto create_hard_link;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1948,6 +1959,7 @@ copy_internal (char const *src_name, char const *dst_name,
|
||||
}
|
||||
else
|
||||
{
|
||||
create_hard_link:;
|
||||
/* We want to guarantee that symlinks are not followed. */
|
||||
bool link_failed = (linkat (AT_FDCWD, earlier_file, AT_FDCWD,
|
||||
dst_name, 0) != 0);
|
||||
|
||||
@@ -341,6 +341,7 @@ TESTS = \
|
||||
cp/parent-perm-race \
|
||||
cp/perm \
|
||||
cp/preserve-2 \
|
||||
cp/preserve-link \
|
||||
cp/preserve-slink-time \
|
||||
cp/proc-short-read \
|
||||
cp/proc-zero-len \
|
||||
|
||||
40
tests/cp/preserve-link
Executable file
40
tests/cp/preserve-link
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
# Exercise the fix for http://debbugs.gnu.org/8419
|
||||
|
||||
# Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
. "${srcdir=.}/init.sh"; path_prepend_ ../src
|
||||
print_ver_ cp
|
||||
|
||||
same_inode()
|
||||
{
|
||||
local u v
|
||||
u=$(stat --format %i "$1") &&
|
||||
v=$(stat --format %i "$2") && test "$u" = "$v"
|
||||
}
|
||||
|
||||
mkdir -p s t/s || framework_failure_
|
||||
touch s/f t/s/f || framework_failure_
|
||||
ln s/f s/link || framework_failure_
|
||||
|
||||
# This must create a hard link, t/s/link, to the existing file, t/s/f.
|
||||
# With cp from coreutils-8.12 and prior, it would mistakenly copy
|
||||
# the file rather than creating the link.
|
||||
cp -au s t || fail=1
|
||||
|
||||
same_inode t/s/f t/s/link || fail=1
|
||||
|
||||
Exit $fail
|
||||
Reference in New Issue
Block a user