diff --git a/include/aaruformat/errors.h b/include/aaruformat/errors.h index 0fc3781..2288cab 100644 --- a/include/aaruformat/errors.h +++ b/include/aaruformat/errors.h @@ -43,6 +43,7 @@ #define AARUF_READ_ONLY -22 #define AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER -23 #define AARUF_ERROR_CANNOT_WRITE_BLOCK_DATA -24 +#define AARUF_ERROR_CANNOT_SET_DDT_ENTRY -25 #define AARUF_STATUS_OK 0 #define AARUF_STATUS_SECTOR_NOT_DUMPED 1 diff --git a/include/internal.h b/include/internal.h index cfd3d33..456c076 100644 --- a/include/internal.h +++ b/include/internal.h @@ -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); int32_t decode_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, uint64_t *offset, 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); -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); -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); aaru_options parse_options(const char *options); uint64_t get_filetime_uint64(); diff --git a/src/ddt/ddt_v2.c b/src/ddt/ddt_v2.c index 851ff43..5ed88f7 100644 --- a/src/ddt/ddt_v2.c +++ b/src/ddt/ddt_v2.c @@ -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 block_offset Block offset 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) { 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) - 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_multi_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 block_offset Block offset 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) { 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) { FATAL("Invalid context or image stream."); - return; + TRACE("Exiting set_ddt_single_level_v2() = false"); + return false; } // Should not really be here if(ctx->userDataDdtHeader.tableShift != 0) { 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 @@ -1095,7 +1103,8 @@ void set_ddt_single_level_v2(aaruformatContext *ctx, uint64_t sector_address, bo if(ddt_entry > 0xFFF) { 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; @@ -1107,12 +1116,16 @@ void set_ddt_single_level_v2(aaruformatContext *ctx, uint64_t sector_address, bo if(ddt_entry > 0xFFFFFFF) { 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; 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 block_offset Block offset 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) { 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) { FATAL("Invalid context or image stream."); - return; + TRACE("Exiting set_ddt_multi_level_v2() = false"); + return false; } // Should not really be here if(ctx->userDataDdtHeader.tableShift == 0) { 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 @@ -1178,7 +1196,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo else { 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 @@ -1198,7 +1217,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo if(ddt_entry > 0xFFF) { 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; @@ -1212,6 +1232,7 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo if(ddt_entry > 0xFFFFFFF) { FATAL("DDT overflow: media does not fit in big DDT"); + TRACE("Exiting set_ddt_multi_level_v2() = false"); 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); - 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 @@ -1282,7 +1304,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo if(crc64_context == NULL) { FATAL("Could not initialize CRC64."); - return; + TRACE("Exiting set_ddt_multi_level_v2() = false"); + return false; } 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) { FATAL("Could not write never-written DDT header to file."); - return; + TRACE("Exiting set_ddt_multi_level_v2() = false"); + return false; } // Write data @@ -1311,7 +1335,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo if(written_bytes != 1) { 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 @@ -1347,7 +1372,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo if(written_bytes != 1) { 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 @@ -1433,7 +1459,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo if(crc64_context == NULL) { FATAL("Could not initialize CRC64."); - return; + TRACE("Exiting set_ddt_multi_level_v2() = false"); + return false; } 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) { FATAL("Could not write DDT header to file."); - return; + TRACE("Exiting set_ddt_multi_level_v2() = false"); + return false; } // Write data @@ -1462,7 +1490,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo if(written_bytes != 1) { 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 @@ -1522,7 +1551,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo if(written_bytes != 1) { 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 @@ -1563,7 +1593,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo ddt_header.type != UserData) { 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) @@ -1571,7 +1602,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo if(buffer == NULL) { 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); @@ -1579,7 +1611,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo { FATAL("Could not read secondary DDT data."); free(buffer); - return; + TRACE("Exiting set_ddt_multi_level_v2() = false"); + return false; } // Verify CRC @@ -1588,7 +1621,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo { FATAL("Could not initialize CRC64."); free(buffer); - return; + TRACE("Exiting set_ddt_multi_level_v2() = false"); + return false; } 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); free(buffer); - return; + TRACE("Exiting set_ddt_multi_level_v2() = false"); + return false; } // Cache the loaded table @@ -1621,7 +1656,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo if(buffer == NULL) { FATAL("Cannot allocate memory for new secondary DDT."); - return; + TRACE("Exiting set_ddt_multi_level_v2() = false"); + return false; } 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) { 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; @@ -1658,7 +1695,8 @@ void set_ddt_multi_level_v2(aaruformatContext *ctx, uint64_t sector_address, boo if(ddt_entry > 0xFFFFFFF) { 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; @@ -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("Exiting set_ddt_multi_level_v2()"); + TRACE("Exiting set_ddt_multi_level_v2() = true"); + return true; } diff --git a/src/write.c b/src/write.c index 96033b2..57b0d1f 100644 --- a/src/write.c +++ b/src/write.c @@ -68,6 +68,12 @@ * - The fwrite() call for the block data fails * - 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: * - The function automatically closes the current block when sector size changes * - 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 if(ctx->writingBufferPosition == 0)