libaaruformat 1.0
Aaru Data Preservation Suite - Format Library
Loading...
Searching...
No Matches
open.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 <errno.h>
20#include <inttypes.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include <aaruformat.h>
26
27#include "internal.h"
28#include "log.h"
29#include "utarray.h"
30
32{
33 if(ctx == NULL) return;
34
35 if(ctx->imageStream != NULL)
36 {
37 fclose(ctx->imageStream);
38 ctx->imageStream = NULL;
39 }
40
41 free(ctx->readableSectorTags);
42 ctx->readableSectorTags = NULL;
43
44 free(ctx);
45}
46
125void *aaruf_open(const char *filepath) // NOLINT(readability-function-size)
126{
127 aaruformat_context *ctx = NULL;
128 int error_no = 0;
129 size_t read_bytes = 0;
130 long pos = 0;
131 int i = 0;
132 uint32_t signature = 0;
133 UT_array *index_entries = NULL;
134
135#ifdef USE_SLOG
136#include "slog.h"
137
138 slog_init("aaruformat.log", SLOG_FLAGS_ALL, 0);
139#endif
140
141 TRACE("Logging initialized");
142
143 TRACE("Entering aaruf_open(%s)", filepath);
144
145 TRACE("Allocating memory for context");
146 ctx = (aaruformat_context *)malloc(sizeof(aaruformat_context));
147
148 if(ctx == NULL)
149 {
150 FATAL("Not enough memory to create context");
152
153 TRACE("Exiting aaruf_open() = NULL");
154 return NULL;
155 }
156
157 memset(ctx, 0, sizeof(aaruformat_context));
158
159 TRACE("Opening file %s", filepath);
160 ctx->imageStream = fopen(filepath, "rb");
161
162 if(ctx->imageStream == NULL)
163 {
164 FATAL("Error %d opening file %s for reading", errno, filepath);
165 error_no = errno;
167 errno = error_no;
168
169 TRACE("Exiting aaruf_open() = NULL");
170 return NULL;
171 }
172
173 TRACE("Reading header at position 0");
174 fseek(ctx->imageStream, 0, SEEK_SET);
175 read_bytes = fread(&ctx->header, 1, sizeof(AaruHeader), ctx->imageStream);
176
177 if(read_bytes != sizeof(AaruHeader))
178 {
179 FATAL("Could not read header");
182
183 TRACE("Exiting aaruf_open() = NULL");
184 return NULL;
185 }
186
188 {
189 FATAL("Incorrect identifier for AaruFormat file: %8.8s", (char *)&ctx->header.identifier);
192
193 TRACE("Exiting aaruf_open() = NULL");
194 return NULL;
195 }
196
197 // Read new header version
199 {
200 TRACE("Reading new header version at position 0");
201 fseek(ctx->imageStream, 0, SEEK_SET);
202 read_bytes = fread(&ctx->header, 1, sizeof(AaruHeaderV2), ctx->imageStream);
203
204 if(read_bytes != sizeof(AaruHeaderV2))
205 {
208
209 return NULL;
210 }
211 }
212
214 {
215 FATAL("Incompatible AaruFormat version %d.%d found, maximum supported is %d.%d", ctx->header.imageMajorVersion,
219
220 TRACE("Exiting aaruf_open() = NULL");
221 return NULL;
222 }
223
224 TRACE("Opening image version %d.%d", ctx->header.imageMajorVersion, ctx->header.imageMinorVersion);
225
226 TRACE("Allocating memory for readable sector tags bitmap");
227 ctx->readableSectorTags = (bool *)malloc(sizeof(bool) * MaxSectorTag);
228
229 if(ctx->readableSectorTags == NULL)
230 {
231 FATAL("Could not allocate memory for readable sector tags bitmap");
234
235 TRACE("Exiting aaruf_open() = NULL");
236 return NULL;
237 }
238
239 memset(ctx->readableSectorTags, 0, sizeof(bool) * MaxSectorTag);
240
241 TRACE("Setting up image info");
242
243 // Handle application name based on image version
244 memset(ctx->image_info.Application, 0, 64);
245
247 {
248 // Version 2+: application name is UTF-8, direct copy
249 TRACE("Converting application name (v2+): UTF-8 direct copy");
250 size_t copy_len = AARU_HEADER_APP_NAME_LEN < 63 ? AARU_HEADER_APP_NAME_LEN : 63;
251 memcpy(ctx->image_info.Application, ctx->header.application, copy_len);
252 ctx->image_info.Application[63] = '\0';
253 }
254 else
255 {
256 // Version 1: application name is UTF-16LE, convert by taking every other byte
257 TRACE("Converting application name (v1): UTF-16LE to ASCII");
258 int dest_idx = 0;
259 for(int j = 0; j < AARU_HEADER_APP_NAME_LEN && dest_idx < 63; j += 2)
260 // Take the low byte, skip the high byte (assuming it's 0x00 for ASCII)
261 if(ctx->header.application[j] != 0)
262 ctx->image_info.Application[dest_idx++] = ctx->header.application[j];
263 else
264 // Stop at null terminator
265 break;
266 ctx->image_info.Application[dest_idx] = '\0';
267 }
268
269 // Set application version string directly in the fixed-size array
270 memset(ctx->image_info.ApplicationVersion, 0, 32);
273
274 // Set image version string directly in the fixed-size array
275 memset(ctx->image_info.Version, 0, 32);
276 sprintf(ctx->image_info.Version, "%d.%d", ctx->header.imageMajorVersion, ctx->header.imageMinorVersion);
277
279
280 // Read the index header
281 TRACE("Reading index header at position %" PRIu64, ctx->header.indexOffset);
282 pos = fseek(ctx->imageStream, ctx->header.indexOffset, SEEK_SET);
283 if(pos < 0)
284 {
287
288 return NULL;
289 }
290
291 pos = ftell(ctx->imageStream);
292 if(pos != ctx->header.indexOffset)
293 {
296
297 return NULL;
298 }
299
300 read_bytes = fread(&signature, 1, sizeof(uint32_t), ctx->imageStream);
301
302 if(read_bytes != sizeof(uint32_t) ||
303 (signature != IndexBlock && signature != IndexBlock2 && signature != IndexBlock3))
304 {
305 FATAL("Could not read index header or incorrect identifier %4.4s", (char *)&signature);
308
309 TRACE("Exiting aaruf_open() = NULL");
310 return NULL;
311 }
312
313 if(signature == IndexBlock)
314 index_entries = process_index_v1(ctx);
315 else if(signature == IndexBlock2)
316 index_entries = process_index_v2(ctx);
317 else if(signature == IndexBlock3)
318 index_entries = process_index_v3(ctx);
319
320 if(index_entries == NULL)
321 {
322 FATAL("Could not process index.");
323 utarray_free(index_entries);
326
327 TRACE("Exiting aaruf_open() = NULL");
328 return NULL;
329 }
330
331 TRACE("Index at %" PRIu64 " contains %d entries", ctx->header.indexOffset, utarray_len(index_entries));
332
333 for(i = 0; i < utarray_len(index_entries); i++)
334 {
335 IndexEntry *entry = utarray_eltptr(index_entries, i);
336 TRACE("Block type %4.4s with data type %d is indexed to be at %" PRIu64 "", (char *)&entry->blockType,
337 entry->dataType, entry->offset);
338 }
339
340 bool found_user_data_ddt = false;
341 ctx->image_info.ImageSize = 0;
342 for(i = 0; i < utarray_len(index_entries); i++)
343 {
344 IndexEntry *entry = utarray_eltptr(index_entries, i);
345 pos = fseek(ctx->imageStream, entry->offset, SEEK_SET);
346
347 if(pos < 0 || ftell(ctx->imageStream) != entry->offset)
348 {
349 TRACE("Could not seek to %" PRIu64 " as indicated by index entry %d, continuing...", entry->offset, i);
350
351 continue;
352 }
353
354 TRACE("Processing block type %4.4s with data type %d at position %" PRIu64 "", (char *)&entry->blockType,
355 entry->dataType, entry->offset);
356 switch(entry->blockType)
357 {
358 case DataBlock:
359 error_no = process_data_block(ctx, entry);
360
361 if(error_no != AARUF_STATUS_OK)
362 {
363 utarray_free(index_entries);
365 errno = error_no;
366
367 return NULL;
368 }
369
370 break;
371
373 error_no = process_ddt_v1(ctx, entry, &found_user_data_ddt);
374
375 if(error_no != AARUF_STATUS_OK)
376 {
377 utarray_free(index_entries);
379 errno = error_no;
380
381 return NULL;
382 }
383
384 break;
386 error_no = process_ddt_v2(ctx, entry, &found_user_data_ddt);
387
388 if(error_no != AARUF_STATUS_OK)
389 {
390 utarray_free(index_entries);
392 errno = error_no;
393
394 return NULL;
395 }
396
397 break;
398 case GeometryBlock:
399 process_geometry_block(ctx, entry);
400
401 break;
402 case MetadataBlock:
403 process_metadata_block(ctx, entry);
404
405 break;
406 case TracksBlock:
407 process_tracks_block(ctx, entry);
408
409 break;
410 case CicmBlock:
411 process_cicm_block(ctx, entry);
412
413 break;
416
417 break;
418 // Dump hardware block
420 process_dumphw_block(ctx, entry);
421
422 break;
423 case ChecksumBlock:
424 process_checksum_block(ctx, entry);
425
426 break;
427 case TapeFileBlock:
428 process_tape_files_block(ctx, entry);
429
430 break;
433
434 break;
435 default:
436 TRACE("Unhandled block type %4.4s with data type %d is indexed to be at %" PRIu64 "",
437 (char *)&entry->blockType, entry->dataType, entry->offset);
438 break;
439 }
440 }
441
442 utarray_free(index_entries);
443
444 if(!found_user_data_ddt)
445 {
446 FATAL("Could not find user data deduplication table, aborting...");
447 aaruf_close(ctx);
448
449 TRACE("Exiting aaruf_open() = NULL");
450 return NULL;
451 }
452
456
458 {
459 ctx->cylinders = (uint32_t)(ctx->image_info.Sectors / 16 / 63);
460 ctx->heads = 16;
461 ctx->sectors_per_track = 63;
462 }
463
464 // Initialize caches
465 TRACE("Initializing caches");
466 ctx->block_header_cache.cache = NULL;
467 ctx->block_cache.cache = NULL;
468
469 const uint64_t cache_divisor = (uint64_t)ctx->image_info.SectorSize * (1ULL << ctx->shift);
470 if(cache_divisor == 0)
471 {
473 ctx->block_cache.max_items = 0;
474 }
475 else
476 {
477 ctx->block_header_cache.max_items = MAX_CACHE_SIZE / cache_divisor;
479 }
480
481 // TODO: Cache tracks and sessions?
482
483 // Initialize ECC for Compact Disc
484 TRACE("Initializing ECC for Compact Disc");
486
487 ctx->magic = AARU_MAGIC;
490
491 TRACE("Exiting aaruf_open() = %p", ctx);
492 return ctx;
493}
#define LIBAARUFORMAT_MAJOR_VERSION
Definition aaruformat.h:22
#define LIBAARUFORMAT_MINOR_VERSION
Definition aaruformat.h:23
#define DIC_MAGIC
Magic identifier for legacy DiscImageChef container (ASCII "DICMFRMT").
Definition consts.h:61
#define AARU_MAGIC
Magic identifier for AaruFormat container (ASCII "AARUFRMT").
Definition consts.h:64
#define MAX_CACHE_SIZE
Maximum read cache size (bytes).
Definition consts.h:79
#define AARUF_VERSION_V2
Second on‑disk version (C implementation).
Definition consts.h:75
#define AARUF_VERSION
Current image format major version (incompatible changes bump this).
Definition consts.h:68
int aaruf_close(void *context)
Close an Aaru image context, flushing pending data structures and releasing resources.
Definition close.c:3995
void * aaruf_ecc_cd_init()
Initializes a Compact Disc ECC context.
Definition ecc_cd.c:35
int32_t aaruf_get_xml_mediatype(int32_t type)
Definition helpers.c:339
@ IndexBlock3
Block containing the index v3.
Definition enums.h:147
@ ChecksumBlock
Block containing contents checksums.
Definition enums.h:152
@ DataBlock
Block containing data.
Definition enums.h:141
@ TapePartitionBlock
Block containing list of partitions for a tape image.
Definition enums.h:158
@ IndexBlock2
Block containing the index v2.
Definition enums.h:146
@ GeometryBlock
Block containing logical geometry.
Definition enums.h:148
@ AaruMetadataJsonBlock
Block containing JSON version of Aaru Metadata.
Definition enums.h:159
@ CicmBlock
Block containing CICM XML metadata.
Definition enums.h:151
@ IndexBlock
Block containing the index (v1).
Definition enums.h:145
@ DeDuplicationTable2
Block containing a deduplication table v2.
Definition enums.h:143
@ TapeFileBlock
Block containing list of files for a tape image.
Definition enums.h:157
@ DeDuplicationTable
Block containing a deduplication table (v1).
Definition enums.h:142
@ DumpHardwareBlock
Block containing an array of hardware used to create the image.
Definition enums.h:156
@ MetadataBlock
Block containing metadata.
Definition enums.h:149
@ TracksBlock
Block containing optical disc tracks.
Definition enums.h:150
@ BlockMedia
Media that is physically block-based or abstracted like that.
Definition enums.h:219
#define AARUF_STATUS_OK
Sector present and read without uncorrectable errors.
Definition errors.h:75
#define AARUF_ERROR_NOT_ENOUGH_MEMORY
Memory allocation failure (critical).
Definition errors.h:48
#define AARUF_ERROR_INCOMPATIBLE_VERSION
Image uses a newer incompatible on-disk version.
Definition errors.h:42
#define AARUF_ERROR_CANNOT_READ_INDEX
Index block unreadable / truncated / bad identifier.
Definition errors.h:43
#define AARUF_ERROR_NOT_AARUFORMAT
Input file/stream failed magic or structural validation.
Definition errors.h:40
#define AARUF_ERROR_FILE_TOO_SMALL
File size insufficient for mandatory header / structures.
Definition errors.h:41
@ MaxSectorTag
Definition aaru.h:916
#define AARU_HEADER_APP_NAME_LEN
Size in bytes (UTF-16LE) of application name field (32 UTF-16 code units).
Definition header.h:59
void process_dumphw_block(aaruformat_context *ctx, const IndexEntry *entry)
Processes a dump hardware block from the image stream.
Definition dump.c:108
UT_array * process_index_v2(aaruformat_context *ctx)
Processes an index block (version 2) from the image stream.
Definition index_v2.c:81
int32_t process_ddt_v2(aaruformat_context *ctx, IndexEntry *entry, bool *found_user_data_ddt)
Processes a DDT v2 block from the image stream.
Definition ddt_v2.c:96
int32_t process_data_block(aaruformat_context *ctx, IndexEntry *entry)
Processes a data block from the image stream.
Definition data.c:71
void process_tracks_block(aaruformat_context *ctx, const IndexEntry *entry)
Parse and integrate a Tracks block from the image stream into the context.
Definition optical.c:111
void process_metadata_block(aaruformat_context *ctx, const IndexEntry *entry)
Processes a metadata block from the image stream.
Definition metadata.c:35
void process_checksum_block(aaruformat_context *ctx, const IndexEntry *entry)
Processes a checksum block from the image stream.
Definition checksum.c:39
UT_array * process_index_v1(aaruformat_context *ctx)
Processes an index block (version 1) from the image stream.
Definition index_v1.c:79
void process_cicm_block(aaruformat_context *ctx, const IndexEntry *entry)
Processes a CICM XML metadata block from the image stream.
Definition metadata.c:306
void process_geometry_block(aaruformat_context *ctx, const IndexEntry *entry)
Processes a logical geometry block from the image stream.
Definition metadata.c:246
void process_tape_files_block(aaruformat_context *ctx, const IndexEntry *entry)
Processes a tape file metadata block from the image stream.
Definition tape.c:126
void process_aaru_metadata_json_block(aaruformat_context *ctx, const IndexEntry *entry)
Processes an Aaru metadata JSON block from the image stream during image opening.
Definition metadata.c:470
void process_tape_partitions_block(aaruformat_context *ctx, const IndexEntry *entry)
Processes a tape partition metadata block from the image stream.
Definition tape.c:346
int32_t process_ddt_v1(aaruformat_context *ctx, IndexEntry *entry, bool *found_user_data_ddt)
Processes a DDT v1 block from the image stream.
Definition ddt_v1.c:85
UT_array * process_index_v3(aaruformat_context *ctx)
Processes an index block (version 3) from the image stream.
Definition index_v3.c:98
#define FATAL(fmt,...)
Definition log.h:40
#define TRACE(fmt,...)
Definition log.h:25
static void cleanup_open_failure(aaruformat_context *ctx)
Definition open.c:31
void * aaruf_open(const char *filepath)
Opens an existing AaruFormat image file.
Definition open.c:125
Version 2 container header with GUID, alignment shifts, and feature negotiation bitmaps.
Definition header.h:107
uint8_t application[64]
UTF-16LE creator application name (fixed 64 bytes).
Definition header.h:109
uint8_t applicationMajorVersion
Creator application major version.
Definition header.h:112
uint64_t identifier
File magic (AARU_MAGIC).
Definition header.h:108
int64_t lastWrittenTime
Last modification FILETIME (100 ns since 1601-01-01 UTC).
Definition header.h:117
uint64_t indexOffset
Absolute byte offset to primary index block (MUST be > 0; 0 => corrupt/unreadable).
Definition header.h:115
uint8_t applicationMinorVersion
Creator application minor / patch version.
Definition header.h:113
uint32_t mediaType
Media type enumeration (value from MediaType).
Definition header.h:114
uint8_t imageMinorVersion
Container format minor version.
Definition header.h:111
int64_t creationTime
Creation FILETIME (100 ns since 1601-01-01 UTC).
Definition header.h:116
uint8_t imageMajorVersion
Container format major version.
Definition header.h:110
Version 1 container header placed at offset 0 for legacy / initial format.
Definition header.h:77
struct CacheEntry * cache
Hash root (uthash). NULL when empty.
Definition lru.h:48
uint64_t max_items
Hard limit for number of entries (policy: enforce/ignore depends on implementation).
Definition lru.h:47
Lookup tables and state for Compact Disc EDC/ECC (P/Q) regeneration / verification.
Definition context.h:86
uint32_t identifier
Block identifier, must be BlockType::GeometryBlock.
Definition data.h:92
uint32_t MediaType
Media type identifier (see MediaType enum; 0=Unknown)
Definition aaru.h:881
uint8_t MetadataMediaType
Media type for sidecar generation (internal archival use)
Definition aaru.h:882
uint32_t SectorSize
Size of each logical sector in bytes (512, 2048, 2352, 4096, etc.)
Definition aaru.h:875
char Application[64]
Name of application that created the image (NUL-terminated)
Definition aaru.h:877
uint64_t ImageSize
Size of the image payload in bytes (excludes headers/metadata)
Definition aaru.h:873
int64_t CreationTime
Image creation timestamp (Windows FILETIME: 100ns since 1601-01-01 UTC)
Definition aaru.h:879
int64_t LastModificationTime
Last modification timestamp (Windows FILETIME format)
Definition aaru.h:880
char Version[32]
Image format version string (NUL-terminated, e.g., "6.0")
Definition aaru.h:876
uint64_t Sectors
Total count of addressable logical sectors/blocks.
Definition aaru.h:874
char ApplicationVersion[32]
Version of the creating application (NUL-terminated)
Definition aaru.h:878
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
uint16_t dataType
Data classification (value from DataType) or unused for untyped blocks.
Definition index.h:111
Master context representing an open or in‑creation Aaru image.
Definition context.h:172
uint8_t library_major_version
Linked library major version.
Definition context.h:177
uint32_t cylinders
Cylinders of the media represented by the image.
Definition context.h:234
struct CacheHeader block_header_cache
LRU/Cache header for block headers.
Definition context.h:256
uint8_t shift
Legacy overall shift (deprecated by data_shift/table_shift).
Definition context.h:195
CdEccContext * ecc_cd_context
CD ECC/EDC helper tables (allocated on demand).
Definition context.h:248
struct CacheHeader block_cache
LRU/Cache header for block payloads.
Definition context.h:257
AaruHeaderV2 header
Parsed container header (v2).
Definition context.h:175
uint64_t magic
File magic (AARU_MAGIC) post-open.
Definition context.h:174
uint8_t library_minor_version
Linked library minor version;.
Definition context.h:178
GeometryBlockHeader geometry_block
Logical geometry block (if present).
Definition context.h:229
uint32_t sectors_per_track
Sectors per track of the media represented by the image (for variable image, the smallest)
Definition context.h:236
uint32_t heads
Heads of the media represented by the image.
Definition context.h:235
FILE * imageStream
Underlying FILE* stream (binary mode).
Definition context.h:176
ImageInfo image_info
Exposed high-level image info summary.
Definition context.h:260
bool * readableSectorTags
Per-sector boolean array (optical tags read successfully?).
Definition context.h:263