mirror of
https://github.com/aaru-dps/libaaruformat.git
synced 2026-11-12 23:30:58 +00:00
Recover a damaged Data Position Measurement block with erasure coding, once the erasure coding map is loaded
This commit is contained in:
@@ -222,6 +222,7 @@ typedef struct aaruformat_context
|
||||
uint8_t *json_block; ///< JSON metadata block payload (UTF-8).
|
||||
uint8_t *dpm_block; ///< Data Position Measurement block, header included.
|
||||
size_t dpm_block_length; ///< Length of dpm_block in bytes, 0 if not present.
|
||||
uint64_t dpm_damaged_offset; ///< Offset of a DPM block that failed to load, to recover it with erasure coding, or 0.
|
||||
uint8_t *creator; ///< Who (person) created the image?
|
||||
uint8_t *media_title; ///< Title of the media represented by the image
|
||||
uint8_t *comments; ///< Image comments
|
||||
|
||||
@@ -78,6 +78,7 @@ void process_aaru_metadata_json_block(aaruformat_context *ctx, const IndexE
|
||||
void process_dumphw_block(aaruformat_context *ctx, const IndexEntry *entry);
|
||||
void process_dpm_block(aaruformat_context *ctx, const IndexEntry *entry);
|
||||
int32_t validate_dpm_block(const uint8_t *data, size_t length);
|
||||
int32_t recover_dpm_block(aaruformat_context *ctx);
|
||||
uint64_t dpm_payload_length(const DpmHeader *header);
|
||||
void process_checksum_block(aaruformat_context *ctx, const IndexEntry *entry);
|
||||
void process_tape_files_block(aaruformat_context *ctx, const IndexEntry *entry);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "aaruformat.h"
|
||||
#include "erasure_internal.h"
|
||||
#include "internal.h"
|
||||
#include "log.h"
|
||||
|
||||
@@ -68,6 +69,69 @@ int32_t validate_dpm_block(const uint8_t *data, size_t length)
|
||||
return AARUF_STATUS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Recovers a damaged Data Position Measurement block with erasure coding.
|
||||
*
|
||||
* The DPM block is part of the erasure coding metadata group. When it fails to load, its offset is remembered in
|
||||
* ctx->dpm_damaged_offset, and this rebuilds it from the parity, trims the alignment padding the recovered bytes
|
||||
* carry, validates it and keeps it in the context. It needs the erasure coding map, which aaruf_open() loads after
|
||||
* processing the indexed blocks, so it is tried again from there.
|
||||
*
|
||||
* @param ctx Pointer to the aaruformat context.
|
||||
* @return AARUF_STATUS_OK if the block was recovered, an error status otherwise.
|
||||
*/
|
||||
int32_t recover_dpm_block(aaruformat_context *ctx)
|
||||
{
|
||||
TRACE("Entering recover_dpm_block(%p)", ctx);
|
||||
|
||||
if(ctx == NULL || ctx->dpm_damaged_offset == 0) return AARUF_ERROR_CANNOT_READ_BLOCK;
|
||||
|
||||
uint8_t *recovered = NULL;
|
||||
uint32_t size = 0;
|
||||
|
||||
if(ec_recover_meta_block(ctx, ctx->dpm_damaged_offset, &recovered, &size) != AARUF_STATUS_OK ||
|
||||
recovered == NULL)
|
||||
{
|
||||
TRACE("Could not recover DPM block at %" PRIu64, ctx->dpm_damaged_offset);
|
||||
|
||||
TRACE("Exiting recover_dpm_block() = AARUF_ERROR_CANNOT_READ_BLOCK");
|
||||
return AARUF_ERROR_CANNOT_READ_BLOCK;
|
||||
}
|
||||
|
||||
int32_t status = AARUF_ERROR_CANNOT_READ_BLOCK;
|
||||
|
||||
if(size >= sizeof(DpmHeader))
|
||||
{
|
||||
DpmHeader header;
|
||||
memcpy(&header, recovered, sizeof(DpmHeader));
|
||||
|
||||
const size_t block_length = sizeof(DpmHeader) + (size_t)header.length;
|
||||
|
||||
if(header.length <= UINT32_MAX && size >= block_length &&
|
||||
validate_dpm_block(recovered, block_length) == AARUF_STATUS_OK)
|
||||
{
|
||||
uint8_t *block = malloc(block_length);
|
||||
|
||||
if(block != NULL)
|
||||
{
|
||||
TRACE("Recovered DPM block at %" PRIu64 " with erasure coding", ctx->dpm_damaged_offset);
|
||||
|
||||
memcpy(block, recovered, block_length);
|
||||
free(ctx->dpm_block);
|
||||
ctx->dpm_block = block;
|
||||
ctx->dpm_block_length = block_length;
|
||||
ctx->dpm_damaged_offset = 0;
|
||||
status = AARUF_STATUS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(recovered);
|
||||
|
||||
TRACE("Exiting recover_dpm_block() = %d", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processes a Data Position Measurement block from the image stream.
|
||||
*
|
||||
@@ -104,9 +168,13 @@ void process_dpm_block(aaruformat_context *ctx, const IndexEntry *entry)
|
||||
|
||||
DpmHeader header;
|
||||
|
||||
// From here on, a damaged block is recovered with erasure coding if the image has it
|
||||
ctx->dpm_damaged_offset = entry->offset;
|
||||
|
||||
if(fread(&header, 1, sizeof(DpmHeader), ctx->imageStream) != sizeof(DpmHeader))
|
||||
{
|
||||
TRACE("Could not read DPM header, continuing...");
|
||||
TRACE("Could not read DPM header, trying to recover it...");
|
||||
recover_dpm_block(ctx);
|
||||
|
||||
TRACE("Exiting process_dpm_block()");
|
||||
return;
|
||||
@@ -115,7 +183,8 @@ void process_dpm_block(aaruformat_context *ctx, const IndexEntry *entry)
|
||||
if(header.identifier != DataPositionMeasurementBlock || header.length != dpm_payload_length(&header) ||
|
||||
header.length > UINT32_MAX)
|
||||
{
|
||||
TRACE("Incorrect DPM header at position %" PRIu64 ", continuing...", entry->offset);
|
||||
TRACE("Incorrect DPM header at position %" PRIu64 ", trying to recover it...", entry->offset);
|
||||
recover_dpm_block(ctx);
|
||||
|
||||
TRACE("Exiting process_dpm_block()");
|
||||
return;
|
||||
@@ -137,16 +206,18 @@ void process_dpm_block(aaruformat_context *ctx, const IndexEntry *entry)
|
||||
if(fread(block + sizeof(DpmHeader), 1, header.length, ctx->imageStream) != header.length ||
|
||||
validate_dpm_block(block, block_length) != AARUF_STATUS_OK)
|
||||
{
|
||||
TRACE("Could not read DPM block or it is corrupted, continuing...");
|
||||
TRACE("Could not read DPM block or it is corrupted, trying to recover it...");
|
||||
free(block);
|
||||
recover_dpm_block(ctx);
|
||||
|
||||
TRACE("Exiting process_dpm_block()");
|
||||
return;
|
||||
}
|
||||
|
||||
free(ctx->dpm_block);
|
||||
ctx->dpm_block = block;
|
||||
ctx->dpm_block_length = block_length;
|
||||
ctx->dpm_block = block;
|
||||
ctx->dpm_block_length = block_length;
|
||||
ctx->dpm_damaged_offset = 0;
|
||||
|
||||
ctx->image_info.ImageSize += header.length;
|
||||
|
||||
|
||||
@@ -744,6 +744,9 @@ AARU_EXPORT void *AARU_CALL aaruf_open(const char *filepath, const bool resume_m
|
||||
/* Try to load erasure coding recovery metadata from EOF footer */
|
||||
ec_load_ecmb(ctx);
|
||||
|
||||
/* Blocks are processed before the erasure coding map is loaded, so recover a damaged DPM block now */
|
||||
if(ctx->dpm_block == NULL && ctx->dpm_damaged_offset != 0) recover_dpm_block(ctx);
|
||||
|
||||
if(!resume_mode)
|
||||
{
|
||||
TRACE("Exiting aaruf_open() = %p", ctx);
|
||||
|
||||
Reference in New Issue
Block a user