77 bool has_cached_secondary_ddt =
82 TRACE(
"Writing cached secondary DDT table to file");
89 if(end_of_file & alignment_mask)
92 uint64_t aligned_position = end_of_file + alignment_mask & ~alignment_mask;
96 end_of_file = aligned_position;
98 TRACE(
"Aligned DDT write position from %ld to %" PRIu64
" (alignment shift: %d)",
119 ddt_header.
blocks = items_per_ddt_entry;
120 ddt_header.
entries = items_per_ddt_entry;
124 ddt_header.
length = items_per_ddt_entry *
sizeof(uint64_t);
128 if(crc64_context != NULL)
134 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");
164 if(dst_size == 0) dst_size = ddt_header.
length;
168 dst_size = (size_t)ddt_header.
length * 2 * 2;
171 lzma_properties, &props_size, 9, ctx->
lzma_dict_size, 4, 0, 2, 273,
175 ddt_header.
cmpLength = (uint32_t)dst_size;
208 const uint64_t new_secondary_table_block_offset =
214 TRACE(
"Updating index for cached secondary DDT");
223 for(
unsigned int k = 0; k < utarray_len(ctx->
index_entries); k++)
230 TRACE(
"Found old DDT index entry at position %u, removing", k);
241 new_ddt_entry.
offset = end_of_file;
245 TRACE(
"Added new DDT index entry at offset %" PRIu64, end_of_file);
253 size_t primary_written_bytes = 0;
256 if(primary_written_bytes != 1)
258 TRACE(
"Could not flush primary DDT table to file.");
265 TRACE(
"Failed to write cached secondary DDT data");
268 TRACE(
"Failed to write cached secondary DDT header");
308 TRACE(
"Writing cached primary DDT table back to file");
312 if(crc64_context != NULL)
332 TRACE(
"Calculated CRC64 for primary DDT: 0x%16lX", crc64);
342 if(headerWritten != 1)
344 TRACE(
"Failed to write primary DDT header to file");
352 size_t written_bytes = 0;
355 if(written_bytes == 1)
357 TRACE(
"Successfully wrote primary DDT header and table to file (%" PRIu64
" entries, %zu bytes)",
361 TRACE(
"Removing any previously existing primary DDT index entries");
362 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
367 TRACE(
"Found existing primary DDT index entry at position %d, removing", k);
373 TRACE(
"Adding primary DDT to index");
384 TRACE(
"Failed to write primary DDT table to file");
413 TRACE(
"Writing single-level DDT table to file");
435 uint8_t *cmp_buffer = NULL;
447 if(cmp_buffer == NULL)
449 TRACE(
"Failed to allocate memory for secondary DDT v2 compression");
502 if(ddt_position & alignment_mask)
504 const uint64_t aligned_position = ddt_position + alignment_mask & ~alignment_mask;
506 ddt_position = aligned_position;
510 if(header_written != 1)
512 TRACE(
"Failed to write single-level DDT header to file");
517 size_t written_bytes = 0;
523 if(written_bytes == 1)
525 TRACE(
"Successfully wrote single-level DDT header and table to file (%" PRIu64
526 " entries, %zu bytes, %zu compressed bytes)",
530 TRACE(
"Removing any previously existing single-level DDT index entries");
531 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
536 TRACE(
"Found existing single-level DDT index entry at position %d, removing", k);
542 TRACE(
"Adding single-level DDT to index");
546 single_ddt_entry.
offset = ddt_position;
550 TRACE(
"Added single-level DDT index entry at offset %" PRIu64, ddt_position);
553 TRACE(
"Failed to write single-level DDT table data to file");
677 uint64_t max_key = 0;
679 HASH_ITER(hh, ctx->
tape_ddt, entry, tmp)
680 if(entry->
key > max_key) max_key = entry->
key;
703 TRACE(
"Failed to allocate memory for tape DDT table");
708 HASH_ITER(hh, ctx->
tape_ddt, entry, tmp)
733 uint64_t alignment_mask;
734 uint64_t aligned_position;
770 if(!has_checksums)
return;
779 if(checksum_position & alignment_mask)
781 aligned_position = checksum_position + alignment_mask & ~alignment_mask;
783 checksum_position = aligned_position;
791 TRACE(
"Writing MD5 checksum entry");
803 TRACE(
"Writing SHA1 checksum entry");
815 TRACE(
"Writing SHA256 checksum entry");
827 TRACE(
"Writing SpamSum checksum entry");
839 TRACE(
"Writing BLAKE3 checksum entry");
841 blake3_entry.
length = BLAKE3_OUT_LEN;
851 TRACE(
"Writing checksum header");
855 TRACE(
"Removing any previously existing checksum block index entries");
856 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
861 TRACE(
"Found existing checksum block index entry at position %d, removing", k);
867 TRACE(
"Adding checksum block to index");
871 checksum_index_entry.
offset = checksum_position;
873 utarray_push_back(ctx->
index_entries, &checksum_index_entry);
875 TRACE(
"Added checksum block index entry at offset %" PRIu64, checksum_position);
897 if(tracks_position & alignment_mask)
899 uint64_t aligned_position = tracks_position + alignment_mask & ~alignment_mask;
901 tracks_position = aligned_position;
904 TRACE(
"Writing tracks block at position %ld", tracks_position);
909 size_t written_entries =
917 TRACE(
"Removing any previously existing tracks block index entries");
918 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
923 TRACE(
"Found existing tracks block index entry at position %d, removing", k);
929 TRACE(
"Adding tracks block to index");
934 tracks_index_entry.
offset = tracks_position;
937 TRACE(
"Added tracks block index entry at offset %" PRIu64, tracks_position);
963 if(mode2_subheaders_position & alignment_mask)
965 uint64_t aligned_position = mode2_subheaders_position + alignment_mask & ~alignment_mask;
967 mode2_subheaders_position = aligned_position;
970 TRACE(
"Writing MODE 2 subheaders block at position %ld", mode2_subheaders_position);
983 uint8_t *buffer = NULL;
993 buffer = malloc((
size_t)subheaders_block.
length * 2);
996 TRACE(
"Failed to allocate memory for MODE 2 subheaders compression");
1006 if(dst_size == 0) dst_size = subheaders_block.
length;
1010 dst_size = (size_t)subheaders_block.
length * 2 * 2;
1016 subheaders_block.
cmpLength = (uint32_t)dst_size;
1037 const size_t length_to_write = subheaders_block.
cmpLength;
1047 const size_t written_bytes = fwrite(buffer, length_to_write, 1, ctx->
imageStream);
1048 if(written_bytes == 1)
1050 TRACE(
"Successfully wrote MODE 2 subheaders block (%" PRIu64
" bytes)", subheaders_block.
cmpLength);
1053 TRACE(
"Removing any previously existing MODE 2 subheaders block index entries");
1054 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
1059 TRACE(
"Found existing MODE 2 subheaders block index entry at position %d, removing", k);
1065 TRACE(
"Adding MODE 2 subheaders block to index");
1069 mode2_subheaders_index_entry.
offset = mode2_subheaders_position;
1070 utarray_push_back(ctx->
index_entries, &mode2_subheaders_index_entry);
1072 TRACE(
"Added MODE 2 subheaders block index entry at offset %" PRIu64, mode2_subheaders_position);
1109 if(prefix_position & alignment_mask)
1111 uint64_t aligned_position = prefix_position + alignment_mask & ~alignment_mask;
1113 prefix_position = aligned_position;
1116 TRACE(
"Writing sector prefix block at position %ld", prefix_position);
1127 uint8_t *buffer = NULL;
1137 buffer = malloc((
size_t)prefix_block.
length * 2);
1140 TRACE(
"Failed to allocate memory for CD sector prefix compression");
1150 if(dst_size == 0) dst_size = prefix_block.
length;
1154 dst_size = (size_t)prefix_block.
length * 2 * 2;
1160 prefix_block.
cmpLength = (uint32_t)dst_size;
1181 const size_t length_to_write = prefix_block.
cmpLength;
1191 const size_t written_bytes = fwrite(buffer, length_to_write, 1, ctx->
imageStream);
1192 if(written_bytes == 1)
1194 TRACE(
"Successfully wrote CD sector prefix block (%" PRIu64
" bytes)", prefix_block.
cmpLength);
1197 TRACE(
"Removing any previously existing CD sector prefix block index entries");
1198 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
1203 TRACE(
"Found existing CD sector prefix block index entry at position %d, removing", k);
1209 TRACE(
"Adding CD sector prefix block to index");
1213 prefix_index_entry.
offset = prefix_position;
1216 TRACE(
"Added CD sector prefix block index entry at offset %" PRIu64, prefix_position);
1262 if(suffix_position & alignment_mask)
1264 const uint64_t aligned_position = suffix_position + alignment_mask & ~alignment_mask;
1266 suffix_position = aligned_position;
1269 TRACE(
"Writing sector suffix block at position %ld", suffix_position);
1280 uint8_t *buffer = NULL;
1290 buffer = malloc((
size_t)suffix_block.
length * 2);
1293 TRACE(
"Failed to allocate memory for CD sector suffix compression");
1303 if(dst_size == 0) dst_size = suffix_block.
length;
1307 dst_size = (size_t)suffix_block.
length * 2 * 2;
1313 suffix_block.
cmpLength = (uint32_t)dst_size;
1334 const size_t length_to_write = suffix_block.
cmpLength;
1344 const size_t written_bytes = fwrite(buffer, length_to_write, 1, ctx->
imageStream);
1345 if(written_bytes == 1)
1347 TRACE(
"Successfully wrote CD sector suffix block (%" PRIu64
" bytes)", suffix_block.
cmpLength);
1350 TRACE(
"Removing any previously existing CD sector suffix block index entries");
1351 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
1356 TRACE(
"Found existing CD sector suffix block index entry at position %d, removing", k);
1362 TRACE(
"Adding CD sector suffix block to index");
1366 suffix_index_entry.
offset = suffix_position;
1369 TRACE(
"Added CD sector suffix block index entry at offset %" PRIu64, suffix_position);
1411 if(prefix_ddt_position & alignment_mask)
1413 const uint64_t aligned_position = prefix_ddt_position + alignment_mask & ~alignment_mask;
1415 prefix_ddt_position = aligned_position;
1418 TRACE(
"Writing sector prefix DDT v2 at position %ld", prefix_ddt_position);
1434 ddt_header2.
start = 0;
1435 ddt_header2.
length = ddt_header2.
entries *
sizeof(uint64_t);
1439 uint8_t *buffer = NULL;
1449 buffer = malloc((
size_t)ddt_header2.
length * 2);
1452 TRACE(
"Failed to allocate memory for sector prefix DDT v2 compression");
1463 if(dst_size == 0) dst_size = ddt_header2.
length;
1467 dst_size = (size_t)ddt_header2.
length * 2 * 2;
1470 lzma_properties, &props_size, 9, ctx->
lzma_dict_size, 4, 0, 2, 273,
1474 ddt_header2.
cmpLength = (uint32_t)dst_size;
1495 const size_t length_to_write = ddt_header2.
cmpLength;
1505 const size_t written_bytes = fwrite(buffer, length_to_write, 1, ctx->
imageStream);
1506 if(written_bytes == 1)
1508 TRACE(
"Successfully wrote sector prefix DDT v2 (%" PRIu64
" bytes)", ddt_header2.
cmpLength);
1511 TRACE(
"Removing any previously existing sector prefix DDT v2 index entries");
1512 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
1517 TRACE(
"Found existing sector prefix DDT v2 index entry at position %d, removing", k);
1523 TRACE(
"Adding sector prefix DDT v2 to index");
1527 prefix_ddt_index_entry.
offset = prefix_ddt_position;
1528 utarray_push_back(ctx->
index_entries, &prefix_ddt_index_entry);
1530 TRACE(
"Added sector prefix DDT v2 index entry at offset %" PRIu64, prefix_ddt_position);
1588 if(suffix_ddt_position & alignment_mask)
1590 const uint64_t aligned_position = suffix_ddt_position + alignment_mask & ~alignment_mask;
1592 suffix_ddt_position = aligned_position;
1595 TRACE(
"Writing sector suffix DDT v2 at position %ld", suffix_ddt_position);
1611 ddt_header2.
start = 0;
1612 ddt_header2.
length = ddt_header2.
entries *
sizeof(uint64_t);
1616 uint8_t *buffer = NULL;
1626 buffer = malloc((
size_t)ddt_header2.
length * 2);
1629 TRACE(
"Failed to allocate memory for sector suffix DDT v2 compression");
1640 if(dst_size == 0) dst_size = ddt_header2.
length;
1644 dst_size = (size_t)ddt_header2.
length * 2 * 2;
1647 lzma_properties, &props_size, 9, ctx->
lzma_dict_size, 4, 0, 2, 273,
1651 ddt_header2.
cmpLength = (uint32_t)dst_size;
1672 const size_t length_to_write = ddt_header2.
cmpLength;
1682 const size_t written_bytes = fwrite(buffer, length_to_write, 1, ctx->
imageStream);
1683 if(written_bytes == 1)
1685 TRACE(
"Successfully wrote sector suffix DDT v2 (%" PRIu64
" bytes)", ddt_header2.
cmpLength);
1688 TRACE(
"Removing any previously existing sector suffix DDT v2 block index entries");
1689 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
1694 TRACE(
"Found existing sector suffix DDT v2 index entry at position %d, removing", k);
1700 TRACE(
"Adding sector suffix DDT v2 to index");
1704 suffix_ddt_index_entry.
offset = suffix_ddt_position;
1705 utarray_push_back(ctx->
index_entries, &suffix_ddt_index_entry);
1707 TRACE(
"Added sector suffix DDT v2 index entry at offset %" PRIu64, suffix_ddt_position);
1779 if(block_position & alignment_mask)
1781 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
1783 block_position = aligned_position;
1786 TRACE(
"Writing sector subchannel block at position %ld", block_position);
1792 bool owns_buffer =
false;
1805 uint8_t *cst_buffer = malloc(subchannel_block.
length);
1807 if(cst_buffer == NULL)
1809 TRACE(
"Failed to allocate memory for Claunia Subchannel Transform output");
1813 uint8_t *dst_buffer = malloc(subchannel_block.
length);
1815 if(dst_buffer == NULL)
1817 TRACE(
"Failed to allocate memory for compressed output");
1830 if(dst_size == 0) dst_size = subchannel_block.
length;
1834 dst_size = subchannel_block.
length;
1843 if(dst_size < subchannel_block.
length)
1846 subchannel_block.
cmpLength = (uint32_t)dst_size;
1847 buffer = dst_buffer;
1877 TRACE(
"Incorrect media type, not writing sector subchannel block");
1882 uint8_t *dst_buffer = malloc(subchannel_block.
length);
1884 if(dst_buffer == NULL)
1886 TRACE(
"Failed to allocate memory for compressed output");
1896 if(dst_size == 0) dst_size = subchannel_block.
length;
1900 dst_size = subchannel_block.
length;
1907 if(dst_size < subchannel_block.
length)
1910 subchannel_block.
cmpLength = (uint32_t)dst_size;
1911 buffer = dst_buffer;
1923 TRACE(
"Incorrect media type, not writing sector subchannel block");
1937 const size_t length_to_write = subchannel_block.
cmpLength;
1949 const size_t written_bytes = fwrite(buffer, length_to_write, 1, ctx->
imageStream);
1950 if(written_bytes == 1)
1952 TRACE(
"Successfully wrote sector subchannel block (%" PRIu64
" bytes)", subchannel_block.
cmpLength);
1955 TRACE(
"Removing any previously existing subchannel block index entries");
1956 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
1961 TRACE(
"Found existing subchannel block index entry at position %d, removing", k);
1967 TRACE(
"Adding sector subchannel block to index");
1970 subchannel_index_entry.
dataType = subchannel_block.
type;
1971 subchannel_index_entry.
offset = block_position;
1972 utarray_push_back(ctx->
index_entries, &subchannel_index_entry);
1974 TRACE(
"Added sector subchannel block index entry at offset %" PRIu64, block_position);
1978 if(owns_buffer) free(buffer);
2122 uint64_t total_sectors =
2129 if(id_position & alignment_mask)
2131 const uint64_t aligned_position = id_position + alignment_mask & ~alignment_mask;
2133 id_position = aligned_position;
2135 TRACE(
"Writing DVD sector ID block at position %ld", id_position);
2141 id_block.
length = (uint32_t)total_sectors * 4;
2146 uint8_t *buffer = NULL;
2156 buffer = malloc((
size_t)id_block.
length * 2);
2159 TRACE(
"Failed to allocate memory for DVD sector ID compression");
2169 if(dst_size == 0) dst_size = id_block.
length;
2173 dst_size = (size_t)id_block.
length * 2 * 2;
2179 id_block.
cmpLength = (uint32_t)dst_size;
2200 size_t length_to_write = id_block.
cmpLength;
2210 const size_t written_bytes = fwrite(buffer, length_to_write, 1, ctx->
imageStream);
2211 if(written_bytes == 1)
2213 TRACE(
"Successfully wrote DVD sector ID block (%" PRIu64
" bytes)", id_block.
cmpLength);
2216 TRACE(
"Removing any previously existing DVD sector ID block index entries");
2217 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
2222 TRACE(
"Found existing DVD sector ID block index entry at position %d, removing", k);
2228 TRACE(
"Adding DVD sector ID block to index");
2232 id_index_entry.
offset = id_position;
2235 TRACE(
"Added DVD sector ID block index entry at offset %" PRIu64, id_position);
2244 if(ied_position & alignment_mask)
2246 const uint64_t aligned_position = ied_position + alignment_mask & ~alignment_mask;
2248 ied_position = aligned_position;
2250 TRACE(
"Writing DVD sector IED block at position %ld", ied_position);
2256 ied_block.
length = (uint32_t)total_sectors * 2;
2269 buffer = malloc((
size_t)ied_block.
length * 2);
2272 TRACE(
"Failed to allocate memory for DVD sector IED compression");
2282 if(dst_size == 0) dst_size = ied_block.
length;
2286 dst_size = (size_t)ied_block.
length * 2 * 2;
2292 ied_block.
cmpLength = (uint32_t)dst_size;
2323 const size_t written_bytes = fwrite(buffer, length_to_write, 1, ctx->
imageStream);
2324 if(written_bytes == 1)
2326 TRACE(
"Successfully wrote DVD sector IED block (%" PRIu64
" bytes)", ied_block.
cmpLength);
2329 TRACE(
"Removing any previously existing DVD sector IED block index entries");
2330 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
2335 TRACE(
"Found existing DVD sector IED block index entry at position %d, removing", k);
2341 TRACE(
"Adding DVD sector IED block to index");
2345 ied_index_entry.
offset = ied_position;
2348 TRACE(
"Added DVD sector IED block index entry at offset %" PRIu64, ied_position);
2357 if(cpr_mai_position & alignment_mask)
2359 const uint64_t aligned_position = cpr_mai_position + alignment_mask & ~alignment_mask;
2361 cpr_mai_position = aligned_position;
2363 TRACE(
"Writing DVD sector CPR/MAI block at position %ld", cpr_mai_position);
2369 cpr_mai_block.
length = (uint32_t)total_sectors * 6;
2382 buffer = malloc((
size_t)cpr_mai_block.
length * 2);
2385 TRACE(
"Failed to allocate memory for DVD sector CPR/MAI compression");
2395 if(dst_size == 0) dst_size = cpr_mai_block.
length;
2399 dst_size = (size_t)cpr_mai_block.
length * 2 * 2;
2405 cpr_mai_block.
cmpLength = (uint32_t)dst_size;
2426 length_to_write = cpr_mai_block.
cmpLength;
2436 const size_t written_bytes = fwrite(buffer, length_to_write, 1, ctx->
imageStream);
2437 if(written_bytes == 1)
2439 TRACE(
"Successfully wrote DVD sector CPR/MAI block (%" PRIu64
" bytes)", cpr_mai_block.
cmpLength);
2442 TRACE(
"Removing any previously existing DVD sector CPR/MAI block index entries");
2443 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
2448 TRACE(
"Found existing DVD sector CPR/MAI block index entry at position %d, removing", k);
2454 TRACE(
"Adding DVD sector CPR/MAI block to index");
2458 cpr_mai_index_entry.
offset = cpr_mai_position;
2459 utarray_push_back(ctx->
index_entries, &cpr_mai_index_entry);
2461 TRACE(
"Added DVD sector CPR/MAI block index entry at offset %" PRIu64, cpr_mai_position);
2470 if(edc_position & alignment_mask)
2472 const uint64_t aligned_position = edc_position + alignment_mask & ~alignment_mask;
2474 edc_position = aligned_position;
2476 TRACE(
"Writing DVD sector EDC block at position %ld", edc_position);
2482 edc_block.
length = (uint32_t)total_sectors * 4;
2495 buffer = malloc((
size_t)edc_block.
length * 2);
2498 TRACE(
"Failed to allocate memory for DVD sector EDC compression");
2508 if(dst_size == 0) dst_size = edc_block.
length;
2512 dst_size = (size_t)edc_block.
length * 2 * 2;
2518 edc_block.
cmpLength = (uint32_t)dst_size;
2549 const size_t written_bytes = fwrite(buffer, length_to_write, 1, ctx->
imageStream);
2550 if(written_bytes == 1)
2552 TRACE(
"Successfully wrote DVD sector EDC block (%" PRIu64
" bytes)", edc_block.
cmpLength);
2555 TRACE(
"Removing any previously existing DVD sector EDC block index entries");
2556 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
2561 TRACE(
"Found existing DVD sector EDC block index entry at position %d, removing", k);
2567 TRACE(
"Adding DVD sector EDC block to index");
2571 edc_index_entry.
offset = edc_position;
2574 TRACE(
"Added DVD sector EDC block index entry at offset %" PRIu64, edc_position);
2681 uint64_t total_sectors =
2688 if(edc_position & alignment_mask)
2690 const uint64_t aligned_position = edc_position + alignment_mask & ~alignment_mask;
2692 edc_position = aligned_position;
2694 TRACE(
"Writing BD sector EDC block at position %ld", edc_position);
2700 edc_block.
length = (uint32_t)total_sectors * 4;
2703 uint8_t *buffer = NULL;
2713 buffer = malloc((
size_t)edc_block.
length * 2);
2716 TRACE(
"Failed to allocate memory for BD sector EDC compression");
2726 if(dst_size == 0) dst_size = edc_block.
length;
2730 dst_size = (size_t)edc_block.
length * 2 * 2;
2736 edc_block.
cmpLength = (uint32_t)dst_size;
2757 size_t length_to_write = edc_block.
cmpLength;
2765 const size_t written_bytes = fwrite(buffer, length_to_write, 1, ctx->
imageStream);
2766 if(written_bytes == 1)
2768 TRACE(
"Successfully wrote BD sector EDC block (%" PRIu64
" bytes)", edc_block.
cmpLength);
2770 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
2775 TRACE(
"Found existing BD sector EDC block index entry at position %d, removing", k);
2783 edc_index_entry.
offset = edc_position;
2786 TRACE(
"Added BD sector EDC block index entry at offset %" PRIu64, edc_position);
2897 if(block_position & alignment_mask)
2899 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
2901 block_position = aligned_position;
2903 TRACE(
"Writing DVD decrypted title key block at position %ld", block_position);
2909 decrypted_title_key_block.
length =
2913 decrypted_title_key_block.
crc64 =
2916 uint8_t *buffer = NULL;
2922 decrypted_title_key_block.
cmpCrc64 = decrypted_title_key_block.
crc64;
2926 buffer = malloc((
size_t)decrypted_title_key_block.
length * 2);
2929 TRACE(
"Failed to allocate memory for DVD decrypted title key compression");
2940 if(dst_size == 0) dst_size = decrypted_title_key_block.
length;
2944 dst_size = (size_t)decrypted_title_key_block.
length * 2 * 2;
2947 decrypted_title_key_block.
length, lzma_properties, &props_size, 9,
2951 decrypted_title_key_block.
cmpLength = (uint32_t)dst_size;
2953 if(decrypted_title_key_block.
cmpLength >= decrypted_title_key_block.
length)
2963 decrypted_title_key_block.
cmpLength = decrypted_title_key_block.
length;
2964 decrypted_title_key_block.
cmpCrc64 = decrypted_title_key_block.
crc64;
2972 const size_t length_to_write = decrypted_title_key_block.
cmpLength;
2983 const size_t written_bytes = fwrite(buffer, length_to_write, 1, ctx->
imageStream);
2984 if(written_bytes == 1)
2986 TRACE(
"Successfully wrote DVD decrypted title key block (%" PRIu64
" bytes)",
2990 TRACE(
"Removing any previously existing DVD decrypted title key block index entries");
2991 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
2996 TRACE(
"Found existing DVD decrypted title key block index entry at position %d, removing", k);
3002 TRACE(
"Adding DVD decrypted title key block to index");
3006 decrypted_title_key_index_entry.
offset = block_position;
3007 utarray_push_back(ctx->
index_entries, &decrypted_title_key_index_entry);
3009 TRACE(
"Added DVD decrypted title key block index entry at offset %" PRIu64, block_position);
3094 HASH_ITER(hh, ctx->
mediaTags, media_tag, tmp_media_tag)
3099 if(tag_position & alignment_mask)
3101 const uint64_t aligned_position = tag_position + alignment_mask & ~alignment_mask;
3103 tag_position = aligned_position;
3118 uint8_t *buffer = NULL;
3123 buffer = media_tag->
data;
3128 buffer = malloc((
size_t)tag_block.
length * 2);
3131 TRACE(
"Failed to allocate memory for media tag compression");
3141 if(dst_size == 0) dst_size = tag_block.
length;
3145 dst_size = (size_t)tag_block.
length * 2 * 2;
3151 tag_block.
cmpLength = (uint32_t)dst_size;
3157 buffer = media_tag->
data;
3172 const size_t length_to_write = tag_block.
cmpLength;
3181 const size_t written_bytes = fwrite(buffer, length_to_write, 1, ctx->
imageStream);
3182 if(written_bytes == 1)
3184 TRACE(
"Successfully wrote media tag block type %d (%" PRIu64
" bytes)", tag_block.
type,
3188 TRACE(
"Removing any previously existing media tag type %d block index entries", tag_block.
type);
3189 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
3194 TRACE(
"Found existing media tag type %d block index entry at position %d, removing",
3201 TRACE(
"Adding media tag type %d block to index", tag_block.
type);
3205 tag_index_entry.
offset = tag_position;
3208 TRACE(
"Added media tag block type %d index entry at offset %" PRIu64, tag_block.
type, tag_position);
3385 size_t tape_file_count = 0;
3386 HASH_ITER(hh, ctx->
tape_files, tape_file, tmp_tape_file) tape_file_count++;
3389 const size_t buffer_size = tape_file_count *
sizeof(
TapeFileEntry);
3393 TRACE(
"Failed to allocate memory for tape file entries");
3396 memset(buffer, 0, buffer_size);
3398 HASH_ITER(hh, ctx->
tape_files, tape_file, tmp_tape_file)
3400 if(index >= tape_file_count)
break;
3408 tape_file_block.
length = (uint32_t)buffer_size;
3415 if(block_position & alignment_mask)
3417 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
3419 block_position = aligned_position;
3421 TRACE(
"Writing tape file block at position %ld", block_position);
3424 const size_t written_bytes = fwrite(buffer, tape_file_block.
length, 1, ctx->
imageStream);
3425 if(written_bytes == 1)
3427 TRACE(
"Successfully wrote tape file block (%" PRIu64
" bytes)", tape_file_block.
length);
3430 TRACE(
"Removing any previously existing tape file block index entries");
3431 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
3436 TRACE(
"Found existing tape file block index entry at position %d, removing", k);
3442 TRACE(
"Adding tape file block to index");
3446 index_entry.
offset = block_position;
3449 TRACE(
"Added tape file block index entry at offset %" PRIu64, block_position);
3631 size_t tape_partition_count = 0;
3632 HASH_ITER(hh, ctx->
tape_partitions, tape_partition, tmp_tape_partition) tape_partition_count++;
3639 TRACE(
"Failed to allocate memory for tape partition entries");
3642 memset(buffer, 0, buffer_size);
3644 HASH_ITER(hh, ctx->
tape_partitions, tape_partition, tmp_tape_partition)
3646 if(index >= tape_partition_count)
break;
3654 tape_partition_block.
length = (uint32_t)buffer_size;
3661 if(block_position & alignment_mask)
3663 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
3665 block_position = aligned_position;
3667 TRACE(
"Writing tape partition block at position %ld", block_position);
3670 const size_t written_bytes = fwrite(buffer, tape_partition_block.
length, 1, ctx->
imageStream);
3671 if(written_bytes == 1)
3673 TRACE(
"Successfully wrote tape partition block (%" PRIu64
" bytes)", tape_partition_block.
length);
3676 TRACE(
"Removing any previously existing tape partition block index entries");
3677 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
3682 TRACE(
"Found existing tape partition block index entry at position %d, removing", k);
3688 TRACE(
"Adding tape partition block to index");
3692 index_entry.
offset = block_position;
3695 TRACE(
"Added tape partition block index entry at offset %" PRIu64, block_position);
3770 if(block_position & alignment_mask)
3772 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
3774 block_position = aligned_position;
3777 TRACE(
"Writing geometry block at position %ld", block_position);
3782 TRACE(
"Successfully wrote geometry block");
3785 TRACE(
"Removing any previously existing geometry block index entries");
3786 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
3791 TRACE(
"Found existing geometry block index entry at position %d, removing", k);
3797 TRACE(
"Adding geometry block to index");
3801 index_entry.
offset = block_position;
3804 TRACE(
"Added geometry block index entry at offset %" PRIu64, block_position);
3936 if(buffer == NULL)
return;
4024 if(block_position & alignment_mask)
4026 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
4028 block_position = aligned_position;
4033 TRACE(
"Writing metadata block at position %ld", block_position);
4037 TRACE(
"Successfully wrote metadata block");
4040 TRACE(
"Removing any previously existing metadata block index entries");
4041 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
4046 TRACE(
"Found existing metadata block index entry at position %d, removing", k);
4052 TRACE(
"Adding metadata block to index");
4056 index_entry.
offset = block_position;
4059 TRACE(
"Added metadata block index entry at offset %" PRIu64, block_position);
4219 uint8_t *buffer = calloc(1, required_length);
4221 if(buffer == NULL)
return;
4238 if(offset + entry_size > required_length)
4240 FATAL(
"Calculated size exceeds provided buffer length");
4322 if(block_position & alignment_mask)
4324 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
4326 block_position = aligned_position;
4328 TRACE(
"Writing dump hardware block at position %ld", block_position);
4329 if(fwrite(buffer, required_length, 1, ctx->
imageStream) == 1)
4331 TRACE(
"Successfully wrote dump hardware block");
4334 TRACE(
"Removing any previously existing dump hardware block index entries");
4335 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
4340 TRACE(
"Found existing dump hardware block index entry at position %d, removing", k);
4346 TRACE(
"Adding dump hardware block to index");
4350 index_entry.
offset = block_position;
4353 TRACE(
"Added dump hardware block index entry at offset %" PRIu64, block_position);
4462 if(block_position & alignment_mask)
4464 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
4466 block_position = aligned_position;
4469 TRACE(
"Writing CICM XML block at position %ld", block_position);
4473 TRACE(
"Successfully wrote CICM XML block");
4476 TRACE(
"Removing any previously existing CICM XML block index entries");
4477 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
4482 TRACE(
"Found existing CICM XML block index entry at position %d, removing", k);
4488 TRACE(
"Adding CICM XML block to index");
4492 index_entry.
offset = block_position;
4495 TRACE(
"Added CICM XML block index entry at offset %" PRIu64, block_position);
4613 if(block_position & alignment_mask)
4615 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
4617 block_position = aligned_position;
4620 TRACE(
"Writing Aaru metadata JSON block at position %ld", block_position);
4624 TRACE(
"Successfully wrote Aaru metadata JSON block");
4627 TRACE(
"Removing any previously existing Aaru metadata JSON block index entries");
4628 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
4633 TRACE(
"Found existing Aaru metadata JSON block index entry at position %d, removing", k);
4639 TRACE(
"Adding Aaru metadata JSON block to index");
4643 index_entry.
offset = block_position;
4646 TRACE(
"Added Aaru metadata JSON block index entry at offset %" PRIu64, block_position);
4659 for(
int k = utarray_len(ctx->
index_entries) - 1; k >= 0; k--)
4665 TRACE(
"Found existing DPM block index entry at position %d, removing", k);
4687 TRACE(
"No DPM to write, removing any previous DPM block from the index");
4697 if(block_position & alignment_mask)
4699 const uint64_t aligned_position = block_position + alignment_mask & ~alignment_mask;
4701 block_position = aligned_position;
4704 TRACE(
"Writing DPM block at position %" PRId64, (int64_t)block_position);
4708 TRACE(
"Could not write DPM block");
4718 index_entry.
offset = block_position;
4721 TRACE(
"Added DPM block index entry at offset %" PRIu64, (uint64_t)block_position);
4911 uint64_t raw_length = data_length + index_length;
4913 if(raw_length > UINT32_MAX)
4915 FATAL(
"Flux capture raw length exceeds 32-bit limit (%" PRIu64
")", raw_length);
4919 uint8_t *raw_buffer = NULL;
4922 raw_buffer = malloc(raw_length);
4923 if(raw_buffer == NULL)
4925 FATAL(
"Could not allocate %" PRIu64
" bytes for flux serialization", raw_length);
4929 if(data_length != 0 && record->
data_buffer != NULL) memcpy(raw_buffer, record->
data_buffer, data_length);
4931 memcpy(raw_buffer + data_length, record->
index_buffer, index_length);
4934 uint64_t raw_crc = raw_length != 0 && raw_buffer != NULL ?
aaruf_crc64_data(raw_buffer, raw_length) : 0;
4939 uint8_t *compressed_buffer = NULL;
4940 uint32_t cmp_length = 0;
4941 uint64_t cmp_crc = 0;
4948 uint8_t *cmp_stream = malloc(cmp_capacity);
4949 if(cmp_stream == NULL)
4952 FATAL(
"Could not allocate %zu bytes for LZMA flux compression", cmp_capacity);
4956 size_t dst_size = cmp_capacity;
4964 TRACE(
"Flux capture compression fell back to uncompressed (err=%d, dst=%zu, raw=%" PRIu64
")", error_no,
4965 dst_size, raw_length);
4972 compressed_buffer = malloc(cmp_length);
4973 if(compressed_buffer == NULL)
4977 FATAL(
"Could not allocate %u bytes for flux compressed payload", cmp_length);
4991 size_t cmp_capacity = raw_length ? raw_length * 2 + 65536 : 16;
4993 uint8_t *cmp_stream = malloc(cmp_capacity);
4994 if(cmp_stream == NULL)
4997 FATAL(
"Could not allocate %zu bytes for zstd flux compression", cmp_capacity);
5004 if(dst_size == 0 || dst_size >= raw_length)
5006 TRACE(
"Flux capture zstd compression fell back to uncompressed (dst=%zu, raw=%" PRIu64
")", dst_size,
5013 cmp_length = (uint32_t)dst_size;
5014 compressed_buffer = cmp_stream;
5024 cmp_length = (uint32_t)raw_length;
5026 compressed_buffer = raw_buffer;
5034 if(payload_position & alignment_mask)
5036 const uint64_t aligned_position = payload_position + alignment_mask & ~alignment_mask;
5038 payload_position = aligned_position;
5044 payload_header.
compression = (uint16_t)compression;
5046 payload_header.
length = (uint32_t)raw_length;
5048 payload_header.
crc64 = raw_crc;
5052 free(compressed_buffer);
5054 FATAL(
"Could not write flux payload header");
5058 if(cmp_length != 0 && compressed_buffer != NULL && fwrite(compressed_buffer, cmp_length, 1, ctx->
imageStream) != 1)
5060 free(compressed_buffer);
5062 FATAL(
"Could not write flux payload data");
5069 payload_entry.
offset = payload_position;
5081 record->
entry = *entry;
5083 free(compressed_buffer);
5324 TRACE(
"Entering write_flux_blocks(%p)", ctx);
5328 FATAL(
"Invalid context when writing flux blocks");
5334 TRACE(
"No flux captures enqueued, skipping flux block serialization");
5339 if(capture_count > UINT16_MAX)
5341 FATAL(
"Flux capture count exceeds header capacity (%zu > %u)", capture_count, UINT16_MAX);
5352 FATAL(
"Could not allocate %zu bytes for flux entries", capture_count *
sizeof(
FluxEntry));
5371 header.
entries = (uint16_t)capture_count;
5380 if(metadata_position & alignment_mask)
5382 const uint64_t aligned_position = metadata_position + alignment_mask & ~alignment_mask;
5384 metadata_position = aligned_position;
5391 FATAL(
"Could not write flux metadata header");
5395 if(capture_count != 0)
5398 if(written_entries != capture_count)
5402 FATAL(
"Could not write %zu flux entries (wrote %zu)", capture_count, written_entries);
5410 metadata_entry.
offset = metadata_position;
5413 if(previous_entries != NULL) free(previous_entries);
5423 TRACE(
"Wrote %zu flux captures", capture_count);
5446 TRACE(
"Writing index at the end of the file");
5452 if(index_position & alignment_mask)
5454 uint64_t aligned_position = index_position + alignment_mask & ~alignment_mask;
5456 index_position = aligned_position;
5457 TRACE(
"Aligned index position to %" PRIu64, aligned_position);
5466 TRACE(
"Writing index with %" PRIu64
" entries at position %ld", index_header.
entries, index_position);
5470 if(index_crc64_context != NULL && index_header.
entries > 0)
5475 TRACE(
"Calculated index CRC64: 0x%16lX", index_header.
crc64);
5478 index_header.
crc64 = 0;
5486 TRACE(
"Successfully wrote index header");
5491 size_t entries_written = 0;
5499 TRACE(
"Wrote index entry: blockType=0x%08X dataType=%u offset=%" PRIu64, entry->
blockType,
5504 TRACE(
"Failed to write index entry %zu", entries_written);
5508 if(entries_written == index_header.
entries)
5510 TRACE(
"Successfully wrote all %zu index entries", entries_written);
5519 TRACE(
"Successfully updated header with index offset");
5522 TRACE(
"Failed to update header with index offset");
5528 TRACE(
"Failed to write all index entries (wrote %zu of %" PRIu64
")", entries_written,
5536 TRACE(
"Failed to write index header");
5557 TRACE(
"File is writing");
5561 TRACE(
"Seeking to start of image");
5565 TRACE(
"Writing header at position 0");
5575 TRACE(
"Closing current block if any");
5696 TRACE(
"Clearing sector hash map");
static void remove_dpm_index_entries(aaruformat_context *ctx)
Removes every Data Position Measurement block from the index.
static int32_t write_flux_capture_payload(aaruformat_context *ctx, FluxCaptureRecord *record, FluxEntry *entry)
Serialize a single flux capture payload block 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 void write_cicm_block(aaruformat_context *ctx)
Serialize the CICM XML metadata block to the image file.
static void write_dpm_block(aaruformat_context *ctx)
Serializes the Data Position Measurement block to the image file.
static void write_sector_subchannel(aaruformat_context *ctx)
Serialize the per-sector subchannel or tag data block.
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(aaruformat_context *ctx)
Serialize all accumulated media tags to the image file.
static void write_dvd_title_key_decrypted_block(aaruformat_context *ctx)
Serialize the DVD decrypted title key data block to the image file.
static int32_t write_single_level_ddt(aaruformat_context *ctx)
Serialize a single-level DDT (tableShift == 0) directly after its header.
static void write_tape_file_block(aaruformat_context *ctx)
Serialize the tape file metadata block to the image file.
static void write_dumphw_block(aaruformat_context *ctx)
Serialize the dump hardware block containing acquisition environment information.
static void write_dvd_long_sector_blocks(aaruformat_context *ctx)
Serialize DVD long sector auxiliary data blocks 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_bd_sector_edc_block(aaruformat_context *ctx)
Serialize Blu-ray long-sector EDC (4 bytes per sector) to the image file.
static void write_aaru_json_block(aaruformat_context *ctx)
Serialize the Aaru metadata JSON block to the image file.
static void write_geometry_block(aaruformat_context *ctx)
Serialize the geometry metadata 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_tape_partition_block(aaruformat_context *ctx)
Serialize the tape partition metadata block to the image file.
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 int32_t write_flux_blocks(aaruformat_context *ctx)
Serialize all accumulated flux capture blocks to the image file.
#define LZMA_PROPERTIES_LENGTH
Size in bytes of the fixed LZMA properties header (lc/lp/pb + dictionary size).
#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.
size_t aaruf_zstd_encode_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer, size_t src_size, int level, int num_threads)
Encodes a buffer using Zstandard compression.
void aaruf_crc64_free(crc64_ctx *ctx)
Frees a CRC64 context.
void aaruf_sha256_final(sha256_ctx *ctx, unsigned char *result)
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.
crc64_ctx * aaruf_crc64_init(void)
Initializes a CRC64 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.
@ DeDuplicationTableSAlpha
Block containing a secondary deduplication table (v2) (mistake).
@ DumpHardwareBlock
Block containing an array of hardware used to create the image.
@ MetadataBlock
Block containing metadata.
@ DataPositionMeasurementBlock
Block containing data position measurements (reserved / TODO).
@ TracksBlock
Block containing optical disc tracks.
@ FluxDataBlock
Block containing flux data metadata.
@ DataStreamPayloadBlock
Block containing compressed data stream payload (e.g., flux data, bitstreams).
@ AARU_FEATURE_INCOMPAT_ZSTD
Image contains Zstandard-compressed blocks.
@ OpticalDisc
Purely optical discs.
@ BlockMedia
Media that is physically block-based or abstracted like that.
@ SpamSum
SpamSum (context-triggered piecewise hash).
@ kDataTypeDvdTitleKeyDecrypted
Decrypted DVD Title Key.
@ kDataTypeDvdSectorId
DVD Identification Data (ID).
@ kDataTypeAppleSonyTag
Apple Sony (12‑byte) tag.
@ kDataTypeCdSectorSuffix
Compact Disc sector suffix (EDC, ECC P, ECC Q).
@ kDataTypeFluxData
Flux data.
@ kDataTypeCdSubchannel
Compact Disc subchannel data.
@ kDataTypeBdSectorEdc
Blu-ray Sector EDC.
@ kDataTypeDvdSectorIed
DVD ID Error Detection Code (IED).
@ kDataTypeDvdSectorCprMai
DVD Copyright Management Information (CPR_MAI).
@ kDataTypePriamDataTowerTag
Priam Data Tower (24‑byte) tag.
@ kDataTypeUserData
User (main) data.
@ kDataTypeDvdSectorEdc
DVD Error Detection Code (EDC).
@ kDataTypeAppleProfileTag
Apple Profile (20‑byte) tag.
@ kDataTypeCdSubHeader
Compact Disc MODE 2 subheader.
@ kDataTypeCdSectorPrefix
Compact Disc sector prefix (sync, header).
@ AARU_FEATURE_RW_BLAKE3
BLAKE3 checksum is present (read/write support for BLAKE3 hashes).
@ AARUF_STATUS_INVALID_CONTEXT
Provided context/handle is invalid.
CompressionType
List of known compression types.
@ kCompressionLzmaCst
LZMA applied to Claunia Subchannel Transform processed data.
@ kCompressionLzma
LZMA compression.
@ kCompressionNone
Not compressed.
@ kCompressionZstd
Zstandard compression.
@ kCompressionZstdCst
Zstandard applied to Claunia Subchannel Transform processed data.
void ec_finalize(aaruformat_context *ctx)
Flush all partial data stripes and write parity for all groups + ECMB + recovery footer.
#define AARUF_ERROR_CANNOT_WRITE_BLOCK_DATA
Failure writing block payload.
#define AARUF_STATUS_OK
Sector present and read without uncorrectable errors.
#define AARUF_ERROR_NOT_ENOUGH_MEMORY
Memory allocation failure (critical).
#define AARUF_ERROR_INCORRECT_DATA_SIZE
Data size does not match expected size.
#define AARUF_ERROR_NOT_AARUFORMAT
Input file/stream failed magic or structural validation.
#define AARUF_ERROR_CANNOT_WRITE_HEADER
Failure writing container header.
#define AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER
Failure writing block 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.
static int aaruf_fseek(FILE *stream, aaru_off_t offset, int origin)
static aaru_off_t aaruf_ftell(FILE *stream)
int32_t aaruf_finalize_write(aaruformat_context *ctx)
Finalize a write-mode image: flush all pending blocks, DDTs, and the index.
#define LZMA_THREADS(ctx)
Clamp num_threads to LZMA's valid range [1, 2].
int32_t flux_map_rebuild_from_entries(aaruformat_context *ctx)
Rebuild the flux capture lookup map from the flux_entries array.
#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.
Internal structure for storing flux capture data during write mode.
FluxEntry entry
Flux entry metadata describing this capture.
uint32_t data_length
Length of the data buffer in bytes.
uint32_t index_length
Length of the index buffer in bytes.
uint8_t * index_buffer
Pointer to the flux index buffer. Owned by the utarray, freed automatically.
uint8_t * data_buffer
Pointer to the flux data buffer. Owned by the utarray, freed automatically.
Metadata entry describing a single flux capture in the FluxDataBlock.
uint64_t indexResolution
Resolution in picoseconds at which the index stream was sampled.
uint64_t dataResolution
Resolution in picoseconds at which the data stream was sampled.
uint32_t head
Head number the flux capture corresponds to. Typically 0 or 1 for double-sided media.
uint64_t payloadOffset
Block-aligned file offset where the DataStreamPayloadBlock containing this capture's data is stored,...
uint16_t track
Track number the flux capture corresponds to. Track numbering is format-dependent.
uint64_t indexOffset
Byte offset within the payload where the index buffer starts (equals data_length).
uint8_t subtrack
Subtrack number, allowing sub-stepping within a track. Used for fine positioning.
uint32_t captureIndex
Capture index, allowing multiple captures for the same location (e.g., multiple revolutions).
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 dirty_checksum_block
True if checksum block should be written during close.
bool deduplicate
Storage deduplication active (duplicates coalesce).
size_t dpm_block_length
Length of dpm_block in bytes, 0 if not present.
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.
bool dirty_media_tags
True if media tags should be written during close.
hash_map_t * sector_hash_map
Deduplication hash map (fingerprint->entry mapping).
FluxHeader flux_data_header
Flux data header (if present).
UT_array * flux_captures
Pending flux capture payloads (write path).
bool dirty_dpm_block
True if DPM block should be written or removed during close.
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.
bool dirty_primary_ddt
True if primary DDT table should be written during close.
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.
bool dirty_sector_suffix_block
True if sector suffix block should be written during close.
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.
bool dirty_dvd_title_key_decrypted_block
True if decrypted title key block should be written during close.
uint64_t * sector_suffix_ddt2
CD sector suffix DDT V2.
tapeFileHashEntry * tape_files
Hash table root for tape files.
bool dirty_mode2_subheaders_block
True if MODE2 subheader block should be written during close.
bool dirty_tape_partition_block
True if tape partition block should be written during close.
uint64_t cached_ddt_offset
File offset of currently cached secondary DDT (0=none).
bool dirty_cicm_block
True if CICM metadata block should be written during close.
bool is_tape
True if the image is a tape image.
uint8_t * sector_edc
DVD or Blu-ray sector EDC (4 bytes) if present (see DvdSectorEdc / BdSectorEdc data types).
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.
bool dirty_tracks_block
True if tracks block should be written during close.
uint8_t * drive_serial_number
Serial number of the drive used to read the media represented by the image.
bool dirty_sector_prefix_block
True if sector prefix block should be written during close.
uint8_t * drive_manufacturer
Manufacturer of the drive used to read the media represented by the image.
bool dirty_index_block
True if index block should be written during close.
uint8_t * sector_suffix
Raw per-sector suffix (EDC/ECC) uncorrected.
AaruHeaderV2 header
Parsed container header (v2).
FluxEntry * flux_entries
Array of flux entries (flux_data_header.entries elements).
bool dirty_json_block
True if JSON metadata block should be written during close.
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.
bool dirty_single_level_ddt
True if single-level DDT should be written during close.
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.
bool dirty_sector_suffix_ddt
True if sector suffix DDT should be written during close.
GeometryBlockHeader geometry_block
Logical geometry block (if present).
size_t sector_suffix_offset
Current position in sector_suffix.
bool has_zstd_blocks
True if any block was actually written with Zstandard compression.
uint64_t * cached_secondary_ddt2
Cached secondary table (big entries) or NULL.
uint8_t * json_block
JSON metadata block payload (UTF-8).
int zstd_level
Zstandard compression level (writing path, default 19).
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.
bool dirty_dumphw_block
True if dump hardware block should be written during close.
AaruMetadataJsonBlockHeader json_block_header
JSON metadata block header (if present).
bool dirty_metadata_block
True if metadata block should be written during close.
uint8_t * sector_subchannel
Raw 96-byte subchannel (if captured).
uint8_t * comments
Image comments.
bool dirty_sector_subchannel_block
True if subchannel block should be written during close.
FILE * imageStream
Underlying FILE* stream (binary mode).
bool dirty_dvd_long_sector_blocks
True if DVD long sector blocks should be written during close.
bool no_user_data_ddt
True if image intentionally has no user-data DDT (e.g. flux-only image). When set,...
bool dirty_sector_prefix_ddt
True if sector prefix DDT should be written during close.
UT_array * index_entries
Flattened index entries (UT_array of IndexEntry).
int num_threads
Compression worker threads (1 = single-threaded, default).
bool dirty_tape_file_block
True if tape file block should be written during close.
uint8_t * mode2_subheaders
MODE2 Form1/Form2 8-byte subheaders (concatenated).
bool dirty_bd_sector_edc_block
True if Blu-ray sector EDC data block should be written during close.
ImageInfo image_info
Exposed high-level image info summary.
bool dirty_flux_block
True if flux block should be written during close.
uint8_t * sector_id
DVD sector ID (4 bytes) if present.
DumpHardwareHeader dump_hardware_header
Dump hardware header.
bool use_zstd
Use Zstandard instead of LZMA for data blocks.
sha1_ctx sha1_context
Opaque SHA-1 context for streaming updates.
bool dirty_secondary_ddt
True if secondary DDT tables should be written during close.
bool dirty_tape_ddt
True if tape DDT should be written during close.
TapePartitionHashEntry * tape_partitions
Hash table root for tape partitions.
uint8_t * dpm_block
Data Position Measurement block, header included.
uint32_t lzma_dict_size
LZMA dictionary size (writing path).
TrackEntry * track_entries
Full track list (tracksHeader.entries elements).
uint64_t cached_ddt_position
Position index of cached secondary DDT.
uint8_t * media_title
Title of the media represented by the image.
bool dirty_geometry_block
True if geometry block should be written during close.
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.