libaaruformat 1.0
Aaru Data Preservation Suite - Format Library
Loading...
Searching...
No Matches
dpm.c
Go to the documentation of this file.
1/*
2 * This file is part of the Aaru Data Preservation Suite.
3 * Copyright (c) 2019-2026 Natalia Portillo.
4 *
5 * This library is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as
7 * published by the Free Software Foundation; either version 2.1 of the
8 * License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <inttypes.h>
20#include <stdint.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "aaruformat.h"
26#include "erasure_internal.h"
27#include "internal.h"
28#include "log.h"
29
36uint64_t dpm_payload_length(const DpmHeader *header)
37{
38 return (uint64_t)header->layerEnds * sizeof(uint64_t) + (uint64_t)header->entries * sizeof(DpmEntry) +
39 (uint64_t)header->calibrations * sizeof(DpmCalibration);
40}
41
53int32_t validate_dpm_block(const uint8_t *data, size_t length)
54{
55 if(data == NULL || length < sizeof(DpmHeader)) return AARUF_ERROR_INCORRECT_DATA_SIZE;
56
57 DpmHeader header;
58 memcpy(&header, data, sizeof(DpmHeader));
59
61
62 if(header.length != length - sizeof(DpmHeader) || header.length != dpm_payload_length(&header) ||
63 header.length > UINT32_MAX)
65
66 if(aaruf_crc64_data(data + sizeof(DpmHeader), (uint32_t)header.length) != header.crc64)
68
69 return AARUF_STATUS_OK;
70}
71
84{
85 TRACE("Entering recover_dpm_block(%p)", ctx);
86
87 if(ctx == NULL || ctx->dpm_damaged_offset == 0) return AARUF_ERROR_CANNOT_READ_BLOCK;
88
89 uint8_t *recovered = NULL;
90 uint32_t size = 0;
91
92 if(ec_recover_meta_block(ctx, ctx->dpm_damaged_offset, &recovered, &size) != AARUF_STATUS_OK ||
93 recovered == NULL)
94 {
95 TRACE("Could not recover DPM block at %" PRIu64, ctx->dpm_damaged_offset);
96
97 TRACE("Exiting recover_dpm_block() = AARUF_ERROR_CANNOT_READ_BLOCK");
99 }
100
101 int32_t status = AARUF_ERROR_CANNOT_READ_BLOCK;
102
103 if(size >= sizeof(DpmHeader))
104 {
105 DpmHeader header;
106 memcpy(&header, recovered, sizeof(DpmHeader));
107
108 const size_t block_length = sizeof(DpmHeader) + (size_t)header.length;
109
110 if(header.length <= UINT32_MAX && size >= block_length &&
111 validate_dpm_block(recovered, block_length) == AARUF_STATUS_OK)
112 {
113 uint8_t *block = malloc(block_length);
114
115 if(block != NULL)
116 {
117 TRACE("Recovered DPM block at %" PRIu64 " with erasure coding", ctx->dpm_damaged_offset);
118
119 memcpy(block, recovered, block_length);
120 free(ctx->dpm_block);
121 ctx->dpm_block = block;
122 ctx->dpm_block_length = block_length;
123 ctx->dpm_damaged_offset = 0;
124 status = AARUF_STATUS_OK;
125 }
126 }
127 }
128
129 free(recovered);
130
131 TRACE("Exiting recover_dpm_block() = %d", status);
132 return status;
133}
134
149{
150 TRACE("Entering process_dpm_block(%p, %p)", ctx, entry);
151
152 if(ctx == NULL || ctx->imageStream == NULL)
153 {
154 FATAL("Invalid context or image stream.");
155
156 TRACE("Exiting process_dpm_block()");
157 return;
158 }
159
160 if(aaruf_fseek(ctx->imageStream, (aaru_off_t)entry->offset, SEEK_SET) < 0 ||
161 aaruf_ftell(ctx->imageStream) != (aaru_off_t)entry->offset)
162 {
163 FATAL("Could not seek to %" PRIu64 " as indicated by index entry...", entry->offset);
164
165 TRACE("Exiting process_dpm_block()");
166 return;
167 }
168
169 DpmHeader header;
170
171 // From here on, a damaged block is recovered with erasure coding if the image has it
172 ctx->dpm_damaged_offset = entry->offset;
173
174 if(fread(&header, 1, sizeof(DpmHeader), ctx->imageStream) != sizeof(DpmHeader))
175 {
176 TRACE("Could not read DPM header, trying to recover it...");
178
179 TRACE("Exiting process_dpm_block()");
180 return;
181 }
182
183 if(header.identifier != DataPositionMeasurementBlock || header.length != dpm_payload_length(&header) ||
184 header.length > UINT32_MAX)
185 {
186 TRACE("Incorrect DPM header at position %" PRIu64 ", trying to recover it...", entry->offset);
188
189 TRACE("Exiting process_dpm_block()");
190 return;
191 }
192
193 const size_t block_length = sizeof(DpmHeader) + (size_t)header.length;
194 uint8_t *block = malloc(block_length);
195
196 if(block == NULL)
197 {
198 TRACE("Could not allocate memory for DPM block, continuing...");
199
200 TRACE("Exiting process_dpm_block()");
201 return;
202 }
203
204 memcpy(block, &header, sizeof(DpmHeader));
205
206 if(fread(block + sizeof(DpmHeader), 1, header.length, ctx->imageStream) != header.length ||
207 validate_dpm_block(block, block_length) != AARUF_STATUS_OK)
208 {
209 TRACE("Could not read DPM block or it is corrupted, trying to recover it...");
210 free(block);
212
213 TRACE("Exiting process_dpm_block()");
214 return;
215 }
216
217 free(ctx->dpm_block);
218 ctx->dpm_block = block;
219 ctx->dpm_block_length = block_length;
220 ctx->dpm_damaged_offset = 0;
221
222 ctx->image_info.ImageSize += header.length;
223
224 TRACE("Found DPM block at %" PRIu64 " with %u entries.", entry->offset, header.entries);
225
226 TRACE("Exiting process_dpm_block()");
227}
uint64_t aaruf_crc64_data(const uint8_t *data, uint32_t len)
Definition crc64.c:160
@ DataPositionMeasurementBlock
Block containing data position measurements (reserved / TODO).
Definition enums.h:177
int32_t ec_recover_meta_block(aaruformat_context *ctx, uint64_t block_offset, uint8_t **recovered_data, uint32_t *recovered_size)
Attempt to recover a metadata/media-tag block at a given file offset.
Definition erasure.c:909
#define AARUF_STATUS_OK
Sector present and read without uncorrectable errors.
Definition errors.h:82
#define AARUF_ERROR_CANNOT_READ_BLOCK
Generic block read failure (seek/read error).
Definition errors.h:46
#define AARUF_ERROR_INCORRECT_DATA_SIZE
Data size does not match expected size.
Definition errors.h:65
#define AARUF_ERROR_INVALID_BLOCK_CRC
CRC64 mismatch indicating corruption.
Definition errors.h:57
uint64_t dpm_payload_length(const DpmHeader *header)
Computes the payload length a Data Position Measurement header describes.
Definition dpm.c:36
static int aaruf_fseek(FILE *stream, aaru_off_t offset, int origin)
Definition internal.h:46
static aaru_off_t aaruf_ftell(FILE *stream)
Definition internal.h:52
void process_dpm_block(aaruformat_context *ctx, const IndexEntry *entry)
Processes a Data Position Measurement block from the image stream.
Definition dpm.c:148
int32_t validate_dpm_block(const uint8_t *data, size_t length)
Validates a serialized Data Position Measurement block.
Definition dpm.c:53
int32_t recover_dpm_block(aaruformat_context *ctx)
Recovers a damaged Data Position Measurement block with erasure coding.
Definition dpm.c:83
int64_t aaru_off_t
Definition internal.h:42
#define FATAL(fmt,...)
Definition log.h:75
#define TRACE(fmt,...)
Definition log.h:69
A rotation calibration done while measuring.
Definition dpm.h:105
A DPM control point.
Definition dpm.h:95
Header of the Data Position Measurement block.
Definition dpm.h:77
uint32_t calibrations
Number of DpmCalibration records.
Definition dpm.h:80
uint32_t entries
Number of DpmEntry records.
Definition dpm.h:79
uint8_t layerEnds
Number of layer boundaries (layers - 1), 0 for single layer media or if unknown.
Definition dpm.h:84
uint64_t length
Payload bytes after this header.
Definition dpm.h:87
uint32_t identifier
Block identifier, must be BlockType::DataPositionMeasurementBlock.
Definition dpm.h:78
uint64_t crc64
CRC64-ECMA of the payload.
Definition dpm.h:88
uint64_t ImageSize
Size of the image payload in bytes (excludes headers/metadata).
Definition aaru.h:937
Single index entry describing a block's type, (optional) data classification, and file offset.
Definition index.h:109
uint64_t offset
Absolute byte offset in the image where the referenced block header begins.
Definition index.h:112
Master context representing an open or in‑creation Aaru image.
Definition context.h:178
size_t dpm_block_length
Length of dpm_block in bytes, 0 if not present.
Definition context.h:224
uint64_t dpm_damaged_offset
Offset of a DPM block that failed to load, to recover it with erasure coding, or 0.
Definition context.h:225
FILE * imageStream
Underlying FILE* stream (binary mode).
Definition context.h:182
ImageInfo image_info
Exposed high-level image info summary.
Definition context.h:270
uint8_t * dpm_block
Data Position Measurement block, header included.
Definition context.h:223