.
[coreutils.git] / src / cp-hash.c
blob8c07923fdd40856bf506bd2f5c4a7b7f728087c6
1 /* cp-hash.c -- file copying (hash search routines)
2 Copyright (C) 1989, 1990, 1991, 1995 Free Software Foundation.
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.
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.
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
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 Written by Torbjorn Granlund, Sweden (tege@sics.se). */
20 #include <config.h>
21 #include <stdio.h>
22 #include "cp.h"
24 char *hash_insert ();
25 char *hash_insert2 ();
27 struct htab *htab;
28 char new_file;
30 /* Add PATH to the list of files that we have created.
31 Return 0 if successful, 1 if not. */
33 int
34 remember_created (path)
35 char *path;
37 struct stat sb;
39 if (stat (path, &sb) < 0)
41 error (0, errno, "%s", path);
42 return 1;
45 hash_insert (sb.st_ino, sb.st_dev, &new_file);
46 return 0;
49 /* Add path NODE, copied from inode number INO and device number DEV,
50 to the list of files we have copied.
51 Return NULL if inserted, otherwise non-NULL. */
53 char *
54 remember_copied (node, ino, dev)
55 char *node;
56 ino_t ino;
57 dev_t dev;
59 return hash_insert (ino, dev, node);
62 /* Allocate space for the hash structures, and set the global
63 variable `htab' to point to it. The initial hash module is specified in
64 MODULUS, and the number of entries are specified in ENTRY_TAB_SIZE. (The
65 hash structure will be rebuilt when ENTRY_TAB_SIZE entries have been
66 inserted, and MODULUS and ENTRY_TAB_SIZE in the global `htab' will be
67 doubled.) */
69 void
70 hash_init (modulus, entry_tab_size)
71 unsigned modulus;
72 unsigned entry_tab_size;
74 struct htab *htab_r;
76 htab_r = (struct htab *)
77 xmalloc (sizeof (struct htab) + sizeof (struct entry *) * modulus);
79 htab_r->entry_tab = (struct entry *)
80 xmalloc (sizeof (struct entry) * entry_tab_size);
82 htab_r->modulus = modulus;
83 htab_r->entry_tab_size = entry_tab_size;
84 htab = htab_r;
86 forget_all ();
89 /* Reset the hash structure in the global variable `htab' to
90 contain no entries. */
92 void
93 forget_all ()
95 int i;
96 struct entry **p;
98 htab->first_free_entry = 0;
100 p = htab->hash;
101 for (i = htab->modulus; i > 0; i--)
102 *p++ = NULL;
105 /* Insert path NODE, copied from inode number INO and device number DEV,
106 into the hash structure in the global variable `htab', if an entry with
107 the same inode and device was not found already.
108 Return NULL if inserted, otherwise non-NULL. */
110 char *
111 hash_insert (ino, dev, node)
112 ino_t ino;
113 dev_t dev;
114 char *node;
116 struct htab *htab_r = htab;
118 if (htab_r->first_free_entry >= htab_r->entry_tab_size)
120 int i;
121 struct entry *ep;
122 unsigned modulus;
123 unsigned entry_tab_size;
125 /* Increase the number of hash entries, and re-hash the data.
126 The method of shrinking and increasing is made to compactify
127 the heap. If twice as much data would be allocated
128 straightforwardly, we would never re-use a byte of memory. */
130 /* Let htab shrink. Keep only the header, not the pointer vector. */
132 htab_r = (struct htab *)
133 xrealloc ((char *) htab_r, sizeof (struct htab));
135 modulus = 2 * htab_r->modulus;
136 entry_tab_size = 2 * htab_r->entry_tab_size;
138 /* Increase the number of possible entries. */
140 htab_r->entry_tab = (struct entry *)
141 xrealloc ((char *) htab_r->entry_tab,
142 sizeof (struct entry) * entry_tab_size);
144 /* Increase the size of htab again. */
146 htab_r = (struct htab *)
147 xrealloc ((char *) htab_r,
148 sizeof (struct htab) + sizeof (struct entry *) * modulus);
150 htab_r->modulus = modulus;
151 htab_r->entry_tab_size = entry_tab_size;
152 htab = htab_r;
154 i = htab_r->first_free_entry;
156 /* Make the increased hash table empty. The entries are still
157 available in htab->entry_tab. */
159 forget_all ();
161 /* Go through the entries and install them in the pointer vector
162 htab->hash. The items are actually inserted in htab->entry_tab at
163 the position where they already are. The htab->coll_link need
164 however be updated. Could be made a little more efficient. */
166 for (ep = htab_r->entry_tab; i > 0; i--)
168 hash_insert2 (htab_r, ep->ino, ep->dev, ep->node);
169 ep++;
173 return hash_insert2 (htab_r, ino, dev, node);
176 /* Insert path NODE, copied from inode number INO and device number DEV,
177 into the hash structure HTAB, if not already present.
178 Return NULL if inserted, otherwise non-NULL. */
180 char *
181 hash_insert2 (htab, ino, dev, node)
182 struct htab *htab;
183 ino_t ino;
184 dev_t dev;
185 char *node;
187 struct entry **hp, *ep2, *ep;
188 hp = &htab->hash[ino % htab->modulus];
189 ep2 = *hp;
191 /* Collision? */
193 if (ep2 != NULL)
195 ep = ep2;
197 /* Search for an entry with the same data. */
201 if (ep->ino == ino && ep->dev == dev)
202 return ep->node; /* Found an entry with the same data. */
203 ep = ep->coll_link;
205 while (ep != NULL);
207 /* Did not find it. */
211 ep = *hp = &htab->entry_tab[htab->first_free_entry++];
212 ep->ino = ino;
213 ep->dev = dev;
214 ep->node = node;
215 ep->coll_link = ep2; /* ep2 is NULL if not collision. */
217 return NULL;