Remove concept of 16-bit DDTs.

This commit is contained in:
2025-10-09 01:47:39 +01:00
parent a51e170183
commit fafca45dae
6 changed files with 192 additions and 461 deletions

View File

@@ -188,8 +188,10 @@ typedef struct aaruformatContext
bool inMemoryDdt; ///< True if primary (and possibly secondary) DDT loaded.
uint64_t *userDataDdt; ///< Legacy flat DDT pointer (NULL when using v2 mini/big arrays).
size_t mappedMemoryDdtSize; ///< Length of mmapped DDT if userDataDdt is mmapped.
uint32_t *sectorPrefixDdt; ///< Legacy CD sector prefix DDT (deprecated by *_Mini/Big).
uint32_t *sectorPrefixDdt; ///< Legacy CD sector prefix DDT (deprecated by *2).
uint32_t *sectorSuffixDdt; ///< Legacy CD sector suffix DDT.
uint32_t *sectorPrefixDdt2; ///< CD sector prefix DDT V2.
uint32_t *sectorSuffixDdt2; ///< CD sector suffix DDT V2.
GeometryBlockHeader geometryBlock; ///< Logical geometry block (if present).
MetadataBlockHeader metadataBlockHeader; ///< Metadata block header.
@@ -213,18 +215,14 @@ typedef struct aaruformatContext
Checksums checksums; ///< Whole-image checksums discovered.
mediaTagEntry *mediaTags; ///< Hash table of extra media tags (uthash root).
DdtHeader2 userDataDdtHeader; ///< Active user data DDT v2 header (primary table meta).
int ddtVersion; ///< DDT version in use (1=legacy, 2=v2 hierarchical).
uint16_t *userDataDdtMini; ///< DDT entries (small variant) primary/secondary current.
uint32_t *userDataDdtBig; ///< DDT entries (big variant) primary/secondary current.
uint16_t *sectorPrefixDdtMini; ///< CD sector prefix corrected DDT (small) if present.
uint16_t *sectorSuffixDdtMini; ///< CD sector suffix corrected DDT (small) if present.
DdtHeader2 userDataDdtHeader; ///< Active user data DDT v2 header (primary table meta).
int ddtVersion; ///< DDT version in use (1=legacy, 2=v2 hierarchical).
uint32_t *userDataDdtBig; ///< DDT entries (big variant) primary/secondary current.
uint64_t cachedDdtOffset; ///< File offset of currently cached secondary DDT (0=none).
uint64_t cachedDdtPosition; ///< Position index of cached secondary DDT.
uint64_t primaryDdtOffset; ///< File offset of the primary DDT v2 table.
uint16_t *cachedSecondaryDdtSmall; ///< Cached secondary table (small entries) or NULL.
uint32_t *cachedSecondaryDdtBig; ///< Cached secondary table (big entries) or NULL.
uint64_t cachedDdtOffset; ///< File offset of currently cached secondary DDT (0=none).
uint64_t cachedDdtPosition; ///< Position index of cached secondary DDT.
uint64_t primaryDdtOffset; ///< File offset of the primary DDT v2 table.
uint32_t *cachedSecondaryDdtBig; ///< Cached secondary table (big entries) or NULL.
bool isWriting; ///< True if context opened/created for writing.
BlockHeader currentBlockHeader; ///< Header for block currently being assembled (write path).

View File

