From 3f918d1acbbf95c4cf83d8aea76d2355c1f59f5c Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Sat, 22 Aug 2009 19:38:07 +0200 Subject: [PATCH] New API call iso_file_make_md5() to equip old file nodes with MD5. --- libisofs/ecma119.c | 25 ++++++++---- libisofs/filesrc.c | 76 +++++++----------------------------- libisofs/libisofs.h | 31 +++++++++++++-- libisofs/md5.c | 57 ++++++++++++++++++++------- libisofs/md5.h | 7 ---- libisofs/node.c | 45 ++++++++++++++++++++++ libisofs/stream.c | 93 +++++++++++++++++++++++++++++++++++++++++++++ libisofs/stream.h | 20 ++++++++++ libisofs/util.h | 22 +++++++++++ 9 files changed, 282 insertions(+), 94 deletions(-) diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index c91f42a..ee4ff52 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -962,10 +962,10 @@ int checksum_prepare_nodes(Ecma119Image *target, IsoNode *node, int flag) IsoNode *pos; IsoFile *file; IsoImage *img; - int ret, i, no_md5 = 0; + int ret, i, no_md5 = 0, has_xinfo = 0; size_t value_length; unsigned int idx = 0; - char *value; + char *value= NULL, *direct_md5; void *xipt = NULL; static char *cx_names = "isofs.cx"; static size_t cx_value_lengths[1] = {0}; @@ -978,10 +978,17 @@ int checksum_prepare_nodes(Ecma119Image *target, IsoNode *node, int flag) if (file->from_old_session && target->appendable) { /* Save MD5 data of files from old image which will not be copied and have an MD5 recorded in the old image. */ - value= NULL; - ret = iso_node_lookup_attr(node, "isofs.cx", &value_length, - &value, 0); - if (ret == 1 && img->checksum_array == NULL) { + has_xinfo = iso_node_get_xinfo(node, checksum_md5_xinfo_func, + &xipt); + if (has_xinfo <= 0) { + ret = iso_node_lookup_attr(node, "isofs.cx", &value_length, + &value, 0); + } + if (has_xinfo > 0) { + /* xinfo MD5 overrides everything else unless data get copied + and checksummed during that copying + */; + } else if (ret == 1 && img->checksum_array == NULL) { /* No checksum array loaded. Delete "isofs.cx" */ iso_node_set_attrs(node, (size_t) 1, &cx_names, cx_value_lengths, &cx_valuept, 4 | 8); @@ -993,7 +1000,7 @@ int checksum_prepare_nodes(Ecma119Image *target, IsoNode *node, int flag) /* xipt is an int disguised as void pointer */ for (i = 0; i < 4; i++) ((char *) &xipt)[i] = value[i]; - ret = iso_node_add_xinfo(node, checksum_xinfo_func, + ret = iso_node_add_xinfo(node, checksum_cx_xinfo_func, xipt); if (ret < 0) return ret; @@ -1002,8 +1009,10 @@ int checksum_prepare_nodes(Ecma119Image *target, IsoNode *node, int flag) } else { no_md5 = 1; } - if (value != NULL) + if (value != NULL) { free(value); + value= NULL; + } } /* Equip nodes with provisory isofs.cx numbers: 4 byte, all 0. Omit those from old image which will not be copied and have no MD5. diff --git a/libisofs/filesrc.c b/libisofs/filesrc.c index 0cf2d3d..505b7d1 100644 --- a/libisofs/filesrc.c +++ b/libisofs/filesrc.c @@ -119,17 +119,21 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src) #ifdef Libisofs_with_checksumS if ((img->md5_file_checksums & 1) && - file->from_old_session && img->appendable) { - /* Omit MD5 indexing with old image nodes which have no MD5 */ - ret = iso_node_get_xinfo((IsoNode *) file, checksum_xinfo_func, &xipt); + file->from_old_session && img->appendable) { + ret = iso_node_get_xinfo((IsoNode *) file, checksum_md5_xinfo_func, + &xipt); if (ret <= 0) + ret = iso_node_get_xinfo((IsoNode *) file, checksum_cx_xinfo_func, + &xipt); + if (ret <= 0) + /* Omit MD5 indexing with old image nodes which have no MD5 */ no_md5 = 1; } if ((img->md5_file_checksums & 1) && !no_md5) { img->checksum_idx_counter++; if (img->checksum_idx_counter < 0x80000000) { - fsrc->checksum_index= img->checksum_idx_counter; + fsrc->checksum_index = img->checksum_idx_counter; } else { fsrc->checksum_index= 0; img->checksum_idx_counter= 0x80000000; /* keep from rolling over */ @@ -289,29 +293,9 @@ int filesrc_close(IsoFileSrc *file) static int filesrc_read(IsoFileSrc *file, char *buf, size_t count) { - size_t bytes = 0; + size_t got; - /* 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; - } + return iso_stream_read_buffer(file->stream, buf, count, &got); } #ifdef Libisofs_with_checksumS @@ -319,46 +303,12 @@ int filesrc_read(IsoFileSrc *file, char *buf, size_t count) /* @return 1=ok, md5 is valid, 0= not ok, go on, <0 fatal error, abort -*/ +*/ + static int filesrc_make_md5(Ecma119Image *t, IsoFileSrc *file, char md5[16], int flag) { - int res, is_open = 0; - char buffer[BLOCK_SIZE]; - void *ctx= NULL; - off_t file_size; - uint32_t b, nblocks; - - if (! iso_stream_is_repeatable(file->stream)) - return 0; - res = iso_md5_start(&ctx); - if (res < 0) - return res; - res = filesrc_open(file); - if (res < 0) - return 0; - is_open = 1; - file_size = iso_file_src_get_size(file); - nblocks = DIV_UP(file_size, BLOCK_SIZE); - for (b = 0; b < nblocks; ++b) { - res = filesrc_read(file, buffer, BLOCK_SIZE); - if (res < 0) { - res = 0; - goto ex; - } - if (file_size - b * BLOCK_SIZE > BLOCK_SIZE) - res = BLOCK_SIZE; - else - res = file_size - b * BLOCK_SIZE; - iso_md5_compute(ctx, buffer, res); - } - res = 1; -ex:; - if (is_open) - filesrc_close(file); - if (ctx != NULL) - iso_md5_end(&ctx, md5); - return res; + return iso_stream_make_md5(file->stream, md5, 0); } #endif /* Libisofs_with_checksumS */ diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 9b67520..6f3e83b 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -1424,10 +1424,13 @@ int iso_write_opts_set_sort_files(IsoWriteOpts *opts, int sort); * @param opts * The option set to be manipulated. * @param session - * If bit0 set: compute session checksum + * If bit0 set: Compute session checksum * @param files - * If bit0 set: compute a checksum for each single IsoFile object. - * If bit1 set: check content stability (only with bit0). I.e. before + * If bit0 set: Compute a checksum for each single IsoFile object which + * gets its data content written into the session. Copy + * checksums from files which keep their data in older + * sessions. + * If bit1 set: Check content stability (only with bit0). I.e. before * writing the file content into to image stream, read it * once and compute a MD5. Do a second reading for writing * into the image stream. Afterwards compare both MD5 and @@ -5055,6 +5058,28 @@ int iso_image_get_session_md5(IsoImage *image, uint32_t *start_lba, */ int iso_file_get_md5(IsoImage *image, IsoFile *file, char md5[16], int flag); +/** + * Read the content of an IsoFile object, compute its MD5 and attach it to + * the IsoFile. It can then be inquired by iso_file_get_md5() and will get + * written into the next session if this is enabled at write time and if the + * image write process does not compute an MD5 from content which it copies. + * So this call can be used to equip nodes from the old image with checksums + * or to make available checksums of newly added files before the session gets + * written. + * @param file + * The file object to read data from and to which to attach the checksum. + * If the file is from the imported image, then its most original stream + * will be checksummed. Else the eventual filter streams will get into + * effect. + * @param flag + * Bitfield for control purposes. Unused yet. Submit 0. + * @return + * 1= ok, MD5 is computed and attached , <0 indicates error + * + * @since 0.6.22 + */ +int iso_file_make_md5(IsoFile *file, int flag); + /** * Check a data block whether it is a libisofs session checksum tag and * eventually obtain its recorded parameters. These tags get written after diff --git a/libisofs/md5.c b/libisofs/md5.c index 8be90b3..2bc4b86 100644 --- a/libisofs/md5.c +++ b/libisofs/md5.c @@ -406,13 +406,25 @@ int iso_md5_match(char first_md5[16], char second_md5[16]) * data is supposed to be a 4 byte integer, bit 31 shall be 0, * value 0 of this integer means that it is not a valid index. */ -int checksum_xinfo_func(void *data, int flag) +int checksum_cx_xinfo_func(void *data, int flag) { /* data is an int disguised as pointer. It does not point to memory. */ return 1; } +/* Function to identify and manage md5 sums of unspecified providence stored + * directly in this xinfo. + */ +int checksum_md5_xinfo_func(void *data, int flag) +{ + if (data == NULL) + return 1; + free(data); + return 1; +} + + /* ----------------------------------------------------------------------- */ /* MD5 checksum image writer */ @@ -432,25 +444,43 @@ int checksum_copy_old_nodes(Ecma119Image *target, IsoNode *node, int flag) int ret, i; size_t value_length; unsigned int idx = 0, old_idx = 0; - char *value = NULL; + char *value = NULL, *md5_pt = NULL; void *xipt; img = target->image; - if (img->checksum_array == NULL || target->checksum_buffer == NULL) + if (target->checksum_buffer == NULL) return 0; if (node->type == LIBISO_FILE) { file = (IsoFile *) node; if (file->from_old_session && target->appendable) { - ret = iso_node_get_xinfo(node, checksum_xinfo_func, &xipt); - if (ret <= 0) - return ret; - /* xipt is an int disguised as void pointer */ - old_idx = 0; - for (i = 0; i < 4; i++) - old_idx = (old_idx << 8) | ((unsigned char *) &xipt)[i]; + /* Look for checksums at various places */ - if (old_idx == 0 || old_idx > img->checksum_idx_count - 1) + /* Try checksum directly stored with node */ + if (md5_pt == NULL) { + ret = iso_node_get_xinfo(node, checksum_md5_xinfo_func, &xipt); + if (ret < 0) + return ret; + if (ret == 1) + md5_pt = (char *) xipt; + } + + /* Try checksum index to image checksum buffer */ + if (md5_pt == NULL && img->checksum_array != NULL) { + ret = iso_node_get_xinfo(node, checksum_cx_xinfo_func, &xipt); + if (ret <= 0) + return ret; + /* xipt is an int disguised as void pointer */ + old_idx = 0; + for (i = 0; i < 4; i++) + old_idx = (old_idx << 8) | ((unsigned char *) &xipt)[i]; + + if (old_idx == 0 || old_idx > img->checksum_idx_count - 1) + return 0; + md5_pt = img->checksum_array + 16 * old_idx; + } + + if (md5_pt == NULL) return 0; ret = iso_node_lookup_attr(node, "isofs.cx", &value_length, @@ -459,12 +489,13 @@ int checksum_copy_old_nodes(Ecma119Image *target, IsoNode *node, int flag) for (i = 0; i < 4; i++) idx = (idx << 8) | ((unsigned char *) value)[i]; if (idx > 0 && idx <= target->checksum_idx_counter) { - memcpy(target->checksum_buffer + 16 * idx, - img->checksum_array + 16 * old_idx, 16); + memcpy(target->checksum_buffer + 16 * idx, md5_pt, 16); } } if (value != NULL) free(value); + iso_node_remove_xinfo(node, checksum_md5_xinfo_func); + iso_node_remove_xinfo(node, checksum_cx_xinfo_func); } } else if (node->type == LIBISO_DIR) { for (pos = ((IsoDir *) node)->children; pos != NULL; pos = pos->next) { diff --git a/libisofs/md5.h b/libisofs/md5.h index 522d7fb..50c262b 100644 --- a/libisofs/md5.h +++ b/libisofs/md5.h @@ -19,13 +19,6 @@ int checksum_writer_create(Ecma119Image *target); -/* Function to identify and manage md5sum indice of the old image. - * data is supposed to be a 4 byte integer, bit 31 shall be 0, - * value 0 of this integer means that it is not a valid index. - */ -int checksum_xinfo_func(void *data, int flag); - - /* Write stream detectable checksum tag to extra block. * All tag ranges start at the beginning of the System Area (i.e. t->ms_block) * and stem from the same MD5 computation context. Tag types 2 and 3 are diff --git a/libisofs/node.c b/libisofs/node.c index 7b55b7d..4a99d1a 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -2678,6 +2678,14 @@ int iso_file_get_md5(IsoImage *image, IsoFile *file, char md5[16], int flag) size_t value_len; char *value = NULL; uint32_t idx = 0; + void *xipt; + + /* xinfo MD5 overrides everything else */ + ret = iso_node_get_xinfo((IsoNode *) file, checksum_md5_xinfo_func, &xipt); + if (ret == 1) { + memcpy(md5, (char *) xipt, 16); + return 1; + } if (image->checksum_array == NULL) return 0; @@ -2714,3 +2722,40 @@ ex:; } + +/* API */ +int iso_file_make_md5(IsoFile *file, int flag) +{ + +#ifdef Libisofs_with_checksumS + int ret, dig = 0; + char *md5 = NULL; + + if (file->from_old_session) + dig = 1; + md5= calloc(16, 1); + ret = iso_stream_make_md5(file->stream, md5, dig); + if (ret < 0) + goto ex; + iso_node_remove_xinfo((IsoNode *) file, checksum_md5_xinfo_func); + ret = iso_node_add_xinfo((IsoNode *) file, checksum_md5_xinfo_func, md5); + if (ret == 0) + ret = ISO_ERROR; /* should not happen after iso_node_remove_xinfo() */ + if (ret < 0) { + free(md5); + goto ex; + } + ret = 1; +ex:; + return ret; + +#else + + return ISO_ERROR; + +#endif /* ! Libisofs_with_checksumS */ + +} + + + diff --git a/libisofs/stream.c b/libisofs/stream.c index af0f401..251ae8b 100644 --- a/libisofs/stream.c +++ b/libisofs/stream.c @@ -830,3 +830,96 @@ int iso_stream_cmp_ino(IsoStream *s1, IsoStream *s2, int flag) return 0; } + + +/** + * @return + * 1 ok, 0 EOF, < 0 error + */ +int iso_stream_read_buffer(IsoStream *stream, char *buf, size_t count, + size_t *got) +{ + ssize_t result; + + *got = 0; + do { + result = iso_stream_read(stream, buf + *got, count - *got); + if (result < 0) { + memset(buf + *got, 0, count - *got); + return result; + } + if (result == 0) + break; + *got += result; + } while (*got < count); + + if (*got < count) { + /* eof */ + memset(buf + *got, 0, count - *got); + return 0; + } + return 1; +} + +#ifdef Libisofs_with_checksumS + + +/* @param flag bit0= dig out most original stream (e.g. because from old image) + @return 1=ok, md5 is valid, + 0= not ok, + <0 fatal error, abort +*/ +int iso_stream_make_md5(IsoStream *stream, char md5[16], int flag) +{ + int res, is_open = 0; + char buffer[2048]; + void *ctx= NULL; + off_t file_size; + uint32_t b, nblocks; + size_t got_bytes; + IsoStream *input_stream; + + if (flag & 1) { + while(1) { + input_stream = iso_stream_get_input_stream(stream, 0); + if (input_stream == NULL) + break; + stream = input_stream; + } + } + + if (! iso_stream_is_repeatable(stream)) + return 0; + res = iso_md5_start(&ctx); + if (res < 0) + return res; + res = iso_stream_open(stream); + if (res < 0) + return 0; + is_open = 1; + file_size = iso_stream_get_size(stream); + nblocks = DIV_UP(file_size, 2048); + for (b = 0; b < nblocks; ++b) { + res = iso_stream_read_buffer(stream, buffer, 2048, &got_bytes); + if (res < 0) { + res = 0; + goto ex; + } + /* Do not use got_bytes to stay closer to IsoFileSrc processing */ + if (file_size - b * 2048 > 2048) + res = 2048; + else + res = file_size - b * 2048; + iso_md5_compute(ctx, buffer, res); + } + res = 1; +ex:; + if (is_open) + iso_stream_close(stream); + if (ctx != NULL) + iso_md5_end(&ctx, md5); + return res; +} + +#endif /* Libisofs_with_checksumS */ + diff --git a/libisofs/stream.h b/libisofs/stream.h index 9346ebc..f096a25 100644 --- a/libisofs/stream.h +++ b/libisofs/stream.h @@ -83,4 +83,24 @@ int iso_stream_get_src_zf(IsoStream *stream, int *header_size_div4, int iso_stream_set_image_ino(IsoStream *stream, ino_t ino, int flag); +/** + * Read the full required amount of data unless error or EOF occurs. + * Fill missing bytes by 0s. + * @param count Required amount + * @param got Returns number of actually read bytes + * @return + * 1 no problem encountered, 0 EOF encountered, < 0 error + */ +int iso_stream_read_buffer(IsoStream *stream, char *buf, size_t count, + size_t *got); + +/** + * @return 1=ok, md5 is valid, + * 0= not ok + * <0 fatal error, abort + */ +int iso_stream_make_md5(IsoStream *stream, char md5[16], int flag); + + + #endif /*STREAM_H_*/ diff --git a/libisofs/util.h b/libisofs/util.h index 188d991..be56625 100644 --- a/libisofs/util.h +++ b/libisofs/util.h @@ -482,4 +482,26 @@ int iso_util_eval_md5_tag(char *block, int desired, uint32_t lba, int iso_util_tag_magic(int tag_type, char **tag_magic, int *len, int flag); +/* ------------------------------------------------------------------------- */ + +/* In md5.h these function prototypes would be neighbors of (Ecma119Image *) + which needs inclusion of ecma119.h and more. So, being generic, they ended + up here. +*/ + +/* Function to identify and manage md5sum indice of the old image. + * data is supposed to be a 4 byte integer, bit 31 shall be 0, + * value 0 of this integer means that it is not a valid index. + */ +int checksum_cx_xinfo_func(void *data, int flag); + +/* Function to identify and manage md5 sums of unspecified providence stored + * directly in this xinfo. This is supposed to override any other recorded + * MD5 of the node unless data get copied and checksummed during that copying. + */ +int checksum_md5_xinfo_func(void *data, int flag); + +/* ------------------------------------------------------------------------- */ + + #endif /*LIBISO_UTIL_H_*/