Update recovery footer size and related documentation for AaruRecoveryFooter

This commit is contained in:
2026-04-12 14:17:56 +01:00
parent 4573ae8f1b
commit 81c367995f
4 changed files with 17 additions and 17 deletions

View File

@@ -194,7 +194,7 @@ CAUTION: Reading a non-DataBlock header as a `BlockHeader` and accessing the `cm
==== Recovery Footer
The last 160 bytes of the file contain the recovery footer, enabling the ECMB to be found even when the header or index is destroyed:
The last 179 bytes of the file contain the recovery footer, enabling the ECMB to be found even when the header or index is destroyed:
[source,c]
----
@@ -203,7 +203,7 @@ typedef struct AaruRecoveryFooter
uint64_t ecmbOffset; // Absolute file offset of the primary ECMB
uint64_t ecmbLength; // Total on-disk size of the ECMB (header + payload)
uint64_t headerCrc64; // CRC64-ECMA of the original AaruHeaderV2
AaruHeaderV2 backupHeader; // Complete copy of AaruHeaderV2 (128 bytes)
AaruHeaderV2 backupHeader; // Complete copy of AaruHeaderV2 (147 bytes)
uint64_t footerMagic; // Must be 0x52464D4345525641 ("AVRECMFR")
} AaruRecoveryFooter;
----
@@ -214,7 +214,7 @@ typedef struct AaruRecoveryFooter
|uint64_t |8 bytes |ecmbOffset |Absolute file offset of the primary ECMB.
|uint64_t |8 bytes |ecmbLength |Total on-disk size of the ECMB (header + payload).
|uint64_t |8 bytes |headerCrc64 |CRC64-ECMA of the original `AaruHeaderV2` at file offset 0.
|AaruHeaderV2 |128 bytes |backupHeader |Complete backup copy of the file header.
|AaruHeaderV2 |147 bytes |backupHeader |Complete backup copy of the file header.
|uint64_t |8 bytes |footerMagic |Must be `0x52464D4345525641` ("AVRECMFR" in ASCII little-endian).
|===
@@ -241,7 +241,7 @@ The recovery chain defines the fallback sequence when structures are damaged:
The erasure coding structures are written at the end of the file:
----
[AaruHeaderV2] offset 0, 128 bytes
[AaruHeaderV2] offset 0, 147 bytes
[Data blocks with consecutive parity] variable size
[DDT blocks (all levels)] variable size
[DDT parity blocks] M blocks (uncompressed)
@@ -251,7 +251,7 @@ The erasure coding structures are written at the end of the file:
[Index parity blocks] M blocks (uncompressed)
[ECMB (primary)] at footer.ecmbOffset
[ECMB (duplicate)] at ecmbOffset + ecmbLength (aligned)
[Recovery Footer] last 160 bytes of file
[Recovery Footer] last 179 bytes of file
----
==== Automatic K,M Selection
@@ -442,7 +442,7 @@ With K=16 and M=2, you need 33+ contiguously corrupted blocks before any stripe
==== Recovery Footer
The last 160 bytes of the file contain the recovery footer, enabling the ECMB to be found even when the header or index is destroyed:
The last 179 bytes of the file contain the recovery footer, enabling the ECMB to be found even when the header or index is destroyed:
[source,c]
----
@@ -451,7 +451,7 @@ typedef struct AaruRecoveryFooter
uint64_t ecmbOffset; // Absolute file offset of the primary ECMB
uint64_t ecmbLength; // Total on-disk size of the ECMB (header + payload)
uint64_t headerCrc64; // CRC64-ECMA of the original AaruHeaderV2
AaruHeaderV2 backupHeader; // Complete copy of AaruHeaderV2 (128 bytes)
AaruHeaderV2 backupHeader; // Complete copy of AaruHeaderV2 (147 bytes)
uint64_t footerMagic; // Must be 0x52464D4345525641 ("AVRECMFR")
} AaruRecoveryFooter;
----
@@ -462,7 +462,7 @@ typedef struct AaruRecoveryFooter
|uint64_t |8 bytes |ecmbOffset |Absolute file offset of the primary ECMB.
|uint64_t |8 bytes |ecmbLength |Total on-disk size of the ECMB (header + payload).
|uint64_t |8 bytes |headerCrc64 |CRC64-ECMA of the original `AaruHeaderV2` at file offset 0.
|AaruHeaderV2 |128 bytes |backupHeader |Complete backup copy of the file header.
|AaruHeaderV2 |147 bytes |backupHeader |Complete backup copy of the file header.
|uint64_t |8 bytes |footerMagic |Must be `0x52464D4345525641` ("AVRECMFR" in ASCII little-endian).
|===
@@ -489,7 +489,7 @@ The recovery chain defines the fallback sequence when structures are damaged:
The erasure coding structures are written after the index block, at the end of the file:
----
[AaruHeaderV2] offset 0, 128 bytes
[AaruHeaderV2] offset 0, 147 bytes
[Data blocks + interleaved parity] variable size
[DDT blocks (all levels)] variable size
[DDT parity blocks] M blocks
@@ -499,5 +499,5 @@ The erasure coding structures are written after the index block, at the end of t
[Index parity blocks] M blocks
[ECMB (primary)] at footer.ecmbOffset
[ECMB (duplicate)] at ecmbOffset + ecmbLength (aligned)
[Recovery Footer] last 160 bytes of file
[Recovery Footer] last 179 bytes of file
----

View File

@@ -117,7 +117,7 @@ typedef struct AaruRecoveryFooter
{
uint64_t ecmbOffset; ///< Absolute file offset of the primary ECMB.
uint64_t ecmbLength; ///< Total on-disk size of the ECMB (header + payload).
uint64_t headerCrc64; ///< CRC64-ECMA of the original AaruHeaderV2 (128 bytes at offset 0).
uint64_t headerCrc64; ///< CRC64-ECMA of the original AaruHeaderV2 (147 bytes at offset 0).
AaruHeaderV2 backupHeader; ///< Complete copy of AaruHeaderV2 from file offset 0.
uint64_t footerMagic; ///< Must be AARU_RECOVERY_FOOTER_MAGIC (0x52464D4345525641).
} AaruRecoveryFooter;

View File

@@ -893,7 +893,7 @@ void ec_load_ecmb(aaruformat_context *ctx)
{
TRACE("Entering ec_load_ecmb(%p)", (void *)ctx);
/* Read recovery footer from last 160 bytes of file */
/* Read recovery footer from last sizeof(AaruRecoveryFooter) bytes of file */
aaruf_fseek(ctx->imageStream, 0, SEEK_END);
int64_t file_size = aaruf_ftell(ctx->imageStream);
if(file_size < (int64_t)sizeof(AaruRecoveryFooter))

View File

@@ -1260,7 +1260,7 @@ struct AaruRecoveryFooter
u64 ecmbOffset;
u64 ecmbLength;
u64 headerCrc64;
AaruHeader backupHeader;
u8 backupHeader[147]; // Raw AaruHeaderV2 bytes (NOT the parsed struct)
u64 footerMagic;
};
@@ -1316,19 +1316,19 @@ if(header.identifier != DIC_MAGIC && header.identifier != AARU_MAGIC)
std::error("Incorrect signature!");
// Parse recovery footer at EOF (if present)
// The footer is the last 160 bytes of the file
// The footer is the last 179 bytes of the file
u64 fileSize = std::mem::size();
if(fileSize >= 160)
if(fileSize >= 179)
{
u64 footerMagicPos = fileSize - 8;
u64 footerMagic = std::mem::read_unsigned(footerMagicPos, 8);
if(footerMagic == 0x52464D4345525641) // "AVRECMFR"
{
AaruRecoveryFooter recoveryFooter @ (fileSize - 160);
AaruRecoveryFooter recoveryFooter @ (fileSize - 179);
// Parse the ECMB at the offset recorded in the recovery footer
// (ECMB is NOT in the index due to chicken-egg: index itself needs recovery)
u64 ecmbOff = std::mem::read_unsigned(fileSize - 160, 8);
u64 ecmbOff = std::mem::read_unsigned(fileSize - 179, 8);
if(ecmbOff > 0 && ecmbOff < fileSize)
{
ErasureCodingMapHeader ecmb @ ecmbOff;