xref: /openbsd/gnu/usr.sbin/mkhybrid/src/hash.c (revision 68cbdb5e)
1 /*
2  * File hash.c - generate hash tables for iso9660 filesystem.
3 
4    Written by Eric Youngdale (1993).
5 
6    Copyright 1993 Yggdrasil Computing, Incorporated
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2, or (at your option)
11    any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
21 
22 
23 #include <stdlib.h>
24 #include "config.h"
25 #include "mkisofs.h"
26 
27 #define NR_HASH 1024
28 
29 #define HASH_FN(DEV, INO) ((DEV + INO + (INO >> 2) + (INO << 8)) % NR_HASH)
30 
31 static struct file_hash * hash_table[NR_HASH] = {0,};
32 
FDECL1(add_hash,struct directory_entry *,spnt)33 void FDECL1(add_hash, struct directory_entry *, spnt){
34   struct file_hash * s_hash;
35   unsigned int hash_number;
36 
37   if(spnt->size == 0 || spnt->starting_block == 0)
38     if(spnt->size != 0 || spnt->starting_block != 0) {
39       fprintf(stderr,"Non zero-length file assigned zero extent.\n");
40       exit(1);
41     };
42 
43   if (spnt->dev == (dev_t) UNCACHED_DEVICE || spnt->inode == UNCACHED_INODE) return;
44   hash_number = HASH_FN((unsigned int) spnt->dev, (unsigned int) spnt->inode);
45 
46 #if 0
47   if (verbose > 1) fprintf(stderr,"%s ",spnt->name);
48 #endif
49   s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash));
50   s_hash->next = hash_table[hash_number];
51   s_hash->inode = spnt->inode;
52   s_hash->dev = spnt->dev;
53   s_hash->starting_block = spnt->starting_block;
54   s_hash->size = spnt->size;
55   hash_table[hash_number] = s_hash;
56 }
57 
FDECL2(find_hash,dev_t,dev,ino_t,inode)58 struct file_hash * FDECL2(find_hash, dev_t, dev, ino_t, inode){
59   unsigned int hash_number;
60   struct file_hash * spnt;
61   hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
62   if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL;
63 
64   spnt = hash_table[hash_number];
65   while(spnt){
66     if(spnt->inode == inode && spnt->dev == dev) return spnt;
67     spnt = spnt->next;
68   };
69   return NULL;
70 }
71 
72 #ifdef APPLE_HYB
73 /* based on flush_file_hash() below - needed as we wnat to re-use the
74    file hash table */
flush_hash()75 void flush_hash(){
76 	struct file_hash  * fh, *fh1;
77 	int i;
78 
79 	for(i=0; i<NR_HASH; i++) {
80 		fh = hash_table[i];
81 		while(fh) {
82 			fh1 =  fh->next;
83 			free(fh);
84 			fh = fh1;
85 		}
86 		hash_table[i] =  NULL;
87 	}
88 }
89 #endif /* APPLE_HYB */
90 
91 static struct file_hash * directory_hash_table[NR_HASH] = {0,};
92 
FDECL2(add_directory_hash,dev_t,dev,ino_t,inode)93 void FDECL2(add_directory_hash, dev_t, dev, ino_t, inode){
94   struct file_hash * s_hash;
95   unsigned int hash_number;
96 
97   if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return;
98   hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
99 
100   s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash));
101   s_hash->next = directory_hash_table[hash_number];
102   s_hash->inode = inode;
103   s_hash->dev = dev;
104   directory_hash_table[hash_number] = s_hash;
105 }
106 
FDECL2(find_directory_hash,dev_t,dev,ino_t,inode)107 struct file_hash * FDECL2(find_directory_hash, dev_t, dev, ino_t, inode){
108   unsigned int hash_number;
109   struct file_hash * spnt;
110   hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
111   if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL;
112 
113   spnt = directory_hash_table[hash_number];
114   while(spnt){
115     if(spnt->inode == inode && spnt->dev == dev) return spnt;
116     spnt = spnt->next;
117   };
118   return NULL;
119 }
120 
121 struct  name_hash
122 {
123   struct name_hash * next;
124   struct directory_entry * de;
125 };
126 
127 #define NR_NAME_HASH 128
128 
129 static struct name_hash * name_hash_table[NR_NAME_HASH] = {0,};
130 
131 /*
132  * Find the hash bucket for this name.
133  */
FDECL1(name_hash,const char *,name)134 static  unsigned int FDECL1(name_hash, const char *, name)
135 {
136   unsigned int hash = 0;
137   const char * p;
138 
139   p = name;
140 
141   while (*p)
142     {
143       /*
144        * Don't hash the  iso9660 version number.  This way
145        * we can detect duplicates in cases where we have
146        * directories (i.e. foo) and non-directories
147        * (i.e. foo;1).
148        */
149       if( *p == ';' )
150 	{
151 	  break;
152 	}
153       hash = (hash << 15) + (hash << 3) + (hash >> 3) + *p++;
154     }
155   return hash % NR_NAME_HASH;
156 }
157 
FDECL1(add_file_hash,struct directory_entry *,de)158 void FDECL1(add_file_hash, struct directory_entry *, de){
159 	struct name_hash  * new;
160 	int hash;
161 
162 	new = (struct  name_hash *) e_malloc(sizeof(struct name_hash));
163 	new->de = de;
164 	new->next = NULL;
165 	hash = name_hash(de->isorec.name);
166 
167 	/* Now insert into the hash table */
168 	new->next = name_hash_table[hash];
169 	name_hash_table[hash] = new;
170 }
171 
FDECL1(find_file_hash,char *,name)172 struct directory_entry * FDECL1(find_file_hash, char *, name)
173 {
174   struct name_hash  * nh;
175   char		    * p1;
176   char		    * p2;
177 
178   for(nh = name_hash_table[name_hash(name)]; nh; nh = nh->next)
179     {
180       p1 = name;
181       p2 = nh->de->isorec.name;
182 
183       /*
184        * Look for end of string, or a mismatch.
185        */
186       while(1==1)
187 	{
188 	  if(    (*p1 == '\0' || *p1 == ';')
189 	      || (*p2 == '\0' || *p2 == ';')
190 	      || (*p1 != *p2) )
191 	    {
192 	      break;
193 	    }
194 	  p1++;
195 	  p2++;
196 	}
197 
198       /*
199        * If we are at the end of both strings, then
200        * we have a match.
201        */
202       if(    (*p1 == '\0' || *p1 == ';')
203 	  && (*p2 == '\0' || *p2 == ';') )
204 	{
205 	  return nh->de;
206 	}
207     }
208   return NULL;
209 }
210 
FDECL1(delete_file_hash,struct directory_entry *,de)211 int FDECL1(delete_file_hash, struct directory_entry *, de){
212 	struct name_hash  * nh, *prev;
213 	int hash;
214 
215 	prev = NULL;
216 	hash = name_hash(de->isorec.name);
217 	for(nh = name_hash_table[hash]; nh; nh = nh->next) {
218 		if(nh->de == de) break;
219 		prev = nh;
220 	}
221 	if(!nh) return 1;
222 	if(!prev)
223 		name_hash_table[hash] = nh->next;
224 	else
225 		prev->next = nh->next;
226 	free(nh);
227 	return 0;
228 }
229 
flush_file_hash()230 void flush_file_hash(){
231 	struct name_hash  * nh, *nh1;
232 	int i;
233 
234 	for(i=0; i<NR_NAME_HASH; i++) {
235 		nh = name_hash_table[i];
236 		while(nh) {
237 			nh1 =  nh->next;
238 			free(nh);
239 			nh = nh1;
240 		}
241 		name_hash_table[i] =  NULL;
242 
243 	}
244 }
245