@@ -226,8 +226,7 @@ typedef enum
*/
typedef enum
{
SmallDdtSizeType = 0, ///< Small sized DDT entries.
BigDdtSizeType = 1 ///< Large sized DDT entries.
BigDdtSizeType = 1 ///< Large sized DDT entries.
} DdtSizeType;
/**

View File

@@ -79,8 +79,7 @@ static int32_t write_cached_secondary_ddt(aaruformatContext *ctx)
// Write cached secondary table to file end and update primary table entry with its position
// Check if we have a cached table that needs to be written (either it has an offset or exists in memory)
bool has_cached_secondary_ddt =
ctx->userDataDdtHeader.tableShift > 0 &&
(ctx->cachedDdtOffset != 0 || ctx->cachedSecondaryDdtSmall != NULL || ctx->cachedSecondaryDdtBig != NULL);
ctx->userDataDdtHeader.tableShift > 0 && (ctx->cachedDdtOffset != 0 || ctx->cachedSecondaryDdtBig != NULL);
if(!has_cached_secondary_ddt) return AARUF_STATUS_OK;
@@ -126,19 +125,13 @@ static int32_t write_cached_secondary_ddt(aaruformatContext *ctx)
ddt_header.start = ctx->cachedDdtPosition * items_per_ddt_entry;
// Calculate data size
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
ddt_header.length = items_per_ddt_entry * sizeof(uint16_t);
else
ddt_header.length = items_per_ddt_entry * sizeof(uint32_t);
ddt_header.length = items_per_ddt_entry * sizeof(uint32_t);
// Calculate CRC64 of the data
crc64_ctx *crc64_context = aaruf_crc64_init();
if(crc64_context != NULL)
{
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
aaruf_crc64_update(crc64_context, (uint8_t *)ctx->cachedSecondaryDdtSmall, (uint32_t)ddt_header.length);
else
aaruf_crc64_update(crc64_context, (uint8_t *)ctx->cachedSecondaryDdtBig, (uint32_t)ddt_header.length);
aaruf_crc64_update(crc64_context, (uint8_t *)ctx->cachedSecondaryDdtBig, (uint32_t)ddt_header.length);
uint64_t crc64;
aaruf_crc64_final(crc64_context, &crc64);
@@ -150,10 +143,7 @@ static int32_t write_cached_secondary_ddt(aaruformatContext *ctx)
if(ddt_header.compression == None)
{
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
buffer = (uint8_t *)ctx->cachedSecondaryDdtSmall;
else
buffer = (uint8_t *)ctx->cachedSecondaryDdtBig;
buffer = (uint8_t *)ctx->cachedSecondaryDdtBig;
ddt_header.cmpCrc64 = ddt_header.crc64;
}
else
@@ -167,11 +157,10 @@ static int32_t write_cached_secondary_ddt(aaruformatContext *ctx)
size_t dst_size = (size_t)ddt_header.length * 2 * 2;
size_t props_size = LZMA_PROPERTIES_LENGTH;
aaruf_lzma_encode_buffer(
buffer, &dst_size,
ctx->userDataDdtHeader.sizeType == SmallDdtSizeType ? (uint8_t *)ctx->cachedSecondaryDdtSmall
: (uint8_t *)ctx->cachedSecondaryDdtBig,
ddt_header.length, lzma_properties, &props_size, 9, ctx->lzma_dict_size, 4, 0, 2, 273, 8);
aaruf_lzma_encode_buffer(buffer, &dst_size,
(uint8_t *)ctx->cachedSecondaryDdtBig, ddt_header.length, lzma_properties, &props_size,
9, ctx->lzma_dict_size, 4, 0, 2, 273, 8);
ddt_header.cmpLength = (uint32_t)dst_size;
@@ -179,10 +168,7 @@ static int32_t write_cached_secondary_ddt(aaruformatContext *ctx)
{
ddt_header.compression = None;
free(buffer);
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
buffer = (uint8_t *)ctx->cachedSecondaryDdtSmall;
else
buffer = (uint8_t *)ctx->cachedSecondaryDdtBig;
buffer = (uint8_t *)ctx->cachedSecondaryDdtBig;
}
}
@@ -207,10 +193,7 @@ static int32_t write_cached_secondary_ddt(aaruformatContext *ctx)
// Update primary table entry to point to new location
const uint64_t new_secondary_table_block_offset = end_of_file >> ctx->userDataDdtHeader.blockAlignmentShift;
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
ctx->userDataDdtMini[ctx->cachedDdtPosition] = (uint16_t)new_secondary_table_block_offset;
else
ctx->userDataDdtBig[ctx->cachedDdtPosition] = (uint32_t)new_secondary_table_block_offset;
ctx->userDataDdtBig[ctx->cachedDdtPosition] = (uint32_t)new_secondary_table_block_offset;
// Update index: remove old entry for cached DDT and add new one
TRACE("Updating index for cached secondary DDT");
@@ -247,15 +230,10 @@ static int32_t write_cached_secondary_ddt(aaruformatContext *ctx)
long saved_pos = ftell(ctx->imageStream);
fseek(ctx->imageStream, ctx->primaryDdtOffset + sizeof(DdtHeader2), SEEK_SET);
size_t primary_table_size = ctx->userDataDdtHeader.sizeType == SmallDdtSizeType
? ctx->userDataDdtHeader.entries * sizeof(uint16_t)
: ctx->userDataDdtHeader.entries * sizeof(uint32_t);
size_t primary_table_size = ctx->userDataDdtHeader.entries * sizeof(uint32_t);
size_t primary_written_bytes = 0;
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
primary_written_bytes = fwrite(ctx->userDataDdtMini, primary_table_size, 1, ctx->imageStream);
else
primary_written_bytes = fwrite(ctx->userDataDdtBig, primary_table_size, 1, ctx->imageStream);
primary_written_bytes = fwrite(ctx->userDataDdtBig, primary_table_size, 1, ctx->imageStream);
if(primary_written_bytes != 1)
{
@@ -272,17 +250,9 @@ static int32_t write_cached_secondary_ddt(aaruformatContext *ctx)
TRACE("Failed to write cached secondary DDT header");
// Free the cached table
if(ctx->cachedSecondaryDdtSmall != NULL)
{
free(ctx->cachedSecondaryDdtSmall);
ctx->cachedSecondaryDdtSmall = NULL;
}
if(ctx->cachedSecondaryDdtBig != NULL)
{
free(ctx->cachedSecondaryDdtBig);
ctx->cachedSecondaryDdtBig = NULL;
}
ctx->cachedDdtOffset = 0;
free(ctx->cachedSecondaryDdtBig);
ctx->cachedSecondaryDdtBig = NULL;
ctx->cachedDdtOffset = 0;
// Set position
fseek(ctx->imageStream, 0, SEEK_END);
@@ -312,8 +282,7 @@ static int32_t write_cached_secondary_ddt(aaruformatContext *ctx)
static int32_t write_primary_ddt(aaruformatContext *ctx)
{
// Write the cached primary DDT table back to its position in the file
if(ctx->userDataDdtHeader.tableShift <= 0 || ctx->userDataDdtMini == NULL && ctx->userDataDdtBig == NULL)
return AARUF_STATUS_OK;
if(ctx->userDataDdtHeader.tableShift <= 0 || ctx->userDataDdtBig == NULL) return AARUF_STATUS_OK;
TRACE("Writing cached primary DDT table back to file");
@@ -321,14 +290,9 @@ static int32_t write_primary_ddt(aaruformatContext *ctx)
crc64_ctx *crc64_context = aaruf_crc64_init();
if(crc64_context != NULL)
{
size_t primary_table_size = ctx->userDataDdtHeader.sizeType == SmallDdtSizeType
? ctx->userDataDdtHeader.entries * sizeof(uint16_t)
: ctx->userDataDdtHeader.entries * sizeof(uint32_t);
size_t primary_table_size = ctx->userDataDdtHeader.entries * sizeof(uint32_t);
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
aaruf_crc64_update(crc64_context, (uint8_t *)ctx->userDataDdtMini, primary_table_size);
else
aaruf_crc64_update(crc64_context, (uint8_t *)ctx->userDataDdtBig, primary_table_size);
aaruf_crc64_update(crc64_context, (uint8_t *)ctx->userDataDdtBig, primary_table_size);
uint64_t crc64;
aaruf_crc64_final(crc64_context, &crc64);
@@ -358,16 +322,11 @@ static int32_t write_primary_ddt(aaruformatContext *ctx)
}
// Then write the table data (position is already after the header)
size_t primary_table_size = ctx->userDataDdtHeader.sizeType == SmallDdtSizeType
? ctx->userDataDdtHeader.entries * sizeof(uint16_t)
: ctx->userDataDdtHeader.entries * sizeof(uint32_t);
size_t primary_table_size = ctx->userDataDdtHeader.entries * sizeof(uint32_t);
// Write the primary table data
size_t written_bytes = 0;
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
written_bytes = fwrite(ctx->userDataDdtMini, primary_table_size, 1, ctx->imageStream);
else
written_bytes = fwrite(ctx->userDataDdtBig, primary_table_size, 1, ctx->imageStream);
written_bytes = fwrite(ctx->userDataDdtBig, primary_table_size, 1, ctx->imageStream);
if(written_bytes == 1)
{
@@ -409,15 +368,12 @@ static int32_t write_primary_ddt(aaruformatContext *ctx)
static int32_t write_single_level_ddt(aaruformatContext *ctx)
{
// Write the single level DDT table block aligned just after the header
if(ctx->userDataDdtHeader.tableShift != 0 || ctx->userDataDdtMini == NULL && ctx->userDataDdtBig == NULL)
return AARUF_STATUS_OK;
if(ctx->userDataDdtHeader.tableShift != 0 || ctx->userDataDdtBig == NULL) return AARUF_STATUS_OK;
TRACE("Writing single-level DDT table to file");
// Calculate CRC64 of the primary DDT table data
const size_t primary_table_size = ctx->userDataDdtHeader.sizeType == SmallDdtSizeType
? ctx->userDataDdtHeader.entries * sizeof(uint16_t)
: ctx->userDataDdtHeader.entries * sizeof(uint32_t);
const size_t primary_table_size = ctx->userDataDdtHeader.entries * sizeof(uint32_t);
// Properly populate all header fields
ctx->userDataDdtHeader.identifier = DeDuplicationTable2;
@@ -431,10 +387,7 @@ static int32_t write_single_level_ddt(aaruformatContext *ctx)
ctx->userDataDdtHeader.length = primary_table_size;
ctx->userDataDdtHeader.cmpLength = primary_table_size;
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
ctx->userDataDdtHeader.crc64 = aaruf_crc64_data((uint8_t *)ctx->userDataDdtMini, primary_table_size);
else
ctx->userDataDdtHeader.crc64 = aaruf_crc64_data((uint8_t *)ctx->userDataDdtBig, primary_table_size);
ctx->userDataDdtHeader.crc64 = aaruf_crc64_data((uint8_t *)ctx->userDataDdtBig, primary_table_size);
TRACE("Calculated CRC64 for single-level DDT: 0x%16lX", ctx->userDataDdtHeader.crc64);
@@ -443,10 +396,8 @@ static int32_t write_single_level_ddt(aaruformatContext *ctx)
if(ctx->userDataDdtHeader.compression == None)
{
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
cmp_buffer = (uint8_t *)ctx->userDataDdtMini;
else
cmp_buffer = (uint8_t *)ctx->userDataDdtBig;
cmp_buffer = (uint8_t *)ctx->userDataDdtBig;
ctx->userDataDdtHeader.cmpCrc64 = ctx->userDataDdtHeader.crc64;
}
else
@@ -460,11 +411,8 @@ static int32_t write_single_level_ddt(aaruformatContext *ctx)
size_t dst_size = (size_t)ctx->userDataDdtHeader.length * 2 * 2;
size_t props_size = LZMA_PROPERTIES_LENGTH;
aaruf_lzma_encode_buffer(cmp_buffer, &dst_size,
ctx->userDataDdtHeader.sizeType == SmallDdtSizeType ? (uint8_t *)ctx->userDataDdtMini
: (uint8_t *)ctx->userDataDdtBig,
ctx->userDataDdtHeader.length, lzma_properties, &props_size, 9, ctx->lzma_dict_size, 4,
0, 2, 273, 8);
aaruf_lzma_encode_buffer(cmp_buffer, &dst_size, (uint8_t *)ctx->userDataDdtBig, ctx->userDataDdtHeader.length,
lzma_properties, &props_size, 9, ctx->lzma_dict_size, 4, 0, 2, 273, 8);
ctx->userDataDdtHeader.cmpLength = (uint32_t)dst_size;
@@ -472,10 +420,8 @@ static int32_t write_single_level_ddt(aaruformatContext *ctx)
{
ctx->userDataDdtHeader.compression = None;
free(cmp_buffer);
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
cmp_buffer = (uint8_t *)ctx->userDataDdtMini;
else
cmp_buffer = (uint8_t *)ctx->userDataDdtBig;
cmp_buffer = (uint8_t *)ctx->userDataDdtBig;
}
}
@@ -1241,7 +1187,7 @@ static void write_sector_suffix(aaruformatContext *ctx)
* Notes:
* - Unlike DDT v1, there are no CD_XFIX_MASK / CD_DFIX_MASK macros used here. The bit layout is compact
* and directly encoded when writing (status values are pre-shifted where needed in write.c).
* - Only the 16-bit mini variant is currently produced (sectorPrefixDdtMini). A 32-bit form is reserved
* - Only the 16-bit mini variant is currently produced (sectorPrefixDdt2). A 32-bit form is reserved
* for future expansion (sectorPrefixDdt) but is not emitted unless populated.
* - The table length equals (negative + Sectors + overflow) * entrySize.
* - dataShift is set to 4 (2^4 = 16) expressing the granularity of referenced prefix units.
@@ -1257,7 +1203,7 @@ static void write_sector_suffix(aaruformatContext *ctx)
*/
static void write_sector_prefix_ddt(aaruformatContext *ctx)
{
if(ctx->sectorPrefixDdtMini == NULL) return;
if(ctx->sectorPrefixDdt2 == NULL) return;
fseek(ctx->imageStream, 0, SEEK_END);
long prefix_ddt_position = ftell(ctx->imageStream);
@@ -1282,20 +1228,20 @@ static void write_sector_prefix_ddt(aaruformatContext *ctx)
ddt_header2.blockAlignmentShift = ctx->userDataDdtHeader.blockAlignmentShift;
ddt_header2.dataShift = ctx->userDataDdtHeader.dataShift;
ddt_header2.tableShift = 0; // Single-level DDT
ddt_header2.sizeType = SmallDdtSizeType;
ddt_header2.sizeType = BigDdtSizeType;
ddt_header2.entries = ctx->imageInfo.Sectors + ctx->userDataDdtHeader.negative + ctx->userDataDdtHeader.overflow;
ddt_header2.blocks = ctx->userDataDdtHeader.blocks;
ddt_header2.start = 0;
ddt_header2.length = ddt_header2.entries * sizeof(uint16_t);
ddt_header2.length = ddt_header2.entries * sizeof(uint32_t);
// Calculate CRC64
ddt_header2.crc64 = aaruf_crc64_data((uint8_t *)ctx->sectorPrefixDdtMini, (uint32_t)ddt_header2.length);
ddt_header2.crc64 = aaruf_crc64_data((uint8_t *)ctx->sectorPrefixDdt2, (uint32_t)ddt_header2.length);
uint8_t *buffer = NULL;
uint8_t lzma_properties[LZMA_PROPERTIES_LENGTH] = {0};
if(ddt_header2.compression == None)
{
buffer = (uint8_t *)ctx->sectorPrefixDdtMini;
buffer = (uint8_t *)ctx->sectorPrefixDdt2;
ddt_header2.cmpCrc64 = ddt_header2.crc64;
}
else
@@ -1309,7 +1255,7 @@ static void write_sector_prefix_ddt(aaruformatContext *ctx)
size_t dst_size = (size_t)ddt_header2.length * 2 * 2;
size_t props_size = LZMA_PROPERTIES_LENGTH;
aaruf_lzma_encode_buffer(buffer, &dst_size, (uint8_t *)ctx->sectorPrefixDdtMini, ddt_header2.length,
aaruf_lzma_encode_buffer(buffer, &dst_size, (uint8_t *)ctx->sectorPrefixDdt2, ddt_header2.length,
lzma_properties, &props_size, 9, ctx->lzma_dict_size, 4, 0, 2, 273, 8);
ddt_header2.cmpLength = (uint32_t)dst_size;
@@ -1318,7 +1264,7 @@ static void write_sector_prefix_ddt(aaruformatContext *ctx)
{
ddt_header2.compression = None;
free(buffer);
buffer = (uint8_t *)ctx->sectorPrefixDdtMini;
buffer = (uint8_t *)ctx->sectorPrefixDdt2;
}
}
@@ -1375,13 +1321,13 @@ static void write_sector_prefix_ddt(aaruformatContext *ctx)
*
* Characteristics & constraints:
* - Only DDT v2 is supported here; no fallback or mixed-mode emission with v1 occurs.
* - Only the compact "mini" (16-bit) table form is currently produced (sectorSuffixDdtMini filled during write).
* - Only the compact "mini" (16-bit) table form is currently produced (sectorSuffixDdt2 filled during write).
* - Table length = (negative + total Sectors + overflow) * sizeof(uint16_t).
* - dataShift mirrors userDataDdtHeader.dataShift (expressing granularity for index referencing).
* - Single-level table (levels = 1, tableLevel = 0, tableShift = 0).
* - Compression is applied if enabled; CRC64 protects the table bytes.
* - Alignment: The table is aligned to 2^(blockAlignmentShift) before writing to guarantee block boundary access.
* - Idempotence: If sectorSuffixDdtMini is NULL the function is a no-op (indicating no suffix anomalies captured).
* - Idempotence: If sectorSuffixDdt2 is NULL the function is a no-op (indicating no suffix anomalies captured).
*
* Index integration:
* On success an IndexEntry (blockType = DeDuplicationTable2, dataType = CdSectorSuffix, offset = file position)
@@ -1395,14 +1341,14 @@ static void write_sector_prefix_ddt(aaruformatContext *ctx)
*
* Preconditions:
* - ctx must be a valid non-NULL pointer opened for writing.
* - ctx->sectorSuffixDdtMini must point to a fully populated contiguous array of uint16_t entries.
* - ctx->sectorSuffixDdt2 must point to a fully populated contiguous array of uint16_t entries.
*
* @param ctx Active aaruformatContext being finalized.
* @internal
*/
static void write_sector_suffix_ddt(aaruformatContext *ctx)
{
if(ctx->sectorSuffixDdtMini == NULL) return;
if(ctx->sectorSuffixDdt2 == NULL) return;
fseek(ctx->imageStream, 0, SEEK_END);
long suffix_ddt_position = ftell(ctx->imageStream);
@@ -1427,20 +1373,20 @@ static void write_sector_suffix_ddt(aaruformatContext *ctx)
ddt_header2.blockAlignmentShift = ctx->userDataDdtHeader.blockAlignmentShift;
ddt_header2.dataShift = ctx->userDataDdtHeader.dataShift;
ddt_header2.tableShift = 0; // Single-level DDT
ddt_header2.sizeType = SmallDdtSizeType;
ddt_header2.sizeType = BigDdtSizeType;
ddt_header2.entries = ctx->imageInfo.Sectors + ctx->userDataDdtHeader.negative + ctx->userDataDdtHeader.overflow;
ddt_header2.blocks = ctx->userDataDdtHeader.blocks;
ddt_header2.start = 0;
ddt_header2.length = ddt_header2.entries * sizeof(uint16_t);
ddt_header2.length = ddt_header2.entries * sizeof(uint32_t);
// Calculate CRC64
ddt_header2.crc64 = aaruf_crc64_data((uint8_t *)ctx->sectorSuffixDdtMini, (uint32_t)ddt_header2.length);
ddt_header2.crc64 = aaruf_crc64_data((uint8_t *)ctx->sectorSuffixDdt2, (uint32_t)ddt_header2.length);
uint8_t *buffer = NULL;
uint8_t lzma_properties[LZMA_PROPERTIES_LENGTH] = {0};
if(ddt_header2.compression == None)
{
buffer = (uint8_t *)ctx->sectorSuffixDdtMini;
buffer = (uint8_t *)ctx->sectorSuffixDdt2;
ddt_header2.cmpCrc64 = ddt_header2.crc64;
}
else
@@ -1454,7 +1400,7 @@ static void write_sector_suffix_ddt(aaruformatContext *ctx)
size_t dst_size = (size_t)ddt_header2.length * 2 * 2;
size_t props_size = LZMA_PROPERTIES_LENGTH;
aaruf_lzma_encode_buffer(buffer, &dst_size, (uint8_t *)ctx->sectorSuffixDdtMini, ddt_header2.length,
aaruf_lzma_encode_buffer(buffer, &dst_size, (uint8_t *)ctx->sectorSuffixDdt2, ddt_header2.length,
lzma_properties, &props_size, 9, ctx->lzma_dict_size, 4, 0, 2, 273, 8);
ddt_header2.cmpLength = (uint32_t)dst_size;
@@ -1463,7 +1409,7 @@ static void write_sector_suffix_ddt(aaruformatContext *ctx)
{
ddt_header2.compression = None;
free(buffer);
buffer = (uint8_t *)ctx->sectorSuffixDdtMini;
buffer = (uint8_t *)ctx->sectorSuffixDdt2;
}
}
@@ -4226,12 +4172,12 @@ int aaruf_close(void *context)
}
#endif
free(ctx->sectorPrefixDdtMini);
ctx->sectorPrefixDdtMini = NULL;
free(ctx->sectorPrefixDdt2);
ctx->sectorPrefixDdt2 = NULL;
free(ctx->sectorPrefixDdt);
ctx->sectorPrefixDdt = NULL;
free(ctx->sectorSuffixDdtMini);
ctx->sectorSuffixDdtMini = NULL;
free(ctx->sectorSuffixDdt2);
ctx->sectorSuffixDdt2 = NULL;
free(ctx->sectorSuffixDdt);
ctx->sectorSuffixDdt = NULL;

View File

@@ -43,12 +43,6 @@ static void cleanup_failed_create(aaruformatContext *ctx)
ctx->indexEntries = NULL;
}
if(ctx->userDataDdtMini != NULL)
{
free(ctx->userDataDdtMini);
ctx->userDataDdtMini = NULL;
}
if(ctx->userDataDdtBig != NULL)
{
free(ctx->userDataDdtBig);
@@ -397,7 +391,7 @@ void *aaruf_create(const char *filepath, const uint32_t media_type, const uint32
// Initialize caches
TRACE("Initializing caches");
ctx->blockHeaderCache.cache = NULL;
ctx->blockHeaderCache.cache = NULL;
const uint64_t cache_divisor = (uint64_t)ctx->imageInfo.SectorSize * (1ULL << ctx->shift);
ctx->blockHeaderCache.max_items = cache_divisor == 0 ? 0 : MAX_CACHE_SIZE / cache_divisor;
ctx->blockCache.cache = NULL;
@@ -459,20 +453,7 @@ void *aaruf_create(const char *filepath, const uint32_t media_type, const uint32
ctx->userDataDdtHeader.entries++;
TRACE("Initializing primary/single DDT");
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
{
ctx->userDataDdtMini =
(uint16_t *)calloc(ctx->userDataDdtHeader.entries, sizeof(uint16_t)); // All entries to zero
if(ctx->userDataDdtMini == NULL)
{
FATAL("Not enough memory to allocate primary DDT (mini)");
errno = AARUF_ERROR_NOT_ENOUGH_MEMORY;
TRACE("Exiting aaruf_create() = NULL");
cleanup_failed_create(ctx);
return NULL;
}
}
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
{
ctx->userDataDdtBig =
(uint32_t *)calloc(ctx->userDataDdtHeader.entries, sizeof(uint32_t)); // All entries to zero
@@ -487,16 +468,14 @@ void *aaruf_create(const char *filepath, const uint32_t media_type, const uint32
}
// Set the primary DDT offset (just after the header, block aligned)
ctx->primaryDdtOffset = sizeof(AaruHeaderV2); // Start just after the header
ctx->primaryDdtOffset = sizeof(AaruHeaderV2); // Start just after the header
const uint64_t alignment_mask = (1ULL << ctx->userDataDdtHeader.blockAlignmentShift) - 1;
ctx->primaryDdtOffset = ctx->primaryDdtOffset + alignment_mask & ~alignment_mask;
ctx->primaryDdtOffset = ctx->primaryDdtOffset + alignment_mask & ~alignment_mask;
TRACE("Primary DDT will be placed at offset %" PRIu64, ctx->primaryDdtOffset);
// Calculate size of primary DDT table
const uint64_t primary_table_size = ctx->userDataDdtHeader.sizeType == SmallDdtSizeType
? ctx->userDataDdtHeader.entries * sizeof(uint16_t)
: ctx->userDataDdtHeader.entries * sizeof(uint32_t);
const uint64_t primary_table_size = ctx->userDataDdtHeader.entries * sizeof(uint32_t);
// Calculate where data blocks can start (after primary DDT + header)
if(ctx->userDataDdtHeader.tableShift > 0)
@@ -514,11 +493,11 @@ void *aaruf_create(const char *filepath, const uint32_t media_type, const uint32
ctx->userDataDdtHeader.dataShift = parsed_options.data_shift;
// Calculate aligned next block position
const uint64_t alignment_mask = (1ULL << parsed_options.block_alignment) - 1;
ctx->nextBlockPosition = sizeof(AaruHeaderV2); // Start just after the header
ctx->nextBlockPosition = ctx->nextBlockPosition + alignment_mask & ~alignment_mask;
ctx->is_tape = 1;
ctx->tapeDdt = NULL;
const uint64_t alignment_mask = (1ULL << parsed_options.block_alignment) - 1;
ctx->nextBlockPosition = sizeof(AaruHeaderV2); // Start just after the header
ctx->nextBlockPosition = ctx->nextBlockPosition + alignment_mask & ~alignment_mask;
ctx->is_tape = 1;
ctx->tapeDdt = NULL;
}
TRACE("Data blocks will start at position %" PRIu64, ctx->nextBlockPosition);

View File

@@ -247,10 +247,7 @@ int32_t process_ddt_v2(aaruformatContext *ctx, IndexEntry *entry, bool *found_us
return AARUF_ERROR_INVALID_BLOCK_CRC;
}
if(ddt_header.sizeType == SmallDdtSizeType)
ctx->userDataDdtMini = (uint16_t *)buffer;
else if(ddt_header.sizeType == BigDdtSizeType)
ctx->userDataDdtBig = (uint32_t *)buffer;
ctx->userDataDdtBig = (uint32_t *)buffer;
ctx->inMemoryDdt = true;
*found_user_data_ddt = true;
@@ -296,10 +293,7 @@ int32_t process_ddt_v2(aaruformatContext *ctx, IndexEntry *entry, bool *found_us
return AARUF_ERROR_INVALID_BLOCK_CRC;
}
if(ddt_header.sizeType == SmallDdtSizeType)
ctx->userDataDdtMini = (uint16_t *)buffer;
else if(ddt_header.sizeType == BigDdtSizeType)
ctx->userDataDdtBig = (uint32_t *)buffer;
ctx->userDataDdtBig = (uint32_t *)buffer;
ctx->inMemoryDdt = true;
*found_user_data_ddt = true;
@@ -405,20 +399,8 @@ int32_t process_ddt_v2(aaruformatContext *ctx, IndexEntry *entry, bool *found_us
return AARUF_ERROR_INVALID_BLOCK_CRC;
}
if(entry->dataType == CdSectorPrefixCorrected)
{
if(ddt_header.sizeType == SmallDdtSizeType)
ctx->sectorPrefixDdtMini = (uint16_t *)buffer;
else if(ddt_header.sizeType == BigDdtSizeType)
ctx->sectorPrefixDdt = (uint32_t *)buffer;
}
else if(entry->dataType == CdSectorSuffixCorrected)
{
if(ddt_header.sizeType == SmallDdtSizeType)
ctx->sectorSuffixDdtMini = (uint16_t *)buffer;
else if(ddt_header.sizeType == BigDdtSizeType)
ctx->sectorSuffixDdt = (uint32_t *)buffer;
}
if(entry->dataType == CdSectorPrefixCorrected) { ctx->sectorPrefixDdt = (uint32_t *)buffer; }
else if(entry->dataType == CdSectorSuffixCorrected) { ctx->sectorSuffixDdt = (uint32_t *)buffer; }
else
free(buffer);
@@ -463,20 +445,8 @@ int32_t process_ddt_v2(aaruformatContext *ctx, IndexEntry *entry, bool *found_us
return AARUF_ERROR_INVALID_BLOCK_CRC;
}
if(entry->dataType == CdSectorPrefixCorrected)
{
if(ddt_header.sizeType == SmallDdtSizeType)
ctx->sectorPrefixDdtMini = (uint16_t *)buffer;
else if(ddt_header.sizeType == BigDdtSizeType)
ctx->sectorPrefixDdt = (uint32_t *)buffer;
}
else if(entry->dataType == CdSectorSuffixCorrected)
{
if(ddt_header.sizeType == SmallDdtSizeType)
ctx->sectorSuffixDdtMini = (uint16_t *)buffer;
else if(ddt_header.sizeType == BigDdtSizeType)
ctx->sectorSuffixDdt = (uint32_t *)buffer;
}
if(entry->dataType == CdSectorPrefixCorrected) { ctx->sectorPrefixDdt = (uint32_t *)buffer; }
else if(entry->dataType == CdSectorSuffixCorrected) { ctx->sectorSuffixDdt = (uint32_t *)buffer; }
else
free(buffer);
@@ -646,9 +616,7 @@ int32_t decode_ddt_single_level_v2(aaruformatContext *ctx, uint64_t sector_addre
else
sector_address += ctx->userDataDdtHeader.negative;
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
ddt_entry = ctx->userDataDdtMini[sector_address];
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
ddt_entry = ctx->userDataDdtBig[sector_address];
else
{
@@ -667,16 +635,8 @@ int32_t decode_ddt_single_level_v2(aaruformatContext *ctx, uint64_t sector_addre
return AARUF_STATUS_OK;
}
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
{
*sector_status = ddt_entry >> 12;
ddt_entry &= 0xfff;
}
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
{
*sector_status = ddt_entry >> 28;
ddt_entry &= 0x0fffffff;
}
*sector_status = ddt_entry >> 28;
ddt_entry &= 0x0fffffff;
const uint64_t offset_mask = (uint64_t)((1 << ctx->userDataDdtHeader.dataShift) - 1);
*offset = ddt_entry & offset_mask;
@@ -818,9 +778,7 @@ int32_t decode_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_addres
items_per_ddt_entry = 1 << ctx->userDataDdtHeader.tableShift;
ddt_position = sector_address / items_per_ddt_entry;
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
secondary_ddt_offset = ctx->userDataDdtMini[ddt_position];
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
secondary_ddt_offset = ctx->userDataDdtBig[ddt_position];
else
{
@@ -949,10 +907,7 @@ int32_t decode_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_addres
return AARUF_ERROR_INVALID_BLOCK_CRC;
}
if(ddt_header.sizeType == SmallDdtSizeType)
ctx->cachedSecondaryDdtSmall = (uint16_t *)buffer;
else if(ddt_header.sizeType == BigDdtSizeType)
ctx->cachedSecondaryDdtBig = (uint32_t *)buffer;
ctx->cachedSecondaryDdtBig = (uint32_t *)buffer;
ctx->cachedDdtOffset = secondary_ddt_offset;
@@ -998,10 +953,7 @@ int32_t decode_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_addres
return AARUF_ERROR_INVALID_BLOCK_CRC;
}
if(ddt_header.sizeType == SmallDdtSizeType)
ctx->cachedSecondaryDdtSmall = (uint16_t *)buffer;
else if(ddt_header.sizeType == BigDdtSizeType)
ctx->cachedSecondaryDdtBig = (uint32_t *)buffer;
ctx->cachedSecondaryDdtBig = (uint32_t *)buffer;
ctx->cachedDdtOffset = secondary_ddt_offset;
@@ -1013,10 +965,7 @@ int32_t decode_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_addres
}
}
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
ddt_entry = ctx->cachedSecondaryDdtSmall[sector_address % items_per_ddt_entry];
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
ddt_entry = ctx->cachedSecondaryDdtBig[sector_address % items_per_ddt_entry];
ddt_entry = ctx->cachedSecondaryDdtBig[sector_address % items_per_ddt_entry];
if(ddt_entry == 0)
{
@@ -1029,16 +978,8 @@ int32_t decode_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_addres
return AARUF_STATUS_OK;
}
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
{
*sector_status = ddt_entry >> 12;
ddt_entry &= 0xfff;
}
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
{
*sector_status = ddt_entry >> 28;
ddt_entry &= 0x0fffffff;
}
*sector_status = ddt_entry >> 28;
ddt_entry &= 0x0fffffff;
const uint64_t offset_mask = (uint64_t)((1 << ctx->userDataDdtHeader.dataShift) - 1);
*offset = ddt_entry & offset_mask;
@@ -1134,41 +1075,20 @@ bool set_ddt_single_level_v2(aaruformatContext *ctx, uint64_t sector_address, co
const uint64_t block_index = block_offset >> ctx->userDataDdtHeader.blockAlignmentShift;
*ddt_entry = offset & (1ULL << ctx->userDataDdtHeader.dataShift) - 1 | block_index
<< ctx->userDataDdtHeader.dataShift;
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
{ // Overflow detection for DDT entry
if(*ddt_entry > 0xFFF)
{
FATAL("DDT overflow: media does not fit in small DDT");
TRACE("Exiting set_ddt_single_level_v2() = false");
return false;
}
*ddt_entry |= (uint64_t)sector_status << 12;
}
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
// Overflow detection for DDT entry
if(*ddt_entry > 0xFFFFFFF)
{
// Overflow detection for DDT entry
if(*ddt_entry > 0xFFFFFFF)
{
FATAL("DDT overflow: media does not fit in big DDT");
TRACE("Exiting set_ddt_single_level_v2() = false");
return false;
}
*ddt_entry |= (uint64_t)sector_status << 28;
FATAL("DDT overflow: media does not fit in big DDT");
TRACE("Exiting set_ddt_single_level_v2() = false");
return false;
}
*ddt_entry |= (uint64_t)sector_status << 28;
}
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
{
TRACE("Setting small single-level DDT entry %d to %u", sector_address, (uint16_t)*ddt_entry);
ctx->userDataDdtMini[sector_address] = (uint16_t)*ddt_entry;
}
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
{
TRACE("Setting big single-level DDT entry %d to %u", sector_address, (uint32_t)*ddt_entry);
ctx->userDataDdtBig[sector_address] = (uint32_t)*ddt_entry;
}
TRACE("Setting big single-level DDT entry %d to %u", sector_address, (uint32_t)*ddt_entry);
ctx->userDataDdtBig[sector_address] = (uint32_t)*ddt_entry;
TRACE("Exiting set_ddt_single_level_v2() = true");
return true;
@@ -1234,9 +1154,7 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
items_per_ddt_entry = 1 << ctx->userDataDdtHeader.tableShift;
ddt_position = sector_address / items_per_ddt_entry;
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
secondary_ddt_offset = ctx->userDataDdtMini[ddt_position];
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
secondary_ddt_offset = ctx->userDataDdtBig[ddt_position];
else
{
@@ -1258,44 +1176,19 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
*ddt_entry = offset & (1ULL << ctx->userDataDdtHeader.dataShift) - 1 |
block_index << ctx->userDataDdtHeader.dataShift;
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
// Overflow detection for DDT entry
if(*ddt_entry > 0xFFFFFFF)
{
// Overflow detection for DDT entry
if(*ddt_entry > 0xFFF)
{
FATAL("DDT overflow: media does not fit in small DDT");
TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
}
*ddt_entry |= (uint64_t)sector_status << 12;
FATAL("DDT overflow: media does not fit in big DDT");
TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
}
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
{
// Overflow detection for DDT entry
if(*ddt_entry > 0xFFFFFFF)
{
FATAL("DDT overflow: media does not fit in big DDT");
TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
}
*ddt_entry |= (uint64_t)sector_status << 28;
}
*ddt_entry |= (uint64_t)sector_status << 28;
}
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
{
TRACE("Setting small secondary DDT entry %d to %u", sector_address % items_per_ddt_entry,
(uint16_t)*ddt_entry);
ctx->cachedSecondaryDdtSmall[sector_address % items_per_ddt_entry] = (uint16_t)*ddt_entry;
}
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
{
TRACE("Setting small secondary DDT entry %d to %u", sector_address % items_per_ddt_entry,
(uint16_t)*ddt_entry);
ctx->cachedSecondaryDdtBig[sector_address % items_per_ddt_entry] = (uint32_t)*ddt_entry;
}
TRACE("Setting small secondary DDT entry %d to %u", sector_address % items_per_ddt_entry, (uint16_t)*ddt_entry);
ctx->cachedSecondaryDdtBig[sector_address % items_per_ddt_entry] = (uint32_t)*ddt_entry;
TRACE("Updated cached secondary DDT entry at position %" PRIu64, sector_address % items_per_ddt_entry);
TRACE("Exiting set_ddt_multi_level_v2() = true");
@@ -1304,7 +1197,7 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
// Step 2.5: Handle case where we have a cached secondary DDT that has never been written to disk
// but does not contain the requested block
if(ctx->cachedDdtOffset == 0 && (ctx->cachedSecondaryDdtSmall != NULL || ctx->cachedSecondaryDdtBig != NULL))
if(ctx->cachedDdtOffset == 0 && (ctx->cachedSecondaryDdtBig != NULL))
{
// Only write the cached table to disk if the requested block belongs to a different DDT position
if(ddt_position != ctx->cachedDdtPosition)
@@ -1346,10 +1239,8 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
ddt_header.entries = items_per_ddt_entry;
// Calculate data size
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
ddt_header.length = items_per_ddt_entry * sizeof(uint16_t);
else
ddt_header.length = items_per_ddt_entry * sizeof(uint32_t);
ddt_header.length = items_per_ddt_entry * sizeof(uint32_t);
// Calculate CRC64 of the data
crc64_context = aaruf_crc64_init();
@@ -1360,10 +1251,7 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
return false;
}
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
aaruf_crc64_update(crc64_context, (uint8_t *)ctx->cachedSecondaryDdtSmall, (uint32_t)ddt_header.length);
else
aaruf_crc64_update(crc64_context, (uint8_t *)ctx->cachedSecondaryDdtBig, (uint32_t)ddt_header.length);
aaruf_crc64_update(crc64_context, (uint8_t *)ctx->cachedSecondaryDdtBig, (uint32_t)ddt_header.length);
aaruf_crc64_final(crc64_context, &crc64);
ddt_header.crc64 = crc64;
@@ -1373,10 +1261,8 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(ddt_header.compression == None)
{
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
cmp_buffer = (uint8_t *)ctx->cachedSecondaryDdtSmall;
else
cmp_buffer = (uint8_t *)ctx->cachedSecondaryDdtBig;
cmp_buffer = (uint8_t *)ctx->cachedSecondaryDdtBig;
ddt_header.cmpCrc64 = ddt_header.crc64;
}
else
@@ -1390,11 +1276,9 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
size_t dst_size = (size_t)ddt_header.length * 2 * 2;
size_t props_size = LZMA_PROPERTIES_LENGTH;
aaruf_lzma_encode_buffer(
cmp_buffer, &dst_size,
ctx->userDataDdtHeader.sizeType == SmallDdtSizeType ? (uint8_t *)ctx->cachedSecondaryDdtSmall
: (uint8_t *)ctx->cachedSecondaryDdtBig,
ddt_header.length, lzma_properties, &props_size, 9, ctx->lzma_dict_size, 4, 0, 2, 273, 8);
aaruf_lzma_encode_buffer(cmp_buffer, &dst_size, (uint8_t *)ctx->cachedSecondaryDdtBig,
ddt_header.length, lzma_properties, &props_size, 9, ctx->lzma_dict_size, 4, 0,
2, 273, 8);
ddt_header.cmpLength = (uint32_t)dst_size;
@@ -1402,10 +1286,8 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
{
ddt_header.compression = None;
free(cmp_buffer);
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
cmp_buffer = (uint8_t *)ctx->cachedSecondaryDdtSmall;
else
cmp_buffer = (uint8_t *)ctx->cachedSecondaryDdtBig;
cmp_buffer = (uint8_t *)ctx->cachedSecondaryDdtBig;
}
}
@@ -1452,23 +1334,15 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
// Update the primary level table entry to point to the new location of the secondary table
uint64_t new_secondary_table_block_offset = end_of_file >> ctx->userDataDdtHeader.blockAlignmentShift;
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
ctx->userDataDdtMini[ctx->cachedDdtPosition] = (uint16_t)new_secondary_table_block_offset;
else
ctx->userDataDdtBig[ctx->cachedDdtPosition] = (uint32_t)new_secondary_table_block_offset;
ctx->userDataDdtBig[ctx->cachedDdtPosition] = (uint32_t)new_secondary_table_block_offset;
// Write the updated primary table back to its original position in the file
long saved_pos = ftell(ctx->imageStream);
fseek(ctx->imageStream, ctx->primaryDdtOffset + sizeof(DdtHeader2), SEEK_SET);
size_t primary_table_size = ctx->userDataDdtHeader.sizeType == SmallDdtSizeType
? ctx->userDataDdtHeader.entries * sizeof(uint16_t)
: ctx->userDataDdtHeader.entries * sizeof(uint32_t);
size_t primary_table_size = ctx->userDataDdtHeader.entries * sizeof(uint32_t);
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
written_bytes = fwrite(ctx->userDataDdtMini, primary_table_size, 1, ctx->imageStream);
else
written_bytes = fwrite(ctx->userDataDdtBig, primary_table_size, 1, ctx->imageStream);
written_bytes = fwrite(ctx->userDataDdtBig, primary_table_size, 1, ctx->imageStream);
if(written_bytes != 1)
{
@@ -1485,16 +1359,9 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
TRACE("Updated nextBlockPosition after never-written DDT write to %" PRIu64, ctx->nextBlockPosition);
// Free the cached table
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType && ctx->cachedSecondaryDdtSmall)
{
free(ctx->cachedSecondaryDdtSmall);
ctx->cachedSecondaryDdtSmall = NULL;
}
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType && ctx->cachedSecondaryDdtBig)
{
free(ctx->cachedSecondaryDdtBig);
ctx->cachedSecondaryDdtBig = NULL;
}
free(ctx->cachedSecondaryDdtBig);
ctx->cachedSecondaryDdtBig = NULL;
// Reset cached values since we've written and freed the table
ctx->cachedDdtOffset = 0;
@@ -1549,10 +1416,8 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
ddt_header.entries = items_per_ddt_entry;
// Calculate data size
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
ddt_header.length = items_per_ddt_entry * sizeof(uint16_t);
else
ddt_header.length = items_per_ddt_entry * sizeof(uint32_t);
ddt_header.length = items_per_ddt_entry * sizeof(uint32_t);
// Calculate CRC64 of the data
crc64_context = aaruf_crc64_init();
@@ -1563,10 +1428,7 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
return false;
}
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
aaruf_crc64_update(crc64_context, (uint8_t *)ctx->cachedSecondaryDdtSmall, ddt_header.length);
else
aaruf_crc64_update(crc64_context, (uint8_t *)ctx->cachedSecondaryDdtBig, ddt_header.length);
aaruf_crc64_update(crc64_context, (uint8_t *)ctx->cachedSecondaryDdtBig, ddt_header.length);
aaruf_crc64_final(crc64_context, &crc64);
ddt_header.crc64 = crc64;
@@ -1576,10 +1438,8 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(ddt_header.compression == None)
{
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
cmp_buffer = (uint8_t *)ctx->cachedSecondaryDdtSmall;
else
cmp_buffer = (uint8_t *)ctx->cachedSecondaryDdtBig;
cmp_buffer = (uint8_t *)ctx->cachedSecondaryDdtBig;
ddt_header.cmpCrc64 = ddt_header.crc64;
}
else
@@ -1593,11 +1453,8 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
size_t dst_size = (size_t)ddt_header.length * 2 * 2;
size_t props_size = LZMA_PROPERTIES_LENGTH;
aaruf_lzma_encode_buffer(
cmp_buffer, &dst_size,
ctx->userDataDdtHeader.sizeType == SmallDdtSizeType ? (uint8_t *)ctx->cachedSecondaryDdtSmall
: (uint8_t *)ctx->cachedSecondaryDdtBig,
ddt_header.length, lzma_properties, &props_size, 9, ctx->lzma_dict_size, 4, 0, 2, 273, 8);
aaruf_lzma_encode_buffer(cmp_buffer, &dst_size, (uint8_t *)ctx->cachedSecondaryDdtBig, ddt_header.length,
lzma_properties, &props_size, 9, ctx->lzma_dict_size, 4, 0, 2, 273, 8);
ddt_header.cmpLength = (uint32_t)dst_size;
@@ -1605,10 +1462,8 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
{
ddt_header.compression = None;
free(cmp_buffer);
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
cmp_buffer = (uint8_t *)ctx->cachedSecondaryDdtSmall;
else
cmp_buffer = (uint8_t *)ctx->cachedSecondaryDdtBig;
cmp_buffer = (uint8_t *)ctx->cachedSecondaryDdtBig;
}
}
@@ -1681,23 +1536,16 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
// Update the primary table entry to point to the new location of the secondary table
// Use ddtPosition which was calculated from sectorAddress, not cachedDdtOffset
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
ctx->userDataDdtMini[ddt_position] = (uint16_t)new_secondary_table_block_offset;
else
ctx->userDataDdtBig[ddt_position] = (uint32_t)new_secondary_table_block_offset;
ctx->userDataDdtBig[ddt_position] = (uint32_t)new_secondary_table_block_offset;
// Write the updated primary table back to its original position in the file
long saved_pos = ftell(ctx->imageStream);
fseek(ctx->imageStream, ctx->primaryDdtOffset + sizeof(DdtHeader2), SEEK_SET);
size_t primary_table_size = ctx->userDataDdtHeader.sizeType == SmallDdtSizeType
? ctx->userDataDdtHeader.entries * sizeof(uint16_t)
: ctx->userDataDdtHeader.entries * sizeof(uint32_t);
size_t primary_table_size = ctx->userDataDdtHeader.entries * sizeof(uint32_t);
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
written_bytes = fwrite(ctx->userDataDdtMini, primary_table_size, 1, ctx->imageStream);
else
written_bytes = fwrite(ctx->userDataDdtBig, primary_table_size, 1, ctx->imageStream);
written_bytes = fwrite(ctx->userDataDdtBig, primary_table_size, 1, ctx->imageStream);
if(written_bytes != 1)
{
@@ -1716,23 +1564,16 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
fseek(ctx->imageStream, saved_pos, SEEK_SET);
// Free the cached table
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType && ctx->cachedSecondaryDdtSmall)
{
free(ctx->cachedSecondaryDdtSmall);
ctx->cachedSecondaryDdtSmall = NULL;
}
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType && ctx->cachedSecondaryDdtBig)
{
free(ctx->cachedSecondaryDdtBig);
ctx->cachedSecondaryDdtBig = NULL;
}
free(ctx->cachedSecondaryDdtBig);
ctx->cachedSecondaryDdtBig = NULL;
// Restore file position
fseek(ctx->imageStream, current_pos, SEEK_SET);
}
// Step 5: Check if the specified block already has an existing secondary level table
create_new_table = ctx->cachedSecondaryDdtSmall == NULL && ctx->cachedSecondaryDdtBig == NULL;
create_new_table = ctx->cachedSecondaryDdtBig == NULL;
if(!create_new_table && secondary_ddt_offset != 0)
{
@@ -1788,10 +1629,8 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
}
// Cache the loaded table
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
ctx->cachedSecondaryDdtSmall = (uint16_t *)buffer;
else
ctx->cachedSecondaryDdtBig = (uint32_t *)buffer;
ctx->cachedSecondaryDdtBig = (uint32_t *)buffer;
ctx->cachedDdtOffset = secondary_ddt_offset;
}
@@ -1799,9 +1638,7 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(create_new_table)
{
// Create a new empty table
size_t table_size = ctx->userDataDdtHeader.sizeType == SmallDdtSizeType
? items_per_ddt_entry * sizeof(uint16_t)
: items_per_ddt_entry * sizeof(uint32_t);
size_t table_size = items_per_ddt_entry * sizeof(uint32_t);
buffer = calloc(1, table_size);
if(buffer == NULL)
@@ -1811,10 +1648,7 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
return false;
}
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
ctx->cachedSecondaryDdtSmall = (uint16_t *)buffer;
else
ctx->cachedSecondaryDdtBig = (uint32_t *)buffer;
ctx->cachedSecondaryDdtBig = (uint32_t *)buffer;
ctx->cachedDdtOffset = 0; // Will be set when written to file
ctx->cachedDdtPosition = ddt_position; // Track which primary DDT position this new table belongs to
@@ -1828,42 +1662,19 @@ bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
*ddt_entry = offset & (1ULL << ctx->userDataDdtHeader.dataShift) - 1 | block_index
<< ctx->userDataDdtHeader.dataShift;
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
// Overflow detection for DDT entry
if(*ddt_entry > 0xFFFFFFF)
{
// Overflow detection for DDT entry
if(*ddt_entry > 0xFFF)
{
FATAL("DDT overflow: media does not fit in small DDT");
TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
}
*ddt_entry |= (uint64_t)sector_status << 12;
FATAL("DDT overflow: media does not fit in big DDT");
TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
}
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
{
// Overflow detection for DDT entry
if(*ddt_entry > 0xFFFFFFF)
{
FATAL("DDT overflow: media does not fit in big DDT");
TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
}
*ddt_entry |= (uint64_t)sector_status << 28;
}
*ddt_entry |= (uint64_t)sector_status << 28;
}
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
{
TRACE("Setting small secondary DDT entry %d to %u", sector_address % items_per_ddt_entry, (uint16_t)*ddt_entry);
ctx->cachedSecondaryDdtSmall[sector_address % items_per_ddt_entry] = (uint16_t)*ddt_entry;
}
else if(ctx->userDataDdtHeader.sizeType == BigDdtSizeType)
{
TRACE("Setting big secondary DDT entry %d to %u", sector_address % items_per_ddt_entry, (uint32_t)*ddt_entry);
ctx->cachedSecondaryDdtBig[sector_address % items_per_ddt_entry] = (uint32_t)*ddt_entry;
}
TRACE("Setting big secondary DDT entry %d to %u", sector_address % items_per_ddt_entry, (uint32_t)*ddt_entry);
ctx->cachedSecondaryDdtBig[sector_address % items_per_ddt_entry] = (uint32_t)*ddt_entry;
TRACE("Updated secondary DDT entry at position %" PRIu64, sector_address % items_per_ddt_entry);
TRACE("Exiting set_ddt_multi_level_v2() = true");

