libaaruformat 1.0 Aaru Data Preservation Suite - Format Library

Loading...
Searching...
No Matches
dump.c
Go to the documentation of this file.
1/*
2 * This file is part of the Aaru Data Preservation Suite.
3 * Copyright (c) 2019-2025 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 <limits.h>
21#include <stdint.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include "aaruformat/consts.h"
27#include "aaruformat/context.h"
28#include "aaruformat/decls.h"
29#include "aaruformat/endian.h"
30#include "aaruformat/enums.h"
31#include "aaruformat/structs/dump.h"
32#include "aaruformat/structs/index.h"
33#include "internal.h"
34#include "log.h"
35
36 static void free_dump_hardware_entries_array(DumpHardwareEntriesWithData *entries, uint16_t count)
37{
38 if(entries == NULL) return;
39
40 for(uint16_t e = 0; e < count; e++)
41 {
42 free(entries[e].manufacturer);
43 free(entries[e].model);
44 free(entries[e].revision);
45 free(entries[e].firmware);
46 free(entries[e].serial);
47 free(entries[e].softwareName);
48 free(entries[e].softwareVersion);
49 free(entries[e].softwareOperatingSystem);
50 free(entries[e].extents);
51 }
52}
53
54 static void reset_dump_hardware_context(aaruformat_context *ctx)
55{
56 if(ctx == NULL) return;
57
58 free_dump_hardware_entries_array(ctx->dump_hardware_entries_with_data, ctx->dump_hardware_header.entries);
59 free(ctx->dump_hardware_entries_with_data);
60 ctx->dump_hardware_entries_with_data = NULL;
61 memset(&ctx->dump_hardware_header, 0, sizeof(ctx->dump_hardware_header));
62}
63
64 static bool read_dump_string(FILE *stream, const char *field_name, const uint32_t length, uint32_t *remaining,
65 uint8_t **destination)
66{
67 if(length == 0) return true;
68
69 if(*remaining < length)
70 {
71 TRACE("Dump hardware %s length %u exceeds remaining payload %u", field_name, length,
72 remaining == NULL ? 0 : *remaining);
73 return false;
74 }
75
76 uint8_t *buffer = malloc(length);
77
78 if(buffer == NULL)
79 {
80 TRACE("Could not allocate %s buffer of length %u", field_name, length);
81 return false;
82 }
83
84 const size_t bytes_read = fread(buffer, 1, length, stream);
85
86 if(bytes_read != length)
87 {
88 TRACE("Could not read %s field, expected %u bytes got %zu", field_name, length, bytes_read);
89 free(buffer);
90 return false;
91 }
92
93 *remaining -= length;
94 *destination = buffer;
95
96 return true;
97}
98
107 void process_dumphw_block(aaruformat_context *ctx, const IndexEntry *entry)
108{
109 TRACE("Entering process_dumphw_block(%p, %p)", ctx, entry);
110 size_t read_bytes = 0;
111
112 if(ctx == NULL || ctx->imageStream == NULL || entry == NULL)
113 {
114 FATAL("Invalid context, image stream, or index entry pointer.");
115 TRACE("Exiting process_dumphw_block()");
116 if(ctx != NULL) reset_dump_hardware_context(ctx);
117 return;
118 }
119
120 if(entry->blockType != DumpHardwareBlock)
121 {
122 TRACE("Index entry block type %u is not DumpHardwareBlock, skipping.", entry->blockType);
123 TRACE("Exiting process_dumphw_block()");
124 return;
125 }
126
127 if(fseek(ctx->imageStream, entry->offset, SEEK_SET) < 0 || ftell(ctx->imageStream) != entry->offset)
128 {
129 FATAL("Could not seek to %" PRIu64 " as indicated by index entry...", entry->offset);
130 reset_dump_hardware_context(ctx);
131 TRACE("Exiting process_dumphw_block()");
132 return;
133 }
134
135 TRACE("Reading dump hardware block header at position %" PRIu64, entry->offset);
136 DumpHardwareHeader header;
137 read_bytes = fread(&header, 1, sizeof(header), ctx->imageStream);
138
139 if(read_bytes != sizeof(header))
140 {
141 TRACE("Could not read dump hardware block header (read %zu bytes)", read_bytes);
142 reset_dump_hardware_context(ctx);
143 TRACE("Exiting process_dumphw_block()");
144 return;
145 }
146
147 if(header.identifier != DumpHardwareBlock)
148 {
149 TRACE("Incorrect identifier 0x%08" PRIx32 " for dump hardware block at position %" PRIu64, header.identifier,
150 entry->offset);
151 reset_dump_hardware_context(ctx);
152 TRACE("Exiting process_dumphw_block()");
153 return;
154 }
155
156 if(header.entries > 0 && header.length == 0)
157 {
158 TRACE("Dump hardware header indicates %u entries but zero payload length", header.entries);
159 reset_dump_hardware_context(ctx);
160 TRACE("Exiting process_dumphw_block()");
161 return;
162 }
163
164 const uint32_t payload_length = header.length;
165
166 if(payload_length > 0)
167 {
168 uint8_t *payload = malloc(payload_length);
169
170 if(payload == NULL)
171 {
172 TRACE("Could not allocate %u bytes for dump hardware payload", payload_length);
173 reset_dump_hardware_context(ctx);
174 TRACE("Exiting process_dumphw_block()");
175 return;
176 }
177
178 read_bytes = fread(payload, 1, payload_length, ctx->imageStream);
179
180 if(read_bytes != payload_length)
181 {
182 TRACE("Could not read dump hardware payload, expected %u bytes got %zu", payload_length, read_bytes);
183 free(payload);
184 reset_dump_hardware_context(ctx);
185 TRACE("Exiting process_dumphw_block()");
186 return;
187 }
188
189 uint64_t crc64 = aaruf_crc64_data(payload, payload_length);
190
191 if(ctx->header.imageMajorVersion <= AARUF_VERSION_V1) crc64 = bswap_64(crc64);
192
193 if(crc64 != header.crc64)
194 {
195 TRACE("Dump hardware block CRC mismatch: computed 0x%" PRIx64 " expected 0x%" PRIx64, crc64, header.crc64);
196 free(payload);
197 reset_dump_hardware_context(ctx);
198 TRACE("Exiting process_dumphw_block()");
199 return;
200 }
201
202 free(payload);
203
204 if(fseek(ctx->imageStream, -(long)payload_length, SEEK_CUR) != 0)
205 {
206 TRACE("Could not rewind after CRC verification");
207 reset_dump_hardware_context(ctx);
208 TRACE("Exiting process_dumphw_block()");
209 return;
210 }
211 }
212
213 if(header.entries == 0)
214 {
215 reset_dump_hardware_context(ctx);
216 ctx->dump_hardware_header = header;
217 TRACE("Dump hardware block contains no entries. Clearing existing metadata.");
218 TRACE("Exiting process_dumphw_block()");
219 return;
220 }
221
222 const size_t allocation_size = (size_t)header.entries * sizeof(DumpHardwareEntriesWithData);
223
224 if(allocation_size / sizeof(DumpHardwareEntriesWithData) != header.entries)
225 {
226 TRACE("Dump hardware entries multiplication overflow (%u entries)", header.entries);
227 reset_dump_hardware_context(ctx);
228 TRACE("Exiting process_dumphw_block()");
229 return;
230 }
231
232 DumpHardwareEntriesWithData *entries = calloc(header.entries, sizeof(DumpHardwareEntriesWithData));
233
234 if(entries == NULL)
235 {
236 TRACE("Could not allocate %zu bytes for dump hardware entries", allocation_size);
237 reset_dump_hardware_context(ctx);
238 TRACE("Exiting process_dumphw_block()");
239 return;
240 }
241
242 uint32_t remaining_payload = payload_length;
243 uint16_t processed_entry = 0;
244
245 TRACE("Processing %u dump hardware block entries", header.entries);
246
247 for(uint16_t e = 0; e < header.entries; e++)
248 {
249 processed_entry = e;
250 DumpHardwareEntriesWithData *current = &entries[e];
251
252 if(remaining_payload < sizeof(DumpHardwareEntry))
253 {
254 TRACE("Remaining payload %u too small for dump hardware entry %u", remaining_payload, e);
255 goto parse_failure;
256 }
257
258 read_bytes = fread(&current->entry, 1, sizeof(DumpHardwareEntry), ctx->imageStream);
259
260 if(read_bytes != sizeof(DumpHardwareEntry))
261 {
262 TRACE("Could not read dump hardware entry %u header (read %zu bytes)", e, read_bytes);
263 goto parse_failure;
264 }
265
266 remaining_payload -= sizeof(DumpHardwareEntry);
267
268 if(!read_dump_string(ctx->imageStream, "manufacturer", current->entry.manufacturerLength, &remaining_payload,
269 &current->manufacturer))
270 goto parse_failure;
271
272 if(!read_dump_string(ctx->imageStream, "model", current->entry.modelLength, &remaining_payload,
273 &current->model))
274 goto parse_failure;
275
276 if(!read_dump_string(ctx->imageStream, "revision", current->entry.revisionLength, &remaining_payload,
277 &current->revision))
278 goto parse_failure;
279
280 if(!read_dump_string(ctx->imageStream, "firmware", current->entry.firmwareLength, &remaining_payload,
281 &current->firmware))
282 goto parse_failure;
283
284 if(!read_dump_string(ctx->imageStream, "serial", current->entry.serialLength, &remaining_payload,
285 &current->serial))
286 goto parse_failure;
287
288 if(!read_dump_string(ctx->imageStream, "software name", current->entry.softwareNameLength, &remaining_payload,
289 &current->softwareName))
290 goto parse_failure;
291
292 if(!read_dump_string(ctx->imageStream, "software version", current->entry.softwareVersionLength,
293 &remaining_payload, &current->softwareVersion))
294 goto parse_failure;
295
296 if(!read_dump_string(ctx->imageStream, "software operating system",
297 current->entry.softwareOperatingSystemLength, &remaining_payload,
298 &current->softwareOperatingSystem))
299 goto parse_failure;
300
301 const uint32_t extent_count = current->entry.extents;
302
303 if(extent_count == 0) continue;
304
305 const size_t extent_bytes = (size_t)extent_count * sizeof(DumpExtent);
306
307 if(extent_bytes / sizeof(DumpExtent) != extent_count || extent_bytes > remaining_payload)
308 {
309 TRACE("Extent array for entry %u exceeds remaining payload (%zu bytes requested, %u left)", e, extent_bytes,
310 remaining_payload);
311 goto parse_failure;
312 }
313
314 current->extents = (DumpExtent *)malloc(extent_bytes);
315
316 if(current->extents == NULL)
317 {
318 TRACE("Could not allocate %zu bytes for dump hardware entry %u extents", extent_bytes, e);
319 goto parse_failure;
320 }
321
322 const size_t extents_read = fread(current->extents, sizeof(DumpExtent), extent_count, ctx->imageStream);
323
324 if(extents_read != extent_count)
325 {
326 TRACE("Could not read %u dump hardware extents for entry %u (read %zu)", extent_count, e, extents_read);
327 goto parse_failure;
328 }
329
330 remaining_payload -= (uint32_t)extent_bytes;
331
332 qsort(current->extents, extent_count, sizeof(DumpExtent), compare_extents);
333 TRACE("Sorted %u extents for entry %u", extent_count, e);
334 }
335
336 reset_dump_hardware_context(ctx);
337 ctx->dump_hardware_entries_with_data = entries;
338 ctx->dump_hardware_header = header;
339
340 if(remaining_payload != 0)
341 {
342 TRACE("Dump hardware block parsing completed with %u trailing payload bytes", remaining_payload);
343 }
344
345 TRACE("Exiting process_dumphw_block()");
346 return;
347
348parse_failure:
349 free_dump_hardware_entries_array(entries, processed_entry + 1);
350 free(entries);
351 reset_dump_hardware_context(ctx);
352 TRACE("Exiting process_dumphw_block()");
353}
process_dumphw_block
void process_dumphw_block(aaruformat_context *ctx, const IndexEntry *entry)
Processes a dump hardware block from the image stream.
Definition dump.c:107
reset_dump_hardware_context
static void reset_dump_hardware_context(aaruformat_context *ctx)
Definition dump.c:54
free_dump_hardware_entries_array
static void free_dump_hardware_entries_array(DumpHardwareEntriesWithData *entries, uint16_t count)
Definition dump.c:36
read_dump_string
static bool read_dump_string(FILE *stream, const char *field_name, const uint32_t length, uint32_t *remaining, uint8_t **destination)
Definition dump.c:64
consts.h
Core public constants and compile‑time limits for the Aaru container format implementation.
AARUF_VERSION_V1
#define AARUF_VERSION_V1
First on‑disk version (C# implementation).
Definition consts.h:71
context.h
Central runtime context structures for libaaruformat (image state, caches, checksum buffers).
decls.h
aaruf_crc64_data
uint64_t aaruf_crc64_data(const uint8_t *data, uint32_t len)
Definition crc64.c:160
dump.h
Packed on-disk structures describing hardware and software used during image acquisition.
endian.h
bswap_64
#define bswap_64(x)
Definition endian.h:81
enums.h
DumpHardwareBlock
@ DumpHardwareBlock
Block containing an array of hardware used to create the image.
Definition enums.h:156
index.h
On‑disk index block header and entry structures (versions 1, 2 and 3).
internal.h
compare_extents
int compare_extents(const void *a, const void *b)
Comparison function for sorting DumpExtent arrays by start sector.
Definition helpers.c:459
log.h
FATAL
#define FATAL(fmt,...)
Definition log.h:40
TRACE
#define TRACE(fmt,...)
Definition log.h:25
AaruHeaderV2::imageMajorVersion
uint8_t imageMajorVersion
Container format major version.
Definition header.h:110
DumpExtent
Inclusive [start,end] logical sector range contributed by a single hardware environment.
Definition context.h:334
DumpHardwareEntriesWithData
In-memory representation of a dump hardware entry plus decoded variable-length fields & extents.
Definition context.h:315
DumpHardwareEntriesWithData::firmware
uint8_t * firmware
Firmware version string or NULL.
Definition context.h:321
DumpHardwareEntriesWithData::revision
uint8_t * revision
Hardware revision string or NULL.
Definition context.h:320
DumpHardwareEntriesWithData::model
uint8_t * model
Model string or NULL.
Definition context.h:319
DumpHardwareEntriesWithData::softwareName
uint8_t * softwareName
Dump software name or NULL.
Definition context.h:323
DumpHardwareEntriesWithData::extents
struct DumpExtent * extents
Array of extents (entry.extents elements) or NULL.
Definition context.h:317
DumpHardwareEntriesWithData::manufacturer
uint8_t * manufacturer
Manufacturer string (UTF-8) or NULL.
Definition context.h:318
DumpHardwareEntriesWithData::softwareVersion
uint8_t * softwareVersion
Dump software version or NULL.
Definition context.h:324
DumpHardwareEntriesWithData::serial
uint8_t * serial
Serial number string or NULL.
Definition context.h:322
DumpHardwareEntriesWithData::entry
DumpHardwareEntry entry
Fixed-size header with lengths & counts.
Definition context.h:316
DumpHardwareEntriesWithData::softwareOperatingSystem
uint8_t * softwareOperatingSystem
Host operating system string or NULL.
Definition context.h:325
DumpHardwareEntry
Per-environment length table describing subsequent UTF-8 strings and optional extent array.
Definition dump.h:113
DumpHardwareEntry::softwareNameLength
uint32_t softwareNameLength
Length in bytes of dumping software name string.
Definition dump.h:119
DumpHardwareEntry::manufacturerLength
uint32_t manufacturerLength
Length in bytes of manufacturer UTF-8 string.
Definition dump.h:114
DumpHardwareEntry::softwareVersionLength
uint32_t softwareVersionLength
Length in bytes of dumping software version string.
Definition dump.h:120
DumpHardwareEntry::firmwareLength
uint32_t firmwareLength
Length in bytes of firmware version string.
Definition dump.h:117
DumpHardwareEntry::extents
uint32_t extents
Number of DumpExtent records following the strings (0 = none).
Definition dump.h:122
DumpHardwareEntry::modelLength
uint32_t modelLength
Length in bytes of model UTF-8 string.
Definition dump.h:115
DumpHardwareEntry::serialLength
uint32_t serialLength
Length in bytes of device serial number string.
Definition dump.h:118
DumpHardwareEntry::revisionLength
uint32_t revisionLength
Length in bytes of revision / hardware revision string.
Definition dump.h:116
DumpHardwareEntry::softwareOperatingSystemLength
uint32_t softwareOperatingSystemLength
Length in bytes of host operating system string.
Definition dump.h:121
DumpHardwareHeader
Header that precedes a sequence of dump hardware entries and their variable-length payload.
Definition dump.h:91
DumpHardwareHeader::crc64
uint64_t crc64
CRC64-ECMA of the payload (byte-swapped for legacy v1 images, handled automatically).
Definition dump.h:95
DumpHardwareHeader::identifier
uint32_t identifier
Block identifier, must be BlockType::DumpHardwareBlock.
Definition dump.h:92
DumpHardwareHeader::length
uint32_t length
Total payload bytes after this header (sum of entries, strings, and extents arrays).
Definition dump.h:94
DumpHardwareHeader::entries
uint16_t entries
Number of DumpHardwareEntry records that follow.
Definition dump.h:93
IndexEntry
Single index entry describing a block's type, (optional) data classification, and file offset.
Definition index.h:109
IndexEntry::blockType
uint32_t blockType
Block identifier of the referenced block (value from BlockType).
Definition index.h:110
IndexEntry::offset
uint64_t offset
Absolute byte offset in the image where the referenced block header begins.
Definition index.h:112
aaruformat_context
Master context representing an open or in‑creation Aaru image.
Definition context.h:172
aaruformat_context::header
AaruHeaderV2 header
Parsed container header (v2).
Definition context.h:175
aaruformat_context::dump_hardware_entries_with_data
struct DumpHardwareEntriesWithData * dump_hardware_entries_with_data
Array of dump hardware entries + strings.
Definition context.h:212
aaruformat_context::imageStream
FILE * imageStream
Underlying FILE* stream (binary mode).
Definition context.h:176
aaruformat_context::dump_hardware_header
DumpHardwareHeader dump_hardware_header
Dump hardware header.
Definition context.h:232