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
26static 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
186AARU_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");
201 }
202
203 if(length == NULL)
204 {
205 FATAL("Invalid length pointer");
206
207 TRACE("Exiting aaruf_get_dumphw() = 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");
220 }
221
222 if(ctx->dump_hardware_entries_with_data == NULL || ctx->dump_hardware_header.entries == 0 ||
224 {
225 FATAL("No dump hardware information present");
226
227 TRACE("Exiting aaruf_get_dumphw() = 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");
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");
247 }
248
249 *length = required_length;
250
251 // Start to iterate and copy the data
252 size_t offset = sizeof(DumpHardwareHeader);
253 for(uint32_t i = 0; i < ctx->dump_hardware_header.entries; i++)
254 {
255 size_t entry_size = sizeof(DumpHardwareEntry);
256
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");
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,
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");
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");
293 }
294
295 memcpy(buffer + offset, &ctx->dump_hardware_entries_with_data[i].entry, sizeof(DumpHardwareEntry));
296 offset += sizeof(DumpHardwareEntry);
299 {
300 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].manufacturer,
303 }
306 {
307 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].model,
310 }
313 {
314 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].revision,
317 }
320 {
321 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].firmware,
324 }
327 {
328 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].serial,
331 }
334 {
335 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].softwareName,
338 }
341 {
342 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].softwareVersion,
345 }
348 {
349 memcpy(buffer + offset, ctx->dump_hardware_entries_with_data[i].softwareOperatingSystem,
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
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
531AARU_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");
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");
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");
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");
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");
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");
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");
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");
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 { \
626 const size_t field##_length = copy[e].entry.field##Length; \
627 if(field##_length > 0) \
628 { \
629 if(field##_length > length - pos) goto invalid_data; \
630 /* Allocate only field##_length bytes, since input is NUL-terminated */ \
631 copy[e].field = (uint8_t *)calloc(1, field##_length); \
632 if(copy[e].field == NULL) goto free_copy_and_error; \
633 memcpy(copy[e].field, data + pos, field##_length); \
634 /* Ensure NUL-termination in case input is malformed */ \
635 copy[e].field[field##_length - 1] = '\0'; \
636 pos += field##_length; \
637 } \
638 } while(0)
639
640 for(uint32_t e = 0; e < header.entries; e++)
641 {
642 if(length - pos < sizeof(DumpHardwareEntry)) goto invalid_data;
643
644 memcpy(&copy[e].entry, data + pos, sizeof(DumpHardwareEntry));
645 pos += sizeof(DumpHardwareEntry);
646
647 COPY_STRING_FIELD(manufacturer);
648 COPY_STRING_FIELD(model);
649 COPY_STRING_FIELD(revision);
650 COPY_STRING_FIELD(firmware);
651 COPY_STRING_FIELD(serial);
652 COPY_STRING_FIELD(softwareName);
653 COPY_STRING_FIELD(softwareVersion);
654 COPY_STRING_FIELD(softwareOperatingSystem);
655
656 const uint32_t extent_count = copy[e].entry.extents;
657 if(extent_count > 0)
658 {
659 const size_t extent_bytes = (size_t)extent_count * sizeof(DumpExtent);
660 if(extent_bytes / sizeof(DumpExtent) != extent_count || extent_bytes > length - pos) goto invalid_data;
661
662 copy[e].extents = (DumpExtent *)malloc(extent_bytes);
663 if(copy[e].extents == NULL) goto free_copy_and_error;
664
665 memcpy(copy[e].extents, data + pos, extent_bytes);
666 pos += extent_bytes;
667
668 qsort(copy[e].extents, extent_count, sizeof(DumpExtent), compare_extents);
669 TRACE("Sorted %u extents for entry %u", extent_count, e);
670 }
671 }
672
673#undef COPY_STRING_FIELD
674
675 if(pos != length)
676 {
677 FATAL("Dump hardware block contains trailing data");
678 goto invalid_data;
679 }
680
683 ctx->dump_hardware_header = header;
684 ctx->dirty_dumphw_block = true; // Mark dump hardware block as dirty
685
686 TRACE("Exiting aaruf_set_dumphw() = AARUF_STATUS_OK");
687 return AARUF_STATUS_OK;
688
689invalid_data:
690 TRACE("Dump hardware block truncated or malformed");
692 TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_INCORRECT_DATA_SIZE");
694
695free_copy_and_error:
697 TRACE("Exiting aaruf_set_dumphw() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
699}
#define AARU_MAGIC
Magic identifier for AaruFormat container (ASCII "AARUFRMT").
Definition consts.h:64
#define AARU_CALL
Definition decls.h:45
uint64_t aaruf_crc64_data(const uint8_t *data, uint32_t len)
Definition crc64.c:160
#define AARU_EXPORT
Definition decls.h:54
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
#define COPY_STRING_FIELD(field)
static void free_dump_hardware_entries(DumpHardwareEntriesWithData *entries, uint32_t count)
Definition dump.c:26
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
Block containing an array of hardware used to create the image.
Definition enums.h:156
#define AARUF_STATUS_OK
Sector present and read without uncorrectable errors.
Definition errors.h:75
#define AARUF_READ_ONLY
Operation requires write mode but context is read-only.
Definition errors.h:61
#define AARUF_ERROR_NOT_ENOUGH_MEMORY
Memory allocation failure (critical).
Definition errors.h:48
#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
#define AARUF_ERROR_NOT_AARUFORMAT
Input file/stream failed magic or structural validation.
Definition errors.h:40
#define AARUF_ERROR_BUFFER_TOO_SMALL
Caller-supplied buffer insufficient for data.
Definition errors.h:49
int compare_extents(const void *a, const void *b)
Comparison function for sorting DumpExtent arrays by start sector.
Definition helpers.c:459
#define FATAL(fmt,...)
Definition log.h:40
#define TRACE(fmt,...)
Definition log.h:25
Inclusive [start,end] logical sector range contributed by a single hardware environment.
Definition context.h:359
In-memory representation of a dump hardware entry plus decoded variable-length fields & extents.
Definition context.h:340
uint8_t * firmware
Firmware version string or NULL.
Definition context.h:346
uint8_t * revision
Hardware revision string or NULL.
Definition context.h:345
uint8_t * model
Model string or NULL.
Definition context.h:344
uint8_t * softwareName
Dump software name or NULL.
Definition context.h:348
struct DumpExtent * extents
Array of extents (entry.extents elements) or NULL.
Definition context.h:342
uint8_t * manufacturer
Manufacturer string (UTF-8) or NULL.
Definition context.h:343
uint8_t * softwareVersion
Dump software version or NULL.
Definition context.h:349
uint8_t * serial
Serial number string or NULL.
Definition context.h:347
DumpHardwareEntry entry
Fixed-size header with lengths & counts.
Definition context.h:341
uint8_t * softwareOperatingSystem
Host operating system string or NULL.
Definition context.h:350
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
Master context representing an open or in‑creation Aaru image.
Definition context.h:172
bool is_writing
True if context opened/created for writing.
Definition context.h:292
uint64_t magic
File magic (AARU_MAGIC) post-open.
Definition context.h:174
struct DumpHardwareEntriesWithData * dump_hardware_entries_with_data
Array of dump hardware entries + strings.
Definition context.h:212
bool dirty_dumphw_block
True if dump hardware block should be written during close.
Definition context.h:327
DumpHardwareHeader dump_hardware_header
Dump hardware header.
Definition context.h:232