From 35ef22cdd78e42fac5400fe667e997f3c804cef5 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sat, 22 Dec 2007 17:09:28 +0100 Subject: [PATCH] Implement ECMA-119 burn_source and writer thread handling. At this time, nglibisofs is able to output an image!! Note that communication between writer and read thread is done via a pipe. That will be replaced by a ring buffer in the near future. --- src/ecma119.c | 92 +++++++++++++++++++++++++++++++++++++++-------- src/ecma119.h | 7 +++- src/error.h | 1 + src/libiso_msgs.h | 2 ++ src/libisofs.h | 5 +++ src/messages.h | 6 +++- 6 files changed, 97 insertions(+), 16 deletions(-) diff --git a/src/ecma119.c b/src/ecma119.c index 157871d..7bd5579 100644 --- a/src/ecma119.c +++ b/src/ecma119.c @@ -455,7 +455,6 @@ int write_path_tables(Ecma119Image *t) Ecma119Node *dir = pathlist[i]; for (j = 0; j < dir->info.dir.nchildren; j++) { Ecma119Node *child = dir->info.dir.children[j]; - //iso_msg_debug(t->image, " bbbbbbbbbb %d %s", j, dir->node->name); if (child->type == ECMA119_DIR) { pathlist[cur++] = child; } @@ -541,13 +540,14 @@ int ecma119_writer_create(Ecma119Image *target) } static -void write_function(Ecma119Image *target) +void *write_function(void *arg) { int res; size_t i; uint8_t buf[BLOCK_SIZE]; IsoImageWriter *writer; + Ecma119Image *target = (Ecma119Image*)arg; iso_msg_debug(target->image, "Starting image writing..."); /* Write System Area, 16 blocks of zeros (ECMA-119, 6.2.1) */ @@ -593,12 +593,14 @@ void write_function(Ecma119Image *target) } } - return; + close(target->wrfd); + pthread_exit(NULL); write_error:; iso_msg_fatal(target->image, LIBISO_WRITE_ERROR, "Image write error, code %d", res); - return; + close(target->wrfd); + pthread_exit(NULL); } static @@ -686,8 +688,35 @@ int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts, target->total_size = (target->curblock - target->ms_block) * BLOCK_SIZE; target->vol_space_size = target->curblock - target->ms_block; - /* 4. Start writting thread */ - //write_function(target); + /* 4. Create and start writting thread */ + + /* TODO for now, a pipe to comunicate both threads + * TODO replace it with a ring buffer */ + ret = pipe(&(target->rdfd)); + if (ret < 0) { + ret = ISO_ERROR; + goto target_cleanup; + } + + /* ensure the thread is created joinable */ + pthread_attr_init(&(target->th_attr)); + pthread_attr_setdetachstate(&(target->th_attr), PTHREAD_CREATE_JOINABLE); + + ret = pthread_create(&(target->wthread), NULL, write_function, + (void *) target); + if (ret != 0) { + iso_msg_fatal(target->image, LIBISO_THREAD_ERROR, + "Cannot create writer thread"); + ret = ISO_THREAD_ERROR; + goto target_cleanup; + } + + /* + * Notice that once we reach this point, target belongs to the writer + * thread and should not be modified until the writer thread finished. + * There're however, specific fields in target that can be accessed, or + * even modified by the read thread (look inside bs_* functions) + */ *img = target; return ISO_SUCCESS; @@ -700,29 +729,62 @@ target_cleanup:; static int bs_read(struct burn_source *bs, unsigned char *buf, int size) { - // TODO to implement - return 0; + ssize_t ret; + int bytes_read = 0; + Ecma119Image *t = (Ecma119Image*)bs->data; + + /* make safe against partial buffer returns */ + while (bytes_read < size) { + ret = read(t->rdfd, buf + bytes_read, size - bytes_read); + if (ret == 0) { + /* EOF */ + return 0; + } else if (ret < 0) { + /* error */ + iso_msg_fatal(t->image, LIBISO_READ_ERROR, "Error reading pipe"); + return -1; + } + bytes_read += ret; + } + return bytes_read; } static off_t bs_get_size(struct burn_source *bs) { - Ecma119Image *image = (Ecma119Image*)bs->data; - return image->total_size; + Ecma119Image *target = (Ecma119Image*)bs->data; + return target->total_size; } static void bs_free_data(struct burn_source *bs) { - ecma119_image_free((Ecma119Image*)bs->data); + Ecma119Image *target = (Ecma119Image*)bs->data; + + /* TODO ugly, forces a SIG_PIPE if writing not finished, + * but I will replace the pipe anyway, so... */ + close(target->rdfd); + + /* wait until writer thread finishes */ + pthread_join(target->wthread, NULL); + + iso_msg_debug(target->image, "Writer thread joined"); + + /* now we can safety free target */ + ecma119_image_free(target); } static int bs_set_size(struct burn_source *bs, off_t size) { - //TODO to implement!! -// struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data; -// t->total_size = size; + Ecma119Image *target = (Ecma119Image*)bs->data; + + /* + * just set the value to be returned by get_size. This is not used at + * all by libisofs, it is here just for helping libburn to correctly pad + * the image if needed. + */ + target->total_size = size; return 1; } @@ -754,6 +816,8 @@ int iso_image_create(IsoImage *image, Ecma119WriteOpts *opts, source->set_size = bs_set_size; source->free_data = bs_free_data; source->data = target; + + *burn_src = source; return ISO_SUCCESS; } diff --git a/src/ecma119.h b/src/ecma119.h index 40c0333..953bcf7 100644 --- a/src/ecma119.h +++ b/src/ecma119.h @@ -13,6 +13,7 @@ #include "util.h" #include +#include #define BLOCK_SIZE 2048 @@ -79,8 +80,12 @@ struct ecma119_image { IsoRBTree *files; /* file descriptors for read and writing image */ - int wrfd; /* write to here */ int rdfd; /* read from here */ + int wrfd; /* write to here */ + + /* writer thread descriptor */ + pthread_t wthread; + pthread_attr_t th_attr; }; #define BP(a,b) [(b) - (a) + 1] diff --git a/src/error.h b/src/error.h index 020cdd0..9e4ed22 100644 --- a/src/error.h +++ b/src/error.h @@ -22,6 +22,7 @@ #define ISO_WRONG_ARG_VALUE -6 #define ISO_WRITE_ERROR -10 +#define ISO_THREAD_ERROR -11 #define ISO_NODE_ALREADY_ADDED -50 #define ISO_NODE_NAME_NOT_UNIQUE -51 diff --git a/src/libiso_msgs.h b/src/libiso_msgs.h index fc6e53b..9a756f7 100644 --- a/src/libiso_msgs.h +++ b/src/libiso_msgs.h @@ -386,6 +386,8 @@ Range "vreixo" : 0x00030000 to 0x0003ffff 0x00030100 (NOTE,MEDIUM) = File cannot be added to image (ignored) 0x00030101 (NOTE,MEDIUM) = File cannot be writing to image (ignored) 0x00030102 (FATAL,HIGH) = Write error + 0x00030103 (FATAL,HIGH) = Read error + 0x00030110 (FATAL,HIGH) = Cannot create writer thread General: 0x00031001 (SORRY,HIGH) = Cannot read file (ignored) diff --git a/src/libisofs.h b/src/libisofs.h index f5a3236..a2783e9 100644 --- a/src/libisofs.h +++ b/src/libisofs.h @@ -10,6 +10,8 @@ #include +struct burn_source; + typedef struct Iso_Image IsoImage; typedef struct Iso_Node IsoNode; @@ -153,6 +155,9 @@ typedef struct { */ int iso_image_new(const char *name, IsoImage **image); +int iso_image_create(IsoImage *image, Ecma119WriteOpts *opts, + struct burn_source **burn_src); + /** * Increments the reference counting of the given image. */ diff --git a/src/messages.h b/src/messages.h index 99cf385..fb4a229 100644 --- a/src/messages.h +++ b/src/messages.h @@ -19,8 +19,12 @@ #define LIBISO_FILE_IGNORED 0x00030100 /** File cannot be writing to image (ignored) */ #define LIBISO_FILE_CANT_WRITE 0x00030101 +/** Read error */ +#define LIBISO_READ_ERROR 0x00030102 /** Write error */ -#define LIBISO_WRITE_ERROR 0x00030102 +#define LIBISO_WRITE_ERROR 0x00030103 +/** Cannot create writer thread */ +#define LIBISO_THREAD_ERROR 0x00030110 /** Can't read file (ignored) */