Add error code for DDT entry setting failure and update related functions to return status

This commit is contained in:
2025-09-30 18:47:38 +01:00
parent ae402f2fd1
commit 495a5bc55a
4 changed files with 88 additions and 36 deletions

View File

@@ -43,6 +43,7 @@
#define AARUF_READ_ONLY -22 #define AARUF_READ_ONLY -22
#define AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER -23 #define AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER -23
#define AARUF_ERROR_CANNOT_WRITE_BLOCK_DATA -24 #define AARUF_ERROR_CANNOT_WRITE_BLOCK_DATA -24
#define AARUF_ERROR_CANNOT_SET_DDT_ENTRY -25
#define AARUF_STATUS_OK 0 #define AARUF_STATUS_OK 0
#define AARUF_STATUS_SECTOR_NOT_DUMPED 1 #define AARUF_STATUS_SECTOR_NOT_DUMPED 1

View File

@@ -45,11 +45,11 @@ int32_t decode_ddt_single_level_v2(aaruformatContext *ctx, uint64_t sector_add
uint64_t *block_offset, uint8_t *sector_status); uint64_t *block_offset, uint8_t *sector_status);
int32_t decode_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, uint64_t *offset, int32_t decode_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, uint64_t *offset,
uint64_t *block_offset, uint8_t *sector_status); uint64_t *block_offset, uint8_t *sector_status);
void set_ddt_entry_v2(aaruformatContext *ctx, uint64_t sector_address, uint64_t offset, uint64_t block_offset, bool set_ddt_entry_v2(aaruformatContext *ctx, uint64_t sector_address, uint64_t offset, uint64_t block_offset,
uint8_t sector_status); uint8_t sector_status);
void set_ddt_single_level_v2(aaruformatContext *ctx, uint64_t sector_address, bool negative, uint64_t offset, bool set_ddt_single_level_v2(aaruformatContext *ctx, uint64_t sector_address, bool negative, uint64_t offset,
uint64_t block_offset, uint8_t sector_status); uint64_t block_offset, uint8_t sector_status);
void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, bool negative, uint64_t offset, bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, bool negative, uint64_t offset,
uint64_t block_offset, uint8_t sector_status); uint64_t block_offset, uint8_t sector_status);
aaru_options parse_options(const char *options); aaru_options parse_options(const char *options);
uint64_t get_filetime_uint64(); uint64_t get_filetime_uint64();

View File

