*** empty log message ***
[platform/upstream/coreutils.git] / src / cp-hash.c
1 /* cp-hash.c  -- file copying (hash search routines)
2    Copyright (C) 89, 90, 91, 1995-2005 Free Software Foundation.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18    Written by Torbjorn Granlund, Sweden (tege@sics.se).
19    Rewritten to use lib/hash.c by Jim Meyering.  */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include "system.h"
26
27 #include "same.h"
28 #include "quote.h"
29 #include "hash.h"
30 #include "error.h"
31 #include "cp-hash.h"
32
33 /* Use ST_DEV and ST_INO as the key, FILENAME as the value.
34    These are used e.g., in copy.c to associate the destination name with
35    the source device/inode pair so that if we encounter a matching dev/ino
36    pair in the source tree we can arrange to create a hard link between
37    the corresponding names in the destination tree.  */
38 struct Src_to_dest
39 {
40   ino_t st_ino;
41   dev_t st_dev;
42   /* Destination file name (of non-directory or pre-existing directory)
43      corresponding to the dev/ino of a copied file, or the destination file
44      name corresponding to a dev/ino pair for a newly-created directory. */
45   char *name;
46 };
47
48 /* This table maps source dev/ino to destination file name.
49    We use it to preserve hard links when copying.  */
50 static Hash_table *src_to_dest;
51
52 /* Initial size of the above hash table.  */
53 #define INITIAL_TABLE_SIZE 103
54
55 static size_t
56 src_to_dest_hash (void const *x, size_t table_size)
57 {
58   struct Src_to_dest const *p = x;
59
60   /* Ignoring the device number here should be fine.  */
61   /* The cast to uintmax_t prevents negative remainders
62      if st_ino is negative.  */
63   return (uintmax_t) p->st_ino % table_size;
64 }
65
66 /* Compare two Src_to_dest entries.
67    Return true if their keys are judged `equal'.  */
68 static bool
69 src_to_dest_compare (void const *x, void const *y)
70 {
71   struct Src_to_dest const *a = x;
72   struct Src_to_dest const *b = y;
73   return SAME_INODE (*a, *b) ? true : false;
74 }
75
76 static void
77 src_to_dest_free (void *x)
78 {
79   struct Src_to_dest *a = x;
80   free (a->name);
81   free (x);
82 }
83
84 /* Remove the entry matching INO/DEV from the table
85    that maps source ino/dev to destination file name.  */
86 extern void
87 forget_created (ino_t ino, dev_t dev)
88 {
89   struct Src_to_dest probe;
90   struct Src_to_dest *ent;
91
92   probe.st_ino = ino;
93   probe.st_dev = dev;
94   probe.name = NULL;
95
96   ent = hash_delete (src_to_dest, &probe);
97   if (ent)
98     src_to_dest_free (ent);
99 }
100
101 /* Add FILE to the list of files that we have created.
102    Return true if successful.  */
103
104 extern bool
105 remember_created (char const *file)
106 {
107   struct stat sb;
108
109   if (stat (file, &sb) < 0)
110     {
111       error (0, errno, "%s", quote (file));
112       return false;
113     }
114
115   remember_copied (file, sb.st_ino, sb.st_dev);
116   return true;
117 }
118
119 /* If INO/DEV correspond to an already-copied source file, return the
120    name of the corresponding destination file.  Otherwise, return NULL.  */
121
122 extern char *
123 src_to_dest_lookup (ino_t ino, dev_t dev)
124 {
125   struct Src_to_dest ent;
126   struct Src_to_dest const *e;
127   ent.st_ino = ino;
128   ent.st_dev = dev;
129   e = hash_lookup (src_to_dest, &ent);
130   return e ? e->name : NULL;
131 }
132
133 /* Add file NAME, copied from inode number INO and device number DEV,
134    to the list of files we have copied.
135    Return NULL if inserted, otherwise non-NULL. */
136
137 extern char *
138 remember_copied (const char *name, ino_t ino, dev_t dev)
139 {
140   struct Src_to_dest *ent;
141   struct Src_to_dest *ent_from_table;
142
143   ent = xmalloc (sizeof *ent);
144   ent->name = xstrdup (name);
145   ent->st_ino = ino;
146   ent->st_dev = dev;
147
148   ent_from_table = hash_insert (src_to_dest, ent);
149   if (ent_from_table == NULL)
150     {
151       /* Insertion failed due to lack of memory.  */
152       xalloc_die ();
153     }
154
155   /* Determine whether there was already an entry in the table
156      with a matching key.  If so, free ENT (it wasn't inserted) and
157      return the `name' from the table entry.  */
158   if (ent_from_table != ent)
159     {
160       src_to_dest_free (ent);
161       return (char *) ent_from_table->name;
162     }
163
164   /* New key;  insertion succeeded.  */
165   return NULL;
166 }
167
168 /* Initialize the hash table.  */
169 extern void
170 hash_init (void)
171 {
172   src_to_dest = hash_initialize (INITIAL_TABLE_SIZE, NULL,
173                                  src_to_dest_hash,
174                                  src_to_dest_compare,
175                                  src_to_dest_free);
176   if (src_to_dest == NULL)
177     xalloc_die ();
178 }
179
180 /* Reset the hash structure in the global variable `htab' to
181    contain no entries.  */
182
183 extern void
184 forget_all (void)
185 {
186   hash_free (src_to_dest);
187 }