summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJim Meyering <meyering@redhat.com>2008-11-19 19:36:45 +0100
committerJim Meyering <meyering@redhat.com>2008-11-20 10:21:52 +0100
commit3ece0355d52e41a1b079c0c46477a32250278c11 (patch)
treeea24ea4aae7129a936c291f29ee7b2724bed6d5c /src
parent1760ade090cbf8c854c1033399d51ff4fdde3ae0 (diff)
downloadcoreutils-3ece0355d52e41a1b079c0c46477a32250278c11.tar.xz
cp: use far less memory in some cases
cp --link was "remembering" many name,dev,inode triples unnecessarily. cp was doing the same, even without --link, for every directory in the source hierarchy, while it can do its job with entries merely for the command-line arguments. Prompted by a report from Patrick Shoenfeld. Details <http://thread.gmane.org/gmane.comp.gnu.coreutils.bugs/15081>. * src/copy.c (copy_internal): Refrain from remembering name,dev,inode for most files, when invoked via cp --link. Record an infloop-avoidance triple for each directory specified on the command line, not for each directory in the source tree. Don't record a dir-triple when x->hard_link is set. * NEWS (Buf fixes): Mention it. * tests/cp/link-heap: New file. Test for cp's lowered memory usage. * tests/Makefile.am (TESTS): Add link-heap.
Diffstat (limited to 'src')
-rw-r--r--src/copy.c36
1 files changed, 21 insertions, 15 deletions
diff --git a/src/copy.c b/src/copy.c
index bc1b20ee2..c9c79a1b1 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -1411,6 +1411,10 @@ copy_internal (char const *src_name, char const *dst_name,
we can arrange to create a hard link between the corresponding names
in the destination tree.
+ When using the --link (-l) option, there is no need to take special
+ measures, because (barring race conditions) files that are hard-linked
+ in the source tree will also be hard-linked in the destination tree.
+
Sometimes, when preserving links, we have to record dev/ino even
though st_nlink == 1:
- when in move_mode, since we may be moving a group of N hard-linked
@@ -1429,27 +1433,29 @@ copy_internal (char const *src_name, char const *dst_name,
- likewise for -L except that it applies to all files, not just
command line arguments.
- Also record directory dev/ino when using --recursive. We'll use that
- info to detect this problem: cp -R dir dir. FIXME-maybe: ideally,
- directory info would be recorded in a separate hash table, since
- such entries are useful only while a single command line hierarchy
- is being copied -- so that separate table could be cleared between
- command line args. Using the same hash table to preserve hard
- links means that it may not be cleared. */
+ Also, with --recursive, record dev/ino of each command-line directory.
+ We'll use that info to detect this problem: cp -R dir dir. */
if (x->move_mode && src_sb.st_nlink == 1)
{
earlier_file = src_to_dest_lookup (src_sb.st_ino, src_sb.st_dev);
}
- else if ((x->preserve_links
- && (1 < src_sb.st_nlink
- || (command_line_arg
- && x->dereference == DEREF_COMMAND_LINE_ARGUMENTS)
- || x->dereference == DEREF_ALWAYS))
- || (x->recursive && S_ISDIR (src_mode)))
+ else if (x->preserve_links
+ && !x->hard_link
+ && (1 < src_sb.st_nlink
+ || (command_line_arg
+ && x->dereference == DEREF_COMMAND_LINE_ARGUMENTS)
+ || x->dereference == DEREF_ALWAYS))
{
earlier_file = remember_copied (dst_name, src_sb.st_ino, src_sb.st_dev);
}
+ else if (x->recursive && S_ISDIR (src_mode))
+ {
+ if (command_line_arg)
+ earlier_file = remember_copied (dst_name, src_sb.st_ino, src_sb.st_dev);
+ else
+ earlier_file = src_to_dest_lookup (src_sb.st_ino, src_sb.st_dev);
+ }
/* Did we copy this inode somewhere else (in this command line argument)
and therefore this is a second hard link to the inode? */
@@ -1730,8 +1736,8 @@ copy_internal (char const *src_name, char const *dst_name,
/* Insert the created directory's inode and device
numbers into the search structure, so that we can
avoid copying it again. */
-
- remember_copied (dst_name, dst_sb.st_ino, dst_sb.st_dev);
+ if (!x->hard_link)
+ remember_copied (dst_name, dst_sb.st_ino, dst_sb.st_dev);
if (x->verbose)
emit_verbose (src_name, dst_name, NULL);