@@ -1025,8 +1025,11 @@ int32_t decode_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_addres
* @param offset Offset to set for the sector. * @param offset Offset to set for the sector.
* @param block_offset Block offset to set for the sector. * @param block_offset Block offset to set for the sector.
* @param sector_status Status to set for the sector. * @param sector_status Status to set for the sector.
*
* @return Returns one of the following status codes:
* @retval true if the entry was set successfully, false otherwise.
*/ */
void set_ddt_entry_v2(aaruformatContext *ctx, uint64_t sector_address, uint64_t offset, uint64_t block_offset, bool set_ddt_entry_v2(aaruformatContext *ctx, uint64_t sector_address, uint64_t offset, uint64_t block_offset,
uint8_t sector_status) uint8_t sector_status)
{ {
TRACE("Entering set_ddt_entry_v2(%p, %" PRIu64 ", %llu, %llu, %d)", ctx, sector_address, offset, block_offset, TRACE("Entering set_ddt_entry_v2(%p, %" PRIu64 ", %llu, %llu, %d)", ctx, sector_address, offset, block_offset,
@@ -1040,9 +1043,9 @@ void set_ddt_entry_v2(aaruformatContext *ctx, uint64_t sector_address, uint64_t
} }
if(ctx->userDataDdtHeader.tableShift > 0) if(ctx->userDataDdtHeader.tableShift > 0)
set_ddt_multi_level_v2(ctx, sector_address, false, offset, block_offset, sector_status); return set_ddt_multi_level_v2(ctx, sector_address, false, offset, block_offset, sector_status);
else
set_ddt_single_level_v2(ctx, sector_address, false, offset, block_offset, sector_status); return set_ddt_single_level_v2(ctx, sector_address, false, offset, block_offset, sector_status);
} }
/** /**
@@ -1056,8 +1059,11 @@ void set_ddt_entry_v2(aaruformatContext *ctx, uint64_t sector_address, uint64_t
* @param offset Offset to set for the sector. * @param offset Offset to set for the sector.
* @param block_offset Block offset to set for the sector. * @param block_offset Block offset to set for the sector.
* @param sector_status Status to set for the sector. * @param sector_status Status to set for the sector.
*
* @return Returns one of the following status codes:
* @retval true if the entry was set successfully, false otherwise.
*/ */
void set_ddt_single_level_v2(aaruformatContext *ctx, uint64_t sector_address, bool negative, uint64_t offset, bool set_ddt_single_level_v2(aaruformatContext *ctx, uint64_t sector_address, bool negative, uint64_t offset,
uint64_t block_offset, uint8_t sector_status) uint64_t block_offset, uint8_t sector_status)
{ {
TRACE("Entering set_ddt_single_level_v2(%p, %" PRIu64 ", %llu, %llu, %d)", ctx, sector_address, offset, TRACE("Entering set_ddt_single_level_v2(%p, %" PRIu64 ", %llu, %llu, %d)", ctx, sector_address, offset,
@@ -1067,14 +1073,16 @@ void set_ddt_single_level_v2(aaruformatContext *ctx, uint64_t sector_address, bo
if(ctx == NULL || ctx->imageStream == NULL) if(ctx == NULL || ctx->imageStream == NULL)
{ {
FATAL("Invalid context or image stream."); FATAL("Invalid context or image stream.");
return; TRACE("Exiting set_ddt_single_level_v2() = false");
return false;
} }
// Should not really be here // Should not really be here
if(ctx->userDataDdtHeader.tableShift != 0) if(ctx->userDataDdtHeader.tableShift != 0)
{ {
FATAL("DDT table shift is not zero, but we are in single-level DDT setting."); FATAL("DDT table shift is not zero, but we are in single-level DDT setting.");
return; TRACE("Exiting set_ddt_single_level_v2() = false");
return false;
} }
// Calculate positive or negative sector // Calculate positive or negative sector
@@ -1095,7 +1103,8 @@ void set_ddt_single_level_v2(aaruformatContext *ctx, uint64_t sector_address, bo
if(ddt_entry > 0xFFF) if(ddt_entry > 0xFFF)
{ {
FATAL("DDT overflow: media does not fit in small DDT"); FATAL("DDT overflow: media does not fit in small DDT");
return; TRACE("Exiting set_ddt_single_level_v2() = false");
return false;
} }
ddt_entry |= (uint64_t)sector_status << 12; ddt_entry |= (uint64_t)sector_status << 12;
@@ -1107,12 +1116,16 @@ void set_ddt_single_level_v2(aaruformatContext *ctx, uint64_t sector_address, bo
if(ddt_entry > 0xFFFFFFF) if(ddt_entry > 0xFFFFFFF)
{ {
FATAL("DDT overflow: media does not fit in big DDT"); FATAL("DDT overflow: media does not fit in big DDT");
return; TRACE("Exiting set_ddt_single_level_v2() = false");
return false;
} }
ddt_entry |= (uint64_t)sector_status << 28; ddt_entry |= (uint64_t)sector_status << 28;
ctx->cachedSecondaryDdtBig[sector_address] = (uint32_t)ddt_entry; ctx->cachedSecondaryDdtBig[sector_address] = (uint32_t)ddt_entry;
} }
TRACE("Exiting set_ddt_single_level_v2() = true");
return true;
} }
/** /**
@@ -1126,8 +1139,11 @@ void set_ddt_single_level_v2(aaruformatContext *ctx, uint64_t sector_address, bo
* @param offset Offset to set for the sector. * @param offset Offset to set for the sector.
* @param block_offset Block offset to set for the sector. * @param block_offset Block offset to set for the sector.
* @param sector_status Status to set for the sector. * @param sector_status Status to set for the sector.
*
* @return Returns one of the following status codes:
* @retval true if the entry was set successfully, false otherwise.
*/ */
void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, bool negative, uint64_t offset, bool set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, bool negative, uint64_t offset,
uint64_t block_offset, uint8_t sector_status) uint64_t block_offset, uint8_t sector_status)
{ {
TRACE("Entering set_ddt_multi_level_v2(%p, %" PRIu64 ", %d, %" PRIu64 ", %" PRIu64 ", %d)", ctx, sector_address, TRACE("Entering set_ddt_multi_level_v2(%p, %" PRIu64 ", %d, %" PRIu64 ", %" PRIu64 ", %d)", ctx, sector_address,
@@ -1151,14 +1167,16 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(ctx == NULL || ctx->imageStream == NULL) if(ctx == NULL || ctx->imageStream == NULL)
{ {
FATAL("Invalid context or image stream."); FATAL("Invalid context or image stream.");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
// Should not really be here // Should not really be here
if(ctx->userDataDdtHeader.tableShift == 0) if(ctx->userDataDdtHeader.tableShift == 0)
{ {
FATAL("DDT table shift is zero, but we are in multi-level DDT setting."); FATAL("DDT table shift is zero, but we are in multi-level DDT setting.");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
// Calculate positive or negative sector // Calculate positive or negative sector
@@ -1178,7 +1196,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
else else
{ {
FATAL("Unknown DDT size type %d.", ctx->userDataDdtHeader.sizeType); FATAL("Unknown DDT size type %d.", ctx->userDataDdtHeader.sizeType);
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
// Position in file of the child DDT table // Position in file of the child DDT table
@@ -1198,7 +1217,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(ddt_entry > 0xFFF) if(ddt_entry > 0xFFF)
{ {
FATAL("DDT overflow: media does not fit in small DDT"); FATAL("DDT overflow: media does not fit in small DDT");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
ddt_entry |= (uint64_t)sector_status << 12; ddt_entry |= (uint64_t)sector_status << 12;
@@ -1212,6 +1232,7 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(ddt_entry > 0xFFFFFFF) if(ddt_entry > 0xFFFFFFF)
{ {
FATAL("DDT overflow: media does not fit in big DDT"); FATAL("DDT overflow: media does not fit in big DDT");
TRACE("Exiting set_ddt_multi_level_v2() = false");
return; return;
} }
@@ -1222,7 +1243,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
} }
TRACE("Updated cached secondary DDT entry at position %" PRIu64, sector_address % items_per_ddt_entry); TRACE("Updated cached secondary DDT entry at position %" PRIu64, sector_address % items_per_ddt_entry);
return; TRACE("Exiting set_ddt_multi_level_v2() = true");
return true;
} }
// Step 2.5: Handle case where we have a cached secondary DDT that has never been written to disk // Step 2.5: Handle case where we have a cached secondary DDT that has never been written to disk
@@ -1282,7 +1304,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(crc64_context == NULL) if(crc64_context == NULL)
{ {
FATAL("Could not initialize CRC64."); FATAL("Could not initialize CRC64.");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType) if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
@@ -1299,7 +1322,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(written_bytes != 1) if(written_bytes != 1)
{ {
FATAL("Could not write never-written DDT header to file."); FATAL("Could not write never-written DDT header to file.");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
// Write data // Write data
@@ -1311,7 +1335,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(written_bytes != 1) if(written_bytes != 1)
{ {
FATAL("Could not write never-written DDT data to file."); FATAL("Could not write never-written DDT data to file.");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
// Add index entry for the newly written secondary DDT // Add index entry for the newly written secondary DDT
@@ -1347,7 +1372,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(written_bytes != 1) if(written_bytes != 1)
{ {
FATAL("Could not flush primary DDT table to file after writing never-written secondary table."); FATAL("Could not flush primary DDT table to file after writing never-written secondary table.");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
// Update nextBlockPosition to ensure future blocks don't overwrite the DDT // Update nextBlockPosition to ensure future blocks don't overwrite the DDT
@@ -1433,7 +1459,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(crc64_context == NULL) if(crc64_context == NULL)
{ {
FATAL("Could not initialize CRC64."); FATAL("Could not initialize CRC64.");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType) if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
@@ -1450,7 +1477,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(written_bytes != 1) if(written_bytes != 1)
{ {
FATAL("Could not write DDT header to file."); FATAL("Could not write DDT header to file.");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
// Write data // Write data
@@ -1462,7 +1490,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(written_bytes != 1) if(written_bytes != 1)
{ {
FATAL("Could not write DDT data to file."); FATAL("Could not write DDT data to file.");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
// Update index: remove old entry and add new one for the evicted secondary DDT // Update index: remove old entry and add new one for the evicted secondary DDT
@@ -1522,7 +1551,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(written_bytes != 1) if(written_bytes != 1)
{ {
FATAL("Could not flush primary DDT table to file."); FATAL("Could not flush primary DDT table to file.");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
// Update nextBlockPosition to ensure future blocks don't overwrite the DDT // Update nextBlockPosition to ensure future blocks don't overwrite the DDT
@@ -1563,7 +1593,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
ddt_header.type != UserData) ddt_header.type != UserData)
{ {
FATAL("Invalid secondary DDT header at %" PRIu64, secondaryDdtOffset); FATAL("Invalid secondary DDT header at %" PRIu64, secondaryDdtOffset);
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
// Read the table data (assuming no compression for now) // Read the table data (assuming no compression for now)
@@ -1571,7 +1602,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(buffer == NULL) if(buffer == NULL)
{ {
FATAL("Cannot allocate memory for secondary DDT."); FATAL("Cannot allocate memory for secondary DDT.");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
read_bytes = fread(buffer, 1, ddt_header.length, ctx->imageStream); read_bytes = fread(buffer, 1, ddt_header.length, ctx->imageStream);
@@ -1579,7 +1611,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
{ {
FATAL("Could not read secondary DDT data."); FATAL("Could not read secondary DDT data.");
free(buffer); free(buffer);
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
// Verify CRC // Verify CRC
@@ -1588,7 +1621,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
{ {
FATAL("Could not initialize CRC64."); FATAL("Could not initialize CRC64.");
free(buffer); free(buffer);
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
aaruf_crc64_update(crc64_context, buffer, read_bytes); aaruf_crc64_update(crc64_context, buffer, read_bytes);
@@ -1598,7 +1632,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
{ {
FATAL("Secondary DDT CRC mismatch. Expected 0x%16lX but got 0x%16lX.", ddtHeader.crc64, crc64); FATAL("Secondary DDT CRC mismatch. Expected 0x%16lX but got 0x%16lX.", ddtHeader.crc64, crc64);
free(buffer); free(buffer);
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
// Cache the loaded table // Cache the loaded table
@@ -1621,7 +1656,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(buffer == NULL) if(buffer == NULL)
{ {
FATAL("Cannot allocate memory for new secondary DDT."); FATAL("Cannot allocate memory for new secondary DDT.");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType) if(ctx->userDataDdtHeader.sizeType == SmallDdtSizeType)
@@ -1645,7 +1681,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(ddt_entry > 0xFFF) if(ddt_entry > 0xFFF)
{ {
FATAL("DDT overflow: media does not fit in small DDT"); FATAL("DDT overflow: media does not fit in small DDT");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
ddt_entry |= (uint64_t)sector_status << 12; ddt_entry |= (uint64_t)sector_status << 12;
@@ -1658,7 +1695,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
if(ddt_entry > 0xFFFFFFF) if(ddt_entry > 0xFFFFFFF)
{ {
FATAL("DDT overflow: media does not fit in big DDT"); FATAL("DDT overflow: media does not fit in big DDT");
return; TRACE("Exiting set_ddt_multi_level_v2() = false");
return false;
} }
ddt_entry |= (uint64_t)sector_status << 28; ddt_entry |= (uint64_t)sector_status << 28;
@@ -1667,5 +1705,6 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo
} }
TRACE("Updated secondary DDT entry at position %" PRIu64, sector_address % items_per_ddt_entry); TRACE("Updated secondary DDT entry at position %" PRIu64, sector_address % items_per_ddt_entry);
TRACE("Exiting set_ddt_multi_level_v2()"); TRACE("Exiting set_ddt_multi_level_v2() = true");
return true;
} }

View File

@@ -68,6 +68,12 @@
* - The fwrite() call for the block data fails * - The fwrite() call for the block data fails
* - Disk space is insufficient or file system errors occur * - Disk space is insufficient or file system errors occur
* *
* @retval AARUF_ERROR_CANNOT_SET_DDT_ENTRY (-25) Failed to update the deduplication table (DDT) entry.
* This occurs when:
* - The DDT entry for the specified sector address could not be set or updated
* - Internal DDT management functions return failure
* - DDT table corruption or memory issues prevent entry updates
*
* @note Block Management: * @note Block Management:
* - The function automatically closes the current block when sector size changes * - The function automatically closes the current block when sector size changes
* - Blocks are also closed when they reach the maximum size (determined by dataShift) * - Blocks are also closed when they reach the maximum size (determined by dataShift)
@@ -149,7 +155,13 @@ int32_t aaruf_write_sector(void *context, uint64_t sector_address, const uint8_t
} }
} }
set_ddt_entry_v2(ctx, sector_address, ctx->currentBlockOffset, ctx->nextBlockPosition, sector_status); bool ddt_ok = set_ddt_entry_v2(ctx, sector_address, ctx->currentBlockOffset, ctx->nextBlockPosition, sector_status);
if(!ddt_ok)
{
TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_CANNOT_SET_DDT_ENTRY");
return AARUF_ERROR_CANNOT_SET_DDT_ENTRY;
}
// No block set // No block set
if(ctx->writingBufferPosition == 0) if(ctx->writingBufferPosition == 0)