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, uint32_t length, uint32_t *remaining,
65 uint8_t **destination)
66{
67 if(length == 0) return true;
68
69 if(remaining == NULL || *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 = (uint8_t *)malloc((size_t)length + 1);
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 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 buffer[length] = 0;
94 *remaining -= length;
95 *destination = buffer;
96
97 return true;
98}
99
108 void process_dumphw_block(aaruformat_context *ctx, const IndexEntry *entry)
109{
110 TRACE("Entering process_dumphw_block(%p, %p)", ctx, entry);
111 size_t read_bytes = 0;
112
113 if(ctx == NULL || ctx->imageStream == NULL || entry == NULL)
114 {
115 FATAL("Invalid context, image stream, or index entry pointer.");
116 TRACE("Exiting process_dumphw_block()");
117 if(ctx != NULL) reset_dump_hardware_context(ctx);
118 return;
119 }
120
121 if(entry->blockType != DumpHardwareBlock)
122 {
123 TRACE("Index entry block type %u is not DumpHardwareBlock, skipping.", entry->blockType);
124 TRACE("Exiting process_dumphw_block()");
125 return;
126 }
127
128 if(fseek(ctx->imageStream, (long)entry->offset, SEEK_SET) < 0 || ftell(ctx->imageStream) != entry->offset)
129 {
130 FATAL("Could not seek to %" PRIu64 " as indicated by index entry...", entry->offset);
131 reset_dump_hardware_context(ctx);
132 TRACE("Exiting process_dumphw_block()");
133 return;
134 }
135
136 TRACE("Reading dump hardware block header at position %" PRIu64, entry->offset);
137 DumpHardwareHeader header;
138 read_bytes = fread(&header, 1, sizeof(header), ctx->imageStream);
139
140 if(read_bytes != sizeof(header))
141 {
142 TRACE("Could not read dump hardware block header (read %zu bytes)", read_bytes);
143 reset_dump_hardware_context(ctx);
144 TRACE("Exiting process_dumphw_block()");
145 return;
146 }
147
148 if(header.identifier != DumpHardwareBlock)
149 {
150 TRACE("Incorrect identifier 0x%08" PRIx32 " for dump hardware block at position %" PRIu64, header.identifier,
151 entry->offset);
152 reset_dump_hardware_context(ctx);
153 TRACE("Exiting process_dumphw_block()");
154 return;
155 }
156
157 if(header.entries > 0 && header.length == 0)
158 {
159 TRACE("Dump hardware header indicates %u entries but zero payload length", header.entries);
160 reset_dump_hardware_context(ctx);
161 TRACE("Exiting process_dumphw_block()");
162 return;
163 }
164
165 const uint32_t payload_length = header.length;
166
167 if(payload_length > 0)
168 {
169 uint8_t *payload = (uint8_t *)malloc(payload_length);
170
171 if(payload == NULL)
172 {
173 TRACE("Could not allocate %u bytes for dump hardware payload", payload_length);
174 reset_dump_hardware_context(ctx);
175 TRACE("Exiting process_dumphw_block()");
176 return;
177 }
178
179 read_bytes = fread(payload, 1, payload_length, ctx->imageStream);
180
181 if(read_bytes != payload_length)
182 {
183 TRACE("Could not read dump hardware payload, expected %u bytes got %zu", payload_length, read_bytes);
184 free(payload);
185 reset_dump_hardware_context(ctx);
186 TRACE("Exiting process_dumphw_block()");
187 return;
188 }
189
190 uint64_t crc64 = aaruf_crc64_data(payload, payload_length);
191
192 if(ctx->header.imageMajorVersion <= AARUF_VERSION_V1) crc64 = bswap_64(crc64);
193
194 if(crc64 != header.crc64)
195 {
196 TRACE("Dump hardware block CRC mismatch: computed 0x%" PRIx64 " expected 0x%" PRIx64, crc64, header.crc64);
197 free(payload);
198 reset_dump_hardware_context(ctx);
199 TRACE("Exiting process_dumphw_block()");
200 return;
201 }
202
203 free(payload);
204
205 if(fseek(ctx->imageStream, -(long)payload_length, SEEK_CUR) != 0)
206 {
207 TRACE("Could not rewind after CRC verification");
208 reset_dump_hardware_context(ctx);
209 TRACE("Exiting process_dumphw_block()");
210 return;
211 }
212 }
213
214 if(header.entries == 0)
215 {
216 reset_dump_hardware_context(ctx);
217 ctx->dump_hardware_header = header;
218 TRACE("Dump hardware block contains no entries. Clearing existing metadata.");
219 TRACE("Exiting process_dumphw_block()");
220 return;
221 }
222
223 const size_t allocation_size = (size_t)header.entries * sizeof(DumpHardwareEntriesWithData);
224
225 if(allocation_size / sizeof(DumpHardwareEntriesWithData) != header.entries)
226 {
227 TRACE("Dump hardware entries multiplication overflow (%u entries)", header.entries);
228 reset_dump_hardware_context(ctx);
229 TRACE("Exiting process_dumphw_block()");
230 return;
231 }
232
233 DumpHardwareEntriesWithData *entries =
234 (DumpHardwareEntriesWithData *)calloc(header.entries, sizeof(DumpHardwareEntriesWithData));
235
236 if(entries == NULL)
237 {
238 TRACE("Could not allocate %zu bytes for dump hardware entries", allocation_size);
239 reset_dump_hardware_context(ctx);
240 TRACE("Exiting process_dumphw_block()");
241 return;
242 }
243
244 uint32_t remaining_payload = payload_length;
245 uint16_t processed_entry = 0;
246
247 TRACE("Processing %u dump hardware block entries", header.entries);
248
249 for(uint16_t e = 0; e < header.entries; e++)
250 {
251 processed_entry = e;
252 DumpHardwareEntriesWithData *current = &entries[e];
253
254 if(remaining_payload < sizeof(DumpHardwareEntry))
255 {
256 TRACE("Remaining payload %u too small for dump hardware entry %u", remaining_payload, e);
257 goto parse_failure;
258 }
259
260 read_bytes = fread(&current->entry, 1, sizeof(DumpHardwareEntry), ctx->imageStream);
261
262 if(read_bytes != sizeof(DumpHardwareEntry))
263 {
264 TRACE("Could not read dump hardware entry %u header (read %zu bytes)", e, read_bytes);
265 goto parse_failure;
266 }
267
268 remaining_payload -= sizeof(DumpHardwareEntry);
269
270 if(!read_dump_string(ctx->imageStream, "manufacturer", current->entry.manufacturerLength, &remaining_payload,
271 &current->manufacturer))
272 goto parse_failure;
273
274 if(!read_dump_string(ctx->imageStream, "model", current->entry.modelLength, &remaining_payload,
275 &current->model))
276 goto parse_failure;
277
278 if(!read_dump_string(ctx->imageStream, "revision", current->entry.revisionLength, &remaining_payload,
279 &current->revision))
280 goto parse_failure;
281
282 if(!read_dump_string(ctx->imageStream, "firmware", current->entry.firmwareLength, &remaining_payload,
283 &current->firmware))
284 goto parse_failure;
285
286 if(!read_dump_string(ctx->imageStream, "serial", current->entry.serialLength, &remaining_payload,
287 &current->serial))
288 goto parse_failure;
289
290 if(!read_dump_string(ctx->imageStream, "software name", current->entry.softwareNameLength, &remaining_payload,
291 &current->softwareName))
292 goto parse_failure;
293
294 if(!read_dump_string(ctx->imageStream, "software version", current->entry.softwareVersionLength,
295 &remaining_payload, &current->softwareVersion))
296 goto parse_failure;
297
298 if(!read_dump_string(ctx->imageStream, "software operating system",
299 current->entry.softwareOperatingSystemLength, &remaining_payload,
300 &current->softwareOperatingSystem))
301 goto parse_failure;
302
303 const uint32_t extent_count = current->entry.extents;
304
305 if(extent_count == 0) continue;
306
307 const size_t extent_bytes = (size_t)extent_count * sizeof(DumpExtent);
308
309 if(extent_bytes / sizeof(DumpExtent) != extent_count || extent_bytes > remaining_payload)
310 {
311 TRACE("Extent array for entry %u exceeds remaining payload (%zu bytes requested, %u left)", e, extent_bytes,
312 remaining_payload);
313 goto parse_failure;
314 }
315
316 current->extents = (DumpExtent *)malloc(extent_bytes);
317
318 if(current->extents == NULL)
319 {
320 TRACE("Could not allocate %zu bytes for dump hardware entry %u extents", extent_bytes, e);
321 goto parse_failure;
322 }
323
324 const size_t extents_read = fread(current->extents, sizeof(DumpExtent), extent_count, ctx->imageStream);
325
326 if(extents_read != extent_count)
327 {
328 TRACE("Could not read %u dump hardware extents for entry %u (read %zu)", extent_count, e, extents_read);
329 goto parse_failure;
330 }
331
332 remaining_payload -= (uint32_t)extent_bytes;
333
334 qsort(current->extents, extent_count, sizeof(DumpExtent), compare_extents);
335 TRACE("Sorted %u extents for entry %u", extent_count, e);
336 }
337
338 reset_dump_hardware_context(ctx);
339 ctx->dump_hardware_entries_with_data = entries;
340 ctx->dump_hardware_header = header;
341
342 if(remaining_payload != 0)
343 {
344 TRACE("Dump hardware block parsing completed with %u trailing payload bytes", remaining_payload);
345 }
346
347 TRACE("Exiting process_dumphw_block()");
348 return;
349
350parse_failure:
351 free_dump_hardware_entries_array(entries, processed_entry + 1);
352 free(entries);
353 reset_dump_hardware_context(ctx);
354 TRACE("Exiting process_dumphw_block()");
355}
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:108
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, 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:333
DumpHardwareEntriesWithData
In-memory representation of a dump hardware entry plus decoded variable-length fields & extents.
Definition context.h:314
DumpHardwareEntriesWithData::firmware
uint8_t * firmware
Firmware version string or NULL.
Definition context.h:320
DumpHardwareEntriesWithData::revision
uint8_t * revision
Hardware revision string or NULL.
Definition context.h:319
DumpHardwareEntriesWithData::model
uint8_t * model
Model string or NULL.
Definition context.h:318
DumpHardwareEntriesWithData::softwareName
uint8_t * softwareName
Dump software name or NULL.
Definition context.h:322
DumpHardwareEntriesWithData::extents
struct DumpExtent * extents
Array of extents (entry.extents elements) or NULL.
Definition context.h:316
DumpHardwareEntriesWithData::manufacturer
uint8_t * manufacturer
Manufacturer string (UTF-8) or NULL.
Definition context.h:317
DumpHardwareEntriesWithData::softwareVersion
uint8_t * softwareVersion
Dump software version or NULL.
Definition context.h:323
DumpHardwareEntriesWithData::serial
uint8_t * serial
Serial number string or NULL.
Definition context.h:321
DumpHardwareEntriesWithData::entry
DumpHardwareEntry entry
Fixed-size header with lengths & counts.
Definition context.h:315
DumpHardwareEntriesWithData::softwareOperatingSystem
uint8_t * softwareOperatingSystem
Host operating system string or NULL.
Definition context.h:324
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