diff --git a/include/aaruformat/context.h b/include/aaruformat/context.h index 6204016..931a850 100644 --- a/include/aaruformat/context.h +++ b/include/aaruformat/context.h @@ -303,6 +303,31 @@ typedef struct aaruformat_context tapeFileHashEntry *tape_files; ///< Hash table root for tape files TapePartitionHashEntry *tape_partitions; ///< Hash table root for tape partitions bool is_tape; ///< True if the image is a tape image + + /* Dirty flags (controls write behavior in close.c) */ + bool dirty_secondary_ddt; ///< True if secondary DDT tables should be written during close + bool dirty_primary_ddt; ///< True if primary DDT table should be written during close + bool dirty_single_level_ddt; ///< True if single-level DDT should be written during close + bool dirty_checksum_block; ///< True if checksum block should be written during close + bool dirty_tracks_block; ///< True if tracks block should be written during close + bool dirty_mode2_subheaders_block; ///< True if MODE2 subheader block should be written during close + bool dirty_sector_prefix_block; ///< True if sector prefix block should be written during close + bool dirty_sector_prefix_ddt; ///< True if sector prefix DDT should be written during close + bool dirty_sector_suffix_block; ///< True if sector suffix block should be written during close + bool dirty_sector_suffix_ddt; ///< True if sector suffix DDT should be written during close + bool dirty_sector_subchannel_block; ///< True if subchannel block should be written during close + bool dirty_dvd_long_sector_blocks; ///< True if DVD long sector blocks should be written during close + bool dirty_dvd_title_key_decrypted_block; ///< True if decrypted title key block should be written during close + bool dirty_media_tags; ///< True if media tags should be written during close + bool dirty_tape_ddt; ///< True if tape DDT should be written during close + bool dirty_tape_file_block; ///< True if tape file block should be written during close + bool dirty_tape_partition_block; ///< True if tape partition block should be written during close + bool dirty_geometry_block; ///< True if geometry block should be written during close + bool dirty_metadata_block; ///< True if metadata block should be written during close + bool dirty_dumphw_block; ///< True if dump hardware block should be written during close + bool dirty_cicm_block; ///< True if CICM metadata block should be written during close + bool dirty_json_block; ///< True if JSON metadata block should be written during close + bool dirty_index_block; ///< True if index block should be written during close } aaruformat_context; /** \struct DumpHardwareEntriesWithData diff --git a/src/blocks/optical.c b/src/blocks/optical.c index bba198d..e762be5 100644 --- a/src/blocks/optical.c +++ b/src/blocks/optical.c @@ -452,6 +452,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_set_tracks(void *context, TrackEntry *tracks ctx->image_info.HasPartitions = true; ctx->image_info.HasSessions = true; + ctx->dirty_tracks_block = true; // Mark tracks block as dirty free(ctx->data_tracks); ctx->data_tracks = NULL; diff --git a/src/blocks/tape.c b/src/blocks/tape.c index dd3d90a..5777fba 100644 --- a/src/blocks/tape.c +++ b/src/blocks/tape.c @@ -208,6 +208,7 @@ void process_tape_files_block(aaruformat_context *ctx, const IndexEntry *entry) // Replace if exists, add if new tapeFileHashEntry *old_entry = NULL; HASH_REPLACE(hh, ctx->tape_files, key, sizeof(uint64_t), hash_entry, old_entry); + ctx->dirty_tape_file_block = true; // Mark tape file block as dirty // Free old entry if it was replaced if(old_entry != NULL) @@ -428,6 +429,7 @@ void process_tape_partitions_block(aaruformat_context *ctx, const IndexEntry *en // Replace if exists, add if new TapePartitionHashEntry *old_entry = NULL; HASH_REPLACE(hh, ctx->tape_partitions, key, sizeof(uint8_t), hash_entry, old_entry); + ctx->dirty_tape_partition_block = true; // Mark tape partition block as dirty // Free old entry if it was replaced if(old_entry != NULL) @@ -825,6 +827,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_set_tape_file(void *context, const uint8_t p // Replace if exists, add if new tapeFileHashEntry *old_entry = NULL; HASH_REPLACE(hh, ctx->tape_files, key, sizeof(uint64_t), hash_entry, old_entry); + ctx->dirty_tape_file_block = true; // Mark tape file block as dirty // Free old entry if it was replaced if(old_entry != NULL) @@ -1249,6 +1252,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_set_tape_partition(void *context, const uint // Replace if exists, add if new TapePartitionHashEntry *old_entry = NULL; HASH_REPLACE(hh, ctx->tape_partitions, key, sizeof(uint8_t), hash_entry, old_entry); + ctx->dirty_tape_partition_block = true; // Mark tape partition block as dirty // Free old entry if it was replaced if(old_entry != NULL) diff --git a/src/close.c b/src/close.c index 53e05df..b6d2b63 100644 --- a/src/close.c +++ b/src/close.c @@ -225,6 +225,7 @@ static int32_t write_cached_secondary_ddt(aaruformat_context *ctx) new_ddt_entry.offset = end_of_file; utarray_push_back(ctx->index_entries, &new_ddt_entry); + ctx->dirty_index_block = true; TRACE("Added new DDT index entry at offset %" PRIu64, end_of_file); // Write the updated primary table back to its original position in the file @@ -354,6 +355,7 @@ static int32_t write_primary_ddt(aaruformat_context *ctx) primary_ddt_entry.offset = ctx->primary_ddt_offset; utarray_push_back(ctx->index_entries, &primary_ddt_entry); + ctx->dirty_index_block = true; TRACE("Added primary DDT index entry at offset %" PRIu64, ctx->primary_ddt_offset); } else @@ -502,6 +504,7 @@ static int32_t write_single_level_ddt(aaruformat_context *ctx) single_ddt_entry.offset = ddt_position; utarray_push_back(ctx->index_entries, &single_ddt_entry); + ctx->dirty_index_block = true; TRACE("Added single-level DDT index entry at offset %" PRIu64, ddt_position); } else @@ -806,6 +809,7 @@ static void write_checksum_block(aaruformat_context *ctx) checksum_index_entry.offset = checksum_position; utarray_push_back(ctx->index_entries, &checksum_index_entry); + ctx->dirty_index_block = true; TRACE("Added checksum block index entry at offset %" PRIu64, checksum_position); } @@ -854,6 +858,7 @@ static void write_tracks_block(aaruformat_context *ctx) tracks_index_entry.dataType = 0; tracks_index_entry.offset = tracks_position; utarray_push_back(ctx->index_entries, &tracks_index_entry); + ctx->dirty_index_block = true; TRACE("Added tracks block index entry at offset %" PRIu64, tracks_position); } } @@ -959,6 +964,7 @@ static void write_mode2_subheaders_block(aaruformat_context *ctx) mode2_subheaders_index_entry.dataType = CompactDiscMode2Subheader; mode2_subheaders_index_entry.offset = mode2_subheaders_position; utarray_push_back(ctx->index_entries, &mode2_subheaders_index_entry); + ctx->dirty_index_block = true; TRACE("Added MODE 2 subheaders block index entry at offset %" PRIu64, mode2_subheaders_position); } } @@ -1073,6 +1079,7 @@ static void write_sector_prefix(aaruformat_context *ctx) prefix_index_entry.dataType = CdSectorPrefix; prefix_index_entry.offset = prefix_position; utarray_push_back(ctx->index_entries, &prefix_index_entry); + ctx->dirty_index_block = true; TRACE("Added CD sector prefix block index entry at offset %" PRIu64, prefix_position); } } @@ -1196,6 +1203,7 @@ static void write_sector_suffix(aaruformat_context *ctx) suffix_index_entry.dataType = CdSectorSuffix; suffix_index_entry.offset = suffix_position; utarray_push_back(ctx->index_entries, &suffix_index_entry); + ctx->dirty_index_block = true; TRACE("Added CD sector suffix block index entry at offset %" PRIu64, suffix_position); } } @@ -1325,6 +1333,7 @@ static void write_sector_prefix_ddt(aaruformat_context *ctx) prefix_ddt_index_entry.dataType = CdSectorPrefix; prefix_ddt_index_entry.offset = prefix_ddt_position; utarray_push_back(ctx->index_entries, &prefix_ddt_index_entry); + ctx->dirty_index_block = true; TRACE("Added sector prefix DDT v2 index entry at offset %" PRIu64, prefix_ddt_position); } } @@ -1470,6 +1479,7 @@ static void write_sector_suffix_ddt(aaruformat_context *ctx) suffix_ddt_index_entry.dataType = CdSectorSuffix; suffix_ddt_index_entry.offset = suffix_ddt_position; utarray_push_back(ctx->index_entries, &suffix_ddt_index_entry); + ctx->dirty_index_block = true; TRACE("Added sector suffix DDT v2 index entry at offset %" PRIu64, suffix_ddt_position); } } @@ -1534,7 +1544,7 @@ static void write_sector_suffix_ddt(aaruformat_context *ctx) * * @internal */ -static void write_sector_subchannel(const aaruformat_context *ctx) +static void write_sector_subchannel(aaruformat_context *ctx) { if(ctx->sector_subchannel == NULL) return; @@ -1694,6 +1704,7 @@ static void write_sector_subchannel(const aaruformat_context *ctx) subchannel_index_entry.dataType = subchannel_block.type; subchannel_index_entry.offset = block_position; utarray_push_back(ctx->index_entries, &subchannel_index_entry); + ctx->dirty_index_block = true; TRACE("Added sector subchannel block index entry at offset %" PRIu64, block_position); } } @@ -1925,6 +1936,7 @@ void write_dvd_long_sector_blocks(aaruformat_context *ctx) id_index_entry.dataType = DvdSectorId; id_index_entry.offset = id_position; utarray_push_back(ctx->index_entries, &id_index_entry); + ctx->dirty_index_block = true; TRACE("Added DVD sector ID block index entry at offset %" PRIu64, id_position); } } @@ -2008,6 +2020,7 @@ void write_dvd_long_sector_blocks(aaruformat_context *ctx) ied_index_entry.dataType = DvdSectorIed; ied_index_entry.offset = ied_position; utarray_push_back(ctx->index_entries, &ied_index_entry); + ctx->dirty_index_block = true; TRACE("Added DVD sector IED block index entry at offset %" PRIu64, ied_position); } } @@ -2091,6 +2104,7 @@ void write_dvd_long_sector_blocks(aaruformat_context *ctx) cpr_mai_index_entry.dataType = DvdSectorCprMai; cpr_mai_index_entry.offset = cpr_mai_position; utarray_push_back(ctx->index_entries, &cpr_mai_index_entry); + ctx->dirty_index_block = true; TRACE("Added DVD sector CPR/MAI block index entry at offset %" PRIu64, cpr_mai_position); } } @@ -2174,6 +2188,7 @@ void write_dvd_long_sector_blocks(aaruformat_context *ctx) edc_index_entry.dataType = DvdSectorEdc; edc_index_entry.offset = edc_position; utarray_push_back(ctx->index_entries, &edc_index_entry); + ctx->dirty_index_block = true; TRACE("Added DVD sector EDC block index entry at offset %" PRIu64, edc_position); } } @@ -2278,7 +2293,7 @@ void write_dvd_long_sector_blocks(aaruformat_context *ctx) * * @internal */ -static void write_dvd_title_key_decrypted_block(const aaruformat_context *ctx) +static void write_dvd_title_key_decrypted_block(aaruformat_context *ctx) { if(ctx->sector_decrypted_title_key == NULL) return; @@ -2365,6 +2380,7 @@ static void write_dvd_title_key_decrypted_block(const aaruformat_context *ctx) decrypted_title_key_index_entry.dataType = DvdSectorTitleKeyDecrypted; decrypted_title_key_index_entry.offset = block_position; utarray_push_back(ctx->index_entries, &decrypted_title_key_index_entry); + ctx->dirty_index_block = true; TRACE("Added DVD decrypted title key block index entry at offset %" PRIu64, block_position); } } @@ -2443,7 +2459,7 @@ static void write_dvd_title_key_decrypted_block(const aaruformat_context *ctx) * * @internal */ -static void write_media_tags(const aaruformat_context *ctx) +static void write_media_tags(aaruformat_context *ctx) { if(ctx->mediaTags == NULL) return; @@ -2534,6 +2550,7 @@ static void write_media_tags(const aaruformat_context *ctx) tag_index_entry.dataType = tag_block.type; tag_index_entry.offset = tag_position; utarray_push_back(ctx->index_entries, &tag_index_entry); + ctx->dirty_index_block = true; TRACE("Added media tag block type %d index entry at offset %" PRIu64, tag_block.type, tag_position); } } @@ -2704,7 +2721,7 @@ static void write_media_tags(const aaruformat_context *ctx) * * @internal */ -static void write_tape_file_block(const aaruformat_context *ctx) +static void write_tape_file_block(aaruformat_context *ctx) { if(ctx->tape_files == NULL) return; @@ -2761,6 +2778,7 @@ static void write_tape_file_block(const aaruformat_context *ctx) index_entry.dataType = 0; index_entry.offset = block_position; utarray_push_back(ctx->index_entries, &index_entry); + ctx->dirty_index_block = true; TRACE("Added tape file block index entry at offset %" PRIu64, block_position); } } @@ -2936,7 +2954,7 @@ static void write_tape_file_block(const aaruformat_context *ctx) * * @internal */ -static void write_tape_partition_block(const aaruformat_context *ctx) +static void write_tape_partition_block(aaruformat_context *ctx) { if(ctx->tape_partitions == NULL) return; @@ -2993,6 +3011,7 @@ static void write_tape_partition_block(const aaruformat_context *ctx) index_entry.dataType = 0; index_entry.offset = block_position; utarray_push_back(ctx->index_entries, &index_entry); + ctx->dirty_index_block = true; TRACE("Added tape partition block index entry at offset %" PRIu64, block_position); } } @@ -3061,7 +3080,7 @@ static void write_tape_partition_block(const aaruformat_context *ctx) * @see GeometryBlockHeader * @see aaruf_set_geometry() for setting geometry values before closing. */ -static void write_geometry_block(const aaruformat_context *ctx) +static void write_geometry_block(aaruformat_context *ctx) { if(ctx->geometry_block.identifier != GeometryBlock) return; @@ -3089,6 +3108,7 @@ static void write_geometry_block(const aaruformat_context *ctx) index_entry.dataType = 0; index_entry.offset = block_position; utarray_push_back(ctx->index_entries, &index_entry); + ctx->dirty_index_block = true; TRACE("Added geometry block index entry at offset %" PRIu64, block_position); } } @@ -3331,6 +3351,7 @@ static void write_metadata_block(aaruformat_context *ctx) index_entry.dataType = 0; index_entry.offset = block_position; utarray_push_back(ctx->index_entries, &index_entry); + ctx->dirty_index_block = true; TRACE("Added metadata block index entry at offset %" PRIu64, block_position); } @@ -3612,6 +3633,7 @@ static void write_dumphw_block(aaruformat_context *ctx) index_entry.dataType = 0; index_entry.offset = block_position; utarray_push_back(ctx->index_entries, &index_entry); + ctx->dirty_index_block = true; TRACE("Added dump hardware block index entry at offset %" PRIu64, block_position); } @@ -3712,7 +3734,7 @@ static void write_dumphw_block(aaruformat_context *ctx) * * @internal */ -static void write_cicm_block(const aaruformat_context *ctx) +static void write_cicm_block(aaruformat_context *ctx) { if(ctx->cicm_block == NULL || ctx->cicm_block_header.length == 0 || ctx->cicm_block_header.identifier != CicmBlock) return; @@ -3741,6 +3763,7 @@ static void write_cicm_block(const aaruformat_context *ctx) index_entry.dataType = 0; index_entry.offset = block_position; utarray_push_back(ctx->index_entries, &index_entry); + ctx->dirty_index_block = true; TRACE("Added CICM XML block index entry at offset %" PRIu64, block_position); } } @@ -3849,7 +3872,7 @@ static void write_cicm_block(const aaruformat_context *ctx) * * @internal */ -static void write_aaru_json_block(const aaruformat_context *ctx) +static void write_aaru_json_block(aaruformat_context *ctx) { if(ctx->json_block == NULL || ctx->json_block_header.length == 0 || ctx->json_block_header.identifier != AaruMetadataJsonBlock) @@ -3879,6 +3902,7 @@ static void write_aaru_json_block(const aaruformat_context *ctx) index_entry.dataType = 0; index_entry.offset = block_position; utarray_push_back(ctx->index_entries, &index_entry); + ctx->dirty_index_block = true; TRACE("Added Aaru metadata JSON block index entry at offset %" PRIu64, block_position); } } @@ -4086,81 +4110,96 @@ AARU_EXPORT int AARU_CALL aaruf_close(void *context) if(ctx->is_tape) { // Write tape DDT - res = write_tape_ddt(ctx); - if(res != AARUF_STATUS_OK) return res; + if(ctx->dirty_tape_ddt) + { + res = write_tape_ddt(ctx); + if(res != AARUF_STATUS_OK) return res; + } } else { // Write cached secondary DDT table if any - res = write_cached_secondary_ddt(ctx); - if(res != AARUF_STATUS_OK) return res; + if(ctx->dirty_secondary_ddt) + { + res = write_cached_secondary_ddt(ctx); + if(res != AARUF_STATUS_OK) return res; + } // Write primary DDT table (multi-level) if applicable - res = write_primary_ddt(ctx); - if(res != AARUF_STATUS_OK) return res; + if(ctx->dirty_primary_ddt) + { + res = write_primary_ddt(ctx); + if(res != AARUF_STATUS_OK) return res; + } // Write single-level DDT table if applicable - res = write_single_level_ddt(ctx); - if(res != AARUF_STATUS_OK) return res; + if(ctx->dirty_single_level_ddt) + { + res = write_single_level_ddt(ctx); + if(res != AARUF_STATUS_OK) return res; + } } // Finalize checksums and write checksum block - write_checksum_block(ctx); + if(ctx->dirty_checksum_block) write_checksum_block(ctx); // Write tracks block - write_tracks_block(ctx); + if(ctx->dirty_tracks_block) write_tracks_block(ctx); // Write MODE 2 subheader data block - write_mode2_subheaders_block(ctx); + if(ctx->dirty_mode2_subheaders_block) write_mode2_subheaders_block(ctx); // Write CD sector prefix data block - write_sector_prefix(ctx); + if(ctx->dirty_sector_prefix_block) write_sector_prefix(ctx); // Write sector prefix DDT (statuses + optional indexes) - write_sector_prefix_ddt(ctx); + if(ctx->dirty_sector_prefix_ddt) write_sector_prefix_ddt(ctx); // Write CD sector suffix data block (EDC/ECC captures) - write_sector_suffix(ctx); + if(ctx->dirty_sector_suffix_block) write_sector_suffix(ctx); // Write sector prefix DDT (EDC/ECC captures) - write_sector_suffix_ddt(ctx); + if(ctx->dirty_sector_suffix_ddt) write_sector_suffix_ddt(ctx); // Write sector subchannel data block - write_sector_subchannel(ctx); + if(ctx->dirty_sector_subchannel_block) write_sector_subchannel(ctx); // Write DVD long sector data blocks - write_dvd_long_sector_blocks(ctx); + if(ctx->dirty_dvd_long_sector_blocks) write_dvd_long_sector_blocks(ctx); // Write DVD decrypted title keys - write_dvd_title_key_decrypted_block(ctx); + if(ctx->dirty_dvd_title_key_decrypted_block) write_dvd_title_key_decrypted_block(ctx); // Write media tags data blocks - write_media_tags(ctx); + if(ctx->dirty_media_tags) write_media_tags(ctx); // Write tape files - write_tape_file_block(ctx); + if(ctx->dirty_tape_file_block) write_tape_file_block(ctx); // Write tape partitions - write_tape_partition_block(ctx); + if(ctx->dirty_tape_partition_block) write_tape_partition_block(ctx); // Write geometry block if any - write_geometry_block(ctx); + if(ctx->dirty_geometry_block) write_geometry_block(ctx); // Write metadata block - write_metadata_block(ctx); + if(ctx->dirty_metadata_block) write_metadata_block(ctx); // Write dump hardware block if any - write_dumphw_block(ctx); + if(ctx->dirty_dumphw_block) write_dumphw_block(ctx); // Write CICM XML block if any - write_cicm_block(ctx); + if(ctx->dirty_cicm_block) write_cicm_block(ctx); // Write Aaru metadata JSON block if any - write_aaru_json_block(ctx); + if(ctx->dirty_json_block) write_aaru_json_block(ctx); // Write the complete index at the end of the file - res = write_index_block(ctx); - if(res != AARUF_STATUS_OK) return res; + if(ctx->dirty_index_block) + { + res = write_index_block(ctx); + if(res != AARUF_STATUS_OK) return res; + } if(ctx->deduplicate && ctx->sector_hash_map != NULL) { diff --git a/src/create.c b/src/create.c index 457a018..d5fd482 100644 --- a/src/create.c +++ b/src/create.c @@ -562,6 +562,31 @@ AARU_EXPORT void AARU_CALL *aaruf_create(const char *filepath, const uint32_t me // Is writing ctx->is_writing = true; + // Initialize dirty flags - all true by default for new images + ctx->dirty_secondary_ddt = true; + ctx->dirty_primary_ddt = true; + ctx->dirty_single_level_ddt = true; + ctx->dirty_checksum_block = true; + ctx->dirty_tracks_block = true; + ctx->dirty_mode2_subheaders_block = true; + ctx->dirty_sector_prefix_block = true; + ctx->dirty_sector_prefix_ddt = true; + ctx->dirty_sector_suffix_block = true; + ctx->dirty_sector_suffix_ddt = true; + ctx->dirty_sector_subchannel_block = true; + ctx->dirty_dvd_long_sector_blocks = true; + ctx->dirty_dvd_title_key_decrypted_block = true; + ctx->dirty_media_tags = true; + ctx->dirty_tape_ddt = true; + ctx->dirty_tape_file_block = true; + ctx->dirty_tape_partition_block = true; + ctx->dirty_geometry_block = true; + ctx->dirty_metadata_block = true; + ctx->dirty_dumphw_block = true; + ctx->dirty_cicm_block = true; + ctx->dirty_json_block = true; + ctx->dirty_index_block = true; + TRACE("Exiting aaruf_create() = %p", ctx); // Return context return ctx; diff --git a/src/ddt/ddt_v2.c b/src/ddt/ddt_v2.c index 5d38e84..755dd29 100644 --- a/src/ddt/ddt_v2.c +++ b/src/ddt/ddt_v2.c @@ -985,8 +985,9 @@ int32_t decode_ddt_multi_level_v2(aaruformat_context *ctx, uint64_t sector_addre * @return Returns one of the following status codes: * @retval true if the entry was set successfully, false otherwise. */ -bool set_ddt_entry_v2(aaruformat_context *ctx, const uint64_t sector_address, const bool negative, const uint64_t offset, - const uint64_t block_offset, const uint8_t sector_status, uint64_t *ddt_entry) +bool set_ddt_entry_v2(aaruformat_context *ctx, const uint64_t sector_address, const bool negative, + const uint64_t offset, const uint64_t block_offset, const uint8_t sector_status, + uint64_t *ddt_entry) { TRACE("Entering set_ddt_entry_v2(%p, %" PRIu64 ", %d, %llu, %llu, %d)", ctx, sector_address, negative, offset, block_offset, sector_status); @@ -1070,6 +1071,7 @@ bool set_ddt_single_level_v2(aaruformat_context *ctx, uint64_t sector_address, c TRACE("Setting big single-level DDT entry %d to %ull", sector_address, (uint64_t)*ddt_entry); ctx->user_data_ddt2[sector_address] = *ddt_entry; + ctx->dirty_single_level_ddt = true; // Mark single-level DDT as dirty TRACE("Exiting set_ddt_single_level_v2() = true"); return true; @@ -1165,6 +1167,7 @@ bool set_ddt_multi_level_v2(aaruformat_context *ctx, uint64_t sector_address, bo TRACE("Setting small secondary DDT entry %d to %ull", sector_address % items_per_ddt_entry, (uint64_t)*ddt_entry); ctx->cached_secondary_ddt2[sector_address % items_per_ddt_entry] = *ddt_entry; + ctx->dirty_secondary_ddt = true; // Mark secondary DDT as dirty TRACE("Updated cached secondary DDT entry at position %" PRIu64, sector_address % items_per_ddt_entry); TRACE("Exiting set_ddt_multi_level_v2() = true"); @@ -1304,12 +1307,14 @@ bool set_ddt_multi_level_v2(aaruformat_context *ctx, uint64_t sector_address, bo new_ddt_entry.offset = end_of_file; utarray_push_back(ctx->index_entries, &new_ddt_entry); + ctx->dirty_index_block = true; TRACE("Added new DDT index entry for never-written table at offset %" PRIu64, end_of_file); // Update the primary level table entry to point to the new location of the secondary table uint64_t new_secondary_table_block_offset = end_of_file >> ctx->user_data_ddt_header.blockAlignmentShift; ctx->user_data_ddt2[ctx->cached_ddt_position] = new_secondary_table_block_offset; + ctx->dirty_primary_ddt = true; // Mark primary DDT as dirty // Write the updated primary table back to its original position in the file long saved_pos = ftell(ctx->imageStream); @@ -1501,6 +1506,7 @@ bool set_ddt_multi_level_v2(aaruformat_context *ctx, uint64_t sector_address, bo new_ddt_entry.offset = end_of_file; utarray_push_back(ctx->index_entries, &new_ddt_entry); + ctx->dirty_index_block = true; TRACE("Added new DDT index entry at offset %" PRIu64, end_of_file); // Step 4: Update the primary level table entry and flush it back to file @@ -1510,6 +1516,7 @@ bool set_ddt_multi_level_v2(aaruformat_context *ctx, uint64_t sector_address, bo // Use ddtPosition which was calculated from sectorAddress, not cachedDdtOffset ctx->user_data_ddt2[ddt_position] = new_secondary_table_block_offset; + ctx->dirty_primary_ddt = true; // Mark primary DDT as dirty // Write the updated primary table back to its original position in the file long saved_pos = ftell(ctx->imageStream); @@ -1649,6 +1656,7 @@ bool set_ddt_multi_level_v2(aaruformat_context *ctx, uint64_t sector_address, bo TRACE("Setting big secondary DDT entry %d to %ull", sector_address % items_per_ddt_entry, (uint64_t)*ddt_entry); ctx->cached_secondary_ddt2[sector_address % items_per_ddt_entry] = *ddt_entry; + ctx->dirty_secondary_ddt = true; TRACE("Updated secondary DDT entry at position %" PRIu64, sector_address % items_per_ddt_entry); TRACE("Exiting set_ddt_multi_level_v2() = true"); @@ -1826,6 +1834,7 @@ bool set_ddt_tape(aaruformat_context *ctx, uint64_t sector_address, const uint64 // Insert entry into tape DDT HASH_REPLACE(hh, ctx->tape_ddt, key, sizeof(uint64_t), new_entry, old_entry); + ctx->dirty_tape_ddt = true; // Mark tape DDT as dirty if(old_entry) free(old_entry); TRACE("Exiting set_ddt_tape() = true"); diff --git a/src/dump.c b/src/dump.c index beb58f9..e851b4a 100644 --- a/src/dump.c +++ b/src/dump.c @@ -621,7 +621,8 @@ AARU_EXPORT int32_t AARU_CALL aaruf_set_dumphw(void *context, uint8_t *data, siz size_t pos = sizeof(DumpHardwareHeader); #define COPY_STRING_FIELD(field) \ - do { \ + do \ + { \ const size_t field##_length = copy[e].entry.field##Length; \ if(field##_length > 0) \ { \ @@ -680,6 +681,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_set_dumphw(void *context, uint8_t *data, siz free_dump_hardware_entries(ctx->dump_hardware_entries_with_data, ctx->dump_hardware_header.entries); ctx->dump_hardware_entries_with_data = copy; ctx->dump_hardware_header = header; + ctx->dirty_dumphw_block = true; // Mark dump hardware block as dirty TRACE("Exiting aaruf_set_dumphw() = AARUF_STATUS_OK"); return AARUF_STATUS_OK; diff --git a/src/metadata.c b/src/metadata.c index 4443fd5..24ce357 100644 --- a/src/metadata.c +++ b/src/metadata.c @@ -269,6 +269,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_set_geometry(void *context, const uint32_t c ctx->cylinders = cylinders; ctx->heads = heads; ctx->sectors_per_track = sectors_per_track; + ctx->dirty_geometry_block = true; // Mark geometry block as dirty TRACE("Exiting aaruf_set_geometry(%p, %u, %u, %u) = AARUF_STATUS_OK", context, cylinders, heads, sectors_per_track); return AARUF_STATUS_OK; @@ -768,6 +769,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_set_media_title(void *context, const uint8_t if(ctx->media_title != NULL) free(ctx->media_title); ctx->media_title = copy; ctx->metadata_block_header.mediaTitleLength = length; + ctx->dirty_metadata_block = true; // Mark metadata block as dirty TRACE("Exiting aaruf_set_media_title(%p, %p, %d) = AARUF_STATUS_OK", context, data, length); return AARUF_STATUS_OK; @@ -2305,6 +2307,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_set_aaru_json_metadata(void *context, uint8_ ctx->json_block = copy; ctx->json_block_header.identifier = AaruMetadataJsonBlock; ctx->json_block_header.length = (uint32_t)length; + ctx->dirty_json_block = true; // Mark JSON block as dirty TRACE("Exiting aaruf_set_aaru_json_metadata(%p, %p, %d) = AARUF_STATUS_OK", context, data, length); return AARUF_STATUS_OK; diff --git a/src/write.c b/src/write.c index 477c793..a91a1dd 100644 --- a/src/write.c +++ b/src/write.c @@ -189,6 +189,12 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector(void *context, uint64_t sector_ if(ctx->calculating_blake3 && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long) blake3_hasher_update(ctx->blake3_context, data, length); + // Mark checksum block as dirty if any checksums are being calculated + if((ctx->calculating_md5 || ctx->calculating_sha1 || ctx->calculating_sha256 || ctx->calculating_spamsum || + ctx->calculating_blake3) && + !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long) + ctx->dirty_checksum_block = true; + // Close current block first if(ctx->writing_buffer != NULL && // When sector size changes or block reaches maximum size @@ -303,7 +309,8 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector(void *context, uint64_t sector_ ctx->current_block_header.compression = None; } - uint32_t max_buffer_size = (1 << ctx->user_data_ddt_header.dataShift) * ctx->current_block_header.sectorSize * 2; + uint32_t max_buffer_size = + (1 << ctx->user_data_ddt_header.dataShift) * ctx->current_block_header.sectorSize * 2; TRACE("Setting max buffer size to %u bytes", max_buffer_size); TRACE("Allocating memory for writing buffer"); @@ -772,6 +779,8 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_long(void *context, uint64_t se { ctx->sector_prefix_ddt2[corrected_sector_address] = SectorStatusNotDumped; ctx->sector_suffix_ddt2[corrected_sector_address] = SectorStatusNotDumped; + ctx->dirty_sector_prefix_ddt = true; // Mark prefix DDT as dirty + ctx->dirty_sector_suffix_ddt = true; // Mark suffix DDT as dirty return aaruf_write_sector(context, sector_address, negative, data + 16, SectorStatusNotDumped, 2048); } @@ -802,6 +811,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_long(void *context, uint64_t se ctx->sector_prefix_ddt2[corrected_sector_address] = (uint64_t)(ctx->sector_prefix_offset / 16); ctx->sector_prefix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60; ctx->sector_prefix_offset += 16; + ctx->dirty_sector_prefix_block = true; // Mark prefix block as dirty // Grow prefix buffer if needed if(ctx->sector_prefix_offset >= ctx->sector_prefix_length) @@ -818,6 +828,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_long(void *context, uint64_t se } } } + ctx->dirty_sector_prefix_ddt = true; // Mark prefix DDT as dirty const bool suffix_correct = aaruf_ecc_cd_is_suffix_correct(ctx->ecc_cd_context, data); @@ -830,6 +841,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_long(void *context, uint64_t se ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)(ctx->sector_suffix_offset / 288); ctx->sector_suffix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60; ctx->sector_suffix_offset += 288; + ctx->dirty_sector_suffix_block = true; // Mark suffix block as dirty // Grow suffix buffer if needed if(ctx->sector_suffix_offset >= ctx->sector_suffix_length) @@ -846,6 +858,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_long(void *context, uint64_t se } } } + ctx->dirty_sector_suffix_ddt = true; // Mark suffix DDT as dirty return aaruf_write_sector(context, sector_address, negative, data + 16, SectorStatusMode1Correct, 2048); @@ -961,6 +974,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_long(void *context, uint64_t se ctx->sector_prefix_ddt2[corrected_sector_address] = (uint32_t)(ctx->sector_prefix_offset / 16); ctx->sector_prefix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60; ctx->sector_prefix_offset += 16; + ctx->dirty_sector_prefix_block = true; // Mark prefix block as dirty // Grow prefix buffer if needed if(ctx->sector_prefix_offset >= ctx->sector_prefix_length) @@ -977,6 +991,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_long(void *context, uint64_t se } } } + ctx->dirty_sector_prefix_ddt = true; // Mark prefix DDT as dirty if(ctx->mode2_subheaders == NULL) { @@ -1014,6 +1029,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_long(void *context, uint64_t se (uint64_t)(ctx->sector_suffix_offset / 288); ctx->sector_suffix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60; ctx->sector_suffix_offset += 288; + ctx->dirty_sector_suffix_block = true; // Mark suffix block as dirty // Grow suffix buffer if needed if(ctx->sector_suffix_offset >= ctx->sector_suffix_length) @@ -1033,6 +1049,9 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_long(void *context, uint64_t se // Copy subheader from data buffer to subheader buffer memcpy(ctx->mode2_subheaders + corrected_sector_address * 8, data + 0x10, 8); + ctx->dirty_sector_prefix_ddt = true; + ctx->dirty_sector_suffix_ddt = true; + ctx->dirty_mode2_subheaders_block = true; return aaruf_write_sector(context, sector_address, negative, data + 24, edc == 0 ? SectorStatusMode2Form2NoCrc : correct_edc ? SectorStatusMode2Form2Ok @@ -1055,6 +1074,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_long(void *context, uint64_t se ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)(ctx->sector_suffix_offset / 288); ctx->sector_suffix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60; ctx->sector_suffix_offset += 288; + ctx->dirty_sector_suffix_block = true; // Mark suffix block as dirty // Grow suffix buffer if needed if(ctx->sector_suffix_offset >= ctx->sector_suffix_length) @@ -1074,6 +1094,9 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_long(void *context, uint64_t se // Copy subheader from data buffer to subheader buffer memcpy(ctx->mode2_subheaders + corrected_sector_address * 8, data + 0x10, 8); + ctx->dirty_sector_prefix_ddt = true; + ctx->dirty_sector_suffix_ddt = true; + ctx->dirty_mode2_subheaders_block = true; return aaruf_write_sector( context, sector_address, negative, data + 24, correct_edc && correct_ecc ? SectorStatusMode2Form1Ok : SectorStatusErrored, 2048); @@ -1202,6 +1225,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_long(void *context, uint64_t se } memcpy(ctx->sector_subchannel + sector_address * newTagSize, newTag, newTagSize); + ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty free(newTag); return aaruf_write_sector(context, sector_address, negative, data, sector_status, 512); @@ -1498,6 +1522,7 @@ int32_t aaruf_close_current_block(aaruformat_context *ctx) index_entry.offset = ctx->next_block_position; utarray_push_back(ctx->index_entries, &index_entry); + ctx->dirty_index_block = true; // Mark index block as dirty TRACE("Block added to index at offset %" PRIu64, index_entry.offset); // Write block header to file @@ -1872,6 +1897,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_media_tag(void *context, const uint8_t old_media_tag = NULL; } + ctx->dirty_media_tags = true; // Mark media tags as dirty TRACE("Exiting aaruf_write_media_tag() = AARUF_STATUS_OK"); return AARUF_STATUS_OK; } @@ -2155,6 +2181,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_tag(void *context, const uint64 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end) { ctx->track_entries[i].flags = data[0]; + ctx->dirty_tracks_block = true; // Mark tracks block as dirty TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK"); return AARUF_STATUS_OK; } @@ -2180,6 +2207,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_tag(void *context, const uint64 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end) { memcpy(ctx->track_entries[i].isrc, data, 12); + ctx->dirty_tracks_block = true; // Mark tracks block as dirty TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK"); return AARUF_STATUS_OK; } @@ -2212,6 +2240,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_tag(void *context, const uint64 } memcpy(ctx->sector_subchannel + corrected_sector_address * 96, data, 96); + ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK"); return AARUF_STATUS_OK; case DvdCmi: @@ -2240,6 +2269,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_tag(void *context, const uint64 } memcpy(ctx->sector_cpr_mai + corrected_sector_address * 6, data, 1); + ctx->dirty_dvd_long_sector_blocks = true; // Mark DVD long sector blocks as dirty TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK"); return AARUF_STATUS_OK; case DvdSectorInformation: @@ -2296,6 +2326,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_tag(void *context, const uint64 } memcpy(ctx->sector_id + corrected_sector_address * 4 + 1, data, 3); + ctx->dirty_dvd_long_sector_blocks = true; // Mark DVD long sector blocks as dirty TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK"); return AARUF_STATUS_OK; case DvdSectorIedAaru: @@ -2324,6 +2355,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_tag(void *context, const uint64 } memcpy(ctx->sector_ied + corrected_sector_address * 2, data, 2); + ctx->dirty_dvd_long_sector_blocks = true; // Mark DVD long sector blocks as dirty TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK"); return AARUF_STATUS_OK; case DvdSectorEdcAaru: @@ -2352,6 +2384,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_tag(void *context, const uint64 } memcpy(ctx->sector_edc + corrected_sector_address * 4, data, 4); + ctx->dirty_dvd_long_sector_blocks = true; // Mark DVD long sector blocks as dirty TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK"); return AARUF_STATUS_OK; case DvdTitleKeyDecrypted: @@ -2380,6 +2413,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_tag(void *context, const uint64 } memcpy(ctx->sector_decrypted_title_key + corrected_sector_address * 5, data, 5); + ctx->dirty_dvd_title_key_decrypted_block = true; // Mark title key block as dirty TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK"); return AARUF_STATUS_OK; case AppleSonyTagAaru: @@ -2408,6 +2442,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_tag(void *context, const uint64 } memcpy(ctx->sector_subchannel + corrected_sector_address * 12, data, 12); + ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK"); return AARUF_STATUS_OK; case AppleProfileTagAaru: @@ -2436,6 +2471,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_tag(void *context, const uint64 } memcpy(ctx->sector_subchannel + corrected_sector_address * 20, data, 20); + ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK"); return AARUF_STATUS_OK; case PriamDataTowerTagAaru: @@ -2464,6 +2500,7 @@ AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_tag(void *context, const uint64 } memcpy(ctx->sector_subchannel + corrected_sector_address * 24, data, 24); + ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK"); return AARUF_STATUS_OK; default: