diff --git a/doc/checksums.txt b/doc/checksums.txt index 9f78790..27a7106 100644 --- a/doc/checksums.txt +++ b/doc/checksums.txt @@ -67,8 +67,8 @@ The tree checksum tag is written after the ECMA-119 directory entries. The session checksum tag is written after all payload including the checksum array. (Then follows eventual padding.) -The tags are single lines of printable text, padded by 0 bytes. They have -the following format: +The tags are single lines of printable text at the very beginning of a block +of 2048 bytes. They have the following format: Tag_id pos=# range_start=# range_size=# [session_start|next=#] md5=# self=#\n @@ -161,9 +161,14 @@ checksums as strings of 32 hex digits. The MD5 checksum of the tag itself up to and including the last hex digit of parameter "md5=". - The newline character at the end is mandatory. For now all bytes of the - block after that newline shall be zero. There may arise future extensions. +The newline character at the end is mandatory. After that newline there may +follow more lines. Their meaning is not necessarily described in this document. +One such line type is the scdbackup checksum tag, an ancestor of libisofs tags +which is suitable only for single session images which begin at LBA 0. It bears +a checksum record which by its MD5 covers all bytes from LBA 0 up to the +newline character preceding the scdbackup tag. See scdbackup/README appendix +VERIFY for details. ------------------------------------------------------------------------------- diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 4a37392..b4ba6cc 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -31,11 +31,13 @@ #include "md5.h" #endif +#include #include #include #include #include #include +#include /* * TODO #00011 : guard against bad path table usage with more than 65535 dirs @@ -1132,6 +1134,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) target->md5_file_checksums = opts->md5_file_checksums; target->md5_session_checksum = opts->md5_session_checksum; + strcpy(target->scdbackup_tag_parm, opts->scdbackup_tag_parm); target->checksum_idx_counter = 0; target->checksum_ctx = NULL; target->checksum_counter = 0; @@ -1866,6 +1869,39 @@ int iso_write_opts_set_record_md5(IsoWriteOpts *opts, int session, int files) return ISO_SUCCESS; } +int iso_write_opts_set_scdbackup_tag(IsoWriteOpts *opts, + char *name, char *timestamp) +{ + +#ifdef Libisofs_with_checksumS + + char eff_name[81], eff_time[19]; + int i; + + for (i = 0; name[i] != 0 && i < 80; i++) + if (isspace((int) ((unsigned char *) name)[i])) + eff_name[i] = '_'; + else + eff_name[i] = name[i]; + if (i == 0) + eff_name[i++] = '_'; + eff_name[i] = 0; + for (i = 0; timestamp[i] != 0 && i < 18; i++) + if (isspace((int) ((unsigned char *) timestamp)[i])) + eff_time[i] = '_'; + else + eff_time[i] = timestamp[i]; + if (i == 0) + eff_time[i++] = '_'; + eff_time[i] = 0; + + sprintf(opts->scdbackup_tag_parm, "%s %s", eff_name, eff_time); + +#endif /* Libisofs_with_checksumS */ + + return ISO_SUCCESS; +} + int iso_write_opts_set_replace_mode(IsoWriteOpts *opts, int dir_mode, int file_mode, int uid, int gid) { diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index 84354da..d982d6c 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -281,6 +281,15 @@ struct iso_write_opts { */ uint32_t data_start_lba; + /** + * If not empty: A text holding parameters "name" and "timestamp" for + * a scdbackup stream checksum tag. See scdbackup/README appendix VERIFY. + * It makes sense only for single session images which start at LBA 0. + * Such a tag may be part of a libisofs checksum tag block after the + * session tag line. It then covers the whole session up to its own start + * position. + */ + char scdbackup_tag_parm[100]; }; typedef struct ecma119_image Ecma119Image; @@ -464,6 +473,8 @@ struct ecma119_image is submitted with ecma119_image_new() ? */ + char scdbackup_tag_parm[96]; + #endif /* Libisofs_with_checksumS */ /* Buffer for communication between burn_source and writer thread */ diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index de1f68d..9c42a2b 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -1446,6 +1446,27 @@ int iso_write_opts_set_sort_files(IsoWriteOpts *opts, int sort); */ int iso_write_opts_set_record_md5(IsoWriteOpts *opts, int session, int files); +/** + * Set the parameters "name" and "timestamp" for a scdbackup checksum tag. + * It will be appended to the libisofs session tag if the image starts at + * LBA 0 (see iso_write_opts_set_ms_block()). The scdbackup tag can be used + * to verify the image by command scdbackup_verify -auto_end. + * See scdbackup/README appendix VERIFY for its inner details. + * + * @param name + * A word of up to 80 characters. Typically _ telling + * that this is volume of a total of volumes. + * @param timestamp + * A string of 13 characters YYMMDD.hhmmss (e.g. A90831.190324). + * A9 = 2009, B0 = 2010, B1 = 2011, ... C0 = 2020, ... + * @return + * 1 indicates success, <0 is error + * + * @since 0.6.24 + */ +int iso_write_opts_set_scdbackup_tag(IsoWriteOpts *opts, + char *name, char *timestamp); + /** * Whether to set default values for files and directory permissions, gid and * uid. All these take one of three values: 0, 1 or 2. @@ -5522,6 +5543,13 @@ int iso_md5_match(char first_md5[16], char second_md5[16]); */ #define ISO_MD5_STREAM_CHANGE 0xE430FE9A +/** + * Session does not start at LBA 0. scdbackup checksum tag not written. + * (WARNING, HIGH, -359) + * @since 0.6.24 +*/ +#define ISO_SCDBACKUP_TAG_NOT_0 0xD030FE99 + /* ! PLACE NEW ERROR CODES HERE ! */ diff --git a/libisofs/md5.c b/libisofs/md5.c index 2bc4b86..3cf41d1 100644 --- a/libisofs/md5.c +++ b/libisofs/md5.c @@ -698,6 +698,66 @@ int checksum_writer_create(Ecma119Image *target) } +static +int iso_md5_write_scdbackup_tag(Ecma119Image *t, char *tag_block, int flag) +{ + +#ifdef Libisofs_with_checksumS + + void *ctx = NULL; + off_t pos = 0, line_start; + int record_len, block_len, res, i; + char postext[20], md5[16], record[160]; + + line_start = strlen(tag_block); + iso_md5_compute(t->checksum_ctx, tag_block, line_start); + res = iso_md5_clone(t->checksum_ctx, &ctx); + if (res < 0) + goto ex; + res = iso_md5_end(&ctx, md5); + + pos = (off_t) t->checksum_tag_pos * (off_t) 2048 + line_start; + if(pos >= 1000000000) + sprintf(postext, "%u%9.9u", (unsigned int) (pos / 1000000000), + (unsigned int) (pos % 1000000000)); + else + sprintf(postext, "%u", (unsigned int) pos), + + sprintf(record, "%s %s ", t->scdbackup_tag_parm, postext); + record_len = strlen(record); + for (i = 0; i < 16; i++) + sprintf(record + record_len + 2 * i, + "%2.2x", ((unsigned char *) md5)[i]); + record_len+= 32; + res = iso_md5_start(&ctx); + if (res < 0) + goto ex; + iso_md5_compute(ctx, record, record_len); + iso_md5_end(&ctx, md5); + + sprintf(tag_block + line_start, "scdbackup_checksum_tag_v0.1 %s %d %s ", + postext, record_len, record); + block_len = strlen(tag_block); + for (i = 0; i < 16; i++) + sprintf(tag_block + block_len + 2 * i, + "%2.2x", ((unsigned char *) md5)[i]); + block_len+= 32; + tag_block[block_len++]= '\n'; + + res = ISO_SUCCESS; +ex:; + if (ctx != NULL) + iso_md5_end(&ctx, md5); + return res; + +#else + + return ISO_SUCCESS; + +#endif /* Libisofs_with_checksumS */ +} + + /* Write stream detectable checksum tag to extra block. * @flag bit0-7= tag type * 1= session tag (End checksumming.) @@ -719,11 +779,16 @@ int iso_md5_write_tag(Ecma119Image *t, int flag) start = t->checksum_range_start; memset(tag_block, 0, 2048); mode = flag & 255; + if (mode < 1 || mode > 4) + return ISO_WRONG_ARG_VALUE; + res = iso_md5_clone(t->checksum_ctx, &ctx); + if (res < 0) + return res; + res = iso_md5_end(&ctx, md5); if (mode == 1) { - res = iso_md5_end(&(t->checksum_ctx), md5); size = t->checksum_range_size; pos = t->checksum_tag_pos; - } else if (mode >= 2 && mode <= 4) { + } else { if (mode == 2) { pos = t->checksum_sb_tag_pos; } else if (mode == 3) { @@ -733,46 +798,51 @@ int iso_md5_write_tag(Ecma119Image *t, int flag) start = pos - (pos % 32); } size = pos - start; - res = iso_md5_clone(t->checksum_ctx, &ctx); - if (res < 0) - return res; - res = iso_md5_end(&ctx, md5); - } else { - return ISO_WRONG_ARG_VALUE; } - if (res > 0) { - iso_util_tag_magic(mode, &tag_id, &tag_id_len, 0); - sprintf(tag_block, - "%s pos=%u range_start=%u range_size=%u", - tag_id, pos, start, size); + if (res < 0) + goto ex; - l = strlen(tag_block); - if (mode == 2) { - sprintf(tag_block + l, " next=%u", t->checksum_tree_tag_pos); - } else if (mode == 3) { - sprintf(tag_block + l, " next=%u", t->checksum_tag_pos); - } else if (mode == 4) { - sprintf(tag_block + l, " session_start=%u", t->ms_block); - } - strcat(tag_block + l, " md5="); - l = strlen(tag_block); + iso_util_tag_magic(mode, &tag_id, &tag_id_len, 0); + sprintf(tag_block, "%s pos=%u range_start=%u range_size=%u", + tag_id, pos, start, size); + + l = strlen(tag_block); + if (mode == 2) { + sprintf(tag_block + l, " next=%u", t->checksum_tree_tag_pos); + } else if (mode == 3) { + sprintf(tag_block + l, " next=%u", t->checksum_tag_pos); + } else if (mode == 4) { + sprintf(tag_block + l, " session_start=%u", t->ms_block); + } + strcat(tag_block + l, " md5="); + l = strlen(tag_block); + for (i = 0; i < 16; i++) + sprintf(tag_block + l + 2 * i, "%2.2x", + ((unsigned char *) md5)[i]); + l+= 32; + + res = iso_md5_start(&ctx); + if (res > 0) { + iso_md5_compute(ctx, tag_block, l); + iso_md5_end(&ctx, md5); + strcpy(tag_block + l, " self="); + l += 6; for (i = 0; i < 16; i++) sprintf(tag_block + l + 2 * i, "%2.2x", ((unsigned char *) md5)[i]); - l+= 32; - - res = iso_md5_start(&ctx); - if (res > 0) { - iso_md5_compute(ctx, tag_block, l); - iso_md5_end(&ctx, md5); - strcpy(tag_block + l, " self="); - l += 6; - for (i = 0; i < 16; i++) - sprintf(tag_block + l + 2 * i, "%2.2x", - ((unsigned char *) md5)[i]); - } - tag_block[l + 32] = '\n'; } + tag_block[l + 32] = '\n'; + + if (mode == 1 && t->scdbackup_tag_parm[0]) { + if (t->ms_block > 0) { + iso_msg_submit(t->image->id, ISO_SCDBACKUP_TAG_NOT_0, 0, NULL); + } else { + res = iso_md5_write_scdbackup_tag(t, tag_block, 0); + if (res < 0) + goto ex; + } + } + if (mode == 4) { if (t->opts_overwrite != NULL) memcpy(t->opts_overwrite + pos * 2048, tag_block, 2048); @@ -783,6 +853,7 @@ int iso_md5_write_tag(Ecma119Image *t, int flag) goto ex; } } + res = ISO_SUCCESS; ex:; if (ctx != NULL) diff --git a/libisofs/messages.c b/libisofs/messages.c index a44361b..f73c473 100644 --- a/libisofs/messages.c +++ b/libisofs/messages.c @@ -274,6 +274,8 @@ const char *iso_error_to_msg(int errcode) return "Checksum tag with unexpected address range encountered"; case ISO_MD5_STREAM_CHANGE: return "Detected file content changes while it was written into the image"; + case ISO_SCDBACKUP_TAG_NOT_0: + return "Session does not start at LBA 0. scdbackup checksum tag not written."; default: return "Unknown error"; }