diff --git a/libisofs/trunk/libisofs/ecma119.c b/libisofs/trunk/libisofs/ecma119.c index 13956cce..083a2885 100644 --- a/libisofs/trunk/libisofs/ecma119.c +++ b/libisofs/trunk/libisofs/ecma119.c @@ -20,6 +20,7 @@ #include "tree.h" #include "util.h" #include "file.h" +#include "file_src.h" #include "libisofs.h" #include "libburn/libburn.h" #include "eltorito.h" @@ -553,67 +554,36 @@ wr_dir_records(struct ecma119_write_target *t, uint8_t *buf) static void wr_files(struct ecma119_write_target *t, uint8_t *buf) { + int res; struct state_files *f_st = &t->state_files; - size_t nread; struct iso_file *f = t->filelist[f_st->file]; - - if (f->prev_img) { - int block; - assert( !t->ms_block && t->src ); + + if (!f_st->src) { - /** - * f->block block where file write begins - * t->curblock block we're writting now - * f->real_ino initial block for file on source - */ - block = t->curblock - f->block; - if ( t->src->read_block(t->src, f->real_ino + block, buf) ) { - iso_msg_sorry(LIBISO_CANT_READ_IMG, - "Problem reading file from previous image"); - } - if ( f->size <= (off_t) (block+1) * t->block_size ) { - f_st->file++; - if (f_st->file >= t->filelist_len) - next_state(t); - } - } else { - const char *path = f->path; - - if (!f_st->fd) { - + if (!f->prev_img) { char msg[PATH_MAX + 14]; - sprintf(msg, "Writing file %s", path); + sprintf(msg, "Writing file %s", f->path); iso_msg_debug(msg); - - f_st->data_len = f->size; - f_st->fd = fopen(path, "r"); - if (!f_st->fd) { - //FIXME instead of exit, just print a msg error and - //skip file (what about reading from /dev/zero? instead) - err(1, "couldn't open %s for reading", path); - } - assert(t->curblock + t->ms_block == f->block); - } - - nread = fread(buf, 1, t->block_size, f_st->fd); - f_st->pos += t->block_size; - if (nread < 0) { - char msg[PATH_MAX + 32]; - sprintf(msg, "Problem reading from %s", path); - iso_msg_sorry(LIBISO_CANT_READ_FILE, msg); - } else if (nread != t->block_size && f_st->pos < f_st->data_len) { - char msg[PATH_MAX + 32]; - sprintf(msg, "Incomplete read from %s", path); - iso_msg_sorry(LIBISO_CANT_READ_FILE, msg); - } - if (f_st->pos >= f_st->data_len) { - fclose(f_st->fd); - f_st->fd = 0; - f_st->pos = 0; - f_st->file++; - if (f_st->file >= t->filelist_len) - next_state(t); + } + + f_st->src = f->src; + if ( f->src->open(f->src) <= 0) { + //FIXME instead of exit, just print a msg error and + //skip file (what about reading from /dev/zero? instead) + /* can only happen with new files */ + err(1, "couldn't open %s for reading", f->path); } + assert(t->curblock + t->ms_block == f->block); + } + + res = f_st->src->read_block(f_st->src, buf); + if (res == 0) { + /* we have read the expected bytes from file */ + f_st->src->close(f_st->src); + f_st->src = NULL; + f_st->file++; + if (f_st->file >= t->filelist_len) + next_state(t); } } @@ -932,8 +902,10 @@ bs_free_data(struct burn_source *bs) free(t->state_data); if (t->joliet) joliet_tree_free(t->joliet_root); - if (t->state_files.fd) - fclose(t->state_files.fd); + + // TODO is this needed? + if (t->state_files.src) + t->state_files.src->close(t->state_files.src); } struct burn_source *iso_source_new_ecma119(struct iso_volset *volset, diff --git a/libisofs/trunk/libisofs/ecma119.h b/libisofs/trunk/libisofs/ecma119.h index 4d93b87e..bdc67a47 100644 --- a/libisofs/trunk/libisofs/ecma119.h +++ b/libisofs/trunk/libisofs/ecma119.h @@ -174,13 +174,14 @@ struct ecma119_write_target /* for writing out files */ struct state_files { - off_t pos; /* The number of bytes we have written - * so far in the current file. - */ - off_t data_len;/* The number of bytes in the currently - * open file. - */ - FILE *fd; /* The currently open file. */ +// off_t pos; /* The number of bytes we have written +// * so far in the current file. +// */ +// off_t data_len;/* The number of bytes in the currently +// * open file. +// */ +// FILE *fd; /* The currently open file. */ + struct iso_file_src *src; /* source for reading from the file */ int file; /* The index in filelist that we are * currently writing (or about to write). */ } state_files; diff --git a/libisofs/trunk/libisofs/ecma119_tree.c b/libisofs/trunk/libisofs/ecma119_tree.c index e49f6d9f..dc140fbc 100644 --- a/libisofs/trunk/libisofs/ecma119_tree.c +++ b/libisofs/trunk/libisofs/ecma119_tree.c @@ -183,7 +183,16 @@ create_file(struct ecma119_write_target *t, * If the file is not already added to the disc, we add it now * to the file table, and get a new inode number for it. */ - file = iso_file_new(iso); + file = iso_file_new(t, iso); + if (!file) { + /* + * That was an error. + * TODO currently this cause the file to be ignored... Maybe + * throw an error is a better alternative + */ + ecma119_tree_free(ret); + return NULL; + } iso_file_table_add_file(t->file_table, file); file->ino = ++t->ino; } else { diff --git a/libisofs/trunk/libisofs/file.c b/libisofs/trunk/libisofs/file.c index 8e1d04cb..c726503a 100644 --- a/libisofs/trunk/libisofs/file.c +++ b/libisofs/trunk/libisofs/file.c @@ -1,23 +1,31 @@ #include #include -#include +#include #include +#include #include #include +#include #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 iso_tree_node_file *f) +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; @@ -26,14 +34,28 @@ iso_file_new(struct iso_tree_node_file *f) * 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, because we will need to use it for - * reading file contents */ + * 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->size = f->node.attrib.st_size; file->nlink = 1; file->sort_weight = f->sort_weight; return file; +creation_error:; + free(file); + return NULL; } static unsigned int @@ -75,6 +97,7 @@ iso_file_table_node_new(struct iso_file *file) 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); } diff --git a/libisofs/trunk/libisofs/file.h b/libisofs/trunk/libisofs/file.h index d751b072..c1253b1e 100644 --- a/libisofs/trunk/libisofs/file.h +++ b/libisofs/trunk/libisofs/file.h @@ -30,6 +30,7 @@ struct iso_file { dev_t real_dev; ino_t real_ino; /**< for lookup by inode caching */ int sort_weight; + struct iso_file_src *src; }; struct iso_file_hash_node { @@ -44,12 +45,14 @@ struct iso_file_table { }; struct iso_tree_node_file; +struct ecma119_write_target; /** * Create a struct that represents the specified iso_tree_node_file, * suitable to be stored into the table, */ -struct iso_file *iso_file_new(struct iso_tree_node_file*); +struct iso_file *iso_file_new(struct ecma119_write_target *t, + struct iso_tree_node_file*); struct iso_file_table *iso_file_table_new(int cache_inodes); diff --git a/libisofs/trunk/libisofs/file_src.c b/libisofs/trunk/libisofs/file_src.c index f7ed4d86..04e9ec18 100644 --- a/libisofs/trunk/libisofs/file_src.c +++ b/libisofs/trunk/libisofs/file_src.c @@ -1,3 +1,10 @@ +/* + * Implementation of iso_file_src for: + * + * a) read from local filesystem files + * b) read from previous session / image files + */ + #include #include #include @@ -10,9 +17,24 @@ #include "file_src.h" #include "messages.h" +#include "libisofs.h" +#include "util.h" #define BLOCK_SIZE 2048 + +void iso_file_src_free(struct iso_file_src *src) +{ + src->free_data(src); + free(src); +} + +/* + * ========================================================================== + * A) FILE SRC FOR LOCAL FILESYSTEM FILES + * ========================================================================== + */ + struct local_file_data { int fd; /* the file descriptor, once the file is opened */ off_t size; /* file size */ @@ -117,7 +139,10 @@ off_t lf_get_size(struct iso_file_src *src) static void lf_free_data(struct iso_file_src *src) { - free(src->data); + struct local_file_data *data; + data = (struct local_file_data*) src->data; + free(data->path); + free(data); } struct iso_file_src* @@ -161,3 +186,121 @@ iso_file_src_from_path(const char *path) src->data = data; return src; } + + +/* + * ========================================================================== + * B) FILE SRC FOR PREVIOUS IMAGE FILES + * ========================================================================== + */ + +struct prev_img_file_data { + int block; /* block where image begins */ + off_t size; /* file size */ + int nblocks; /* file size in blocks */ + int current; /* last block read from file */ + int error; + struct data_source *src; /* source for reading from previous image */ +}; + +static +int pi_open(struct iso_file_src *src) +{ + struct prev_img_file_data *data; + assert(src); + + data = (struct prev_img_file_data*) src->data; + data->current = data->block; + data->error = 0; + return 1; +} + +static +void pi_close(struct iso_file_src *src) +{ + /* nothing needed */ + return; +} + +static +int pi_read_block(struct iso_file_src *src, unsigned char *buffer) +{ + int res; + struct prev_img_file_data *data; + assert(src); + assert(buffer); + + data = (struct prev_img_file_data*) src->data; + + if (data->current >= data->block + data->nblocks) { + return 0; + } + + if (data->error) { + memset(buffer, 0, BLOCK_SIZE); + data->current++; + return -2; + } + + res = data->src->read_block(data->src, data->current++, buffer); + if (res < 0) { + iso_msg_sorry(LIBISO_CANT_READ_IMG, + "Problem reading file from previous image"); + /* fill buffer with 0s and return */ + memset(buffer, 0, BLOCK_SIZE); + return -1; + } + + if (data->current >= data->block + data->nblocks) { + return 0; + } else { + return 1; + } +} + +static +off_t pi_get_size(struct iso_file_src *src) +{ + struct prev_img_file_data *data; + assert(src); + + data = (struct prev_img_file_data*) src->data; + return data->size; +} + +static +void pi_free_data(struct iso_file_src *src) +{ + free(src->data); +} + +struct iso_file_src* +iso_file_src_from_prev_img(struct data_source* data_src, int block, off_t size) +{ + struct iso_file_src *src; + struct prev_img_file_data *data; + + data = malloc(sizeof(struct prev_img_file_data)); + if (!data) + return NULL; + + src = malloc(sizeof(struct iso_file_src)); + if (!src) { + free(data); + return NULL; + } + + data->block = block; + data->size = size; + data->nblocks = div_up(size, BLOCK_SIZE); + data->src = data_src; + + src->open = pi_open; + src->close = pi_close; + src->read_block = pi_read_block; + src->get_size = pi_get_size; + src->free_data = pi_free_data; + + src->data = data; + return src; +} diff --git a/libisofs/trunk/libisofs/file_src.h b/libisofs/trunk/libisofs/file_src.h index f0b3abfa..acf431ee 100644 --- a/libisofs/trunk/libisofs/file_src.h +++ b/libisofs/trunk/libisofs/file_src.h @@ -12,6 +12,8 @@ #include +struct data_source; + struct iso_file_src { /** @@ -74,7 +76,17 @@ struct iso_file_src { struct iso_file_src* iso_file_src_from_path(const char *path); /** - * close and free a iso_file_src + * Get a iso_file_src() for reading from a previous image file. + * @param src data_source to read from previous image. It is not freed, + * so you need to free it when no more needed. + * @param block block on image where file begins + * @param nblocks number of block of the file + */ +struct iso_file_src* +iso_file_src_from_prev_img(struct data_source* src, int block, off_t size); + +/** + * free a iso_file_src */ void iso_file_src_free(struct iso_file_src *src); diff --git a/libisofs/trunk/libisofs/joliet.c b/libisofs/trunk/libisofs/joliet.c index dda25799..8fc0df0b 100644 --- a/libisofs/trunk/libisofs/joliet.c +++ b/libisofs/trunk/libisofs/joliet.c @@ -36,7 +36,16 @@ create_node(struct ecma119_write_target *t, struct iso_file *file; file = iso_file_table_lookup(t->file_table, iso_f); if ( file == NULL ) { - file = iso_file_new(iso_f); + file = iso_file_new(t, iso_f); + if (!file) { + /* + * That was an error. + * TODO currently this cause the file to be ignored... Maybe + * throw an error is a better alternative + */ + joliet_tree_free(ret); + return NULL; + } iso_file_table_add_file(t->file_table, file); } ret->info.file = file;