libaaruformat 1.0
Aaru Data Preservation Suite - Format Library
Loading...
Searching...
No Matches
tape.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 "aaruformat.h"
20#include "log.h"
21
127{
128 long pos = 0;
129 size_t read_bytes = 0;
130 TapeFileHeader tape_file_header = {0};
131
132 // Check if the context and image stream are valid
133 if(ctx == NULL || ctx->imageStream == NULL)
134 {
135 FATAL("Invalid context or image stream.");
136 return;
137 }
138
139 // Seek to block
140 pos = fseek(ctx->imageStream, entry->offset, SEEK_SET);
141 if(pos < 0 || ftell(ctx->imageStream) != entry->offset)
142 {
143 FATAL("Could not seek to %" PRIu64 " as indicated by index entry...", entry->offset);
144
145 return;
146 }
147
148 // Even if those two checks shall have been done before
149 read_bytes = fread(&tape_file_header, 1, sizeof(TapeFileHeader), ctx->imageStream);
150
151 if(read_bytes != sizeof(TapeFileHeader))
152 {
153 TRACE("Could not read tape files header, continuing...");
154 return;
155 }
156
157 if(tape_file_header.identifier != TapeFileBlock)
158 {
159 TRACE("Incorrect identifier for data block at position %" PRIu64 "\n", entry->offset);
160 return;
161 }
162
163 ctx->image_info.ImageSize += sizeof(TapeFileEntry) * tape_file_header.entries;
164
165 uint8_t *buffer = malloc(sizeof(TapeFileEntry) * tape_file_header.entries);
166 if(buffer == NULL)
167 {
168 FATAL("Could not allocate memory for tape files block, continuing...");
169 return;
170 }
171 read_bytes = fread(buffer, sizeof(TapeFileEntry), tape_file_header.entries, ctx->imageStream);
172 if(read_bytes != tape_file_header.entries)
173 {
174 free(buffer);
175 FATAL("Could not read tape files block, continuing...");
176 return;
177 }
178 // Check CRC64
179 uint64_t crc64 = aaruf_crc64_data(buffer, sizeof(TapeFileEntry) * tape_file_header.entries);
180
181 if(crc64 != tape_file_header.crc64)
182 {
183 TRACE("Incorrect CRC found: 0x%" PRIx64 " found, expected 0x%" PRIx64 ", continuing...", crc64,
184 tape_file_header.crc64);
185 free(buffer);
186 return;
187 }
188
189 // Insert entries into UTHASH array indexed by partition << 32 | file number
190 const TapeFileEntry *entries = (TapeFileEntry *)buffer;
191
192 for(uint32_t i = 0; i < tape_file_header.entries; i++)
193 {
194 // Create hash table entry
195 tapeFileHashEntry *hash_entry = malloc(sizeof(tapeFileHashEntry));
196 if(hash_entry == NULL)
197 {
198 FATAL("Could not allocate memory for tape file hash entry");
199 continue;
200 }
201
202 // Create composite key: partition << 32 | file number
203 hash_entry->key = (uint64_t)entries[i].Partition << 32 | entries[i].File;
204
205 // Copy the tape file entry data
206 hash_entry->fileEntry = entries[i];
207
208 // Replace if exists, add if new
209 tapeFileHashEntry *old_entry = NULL;
210 HASH_REPLACE(hh, ctx->tape_files, key, sizeof(uint64_t), hash_entry, old_entry);
211
212 // Free old entry if it was replaced
213 if(old_entry != NULL)
214 {
215 TRACE("Replaced existing tape file entry for partition %u, file %u", entries[i].Partition, entries[i].File);
216 free(old_entry);
217 }
218 else
219 TRACE("Added new tape file entry for partition %u, file %u", entries[i].Partition, entries[i].File);
220 }
221
222 free(buffer);
223}
224
347{
348 long pos = 0;
349 size_t read_bytes = 0;
350 TapePartitionHeader tape_partition_header = {0};
351
352 // Check if the context and image stream are valid
353 if(ctx == NULL || ctx->imageStream == NULL)
354 {
355 FATAL("Invalid context or image stream.");
356 return;
357 }
358
359 // Seek to block
360 pos = fseek(ctx->imageStream, entry->offset, SEEK_SET);
361 if(pos < 0 || ftell(ctx->imageStream) != entry->offset)
362 {
363 FATAL("Could not seek to %" PRIu64 " as indicated by index entry...", entry->offset);
364
365 return;
366 }
367
368 // Even if those two checks shall have been done before
369 read_bytes = fread(&tape_partition_header, 1, sizeof(TapePartitionHeader), ctx->imageStream);
370
371 if(read_bytes != sizeof(TapePartitionHeader))
372 {
373 TRACE("Could not read tape partitions header, continuing...");
374 return;
375 }
376
377 if(tape_partition_header.identifier != TapePartitionBlock)
378 {
379 TRACE("Incorrect identifier for data block at position %" PRIu64 "\n", entry->offset);
380 return;
381 }
382
383 ctx->image_info.ImageSize += sizeof(TapePartitionEntry) * tape_partition_header.entries;
384
385 uint8_t *buffer = malloc(sizeof(TapePartitionEntry) * tape_partition_header.entries);
386 if(buffer == NULL)
387 {
388 FATAL("Could not allocate memory for tape partitions block, continuing...");
389 return;
390 }
391 read_bytes = fread(buffer, sizeof(TapePartitionEntry), tape_partition_header.entries, ctx->imageStream);
392 if(read_bytes != tape_partition_header.entries)
393 {
394 free(buffer);
395 FATAL("Could not read tape partitions block, continuing...");
396 return;
397 }
398 // Check CRC64
399 uint64_t crc64 = aaruf_crc64_data(buffer, sizeof(TapePartitionEntry) * tape_partition_header.entries);
400
401 if(crc64 != tape_partition_header.crc64)
402 {
403 TRACE("Incorrect CRC found: 0x%" PRIx64 " found, expected 0x%" PRIx64 ", continuing...", crc64,
404 tape_partition_header.crc64);
405 free(buffer);
406 return;
407 }
408
409 // Insert entries into UTHASH array indexed by partition
410 const TapePartitionEntry *entries = (TapePartitionEntry *)buffer;
411
412 for(uint32_t i = 0; i < tape_partition_header.entries; i++)
413 {
414 // Create hash table entry
415 TapePartitionHashEntry *hash_entry = malloc(sizeof(TapePartitionHashEntry));
416 if(hash_entry == NULL)
417 {
418 FATAL("Could not allocate memory for tape partition hash entry");
419 continue;
420 }
421
422 // Create key: partition
423 hash_entry->key = entries[i].Number;
424
425 // Copy the tape partition entry data
426 hash_entry->partitionEntry = entries[i];
427
428 // Replace if exists, add if new
429 TapePartitionHashEntry *old_entry = NULL;
430 HASH_REPLACE(hh, ctx->tape_partitions, key, sizeof(uint8_t), hash_entry, old_entry);
431
432 // Free old entry if it was replaced
433 if(old_entry != NULL)
434 {
435 TRACE("Replaced existing tape partition entry for partition %u", entries[i].Number);
436 free(old_entry);
437 }
438 else
439 TRACE("Added new tape partition entry for partition %u", entries[i].Number);
440 }
441
442 free(buffer);
443}
444
569int32_t aaruf_get_tape_file(const void *context, const uint8_t partition, const uint32_t file, uint64_t *starting_block,
570 uint64_t *ending_block)
571{
572 TRACE("Entering aaruf_get_tape_file(%p, %d, %d, %llu, %llu)", context, partition, file, *starting_block,
573 *ending_block);
574
575 const aaruformat_context *ctx = NULL;
576
577 if(context == NULL)
578 {
579 FATAL("Invalid context");
580
581 TRACE("Exiting aaruf_get_tape_file() = AARUF_ERROR_NOT_AARUFORMAT");
583 }
584
585 ctx = context;
586
587 // Not a libaaruformat context
588 if(ctx->magic != AARU_MAGIC)
589 {
590 FATAL("Invalid context");
591
592 TRACE("Exiting aaruf_get_tape_file() = AARUF_ERROR_NOT_AARUFORMAT");
594 }
595
596 uint64_t key = (uint64_t)partition << 32 | file;
597 tapeFileHashEntry *entry = NULL;
598 HASH_FIND(hh, ctx->tape_files, &key, sizeof(uint64_t), entry);
599
600 if(entry == NULL)
601 {
602 TRACE("Tape file not found");
604 }
605
606 *starting_block = entry->fileEntry.FirstBlock;
607 *ending_block = entry->fileEntry.LastBlock;
608
609 TRACE("Exiting aaruf_get_tape_file(%p, %d, %d, %llu, %llu) = AARUF_STATUS_OK", context, partition, file,
610 *starting_block, *ending_block);
611 return AARUF_STATUS_OK;
612}
613
770int32_t aaruf_set_tape_file(void *context, const uint8_t partition, const uint32_t file, const uint64_t starting_block,
771 const uint64_t ending_block)
772{
773 TRACE("Entering aaruf_set_tape_file(%p, %d, %d, %llu, %llu)", context, partition, file, starting_block,
774 ending_block);
775
776 aaruformat_context *ctx = NULL;
777
778 if(context == NULL)
779 {
780 FATAL("Invalid context");
781
782 TRACE("Exiting aaruf_set_tape_file() = AARUF_ERROR_NOT_AARUFORMAT");
784 }
785
786 ctx = context;
787
788 // Not a libaaruformat context
789 if(ctx->magic != AARU_MAGIC)
790 {
791 FATAL("Invalid context");
792
793 TRACE("Exiting aaruf_set_tape_file() = AARUF_ERROR_NOT_AARUFORMAT");
795 }
796
797 // Check we are writing
798 if(!ctx->is_writing)
799 {
800 FATAL("Trying to write a read-only image");
801
802 TRACE("Exiting aaruf_set_tape_file() = AARUF_READ_ONLY");
803 return AARUF_READ_ONLY;
804 }
805
806 // Create hash table entry
807 tapeFileHashEntry *hash_entry = malloc(sizeof(tapeFileHashEntry));
808 if(hash_entry == NULL)
809 {
810 FATAL("Could not allocate memory for tape file hash entry");
811
812 TRACE("Exiting aaruf_set_tape_file() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
814 }
815
816 // Create composite key: partition << 32 | file number
817 hash_entry->key = (uint64_t)partition << 32 | file;
818
819 // Copy the tape file entry data
820 hash_entry->fileEntry.File = file;
821 hash_entry->fileEntry.Partition = partition;
822 hash_entry->fileEntry.FirstBlock = starting_block;
823 hash_entry->fileEntry.LastBlock = ending_block;
824
825 // Replace if exists, add if new
826 tapeFileHashEntry *old_entry = NULL;
827 HASH_REPLACE(hh, ctx->tape_files, key, sizeof(uint64_t), hash_entry, old_entry);
828
829 // Free old entry if it was replaced
830 if(old_entry != NULL)
831 {
832 TRACE("Replaced existing tape file entry for partition %u, file %u", partition, file);
833 free(old_entry);
834 }
835 else
836 TRACE("Added new tape file entry for partition %u, file %u", partition, file);
837
838 TRACE("Exiting aaruf_set_tape_file(%p, %d, %d, %llu, %llu) = AARUF_STATUS_OK", context, partition, file,
839 starting_block, ending_block);
840 return AARUF_STATUS_OK;
841}
842
982int32_t aaruf_get_tape_partition(const void *context, const uint8_t partition, uint64_t *starting_block,
983 uint64_t *ending_block)
984{
985 TRACE("Entering aaruf_get_tape_partition(%p, %d, %llu, %llu)", context, partition, *starting_block, *ending_block);
986
987 const aaruformat_context *ctx = NULL;
988
989 if(context == NULL)
990 {
991 FATAL("Invalid context");
992
993 TRACE("Exiting aaruf_get_tape_partition() = AARUF_ERROR_NOT_AARUFORMAT");
995 }
996
997 ctx = context;
998
999 // Not a libaaruformat context
1000 if(ctx->magic != AARU_MAGIC)
1001 {
1002 FATAL("Invalid context");
1003
1004 TRACE("Exiting aaruf_get_tape_partition() = AARUF_ERROR_NOT_AARUFORMAT");
1006 }
1007
1008 uint8_t key = partition;
1009 TapePartitionHashEntry *entry = NULL;
1010 HASH_FIND(hh, ctx->tape_partitions, &key, sizeof(uint8_t), entry);
1011
1012 if(entry == NULL)
1013 {
1014 TRACE("Tape partition not found");
1016 }
1017
1018 *starting_block = entry->partitionEntry.FirstBlock;
1019 *ending_block = entry->partitionEntry.LastBlock;
1020
1021 TRACE("Exiting aaruf_get_tape_partition(%p, %d, %llu, %llu) = AARUF_STATUS_OK", context, partition, *starting_block,
1022 *ending_block);
1023 return AARUF_STATUS_OK;
1024}
1025
1196int32_t aaruf_set_tape_partition(void *context, const uint8_t partition, const uint64_t starting_block,
1197 const uint64_t ending_block)
1198{
1199 TRACE("Entering aaruf_set_tape_partition(%p, %d, %llu, %llu)", context, partition, starting_block, ending_block);
1200
1201 aaruformat_context *ctx = NULL;
1202
1203 if(context == NULL)
1204 {
1205 FATAL("Invalid context");
1206
1207 TRACE("Exiting aaruf_set_tape_partition() = AARUF_ERROR_NOT_AARUFORMAT");
1209 }
1210
1211 ctx = context;
1212
1213 // Not a libaaruformat context
1214 if(ctx->magic != AARU_MAGIC)
1215 {
1216 FATAL("Invalid context");
1217
1218 TRACE("Exiting aaruf_set_tape_partition() = AARUF_ERROR_NOT_AARUFORMAT");
1220 }
1221
1222 // Check we are writing
1223 if(!ctx->is_writing)
1224 {
1225 FATAL("Trying to write a read-only image");
1226
1227 TRACE("Exiting aaruf_set_tape_partition() = AARUF_READ_ONLY");
1228 return AARUF_READ_ONLY;
1229 }
1230
1231 // Create hash table entry
1232 TapePartitionHashEntry *hash_entry = malloc(sizeof(TapePartitionHashEntry));
1233 if(hash_entry == NULL)
1234 {
1235 FATAL("Could not allocate memory for tape partition hash entry");
1236
1237 TRACE("Exiting aaruf_set_tape_partition() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1239 }
1240
1241 // Create key: partition
1242 hash_entry->key = partition;
1243
1244 // Copy the tape partition entry data
1245 hash_entry->partitionEntry.Number = partition;
1246 hash_entry->partitionEntry.FirstBlock = starting_block;
1247 hash_entry->partitionEntry.LastBlock = ending_block;
1248
1249 // Replace if exists, add if new
1250 TapePartitionHashEntry *old_entry = NULL;
1251 HASH_REPLACE(hh, ctx->tape_partitions, key, sizeof(uint8_t), hash_entry, old_entry);
1252
1253 // Free old entry if it was replaced
1254 if(old_entry != NULL)
1255 {
1256 TRACE("Replaced existing tape partition entry for partition %u", partition);
1257 free(old_entry);
1258 }
1259 else
1260 TRACE("Added new tape partition entry for partition %u", partition);
1261
1262 TRACE("Exiting aaruf_set_tape_partition(%p, %d, %llu, %llu) = AARUF_STATUS_OK", context, partition, starting_block,
1263 ending_block);
1264 return AARUF_STATUS_OK;
1265}
#define AARU_MAGIC
Magic identifier for AaruFormat container (ASCII "AARUFRMT").
Definition consts.h:64
struct TapeFileHashEntry tapeFileHashEntry
uint64_t aaruf_crc64_data(const uint8_t *data, uint32_t len)
Definition crc64.c:160
@ TapePartitionBlock
Block containing list of partitions for a tape image.
Definition enums.h:158
@ TapeFileBlock
Block containing list of files for a tape image.
Definition enums.h:157
#define AARUF_ERROR_TAPE_PARTITION_NOT_FOUND
Requested tape partition not present in image.
Definition errors.h:68
#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_TAPE_FILE_NOT_FOUND
Requested tape file number not present in image.
Definition errors.h:67
#define AARUF_ERROR_NOT_AARUFORMAT
Input file/stream failed magic or structural validation.
Definition errors.h:40
#define FATAL(fmt,...)
Definition log.h:40
#define TRACE(fmt,...)
Definition log.h:25
uint64_t ImageSize
Size of the image payload in bytes (excludes headers/metadata)
Definition aaru.h:873
Single index entry describing a block's type, (optional) data classification, and file offset.
Definition index.h:109
uint64_t offset
Absolute byte offset in the image where the referenced block header begins.
Definition index.h:112
Describes a single logical file on a tape medium.
Definition tape.h:134
uint32_t File
File number (unique within the partition).
Definition tape.h:135
uint64_t LastBlock
Last block of the file (inclusive).
Definition tape.h:142
uint64_t FirstBlock
First block of the file (inclusive).
Definition tape.h:139
uint8_t Partition
Partition number containing this file.
Definition tape.h:137
uint64_t key
Composite key: partition << 32 | file.
Definition context.h:128
TapeFileEntry fileEntry
The actual tape file data.
Definition context.h:129
Header for a tape file metadata block containing file layout information.
Definition tape.h:238
uint32_t entries
Number of file entries following this header.
Definition tape.h:241
uint32_t identifier
Block type identifier.
Definition tape.h:239
uint64_t crc64
CRC64-ECMA checksum of the entry data.
Definition tape.h:245
Describes a single physical partition on a tape medium.
Definition tape.h:320
uint64_t LastBlock
Last block in the partition (inclusive).
Definition tape.h:325
uint64_t FirstBlock
First block in the partition (inclusive).
Definition tape.h:323
uint8_t Number
Partition number (unique identifier for this partition).
Definition tape.h:321
uint8_t key
Key: partition.
Definition context.h:135
TapePartitionEntry partitionEntry
The actual tape partition data.
Definition context.h:136
Header for a tape partition metadata block containing partition layout information.
Definition tape.h:441
uint64_t crc64
CRC64-ECMA checksum of the entry data.
Definition tape.h:448
uint8_t entries
Number of partition entries following this header.
Definition tape.h:444
uint32_t identifier
Block type identifier.
Definition tape.h:442
Master context representing an open or in‑creation Aaru image.
Definition context.h:172
tapeFileHashEntry * tape_files
Hash table root for tape files.
Definition context.h:302
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
FILE * imageStream
Underlying FILE* stream (binary mode).
Definition context.h:176
ImageInfo image_info
Exposed high-level image info summary.
Definition context.h:260
TapePartitionHashEntry * tape_partitions
Hash table root for tape partitions.
Definition context.h:303
int32_t aaruf_set_tape_file(void *context, const uint8_t partition, const uint32_t file, const uint64_t starting_block, const uint64_t ending_block)
Sets or updates the block range for a specific tape file in an Aaru tape image.
Definition tape.c:770
int32_t aaruf_get_tape_file(const void *context, const uint8_t partition, const uint32_t file, uint64_t *starting_block, uint64_t *ending_block)
Retrieves the block range for a specific tape file from an Aaru tape image.
Definition tape.c:569
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
int32_t aaruf_get_tape_partition(const void *context, const uint8_t partition, uint64_t *starting_block, uint64_t *ending_block)
Retrieves the block range for a specific tape partition from an Aaru tape image.
Definition tape.c:982
int32_t aaruf_set_tape_partition(void *context, const uint8_t partition, const uint64_t starting_block, const uint64_t ending_block)
Sets or updates the block range for a specific tape partition in an Aaru tape image.
Definition tape.c:1196
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