summaryrefslogtreecommitdiff
path: root/src/copy.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2001-11-22 19:45:27 +0000
committerJim Meyering <jim@meyering.net>2001-11-22 19:45:27 +0000
commit507e4c7e696f35c8f9ff7e457d250c24cee1845f (patch)
tree19fcf485333809faeb92db84f381616b56d60c19 /src/copy.c
parent8529df5a59358a5ae4b904b40c5c6aad3a260099 (diff)
downloadcoreutils-507e4c7e696f35c8f9ff7e457d250c24cee1845f.tar.xz
(triple_hash_no_name): New function.
(src_info_init): New function. (copy_internal): Warn and return early for the second and subsequent occurrences of the same source file named on the command line.
Diffstat (limited to 'src/copy.c')
-rw-r--r--src/copy.c68
1 files changed, 59 insertions, 9 deletions
diff --git a/src/copy.c b/src/copy.c
index 1f8770f74..9e84ce7fa 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -597,6 +597,16 @@ triple_hash (void const *x, unsigned int table_size)
return (tmp | p->st_ino) % table_size;
}
+/* Hash an F_triple. */
+static unsigned int
+triple_hash_no_name (void const *x, unsigned int table_size)
+{
+ struct F_triple const *p = x;
+
+ /* Ignoring the device number here should be fine. */
+ return p->st_ino % table_size;
+}
+
/* Compare two F_triple structs. */
static bool
triple_compare (void const *x, void const *y)
@@ -615,7 +625,8 @@ triple_free (void *x)
free (a);
}
-/* Initialize the hash table implementing a set of F_triple entries. */
+/* Initialize the hash table implementing a set of F_triple entries
+ corresponding to destination files. */
void
dest_info_init (struct cp_options *x)
{
@@ -627,8 +638,30 @@ dest_info_init (struct cp_options *x)
triple_free);
}
-/* Return nonzero if the file described by name, FILENAME, and STATS
- has already been created (and hence has an entry in hash table, HT).
+/* Initialize the hash table implementing a set of F_triple entries
+ corresponding to source files listed on the command line. */
+void
+src_info_init (struct cp_options *x)
+{
+
+ /* Note that we use triple_hash_no_name here.
+ Contrast with the use of triple_hash above.
+ That is necessary because a source file may be specified
+ in many different ways. We want to warn about this
+ cp a a d/
+ as well as this:
+ cp a ./a d/
+ */
+ x->src_info
+ = hash_initialize (DEST_INFO_INITIAL_CAPACITY,
+ NULL,
+ triple_hash_no_name,
+ triple_compare,
+ triple_free);
+}
+
+/* Return nonzero if there is an entry in hash table, HT,
+ for the file described by FILENAME and STATS.
Otherwise, return zero. */
static int
seen_file (Hash_table const *ht, char const *filename,
@@ -646,12 +679,11 @@ seen_file (Hash_table const *ht, char const *filename,
return !!hash_lookup (ht, &new_ent);
}
-/* Record destination filename, FILENAME, and dev/ino from *STATS, in
- the hash table, HT, so that if we are asked to overwrite that
- file again, we can detect it and fail. If HT is NULL, return
- immediately. If STATS is NULL, call lstat on FILENAME to get device
- and inode numbers. If that lstat fails, simply return. If memory
- allocation fails, exit immediately. */
+/* Record destination filename, FILENAME, and dev/ino from *STATS,
+ in the hash table, HT. If HT is NULL, return immediately.
+ If STATS is NULL, call lstat on FILENAME to get the device
+ and inode numbers. If that lstat fails, simply return.
+ If memory allocation fails, exit immediately. */
static void
record_file (Hash_table *ht, char const *filename,
struct stat const *stats)
@@ -788,6 +820,24 @@ copy_internal (const char *src_path, const char *dst_path,
return 1;
}
+ /* Detect the case in which the same source file appears more than
+ once on the command line and no backup option has been selected.
+ If so, simply warn and don't copy it the second time.
+ This check is enabled only if x->src_info is non-NULL. */
+ if (command_line_arg)
+ {
+ if ( ! S_ISDIR (src_sb.st_mode)
+ && x->backup_type == none
+ && seen_file (x->src_info, src_path, &src_sb))
+ {
+ error (0, 0, _("warning: source file %s specified more than once"),
+ quote (src_path));
+ return 0;
+ }
+
+ record_file (x->src_info, src_path, &src_sb);
+ }
+
if (!new_dst)
{
if ((*(x->xstat)) (dst_path, &dst_sb))