255 lines
5.8 KiB
C
255 lines
5.8 KiB
C
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <limits.h>
|
|
|
|
#include "file.h"
|
|
#include "tree.h"
|
|
#include "file_src.h"
|
|
#include "messages.h"
|
|
#include "ecma119.h"
|
|
|
|
//TODO: refactor both hash and this hash table into a single one??
|
|
|
|
struct iso_file *
|
|
iso_file_new(struct ecma119_write_target *t, struct iso_tree_node_file *f)
|
|
{
|
|
struct iso_file *file = calloc(1, sizeof(struct iso_file));
|
|
if (!file)
|
|
return NULL;
|
|
if (f->node.procedence == LIBISO_NEW) {
|
|
file->path = f->loc.path; /*TODO strdup? it needs to be free on clear then */
|
|
file->real_dev = f->node.attrib.st_dev;
|
|
file->real_ino = f->node.attrib.st_ino;
|
|
file->src = iso_file_src_from_path(file->path);
|
|
} else {
|
|
file->block = f->loc.block;
|
|
file->prev_img = 1;
|
|
file->real_dev = 0; /* we use 0 as dev for prev. session files */
|
|
/* don't take care about inode number read from RR TX, block
|
|
* number is good enouht for this. Moreover, when we are modifying
|
|
* an image, we will modify file->block with the block where the
|
|
* file needs to be written in the new image. So, we store the block
|
|
* in original image here */
|
|
file->real_ino = f->loc.block;
|
|
file->src = iso_file_src_from_prev_img(t->src, f->loc.block,
|
|
f->node.attrib.st_size);
|
|
}
|
|
if (!file->src)
|
|
goto creation_error;
|
|
file->size = file->src->get_size(file->src);
|
|
|
|
if (file->size != f->node.attrib.st_size) {
|
|
char msg[PATH_MAX + 32];
|
|
/* can only happen on path files */
|
|
assert(f->node.procedence == LIBISO_NEW);
|
|
sprintf(msg, "Size of file %s has changed\n", file->path);
|
|
iso_msg_sorry(LIBISO_CANT_READ_FILE, msg);
|
|
}
|
|
file->nlink = 1;
|
|
file->sort_weight = f->sort_weight;
|
|
return file;
|
|
creation_error:;
|
|
free(file);
|
|
return NULL;
|
|
}
|
|
|
|
static unsigned int
|
|
iso_file_table_hash(const char *path)
|
|
{
|
|
unsigned int hash_num=0;
|
|
const char *c;
|
|
|
|
c=path;
|
|
while(*c)
|
|
hash_num = (hash_num << 15) + (hash_num << 3) + (hash_num >> 3) + *c++;
|
|
|
|
return hash_num % FILE_HASH_NODES;
|
|
}
|
|
|
|
static inline unsigned int
|
|
iso_file_table_hash_inode(dev_t dev, ino_t ino)
|
|
{
|
|
return (dev ^ ino) % FILE_HASH_NODES;
|
|
}
|
|
|
|
struct iso_file_table*
|
|
iso_file_table_new(int cache_inodes)
|
|
{
|
|
struct iso_file_table *table = calloc(1, sizeof(struct iso_file_table));
|
|
table->cache_inodes = cache_inodes;
|
|
return table;
|
|
}
|
|
|
|
static struct iso_file_hash_node *
|
|
iso_file_table_node_new(struct iso_file *file)
|
|
{
|
|
struct iso_file_hash_node *node;
|
|
node = calloc(1, sizeof(struct iso_file_hash_node) );
|
|
node->file = file;
|
|
return node;
|
|
}
|
|
|
|
static void
|
|
iso_file_table_node_free(struct iso_file_hash_node *node)
|
|
{
|
|
iso_file_src_free(node->file->src);
|
|
free(node->file);
|
|
free(node);
|
|
}
|
|
|
|
void
|
|
iso_file_table_clear(struct iso_file_table *ft)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i < FILE_HASH_NODES; i++) {
|
|
struct iso_file_hash_node *node;
|
|
|
|
node=ft->table[i];
|
|
if (!node)
|
|
continue;
|
|
|
|
ft->table[i] = NULL;
|
|
|
|
do {
|
|
struct iso_file_hash_node *next;
|
|
|
|
next = node->next;
|
|
iso_file_table_node_free(node);
|
|
node = next;
|
|
} while (node);
|
|
}
|
|
ft->count = 0;
|
|
}
|
|
|
|
/**
|
|
* return 0 if equal, != 0 if not
|
|
*/
|
|
static int
|
|
iso_table_compare_files(struct iso_file_table *ft,
|
|
struct iso_file *f1, struct iso_file *f2)
|
|
{
|
|
assert(ft && f1 && f2);
|
|
if (f1->prev_img || f2->prev_img) {
|
|
if (f1->prev_img && f2->prev_img)
|
|
return f1->real_ino != f2->real_ino;
|
|
else
|
|
return 1;
|
|
}
|
|
if (ft->cache_inodes) {
|
|
return (f1->real_dev != f2->real_dev) || (f1->real_ino != f2->real_ino);
|
|
} else {
|
|
return strcmp(f1->path, f2->path);
|
|
}
|
|
}
|
|
|
|
int
|
|
iso_file_table_add_file(struct iso_file_table *ft, struct iso_file *f)
|
|
{
|
|
struct iso_file_hash_node *node;
|
|
unsigned int hash_num;
|
|
|
|
assert(ft && f);
|
|
|
|
/* find the hash number */
|
|
if (f->prev_img)
|
|
hash_num = f->real_ino % FILE_HASH_NODES;
|
|
else if (ft->cache_inodes)
|
|
hash_num = iso_file_table_hash_inode(f->real_dev, f->real_ino);
|
|
else
|
|
hash_num = iso_file_table_hash(f->path);
|
|
|
|
/* insert it */
|
|
node = ft->table[hash_num];
|
|
|
|
/* unfortunately, we can't safely consider that a file
|
|
* won't be twice in the hash table so make sure it
|
|
* doesn't already exists */
|
|
if (!node) {
|
|
ft->table[hash_num]=iso_file_table_node_new(f);
|
|
ft->count++;
|
|
return 1;
|
|
}
|
|
|
|
/* if it's already in, we don't do anything */
|
|
if (!iso_table_compare_files(ft, f, node->file))
|
|
return 0;
|
|
|
|
while (node->next) {
|
|
node = node->next;
|
|
|
|
/* if it's already in, we don't do anything */
|
|
if (!iso_table_compare_files(ft, f, node->file))
|
|
return 0;
|
|
}
|
|
|
|
node->next = iso_file_table_node_new(f);
|
|
ft->count++;
|
|
return 1;
|
|
}
|
|
|
|
/** 0 on equal, != 0 otherwise */
|
|
static int
|
|
iso_table_compare_node_file(struct iso_file_table *ft,
|
|
struct iso_tree_node_file *f1, struct iso_file *f2)
|
|
{
|
|
assert(ft && f1 && f2);
|
|
|
|
if (f1->node.procedence || f2->prev_img) {
|
|
if (f1->node.procedence && f2->prev_img)
|
|
return f1->loc.block != f2->real_ino;
|
|
else
|
|
return 1;
|
|
}
|
|
if (ft->cache_inodes) {
|
|
return (f1->node.attrib.st_dev != f2->real_dev)
|
|
|| (f1->node.attrib.st_ino != f2->real_ino);
|
|
} else {
|
|
return strcmp(f1->loc.path, f2->path);
|
|
}
|
|
}
|
|
|
|
struct iso_file *
|
|
iso_file_table_lookup(struct iso_file_table *ft, struct iso_tree_node_file *f)
|
|
{
|
|
struct iso_file_hash_node *node;
|
|
unsigned int hash_num;
|
|
int equal;
|
|
|
|
assert(ft && f);
|
|
|
|
/* find the hash number */
|
|
if (f->node.procedence == LIBISO_PREVIMG)
|
|
hash_num = f->loc.block % FILE_HASH_NODES;
|
|
else if ( ft->cache_inodes )
|
|
hash_num = iso_file_table_hash_inode(f->node.attrib.st_dev,
|
|
f->node.attrib.st_ino);
|
|
else
|
|
hash_num = iso_file_table_hash(f->loc.path);
|
|
|
|
node = ft->table[hash_num];
|
|
|
|
if (!node)
|
|
return NULL;
|
|
|
|
equal = !iso_table_compare_node_file(ft, f, node->file);
|
|
if (equal)
|
|
return node->file;
|
|
|
|
while (node->next) {
|
|
node = node->next;
|
|
|
|
equal = !iso_table_compare_node_file(ft, f, node->file);
|
|
if (equal)
|
|
return node->file;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|