226 lines
5.6 KiB
C
226 lines
5.6 KiB
C
/*
|
|
* File hash.c - generate hash tables for iso9660 filesystem.
|
|
|
|
Written by Eric Youngdale (1993).
|
|
|
|
Copyright 1993 Yggdrasil Computing, Incorporated
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
static char rcsid[] ="$Id: hash.c,v 1.2 1997/02/23 16:11:15 eric Rel $";
|
|
|
|
#include <stdlib.h>
|
|
#include "mkisofs.h"
|
|
|
|
#define NR_HASH 1024
|
|
|
|
#define HASH_FN(DEV, INO) ((DEV + INO + (INO >> 2) + (INO << 8)) % NR_HASH)
|
|
|
|
static struct file_hash * hash_table[NR_HASH] = {0,};
|
|
|
|
void FDECL1(add_hash, struct directory_entry *, spnt){
|
|
struct file_hash * s_hash;
|
|
unsigned int hash_number;
|
|
|
|
if(spnt->size == 0 || spnt->starting_block == 0)
|
|
if(spnt->size != 0 || spnt->starting_block != 0) {
|
|
fprintf(stderr,"Non zero-length file assigned zero extent.\n");
|
|
exit(1);
|
|
};
|
|
|
|
if (spnt->dev == (dev_t) UNCACHED_DEVICE || spnt->inode == UNCACHED_INODE) return;
|
|
hash_number = HASH_FN((unsigned int) spnt->dev, (unsigned int) spnt->inode);
|
|
|
|
#if 0
|
|
if (verbose) fprintf(stderr,"%s ",spnt->name);
|
|
#endif
|
|
s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash));
|
|
s_hash->next = hash_table[hash_number];
|
|
s_hash->inode = spnt->inode;
|
|
s_hash->dev = spnt->dev;
|
|
s_hash->starting_block = spnt->starting_block;
|
|
s_hash->size = spnt->size;
|
|
hash_table[hash_number] = s_hash;
|
|
}
|
|
|
|
struct file_hash * FDECL2(find_hash, dev_t, dev, ino_t, inode){
|
|
unsigned int hash_number;
|
|
struct file_hash * spnt;
|
|
hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
|
|
if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL;
|
|
|
|
spnt = hash_table[hash_number];
|
|
while(spnt){
|
|
if(spnt->inode == inode && spnt->dev == dev) return spnt;
|
|
spnt = spnt->next;
|
|
};
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static struct file_hash * directory_hash_table[NR_HASH] = {0,};
|
|
|
|
void FDECL2(add_directory_hash, dev_t, dev, ino_t, inode){
|
|
struct file_hash * s_hash;
|
|
unsigned int hash_number;
|
|
|
|
if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return;
|
|
hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
|
|
|
|
s_hash = (struct file_hash *) e_malloc(sizeof(struct file_hash));
|
|
s_hash->next = directory_hash_table[hash_number];
|
|
s_hash->inode = inode;
|
|
s_hash->dev = dev;
|
|
directory_hash_table[hash_number] = s_hash;
|
|
}
|
|
|
|
struct file_hash * FDECL2(find_directory_hash, dev_t, dev, ino_t, inode){
|
|
unsigned int hash_number;
|
|
struct file_hash * spnt;
|
|
hash_number = HASH_FN((unsigned int) dev, (unsigned int) inode);
|
|
if (dev == (dev_t) UNCACHED_DEVICE || inode == UNCACHED_INODE) return NULL;
|
|
|
|
spnt = directory_hash_table[hash_number];
|
|
while(spnt){
|
|
if(spnt->inode == inode && spnt->dev == dev) return spnt;
|
|
spnt = spnt->next;
|
|
};
|
|
return NULL;
|
|
}
|
|
|
|
struct name_hash
|
|
{
|
|
struct name_hash * next;
|
|
struct directory_entry * de;
|
|
};
|
|
|
|
#define NR_NAME_HASH 128
|
|
|
|
static struct name_hash * name_hash_table[NR_NAME_HASH] = {0,};
|
|
|
|
/*
|
|
* Find the hash bucket for this name.
|
|
*/
|
|
static unsigned int FDECL1(name_hash, const char *, name)
|
|
{
|
|
unsigned int hash = 0;
|
|
const char * p;
|
|
|
|
p = name;
|
|
|
|
while (*p)
|
|
{
|
|
/*
|
|
* Don't hash the iso9660 version number. This way
|
|
* we can detect duplicates in cases where we have
|
|
* directories (i.e. foo) and non-directories
|
|
* (i.e. foo;1).
|
|
*/
|
|
if( *p == ';' )
|
|
{
|
|
break;
|
|
}
|
|
hash = (hash << 15) + (hash << 3) + (hash >> 3) + *p++;
|
|
}
|
|
return hash % NR_NAME_HASH;
|
|
}
|
|
|
|
void FDECL1(add_file_hash, struct directory_entry *, de){
|
|
struct name_hash * new;
|
|
int hash;
|
|
|
|
new = (struct name_hash *) e_malloc(sizeof(struct name_hash));
|
|
new->de = de;
|
|
new->next = NULL;
|
|
hash = name_hash(de->isorec.name);
|
|
|
|
/* Now insert into the hash table */
|
|
new->next = name_hash_table[hash];
|
|
name_hash_table[hash] = new;
|
|
}
|
|
|
|
struct directory_entry * FDECL1(find_file_hash, char *, name)
|
|
{
|
|
struct name_hash * nh;
|
|
char * p1;
|
|
char * p2;
|
|
|
|
for(nh = name_hash_table[name_hash(name)]; nh; nh = nh->next)
|
|
{
|
|
p1 = name;
|
|
p2 = nh->de->isorec.name;
|
|
|
|
/*
|
|
* Look for end of string, or a mismatch.
|
|
*/
|
|
while(1==1)
|
|
{
|
|
if( (*p1 == '\0' || *p1 == ';')
|
|
|| (*p2 == '\0' || *p2 == ';')
|
|
|| (*p1 != *p2) )
|
|
{
|
|
break;
|
|
}
|
|
p1++;
|
|
p2++;
|
|
}
|
|
|
|
/*
|
|
* If we are at the end of both strings, then
|
|
* we have a match.
|
|
*/
|
|
if( (*p1 == '\0' || *p1 == ';')
|
|
&& (*p2 == '\0' || *p2 == ';') )
|
|
{
|
|
return nh->de;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int FDECL1(delete_file_hash, struct directory_entry *, de){
|
|
struct name_hash * nh, *prev;
|
|
int hash;
|
|
|
|
prev = NULL;
|
|
hash = name_hash(de->isorec.name);
|
|
for(nh = name_hash_table[hash]; nh; nh = nh->next) {
|
|
if(nh->de == de) break;
|
|
prev = nh;
|
|
}
|
|
if(!nh) return 1;
|
|
if(!prev)
|
|
name_hash_table[hash] = nh->next;
|
|
else
|
|
prev->next = nh->next;
|
|
free(nh);
|
|
return 0;
|
|
}
|
|
|
|
void flush_file_hash(){
|
|
struct name_hash * nh, *nh1;
|
|
int i;
|
|
|
|
for(i=0; i<NR_NAME_HASH; i++) {
|
|
nh = name_hash_table[i];
|
|
while(nh) {
|
|
nh1 = nh->next;
|
|
free(nh);
|
|
nh = nh1;
|
|
}
|
|
name_hash_table[i] = NULL;
|
|
|
|
}
|
|
}
|