81 bool has_cached_secondary_ddt =
86 TRACE(
"Writing cached secondary DDT table to file");
93 if(end_of_file & alignment_mask)
96 uint64_t aligned_position = end_of_file + alignment_mask & ~alignment_mask;
99 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
100 end_of_file = aligned_position;
102 TRACE(
"Aligned DDT write position from %ld to %" PRIu64
" (alignment shift: %d)",
103 ftell(ctx->
imageStream) - (aligned_position - end_of_file), aligned_position,
122 ddt_header.
blocks = items_per_ddt_entry;
123 ddt_header.
entries = items_per_ddt_entry;
127 ddt_header.
length = items_per_ddt_entry *
sizeof(uint64_t);
131 if(crc64_context != NULL)
137 ddt_header.
crc64 = crc64;
140 uint8_t *buffer = NULL;
150 buffer = malloc((
size_t)ddt_header.
length * 2);
153 TRACE(
"Failed to allocate memory for secondary DDT v2 compression");
157 size_t dst_size = (size_t)ddt_header.
length * 2 * 2;
164 ddt_header.
cmpLength = (uint32_t)dst_size;
193 const uint64_t new_secondary_table_block_offset =
199 TRACE(
"Updating index for cached secondary DDT");
208 for(
unsigned int k = 0; k < utarray_len(ctx->
index_entries); k++)
214 TRACE(
"Found old DDT index entry at position %u, removing", k);
225 new_ddt_entry.
offset = end_of_file;
228 TRACE(
"Added new DDT index entry at offset %" PRIu64, end_of_file);
236 size_t primary_written_bytes = 0;
239 if(primary_written_bytes != 1)
241 TRACE(
"Could not flush primary DDT table to file.");
248 TRACE(
"Failed to write cached secondary DDT data");
251 TRACE(
"Failed to write cached secondary DDT header");
288 TRACE(
"Writing cached primary DDT table back to file");
292 if(crc64_context != NULL)
312 TRACE(
"Calculated CRC64 for primary DDT: 0x%16lX", crc64);
319 if(headerWritten != 1)
321 TRACE(
"Failed to write primary DDT header to file");
329 size_t written_bytes = 0;
332 if(written_bytes == 1)
334 TRACE(
"Successfully wrote primary DDT header and table to file (%" PRIu64
" entries, %zu bytes)",
338 TRACE(
"Adding primary DDT to index");
348 TRACE(
"Failed to write primary DDT table to file");
374 TRACE(
"Writing single-level DDT table to file");
395 uint8_t *cmp_buffer = NULL;
407 if(cmp_buffer == NULL)
409 TRACE(
"Failed to allocate memory for secondary DDT v2 compression");
446 if(ddt_position & alignment_mask)
448 const uint64_t aligned_position = ddt_position + alignment_mask & ~alignment_mask;
449 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
450 ddt_position = aligned_position;
454 if(header_written != 1)
456 TRACE(
"Failed to write single-level DDT header to file");
461 size_t written_bytes = 0;
467 if(written_bytes == 1)
469 TRACE(
"Successfully wrote single-level DDT header and table to file (%" PRIu64
470 " entries, %zu bytes, %zu compressed bytes)",
474 TRACE(
"Adding single-level DDT to index");
478 single_ddt_entry.
offset = ddt_position;
481 TRACE(
"Added single-level DDT index entry at offset %" PRIu64, ddt_position);
484 TRACE(
"Failed to write single-level DDT table data to file");
601 uint64_t max_key = 0;
603 HASH_ITER(hh, ctx->
tape_ddt, entry, tmp)
604 if(entry->
key > max_key) max_key = entry->
key;
626 TRACE(
"Failed to allocate memory for tape DDT table");
631 HASH_ITER(hh, ctx->
tape_ddt, entry, tmp)
656 uint64_t alignment_mask;
657 uint64_t aligned_position;
693 if(!has_checksums)
return;
702 if(checksum_position & alignment_mask)
704 aligned_position = checksum_position + alignment_mask & ~alignment_mask;
705 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
706 checksum_position = aligned_position;
710 fseek(ctx->
imageStream,
sizeof(checksum_header), SEEK_CUR);
714 TRACE(
"Writing MD5 checksum entry");
726 TRACE(
"Writing SHA1 checksum entry");
738 TRACE(
"Writing SHA256 checksum entry");
750 TRACE(
"Writing SpamSum checksum entry");
762 TRACE(
"Writing BLAKE3 checksum entry");
764 blake3_entry.
length = BLAKE3_OUT_LEN;
773 fseek(ctx->
imageStream, checksum_position, SEEK_SET);
774 TRACE(
"Writing checksum header");
778 TRACE(
"Adding checksum block to index");
782 checksum_index_entry.
offset = checksum_position;
784 utarray_push_back(ctx->
index_entries, &checksum_index_entry);
785 TRACE(
"Added checksum block index entry at offset %" PRIu64, checksum_position);
807 if(tracks_position & alignment_mask)
809 uint64_t aligned_position = tracks_position + alignment_mask & ~alignment_mask;
810 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
811 tracks_position = aligned_position;
814 TRACE(
"Writing tracks block at position %ld", tracks_position);
819 size_t written_entries =
826 TRACE(
"Adding tracks block to index");
831 tracks_index_entry.
offset = tracks_position;
833 TRACE(
"Added tracks block index entry at offset %" PRIu64, tracks_position);
856 long mode2_subheaders_position = ftell(ctx->
imageStream);
859 if(mode2_subheaders_position & alignment_mask)
861 uint64_t aligned_position = mode2_subheaders_position + alignment_mask & ~alignment_mask;
862 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
863 mode2_subheaders_position = aligned_position;
866 TRACE(
"Writing MODE 2 subheaders block at position %ld", mode2_subheaders_position);
878 uint8_t *buffer = NULL;
888 buffer = malloc((
size_t)subheaders_block.
length * 2);
891 TRACE(
"Failed to allocate memory for MODE 2 subheaders compression");
895 size_t dst_size = (size_t)subheaders_block.
length * 2 * 2;
900 subheaders_block.
cmpLength = (uint32_t)dst_size;
927 if(written_bytes == 1)
929 TRACE(
"Successfully wrote MODE 2 subheaders block (%" PRIu64
" bytes)", subheaders_block.
cmpLength);
931 TRACE(
"Adding MODE 2 subheaders block to index");
935 mode2_subheaders_index_entry.
offset = mode2_subheaders_position;
936 utarray_push_back(ctx->
index_entries, &mode2_subheaders_index_entry);
937 TRACE(
"Added MODE 2 subheaders block index entry at offset %" PRIu64, mode2_subheaders_position);
974 if(prefix_position & alignment_mask)
976 uint64_t aligned_position = prefix_position + alignment_mask & ~alignment_mask;
977 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
978 prefix_position = aligned_position;
981 TRACE(
"Writing sector prefix block at position %ld", prefix_position);
991 uint8_t *buffer = NULL;
1001 buffer = malloc((
size_t)prefix_block.
length * 2);
1004 TRACE(
"Failed to allocate memory for CD sector prefix compression");
1008 size_t dst_size = (size_t)prefix_block.
length * 2 * 2;
1013 prefix_block.
cmpLength = (uint32_t)dst_size;
1040 if(written_bytes == 1)
1042 TRACE(
"Successfully wrote CD sector prefix block (%" PRIu64
" bytes)", prefix_block.
cmpLength);
1044 TRACE(
"Adding CD sector prefix block to index");
1048 prefix_index_entry.
offset = prefix_position;
1050 TRACE(
"Added CD sector prefix block index entry at offset %" PRIu64, prefix_position);
1096 if(suffix_position & alignment_mask)
1098 const uint64_t aligned_position = suffix_position + alignment_mask & ~alignment_mask;
1099 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
1100 suffix_position = aligned_position;
1103 TRACE(
"Writing sector suffix block at position %ld", suffix_position);
1113 uint8_t *buffer = NULL;
1123 buffer = malloc((
size_t)suffix_block.
length * 2);
1126 TRACE(
"Failed to allocate memory for CD sector suffix compression");
1130 size_t dst_size = (size_t)suffix_block.
length * 2 * 2;
1135 suffix_block.
cmpLength = (uint32_t)dst_size;
1162 if(written_bytes == 1)
1164 TRACE(
"Successfully wrote CD sector suffix block (%" PRIu64
" bytes)", suffix_block.
cmpLength);
1166 TRACE(
"Adding CD sector suffix block to index");
1170 suffix_index_entry.
offset = suffix_position;
1172 TRACE(
"Added CD sector suffix block index entry at offset %" PRIu64, suffix_position);
1211 long prefix_ddt_position = ftell(ctx->
imageStream);
1214 if(prefix_ddt_position & alignment_mask)
1216 const uint64_t aligned_position = prefix_ddt_position + alignment_mask & ~alignment_mask;
1217 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
1218 prefix_ddt_position = aligned_position;
1221 TRACE(
"Writing sector prefix DDT v2 at position %ld", prefix_ddt_position);
1236 ddt_header2.
start = 0;
1237 ddt_header2.
length = ddt_header2.
entries *
sizeof(uint64_t);
1241 uint8_t *buffer = NULL;
1251 buffer = malloc((
size_t)ddt_header2.
length * 2);
1254 TRACE(
"Failed to allocate memory for sector prefix DDT v2 compression");
1258 size_t dst_size = (size_t)ddt_header2.
length * 2 * 2;
1261 lzma_properties, &props_size, 9, ctx->
lzma_dict_size, 4, 0, 2, 273, 8);
1263 ddt_header2.
cmpLength = (uint32_t)dst_size;
1290 if(written_bytes == 1)
1292 TRACE(
"Successfully wrote sector prefix DDT v2 (%" PRIu64
" bytes)", ddt_header2.
cmpLength);
1294 TRACE(
"Adding sector prefix DDT v2 to index");
1298 prefix_ddt_index_entry.
offset = prefix_ddt_position;
1299 utarray_push_back(ctx->
index_entries, &prefix_ddt_index_entry);
1300 TRACE(
"Added sector prefix DDT v2 index entry at offset %" PRIu64, prefix_ddt_position);
1355 long suffix_ddt_position = ftell(ctx->
imageStream);
1358 if(suffix_ddt_position & alignment_mask)
1360 const uint64_t aligned_position = suffix_ddt_position + alignment_mask & ~alignment_mask;
1361 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
1362 suffix_ddt_position = aligned_position;
1365 TRACE(
"Writing sector suffix DDT v2 at position %ld", suffix_ddt_position);
1380 ddt_header2.
start = 0;
1381 ddt_header2.
length = ddt_header2.
entries *
sizeof(uint64_t);
1385 uint8_t *buffer = NULL;
1395 buffer = malloc((
size_t)ddt_header2.
length * 2);
1398 TRACE(
"Failed to allocate memory for sector suffix DDT v2 compression");
1402 size_t dst_size = (size_t)ddt_header2.
length * 2 * 2;
1405 lzma_properties, &props_size, 9, ctx->
lzma_dict_size, 4, 0, 2, 273, 8);
1407 ddt_header2.
cmpLength = (uint32_t)dst_size;
1434 if(written_bytes == 1)
1436 TRACE(
"Successfully wrote sector suffix DDT v2 (%" PRIu64
" bytes)", ddt_header2.
cmpLength);
1438 TRACE(
"Adding sector suffix DDT v2 to index");
1442 suffix_ddt_index_entry.
offset = suffix_ddt_position;
1443 utarray_push_back(ctx->
index_entries, &suffix_ddt_index_entry);
1444 TRACE(
"Added sector suffix DDT v2 index entry at offset %" PRIu64, suffix_ddt_position);
1516 if(block_position & alignment_mask)
1518 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
1519 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
1520 block_position = aligned_position;
1523 TRACE(
"Writing sector subchannel block at position %ld", block_position);
1529 bool owns_buffer =
false;
1543 uint8_t *cst_buffer = malloc(subchannel_block.
length);
1545 if(cst_buffer == NULL)
1547 TRACE(
"Failed to allocate memory for Claunia Subchannel Transform output");
1551 uint8_t *dst_buffer = malloc(subchannel_block.
length);
1553 if(dst_buffer == NULL)
1555 TRACE(
"Failed to allocate memory for LZMA output");
1561 size_t dst_size = subchannel_block.
length;
1569 if(dst_size < subchannel_block.
length)
1572 subchannel_block.
cmpLength = (uint32_t)dst_size;
1573 buffer = dst_buffer;
1603 TRACE(
"Incorrect media type, not writing sector subchannel block");
1608 uint8_t *dst_buffer = malloc(subchannel_block.
length);
1610 if(dst_buffer == NULL)
1612 TRACE(
"Failed to allocate memory for LZMA output");
1616 size_t dst_size = subchannel_block.
length;
1620 lzma_properties, &props_size, 9, ctx->
lzma_dict_size, 4, 0, 2, 273, 8);
1622 if(dst_size < subchannel_block.
length)
1624 subchannel_block.
cmpLength = (uint32_t)dst_size;
1625 buffer = dst_buffer;
1637 TRACE(
"Incorrect media type, not writing sector subchannel block");
1655 if(written_bytes == 1)
1657 TRACE(
"Successfully wrote sector subchannel block (%" PRIu64
" bytes)", subchannel_block.
cmpLength);
1659 TRACE(
"Adding sector subchannel block to index");
1662 subchannel_index_entry.
dataType = subchannel_block.
type;
1663 subchannel_index_entry.
offset = block_position;
1664 utarray_push_back(ctx->
index_entries, &subchannel_index_entry);
1665 TRACE(
"Added sector subchannel block index entry at offset %" PRIu64, block_position);
1669 if(owns_buffer) free(buffer);
1813 uint64_t total_sectors =
1820 if(id_position & alignment_mask)
1822 const uint64_t aligned_position = id_position + alignment_mask & ~alignment_mask;
1823 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
1824 id_position = aligned_position;
1826 TRACE(
"Writing DVD sector ID block at position %ld", id_position);
1831 id_block.
length = (uint32_t)total_sectors * 4;
1836 uint8_t *buffer = NULL;
1846 buffer = malloc((
size_t)id_block.
length * 2);
1849 TRACE(
"Failed to allocate memory for DVD sector ID compression");
1853 size_t dst_size = (size_t)id_block.
length * 2 * 2;
1858 id_block.
cmpLength = (uint32_t)dst_size;
1885 if(written_bytes == 1)
1887 TRACE(
"Successfully wrote DVD sector ID block (%" PRIu64
" bytes)", id_block.
cmpLength);
1889 TRACE(
"Adding DVD sector ID block to index");
1893 id_index_entry.
offset = id_position;
1895 TRACE(
"Added DVD sector ID block index entry at offset %" PRIu64, id_position);
1904 if(ied_position & alignment_mask)
1906 const uint64_t aligned_position = ied_position + alignment_mask & ~alignment_mask;
1907 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
1908 ied_position = aligned_position;
1910 TRACE(
"Writing DVD sector IED block at position %ld", ied_position);
1915 ied_block.
length = (uint32_t)total_sectors * 2;
1928 buffer = malloc((
size_t)ied_block.
length * 2);
1931 TRACE(
"Failed to allocate memory for DVD sector IED compression");
1935 size_t dst_size = (size_t)ied_block.
length * 2 * 2;
1940 ied_block.
cmpLength = (uint32_t)dst_size;
1967 if(written_bytes == 1)
1969 TRACE(
"Successfully wrote DVD sector IED block (%" PRIu64
" bytes)", ied_block.
cmpLength);
1971 TRACE(
"Adding DVD sector IED block to index");
1975 ied_index_entry.
offset = ied_position;
1977 TRACE(
"Added DVD sector IED block index entry at offset %" PRIu64, ied_position);
1986 if(cpr_mai_position & alignment_mask)
1988 const uint64_t aligned_position = cpr_mai_position + alignment_mask & ~alignment_mask;
1989 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
1990 cpr_mai_position = aligned_position;
1992 TRACE(
"Writing DVD sector CPR/MAI block at position %ld", cpr_mai_position);
1997 cpr_mai_block.
length = (uint32_t)total_sectors * 6;
2010 buffer = malloc((
size_t)cpr_mai_block.
length * 2);
2013 TRACE(
"Failed to allocate memory for DVD sector CPR/MAI compression");
2017 size_t dst_size = (size_t)cpr_mai_block.
length * 2 * 2;
2022 cpr_mai_block.
cmpLength = (uint32_t)dst_size;
2049 if(written_bytes == 1)
2051 TRACE(
"Successfully wrote DVD sector CPR/MAI block (%" PRIu64
" bytes)", cpr_mai_block.
cmpLength);
2053 TRACE(
"Adding DVD sector CPR/MAI block to index");
2057 cpr_mai_index_entry.
offset = cpr_mai_position;
2058 utarray_push_back(ctx->
index_entries, &cpr_mai_index_entry);
2059 TRACE(
"Added DVD sector CPR/MAI block index entry at offset %" PRIu64, cpr_mai_position);
2068 if(edc_position & alignment_mask)
2070 const uint64_t aligned_position = edc_position + alignment_mask & ~alignment_mask;
2071 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
2072 edc_position = aligned_position;
2074 TRACE(
"Writing DVD sector EDC block at position %ld", edc_position);
2079 edc_block.
length = (uint32_t)total_sectors * 4;
2092 buffer = malloc((
size_t)edc_block.
length * 2);
2095 TRACE(
"Failed to allocate memory for DVD sector EDC compression");
2099 size_t dst_size = (size_t)edc_block.
length * 2 * 2;
2104 edc_block.
cmpLength = (uint32_t)dst_size;
2131 if(written_bytes == 1)
2133 TRACE(
"Successfully wrote DVD sector EDC block (%" PRIu64
" bytes)", edc_block.
cmpLength);
2135 TRACE(
"Adding DVD sector EDC block to index");
2139 edc_index_entry.
offset = edc_position;
2141 TRACE(
"Added DVD sector EDC block index entry at offset %" PRIu64, edc_position);
2252 if(block_position & alignment_mask)
2254 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
2255 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
2256 block_position = aligned_position;
2258 TRACE(
"Writing DVD decrypted title key block at position %ld", block_position);
2263 decrypted_title_key_block.
length =
2267 decrypted_title_key_block.
crc64 =
2270 uint8_t *buffer = NULL;
2276 decrypted_title_key_block.
cmpCrc64 = decrypted_title_key_block.
crc64;
2280 buffer = malloc((
size_t)decrypted_title_key_block.
length * 2);
2283 TRACE(
"Failed to allocate memory for DVD decrypted title key compression");
2287 size_t dst_size = (size_t)decrypted_title_key_block.
length * 2 * 2;
2290 lzma_properties, &props_size, 9, ctx->
lzma_dict_size, 4, 0, 2, 273, 8);
2292 decrypted_title_key_block.
cmpLength = (uint32_t)dst_size;
2294 if(decrypted_title_key_block.
cmpLength >= decrypted_title_key_block.
length)
2304 decrypted_title_key_block.
cmpLength = decrypted_title_key_block.
length;
2305 decrypted_title_key_block.
cmpCrc64 = decrypted_title_key_block.
crc64;
2319 const size_t written_bytes = fwrite(buffer, decrypted_title_key_block.
cmpLength, 1, ctx->
imageStream);
2320 if(written_bytes == 1)
2322 TRACE(
"Successfully wrote DVD decrypted title key block (%" PRIu64
" bytes)",
2325 TRACE(
"Adding DVD decrypted title key block to index");
2329 decrypted_title_key_index_entry.
offset = block_position;
2330 utarray_push_back(ctx->
index_entries, &decrypted_title_key_index_entry);
2331 TRACE(
"Added DVD decrypted title key block index entry at offset %" PRIu64, block_position);
2416 HASH_ITER(hh, ctx->
mediaTags, media_tag, tmp_media_tag)
2421 if(tag_position & alignment_mask)
2423 const uint64_t aligned_position = tag_position + alignment_mask & ~alignment_mask;
2424 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
2425 tag_position = aligned_position;
2439 uint8_t *buffer = NULL;
2444 buffer = media_tag->
data;
2449 buffer = malloc((
size_t)tag_block.
length * 2);
2452 TRACE(
"Failed to allocate memory for media tag compression");
2456 size_t dst_size = (size_t)tag_block.
length * 2 * 2;
2461 tag_block.
cmpLength = (uint32_t)dst_size;
2467 buffer = media_tag->
data;
2488 if(written_bytes == 1)
2490 TRACE(
"Successfully wrote media tag block type %d (%" PRIu64
" bytes)", tag_block.
type,
2493 TRACE(
"Adding media tag type %d block to index", tag_block.
type);
2497 tag_index_entry.
offset = tag_position;
2499 TRACE(
"Added media tag block type %d index entry at offset %" PRIu64, tag_block.
type, tag_position);
2676 size_t tape_file_count = 0;
2677 HASH_ITER(hh, ctx->
tape_files, tape_file, tmp_tape_file) tape_file_count++;
2680 const size_t buffer_size = tape_file_count *
sizeof(
TapeFileEntry);
2684 TRACE(
"Failed to allocate memory for tape file entries");
2687 memset(buffer, 0, buffer_size);
2689 HASH_ITER(hh, ctx->
tape_files, tape_file, tmp_tape_file)
2691 if(index >= tape_file_count)
break;
2699 tape_file_block.
length = (uint32_t)buffer_size;
2706 if(block_position & alignment_mask)
2708 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
2709 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
2710 block_position = aligned_position;
2712 TRACE(
"Writing tape file block at position %ld", block_position);
2715 const size_t written_bytes = fwrite(buffer, tape_file_block.
length, 1, ctx->
imageStream);
2716 if(written_bytes == 1)
2718 TRACE(
"Successfully wrote tape file block (%" PRIu64
" bytes)", tape_file_block.
length);
2720 TRACE(
"Adding tape file block to index");
2724 index_entry.
offset = block_position;
2726 TRACE(
"Added tape file block index entry at offset %" PRIu64, block_position);
2908 size_t tape_partition_count = 0;
2909 HASH_ITER(hh, ctx->
tape_partitions, tape_partition, tmp_tape_partition) tape_partition_count++;
2916 TRACE(
"Failed to allocate memory for tape partition entries");
2919 memset(buffer, 0, buffer_size);
2921 HASH_ITER(hh, ctx->
tape_partitions, tape_partition, tmp_tape_partition)
2923 if(index >= tape_partition_count)
break;
2931 tape_partition_block.
length = (uint32_t)buffer_size;
2938 if(block_position & alignment_mask)
2940 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
2941 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
2942 block_position = aligned_position;
2944 TRACE(
"Writing tape partition block at position %ld", block_position);
2947 const size_t written_bytes = fwrite(buffer, tape_partition_block.
length, 1, ctx->
imageStream);
2948 if(written_bytes == 1)
2950 TRACE(
"Successfully wrote tape partition block (%" PRIu64
" bytes)", tape_partition_block.
length);
2952 TRACE(
"Adding tape partition block to index");
2956 index_entry.
offset = block_position;
2958 TRACE(
"Added tape partition block index entry at offset %" PRIu64, block_position);
3033 if(block_position & alignment_mask)
3035 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
3036 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
3037 block_position = aligned_position;
3040 TRACE(
"Writing geometry block at position %ld", block_position);
3045 TRACE(
"Successfully wrote geometry block");
3048 TRACE(
"Adding geometry block to index");
3052 index_entry.
offset = block_position;
3054 TRACE(
"Added geometry block index entry at offset %" PRIu64, block_position);
3186 if(buffer == NULL)
return;
3274 if(block_position & alignment_mask)
3276 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
3277 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
3278 block_position = aligned_position;
3281 TRACE(
"Writing metadata block at position %ld", block_position);
3285 TRACE(
"Successfully wrote metadata block");
3288 TRACE(
"Adding metadata block to index");
3292 index_entry.
offset = block_position;
3294 TRACE(
"Added metadata block index entry at offset %" PRIu64, block_position);
3454 uint8_t *buffer = calloc(1, required_length);
3456 if(buffer == NULL)
return;
3473 if(offset + entry_size > required_length)
3475 FATAL(
"Calculated size exceeds provided buffer length");
3557 if(block_position & alignment_mask)
3559 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
3560 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
3561 block_position = aligned_position;
3563 TRACE(
"Writing dump hardware block at position %ld", block_position);
3564 if(fwrite(buffer, required_length, 1, ctx->
imageStream) == 1)
3566 TRACE(
"Successfully wrote dump hardware block");
3569 TRACE(
"Adding dump hardware block to index");
3573 index_entry.
offset = block_position;
3575 TRACE(
"Added dump hardware block index entry at offset %" PRIu64, block_position);
3684 if(block_position & alignment_mask)
3686 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
3687 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
3688 block_position = aligned_position;
3691 TRACE(
"Writing CICM XML block at position %ld", block_position);
3695 TRACE(
"Successfully wrote CICM XML block");
3698 TRACE(
"Adding CICM XML block to index");
3702 index_entry.
offset = block_position;
3704 TRACE(
"Added CICM XML block index entry at offset %" PRIu64, block_position);
3822 if(block_position & alignment_mask)
3824 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
3825 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
3826 block_position = aligned_position;
3829 TRACE(
"Writing Aaru metadata JSON block at position %ld", block_position);
3833 TRACE(
"Successfully wrote Aaru metadata JSON block");
3836 TRACE(
"Adding Aaru metadata JSON block to index");
3840 index_entry.
offset = block_position;
3842 TRACE(
"Added Aaru metadata JSON block index entry at offset %" PRIu64, block_position);
3865 TRACE(
"Writing index at the end of the file");
3871 if(index_position & alignment_mask)
3873 uint64_t aligned_position = index_position + alignment_mask & ~alignment_mask;
3874 fseek(ctx->
imageStream, aligned_position, SEEK_SET);
3875 index_position = aligned_position;
3876 TRACE(
"Aligned index position to %" PRIu64, aligned_position);
3885 TRACE(
"Writing index with %" PRIu64
" entries at position %ld", index_header.
entries, index_position);
3889 if(index_crc64_context != NULL && index_header.
entries > 0)
3894 TRACE(
"Calculated index CRC64: 0x%16lX", index_header.
crc64);
3897 index_header.
crc64 = 0;
3902 TRACE(
"Successfully wrote index header");
3907 size_t entries_written = 0;
3915 TRACE(
"Wrote index entry: blockType=0x%08X dataType=%u offset=%" PRIu64, entry->
blockType,
3920 TRACE(
"Failed to write index entry %zu", entries_written);
3924 if(entries_written == index_header.
entries)
3926 TRACE(
"Successfully wrote all %zu index entries", entries_written);
3935 TRACE(
"Successfully updated header with index offset");
3938 TRACE(
"Failed to update header with index offset");
3944 TRACE(
"Failed to write all index entries (wrote %zu of %" PRIu64
")", entries_written,
3952 TRACE(
"Failed to write index header");
3997 TRACE(
"Entering aaruf_close(%p)", context);
4004 FATAL(
"Invalid context");
4014 FATAL(
"Invalid context");
4021 TRACE(
"File is writing");
4023 TRACE(
"Seeking to start of image");
4027 TRACE(
"Writing header at position 0");
4037 TRACE(
"Closing current block if any");
4127 TRACE(
"Clearing sector hash map");
4134 TRACE(
"Freeing memory pointers");
4162 TRACE(
"Freeing media tags");
4166 free(media_tag->
data);
4171 TRACE(
"Unmapping user data DDT if it is not in memory");
4239 TRACE(
"Exiting aaruf_close() = 0");
void write_dvd_long_sector_blocks(aaruformat_context *ctx)
Serialize DVD long sector auxiliary data blocks to the image file.
static int32_t write_primary_ddt(aaruformat_context *ctx)
Write (flush) the multi-level primary DDT table header and data back to its file offset.
static int32_t write_index_block(aaruformat_context *ctx)
Serialize the accumulated index entries at the end of the image and back-patch the header.
static void write_media_tags(const aaruformat_context *ctx)
Serialize all accumulated media tags to the image file.
static void write_geometry_block(const aaruformat_context *ctx)
Serialize the geometry metadata block to the image file.
int aaruf_close(void *context)
Close an Aaru image context, flushing pending data structures and releasing resources.
static int32_t write_single_level_ddt(aaruformat_context *ctx)
Serialize a single-level DDT (tableShift == 0) directly after its header.
static void write_dumphw_block(aaruformat_context *ctx)
Serialize the dump hardware block containing acquisition environment information.
static void write_tape_partition_block(const aaruformat_context *ctx)
Serialize the tape partition metadata block to the image file.
static void write_checksum_block(aaruformat_context *ctx)
Finalize any active checksum calculations and append a checksum block.
static void write_sector_suffix(aaruformat_context *ctx)
Serialize the optional CD sector suffix block (EDC/ECC region capture).
static void write_sector_suffix_ddt(aaruformat_context *ctx)
Serialize the per-sector CD suffix status / index DeDuplication Table (DDT v2, suffix variant).
static void write_tracks_block(aaruformat_context *ctx)
Serialize the tracks metadata block and add it to the index.
static void write_cicm_block(const aaruformat_context *ctx)
Serialize the CICM XML metadata block to the image file.
static void write_aaru_json_block(const aaruformat_context *ctx)
Serialize the Aaru metadata JSON block to the image file.
static void write_mode2_subheaders_block(aaruformat_context *ctx)
Serialize a MODE 2 (XA) subheaders data block.
static void write_sector_subchannel(const aaruformat_context *ctx)
Serialize the per-sector subchannel or tag data block.
static void write_sector_prefix_ddt(aaruformat_context *ctx)
Serialize the per-sector CD prefix status / index DeDuplication Table (DDT v2, prefix variant).
static int32_t write_tape_ddt(aaruformat_context *ctx)
Converts tape DDT hash table to array format and writes it as a single-level DDT.
static int32_t write_cached_secondary_ddt(aaruformat_context *ctx)
Flush a cached secondary (child) DeDuplication Table (DDT) to the image.
static void write_metadata_block(aaruformat_context *ctx)
Serialize the metadata block containing image and media descriptive information.
static void write_sector_prefix(aaruformat_context *ctx)
Serialize the optional CD sector prefix block.
static void write_dvd_title_key_decrypted_block(const aaruformat_context *ctx)
Serialize the DVD decrypted title key data block to the image file.
static void write_tape_file_block(const aaruformat_context *ctx)
Serialize the tape file metadata block to the image file.
#define LZMA_PROPERTIES_LENGTH
Size in bytes of the fixed LZMA properties header (lc/lp/pb + dictionary size).
#define AARU_MAGIC
Magic identifier for AaruFormat container (ASCII "AARUFRMT").
#define MD5_DIGEST_LENGTH
struct TapeFileHashEntry tapeFileHashEntry
void aaruf_sha1_final(sha1_ctx *ctx, unsigned char *result)
int32_t aaruf_cst_transform(const uint8_t *interleaved, uint8_t *sequential, size_t length)
Transforms interleaved subchannel data to sequential format.
int32_t aaruf_lzma_encode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer, size_t src_size, uint8_t *out_props, size_t *out_props_size, int32_t level, uint32_t dict_size, int32_t lc, int32_t lp, int32_t pb, int32_t fb, int32_t num_threads)
Encodes a buffer using LZMA compression.
uint64_t aaruf_crc64_data(const uint8_t *data, uint32_t len)
int aaruf_crc64_update(crc64_ctx *ctx, const uint8_t *data, uint32_t len)
Updates the CRC64 context with new data.
void aaruf_sha256_final(sha256_ctx *ctx, unsigned char *result)
crc64_ctx * aaruf_crc64_init()
Initializes a CRC64 context.
void aaruf_md5_final(md5_ctx *ctx, unsigned char *result)
void aaruf_spamsum_free(spamsum_ctx *ctx)
Frees a spamsum (fuzzy hash) context.
int32_t aaruf_get_datatype_for_media_tag_type(int32_t tag_type)
Converts an Aaru media tag type to an image data type.
int aaruf_spamsum_final(spamsum_ctx *ctx, uint8_t *result)
int aaruf_crc64_final(crc64_ctx *ctx, uint64_t *crc)
Computes the final CRC64 value from the context.
@ IndexBlock3
Block containing the index v3.
@ ChecksumBlock
Block containing contents checksums.
@ DataBlock
Block containing data.
@ TapePartitionBlock
Block containing list of partitions for a tape image.
@ GeometryBlock
Block containing logical geometry.
@ DeDuplicationTableSecondary
Block containing a secondary deduplication table (v2).
@ AaruMetadataJsonBlock
Block containing JSON version of Aaru Metadata.
@ CicmBlock
Block containing CICM XML metadata.
@ DeDuplicationTable2
Block containing a deduplication table v2.
@ TapeFileBlock
Block containing list of files for a tape image.
@ DumpHardwareBlock
Block containing an array of hardware used to create the image.
@ MetadataBlock
Block containing metadata.
@ TracksBlock
Block containing optical disc tracks.
@ OpticalDisc
Purely optical discs.
@ BlockMedia
Media that is physically block-based or abstracted like that.
@ SpamSum
SpamSum (context-triggered piecewise hash).
@ CdSectorSubchannel
Compact Disc subchannel data.
@ AppleProfileTag
Apple Profile (20‑byte) tag.
@ DvdSectorIed
DVD ID Error Detection Code (IED)
@ DvdSectorCprMai
DVD Copyright Management Information (CPR_MAI)
@ AppleSonyTag
Apple Sony (12‑byte) tag.
@ CdSectorPrefix
Compact Disc sector prefix (sync, header).
@ PriamDataTowerTag
Priam Data Tower (24‑byte) tag.
@ UserData
User (main) data.
@ DvdSectorEdc
DVD Error Detection Code (EDC)
@ DvdSectorTitleKeyDecrypted
Decrypted DVD Title Key.
@ DvdSectorId
DVD Identification Data (ID)
@ CdSectorSuffix
Compact Disc sector suffix (EDC, ECC P, ECC Q).
@ CompactDiscMode2Subheader
Compact Disc MODE 2 subheader.
@ AARU_FEATURE_RW_BLAKE3
BLAKE3 checksum is present (read/write support for BLAKE3 hashes).
@ AARUF_STATUS_INVALID_CONTEXT
Provided context/handle is invalid.
@ LzmaClauniaSubchannelTransform
LZMA applied to Claunia Subchannel Transform processed data.
#define AARUF_STATUS_OK
Sector present and read without uncorrectable errors.
#define AARUF_ERROR_NOT_ENOUGH_MEMORY
Memory allocation failure (critical).
#define AARUF_ERROR_CANNOT_WRITE_HEADER
Failure writing container header.
void free_map(hash_map_t *map)
Frees all memory associated with a hash map.
int32_t aaruf_close_current_block(aaruformat_context *ctx)
Finalizes and writes the current data block to the AaruFormat image file.
#define SHA1_DIGEST_LENGTH
#define SHA256_DIGEST_LENGTH
Per-checksum metadata immediately followed by the digest / signature bytes.
uint32_t length
Length in bytes of the digest that immediately follows this structure.
uint8_t type
Algorithm used (value from ChecksumAlgorithm).
uint8_t * spamsum
SpamSum fuzzy hash (ASCII), allocated length+1 with trailing 0.
bool hasSha256
True if sha256[] buffer populated.
uint8_t sha1[20]
SHA-1 digest (20 bytes).
uint8_t sha256[32]
SHA-256 digest (32 bytes).
uint8_t md5[16]
MD5 digest (16 bytes).
bool hasSpamSum
True if spamsum pointer allocated and signature read.
bool hasSha1
True if sha1[] buffer populated.
uint8_t blake3[BLAKE3_OUT_LEN]
BLAKE3 digest (32 bytes).
bool hasMd5
True if md5[] buffer populated.
bool hasBlake3
True if blake3[] buffer populated.
Inclusive [start,end] logical sector range contributed by a single hardware environment.
uint8_t * firmware
Firmware version string or NULL.
uint8_t * revision
Hardware revision string or NULL.
uint8_t * model
Model string or NULL.
uint8_t * softwareName
Dump software name or NULL.
struct DumpExtent * extents
Array of extents (entry.extents elements) or NULL.
uint8_t * manufacturer
Manufacturer string (UTF-8) or NULL.
uint8_t * softwareVersion
Dump software version or NULL.
uint8_t * serial
Serial number string or NULL.
DumpHardwareEntry entry
Fixed-size header with lengths & counts.
uint8_t * softwareOperatingSystem
Host operating system string or NULL.
Per-environment length table describing subsequent UTF-8 strings and optional extent array.
uint32_t softwareNameLength
Length in bytes of dumping software name string.
uint32_t manufacturerLength
Length in bytes of manufacturer UTF-8 string.
uint32_t softwareVersionLength
Length in bytes of dumping software version string.
uint32_t firmwareLength
Length in bytes of firmware version string.
uint32_t extents
Number of DumpExtent records following the strings (0 = none).
uint32_t modelLength
Length in bytes of model UTF-8 string.
uint32_t serialLength
Length in bytes of device serial number string.
uint32_t revisionLength
Length in bytes of revision / hardware revision string.
uint32_t softwareOperatingSystemLength
Length in bytes of host operating system string.
uint32_t MediaType
Media type identifier (see MediaType enum; 0=Unknown)
uint8_t MetadataMediaType
Media type for sidecar generation (internal archival use)
uint64_t Sectors
Total count of addressable logical sectors/blocks.
Single index entry describing a block's type, (optional) data classification, and file offset.
uint32_t blockType
Block identifier of the referenced block (value from BlockType).
uint64_t offset
Absolute byte offset in the image where the referenced block header begins.
uint16_t dataType
Data classification (value from DataType) or unused for untyped blocks.
uint64_t key
Key: sector address.
uint64_t value
Value: DDT entry.
Describes a single logical file on a tape medium.
TapeFileEntry fileEntry
The actual tape file data.
Describes a single physical partition on a tape medium.
TapePartitionEntry partitionEntry
The actual tape partition data.
Single optical disc track descriptor (sequence, type, LBAs, session, ISRC, flags).
Master context representing an open or in‑creation Aaru image.
uint8_t * media_barcode
Barcode of the media represented by the image.
DdtHeader2 user_data_ddt_header
Active user data DDT v2 header (primary table meta).
Checksums checksums
Whole-image checksums discovered.
uint8_t * creator
Who (person) created the image?
bool deduplicate
Storage deduplication active (duplicates coalesce).
bool compression_enabled
True if block compression enabled (writing path).
uint8_t * cicm_block
CICM XML payload.
uint8_t * sector_cpr_mai
DVD sector CPR_MAI (6 bytes) if present.
hash_map_t * sector_hash_map
Deduplication hash map (fingerprint->entry mapping).
uint8_t * sector_prefix_corrected
Corrected variant (post error correction) if stored.
uint64_t * user_data_ddt
Legacy flat DDT pointer (NULL when using v2 mini/big arrays).
sha256_ctx sha256_context
Opaque SHA-256 context for streaming updates.
bool calculating_sha256
True if whole-image SHA-256 being calculated on-the-fly.
uint8_t * drive_firmware_revision
Firmware revision of the drive used to read the media represented by the image.
uint8_t * media_serial_number
Serial number of the media represented by the image.
uint8_t * sector_ied
DVD sector IED (2 bytes) if present.
md5_ctx md5_context
Opaque MD5 context for streaming updates.
uint64_t * user_data_ddt2
DDT entries (big variant) primary/secondary current.
MetadataBlockHeader metadata_block_header
Metadata block header.
uint8_t * sector_prefix
Raw per-sector prefix (e.g., sync+header) uncorrected.
uint64_t * sector_suffix_ddt2
CD sector suffix DDT V2.
tapeFileHashEntry * tape_files
Hash table root for tape files.
uint64_t cached_ddt_offset
File offset of currently cached secondary DDT (0=none).
bool is_tape
True if the image is a tape image.
uint8_t * sector_edc
DVD sector EDC (4 bytes) if present.
bool calculating_sha1
True if whole-image SHA-1 being calculated on-the-fly.
uint8_t * media_model
Model of the media represented by the image.
uint8_t * drive_serial_number
Serial number of the drive used to read the media represented by the image.
CdEccContext * ecc_cd_context
CD ECC/EDC helper tables (allocated on demand).
uint32_t * sector_suffix_ddt
Legacy CD sector suffix DDT.
uint8_t * drive_manufacturer
Manufacturer of the drive used to read the media represented by the image.
bool in_memory_ddt
True if primary (and possibly secondary) DDT loaded.
uint8_t * sector_suffix
Raw per-sector suffix (EDC/ECC) uncorrected.
AaruHeaderV2 header
Parsed container header (v2).
bool is_writing
True if context opened/created for writing.
TapeDdtHashEntry * tape_ddt
Hash table root for tape DDT entries.
spamsum_ctx * spamsum_context
Opaque SpamSum context for streaming updates.
CicmMetadataBlock cicm_block_header
CICM metadata header (if present).
size_t sector_prefix_offset
Current position in sector_prefix.
uint8_t * drive_model
Model of the drive used to read the media represented by the image.
uint64_t magic
File magic (AARU_MAGIC) post-open.
uint8_t * writing_buffer
Accumulation buffer for current block data.
uint64_t * sector_prefix_ddt2
CD sector prefix DDT V2.
bool calculating_spamsum
True if whole-image SpamSum being calculated on-the-fly.
uint64_t primary_ddt_offset
File offset of the primary DDT v2 table.
mediaTagEntry * mediaTags
Hash table of extra media tags (uthash root).
blake3_hasher * blake3_context
Opaque BLAKE3 context for streaming updates.
bool calculating_blake3
True if whole-image BLAKE3 being calculated on-the-fly.
struct DumpHardwareEntriesWithData * dump_hardware_entries_with_data
Array of dump hardware entries + strings.
bool calculating_md5
True if whole-image MD5 being calculated on-the-fly.
GeometryBlockHeader geometry_block
Logical geometry block (if present).
size_t sector_suffix_offset
Current position in sector_suffix.
uint64_t * cached_secondary_ddt2
Cached secondary table (big entries) or NULL.
uint8_t * json_block
JSON metadata block payload (UTF-8).
uint8_t * media_part_number
Part number of the media represented by the image.
uint8_t * sector_decrypted_title_key
DVD decrypted title key (5 bytes) if present.
AaruMetadataJsonBlockHeader json_block_header
JSON metadata block header (if present).
uint8_t * sector_subchannel
Raw 96-byte subchannel (if captured).
uint8_t * comments
Image comments.
FILE * imageStream
Underlying FILE* stream (binary mode).
UT_array * index_entries
Flattened index entries (UT_array of IndexEntry).
uint8_t * mode2_subheaders
MODE2 Form1/Form2 8-byte subheaders (concatenated).
ImageInfo image_info
Exposed high-level image info summary.
uint8_t * sector_id
DVD sector ID (4 bytes) if present.
DumpHardwareHeader dump_hardware_header
Dump hardware header.
sha1_ctx sha1_context
Opaque SHA-1 context for streaming updates.
bool * readableSectorTags
Per-sector boolean array (optical tags read successfully?).
TapePartitionHashEntry * tape_partitions
Hash table root for tape partitions.
uint32_t * sector_prefix_ddt
Legacy CD sector prefix DDT (deprecated by *2).
uint32_t lzma_dict_size
LZMA dictionary size (writing path).
TrackEntry * track_entries
Full track list (tracksHeader.entries elements).
uint8_t * sector_suffix_corrected
Corrected suffix if stored separately.
uint8_t * metadata_block
Raw metadata UTF-16LE concatenated strings.
uint64_t cached_ddt_position
Position index of cached secondary DDT.
uint8_t * media_title
Title of the media represented by the image.
size_t mapped_memory_ddt_size
Length of mmapped DDT if userDataDdt is mmapped.
uint8_t * media_manufacturer
Manufacturer of the media represented by the image.
TracksHeader tracks_header
Tracks header (optical) if present.
Minimal ECMA-182 CRC64 incremental state container (running value only).
Hash table entry for an arbitrary media tag (e.g., proprietary drive/medium descriptor).
uint8_t * data
Tag data blob (opaque to library core); length bytes long.
int32_t type
Numeric type identifier.
uint32_t length
Length in bytes of data.