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 <stdint.h>
20#include <stdlib.h>
21
22#include "aaruformat.h"
23#include "internal.h"
24#include "log.h"
25
26 static void free_dump_hardware_entries(DumpHardwareEntriesWithData *entries, uint32_t count)
27{
28 if(entries == NULL) return;
29
30 for(uint32_t e = 0; e < count; e++)
31 {
32 free(entries[e].manufacturer);
33 free(entries[e].model);
34 free(entries[e].revision);
35 free(entries[e].firmware);
36 free(entries[e].serial);
37 free(entries[e].softwareName);
38 free(entries[e].softwareVersion);
39 free(entries[e].softwareOperatingSystem);
40 free(entries[e].extents);
41 }
42
43 free(entries);
44}
45
186 AARU_EXPORT int32_t AARU_CALL aaruf_get_dumphw(void *context, uint8_t *buffer, size_t *length)
187{
188 size_t length_value = 0;
189 if(length != NULL) length_value = *length;
190
191 TRACE("Entering aaruf_get_dumphw(%p, %p, %zu)", context, buffer, length_value);
192
193 aaruformat_context *ctx = NULL;
194
195 if(context == NULL)
196 {
197 FATAL("Invalid context");
198
199 TRACE("Exiting aaruf_get_dumphw() = AARUF_ERROR_NOT_AARUFORMAT");
200 return AARUF_ERROR_NOT_AARUFORMAT;
201 }
202
203 if(length == NULL)
204 {
205 FATAL("Invalid length pointer");
206
207 TRACE("Exiting aaruf_get_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
208 return AARUF_ERROR_INCORRECT_DATA_SIZE;
209 }
210
211 ctx = context;
212
213 // Not a libaaruformat context
214 if(ctx->magic != AARU_MAGIC)
215 {
216 FATAL("Invalid context");
217
218 TRACE("Exiting aaruf_get_dumphw() = AARUF_ERROR_NOT_AARUFORMAT");
219 return AARUF_ERROR_NOT_AARUFORMAT;
220 }
221
222 if(ctx->dump_hardware_entries_with_data == NULL || ctx->dump_hardware_header.entries == 0 ||
223 ctx->dump_hardware_header.identifier != DumpHardwareBlock)
224 {
225 FATAL("No dump hardware information present");
226
227 TRACE("Exiting aaruf_get_dumphw() = AARUF_ERROR_CANNOT_READ_BLOCK");
228 return AARUF_ERROR_CANNOT_READ_BLOCK;
229 }
230
231 size_t required_length = sizeof(DumpHardwareHeader) + (size_t)ctx->dump_hardware_header.length;
232 if(required_length < sizeof(DumpHardwareHeader))
233 {
234 FATAL("Dump hardware payload length overflow");
235
236 TRACE("Exiting aaruf_get_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
237 return AARUF_ERROR_INCORRECT_DATA_SIZE;
238 }
239
240 if(buffer == NULL || *length < required_length)
241 {
242 TRACE("Buffer too small for dump hardware block, required %zu bytes", required_length);
243 *length = required_length;
244
245 TRACE("Exiting aaruf_get_dumphw() = AARUF_ERROR_BUFFER_TOO_SMALL");
246 return AARUF_ERROR_BUFFER_TOO_SMALL;
247 }
248
249 *length = required_length;
250
251 // Start to iterate and copy the data
252 size_t offset = 0;
253 for(uint32_t i = 0; i < ctx->dump_hardware_header.entries; i++)
254 {
255 size_t entry_size = sizeof(DumpHardwareEntry);
256
257 const DumpHardwareEntry *entry = &ctx->dump_hardware_entries_with_data[i].entry;
258
259 const size_t extent_bytes = (size_t)entry->extents * sizeof(DumpExtent);
260 if(entry->extents != 0 && extent_bytes / sizeof(DumpExtent) != entry->extents)
261 {
262 FATAL("Dump hardware extent size overflow");
263 TRACE("Exiting aaruf_get_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
264 return AARUF_ERROR_INCORRECT_DATA_SIZE;
265 }
266
267 const size_t additive_lengths[] = {entry->manufacturerLength,
268 entry->modelLength,
269 entry->revisionLength,
270 entry->firmwareLength,
271 entry->serialLength,
272 entry->softwareNameLength,
273 entry->softwareVersionLength,
274 entry->softwareOperatingSystemLength,
275 extent_bytes};
276
277 for(size_t j = 0; j < sizeof(additive_lengths) / sizeof(additive_lengths[0]); j++)
278 {
279 if(additive_lengths[j] > SIZE_MAX - entry_size)
280 {
281 FATAL("Dump hardware entry size overflow");
282 TRACE("Exiting aaruf_get_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
283 return AARUF_ERROR_INCORRECT_DATA_SIZE;
284 }
285 entry_size += additive_lengths[j];
286 }
287
288 if(offset + entry_size > *length)
289 {
290 FATAL("Calculated size exceeds provided buffer length");
291 TRACE("Exiting aaruf_get_dumphw() = AARUF_ERROR_BUFFER_TOO_SMALL");
292 return AARUF_ERROR_BUFFER_TOO_SMALL;
293 }
294
295 memcpy(buffer + offset, &ctx->dump_hardware_entries_with_data[i].entry, sizeof(DumpHardwareEntry));
296 offset += sizeof(DumpHardwareEntry);
297 if(ctx->dump_hardware_entries_with_data[i].entry.manufacturerLength > 0 &&
298 ctx->dump_hardware_entries_with_data[i].manufacturer != NULL)
299 {
300 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].manufacturer,
301 ctx->dump_hardware_entries_with_data[i].entry.manufacturerLength);
302 offset += ctx->dump_hardware_entries_with_data[i].entry.manufacturerLength;
303 }
304 if(ctx->dump_hardware_entries_with_data[i].entry.modelLength > 0 &&
305 ctx->dump_hardware_entries_with_data[i].model != NULL)
306 {
307 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].model,
308 ctx->dump_hardware_entries_with_data[i].entry.modelLength);
309 offset += ctx->dump_hardware_entries_with_data[i].entry.modelLength;
310 }
311 if(ctx->dump_hardware_entries_with_data[i].entry.revisionLength > 0 &&
312 ctx->dump_hardware_entries_with_data[i].revision != NULL)
313 {
314 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].revision,
315 ctx->dump_hardware_entries_with_data[i].entry.revisionLength);
316 offset += ctx->dump_hardware_entries_with_data[i].entry.revisionLength;
317 }
318 if(ctx->dump_hardware_entries_with_data[i].entry.firmwareLength > 0 &&
319 ctx->dump_hardware_entries_with_data[i].firmware != NULL)
320 {
321 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].firmware,
322 ctx->dump_hardware_entries_with_data[i].entry.firmwareLength);
323 offset += ctx->dump_hardware_entries_with_data[i].entry.firmwareLength;
324 }
325 if(ctx->dump_hardware_entries_with_data[i].entry.serialLength > 0 &&
326 ctx->dump_hardware_entries_with_data[i].serial != NULL)
327 {
328 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].serial,
329 ctx->dump_hardware_entries_with_data[i].entry.serialLength);
330 offset += ctx->dump_hardware_entries_with_data[i].entry.serialLength;
331 }
332 if(ctx->dump_hardware_entries_with_data[i].entry.softwareNameLength > 0 &&
333 ctx->dump_hardware_entries_with_data[i].softwareName != NULL)
334 {
335 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].softwareName,
336 ctx->dump_hardware_entries_with_data[i].entry.softwareNameLength);
337 offset += ctx->dump_hardware_entries_with_data[i].entry.softwareNameLength;
338 }
339 if(ctx->dump_hardware_entries_with_data[i].entry.softwareVersionLength > 0 &&
340 ctx->dump_hardware_entries_with_data[i].softwareVersion != NULL)
341 {
342 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].softwareVersion,
343 ctx->dump_hardware_entries_with_data[i].entry.softwareVersionLength);
344 offset += ctx->dump_hardware_entries_with_data[i].entry.softwareVersionLength;
345 }
346 if(ctx->dump_hardware_entries_with_data[i].entry.softwareOperatingSystemLength > 0 &&
347 ctx->dump_hardware_entries_with_data[i].softwareOperatingSystem != NULL)
348 {
349 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].softwareOperatingSystem,
350 ctx->dump_hardware_entries_with_data[i].entry.softwareOperatingSystemLength);
351 offset += ctx->dump_hardware_entries_with_data[i].entry.softwareOperatingSystemLength;
352 }
353 if(entry->extents > 0 && ctx->dump_hardware_entries_with_data[i].extents != NULL)
354 {
355 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].extents, extent_bytes);
356 offset += extent_bytes;
357 }
358 }
359
360 // Calculate CRC64
361 ctx->dump_hardware_header.crc64 =
362 aaruf_crc64_data(buffer + sizeof(DumpHardwareHeader), ctx->dump_hardware_header.length);
363
364 // Copy header
365 memcpy(buffer, &ctx->dump_hardware_header, sizeof(DumpHardwareHeader));
366
367 TRACE("Exiting aaruf_get_dumphw() = AARUF_STATUS_OK");
368 return AARUF_STATUS_OK;
369}
370
531 AARU_EXPORT int32_t AARU_CALL aaruf_set_dumphw(void *context, uint8_t *data, size_t length)
532{
533 TRACE("Entering aaruf_set_dumphw(%p, %p, %zu)", context, data, length);
534
535 // Check context is correct AaruFormat context
536 if(context == NULL)
537 {
538 FATAL("Invalid context");
539
540 TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_NOT_AARUFORMAT");
541 return AARUF_ERROR_NOT_AARUFORMAT;
542 }
543
544 aaruformat_context *ctx = context;
545
546 // Not a libaaruformat context
547 if(ctx->magic != AARU_MAGIC)
548 {
549 FATAL("Invalid context");
550
551 TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_NOT_AARUFORMAT");
552 return AARUF_ERROR_NOT_AARUFORMAT;
553 }
554
555 // Check we are writing
556 if(!ctx->is_writing)
557 {
558 FATAL("Trying to write a read-only image");
559
560 TRACE("Exiting aaruf_set_dumphw() = AARUF_READ_ONLY");
561 return AARUF_READ_ONLY;
562 }
563
564 if(data == NULL || length == 0)
565 {
566 FATAL("Invalid data or length");
567
568 TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
569 return AARUF_ERROR_INCORRECT_DATA_SIZE;
570 }
571
572 if(length < sizeof(DumpHardwareHeader))
573 {
574 FATAL("Dump hardware block shorter than header");
575
576 TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
577 return AARUF_ERROR_INCORRECT_DATA_SIZE;
578 }
579
580 DumpHardwareHeader header;
581 memcpy(&header, data, sizeof(DumpHardwareHeader));
582 if(header.identifier != DumpHardwareBlock)
583 {
584 FATAL("Invalid dump hardware block identifier");
585
586 TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_CANNOT_READ_BLOCK");
587 return AARUF_ERROR_CANNOT_READ_BLOCK;
588 }
589
590 if(length != sizeof(DumpHardwareHeader) + header.length)
591 {
592 FATAL("Invalid dump hardware block length");
593
594 TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
595 return AARUF_ERROR_INCORRECT_DATA_SIZE;
596 }
597
598 uint64_t crc64 = aaruf_crc64_data(data + sizeof(DumpHardwareHeader), header.length);
599 if(header.crc64 != crc64)
600 {
601 FATAL("Invalid dump hardware block CRC64");
602
603 TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_INVALID_BLOCK_CRC");
604 return AARUF_ERROR_INVALID_BLOCK_CRC;
605 }
606
607 DumpHardwareEntriesWithData *copy = NULL;
608 if(header.entries > 0)
609 {
610 copy = calloc(header.entries, sizeof(DumpHardwareEntriesWithData));
611 if(copy == NULL)
612 {
613 TRACE("Could not allocate memory for dump hardware block entries");
614 TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
615 return AARUF_ERROR_NOT_ENOUGH_MEMORY;
616 }
617 }
618
619 TRACE("Processing %u dump hardware block entries", header.entries);
620
621 size_t pos = sizeof(DumpHardwareHeader);
622
623#define COPY_STRING_FIELD(field) \
624 do { \
625 const size_t field##_length = copy[e].entry.field##Length; \
626 if(field##_length > 0) \
627 { \
628 if(field##_length > length - pos) goto invalid_data; \
629 copy[e].field = (uint8_t *)calloc(1, field##_length + 1); \
630 if(copy[e].field == NULL) goto free_copy_and_error; \
631 memcpy(copy[e].field, data + pos, field##_length); \
632 pos += field##_length; \
633 } \
634 } while(0)
635
636 for(uint32_t e = 0; e < header.entries; e++)
637 {
638 if(length - pos < sizeof(DumpHardwareEntry)) goto invalid_data;
639
640 memcpy(&copy[e].entry, data + pos, sizeof(DumpHardwareEntry));
641 pos += sizeof(DumpHardwareEntry);
642
643 COPY_STRING_FIELD(manufacturer);
644 COPY_STRING_FIELD(model);
645 COPY_STRING_FIELD(revision);
646 COPY_STRING_FIELD(firmware);
647 COPY_STRING_FIELD(serial);
648 COPY_STRING_FIELD(softwareName);
649 COPY_STRING_FIELD(softwareVersion);
650 COPY_STRING_FIELD(softwareOperatingSystem);
651
652 const uint32_t extent_count = copy[e].entry.extents;
653 if(extent_count > 0)
654 {
655 const size_t extent_bytes = (size_t)extent_count * sizeof(DumpExtent);
656 if(extent_bytes / sizeof(DumpExtent) != extent_count || extent_bytes > length - pos) goto invalid_data;
657
658 copy[e].extents = (DumpExtent *)malloc(extent_bytes);
659 if(copy[e].extents == NULL) goto free_copy_and_error;
660
661 memcpy(copy[e].extents, data + pos, extent_bytes);
662 pos += extent_bytes;
663
664 qsort(copy[e].extents, extent_count, sizeof(DumpExtent), compare_extents);
665 TRACE("Sorted %u extents for entry %u", extent_count, e);
666 }
667 }
668
669#undef COPY_STRING_FIELD
670
671 if(pos != length)
672 {
673 FATAL("Dump hardware block contains trailing data");
674 goto invalid_data;
675 }
676
677 free_dump_hardware_entries(ctx->dump_hardware_entries_with_data, ctx->dump_hardware_header.entries);
678 ctx->dump_hardware_entries_with_data = copy;
679 ctx->dump_hardware_header = header;
680
681 TRACE("Exiting aaruf_set_dumphw() = AARUF_STATUS_OK");
682 return AARUF_STATUS_OK;
683
684invalid_data:
685 TRACE("Dump hardware block truncated or malformed");
686 free_dump_hardware_entries(copy, header.entries);
687 TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
688 return AARUF_ERROR_INCORRECT_DATA_SIZE;
689
690free_copy_and_error:
691 free_dump_hardware_entries(copy, header.entries);
692 TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
693 return AARUF_ERROR_NOT_ENOUGH_MEMORY;
694}
aaruformat.h
AARU_MAGIC
#define AARU_MAGIC
Magic identifier for AaruFormat container (ASCII "AARUFRMT").
Definition consts.h:64
AARU_CALL
#define AARU_CALL
Definition decls.h:45
aaruf_crc64_data
uint64_t aaruf_crc64_data(const uint8_t *data, uint32_t len)
Definition crc64.c:160
AARU_EXPORT
#define AARU_EXPORT
Definition decls.h:54
aaruf_get_dumphw
int32_t aaruf_get_dumphw(void *context, uint8_t *buffer, size_t *length)
Retrieves the dump hardware block containing acquisition environment information.
Definition dump.c:186
COPY_STRING_FIELD
#define COPY_STRING_FIELD(field)
free_dump_hardware_entries
static void free_dump_hardware_entries(DumpHardwareEntriesWithData *entries, uint32_t count)
Definition dump.c:26
aaruf_set_dumphw
int32_t aaruf_set_dumphw(void *context, uint8_t *data, size_t length)
Sets the dump hardware block for the image during creation.
Definition dump.c:531
DumpHardwareBlock
@ DumpHardwareBlock
Block containing an array of hardware used to create the image.
Definition enums.h:156
AARUF_STATUS_OK
#define AARUF_STATUS_OK
Sector present and read without uncorrectable errors.
Definition errors.h:75
AARUF_READ_ONLY
#define AARUF_READ_ONLY
Operation requires write mode but context is read-only.
Definition errors.h:61
AARUF_ERROR_NOT_ENOUGH_MEMORY
#define AARUF_ERROR_NOT_ENOUGH_MEMORY
Memory allocation failure (critical).
Definition errors.h:48
AARUF_ERROR_CANNOT_READ_BLOCK
#define AARUF_ERROR_CANNOT_READ_BLOCK
Generic block read failure (seek/read error).
Definition errors.h:46
AARUF_ERROR_INCORRECT_DATA_SIZE
#define AARUF_ERROR_INCORRECT_DATA_SIZE
Data size does not match expected size.
Definition errors.h:65
AARUF_ERROR_INVALID_BLOCK_CRC
#define AARUF_ERROR_INVALID_BLOCK_CRC
CRC64 mismatch indicating corruption.
Definition errors.h:57
AARUF_ERROR_NOT_AARUFORMAT
#define AARUF_ERROR_NOT_AARUFORMAT
Input file/stream failed magic or structural validation.
Definition errors.h:40
AARUF_ERROR_BUFFER_TOO_SMALL
#define AARUF_ERROR_BUFFER_TOO_SMALL
Caller-supplied buffer insufficient for data.
Definition errors.h:49
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
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
aaruformat_context
Master context representing an open or in‑creation Aaru image.
Definition context.h:172
aaruformat_context::is_writing
bool is_writing
True if context opened/created for writing.
Definition context.h:292
aaruformat_context::magic
uint64_t magic
File magic (AARU_MAGIC) post-open.
Definition context.h:174
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::dump_hardware_header
DumpHardwareHeader dump_hardware_header
Dump hardware header.
Definition context.h:232