View File

@@ -371,8 +371,8 @@ int32_t aaruf_write_sector(void *context, uint64_t sector_address, bool negative
*
* **Memory Management Strategy:**
* - **Mini-DDT Arrays**: Lazily allocated 16-bit arrays sized for total addressable space (negative + user + overflow)
* * sectorPrefixDdtMini: Tracks prefix status and buffer offsets (high 4 bits = status, low 12 bits = offset/16)
* * sectorSuffixDdtMini: Tracks suffix status and buffer offsets (high 4 bits = status, low 12 bits = offset/288)
* * sectorPrefixDdt2: Tracks prefix status and buffer offsets (high 4 bits = status, low 12 bits = offset/16)
* * sectorSuffixDdt2: Tracks suffix status and buffer offsets (high 4 bits = status, low 12 bits = offset/288)
* - **Prefix Buffer**: Dynamically growing buffer storing non-standard 16-byte CD prefixes
* - **Suffix Buffer**: Dynamically growing buffer storing non-standard CD suffixes (288 bytes for Mode 1, 4 bytes for
* Mode 2 Form 2, 280 bytes for Mode 2 Form 1)
@@ -468,7 +468,7 @@ int32_t aaruf_write_sector(void *context, uint64_t sector_address, bool negative
* - length not in {512, 524, 532, 536} for supported block media types
*
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-9) Memory allocation failed. This occurs when:
* - Failed to allocate mini-DDT arrays (sectorPrefixDdtMini, sectorSuffixDdtMini)
* - Failed to allocate mini-DDT arrays (sectorPrefixDdt2, sectorSuffixDdt2)
* - Failed to allocate or grow prefix buffer (sector_prefix)
* - Failed to allocate or grow suffix buffer (sector_suffix)
* - Failed to allocate subheader buffer (mode2_subheaders)
@@ -686,13 +686,13 @@ int32_t aaruf_write_sector_long(void *context, uint64_t sector_address, bool neg
case CdMode1:
// If we do not have a DDT V2 for sector prefix, create one
if(ctx->sectorPrefixDdtMini == NULL)
if(ctx->sectorPrefixDdt2 == NULL)
{
ctx->sectorPrefixDdtMini =
calloc(1, sizeof(uint16_t) * (ctx->userDataDdtHeader.negative + ctx->imageInfo.Sectors +
ctx->sectorPrefixDdt2 =
calloc(1, sizeof(uint32_t) * (ctx->userDataDdtHeader.negative + ctx->imageInfo.Sectors +
ctx->userDataDdtHeader.overflow));
if(ctx->sectorPrefixDdtMini == NULL)
if(ctx->sectorPrefixDdt2 == NULL)
{
FATAL("Could not allocate memory for CD sector prefix DDT");
@@ -702,13 +702,13 @@ int32_t aaruf_write_sector_long(void *context, uint64_t sector_address, bool neg
}
// If we do not have a DDT V2 for sector suffix, create one
if(ctx->sectorSuffixDdtMini == NULL)
if(ctx->sectorSuffixDdt2 == NULL)
{
ctx->sectorSuffixDdtMini =
calloc(1, sizeof(uint16_t) * (ctx->userDataDdtHeader.negative + ctx->imageInfo.Sectors +
ctx->sectorSuffixDdt2 =
calloc(1, sizeof(uint32_t) * (ctx->userDataDdtHeader.negative + ctx->imageInfo.Sectors +
ctx->userDataDdtHeader.overflow));
if(ctx->sectorSuffixDdtMini == NULL)
if(ctx->sectorSuffixDdt2 == NULL)
{
FATAL("Could not allocate memory for CD sector prefix DDT");
@@ -758,8 +758,8 @@ int32_t aaruf_write_sector_long(void *context, uint64_t sector_address, bool neg
if(empty)
{
ctx->sectorPrefixDdtMini[corrected_sector_address] = SectorStatusNotDumped;
ctx->sectorSuffixDdtMini[corrected_sector_address] = SectorStatusNotDumped;
ctx->sectorPrefixDdt2[corrected_sector_address] = SectorStatusNotDumped;
ctx->sectorSuffixDdt2[corrected_sector_address] = SectorStatusNotDumped;
return aaruf_write_sector(context, sector_address, negative, data + 16, SectorStatusNotDumped,
2048);
}
@@ -782,13 +782,13 @@ int32_t aaruf_write_sector_long(void *context, uint64_t sector_address, bool neg
}
if(prefix_correct)
ctx->sectorPrefixDdtMini[corrected_sector_address] = SectorStatusMode1Correct << 12;
ctx->sectorPrefixDdt2[corrected_sector_address] = SectorStatusMode1Correct << 28;
else
{
// Copy CD prefix from data buffer to prefix buffer
memcpy(ctx->sector_prefix + ctx->sector_prefix_offset, data, 16);
ctx->sectorPrefixDdtMini[corrected_sector_address] = (uint16_t)(ctx->sector_prefix_offset / 16);
ctx->sectorPrefixDdtMini[corrected_sector_address] |= SectorStatusErrored << 12;
ctx->sectorPrefixDdt2[corrected_sector_address] = (uint32_t)(ctx->sector_prefix_offset / 16);
ctx->sectorPrefixDdt2[corrected_sector_address] |= SectorStatusErrored << 28;
ctx->sector_prefix_offset += 16;
// Grow prefix buffer if needed
@@ -810,14 +810,13 @@ int32_t aaruf_write_sector_long(void *context, uint64_t sector_address, bool neg
const bool suffix_correct = aaruf_ecc_cd_is_suffix_correct(context, data);
if(suffix_correct)
ctx->sectorSuffixDdtMini[corrected_sector_address] = SectorStatusMode1Correct << 12;
ctx->sectorSuffixDdt2[corrected_sector_address] = SectorStatusMode1Correct << 28;
else
{
// Copy CD suffix from data buffer to suffix buffer
memcpy(ctx->sector_suffix + ctx->sector_suffix_offset, data + 2064, 288);
ctx->sectorSuffixDdtMini[corrected_sector_address] =
(uint16_t)(ctx->sector_suffix_offset / 288);
ctx->sectorSuffixDdtMini[corrected_sector_address] |= SectorStatusErrored << 12;
ctx->sectorSuffixDdt2[corrected_sector_address] = (uint32_t)(ctx->sector_suffix_offset / 288);
ctx->sectorSuffixDdt2[corrected_sector_address] |= SectorStatusErrored << 28;
ctx->sector_suffix_offset += 288;
// Grow suffix buffer if needed
@@ -842,13 +841,13 @@ int32_t aaruf_write_sector_long(void *context, uint64_t sector_address, bool neg
case CdMode2Form2:
case CdMode2Formless:
// If we do not have a DDT V2 for sector prefix, create one
if(ctx->sectorPrefixDdtMini == NULL)
if(ctx->sectorPrefixDdt2 == NULL)
{
ctx->sectorPrefixDdtMini =
calloc(1, sizeof(uint16_t) * (ctx->userDataDdtHeader.negative + ctx->imageInfo.Sectors +
ctx->sectorPrefixDdt2 =
calloc(1, sizeof(uint32_t) * (ctx->userDataDdtHeader.negative + ctx->imageInfo.Sectors +
ctx->userDataDdtHeader.overflow));
if(ctx->sectorPrefixDdtMini == NULL)
if(ctx->sectorPrefixDdt2 == NULL)
{
FATAL("Could not allocate memory for CD sector prefix DDT");
@@ -858,13 +857,13 @@ int32_t aaruf_write_sector_long(void *context, uint64_t sector_address, bool neg
}
// If we do not have a DDT V2 for sector suffix, create one
if(ctx->sectorSuffixDdtMini == NULL)
if(ctx->sectorSuffixDdt2 == NULL)
{
ctx->sectorSuffixDdtMini =
calloc(1, sizeof(uint16_t) * (ctx->userDataDdtHeader.negative + ctx->imageInfo.Sectors +
ctx->sectorSuffixDdt2 =
calloc(1, sizeof(uint32_t) * (ctx->userDataDdtHeader.negative + ctx->imageInfo.Sectors +
ctx->userDataDdtHeader.overflow));
if(ctx->sectorSuffixDdtMini == NULL)
if(ctx->sectorSuffixDdt2 == NULL)
{
FATAL("Could not allocate memory for CD sector prefix DDT");
@@ -914,8 +913,8 @@ int32_t aaruf_write_sector_long(void *context, uint64_t sector_address, bool neg
if(empty)
{
ctx->sectorPrefixDdtMini[corrected_sector_address] = SectorStatusNotDumped;
ctx->sectorSuffixDdtMini[corrected_sector_address] = SectorStatusNotDumped;
ctx->sectorPrefixDdt2[corrected_sector_address] = SectorStatusNotDumped;
ctx->sectorSuffixDdt2[corrected_sector_address] = SectorStatusNotDumped;
return aaruf_write_sector(context, sector_address, negative, data + 16, SectorStatusNotDumped,
2328);
}
@@ -940,14 +939,14 @@ int32_t aaruf_write_sector_long(void *context, uint64_t sector_address, bool neg
}
if(prefix_correct)
ctx->sectorPrefixDdtMini[corrected_sector_address] =
(form2 ? SectorStatusMode2Form2Ok : SectorStatusMode2Form1Ok) << 12;
ctx->sectorPrefixDdt2[corrected_sector_address] =
(form2 ? SectorStatusMode2Form2Ok : SectorStatusMode2Form1Ok) << 28;
else
{
// Copy CD prefix from data buffer to prefix buffer
memcpy(ctx->sector_prefix + ctx->sector_prefix_offset, data, 16);
ctx->sectorPrefixDdtMini[corrected_sector_address] = (uint16_t)(ctx->sector_prefix_offset / 16);
ctx->sectorPrefixDdtMini[corrected_sector_address] |= SectorStatusErrored << 12;
ctx->sectorPrefixDdt2[corrected_sector_address] = (uint32_t)(ctx->sector_prefix_offset / 16);
ctx->sectorPrefixDdt2[corrected_sector_address] |= SectorStatusErrored << 28;
ctx->sector_prefix_offset += 16;
// Grow prefix buffer if needed
@@ -989,16 +988,16 @@ int32_t aaruf_write_sector_long(void *context, uint64_t sector_address, bool neg
const bool correct_edc = computed_edc == edc;
if(correct_edc)
ctx->sectorSuffixDdtMini[corrected_sector_address] = SectorStatusMode2Form2Ok << 12;
ctx->sectorSuffixDdt2[corrected_sector_address] = SectorStatusMode2Form2Ok << 28;
else if(edc == 0)
ctx->sectorSuffixDdtMini[corrected_sector_address] = SectorStatusMode2Form2NoCrc << 12;
ctx->sectorSuffixDdt2[corrected_sector_address] = SectorStatusMode2Form2NoCrc << 28;
else
{
// Copy CD suffix from data buffer to suffix buffer
memcpy(ctx->sector_suffix + ctx->sector_suffix_offset, data + 2348, 4);
ctx->sectorSuffixDdtMini[corrected_sector_address] =
(uint16_t)(ctx->sector_suffix_offset / 288);
ctx->sectorSuffixDdtMini[corrected_sector_address] |= SectorStatusErrored << 12;
ctx->sectorSuffixDdt2[corrected_sector_address] =
(uint32_t)(ctx->sector_suffix_offset / 288);
ctx->sectorSuffixDdt2[corrected_sector_address] |= SectorStatusErrored << 28;
ctx->sector_suffix_offset += 288;
// Grow suffix buffer if needed
@@ -1033,14 +1032,13 @@ int32_t aaruf_write_sector_long(void *context, uint64_t sector_address, bool neg
const bool correct_edc = computed_edc == edc;
if(correct_ecc && correct_edc)
ctx->sectorSuffixDdtMini[corrected_sector_address] = SectorStatusMode2Form1Ok << 12;
ctx->sectorSuffixDdt2[corrected_sector_address] = SectorStatusMode2Form1Ok << 28;
else
{
// Copy CD suffix from data buffer to suffix buffer
memcpy(ctx->sector_suffix + ctx->sector_suffix_offset, data + 2072, 280);
ctx->sectorSuffixDdtMini[corrected_sector_address] =
(uint16_t)(ctx->sector_suffix_offset / 288);
ctx->sectorSuffixDdtMini[corrected_sector_address] |= SectorStatusErrored << 12;
ctx->sectorSuffixDdt2[corrected_sector_address] = (uint32_t)(ctx->sector_suffix_offset / 288);
ctx->sectorSuffixDdt2[corrected_sector_address] |= SectorStatusErrored << 28;
ctx->sector_suffix_offset += 288;
// Grow suffix buffer if needed