diff options
author | Jim Meyering <meyering@redhat.com> | 2008-11-19 19:36:45 +0100 |
---|---|---|
committer | Jim Meyering <meyering@redhat.com> | 2008-11-20 10:21:52 +0100 |
commit | 3ece0355d52e41a1b079c0c46477a32250278c11 (patch) | |
tree | ea24ea4aae7129a936c291f29ee7b2724bed6d5c /src | |
parent | 1760ade090cbf8c854c1033399d51ff4fdde3ae0 (diff) | |
download | coreutils-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.c | 36 |
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); |