diff --git a/doc/susp_aaip_isofs_names.txt b/doc/susp_aaip_isofs_names.txt index 5d8c83b..a7a1ae1 100644 --- a/doc/susp_aaip_isofs_names.txt +++ b/doc/susp_aaip_isofs_names.txt @@ -12,6 +12,93 @@ specification of AAIP : ------------------------------------------------------------------------------- +Name: + isofs.ca + +Purpose: + Records the range of checksummed image data (START, END), the number + of checksum items (COUNT), the number of bytes in a single checksum item + (SIZE), and the name of the checksum algorithm (CHECKSUM_TYPE). + END is also the block address of the start of the checksum recording + area in the image. + See also isofs.cx . + +Format of Value: + START_LEN | START_BYTES | END_LEN | END_BYTES | + COUNT_LEN | COUNT_BYTES | SIZE_LEN | SIZE_BYTES | CHECKSUM_TYPE + Each number is encoded as _LEN byte and _BYTES value string. + The _LEN fields comply to ISO 9660 Format section 7.1.1. + The byte strings START_BYTES, END_BYTES, COUNT_BYTES, SIZE_BYTES begin + with the most significant byte. Leading zero bytes are allowed. + CHECKSUM_TYPE consists of the bytes after + START_LEN + END_LEN + COUNT_LEN + SIZE_LEN + 4. + It shall be a string of printable characters without terminating 0-byte. + Type names shall be registered here. + For now there is: + "MD5" 128 bit message digest, see RFC 1321, see man md5sum + +Example: + LBA range 32 to 1000000 , 520 checksums recorded, MD5 + { 1, 32, + 3, 15, 66, 64, + 2, 2, 8, + 1, 16, + 'M', 'D', '5' } + or + { 4, 0, 0, 0, 32, + 4, 0, 15, 66, 64, + 4, 0, 0, 2, 8, + 1, 16, + 'M', 'D', '5' } + +Registered: + 16 Jul 2009 by Thomas Schmitt for libisofs. + +------------------------------------------------------------------------------- + +Name: + isofs.cs + +Purpose: + Records the name of the character set that was used as output character + set when writing the RRIP name tree of the ISO 9660 image. It shall be + suitable as parameter for function iconv_open(3). + This attribute shall eventually be attached to the root directory entry + and be global for the whole image. + +Format of Value: + Shall hold the character set name without terminating 0-byte. + +Example: + { 'I', 'S', 'O', '-', '8', '8', '5', '9' , '-', '1' } + +Registered: + 18 Mar 2009 by Thomas Schmitt for libisofs. + +------------------------------------------------------------------------------- + +Name: + isofs.cx + +Purpose: + Records the index of the file's checksum in the checksum area at the + end of the image. The byte address of the checksum is + checksum_area_lba * 2048 + isofs.cx * checksum_size + Default checksum algorithm is MD5 with a size of 16 byte. + See also isofs.ca . + +Format of Value: + A byte string which begins with the most significant byte. + +Example: + Index 123456 + { 1, 226, 64 } + +Registered: + 16 Jul 2009 by Thomas Schmitt for libisofs. + +------------------------------------------------------------------------------- + Name: isofs.di @@ -31,28 +118,7 @@ Example: Registered: 17 Feb 2009 by Thomas Schmitt for xorriso. - -------------------------------------------------------------------------------- -Name: - isofs.cs - -Purpose: - Records the name of the character set that was used as output character - set when writing the RRIP name tree of the ISO 9660 image. It shall be - suitable as parameter for function iconv_open(3). - This attribute shall eventually be attached to the root directory entry - and be global for the whole image. - -Format of Value: - Shall hold the character set name without terminating 0-byte. - -Example: - { 'I', 'S', 'O', '-', '8', '8', '5', '9' , '-', '1' } - -Registered: - 18 Mar 2009 by Thomas Schmitt for libisofs. - ------------------------------------------------------------------------------- Name: @@ -78,7 +144,7 @@ Example: Registered: 03 Apr 2009 by Thomas Schmitt for xorriso. - + ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index f33b498..4de22a0 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -27,6 +27,10 @@ #include "util.h" #include "system_area.h" +#ifdef Libisofs_with_checksumS +#include "md5.h" +#endif + #include #include #include @@ -57,6 +61,14 @@ void ecma119_image_free(Ecma119Image *t) } free(t->input_charset); free(t->output_charset); + +#ifdef Libisofs_with_checksumS + if (t->checksum_ctx != NULL) /* dispose checksum context */ + libisofs_md5(&(t->checksum_ctx), NULL, 0, NULL, (1 << 15)); + if (t->checksum_buffer != NULL) + free(t->checksum_buffer); +#endif + free(t->writers); free(t); } @@ -294,7 +306,7 @@ void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id, rec->len_dr[0] = len_dr + (info != NULL ? info->suf_len : 0); iso_bb(rec->block, block, 4); iso_bb(rec->length, len, 4); - if(t->dir_rec_mtime) { + if (t->dir_rec_mtime) { iso= node->node; iso_datetime_7(rec->recording_time, t->replace_timestamps ? t->timestamp : iso->mtime, @@ -860,6 +872,79 @@ void *write_function(void *arg) pthread_exit(NULL); } + +#ifdef Libisofs_with_checksumS + + +static +int checksum_prepare_image(IsoImage *src, int flag) +{ + int ret; + + /* Set provisory value of isofs.ca with + 4 byte LBA, 4 byte count, size 16, name MD5 */ + ret = iso_root_set_isofsca((IsoNode *) src->root, 0, 0, 0, 16, "MD5", 0); + if (ret < 0) + return ret; + return ISO_SUCCESS; +} + + +/* + @flag bit0= recursion +*/ +static +int checksum_prepare_nodes(IsoImage *img, IsoNode *node, int flag) +{ + IsoNode *pos; + IsoFile *file; + int ret, i; + size_t value_length; + unsigned int idx = 0; + char *value; + void *xipt = NULL; + + if (node->type == LIBISO_FILE) { + file = (IsoFile *) node; + if (file->from_old_session) { + /* Save eventual MD5 data of files from old image */ + value= NULL; + ret = iso_node_lookup_attr(node, "isofs.cx", &value_length, + &value, 0); + if (ret == 1 && value_length == 4) { + for (i = 0; i < 4; i++) + idx = (idx << 8) | ((unsigned char *) value)[i]; + if (idx > 0 && idx < 0x8000000) { + /* 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, + xipt); + if (ret < 0) + return ret; + } + } + if (value != NULL) + free(value); + } + /* Equip all nodes with provisory isofs.cx numbers: 4 byte, all 0. */ + ret = iso_file_set_isofscx(file, (unsigned int) 0, 0); + if (ret < 0) + return ret; + } else if (node->type == LIBISO_DIR) { + for (pos = ((IsoDir *) node)->children; pos != NULL; pos = pos->next) { + ret = checksum_prepare_nodes(img, pos, 1); + if (ret < 0) + return ret; + } + } + return ISO_SUCCESS; +} + + +#endif /* Libisofs_with_checksumS */ + + static int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) { @@ -951,6 +1036,18 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) return ISO_OUT_OF_MEM; } +#ifdef Libisofs_with_checksumS + + /* >>> need an IsoWriteOpts component to control this */; + target->md5_checksums = 1; + + target->checksum_idx_counter = 0; + target->checksum_ctx = NULL; + target->checksum_counter = 0; + target->checksum_buffer = NULL; + +#endif + /* * 2. Based on those options, create needed writers: iso, joliet... * Each writer inits its structures and stores needed info into @@ -974,6 +1071,25 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) nwriters++; } + +#ifdef Libisofs_with_checksumS + + if (target->md5_checksums) { + nwriters++; + ret = checksum_prepare_image(src, 0); + if (ret < 0) + return ret; + if (target->appendable) { + ret = checksum_prepare_nodes(src, (IsoNode *) src->root, 0); + if (ret < 0) + return ret; + } + target->checksum_idx_counter = 0; + } + +#endif /* Libisofs_with_checksumS */ + + target->writers = malloc(nwriters * sizeof(void*)); if (target->writers == NULL) { iso_image_unref(src); @@ -1019,7 +1135,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) /* * Create the writer for possible padding to ensure that in case of image - * growing we can safety overwrite the first 64 KiB of image. + * growing we can safely overwrite the first 64 KiB of image. */ ret = pad_writer_create(target); if (ret < 0) { @@ -1033,6 +1149,20 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) } file_src_writer_index = target->nwriters - 1; + +#ifdef Libisofs_with_checksumS + + /* ??? Is it safe to add a writer after the content writer ? */ + + if (target->md5_checksums) { + ret = checksum_writer_create(target); + if (ret < 0) + goto target_cleanup; + } + +#endif /* Libisofs_with_checksumS */ + + /* * 3. * Call compute_data_blocks() in each Writer. @@ -1140,7 +1270,15 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) target->vol_space_size = target->curblock - target->ms_block; target->total_size = (off_t) target->vol_space_size * BLOCK_SIZE; - /* 4. Create and start writting thread */ + + /* 4. Create and start writing thread */ + +#ifdef Libisofs_with_checksumS + /* After any fake writes are done: Initialize image checksum context */ + ret = libisofs_md5(&(target->checksum_ctx), NULL, 0, NULL, 1); + if (ret < 0) + return ret; +#endif /* Libisofs_with_checksumS */ /* ensure the thread is created joinable */ pthread_attr_init(&(target->th_attr)); @@ -1306,6 +1444,17 @@ int iso_write(Ecma119Image *target, void *buf, size_t count) return ISO_CANCELED; } +#ifdef Libisofs_with_checksumS + + if (target->checksum_ctx != NULL) { + /* Add to image checksum */ + target->checksum_counter += count; + libisofs_md5(&(target->checksum_ctx), (char *) buf, (int) count, + NULL, 0); + } + +#endif /* Libisofs_with_checksumS */ + /* total size is 0 when writing the overwrite buffer */ if (ret > 0 && (target->total_size != (off_t) 0)){ unsigned int kbw, kbt; @@ -1710,7 +1859,7 @@ int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size) int iso_write_opts_get_data_start(IsoWriteOpts *opts, uint32_t *data_start, int flag) { - if(opts->data_start_lba == 0) + if (opts->data_start_lba == 0) return ISO_ERROR; *data_start = opts->data_start_lba; return ISO_SUCCESS; diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index e723604..a6684c9 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -312,6 +312,12 @@ struct ecma119_image /* Store in ECMA-119 timestamp mtime of source */ unsigned int dir_rec_mtime :1; +#ifdef Libisofs_with_checksumS + + unsigned int md5_checksums :1; + +#endif /* Libisofs_with_checksumS */ + /* * Mode replace. If one of these flags is set, the correspodent values are * replaced with values below. @@ -421,6 +427,16 @@ struct ecma119_image /* tree of files sources */ IsoRBTree *files; +#ifdef Libisofs_with_checksumS + + unsigned int checksum_idx_counter; + void *checksum_ctx; + off_t checksum_counter; + char image_md5[16]; + char *checksum_buffer; + +#endif /* Libisofs_with_checksumS */ + /* Buffer for communication between burn_source and writer thread */ IsoRingBuffer *buffer; diff --git a/libisofs/filesrc.c b/libisofs/filesrc.c index d30f1a8..d63b7e7 100644 --- a/libisofs/filesrc.c +++ b/libisofs/filesrc.c @@ -14,6 +14,10 @@ #include "image.h" #include "stream.h" +#ifdef Libisofs_with_checksumS +#include "md5.h" +#endif /* Libisofs_with_checksumS */ + #include #include #include @@ -44,6 +48,10 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src) dev_t dev_id; ino_t ino_id; +#ifdef Libisofs_with_checksumS + int cret; +#endif + if (img == NULL || file == NULL || src == NULL) { return ISO_NULL_POINTER; } @@ -88,11 +96,42 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src) /* insert the filesrc in the tree */ ret = iso_rbtree_insert(img->files, fsrc, (void**)src); if (ret <= 0) { + +#ifdef Libisofs_with_checksumS + + if (ret == 0) { + /* Duplicate file source was mapped to previously registered source + */ + cret = iso_file_set_isofscx(file, (*src)->checksum_index, 0); + if (cret < 0) + ret = cret; + } + +#endif /* Libisofs_with_checksumS */ + free(fsrc->sections); free(fsrc); return ret; } iso_stream_ref(fsrc->stream); + +#ifdef Libisofs_with_checksumS + + if(img->md5_checksums) { + img->checksum_idx_counter++; + if (img->checksum_idx_counter < 0x80000000) { + fsrc->checksum_index= img->checksum_idx_counter; + } else { + fsrc->checksum_index= 0; + img->checksum_idx_counter= 0x80000000; /* keep from rolling over */ + } + cret = iso_file_set_isofscx(file, (*src)->checksum_index, 0); + if (cret < 0) + return cret; + } + +#endif /* Libisofs_with_checksumS */ + return ISO_SUCCESS; } @@ -276,6 +315,14 @@ int filesrc_writer_write_data(IsoImageWriter *writer) IsoFileSrc **filelist; char name[PATH_MAX]; char buffer[BLOCK_SIZE]; + off_t file_size; + uint32_t nblocks; + +#ifdef Libisofs_with_checksumS + void *ctx= NULL; + char md5[16]; +#endif + if (writer == NULL) { return ISO_ASSERT_FAILURE; @@ -288,8 +335,10 @@ int filesrc_writer_write_data(IsoImageWriter *writer) i = 0; while ((file = filelist[i++]) != NULL) { + file_size = iso_file_src_get_size(file); + nblocks = DIV_UP(file_size, BLOCK_SIZE); - uint32_t nblocks = DIV_UP(iso_file_src_get_size(file), BLOCK_SIZE); + /* >>> Eventually obtain an MD5 of content by a first read pass */; res = filesrc_open(file); iso_stream_get_file_name(file->stream, name); @@ -329,6 +378,18 @@ int filesrc_writer_write_data(IsoImageWriter *writer) } #endif + +#ifdef Libisofs_with_checksumS + + if (file->checksum_index > 0) { + /* initialize file checksum */ + res = libisofs_md5(&ctx, NULL, 0, md5, 1); + if (res <= 0) + file->checksum_index = 0; + } + +#endif /* Libisofs_with_checksumS */ + /* write file contents to image */ for (b = 0; b < nblocks; ++b) { int wres; @@ -343,6 +404,21 @@ int filesrc_writer_write_data(IsoImageWriter *writer) filesrc_close(file); return wres; } + +#ifdef Libisofs_with_checksumS + + if (file->checksum_index > 0) { + /* Add to file checksum */ + res = file_size - b * BLOCK_SIZE; + if (res > BLOCK_SIZE) + res = BLOCK_SIZE; + res = libisofs_md5(&ctx, buffer, res, md5, 0); + if (res <= 0) + file->checksum_index = 0; + } + +#endif /* Libisofs_with_checksumS */ + } filesrc_close(file); @@ -374,8 +450,41 @@ int filesrc_writer_write_data(IsoImageWriter *writer) /* ko, writer error, we need to go out! */ return res; } + +#ifdef Libisofs_with_checksumS + + if (file->checksum_index > 0) { + /* Add to file checksum */ + res = file_size - b * BLOCK_SIZE; + if (res > BLOCK_SIZE) + res = BLOCK_SIZE; + res = libisofs_md5(&ctx, buffer, res, md5, 0); + if (res <= 0) + file->checksum_index = 0; + } + +#endif /* Libisofs_with_checksumS */ + } } + +#ifdef Libisofs_with_checksumS + + if (file->checksum_index > 0) { + /* Obtain checksum and dispose checksum context */ + res = libisofs_md5(&ctx, buffer, 0, md5, 2 | (1 << 15)); + if (res <= 0) + file->checksum_index = 0; + + /* >>> Eventually compare with MD5 of first read pass + and issue error if mismatch */; + + /* Write md5 into checksum buffer at file->checksum_index */ + memcpy(t->checksum_buffer + 16 * file->checksum_index, md5, 16); + } + +#endif /* Libisofs_with_checksumS */ + } return ISO_SUCCESS; @@ -395,7 +504,7 @@ int iso_file_src_writer_create(Ecma119Image *target) writer = malloc(sizeof(IsoImageWriter)); if (writer == NULL) { - return ISO_ASSERT_FAILURE; + return ISO_OUT_OF_MEM; } writer->compute_data_blocks = filesrc_writer_compute_data_blocks; diff --git a/libisofs/filesrc.h b/libisofs/filesrc.h index 88e4760..b4d5824 100644 --- a/libisofs/filesrc.h +++ b/libisofs/filesrc.h @@ -18,6 +18,13 @@ struct Iso_File_Src { unsigned int prev_img :1; /**< if the file comes from a previous image */ +#ifdef Libisofs_with_checksumS + + unsigned int checksum_index :31; + +#endif /* Libisofs_with_checksumS */ + + /** File Sections of the file in the image */ struct iso_file_section *sections; int nsections; @@ -43,7 +50,7 @@ int iso_file_src_cmp(const void *n1, const void *n2); * @param src * Will be filled with a pointer to the IsoFileSrc * @return - * 1 on success, < 0 on error + * 1 if new object was created, 0 if object existed, < 0 on error */ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src); diff --git a/libisofs/fs_image.c b/libisofs/fs_image.c index d454091..0b74dfc 100644 --- a/libisofs/fs_image.c +++ b/libisofs/fs_image.c @@ -2935,6 +2935,18 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, _ImageFsData *data; struct el_torito_boot_catalog *oldbootcat; +#ifdef Libisofs_with_checksumS + int i; + uint32_t old_checksum_start_lba; + uint32_t old_checksum_end_lba; + uint32_t old_checksum_idx_count; + char *old_checksum_array = NULL; + char checksum_type[81]; + uint32_t checksum_size; + size_t size; + uint8_t *rpt; +#endif + if (image == NULL || src == NULL || opts == NULL) { return ISO_NULL_POINTER; } @@ -2956,9 +2968,16 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, blback = image->builder; oldroot = image->root; oldbootcat = image->bootcat; /* could be NULL */ - image->bootcat = NULL; +#ifdef Libisofs_with_checksumS + old_checksum_start_lba = image->checksum_start_lba; + old_checksum_end_lba = image->checksum_end_lba; + old_checksum_idx_count = image->checksum_idx_count; + old_checksum_array = image->checksum_array; + image->checksum_array = NULL; +#endif + /* create new builder */ ret = iso_image_builder_new(blback, &image->builder); if (ret < 0) { @@ -3119,7 +3138,7 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, *features = malloc(sizeof(IsoReadImageFeatures)); if (*features == NULL) { ret = ISO_OUT_OF_MEM; - goto import_cleanup; + goto import_revert; } (*features)->hasJoliet = data->joliet; (*features)->hasRR = data->rr_version != 0; @@ -3128,6 +3147,39 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, (*features)->size = data->nblocks; } +#ifdef Libisofs_with_checksumS + + /* Read checksum buffer */ + + /* >>> needs to be controlled by iso_read_opts */; + + ret = iso_root_get_isofsca((IsoNode *) image->root, + &(image->checksum_start_lba), + &(image->checksum_end_lba), + &(image->checksum_idx_count), + &checksum_size, checksum_type, 0); + if (ret > 0) + if (checksum_size != 16 || strcmp(checksum_type, "MD5") != 0) + ret = 0; + if (ret > 0) { + size = image->checksum_idx_count / 128 + 1; + image->checksum_array = calloc(size, 2048); + if (image->checksum_array == NULL) { + ret = ISO_OUT_OF_MEM; + goto import_revert; + } + + /* Load from image->checksum_end_lba */; + for (i = 0; i < size; i++) { + rpt = (uint8_t *) (image->checksum_array + i * 2048); + ret = src->read_block(src, image->checksum_end_lba + i, rpt); + if (ret <= 0) + goto import_revert; + } + } + +#endif /* Libisofs_with_checksumS */ + ret = ISO_SUCCESS; goto import_cleanup; @@ -3136,9 +3188,16 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, iso_node_unref((IsoNode*)image->root); el_torito_boot_catalog_free(image->bootcat); image->root = oldroot; - image->fs = fsback; image->bootcat = oldbootcat; +#ifdef Libisofs_with_checksumS + old_checksum_start_lba = image->checksum_start_lba; + old_checksum_end_lba = image->checksum_end_lba; + old_checksum_idx_count = image->checksum_idx_count; + image->checksum_array = old_checksum_array; + old_checksum_array = NULL; +#endif + import_cleanup:; /* recover backed fs and builder */ @@ -3149,6 +3208,12 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, fs->close(fs); iso_filesystem_unref(fs); +#ifdef Libisofs_with_checksumS + if (old_checksum_array != NULL) + free(old_checksum_array); +#endif + + return ret; } diff --git a/libisofs/image.c b/libisofs/image.c index 651dc20..832fad1 100644 --- a/libisofs/image.c +++ b/libisofs/image.c @@ -78,6 +78,14 @@ int iso_image_new(const char *name, IsoImage **image) img->inode_counter = 0; img->used_inodes = NULL; img->used_inodes_start = 0; + +#ifdef Libisofs_with_checksumS + img->checksum_start_lba = 0; + img->checksum_end_lba = 0; + img->checksum_idx_count = 0; + img->checksum_array = NULL; +#endif + *image = img; return ISO_SUCCESS; } @@ -529,3 +537,25 @@ ex:; return ret; } + +/* API */ +int iso_image_get_session_md5(IsoImage *image, uint32_t *start_lba, + uint32_t *end_lba, char md5[16], int flag) +{ + +#ifdef Libisofs_with_checksumS + + if (image->checksum_array == NULL || image->checksum_idx_count < 1) + return 0; + *start_lba = image->checksum_start_lba; + *end_lba = image->checksum_end_lba; + memcpy(md5, image->checksum_array, 16); + return ISO_SUCCESS; + +#else + + return 0; + +#endif /* ! Libisofs_with_checksumS */ + +} diff --git a/libisofs/image.h b/libisofs/image.h index 566abec..253c6b0 100644 --- a/libisofs/image.h +++ b/libisofs/image.h @@ -148,6 +148,22 @@ struct Iso_Image uint8_t *used_inodes; ino_t used_inodes_start; +#ifdef Libisofs_with_checksumS + + /** + * Array of MD5 checksums as announced by xattr "isofs.ca" of the + * root node. Array element 0 contains an overall image checksum for the + * block range checksum_start_lba,checksum_end_lba. Element size is + * 16 bytes. IsoFile objects in the image may have xattr "isofs.cx" + * which gives their index in checksum_array. + */ + uint32_t checksum_start_lba; + uint32_t checksum_end_lba; + uint32_t checksum_idx_count; + char *checksum_array; + +#endif /* Libisofs_with_checksumS */ + }; diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 0e02f54..69d6b8d 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -4442,7 +4442,11 @@ int iso_node_lookup_attr(IsoNode *node, char *name, * bit0= Do not maintain eventual existing ACL of the node. * Set eventual new ACL from value of empty name. * bit1= Do not clear the existing attribute list but merge it with - * the list given by this call + * the list given by this call. + * The given values override the values of their eventually existing + * names. If no xattr with a given name exists, then it will be + * added as new xattr. So this bit can be used to set a single + * xattr without inquiring any other xattr of the node. * bit2= Delete the attributes with the given names * bit3= Allow to affect non-user attributes. * I.e. those with a non-empty name which does not begin by "user." @@ -4953,6 +4957,57 @@ int iso_file_add_gzip_filter(IsoFile *file, int flag); int iso_gzip_get_refcounts(off_t *gzip_count, off_t *gunzip_count, int flag); +/* ---------------------------- MD5 Checksums --------------------------- */ + + +/** + * Eventually obtain the recorded MD5 checksum of the session which was + * loaded as ISO image. Such a checksum may be stored together with others + * in a contiguous array at the end of the ISO image. The session checksum + * covers the data blocks from address start_lba to address end_lba - 1. + * It does not cover the recorded array of md5 checksums. + * Layout, size, and position of the checksum array is recorded in the xattr + * "isofs.ca" of the session root node. + * @param image + * The image to inquire + * @param start_lba + * Eventually returns the first block address covered by md5 + * @param start_lba + * Eventually returns the first block address not covered by md5 any more + * @param md5 + * Eventually returns 16 byte of MD5 checksum + * @param flag + * Bitfield for control purposes, unused yet, submit 0 + * @return + * 1= md5 found , 0= no md5 available , <0 indicates error + * + * @since 0.6.22 + */ +int iso_image_get_session_md5(IsoImage *image, uint32_t *start_lba, + uint32_t *end_lba, char md5[16], int flag); + +/** + * Eventually obtain the recorded MD5 checksum of a data file from the loaded + * ISO image. Such a checksum may be stored with others in a contiguous + * array at the end of the ISO image. The data file eventually has an xattr + * "isofs.cx" which gives the index in that array. + * @param image + * The image from which file stems. + * @param file + * The file object to inquire + * @param md5 + * Eventually returns 16 byte of MD5 checksum + * @param flag + * Bitfield for control purposes, unused yet, submit 0 + * @return + * 1= md5 found , 0= no md5 available , <0 indicates error + * + * @since 0.6.22 + */ +int iso_file_get_md5(IsoImage *image, IsoFile *file, char md5[16], int flag); + + + /************ Error codes and return values for libisofs ********************/ /** successfully execution */ @@ -5412,12 +5467,9 @@ struct burn_source { /* currently none being tested */ + /* ---------------------------- Improvements --------------------------- */ -/* currently none being tested */ - -/* ---------------------------- Experiments ---------------------------- */ - /* Hardlinks : During image generation accompany the tree of IsoFileSrc by a sorted array of Ecma119Node. The sorting order shall bring together candidates for being @@ -5439,7 +5491,10 @@ struct burn_source { #define Libisofs_hardlink_prooF yes -/* Experiment: Ignore PX inode numbers, +/* ---------------------------- Experiments ---------------------------- */ + +/* <<< on its way out + Experiment: Ignore PX inode numbers, have boot image inode number counted by fs_give_ino_number() Overridden if Libisofs_hardlink_prooF is defined. @@ -5455,5 +5510,14 @@ struct burn_source { */ +/* Experiment: During image writing equip IsoFile objects with MD5 checksums + and compute an overall checksum of the image. Store them in + a separate checksum block area after the data area of the + image. + + ENABLE ONLY FOR DEVELOPMENT TESTS ! + #define Libisofs_with_checksumS yes +*/ + #endif /*LIBISO_LIBISOFS_H_*/ diff --git a/libisofs/md5.c b/libisofs/md5.c new file mode 100644 index 0000000..20ea1b6 --- /dev/null +++ b/libisofs/md5.c @@ -0,0 +1,514 @@ +/* + * Copyright (c) 2009 Thomas Schmitt + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See COPYING file for details. + */ + + +#include +#include +#include + +#include "writer.h" +#include "messages.h" +#include "ecma119.h" +#include "image.h" + +#include "md5.h" + + +/* This code is derived from RFC 1321 and implements computation of the + "RSA Data Security, Inc. MD5 Message-Digest Algorithm" */ + +#define Libisofs_md5_S11 7 +#define Libisofs_md5_S12 12 +#define Libisofs_md5_S13 17 +#define Libisofs_md5_S14 22 +#define Libisofs_md5_S21 5 +#define Libisofs_md5_S22 9 +#define Libisofs_md5_S23 14 +#define Libisofs_md5_S24 20 +#define Libisofs_md5_S31 4 +#define Libisofs_md5_S32 11 +#define Libisofs_md5_S33 16 +#define Libisofs_md5_S34 23 +#define Libisofs_md5_S41 6 +#define Libisofs_md5_S42 10 +#define Libisofs_md5_S43 15 +#define Libisofs_md5_S44 21 + + +/* F, G, H and I are basic MD5 functions. + */ +#define Libisofs_md5_F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define Libisofs_md5_G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define Libisofs_md5_H(x, y, z) ((x) ^ (y) ^ (z)) +#define Libisofs_md5_I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define Libisofs_md5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define Libisofs_md5_FF(a, b, c, d, x, s, ac) { \ + (a) += Libisofs_md5_F ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define Libisofs_md5_GG(a, b, c, d, x, s, ac) { \ + (a) += Libisofs_md5_G ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define Libisofs_md5_HH(a, b, c, d, x, s, ac) { \ + (a) += Libisofs_md5_H ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define Libisofs_md5_II(a, b, c, d, x, s, ac) { \ + (a) += Libisofs_md5_I ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + + +/* MD5 context. */ +struct _libisofs_md5_ctx { + uint32_t state[4]; /* state (ABCD) */ + uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +}; + +typedef struct _libisofs_md5_ctx libisofs_md5_ctx; + + +/* MD5 basic transformation. Transforms state based on block. + */ +static int md5__transform (uint32_t state[4], unsigned char block[64]) +{ + uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + unsigned int i, j; + + for (i = 0, j = 0; j < 64; i++, j += 4) + x[i] = ((uint32_t)block[j]) | (((uint32_t)block[j+1]) << 8) | + (((uint32_t)block[j+2]) << 16) | (((uint32_t)block[j+3]) << 24); + + /* Round 1 */ + Libisofs_md5_FF (a, b, c, d, x[ 0], Libisofs_md5_S11, 0xd76aa478); /* 1 */ + Libisofs_md5_FF (d, a, b, c, x[ 1], Libisofs_md5_S12, 0xe8c7b756); /* 2 */ + Libisofs_md5_FF (c, d, a, b, x[ 2], Libisofs_md5_S13, 0x242070db); /* 3 */ + Libisofs_md5_FF (b, c, d, a, x[ 3], Libisofs_md5_S14, 0xc1bdceee); /* 4 */ + Libisofs_md5_FF (a, b, c, d, x[ 4], Libisofs_md5_S11, 0xf57c0faf); /* 5 */ + Libisofs_md5_FF (d, a, b, c, x[ 5], Libisofs_md5_S12, 0x4787c62a); /* 6 */ + Libisofs_md5_FF (c, d, a, b, x[ 6], Libisofs_md5_S13, 0xa8304613); /* 7 */ + Libisofs_md5_FF (b, c, d, a, x[ 7], Libisofs_md5_S14, 0xfd469501); /* 8 */ + Libisofs_md5_FF (a, b, c, d, x[ 8], Libisofs_md5_S11, 0x698098d8); /* 9 */ + Libisofs_md5_FF (d, a, b, c, x[ 9], Libisofs_md5_S12, 0x8b44f7af); /* 10 */ + Libisofs_md5_FF (c, d, a, b, x[10], Libisofs_md5_S13, 0xffff5bb1); /* 11 */ + Libisofs_md5_FF (b, c, d, a, x[11], Libisofs_md5_S14, 0x895cd7be); /* 12 */ + Libisofs_md5_FF (a, b, c, d, x[12], Libisofs_md5_S11, 0x6b901122); /* 13 */ + Libisofs_md5_FF (d, a, b, c, x[13], Libisofs_md5_S12, 0xfd987193); /* 14 */ + Libisofs_md5_FF (c, d, a, b, x[14], Libisofs_md5_S13, 0xa679438e); /* 15 */ + Libisofs_md5_FF (b, c, d, a, x[15], Libisofs_md5_S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + Libisofs_md5_GG (a, b, c, d, x[ 1], Libisofs_md5_S21, 0xf61e2562); /* 17 */ + Libisofs_md5_GG (d, a, b, c, x[ 6], Libisofs_md5_S22, 0xc040b340); /* 18 */ + Libisofs_md5_GG (c, d, a, b, x[11], Libisofs_md5_S23, 0x265e5a51); /* 19 */ + Libisofs_md5_GG (b, c, d, a, x[ 0], Libisofs_md5_S24, 0xe9b6c7aa); /* 20 */ + Libisofs_md5_GG (a, b, c, d, x[ 5], Libisofs_md5_S21, 0xd62f105d); /* 21 */ + Libisofs_md5_GG (d, a, b, c, x[10], Libisofs_md5_S22, 0x2441453); /* 22 */ + Libisofs_md5_GG (c, d, a, b, x[15], Libisofs_md5_S23, 0xd8a1e681); /* 23 */ + Libisofs_md5_GG (b, c, d, a, x[ 4], Libisofs_md5_S24, 0xe7d3fbc8); /* 24 */ + Libisofs_md5_GG (a, b, c, d, x[ 9], Libisofs_md5_S21, 0x21e1cde6); /* 25 */ + Libisofs_md5_GG (d, a, b, c, x[14], Libisofs_md5_S22, 0xc33707d6); /* 26 */ + Libisofs_md5_GG (c, d, a, b, x[ 3], Libisofs_md5_S23, 0xf4d50d87); /* 27 */ + Libisofs_md5_GG (b, c, d, a, x[ 8], Libisofs_md5_S24, 0x455a14ed); /* 28 */ + Libisofs_md5_GG (a, b, c, d, x[13], Libisofs_md5_S21, 0xa9e3e905); /* 29 */ + Libisofs_md5_GG (d, a, b, c, x[ 2], Libisofs_md5_S22, 0xfcefa3f8); /* 30 */ + Libisofs_md5_GG (c, d, a, b, x[ 7], Libisofs_md5_S23, 0x676f02d9); /* 31 */ + Libisofs_md5_GG (b, c, d, a, x[12], Libisofs_md5_S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + Libisofs_md5_HH (a, b, c, d, x[ 5], Libisofs_md5_S31, 0xfffa3942); /* 33 */ + Libisofs_md5_HH (d, a, b, c, x[ 8], Libisofs_md5_S32, 0x8771f681); /* 34 */ + Libisofs_md5_HH (c, d, a, b, x[11], Libisofs_md5_S33, 0x6d9d6122); /* 35 */ + Libisofs_md5_HH (b, c, d, a, x[14], Libisofs_md5_S34, 0xfde5380c); /* 36 */ + Libisofs_md5_HH (a, b, c, d, x[ 1], Libisofs_md5_S31, 0xa4beea44); /* 37 */ + Libisofs_md5_HH (d, a, b, c, x[ 4], Libisofs_md5_S32, 0x4bdecfa9); /* 38 */ + Libisofs_md5_HH (c, d, a, b, x[ 7], Libisofs_md5_S33, 0xf6bb4b60); /* 39 */ + Libisofs_md5_HH (b, c, d, a, x[10], Libisofs_md5_S34, 0xbebfbc70); /* 40 */ + Libisofs_md5_HH (a, b, c, d, x[13], Libisofs_md5_S31, 0x289b7ec6); /* 41 */ + Libisofs_md5_HH (d, a, b, c, x[ 0], Libisofs_md5_S32, 0xeaa127fa); /* 42 */ + Libisofs_md5_HH (c, d, a, b, x[ 3], Libisofs_md5_S33, 0xd4ef3085); /* 43 */ + Libisofs_md5_HH (b, c, d, a, x[ 6], Libisofs_md5_S34, 0x4881d05); /* 44 */ + Libisofs_md5_HH (a, b, c, d, x[ 9], Libisofs_md5_S31, 0xd9d4d039); /* 45 */ + Libisofs_md5_HH (d, a, b, c, x[12], Libisofs_md5_S32, 0xe6db99e5); /* 46 */ + Libisofs_md5_HH (c, d, a, b, x[15], Libisofs_md5_S33, 0x1fa27cf8); /* 47 */ + Libisofs_md5_HH (b, c, d, a, x[ 2], Libisofs_md5_S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + Libisofs_md5_II (a, b, c, d, x[ 0], Libisofs_md5_S41, 0xf4292244); /* 49 */ + Libisofs_md5_II (d, a, b, c, x[ 7], Libisofs_md5_S42, 0x432aff97); /* 50 */ + Libisofs_md5_II (c, d, a, b, x[14], Libisofs_md5_S43, 0xab9423a7); /* 51 */ + Libisofs_md5_II (b, c, d, a, x[ 5], Libisofs_md5_S44, 0xfc93a039); /* 52 */ + Libisofs_md5_II (a, b, c, d, x[12], Libisofs_md5_S41, 0x655b59c3); /* 53 */ + Libisofs_md5_II (d, a, b, c, x[ 3], Libisofs_md5_S42, 0x8f0ccc92); /* 54 */ + Libisofs_md5_II (c, d, a, b, x[10], Libisofs_md5_S43, 0xffeff47d); /* 55 */ + Libisofs_md5_II (b, c, d, a, x[ 1], Libisofs_md5_S44, 0x85845dd1); /* 56 */ + Libisofs_md5_II (a, b, c, d, x[ 8], Libisofs_md5_S41, 0x6fa87e4f); /* 57 */ + Libisofs_md5_II (d, a, b, c, x[15], Libisofs_md5_S42, 0xfe2ce6e0); /* 58 */ + Libisofs_md5_II (c, d, a, b, x[ 6], Libisofs_md5_S43, 0xa3014314); /* 59 */ + Libisofs_md5_II (b, c, d, a, x[13], Libisofs_md5_S44, 0x4e0811a1); /* 60 */ + Libisofs_md5_II (a, b, c, d, x[ 4], Libisofs_md5_S41, 0xf7537e82); /* 61 */ + Libisofs_md5_II (d, a, b, c, x[11], Libisofs_md5_S42, 0xbd3af235); /* 62 */ + Libisofs_md5_II (c, d, a, b, x[ 2], Libisofs_md5_S43, 0x2ad7d2bb); /* 63 */ + Libisofs_md5_II (b, c, d, a, x[ 9], Libisofs_md5_S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + memset ((char *) x, 0, sizeof (x)); + return(1); +} + + +static int md5__encode(unsigned char *output, uint32_t *input, + unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } + return(1); +} + + + +static int md5_init(libisofs_md5_ctx *ctx, int flag) +{ + ctx->count[0] = ctx->count[1] = 0; + /* Load magic initialization constants. */ + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xefcdab89; + ctx->state[2] = 0x98badcfe; + ctx->state[3] = 0x10325476; + return(1); +} + + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +static int md5_update(libisofs_md5_ctx *ctx, unsigned char *data, + int datalen, int flag) +{ + unsigned int i, index, partlen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((ctx->count[0] >> 3) & 0x3F); + /* Update number of bits */ + if ((ctx->count[0] += ((uint32_t) datalen << 3)) < + ((uint32_t) datalen << 3)) + ctx->count[1]++; + ctx->count[1] += ((uint32_t) datalen >> 29); + partlen = 64 - index; + + /* Transform as many times as possible. */ + if (datalen >= partlen) { + memcpy((char *) &ctx->buffer[index], (char *) data, partlen); + md5__transform(ctx->state, ctx->buffer); + for (i = partlen; i + 63 < datalen; i += 64) + md5__transform(ctx->state, &data[i]); + index = 0; + } else + i = 0; + + /* Buffer remaining data */ + memcpy((char *) &ctx->buffer[index], (char *) &data[i],datalen-i); + + return(1); +} + + +static int md5_final(libisofs_md5_ctx *ctx, char result[16], int flag) +{ + unsigned char bits[8], *respt; + unsigned int index, padlen; + static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + /* Save number of bits */ + md5__encode(bits, ctx->count, 8); + /* Pad out to 56 mod 64. */ + index = (unsigned int)((ctx->count[0] >> 3) & 0x3f); + padlen = (index < 56) ? (56 - index) : (120 - index); + md5_update(ctx, PADDING, padlen,0); + /* Append length (before padding) */ + md5_update(ctx, bits, 8,0); + /* Store state in result */ + respt= (unsigned char *) result; + md5__encode(respt, ctx->state, 16); + /* Zeroize sensitive information. */ + memset ((char *) ctx, 0, sizeof (*ctx)); + return(1); +} + + +int libisofs_md5(void **ctx_in, char *data, int datalen, + char result[16], int flag) +/* *ctx has to be NULL or point to freeable memory */ +/* + bit0= allocate and init *ctx + bit1= transfer ctx to result + bit2= with bit 0 : clone new *ctx from data + bit15= free *ctx +*/ +{ + unsigned char *datapt; + libisofs_md5_ctx **ctx; + + ctx= (libisofs_md5_ctx **) ctx_in; + if(flag&1) { + if(*ctx!=NULL) + free((char *) *ctx); + *ctx= calloc(1, sizeof(libisofs_md5_ctx)); + if(*ctx==NULL) + return(-1); + md5_init(*ctx,0); + if(flag&4) + memcpy((char *) *ctx,data,sizeof(libisofs_md5_ctx)); + } + if(*ctx==NULL) + return(0); + if(datalen>0) { + datapt= (unsigned char *) data; + md5_update(*ctx, datapt, datalen, 0); + } + if(flag&2) + md5_final(*ctx, result, 0); + if(flag&(1<<15)) { + free((char *) *ctx); + *ctx= NULL; + } + return(1); +} + + +/* ----------------------------------------------------------------------- */ + + +/* 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) +{ + /* data is an int disguised as pointer. It does not point to memory. */ + return 1; +} + + +#ifdef Libisofs_with_checksumS + +/* + @flag bit0= recursion + bit1= session will be appended to an existing image +*/ +static +int checksum_copy_old_nodes(Ecma119Image *target, IsoNode *node, int flag) +{ + IsoNode *pos; + IsoFile *file; + IsoImage *img; + int ret, i; + size_t value_length; + unsigned int idx = 0, old_idx = 0; + char *value = NULL; + void *xipt; + + img = target->image; + if (img->checksum_array == NULL || target->checksum_buffer == NULL) + return 0; + + if (node->type == LIBISO_FILE) { + file = (IsoFile *) node; + if (file->from_old_session) { + 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]; + + if (old_idx == 0 || old_idx > img->checksum_idx_count - 1) + return 0; + + ret = iso_node_lookup_attr(node, "isofs.cx", &value_length, + &value, 0); + if (ret == 1 && value_length == 4) { + 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); + } + } + if (value != NULL) + free(value); + } + } else if (node->type == LIBISO_DIR) { + for (pos = ((IsoDir *) node)->children; pos != NULL; pos = pos->next) { + ret = checksum_copy_old_nodes(target, pos, 1); + if (ret < 0) + return ret; + } + } + return ISO_SUCCESS; +} + +#endif /* Libisofs_with_checksumS */ + + +static +int checksum_writer_compute_data_blocks(IsoImageWriter *writer) +{ + +#ifdef Libisofs_with_checksumS + + size_t size; + Ecma119Image *t; + int ret; + unsigned int lba; + + if (writer == NULL) { + return ISO_ASSERT_FAILURE; + } + t = writer->target; + + lba = t->curblock; /* (t->curblock already contains t->ms_block) */ + size = (t->checksum_idx_counter + 2) / 128 + 1; + t->curblock += size; + + /* >>> ??? reserve extra block for stream detectable checksum */; + + /* Allocate array of MD5 sums */ + t->checksum_buffer = calloc(size, 2048); + if (t->checksum_buffer == NULL) + return ISO_OUT_OF_MEM; + + /* Copy MD5 from nodes of old image into writer->data */ + ret = checksum_copy_old_nodes(t, (IsoNode *) t->image->root, 0); + if (ret < 0) + return ret; + + /* Record lba,count,size,cecksum_type in "isofs.ca" of root node */ + ret = iso_root_set_isofsca((IsoNode *) t->image->root, + (unsigned int) t->ms_block, lba, + t->checksum_idx_counter + 2, 16, "MD5", 0); + if (ret < 0) + return ret; + +#endif /* Libisofs_with_checksumS */ + + return ISO_SUCCESS; +} + + +static +int checksum_writer_write_vol_desc(IsoImageWriter *writer) +{ + /* nothing needed */ + return ISO_SUCCESS; +} + + +static +int checksum_writer_write_data(IsoImageWriter *writer) +{ + +#ifdef Libisofs_with_checksumS + + int wres, res; + size_t i, size; + Ecma119Image *t; + + if (writer == NULL) { + return ISO_ASSERT_FAILURE; + } + + t = writer->target; + iso_msg_debug(t->image->id, "Writing Checksums..."); + + /* Write image checksum to index 0 */ + /* >>> rather fork a result than killing t->checksum_ctx */; + res = libisofs_md5(&(t->checksum_ctx), NULL, 0, t->image_md5, + 2 | (1 << 15)); + if (res > 0) + memcpy(t->checksum_buffer + 0, t->image_md5, 16); + + size = (t->checksum_idx_counter + 2) / 128 + 1; + + /* >>> write overall checksum as index t->checksum_idx_counter + 1 */; + + for (i = 0; i < size; i++) { + wres = iso_write(t, t->checksum_buffer + ((size_t) 2048) * i, + BLOCK_SIZE); + if (wres < 0) + return wres; + } + + /* >>> write scdbackup checksum tag to an extra block */; + +#endif /* Libisofs_with_checksumS */ + + return ISO_SUCCESS; +} + + +static +int checksum_writer_free_data(IsoImageWriter *writer) +{ + /* nothing was allocated at writer->data */ + return ISO_SUCCESS; +} + + +int checksum_writer_create(Ecma119Image *target) +{ + IsoImageWriter *writer; + + writer = malloc(sizeof(IsoImageWriter)); + if (writer == NULL) { + return ISO_OUT_OF_MEM; + } + + writer->compute_data_blocks = checksum_writer_compute_data_blocks; + writer->write_vol_desc = checksum_writer_write_vol_desc; + writer->write_data = checksum_writer_write_data; + writer->free_data = checksum_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/libisofs/md5.h b/libisofs/md5.h new file mode 100644 index 0000000..1387b98 --- /dev/null +++ b/libisofs/md5.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2009 Thomas Schmitt + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See COPYING file for details. + */ + +#ifndef LIBISO_MD5_H_ +#define LIBISO_MD5_H_ + + +/** Compute a MD5 checksum from one or more calls of this function. + The first call has to be made with flag bit0 == 1. It may already submit + processing payload in data and datalen. + The last call has to be made with bit15 set. Normally bit1 will be set + too in order to receive the checksum before it gets disposed. + bit1 may only be set in the last call or together with bit2. + The combination of bit1 and bit2 may be used to get an intermediate + result without hampering an ongoing checksum computation. + + @param ctx the checksum context which stores the state between calls. + It gets created with flag bit0 and disposed with bit15. + With flag bit0, *ctx has to be NULL or point to freeable + memory. + @param data the bytes to be checksummed + @param datalen the number of bytes in data + @param result returns the 16 bytes of checksum if called with bit1 set + @param flag bit0= allocate and init *ctx + bit1= transfer ctx to result + bit2= with bit 0 : clone new *ctx from data + bit15= free *ctx +*/ +int libisofs_md5(void **ctx, char *data, int datalen, + char result[16], int flag); + + +/** Create a writer object for checksums and add it to the writer list of + the given Ecma119Image. +*/ +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); + + +#endif /* ! LIBISO_MD5_H_ */ + + diff --git a/libisofs/node.c b/libisofs/node.c index 924dad2..008ab5e 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -13,6 +13,7 @@ #include "stream.h" #include "aaip_0_2.h" #include "messages.h" +#include "util.h" #include @@ -2575,3 +2576,138 @@ int iso_node_cmp_ino(IsoNode *n1, IsoNode *n2, int flag) { return iso_node_cmp_flag(n1, n2, 1); } + + +int iso_file_set_isofscx(IsoFile *file, unsigned int checksum_index, + int flag) +{ + static char *names = "isofs.cx"; + static size_t value_lengths[1] = {4}; + unsigned char value[4]; + char *valuept; + int i, ret; + + for(i = 0; i < 4; i++) + value[3 - i] = (checksum_index >> (8 * i)) & 0xff; + valuept= (char *) value; + ret = iso_node_set_attrs((IsoNode *) file, (size_t) 1, + &names, value_lengths, &valuept, 2 | 8); + return ret; +} + + +int iso_root_set_isofsca(IsoNode *node, uint32_t start_lba, uint32_t end_lba, + uint32_t count, uint32_t size, char *typetext, + int flag) +{ + char buffer[5 + 5 + 5 + 2 + 81], *wpt = buffer, *valuept = buffer; + int result_len, ret; + static char *names = "isofs.ca"; + static size_t value_lengths[1]; + + /* Set value of isofs.ca with + 4 byte START, 4 byte END, 4 byte COUNT, SIZE = 16, MD5 */ + iso_util_encode_len_bytes(start_lba, wpt, 4, &result_len, 0); + wpt += result_len; + iso_util_encode_len_bytes(end_lba, wpt, 4, &result_len, 0); + wpt += result_len; + iso_util_encode_len_bytes(count, wpt, 4, &result_len, 0); + wpt += result_len; + iso_util_encode_len_bytes(size, wpt, 1, &result_len, 0); + wpt += result_len; + strncpy(wpt, typetext, 80); + if (strlen(typetext) > 80) + wpt += 80; + else + wpt += strlen(typetext); + value_lengths[0] = wpt - buffer; + ret = iso_node_set_attrs(node, (size_t) 1, + &names, value_lengths, &valuept, 2 | 8); + return ret; +} + + +int iso_root_get_isofsca(IsoNode *node, uint32_t *start_lba, uint32_t *end_lba, + uint32_t *count, uint32_t *size, char typetext[81], + int flag) +{ + int ret, len; + size_t value_len; + char *value = NULL, *rpt; + + ret = iso_node_lookup_attr(node, "isofs.ca", &value_len, &value, 0); + if (ret <= 0) + goto ex; + + /* Parse value of isofs.ca with + 4 byte START, 4 byte END, 4 byte COUNT, SIZE = 16, MD5 */ + rpt = value; + iso_util_decode_len_bytes(start_lba, rpt, &len, + value_len - (rpt - value), 0); + rpt += len + 1; + iso_util_decode_len_bytes(end_lba, rpt, &len, + value_len - (rpt - value), 0); + rpt += len + 1; + iso_util_decode_len_bytes(count, rpt, &len, + value_len - (rpt - value), 0); + rpt += len + 1; + iso_util_decode_len_bytes(size, rpt, &len, + value_len - (rpt - value), 0); + rpt += len + 1; + len = value_len - (rpt - value); + if (len > 80) + len = 80; + memcpy(typetext, rpt, len); + typetext[len] = 0; + + ret= ISO_SUCCESS; +ex:; + if (value != NULL) + free(value); + return ret; +} + + +/* API */ +int iso_file_get_md5(IsoImage *image, IsoFile *file, char md5[16], int flag) +{ + +#ifdef Libisofs_with_checksumS + + int ret, i; + size_t value_len; + char *value = NULL; + uint32_t idx = 0; + + if (image->checksum_array == NULL) + return 0; + ret = iso_node_lookup_attr((IsoNode *) file, "isofs.cx", + &value_len, &value, 0); + if (ret <= 0) + goto ex; + if (value_len > 4) { + ret = 0; + goto ex; + } + for (i = 0; i < value_len; i++) + idx = (idx << 8) | ((unsigned char *) value)[i]; + if (idx == 0 || idx > image->checksum_idx_count - 1) { + /* (last index is not MD5 of a file) */ + ret = 0; + goto ex; + } + memcpy(md5, image->checksum_array + ((size_t) 16) * ((size_t) idx), 16); + ret = ISO_SUCCESS; +ex:; + if (value != NULL) + free(value); + return ret; + +#else + + return 0; + +#endif /* ! Libisofs_with_checksumS */ + +} + diff --git a/libisofs/node.h b/libisofs/node.h index 09e5501..980eeed 100644 --- a/libisofs/node.h +++ b/libisofs/node.h @@ -24,7 +24,7 @@ /** * The extended information is a way to attach additional information to each * IsoNode. External applications may want to use this extension system to - * store application speficic information related to each node. On the other + * store application specific information related to each node. On the other * side, libisofs may make use of this struct to attach information to nodes in * some particular, uncommon, cases, without incrementing the size of the * IsoNode struct. @@ -67,7 +67,7 @@ struct iso_extended_info { struct Iso_Node { /* - * Initilized to 1, originally owned by user, until added to another node. + * Initialized to 1, originally owned by user, until added to another node. * Then it is owned by the parent node, so the user must take his own ref * if needed. With the exception of the creation functions, none of the * other libisofs functions that return an IsoNode increment its @@ -451,4 +451,31 @@ int iso_node_set_ino(IsoNode *node, ino_t ino, int flag); */ int iso_node_cmp_flag(IsoNode *n1, IsoNode *n2, int flag); + +/** + * Set the checksum index (typically comming from IsoFileSrc.checksum_index) + * of a regular file node. The index is encoded as xattr "isofs.cx" with + * four bytes of value. + */ +int iso_file_set_isofscx(IsoFile *file, unsigned int checksum_index, + int flag); + + +/** + * Set the checksum area description. node should be the root node. + * It is encoded as xattr "isofs.ca". + */ +int iso_root_set_isofsca(IsoNode *node, uint32_t start_lba, uint32_t end_lba, + uint32_t count, uint32_t size, char *typetext, + int flag); + +/** + * Get the checksum area description. node should be the root node. + * It is encoded as xattr "isofs.ca". + */ +int iso_root_get_isofsca(IsoNode *node, uint32_t *start_lba, uint32_t *end_lba, + uint32_t *count, uint32_t *size, char typetext[81], + int flag); + + #endif /*LIBISO_NODE_H_*/ diff --git a/libisofs/util.c b/libisofs/util.c index 8381b71..0223a04 100644 --- a/libisofs/util.c +++ b/libisofs/util.c @@ -1489,3 +1489,42 @@ int iso_init_locale(int flag) } +int iso_util_encode_len_bytes(uint32_t data, char *buffer, int data_len, + int *result_len, int flag) +{ + uint32_t x; + int i, l; + char *wpt = buffer; + + if (data_len <= 0) { + x = data; + for (i = 0; i < 4 && x != 0; i++) + x = x >> 8; + l = i; + if (l == 0) + l = 1; + } else + l = data_len; + *((unsigned char *) (wpt++)) = l; + for (i = 0; i < l; i++) + *((unsigned char *) (wpt++)) = data >> (8 * (l - i - 1)); + *result_len = l + 1; + return ISO_SUCCESS; +} + + +int iso_util_decode_len_bytes(uint32_t *data, char *buffer, int *data_len, + int buffer_len, int flag) +{ + int i; + + *data = 0; + *data_len = ((unsigned char *) buffer)[0]; + if (*data_len > buffer_len - 1) + *data_len = buffer_len - 1; + for (i = 1; i <= *data_len; i++) + *data = (*data << 8) | ((unsigned char *) buffer)[i]; + return ISO_SUCCESS; +} + + diff --git a/libisofs/util.h b/libisofs/util.h index 28545d6..c5af0d1 100644 --- a/libisofs/util.h +++ b/libisofs/util.h @@ -440,4 +440,22 @@ void iso_htable_destroy(IsoHTable *table, hfree_data_t free_data); */ unsigned int iso_str_hash(const void *key); +/** + * Encode an integer as LEN,BYTES for being a component in certain AAIP + * attribute values. + */ +int iso_util_encode_len_bytes(uint32_t data, char *buffer, int data_len, + int *result_len, int flag); + +/** + * Decode an integer as LEN,BYTES for being a component in certain AAIP + * attribute values. + * @param data returns the decoded value + * @param buffer contains the encoded value + * @param data_len returns the number of value bytes (without len byte) + * @param buffer_len tells the number of valid buffer bytes + */ +int iso_util_decode_len_bytes(uint32_t *data, char *buffer, int *data_len, + int buffer_len, int flag); + #endif /*LIBISO_UTIL_H_*/