From 2f383215ffa1e1a4d79bf3662d7d4c796c2e844c Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Thu, 20 Dec 2007 22:17:18 +0100 Subject: [PATCH] Implement Writer for file contents. Some aspects, such as better reporting of file bigger or smaller than expected is needed, but all situations are handled propertly. --- src/ecma119.c | 6 +- src/filesrc.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++ src/filesrc.h | 41 +-------- src/libiso_msgs.h | 1 + src/messages.h | 2 + src/util.c | 10 --- src/util.h | 10 ++- 7 files changed, 238 insertions(+), 51 deletions(-) diff --git a/src/ecma119.c b/src/ecma119.c index 1bb25a4..0d024d0 100644 --- a/src/ecma119.c +++ b/src/ecma119.c @@ -310,7 +310,6 @@ int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts, target->ms_block = 0; target->input_charset = strdup("UTF-8"); //TODO - /* * 2. Based on those options, create needed writers: iso, joliet... * Each writer inits its structures and stores needed info into @@ -338,6 +337,11 @@ int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts, /* Volume Descriptor Set Terminator */ target->curblock++; + /* create writer for file contents */ + ret = iso_file_src_writer_create(target); + if (ret < 0) { + goto target_cleanup; + } /* * 3. diff --git a/src/filesrc.c b/src/filesrc.c index d66711a..819befd 100644 --- a/src/filesrc.c +++ b/src/filesrc.c @@ -10,8 +10,11 @@ #include "error.h" #include "node.h" #include "util.h" +#include "writer.h" +#include "messages.h" #include +#include int iso_file_src_cmp(const void *n1, const void *n2) { @@ -101,3 +104,219 @@ off_t iso_file_src_get_size(IsoFileSrc *file) { return iso_stream_get_size(file->stream); } + +static int +cmp_by_weight(const void *f1, const void *f2) +{ + IsoFileSrc *f = *((IsoFileSrc**)f1); + IsoFileSrc *g = *((IsoFileSrc**)f2); + /* higher weighted first */ + return g->sort_weight - f->sort_weight; +} + +static +int filesrc_writer_compute_data_blocks(IsoImageWriter *writer) +{ + size_t i, size; + Ecma119Image *t; + IsoFileSrc **filelist; + + if (writer == NULL) { + return ISO_MEM_ERROR; + } + + t = writer->target; + + /* store the filesrcs in a array */ + filelist = (IsoFileSrc**)iso_rbtree_to_array(t->files); + if (filelist == NULL) { + return ISO_MEM_ERROR; + } + + size = iso_rbtree_get_size(t->files); + + /* sort files by weight, if needed */ + if (t->sort_files) { + qsort(t->files, size, sizeof(void*), cmp_by_weight); + } + + /* fill block value */ + for (i = 0; i < size; ++i) { + IsoFileSrc *file = filelist[i]; + file->block = t->curblock; + t->curblock += div_up(iso_file_src_get_size(file), BLOCK_SIZE); + } + + /* the list is only needed by this writer, store locally */ + writer->data = filelist; + return ISO_SUCCESS; +} + +static +int filesrc_writer_write_vol_desc(IsoImageWriter *writer) +{ + /* nothing needed */ + return ISO_SUCCESS; +} + +/* open a file, i.e., its Stream */ +static inline +int filesrc_open(IsoFileSrc *file) +{ + return iso_stream_open(file->stream); +} + +static inline +int filesrc_close(IsoFileSrc *file) +{ + return iso_stream_close(file->stream); +} + +/** + * @return + * 1 ok, 0 EOF, < 0 error + */ +static +int filesrc_read(IsoFileSrc *file, char *buf, size_t count) +{ + size_t bytes = 0; + + /* loop to ensure the full buffer is filled */ + do { + ssize_t result; + result = iso_stream_read(file->stream, buf + bytes, count - bytes); + if (result < 0) { + /* fill buffer with 0s and return */ + memset(buf + bytes, 0, count - bytes); + return result; + } + if (result == 0) + break; + bytes += result; + } while (bytes < count); + + if (bytes < count) { + /* eof */ + memset(buf + bytes, 0, count - bytes); + return 0; + } else { + return 1; + } +} + +static +int filesrc_writer_write_data(IsoImageWriter *writer) +{ + int res; + size_t i, b, nfiles; + Ecma119Image *t; + IsoFileSrc **filelist; + char buffer[BLOCK_SIZE]; + + if (writer == NULL) { + return ISO_MEM_ERROR; + } + + t = writer->target; + filelist = writer->data; + + nfiles = iso_rbtree_get_size(t->files); + for (i = 0; i < nfiles; ++i) { + IsoFileSrc *file = filelist[i]; + + /* + * TODO WARNING + * when we allow files greater than 4GB, current div_up implementation + * can overflow!! + */ + uint32_t nblocks = div_up(iso_file_src_get_size(file), BLOCK_SIZE); + + res = filesrc_open(file); + if (res < 0) { + /* + * UPS, very ugly error, the best we can do is just to write + * 0's to image + */ + // TODO Stream needs a get_path function + iso_msg_sorry(t->image, LIBISO_FILE_CANT_WRITE, + "File XXX can't be openned. Filling with 0s."); + memset(buffer, 0, BLOCK_SIZE); + for (b = 0; b < nblocks; ++b) { + res = iso_write(t, buffer, BLOCK_SIZE); + if (res < 0) { + /* ko, writer error, we need to go out! */ + return res; + } + } + continue; + } + + /* write file contents to image */ + for (b = 0; b < nblocks; ++b) { + int wres; + res = filesrc_read(file, buffer, BLOCK_SIZE); + wres = iso_write(t, buffer, BLOCK_SIZE); + if (wres < 0) { + /* ko, writer error, we need to go out! */ + return wres; + } + } + + if (b < nblocks) { + /* premature end of file, due to error or eof */ + if (res < 0) { + /* error */ + iso_msg_sorry(t->image, LIBISO_FILE_CANT_WRITE, + "Read error in file XXXXX."); + } else { + /* eof */ + iso_msg_sorry(t->image, LIBISO_FILE_CANT_WRITE, + "Premature end of file XXXXX."); + } + /* fill with 0s */ + iso_msg_sorry(t->image, LIBISO_FILE_CANT_WRITE, "Filling with 0"); + memset(buffer, 0, BLOCK_SIZE); + while (b++ < nblocks) { + res = iso_write(t, buffer, BLOCK_SIZE); + if (res < 0) { + /* ko, writer error, we need to go out! */ + return res; + } + } + } + + filesrc_close(file); + } + + return ISO_SUCCESS; +} + +static +int filesrc_writer_free_data(IsoImageWriter *writer) +{ + /* free the list of files (contents are free together with the tree) */ + free(writer->data); + return ISO_SUCCESS; +} + +int iso_file_src_writer_create(Ecma119Image *target) +{ + IsoImageWriter *writer; + + writer = malloc(sizeof(IsoImageWriter)); + if (writer == NULL) { + return ISO_MEM_ERROR; + } + + writer->compute_data_blocks = filesrc_writer_compute_data_blocks; + writer->write_vol_desc = filesrc_writer_write_vol_desc; + writer->write_data = filesrc_writer_write_data; + writer->free_data = filesrc_writer_free_data; + writer->data = NULL; + writer->target = target; + + /* add this writer to image */ + target->writers[target->nwriters++] = writer; + + return ISO_SUCCESS; +} diff --git a/src/filesrc.h b/src/filesrc.h index fa95318..46425c6 100644 --- a/src/filesrc.h +++ b/src/filesrc.h @@ -52,46 +52,11 @@ void iso_file_src_free(void *node); */ off_t iso_file_src_get_size(IsoFileSrc *file); -// TODO not implemented -int iso_file_src_open(IsoFileSrc *file); - -// TODO not implemented -int iso_file_src_close(IsoFileSrc *file); - /** - * TODO define propertly this comment - * TODO not implemented + * Create a Writer for file contents. * - * Read a block (2048 bytes) from the IsoFileSrc. - * - * This function should always read the full 2048 bytes, blocking if - * needed. When it reaches EOF, the buf is filled with 0's, if needed. - * Note that the EOF is not reported in that call, but in the next call. - * I.e., when the EOF is reported you can be sure that the function - * has not written anything to the buffer. If the file size is a multiple - * of block size, i.e N*2048, the read_block reports the EOF just when - * reading the N+1 block. - * - * Note that EOF refers to the original size as reported by get_size. - * If the underlying source size has changed, this function should take - * care of this, truncating the file, or filling the buffer with 0s. I.e. - * this function return 0 (EOF) only when get_size() bytes have been - * readed. - * - * On an I/O error, or a file smaller than the expected size, this - * function returns a [specific error code], and the buffer is filled - * with 0s. Subsequent calls will still return an error code and fill - * buffer with 0's, until EOF (as defined above) is reached, and then - * the function will return 0. - * - * Note that if the current size is larger than expected, you don't get - * any error on reading. - * - * @param buf - * Buffer where data fill be copied, with at least 2048 bytes. - * @return - * 1 sucess, 0 EOF, < 0 error (buf is filled with 0's) + * It takes care of written the files in the correct order. */ -int iso_file_src_read_block(IsoFileSrc *file, void *buf); +int iso_file_src_writer_create(Ecma119Image *target); #endif /*LIBISO_FILESRC_H_*/ diff --git a/src/libiso_msgs.h b/src/libiso_msgs.h index a4ad5bf..ee1cb8e 100644 --- a/src/libiso_msgs.h +++ b/src/libiso_msgs.h @@ -384,6 +384,7 @@ Range "vreixo" : 0x00030000 to 0x0003ffff Image creation: 0x00030100 (NOTE,MEDIUM) = File cannot be added to image (ignored) + 0x00030101 (NOTE,MEDIUM) = File cannot be writing to image (ignored) General: 0x00031001 (SORRY,HIGH) = Cannot read file (ignored) diff --git a/src/messages.h b/src/messages.h index 5c41307..6e534c2 100644 --- a/src/messages.h +++ b/src/messages.h @@ -17,6 +17,8 @@ /** File cannot be added to image (ignored) */ #define LIBISO_FILE_IGNORED 0x00030100 +/** File cannot be writing to image (ignored) */ +#define LIBISO_FILE_CANT_WRITE 0x00030101 /** Can't read file (ignored) */ #define LIBISO_CANT_READ_FILE 0x00031001 diff --git a/src/util.c b/src/util.c index 1f9022b..f4cb9ea 100644 --- a/src/util.c +++ b/src/util.c @@ -18,16 +18,6 @@ #include #include -int div_up(int n, int div) -{ - return (n + div - 1) / div; -} - -int round_up(int n, int mul) -{ - return div_up(n, mul) * mul; -} - int int_pow(int base, int power) { int result = 1; diff --git a/src/util.h b/src/util.h index 3cb4f16..700ce9a 100644 --- a/src/util.h +++ b/src/util.h @@ -20,9 +20,15 @@ # define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif -extern inline int div_up(int n, int div); +extern inline int div_up(unsigned int n, unsigned int div) +{ + return (n + div - 1) / div; +} -extern inline int round_up(int n, int mul); +extern inline int round_up(unsigned int n, unsigned int mul) +{ + return div_up(n, mul) * mul; +} int int_pow(int base, int power);