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-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 <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"
33#include "internal.h"
34#include "log.h"
35
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
63
64static 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
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(aaruf_fseek(ctx->imageStream, (aaru_off_t)entry->offset, SEEK_SET) < 0 ||
128 aaruf_ftell(ctx->imageStream) != (aaru_off_t)entry->offset)
129 {
130 FATAL("Could not seek to %" PRIu64 " as indicated by index entry...", entry->offset);
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);
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);
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);
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 = malloc(payload_length);
170
171 if(payload == NULL)
172 {
173 TRACE("Could not allocate %u bytes for dump hardware payload", payload_length);
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);
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);
199 TRACE("Exiting process_dumphw_block()");
200 return;
201 }
202
203 free(payload);
204
205 if(aaruf_fseek(ctx->imageStream, -(aaru_off_t)payload_length, SEEK_CUR) != 0)
206 {
207 TRACE("Could not rewind after CRC verification");
209 TRACE("Exiting process_dumphw_block()");
210 return;
211 }
212 }
213
214 if(header.entries == 0)
215 {
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);
229 TRACE("Exiting process_dumphw_block()");
230 return;
231 }
232
233 DumpHardwareEntriesWithData *entries = calloc(header.entries, sizeof(DumpHardwareEntriesWithData));
234
235 if(entries == NULL)
236 {
237 TRACE("Could not allocate %zu bytes for dump hardware entries", allocation_size);
239 TRACE("Exiting process_dumphw_block()");
240 return;
241 }
242
243 uint32_t remaining_payload = payload_length;
244 uint16_t processed_entry = 0;
245
246 TRACE("Processing %u dump hardware block entries", header.entries);
247
248 for(uint16_t e = 0; e < header.entries; e++)
249 {
250 processed_entry = e;
251 DumpHardwareEntriesWithData *current = &entries[e];
252
253 if(remaining_payload < sizeof(DumpHardwareEntry))
254 {
255 TRACE("Remaining payload %u too small for dump hardware entry %u", remaining_payload, e);
256 goto parse_failure;
257 }
258
259 read_bytes = fread(&current->entry, 1, sizeof(DumpHardwareEntry), ctx->imageStream);
260
261 if(read_bytes != sizeof(DumpHardwareEntry))
262 {
263 TRACE("Could not read dump hardware entry %u header (read %zu bytes)", e, read_bytes);
264 goto parse_failure;
265 }
266
267 remaining_payload -= sizeof(DumpHardwareEntry);
268
269 if(!read_dump_string(ctx->imageStream, "manufacturer", current->entry.manufacturerLength, &remaining_payload,
270 &current->manufacturer))
271 goto parse_failure;
272
273 if(!read_dump_string(ctx->imageStream, "model", current->entry.modelLength, &remaining_payload,
274 &current->model))
275 goto parse_failure;
276
277 if(!read_dump_string(ctx->imageStream, "revision", current->entry.revisionLength, &remaining_payload,
278 &current->revision))
279 goto parse_failure;
280
281 if(!read_dump_string(ctx->imageStream, "firmware", current->entry.firmwareLength, &remaining_payload,
282 &current->firmware))
283 goto parse_failure;
284
285 if(!read_dump_string(ctx->imageStream, "serial", current->entry.serialLength, &remaining_payload,
286 &current->serial))
287 goto parse_failure;
288
289 if(!read_dump_string(ctx->imageStream, "software name", current->entry.softwareNameLength, &remaining_payload,
290 &current->softwareName))
291 goto parse_failure;
292
293 if(!read_dump_string(ctx->imageStream, "software version", current->entry.softwareVersionLength,
294 &remaining_payload, &current->softwareVersion))
295 goto parse_failure;
296
297 if(!read_dump_string(ctx->imageStream, "software operating system",
298 current->entry.softwareOperatingSystemLength, &remaining_payload,
299 &current->softwareOperatingSystem))
300 goto parse_failure;
301
302 const uint32_t extent_count = current->entry.extents;
303
304 if(extent_count == 0) continue;
305
306 const size_t extent_bytes = (size_t)extent_count * sizeof(DumpExtent);
307
308 if(extent_bytes / sizeof(DumpExtent) != extent_count || extent_bytes > remaining_payload)
309 {
310 TRACE("Extent array for entry %u exceeds remaining payload (%zu bytes requested, %u left)", e, extent_bytes,
311 remaining_payload);
312 goto parse_failure;
313 }
314
315 current->extents = (DumpExtent *)malloc(extent_bytes);
316
317 if(current->extents == NULL)
318 {
319 TRACE("Could not allocate %zu bytes for dump hardware entry %u extents", extent_bytes, e);
320 goto parse_failure;
321 }
322
323 const size_t extents_read = fread(current->extents, sizeof(DumpExtent), extent_count, ctx->imageStream);
324
325 if(extents_read != extent_count)
326 {
327 TRACE("Could not read %u dump hardware extents for entry %u (read %zu)", extent_count, e, extents_read);
328 goto parse_failure;
329 }
330
331 remaining_payload -= (uint32_t)extent_bytes;
332
333 qsort(current->extents, extent_count, sizeof(DumpExtent), compare_extents);
334 TRACE("Sorted %u extents for entry %u", extent_count, e);
335 }
336
338 ctx->dump_hardware_entries_with_data = entries;
339 ctx->dump_hardware_header = header;
340
341 if(remaining_payload != 0)
342 {
343 TRACE("Dump hardware block parsing completed with %u trailing payload bytes", remaining_payload);
344 }
345
346 TRACE("Exiting process_dumphw_block()");
347 return;
348
349parse_failure:
350 free_dump_hardware_entries_array(entries, processed_entry + 1);
351 free(entries);
353 TRACE("Exiting process_dumphw_block()");
354}
void process_dumphw_block(aaruformat_context *ctx, const IndexEntry *entry)
Processes a dump hardware block from the image stream.
Definition dump.c:107
static void reset_dump_hardware_context(aaruformat_context *ctx)
Definition dump.c:54
static void free_dump_hardware_entries_array(DumpHardwareEntriesWithData *entries, uint16_t count)
Definition dump.c:36
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
Core public constants and compile‑time limits for the Aaru container format implementation.
#define AARUF_VERSION_V1
First on‑disk version (C# implementation).
Definition consts.h:71
Central runtime context structures for libaaruformat (image state, caches, checksum buffers).
uint64_t aaruf_crc64_data(const uint8_t *data, uint32_t len)
Definition crc64.c:160
Packed on-disk structures describing hardware and software used during image acquisition.
#define bswap_64(x)
Definition endian.h:81
@ DumpHardwareBlock
Block containing an array of hardware used to create the image.
Definition enums.h:180
On‑disk index block header and entry structures (versions 1, 2 and 3).
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
int compare_extents(const void *a, const void *b)
Comparison function for sorting DumpExtent arrays by start sector.
Definition helpers.c:511
int64_t aaru_off_t
Definition internal.h:42
#define FATAL(fmt,...)
Definition log.h:40
#define TRACE(fmt,...)
Definition log.h:25
uint8_t imageMajorVersion
Container format major version.
Definition header.h:110
Inclusive [start,end] logical sector range contributed by a single hardware environment.
Definition context.h:431
In-memory representation of a dump hardware entry plus decoded variable-length fields & extents.
Definition context.h:412
uint8_t * firmware
Firmware version string or NULL.
Definition context.h:418
uint8_t * revision
Hardware revision string or NULL.
Definition context.h:417
uint8_t * model
Model string or NULL.
Definition context.h:416
uint8_t * softwareName
Dump software name or NULL.
Definition context.h:420
struct DumpExtent * extents
Array of extents (entry.extents elements) or NULL.
Definition context.h:414
uint8_t * manufacturer
Manufacturer string (UTF-8) or NULL.
Definition context.h:415
uint8_t * softwareVersion
Dump software version or NULL.
Definition context.h:421
uint8_t * serial
Serial number string or NULL.
Definition context.h:419
DumpHardwareEntry entry
Fixed-size header with lengths & counts.
Definition context.h:413
uint8_t * softwareOperatingSystem
Host operating system string or NULL.
Definition context.h:422
Per-environment length table describing subsequent UTF-8 strings and optional extent array.
Definition dump.h:113
uint32_t softwareNameLength
Length in bytes of dumping software name string.
Definition dump.h:119
uint32_t manufacturerLength
Length in bytes of manufacturer UTF-8 string.
Definition dump.h:114
uint32_t softwareVersionLength
Length in bytes of dumping software version string.
Definition dump.h:120
uint32_t firmwareLength
Length in bytes of firmware version string.
Definition dump.h:117
uint32_t extents
Number of DumpExtent records following the strings (0 = none).
Definition dump.h:122
uint32_t modelLength
Length in bytes of model UTF-8 string.
Definition dump.h:115
uint32_t serialLength
Length in bytes of device serial number string.
Definition dump.h:118
uint32_t revisionLength
Length in bytes of revision / hardware revision string.
Definition dump.h:116
uint32_t softwareOperatingSystemLength
Length in bytes of host operating system string.
Definition dump.h:121
Header that precedes a sequence of dump hardware entries and their variable-length payload.
Definition dump.h:91
uint64_t crc64
CRC64-ECMA of the payload (byte-swapped for legacy v1 images, handled automatically).
Definition dump.h:95
uint32_t identifier
Block identifier, must be BlockType::DumpHardwareBlock.
Definition dump.h:92
uint32_t length
Total payload bytes after this header (sum of entries, strings, and extents arrays).
Definition dump.h:94
uint16_t entries
Number of DumpHardwareEntry records that follow.
Definition dump.h:93
Single index entry describing a block's type, (optional) data classification, and file offset.
Definition index.h:109
uint32_t blockType
Block identifier of the referenced block (value from BlockType).
Definition index.h:110
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:175
AaruHeaderV2 header
Parsed container header (v2).
Definition context.h:178
struct DumpHardwareEntriesWithData * dump_hardware_entries_with_data
Array of dump hardware entries + strings.
Definition context.h:215
FILE * imageStream
Underlying FILE* stream (binary mode).
Definition context.h:179
DumpHardwareHeader dump_hardware_header
Dump hardware header.
Definition context.h:235