Recover damaged headers.

This commit is contained in:
2026-04-11 21:27:25 +01:00
parent 6f7cfbdf5e
commit 640ec68146
2 changed files with 71 additions and 5 deletions

View File

@@ -302,12 +302,58 @@ AARU_EXPORT void *AARU_CALL aaruf_open(const char *filepath, const bool resume_m
if(ctx->header.identifier != DIC_MAGIC && ctx->header.identifier != AARU_MAGIC)
{
FATAL("Incorrect identifier for AaruFormat file: %8.8s", (char *)&ctx->header.identifier);
cleanup_open_failure(ctx);
aaruf_set_open_error(AARUF_ERROR_NOT_AARUFORMAT);
/* Primary header corrupt — try recovery footer backup header */
TRACE("Primary header invalid, trying recovery footer backup header");
TRACE("Exiting aaruf_open() = NULL");
return NULL;
aaruf_fseek(ctx->imageStream, 0, SEEK_END);
int64_t file_size = aaruf_ftell(ctx->imageStream);
if(file_size >= (int64_t)sizeof(AaruRecoveryFooter))
{
aaruf_fseek(ctx->imageStream,
(aaru_off_t)(file_size - (int64_t)sizeof(AaruRecoveryFooter)), SEEK_SET);
AaruRecoveryFooter recovery_footer;
if(fread(&recovery_footer, sizeof(AaruRecoveryFooter), 1, ctx->imageStream) == 1 &&
recovery_footer.footerMagic == AARU_RECOVERY_FOOTER_MAGIC)
{
/* Verify the backup header's CRC matches what was recorded */
uint64_t backup_crc = aaruf_crc64_data(
(const uint8_t *)&recovery_footer.backupHeader, sizeof(AaruHeaderV2));
if(backup_crc == recovery_footer.headerCrc64 &&
(recovery_footer.backupHeader.identifier == DIC_MAGIC ||
recovery_footer.backupHeader.identifier == AARU_MAGIC))
{
TRACE("Recovery footer backup header valid, using it");
memcpy(&ctx->header, &recovery_footer.backupHeader, sizeof(AaruHeaderV2));
/* Seek past the header for the next read */
aaruf_fseek(ctx->imageStream, (aaru_off_t)sizeof(AaruHeaderV2), SEEK_SET);
}
else
{
FATAL("Recovery footer backup header also invalid");
cleanup_open_failure(ctx);
aaruf_set_open_error(AARUF_ERROR_NOT_AARUFORMAT);
TRACE("Exiting aaruf_open() = NULL");
return NULL;
}
}
else
{
FATAL("No recovery footer found, cannot recover from corrupt header");
cleanup_open_failure(ctx);
aaruf_set_open_error(AARUF_ERROR_NOT_AARUFORMAT);
TRACE("Exiting aaruf_open() = NULL");
return NULL;
}
}
else
{
FATAL("Incorrect identifier for AaruFormat file: %8.8s", (char *)&ctx->header.identifier);
cleanup_open_failure(ctx);
aaruf_set_open_error(AARUF_ERROR_NOT_AARUFORMAT);
TRACE("Exiting aaruf_open() = NULL");
return NULL;
}
}
if(ctx->header.imageMajorVersion < AARUF_VERSION_V2 && resume_mode)

View File

@@ -355,3 +355,23 @@ TEST_F(ErasureCodingTest, RecoverWithXOR_M1)
ASSERT_TRUE(success) << "XOR recovery failed";
EXPECT_EQ(read_crc, golden_crc);
}
/**
* @test Corrupt the primary header (first 128 bytes), verify backup header from recovery footer is used.
*/
TEST_F(ErasureCodingTest, BackupHeaderRecovery)
{
uint64_t golden_crc = 0;
ASSERT_TRUE(create_ec_image("data/mf2hd.aif", "ec_test_output.aif", 4, 2, &golden_crc));
ASSERT_TRUE(copy_file("ec_test_output.aif", "ec_test_corrupt.aif"));
/* Corrupt the first 64 bytes of the file (part of AaruHeaderV2, including the magic) */
corrupt_file("ec_test_corrupt.aif", 0, 64);
/* Open should succeed using the backup header from the recovery footer */
bool success = false;
uint64_t read_crc = compute_image_crc("ec_test_corrupt.aif", &success);
ASSERT_TRUE(success) << "Backup header recovery failed — could not open/read corrupted image";
EXPECT_EQ(read_crc, golden_crc) << "CRC mismatch after backup header recovery";
}