2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)hash.c 1.18 04/06/18 joerg */
14 /* @(#)hash.c 1.23 06/10/04 joerg */
16 * File hash.c - generate hash tables for iso9660 filesystem.
18 * Written by Eric Youngdale (1993).
20 * Copyright 1993 Yggdrasil Computing, Incorporated
21 * Copyright (c) 1999,2000-2006 J. Schilling
23 * This program is free software; you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License as published by
25 * the Free Software Foundation; either version 2, or (at your option)
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
38 /* APPLE_HYB James Pearson j.pearson@ge.ucl.ac.uk 23/2/2000 */
43 * Cygwin fakes inodes by hashing file info, actual collisions observed!
44 * This is documented in the cygwin source, look at winsup/cygwin/path.cc
45 * and search for the word 'Hash'. On NT, cygwin ORs together the
46 * high and low 32 bits of the 64 bit genuine inode, look at fhandler.cc.
48 * Note: Other operating systems which support the FAT filesystem may
49 * have the same problem because FAT does not use the inode
50 * concept. For NTFS, genuine inode numbers exist, but they are
51 * 64 bits and available only through an open file handle.
53 * The solution is the new options -no-cache-inodes/-cache-inodes that
54 * allow to disable the genisoimage inode cache.
58 #include "genisoimage.h"
61 #define NR_HASH (16*1024)
63 #define HASH_FN(DEV, INO) ((DEV + INO + (INO >> 8) + (INO << 16)) % NR_HASH)
65 static struct file_hash *hash_table[NR_HASH];
67 void add_hash(struct directory_entry *spnt);
68 struct file_hash *find_hash(dev_t dev, ino_t inode);
69 void flush_hash(void);
70 void add_directory_hash(dev_t dev, ino_t inode);
71 struct file_hash *find_directory_hash(dev_t dev, ino_t inode);
72 static unsigned int name_hash(const char *name);
73 void add_file_hash(struct directory_entry *de);
74 struct directory_entry *find_file_hash(char *name);
75 static BOOL isoname_endsok(char *name);
76 int delete_file_hash(struct directory_entry *de);
77 void flush_file_hash(void);
80 add_hash(struct directory_entry *spnt)
82 struct file_hash *s_hash;
83 unsigned int hash_number;
85 if (spnt->size == 0 || spnt->starting_block == 0)
86 if (spnt->size != 0 && spnt->starting_block == 0) {
88 "Non zero-length file '%s' assigned zero extent.\n",
94 if (spnt->dev == UNCACHED_DEVICE &&
95 (spnt->inode == TABLE_INODE || spnt->inode == UNCACHED_INODE)) {
98 hash_number = HASH_FN((unsigned int) spnt->dev,
99 (unsigned int) spnt->inode);
103 fprintf(stderr, "%s ", spnt->name);
105 s_hash = (struct file_hash *) e_malloc(sizeof (struct file_hash));
106 s_hash->next = hash_table[hash_number];
107 s_hash->inode = spnt->inode;
108 s_hash->dev = spnt->dev;
110 s_hash->starting_block = spnt->starting_block;
111 s_hash->size = spnt->size;
115 hash_table[hash_number] = s_hash;
119 find_hash(dev_t dev, ino_t inode)
121 unsigned int hash_number;
122 struct file_hash *spnt;
126 if (dev == UNCACHED_DEVICE &&
127 (inode == TABLE_INODE || inode == UNCACHED_INODE))
130 hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
131 spnt = hash_table[hash_number];
133 if (spnt->inode == inode && spnt->dev == dev)
141 * based on flush_file_hash() below - needed as we want to re-use the
147 struct file_hash *fh;
148 struct file_hash *fh1;
151 for (i = 0; i < NR_HASH; i++) {
158 hash_table[i] = NULL;
162 static struct file_hash *directory_hash_table[NR_HASH];
165 add_directory_hash(dev_t dev, ino_t inode)
167 struct file_hash *s_hash;
168 unsigned int hash_number;
172 if (dev == UNCACHED_DEVICE &&
173 (inode == TABLE_INODE || inode == UNCACHED_INODE))
176 hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
178 s_hash = (struct file_hash *) e_malloc(sizeof (struct file_hash));
179 s_hash->next = directory_hash_table[hash_number];
180 s_hash->inode = inode;
183 directory_hash_table[hash_number] = s_hash;
187 find_directory_hash(dev_t dev, ino_t inode)
189 unsigned int hash_number;
190 struct file_hash *spnt;
194 if (dev == UNCACHED_DEVICE &&
195 (inode == TABLE_INODE || inode == UNCACHED_INODE))
198 hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
199 spnt = directory_hash_table[hash_number];
201 if (spnt->inode == inode && spnt->dev == dev)
209 struct name_hash *next;
210 struct directory_entry *de;
214 #define NR_NAME_HASH (256*1024)
216 static struct name_hash *name_hash_table[NR_NAME_HASH] = {0, };
219 * Find the hash bucket for this name.
222 name_hash(const char *name)
224 unsigned int hash = 0;
231 * Don't hash the iso9660 version number.
232 * This way we can detect duplicates in cases where we have
233 * directories (i.e. foo) and non-directories (i.e. foo;1).
238 hash = (hash << 15) + (hash << 3) + (hash >> 3) + (*p++ & 0xFF);
240 return (hash % NR_NAME_HASH);
244 add_file_hash(struct directory_entry *de)
246 struct name_hash *new;
251 new = (struct name_hash *) e_malloc(sizeof (struct name_hash));
254 for (p = (Uchar *)de->isorec.name; *p; p++) {
260 hash = name_hash(de->isorec.name);
262 /* Now insert into the hash table */
263 new->next = name_hash_table[hash];
264 name_hash_table[hash] = new;
267 struct directory_entry *
268 find_file_hash(register char *name)
272 register struct name_hash *nh;
273 register int sum = 0;
276 fprintf(stderr, "find_hash('%s')\n", name);
278 for (p1 = name; *p1; p1++) {
284 for (nh = name_hash_table[name_hash(name)]; nh; nh = nh->next) {
289 p2 = nh->de->isorec.name;
291 fprintf(stderr, "Checking name '%s' isorec.name '%s'\n", p1, p2);
293 /* Look for end of string, or a mismatch. */
295 if ((*p1 == '\0' || *p1 == ';') ||
296 (*p2 == '\0' || *p2 == ';') ||
303 if (!isoname_endsok(p1) || !isoname_endsok(p2)) {
305 if (!isoname_endsok(p1))
306 fprintf(stderr, "'%s' does NOT END OK\n", p1);
307 if (!isoname_endsok(p2))
308 fprintf(stderr, "'%s' does NOT END OK\n", p2);
311 * If one file does not end with a valid version number
312 * and the other name ends here, we found a miss match.
314 if (*p1 == '\0' || *p2 == '\0')
317 if (*p1 == ';' && *p2 == ';') {
325 * If we are at the end of both strings, then we have a match.
327 if ((*p1 == '\0' || *p1 == ';') &&
328 (*p2 == '\0' || *p2 == ';')) {
336 * The macro 'eo' is just an idea on how one might speed up isoname_endsok()
338 #define eo(p) (((p)[0] == '\0') || \
339 ((p)[0] == ';' && (p)[1] == '1' && (p)[2] == '\0') || \
343 isoname_endsok(char *name)
353 for (p = ++name, i = 0; *p && i < 5; p++, i++) {
354 if (*p < '0' || *p > '9')
358 if (i < 1 || i > 32767)
364 delete_file_hash(struct directory_entry *de)
366 struct name_hash *nh;
367 struct name_hash *prev;
371 hash = name_hash(de->isorec.name);
372 for (nh = name_hash_table[hash]; nh; nh = nh->next) {
380 name_hash_table[hash] = nh->next;
382 prev->next = nh->next;
390 struct name_hash *nh;
391 struct name_hash *nh1;
394 for (i = 0; i < NR_NAME_HASH; i++) {
395 nh = name_hash_table[i];
401 name_hash_table[i] = NULL;