diff --git a/xorriso/opts_d_h.c b/xorriso/opts_d_h.c index 646f8d17..940060eb 100644 --- a/xorriso/opts_d_h.c +++ b/xorriso/opts_d_h.c @@ -1845,6 +1845,9 @@ int Xorriso_option_help(struct XorrisO *xorriso, int flag) " -blank [\"force:\"]\"fast\"|\"all\"|\"deformat\"|\"deformat_quickest\"", " Blank medium or invalidate ISO image on medium.", " Prefix \"force:\" overrides medium evaluation.", +" -truncate_overwritable entity id adjust", +" Activate an older session on overwritable medium. Adjust", +" its size to some value not smaller than original old size.", " -close_damaged \"as_needed\"|\"force\"", " Close track and session of damaged medium.", " -format \"as_needed\"|\"full\"|\"fast\"|\"by_index_#\"|\"by_size_#\"", diff --git a/xorriso/opts_p_z.c b/xorriso/opts_p_z.c index 23eb8f91..92c54fad 100644 --- a/xorriso/opts_p_z.c +++ b/xorriso/opts_p_z.c @@ -1,7 +1,7 @@ /* xorriso - creates, loads, manipulates and burns ISO 9660 filesystem images. - Copyright 2007-2018 Thomas Schmitt, + Copyright 2007-2020 Thomas Schmitt, Provided under GPL version 2 or later. @@ -1703,6 +1703,18 @@ int Xorriso_option_toc_of(struct XorrisO *xorriso, char *which, int flag) } +/* Command -truncate_overwritable */ +int Xorriso_option_truncate_overwritable(struct XorrisO *xorriso, + char *adr_mode, char *adr_value, + char *adjust, int flag) +{ + int ret; + + ret= Xorriso_truncate_overwritable(xorriso, adr_mode, adr_value, adjust, 0); + return(ret); +} + + /* Option -uid */ int Xorriso_option_uid(struct XorrisO *xorriso, char *uid, int flag) { diff --git a/xorriso/parse_exec.c b/xorriso/parse_exec.c index 1ca7656a..28b4f323 100644 --- a/xorriso/parse_exec.c +++ b/xorriso/parse_exec.c @@ -1,7 +1,7 @@ /* xorriso - creates, loads, manipulates and burns ISO 9660 filesystem images. - Copyright 2007-2019 Thomas Schmitt, + Copyright 2007-2020 Thomas Schmitt, Provided under GPL version 2 or later. @@ -573,7 +573,7 @@ int Xorriso_count_args(struct XorrisO *xorriso, int argc, char **argv, "" }; static char arg3_commands[][40]= { - "append_partition", + "append_partition", "truncate_overwritable", "" }; static char arg4_commands[][40]= { @@ -778,7 +778,7 @@ int Xorriso_cmd_sorting_rank(struct XorrisO *xorriso, "print_size", "tell_media_space", "* Writing the result, drive control:", - "format", "blank", "close_damaged", + "format", "blank", "truncate_overwritable", "close_damaged", "rollback", "changes_pending", "commit", "commit_eject", "eject", @@ -1941,6 +1941,10 @@ if (0) { (*idx)++; Xorriso_option_toc_of(xorriso, arg1, 0); + } else if(strcmp(cmd,"truncate_overwritable")==0) { + (*idx)+= 3; + ret= Xorriso_option_truncate_overwritable(xorriso, arg1, arg2, arg3, 0); + } else if(strcmp(cmd,"uid")==0) { (*idx)++; ret= Xorriso_option_uid(xorriso,arg1,0); diff --git a/xorriso/write_run.c b/xorriso/write_run.c index 7ca75794..7a791cbd 100644 --- a/xorriso/write_run.c +++ b/xorriso/write_run.c @@ -2,7 +2,7 @@ /* xorriso - creates, loads, manipulates and burns ISO 9660 filesystem images. - Copyright 2007-2017 Thomas Schmitt, + Copyright 2007-2020 Thomas Schmitt, Provided under GPL version 2 or later. @@ -2866,24 +2866,169 @@ ex: } +int Xorriso_overwrite_iso_head(struct XorrisO *xorriso, + struct burn_drive *drive, char *head_buffer, + int lba, int flag) +{ + int ret; + off_t to_write; + + to_write= 64 * 1024; + burn_drive_reset_simulate(drive, xorriso->do_dummy); + ret= burn_random_access_write(drive, (off_t) lba * (off_t) 2048, + head_buffer, to_write, 1); + if(ret <= 0) { + Xorriso_process_msg_queues(xorriso, 0); + sprintf(xorriso->info_text, + "Cannot write new ISO image head to LBA %d", lba); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + return(0); + } + return(1); +} + + +/* @param flag bit0= insist on tag_type 4 (relocated superblock tag) +*/ +int Xorriso_find_sb_checksum(struct XorrisO *xorriso, + char *head_buffer, int *vd_end, int flag) +{ + int i, tag_type, ret; + uint32_t pos, range_start, range_size, next_tag; + char md5[16]; + + *vd_end= 0; + + /* Look for volume descriptor end */ + for(i= 16; i < 32; i++) + if(((unsigned char *) head_buffer)[i * 2048] == 0xff && + strncmp(head_buffer + i * 2048 + 1, "CD001", 5) == 0) + break; + /* Check whether the next one is a libisofs checksum tag */ + if(i < 32) { + *vd_end= i; + i++; + ret= iso_util_decode_md5_tag(head_buffer + i * 2048, &tag_type, &pos, + &range_start, &range_size, &next_tag, md5, 0); + if(ret <= 0) + return(ret); + if((flag & 1) && tag_type != 4) + return(0); /* No other tag type is supposed to occur before type 4 */ + } + return(i + 1); +} + + +/* @param field_head Example: " md5=" +*/ +int Xorriso__set_iso_check_tag_md5(char *tag_data, char *field_head, + void **ctx, int *field_end, int flag) +{ + char md5_bin[16], m32, *cpt; + int i; + + iso_md5_end(ctx, md5_bin); + cpt= strstr(tag_data, field_head); + if(cpt == NULL) + return(0); + cpt+= strlen(field_head); + m32= cpt[32]; + for(i= 0; i < 16; i++) + sprintf(cpt + 2 * i, "%2.2x", ((unsigned char *) md5_bin)[i]); + cpt[32]= m32; + *field_end= (cpt - tag_data) + 32; + return(1); +} + + +int Xorriso_verify_sb_tag(struct XorrisO *xorriso, char *head_buffer, + int checksum_block, int flag) +{ + int tag_type, ret; + uint32_t pos, range_start, range_size, next_tag; + char md5_rec[16], md5_comp[16]; + void *ctx= NULL; + + /* Obtain checksum */ + iso_util_decode_md5_tag(head_buffer + checksum_block * 2048, + &tag_type, &pos, &range_start, &range_size, + &next_tag, md5_rec, 0); + /* Verify checksum */ + ret= iso_md5_start(&ctx); + if(ret <= 0) { + Xorriso_process_msg_queues(xorriso,0); + Xorriso_no_malloc_memory(xorriso, NULL, 0); + return(0); + } + ret= iso_md5_compute(ctx, head_buffer, checksum_block * 2048); + iso_md5_end(&ctx, md5_comp); + if(ret <= 0) { + Xorriso_process_msg_queues(xorriso,0); + return(0); + } + if(iso_md5_match(md5_rec, md5_comp)) + return(1); + Xorriso_msgs_submit(xorriso, 0, + "Superblock data do not match superblock checksum tag", + 0, "WARNING", 0); + return(0); +} + + +int Xorriso_refresh_sb_tag(struct XorrisO *xorriso, char *head_buffer, + int checksum_block, int flag) +{ + int ret, field_end; + char md5_bin[16]; + void *ctx= NULL; + + /* Recompute checksum and update found checksum tag */; + ret= iso_md5_start(&ctx); + if(ret <= 0) { +no_md5_ctx:; + Xorriso_process_msg_queues(xorriso,0); + Xorriso_no_malloc_memory(xorriso, NULL, 0); + return(0); + } + ret= iso_md5_compute(ctx, head_buffer, checksum_block * 2048); + if(ret <= 0) { +md5_comp_failed:; + iso_md5_end(&ctx, md5_bin); + return(0); + } + Xorriso__set_iso_check_tag_md5(head_buffer + checksum_block * 2048, + " md5=", &ctx, &field_end, 0); + if(ret <= 0) + return(2); + ret= iso_md5_start(&ctx); + if(ret <= 0) + goto no_md5_ctx; + ret= iso_md5_compute(ctx, head_buffer + checksum_block * 2048, + field_end); + if(ret <= 0) + goto md5_comp_failed; + Xorriso__set_iso_check_tag_md5(head_buffer + checksum_block * 2048, + " self=", &ctx, &field_end, 0); + return(1); +} + + /* @param flag bit0= obtain iso_lba from indev bit1= head_buffer already contains a valid head bit2= issue message about success bit3= check whether source blocks are banned by in_sector_map + bit4= refresh relocated sb checksum tag */ int Xorriso_update_iso_lba0(struct XorrisO *xorriso, int iso_lba, int isosize, char *head_buffer, struct CheckmediajoB *job, int flag) { - int ret, full_size, i; + int ret, full_size, i, checksum_block= -1, vd_end; char *headpt; struct burn_drive_info *dinfo; struct burn_drive *drive = NULL; off_t seek_ret, to_write; - int tag_type; - uint32_t pos, range_start, range_size, next_tag; - char md5[16]; ret= Xorriso_may_burn(xorriso, 0); if(ret <= 0) @@ -2960,33 +3105,41 @@ int Xorriso_update_iso_lba0(struct XorrisO *xorriso, int iso_lba, int isosize, } } } + /* patch ISO header */ full_size= iso_lba + isosize; headpt= head_buffer + 32*1024; for(i=0;i<4;i++) headpt[87-i]= headpt[80+i]= (full_size >> (8*i)) & 0xff; + /* >>> What about Joliet et.al. ? */; + + if(flag & 16) { + /* Find relocated sb checksum tag */ + ret= Xorriso_find_sb_checksum(xorriso, head_buffer, &vd_end, 1); + if(ret > 0) { + /* If it is recognizable then it matched in Xorriso_adjust_relocated_sb */ + checksum_block= ret - 1; + ret= Xorriso_refresh_sb_tag(xorriso, head_buffer, checksum_block, 0); + if(ret <= 0) + return(0); + } + } if(job != NULL) { /* This is a check_media superblock relocation: Invalidate eventual libisofs checksum tags. Write only up to PVD end plus eventual invalidated tag. */ - /* Look for volume descriptor end */ - for(i= 16; i < 32; i++) - if(((unsigned char *) head_buffer)[i * 2048] == 0xff && - strncmp(head_buffer + i * 2048 + 1, "CD001", 5) == 0) - break; - /* Check whether the next one is a libisofs checksum tag */ - if(i < 32) { - i++; - ret= iso_util_decode_md5_tag(head_buffer + i * 2048, &tag_type, &pos, - &range_start, &range_size, &next_tag, md5, 0); - if(ret != 0) /* corrupted or not: invalidate */ - memset(head_buffer + i * 2048, 0, 8); + to_write= 2048 * 32; + ret= Xorriso_find_sb_checksum(xorriso, head_buffer, &i, 0); + if(ret > 0) { + if(!(flag & 16)) /* invalidate */ + memset(head_buffer + (ret - 1) * 2048, 0, 8); + to_write= 2048 * ret; + } else if(i > 0) { + to_write= 2048 * (i + 1); } - to_write= 2048 * (i + 1); - seek_ret= lseek(job->data_to_fd, (off_t) 0, SEEK_SET); if(seek_ret == -1) ret= 0; @@ -3001,16 +3154,9 @@ int Xorriso_update_iso_lba0(struct XorrisO *xorriso, int iso_lba, int isosize, } } else { /* This is a regular superblock relocation. Write full 64 kB. */ - to_write= 64 * 1024; - burn_drive_reset_simulate(drive, xorriso->do_dummy); - ret= burn_random_access_write(drive, (off_t) 0, head_buffer, to_write, 1); - if(ret<=0) { - Xorriso_process_msg_queues(xorriso,0); - sprintf(xorriso->info_text, - "Cannot write new ISO image head to LBA 0"); - Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); - return(0); - } + ret= Xorriso_overwrite_iso_head(xorriso, drive, head_buffer, 0, 0); + if(ret <= 0) + return(ret); } if(flag & 4) { sprintf(xorriso->info_text, @@ -3021,6 +3167,485 @@ int Xorriso_update_iso_lba0(struct XorrisO *xorriso, int iso_lba, int isosize, } +/* @return 1= ok, 0= no match, -1= MD5 computation error, + -2= MD5 clone or start error +*/ +int Xorriso_migrate_checksum_tag(struct XorrisO *xorriso, char *buffer, + int buf_base, int start, + int checksum_block, char md5_rec[16], + void *ctx_unch, void *ctx_chng, int flag) +{ + int ret, to_compute; + char *headpt, md5_clone[16]; + void *ctx_clone= NULL; + int field_end; + + /* Checksum both up to before checksum tag */ + headpt= buffer + start * 2048; + to_compute= (checksum_block - start) * 2048; + if(to_compute > 0) { + ret= iso_md5_compute(ctx_unch, headpt, to_compute); + if(ret <= 0) + {ret= -1; goto ex;} + ret= iso_md5_compute(ctx_chng, headpt, to_compute); + if(ret <= 0) + {ret= -1; goto ex;} + } + /* Verify with unchanged checksum */ + ret= iso_md5_clone(ctx_unch, &ctx_clone); + if(ret <= 0) + {ret= -2; goto ex;} + iso_md5_end(&ctx_clone, md5_clone); + if(!iso_md5_match(md5_rec, md5_clone)) + {ret= 0; goto ex;} + /* Compute unchanged rest of block range */ + headpt= buffer + checksum_block * 2048; + to_compute= 2048; + ret= iso_md5_compute(ctx_unch, headpt, to_compute); + if(ret <= 0) + {ret= -1; goto ex;} + /* Replace checksum in tag by changed checksum */ + ret= iso_md5_clone(ctx_chng, &ctx_clone); + if(ret <= 0) + {ret= -2; goto ex;} + Xorriso__set_iso_check_tag_md5(headpt, " md5=", &ctx_clone, &field_end, 0); + /* Recompute and write self= checksum */ + ret= iso_md5_start(&ctx_clone); + if(ret <= 0) + {ret= -2; goto ex;} + ret= iso_md5_compute(ctx_clone, headpt, field_end); + if(ret <= 0) + {ret= -1; goto ex;} + Xorriso__set_iso_check_tag_md5(headpt, " self=", &ctx_clone, &field_end, 0); + /* Add rest of head_buffer to changed checksum */ + ret= iso_md5_compute(ctx_chng, headpt, to_compute); + if(ret <= 0) + {ret= -1; goto ex;} + ret= 1; +ex:; + if(ctx_clone != NULL) + iso_md5_end(&ctx_clone, md5_clone); + return(ret); +} + + +/* Verify and re-compute tree and session checksum tag */ +int Xorriso_refresh_ts_tags(struct XorrisO *xorriso, + struct burn_drive *drive, + void *ctx_unch, void *ctx_chng, + int iso_lba, int session_size, + int checksum_block, int flag) +{ + int i, ret, tag_type, look_for_tag, check_start, look_from_block, was_change; + off_t read_pos, to_read, data_count; + uint32_t pos, range_start, range_size, next_tag; + char md5_rec[16]; + char *buf= NULL; + + look_for_tag= 3; /* tree tag */ + look_from_block= checksum_block + 1; /* first buffer is already partly done */ + Xorriso_alloc_meM(buf, char, 32 * 2048); + for(read_pos= iso_lba; read_pos < iso_lba + session_size; read_pos+= 32) { + was_change= 0; + to_read= 32; + if(read_pos + to_read > iso_lba + session_size) + to_read= iso_lba + session_size - read_pos; + ret= burn_read_data(drive, read_pos * (off_t) 2048, buf, + to_read * (off_t) 2048, &data_count, 0); + if(ret <= 0) + {ret= 0; goto ex;} + check_start= look_from_block; + for(i= look_from_block; i < to_read; i++) { + /* Watch out for tag */ + ret= iso_util_decode_md5_tag(buf + i * 2048, + &tag_type, &pos, &range_start, &range_size, + &next_tag, md5_rec, look_for_tag); + if(ret < 0 ) { + ret= 0; goto ex; + } else if(ret == 1) { + if(tag_type != look_for_tag) { + sprintf(xorriso->info_text, + "Encountered checksum tag type %d while looking for %d", + tag_type, look_for_tag); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "MISHAP", 0); + ret= 2; goto ex; + } + /* Checksum up to before tag, verify, + if match replace checksum and write */ + ret= Xorriso_migrate_checksum_tag(xorriso, buf, read_pos, check_start, + i, md5_rec, ctx_unch, ctx_chng, 0); + if(ret == -2) + goto ex; + if(ret < 0) + {ret= 0; goto ex;} + if(ret == 0) { + sprintf(xorriso->info_text, + "Checksum tag MD5 mismatch in old session state"); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "MISHAP", 0); + ret= 2; goto ex; + } + + was_change= 1; + if(look_for_tag == 3) { + look_for_tag= 1; /* session tag */ + } else { + look_for_tag= -1; + break; + } + check_start= i + 1; + } + } + + look_from_block= 0; /* all following buffer need processing from start */ + + if(was_change) { + ret= burn_random_access_write(drive, (off_t) read_pos * (off_t) 2048, + buf, to_read * (off_t) 2048, 1); + if(ret <= 0) { + Xorriso_process_msg_queues(xorriso, 0); + sprintf(xorriso->info_text, + "Cannot write new checksum tag data to LBA %d", (int) read_pos); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + ret= 0; goto ex; + } + } + + if(look_for_tag < 0) + {ret= 1; goto ex;} + + /* Checksum what was not checksummed yet */ + if(to_read - check_start > 0) { + ret= iso_md5_compute(ctx_unch, buf + 2048 * check_start, + (to_read - check_start) * 2048); + if(ret <= 0) + {ret= 0; goto ex;} + ret= iso_md5_compute(ctx_chng, buf + 2048 * check_start, + (to_read - check_start) * 2048); + if(ret <= 0) + {ret= 0; goto ex;} + } + } + ret= 1; +ex:; + Xorriso_free_meM(buf); + return(ret); +} + + +int Xorriso_adjust_session_size(struct XorrisO *xorriso, + struct burn_drive *drive, + char *head_buffer, + int iso_lba, int iso_size, + int checksum_block, int session_size, int flag) +{ + int i, ret, tag_type; + uint32_t pos, range_start, range_size, next_tag; + char *headpt, md5_unch[16], md5_chng[16], md5_clone[16], md5_rec[16]; + void *ctx_unch= NULL, *ctx_chng= NULL, *ctx_clone= NULL; + + if(checksum_block > 0) { + /* Obtain recorded superblock MD5 */ + ret= iso_util_decode_md5_tag(head_buffer + checksum_block * 2048, + &tag_type, &pos, &range_start, &range_size, + &next_tag, md5_rec, 0); + if(ret <= 0 || tag_type != 2) { + sprintf(xorriso->info_text, + "Encountered checksum tag type %d while looking for 2", tag_type); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "MISHAP", 0); + checksum_block= 0; + } + } + if(checksum_block > 0) { + /* Create md5 context for unchanged state */ + ret= iso_md5_start(&ctx_unch); + if(ret <= 0) { +no_ctx:; + Xorriso_process_msg_queues(xorriso, 0); + Xorriso_no_malloc_memory(xorriso, NULL, 0); + goto ex; + } + /* Checksum up to before PVD */ + ret= iso_md5_compute(ctx_unch, head_buffer, 32768); + if(ret <= 0) + goto ex; + /* Before the first change: obtain md5 object for changed state */ + ret= iso_md5_clone(ctx_unch, &ctx_chng); + if(ret <= 0) + goto no_ctx; + /* Add PVD to unchanged checksum */ + ret= iso_md5_compute(ctx_unch, head_buffer + 32768, 2048); + if(ret <= 0) + goto ex; + } + + /* Update session PVD at iso_lba+16 to iso_size */ + headpt= head_buffer + 32 * 1024; + for(i= 0; i < 4; i++) + headpt[87 - i]= headpt[80 + i]= (iso_size >> (8 * i)) & 0xff; + + if(checksum_block > 0) { + /* Add changed PVD to changed checksum */ + ret= iso_md5_compute(ctx_chng, head_buffer + 32768, 2048); + if(ret <= 0) + goto ex; + ret= Xorriso_migrate_checksum_tag(xorriso, head_buffer, iso_lba, 17, + checksum_block, md5_rec, + ctx_unch, ctx_chng, 0); + if(ret == -2) + goto no_ctx; + if(ret < 0) + {ret= 0; goto ex;} + if(ret == 0) { + sprintf(xorriso->info_text, + "Superblock MD5 mismatch in old session state"); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "MISHAP", 0); + checksum_block= 0; + } + } + + ret= Xorriso_overwrite_iso_head(xorriso, drive, head_buffer, iso_lba, 0); + if(ret <= 0) + goto ex; + + if(checksum_block > 0) { + /* Verify and re-compute existing checksum tree and session tag */ + ret= Xorriso_refresh_ts_tags(xorriso, drive, ctx_unch, ctx_chng, + iso_lba, session_size, checksum_block, 0); + if(ret == -2) + goto no_ctx; + if(ret <= 0) + goto ex; + } + + ret= 1; +ex:; + Xorriso_process_msg_queues(xorriso, 0); + if(ctx_unch != NULL) + iso_md5_end(&ctx_unch, md5_unch); + if(ctx_chng != NULL) + iso_md5_end(&ctx_chng, md5_chng); + if(ctx_clone != NULL) + iso_md5_end(&ctx_clone, md5_clone); + return(ret); +} + + +/* Read relocated superblock and patch in the VDs of the session superblock */ +int Xorriso_adjust_relocated_sb(struct XorrisO *xorriso, + struct burn_drive *drive, + char *head_buffer, + char **sb_buffer, + int flag) +{ + int ret, old_size, i, vd_end, checksum_block= -1; + char *buffer, *checksum= NULL; + + *sb_buffer= NULL; + Xorriso_alloc_meM(*sb_buffer, char, 32 * 2048); + buffer= *sb_buffer; + Xorriso_alloc_meM(checksum, char, 2048); + + ret= isoburn_read_iso_head(drive, 0, &old_size, buffer, 2); + if(ret <= 0) + goto ex; + ret= Xorriso_find_sb_checksum(xorriso, buffer, &vd_end, 0); + if(ret <= 0) + goto ex; + if(ret > 0) { + checksum_block= ret - 1; + memcpy(checksum, buffer + checksum_block * 2048, 2048); + ret= Xorriso_verify_sb_tag(xorriso, buffer, checksum_block, 0); + if(ret <= 0) { + checksum_block= -1; + memset(checksum, 0, 8); + } + } + + for(i= 16; i < 32; i++) { + memcpy(buffer + i * 2048, head_buffer + i * 2048, 2048); + if(((unsigned char *) head_buffer)[i * 2048] == 0xff && + strncmp(head_buffer + i * 2048 + 1, "CD001", 5) == 0) { + i++; + break; + } + } + if(checksum_block >= 0 && i < 32) + memcpy(buffer + i * 2048, checksum, 2048); + + ret= 1; +ex: + if(ret <= 0) + Xorriso_free_meM(*sb_buffer); + Xorriso_free_meM(checksum); + return(ret); +} + + +int Xorriso_truncate_overwritable(struct XorrisO *xorriso, char *adr_mode, + char *adr_value, char *adjust, int flag) +{ + int ret, iso_lba= 0, iso_session, iso_track, iso_size= 0, image_start_mode= 0; + int old_size, new_size, blocks, was_indev= 0, checksum_block= 0, vd_end; + int readable_blocks; + char image_start_value[81], *head_buffer= NULL, iso_volid[33]; + char *sb_buffer= NULL; + struct burn_drive_info *dinfo; + struct burn_drive *drive = NULL, *in_drive = NULL; + struct burn_multi_caps *caps= NULL; + + Xorriso_alloc_meM(head_buffer, char, 32 * 2048); + + if(Xorriso_change_is_pending(xorriso, 0)) { + sprintf(xorriso->info_text, + "-truncate_overwritable: Image changes pending. -commit or -rollback first"); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + ret= 0; goto ex; + } + ret= Xorriso_may_burn(xorriso, 0); + if(ret <= 0) + goto ex; + ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive, + "on attempt to activate an older session", 2); + if(ret <= 0) + goto ex; + + /* Is it overwritable ? */ + ret= burn_disc_get_multi_caps(drive, BURN_WRITE_NONE, &caps, 0); + if(ret > 0) { + if(caps->start_adr == 0) + ret= 0; + } + if(ret <= 0) { + sprintf(xorriso->info_text, + "-truncate_overwritable: Loaded medium is not random-access overwritable"); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + goto ex; + } + + ret= Xorriso_reassure(xorriso, "-truncate_overwritable", + "activates an older session and destroys newer ones", 0); + if(ret <= 0) + {ret= 2; goto ex;} + + /* Learn old size */ + ret= isoburn_read_iso_head(drive, 0, &old_size, iso_volid, 0); + if(ret <= 0) { + sprintf(xorriso->info_text, + "-truncate_overwritable: Cannot read ISO 9660 Volume Descriptor from LBA 0"); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + goto ex; + } + + /* Check for PVD at image_start_value and learn new size */ + ret= Xorriso_decode_load_adr(xorriso, "-truncate_overwritable", + adr_mode, adr_value, &image_start_mode, + image_start_value, 0); + if(ret <= 0) + goto ex; + ret= isoburn_get_mount_params(drive, image_start_mode, image_start_value, + &iso_lba, &iso_track, &iso_session, iso_volid, + 0); + if(ret <= 0) + goto ex; + if(ret != 1) { + sprintf(xorriso->info_text, + "-truncate_overwritable: Given address does not lead to ISO 9660 Volume Descriptor"); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + ret= 0; goto ex; + } + if(iso_lba >= old_size) { + sprintf(xorriso->info_text, + "-truncate_overwritable: Given address is larger than current ISO size"); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + ret= 0; goto ex; + } + ret= isoburn_read_iso_head(drive, iso_lba, &new_size, head_buffer, 2); + if(ret <= 0) + goto ex; + + ret= Xorriso_find_sb_checksum(xorriso, head_buffer, &vd_end, 0); + if(ret > 0) + checksum_block= ret - 1; + + /* Default is "new" */ + iso_size= new_size; + if(strcmp(adjust, "old") == 0) { + /* ISO size before truncation */ + iso_size= old_size - iso_lba; + } else if(adjust[0] == '+') { + /* Add-on size to new */ + blocks= Scanf_io_size(adjust + 1, 0) / 2048; + if(blocks < 0) + goto wrong_adjust; + iso_size+= blocks; + } else if(adjust[0] >= '0' && adjust[0] <= '9') { + /* Add-on size to new */ + blocks= Scanf_io_size(adjust, 0) / 2048; + if(blocks < iso_lba + iso_size) { +wrong_adjust:; + sprintf(xorriso->info_text, + "-truncate_overwritable: Given total filesystem size is smaller than new session size"); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + ret= 0; goto ex; + } + iso_size= blocks - iso_lba; + } + + ret= burn_get_read_capacity(drive, &readable_blocks, 0); + Xorriso_process_msg_queues(xorriso, 0); + if(ret > 0) { + if(iso_lba + iso_size > readable_blocks) { + sprintf(xorriso->info_text, "-truncate_overwritable: Given total filesystem size is larger than formatted medium size"); + Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0); + ret= 0; goto ex; + } + } + + /* Give up possible input drive */ + ret= Xorriso_get_drive_handles(xorriso, &dinfo, &in_drive, "", 16); + if(ret < 0) + goto ex; + if(ret == 1) { + ret= Xorriso_give_up_drive(xorriso, 1); + if(ret<=0) + goto ex; + was_indev= 1; + } + + if(iso_size != new_size) { + ret=Xorriso_adjust_session_size(xorriso, drive, head_buffer, + iso_lba, iso_size, checksum_block, + new_size, 0); + if(ret <= 0) + goto ex; + } + + /* Load first 64 kB and transfer VDs from head_buffer */ + ret= Xorriso_adjust_relocated_sb(xorriso, drive, head_buffer, &sb_buffer, 0); + if(ret <= 0) + goto ex; + + /* Patch the size and write back */ + ret= Xorriso_update_iso_lba0(xorriso, iso_lba, iso_size, sb_buffer, + NULL, 2 | 16); + if(ret <= 0) + goto ex; + + ret= Xorriso_reaquire_outdev(xorriso, 2 + was_indev); + if(ret <= 0) + goto ex; + + ret= 1; +ex: + if(caps!=NULL) + burn_disc_free_multi_caps(&caps); + Xorriso_free_meM(head_buffer); + Xorriso_free_meM(sb_buffer); + Xorriso_process_msg_queues(xorriso,0); + return(ret); +} + + int Xorriso_set_system_area_path(struct XorrisO *xorriso, char *path, int flag) { int ret; diff --git a/xorriso/xorriso.1 b/xorriso/xorriso.1 index b837267d..b925b6d7 100644 --- a/xorriso/xorriso.1 +++ b/xorriso/xorriso.1 @@ -2652,6 +2652,57 @@ as reported by the drive. They would be chosen by \-read_speed "min" or "max" if they undercut or surpass the built\-in limits. These are "1x", "52xCD", "24xDVD", "20xBD". .TP +\fB\-list_profiles\fR "in"|"out"|"all" +Put out a list of media types supported by \-indev, \-outdev, or both, +respectively. +The currently recognized type is marked by text "(current)". +.TP +\fB\-truncate_overwritable\fR entity id adjust +On overwritable medium copy the volume descriptors of an existing session to +the overall descriptors at LBA 0 ff. This makes all sessions +\fBinaccessible\fR which are younger than the activated one. +A reason to do this would be read errors in the younger sessions and +the wish to re\-write or skip them. +.br +This operation is only allowed if no changes to the loaded filesystem are +pending. If an \-indev is acquired then it is released before the write +operation begins and re\-acquired only in case of success. +.br +The parameters "entity" and "id" have the same meaning as with command \-load. +They choose the existing ISO session which shall become the youngest accessible +session. Available entity names are "session", "track", "lba", "sbsector", +"volid". "auto" makes few sense. id is a number or search text as appropriate +for the given entity. +.br +Parameter "adjust" controls the claimed size of the activated session. Text +"new" means the size of the newly activated session as it was before this +command. I.e. the space of the then inaccessible younger sessions will be +re\-used when appending more sessions. +.br +"old" means the size up to the end of the previously youngest session. +I.e. "old" will not free the space of the then inaccessible younger sessions +for re\-use. +.br +A number preceded by "+" gives the number of bytes to be added to "new". +A number without "+" gives the overall number of bytes. In any case the result +may not be smaller than "new". Numbers may have a unit suffix: "d"=512, +"k"=1024, "s"=2048, "m"=1024k, "g"=1024m. +.br +Examples: +.br +Activate session 4 and enable overwriting of the blocks of younger sessions: +.br + \-truncate_overwritable session 4 new +.br +Activate session 4 and claim the blocks of younger sessions as useless part of +session 4: +.br + \-truncate_overwritable session 4 old +.br +Let session 4 claim additional 500 MiB as useless data: +.br + \-truncate_overwritable session 4 +500m +.TP \fB\-close_damaged\fR "as_needed"|"force" Try to close the upcoming track and session if the drive reported the medium as damaged. This may apply to CD\-R, CD\-RW, DVD\-R, DVD\-RW, DVD+R, DVD+R DL, @@ -2668,11 +2719,6 @@ appear undamaged. No image changes are allowed to be pending before this command is performed. After closing was attempted, both drives are given up. .TP -\fB\-list_profiles\fR "in"|"out"|"all" -Put out a list of media types supported by \-indev, \-outdev, or both, -respectively. -The currently recognized type is marked by text "(current)". -.TP .B Settings for result writing: .PP Rock Ridge info will be generated by default. @@ -6268,7 +6314,7 @@ Thomas Schmitt .br for libburnia\-project.org .SH COPYRIGHT -Copyright (c) 2007 \- 2019 Thomas Schmitt +Copyright (c) 2007 \- 2020 Thomas Schmitt .br Permission is granted to distribute this text freely. It shall only be modified in sync with the technical properties of \fBxorriso\fR. diff --git a/xorriso/xorriso.h b/xorriso/xorriso.h index b4e45e1d..03ed4c50 100644 --- a/xorriso/xorriso.h +++ b/xorriso/xorriso.h @@ -2,7 +2,7 @@ /* xorriso - libisoburn higher level API which creates, loads, manipulates and burns ISO 9660 filesystem images. - Copyright 2007-2019 Thomas Schmitt, + Copyright 2007-2020 Thomas Schmitt, Provided under GPL version 2 or later. @@ -2126,6 +2126,12 @@ int Xorriso_option_toc(struct XorrisO *xorriso, int flag); /* @since 1.2.6 */ int Xorriso_option_toc_of(struct XorrisO *xorriso, char *which, int flag); +/* Command -truncate_overwritable */ +/* @since 1.5.4 */ +int Xorriso_option_truncate_overwritable(struct XorrisO *xorriso, + char *adr_mode, char *adr_value, + char *adjust, int flag); + /* Command -uid */ /* @since 0.1.0 */ int Xorriso_option_uid(struct XorrisO *xorriso, char *uid, int flag); diff --git a/xorriso/xorriso.info b/xorriso/xorriso.info index 1b2c127b..a222c9d7 100644 --- a/xorriso/xorriso.info +++ b/xorriso/xorriso.info @@ -4,7 +4,7 @@ xorriso.texi. xorriso - creates, loads, manipulates and writes ISO 9660 filesystem images with Rock Ridge extensions. - Copyright (C) 2007 - 2019 Thomas Schmitt + Copyright (C) 2007 - 2020 Thomas Schmitt Permission is granted to distribute this text freely. INFO-DIR-SECTION Archiving @@ -2259,6 +2259,48 @@ File: xorriso.info, Node: Writing, Next: SetWrite, Prev: Filter, Up: Command speeds, as reported by the drive. They would be chosen by -read_speed "min" or "max" if they undercut or surpass the built-in limits. These are "1x", "52xCD", "24xDVD", "20xBD". +-list_profiles "in"|"out"|"all" + Put out a list of media types supported by -indev, -outdev, or + both, respectively. The currently recognized type is marked by + text "(current)". +-truncate_overwritable entity id adjust + On overwritable medium copy the volume descriptors of an existing + session to the overall descriptors at LBA 0 ff. This makes all + sessions *inaccessible* which are younger than the activated one. + A reason to do this would be read errors in the younger sessions + and the wish to re-write or skip them. + This operation is only allowed if no changes to the loaded + filesystem are pending. If an -indev is acquired then it is + released before the write operation begins and re-acquired only in + case of success. + The parameters "entity" and "id" have the same meaning as with + command -load. They choose the existing ISO session which shall + become the youngest accessible session. Available entity names are + "session", "track", "lba", "sbsector", "volid". "auto" makes few + sense. id is a number or search text as appropriate for the given + entity. + Parameter "adjust" controls the claimed size of the activated + session. Text "new" means the size of the newly activated session + as it was before this command. I.e. the space of the then + inaccessible younger sessions will be re-used when appending more + sessions. + "old" means the size up to the end of the previously youngest + session. I.e. "old" will not free the space of the then + inaccessible younger sessions for re-use. + A number preceded by "+" gives the number of bytes to be added to + "new". A number without "+" gives the overall number of bytes. In + any case the result may not be smaller than "new". Numbers may + have a unit suffix: "d"=512, "k"=1024, "s"=2048, "m"=1024k, + "g"=1024m. + Examples: + Activate session 4 and enable overwriting of the blocks of younger + sessions: + -truncate_overwritable session 4 new + Activate session 4 and claim the blocks of younger sessions as + useless part of session 4: + -truncate_overwritable session 4 old + Let session 4 claim additional 500 MiB as useless data: + -truncate_overwritable session 4 +500m -close_damaged "as_needed"|"force" Try to close the upcoming track and session if the drive reported the medium as damaged. This may apply to CD-R, CD-RW, DVD-R, @@ -2272,10 +2314,6 @@ File: xorriso.info, Node: Writing, Next: SetWrite, Prev: Filter, Up: Command media which appear undamaged. No image changes are allowed to be pending before this command is performed. After closing was attempted, both drives are given up. --list_profiles "in"|"out"|"all" - Put out a list of media types supported by -indev, -outdev, or - both, respectively. The currently recognized type is marked by - text "(current)".  File: xorriso.info, Node: SetWrite, Next: Bootable, Prev: Writing, Up: Commands @@ -5307,7 +5345,7 @@ for libburnia-project.org 15.2 Copyright ============== -Copyright (c) 2007 - 2019 Thomas Schmitt +Copyright (c) 2007 - 2020 Thomas Schmitt Permission is granted to distribute this text freely. It shall only be modified in sync with the technical properties of 'xorriso'. If you make use of the license to derive modified versions of 'xorriso' then @@ -5370,7 +5408,7 @@ File: xorriso.info, Node: CommandIdx, Next: ConceptIdx, Prev: Legal, Up: Top * -chown_r sets ownership in ISO image: Manip. (line 47) * -clone copies ISO directory tree: Insert. (line 185) * -close controls media closing: SetWrite. (line 407) -* -close_damaged closes damaged track and session: Writing. (line 163) +* -close_damaged closes damaged track and session: Writing. (line 205) * -close_filter_list bans filter registration: Filter. (line 50) * -commit writes pending ISO image: Writing. (line 27) * -commit_eject writes and ejects: Writing. (line 53) @@ -5448,7 +5486,7 @@ File: xorriso.info, Node: CommandIdx, Next: ConceptIdx, Prev: Legal, Up: Top * -list_delimiter replaces '--': Scripting. (line 55) * -list_extras lists compile time extra features: Scripting. (line 24) * -list_formats lists available formats: Writing. (line 128) -* -list_profiles lists supported media: Writing. (line 176) +* -list_profiles lists supported media: Writing. (line 163) * -list_speeds lists available write speeds: Writing. (line 139) * -lns creates ISO symbolic link: Insert. (line 181) * -load addresses a particular session as input: Loading. (line 33) @@ -5556,6 +5594,7 @@ File: xorriso.info, Node: CommandIdx, Next: ConceptIdx, Prev: Legal, Up: Top * -temp_mem_limit curbs memory consumption: Scripting. (line 96) * -toc shows list of sessions: Inquiry. (line 27) * -toc_of shows list of sessions: Inquiry. (line 41) +* -truncate_overwritable activates older session: Writing. (line 167) * -uid sets global ownership: SetWrite. (line 290) * -update inserts path if different: Insert. (line 100) * -update_l inserts paths if different: Insert. (line 120) @@ -5619,7 +5658,7 @@ File: xorriso.info, Node: ConceptIdx, Prev: CommandIdx, Up: Top * Create, new ISO image, _definition: Methods. (line 7) * Cylinder alignment, _definition: Bootable. (line 338) * Cylinder size, _definition: Bootable. (line 323) -* Damaged track and session, close, -close_damaged: Writing. (line 163) +* Damaged track and session, close, -close_damaged: Writing. (line 205) * DEC Alpha SRM boot sector, production: Bootable. (line 398) * Delete, from ISO image, -rm: Manip. (line 20) * Delete, from ISO image, -rm_r: Manip. (line 26) @@ -5645,7 +5684,7 @@ File: xorriso.info, Node: ConceptIdx, Prev: CommandIdx, Up: Top * Drive, for output, -outdev: AqDrive. (line 29) * Drive, get drive list, -devices: Inquiry. (line 7) * Drive, get drive list, -device_links: Inquiry. (line 17) -* Drive, list supported media, -list_profiles: Writing. (line 176) +* Drive, list supported media, -list_profiles: Writing. (line 163) * Drive, reduce activity, -calm_drive: Loading. (line 306) * Drive, report SCSI commands, -scsi_log: Scripting. (line 143) * Drive, write and eject, -commit_eject: Writing. (line 53) @@ -5772,6 +5811,7 @@ File: xorriso.info, Node: ConceptIdx, Prev: CommandIdx, Up: Top * Navigate, tell disk working directory, -pwdx: Navigate. (line 21) * Navigate, tell ISO working directory, -pwd: Navigate. (line 19) * Next writeable address, -grow_blindly: AqDrive. (line 112) +* Older session, activate, -truncate_overwritable: Writing. (line 167) * Output Character Set, _definition: Charset. (line 26) * Overwritable media, _definition: Media. (line 14) * Ownership, global in ISO image, -uid: SetWrite. (line 290) @@ -5913,42 +5953,42 @@ Node: Manip76969 Node: CmdFind87069 Node: Filter105998 Node: Writing110620 -Node: SetWrite120767 -Node: Bootable145844 -Node: Jigdo172799 -Node: Charset177802 -Node: Exception181131 -Node: DialogCtl187260 -Node: Inquiry189862 -Node: Navigate198744 -Node: Verify207201 -Node: Restore217672 -Node: Emulation226838 -Node: Scripting237294 -Node: Frontend245077 -Node: Examples254703 -Node: ExDevices255881 -Node: ExCreate256542 -Node: ExDialog257842 -Node: ExGrowing259113 -Node: ExModifying259922 -Node: ExBootable260432 -Node: ExCharset260987 -Node: ExPseudo261883 -Node: ExCdrecord262810 -Node: ExMkisofs263130 -Node: ExGrowisofs265027 -Node: ExException266180 -Node: ExTime266638 -Node: ExIncBackup267096 -Node: ExRestore271122 -Node: ExRecovery272068 -Node: Files272640 -Node: Environ273974 -Node: Seealso274722 -Node: Bugreport275439 -Node: Legal276030 -Node: CommandIdx277042 -Node: ConceptIdx294585 +Node: SetWrite122875 +Node: Bootable147952 +Node: Jigdo174907 +Node: Charset179910 +Node: Exception183239 +Node: DialogCtl189368 +Node: Inquiry191970 +Node: Navigate200852 +Node: Verify209309 +Node: Restore219780 +Node: Emulation228946 +Node: Scripting239402 +Node: Frontend247185 +Node: Examples256811 +Node: ExDevices257989 +Node: ExCreate258650 +Node: ExDialog259950 +Node: ExGrowing261221 +Node: ExModifying262030 +Node: ExBootable262540 +Node: ExCharset263095 +Node: ExPseudo263991 +Node: ExCdrecord264918 +Node: ExMkisofs265238 +Node: ExGrowisofs267135 +Node: ExException268288 +Node: ExTime268746 +Node: ExIncBackup269204 +Node: ExRestore273230 +Node: ExRecovery274176 +Node: Files274748 +Node: Environ276082 +Node: Seealso276830 +Node: Bugreport277547 +Node: Legal278138 +Node: CommandIdx279150 +Node: ConceptIdx296766  End Tag Table diff --git a/xorriso/xorriso.texi b/xorriso/xorriso.texi index c6ec6d0d..be73660d 100644 --- a/xorriso/xorriso.texi +++ b/xorriso/xorriso.texi @@ -69,7 +69,7 @@ xorriso - creates, loads, manipulates and writes ISO 9660 filesystem images with Rock Ridge extensions. -Copyright @copyright{} 2007 - 2019 Thomas Schmitt +Copyright @copyright{} 2007 - 2020 Thomas Schmitt @quotation Permission is granted to distribute this text freely. @@ -3111,6 +3111,61 @@ as reported by the drive. They would be chosen by -read_speed "min" or "max" if they undercut or surpass the built-in limits. These are "1x", "52xCD", "24xDVD", "20xBD". @c man .TP +@item -list_profiles "in"|"out"|"all" +@kindex -list_profiles lists supported media +@cindex Drive, list supported media, -list_profiles +Put out a list of media types supported by -indev, -outdev, or both, +respectively. +The currently recognized type is marked by text "(current)". +@c man .TP +@item -truncate_overwritable entity id adjust +@kindex -truncate_overwritable activates older session +@cindex Older session, activate, -truncate_overwritable +On overwritable medium copy the volume descriptors of an existing session to +the overall descriptors at LBA 0 ff. This makes all sessions +@strong{inaccessible} which are younger than the activated one. +A reason to do this would be read errors in the younger sessions and +the wish to re-write or skip them. +@* +This operation is only allowed if no changes to the loaded filesystem are +pending. If an -indev is acquired then it is released before the write +operation begins and re-acquired only in case of success. +@* +The parameters "entity" and "id" have the same meaning as with command -load. +They choose the existing ISO session which shall become the youngest accessible +session. Available entity names are "session", "track", "lba", "sbsector", +"volid". "auto" makes few sense. id is a number or search text as appropriate +for the given entity. +@* +Parameter "adjust" controls the claimed size of the activated session. Text +"new" means the size of the newly activated session as it was before this +command. I.e. the space of the then inaccessible younger sessions will be +re-used when appending more sessions. +@* +"old" means the size up to the end of the previously youngest session. +I.e. "old" will not free the space of the then inaccessible younger sessions +for re-use. +@* +A number preceded by "+" gives the number of bytes to be added to "new". +A number without "+" gives the overall number of bytes. In any case the result +may not be smaller than "new". Numbers may have a unit suffix: "d"=512, +"k"=1024, "s"=2048, "m"=1024k, "g"=1024m. +@* +Examples: +@* +Activate session 4 and enable overwriting of the blocks of younger sessions: +@* + -truncate_overwritable session 4 new +@* +Activate session 4 and claim the blocks of younger sessions as useless part of +session 4: +@* + -truncate_overwritable session 4 old +@* +Let session 4 claim additional 500 MiB as useless data: +@* + -truncate_overwritable session 4 +500m +@c man .TP @item -close_damaged "as_needed"|"force" @kindex -close_damaged closes damaged track and session @cindex Damaged track and session, close, -close_damaged @@ -3128,13 +3183,6 @@ appear undamaged. @* No image changes are allowed to be pending before this command is performed. After closing was attempted, both drives are given up. -@c man .TP -@item -list_profiles "in"|"out"|"all" -@kindex -list_profiles lists supported media -@cindex Drive, list supported media, -list_profiles -Put out a list of media types supported by -indev, -outdev, or both, -respectively. -The currently recognized type is marked by text "(current)". @end table @c man .TP @c man .B Settings for result writing: @@ -7327,7 +7375,7 @@ Thomas Schmitt for libburnia-project.org @c man .SH COPYRIGHT @section Copyright -Copyright (c) 2007 - 2019 Thomas Schmitt +Copyright (c) 2007 - 2020 Thomas Schmitt @* Permission is granted to distribute this text freely. It shall only be modified in sync with the technical properties of @command{xorriso}. diff --git a/xorriso/xorriso_timestamp.h b/xorriso/xorriso_timestamp.h index 8ff52849..d706b247 100644 --- a/xorriso/xorriso_timestamp.h +++ b/xorriso/xorriso_timestamp.h @@ -1 +1 @@ -#define Xorriso_timestamP "2020.08.06.101015" +#define Xorriso_timestamP "2020.08.06.153930" diff --git a/xorriso/xorrisoburn.h b/xorriso/xorrisoburn.h index 1e04948f..43ce33ac 100644 --- a/xorriso/xorrisoburn.h +++ b/xorriso/xorrisoburn.h @@ -4,7 +4,7 @@ a command line oriented batch and dialog tool which creates, loads, manipulates and burns ISO 9660 filesystem images. - Copyright 2007-2019 Thomas Schmitt, + Copyright 2007-2020 Thomas Schmitt, Provided under GPL version 2 or later. @@ -338,6 +338,9 @@ int Xorriso_update_iso_lba0(struct XorrisO *xorriso, int iso_lba, int isosize, char *head_buffer, struct CheckmediajoB *job, int flag); +int Xorriso_truncate_overwritable(struct XorrisO *xorriso, char *adr_mode, + char *adr_value, char *adjust, int flag); + int Xorriso_get_local_charset(struct XorrisO *xorriso, char **name, int flag); int Xorriso_set_local_charset(struct XorrisO *xorriso, char *name, int flag);