From f8ac3e2a415f473410dac802a276d2dc5ac71a8b Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Tue, 7 Oct 2025 14:48:12 +0100 Subject: [PATCH] Add function to retrieve block range for specific tape partitions --- include/aaruformat/decls.h | 2 + include/aaruformat/errors.h | 1 + src/blocks/tape.c | 183 ++++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+) diff --git a/include/aaruformat/decls.h b/include/aaruformat/decls.h index 16d4b41..c38ceef 100644 --- a/include/aaruformat/decls.h +++ b/include/aaruformat/decls.h @@ -168,6 +168,8 @@ AARU_EXPORT int32_t AARU_CALL aaruf_get_tape_file(const void *context, uint8_t p uint64_t *starting_block, uint64_t *ending_block); AARU_EXPORT int32_t AARU_CALL aaruf_set_tape_file(void *context, uint8_t partition, uint32_t file, uint64_t starting_block, uint64_t ending_block); +AARU_EXPORT int32_t AARU_CALL aaruf_get_tape_partition(const void *context, uint8_t partition, uint64_t *starting_block, + uint64_t *ending_block); AARU_EXPORT int32_t AARU_CALL aaruf_get_dumphw(void *context, uint8_t *buffer, size_t *length); AARU_EXPORT int32_t AARU_CALL aaruf_set_dumphw(void *context, uint8_t *data, size_t length); diff --git a/include/aaruformat/errors.h b/include/aaruformat/errors.h index f6febf6..4827f4d 100644 --- a/include/aaruformat/errors.h +++ b/include/aaruformat/errors.h @@ -65,6 +65,7 @@ #define AARUF_ERROR_INCORRECT_DATA_SIZE (-26) ///< Data size does not match expected size. #define AARUF_ERROR_INVALID_TAG (-27) ///< Invalid or unsupported media or sector tag format. #define AARUF_ERROR_TAPE_FILE_NOT_FOUND (-28) ///< Requested tape file number not present in image. +#define AARUF_ERROR_TAPE_PARTITION_NOT_FOUND (-29) ///< Requested tape partition not present in image. /** @} */ /** \name Non-fatal sector status codes (non-negative) diff --git a/src/blocks/tape.c b/src/blocks/tape.c index 3f0ca59..332b4f8 100644 --- a/src/blocks/tape.c +++ b/src/blocks/tape.c @@ -832,4 +832,187 @@ int32_t aaruf_set_tape_file(void *context, const uint8_t partition, const uint32 TRACE("Exiting aaruf_set_tape_file(%p, %d, %d, %llu, %llu) = AARUF_STATUS_OK", context, partition, file, starting_block, ending_block); return AARUF_STATUS_OK; +} + +/** + * @brief Retrieves the block range for a specific tape partition from an Aaru tape image. + * + * Queries the tape partition hash table to locate a partition by its partition number, + * returning the first and last block addresses that define the partition's extent on the + * tape medium. This function provides the core lookup mechanism for accessing partition + * layout information in tape images. + * + * **Tape Partition Identification:** + * Each tape partition is uniquely identified by its partition number (0-255). Most tapes + * have a single partition (partition 0), but multi-partition formats like LTO, DLT, and + * AIT support multiple partitions with independent block address spaces. + * + * The partition number is used as the hash table key to perform a lookup in the context's + * tapePartitions table, which was previously populated by process_tape_partitions_block() + * during image initialization. + * + * **Block Range Semantics:** + * The returned block range [FirstBlock, LastBlock] is inclusive on both ends: + * - FirstBlock: The first block address in the partition (often 0, but format-dependent) + * - LastBlock: The final block address in the partition (inclusive) + * - Block count: (LastBlock - FirstBlock + 1) + * + * Block addresses are local to each partition. Different partitions may have overlapping + * logical block numbers (e.g., both partition 0 and partition 1 can have blocks 0-1000). + * When accessing blocks, both the partition number and block number are required for + * unique identification. + * + * **Typical Usage Flow:** + * 1. Open an Aaru tape image with aaruf_open() + * 2. Call aaruf_get_tape_partition() to get the block range for a specific partition + * 3. Use the returned block range to understand partition boundaries + * 4. Access files within the partition using aaruf_get_tape_file() + * 5. Repeat for other partitions as needed + * + * **Error Handling:** + * The function performs validation in the following order: + * 1. Context pointer validation (NULL check) + * 2. Magic number verification (ensures valid aaruformat context) + * 3. Hash table lookup for the specified partition number + * + * If any validation fails, an appropriate error code is returned and the + * output parameters (starting_block, ending_block) are left unmodified. + * + * **Thread Safety:** + * This function performs read-only operations on the context and is safe + * to call from multiple threads concurrently, provided the context is not + * being modified by other operations (e.g., during image opening/closing). + * + * **Performance Characteristics:** + * - Hash table lookup: O(1) average case + * - No I/O operations performed + * - Minimal stack usage + * - Suitable for high-frequency queries + * + * **Partition Layout Information:** + * The partition metadata is essential for: + * - Understanding the physical organization of the tape + * - Determining partition boundaries for file access + * - Validating that file block ranges fall within partition limits + * - Supporting multi-partition tape formats correctly + * - Preserving original tape partitioning schemes + * + * @param context Pointer to an initialized aaruformat context. Must not be NULL. + * The context must have been successfully opened with aaruf_open() + * and contain a valid tape partition hash table. The context is treated + * as const and is not modified by this operation. + * + * @param partition The partition number (0-255) to query. For single-partition tapes, + * this is typically 0. Multi-partition tapes may have multiple + * partitions numbered sequentially from 0. + * + * @param[out] starting_block Pointer to receive the first block address of the partition. + * Must not be NULL. Only modified on success. + * The value written represents the inclusive start of the + * partition's block range (often 0, but format-dependent). + * + * @param[out] ending_block Pointer to receive the last block address of the partition. + * Must not be NULL. Only modified on success. + * The value written represents the inclusive end of the + * partition's block range. + * + * @retval AARUF_STATUS_OK (0) Successfully retrieved tape partition information. Both + * output parameters have been populated with valid block addresses. The + * requested partition exists in the image's partition table. + * + * @retval AARUF_ERROR_NOT_AARUFORMAT (-1) Invalid context or context validation failed. + * This is returned when: + * - The context pointer is NULL + * - The context magic number doesn't match AARU_MAGIC (corrupted or wrong type) + * The output parameters are not modified. + * + * @retval AARUF_ERROR_TAPE_PARTITION_NOT_FOUND (-29) The requested partition number + * does not exist in the image's tape partition table. This is returned when: + * - The specified partition number was not defined in the TapePartitionBlock + * - The tape partition block was not present or failed to load during image open + * - The partition number is out of range for this tape + * The output parameters are not modified. + * + * @note The function logs entry and exit points via TRACE macros when tracing is + * enabled, including parameter values and return codes for debugging. + * + * @note The tape partition hash table (ctx->tapePartitions) must have been populated + * during image initialization. If the image doesn't contain a TapePartitionBlock, + * or if that block failed to load, all queries will return + * AARUF_ERROR_TAPE_PARTITION_NOT_FOUND. + * + * @note For images without tape partition metadata, the entire tape may be treated + * as a single implicit partition, and applications should handle the absence + * of partition information gracefully. + * + * @note The returned block addresses are logical block numbers within the partition's + * address space. To read actual data, these must be combined with the partition + * number and translated through the appropriate read functions. + * + * @note Partition metadata is primarily informational and used for validation. File + * access is primarily driven by file metadata (TapeFileBlock), which references + * partition numbers to establish context. + * + * @warning The output parameter pointers must be valid. Passing NULL for either + * starting_block or ending_block will cause undefined behavior (likely + * a crash when the function attempts to dereference them on success). + * + * @warning If the same partition number appears multiple times in the TapePartitionBlock, + * only the last occurrence is retained (due to HASH_REPLACE behavior in + * process_tape_partitions_block). This should not occur in valid images but + * may happen with corrupted or malformed partition metadata. + * + * @warning Single-partition tapes may not include a TapePartitionBlock at all, in which + * case this function will always return AARUF_ERROR_TAPE_PARTITION_NOT_FOUND. + * Applications should handle this case and assume a default partition 0 + * spanning the entire tape. + * + * @see process_tape_partitions_block() for partition table initialization + * @see TapePartitionEntry for the structure defining partition block ranges + * @see TapePartitionHashEntry for the hash table entry structure + * @see aaruf_get_tape_file() for file-level queries within partitions + * @see aaruf_set_tape_partition() for setting partition information during write + */ +int32_t aaruf_get_tape_partition(const void *context, const uint8_t partition, uint64_t *starting_block, + uint64_t *ending_block) +{ + TRACE("Entering aaruf_get_tape_partition(%p, %d, %llu, %llu)", context, partition, *starting_block, *ending_block); + + const aaruformatContext *ctx = NULL; + + if(context == NULL) + { + FATAL("Invalid context"); + + TRACE("Exiting aaruf_get_tape_partition() = AARUF_ERROR_NOT_AARUFORMAT"); + return AARUF_ERROR_NOT_AARUFORMAT; + } + + ctx = context; + + // Not a libaaruformat context + if(ctx->magic != AARU_MAGIC) + { + FATAL("Invalid context"); + + TRACE("Exiting aaruf_get_tape_partition() = AARUF_ERROR_NOT_AARUFORMAT"); + return AARUF_ERROR_NOT_AARUFORMAT; + } + + uint8_t key = partition; + TapePartitionHashEntry *entry = NULL; + HASH_FIND(hh, ctx->tapePartitions, &key, sizeof(uint8_t), entry); + + if(entry == NULL) + { + TRACE("Tape partition not found"); + return AARUF_ERROR_TAPE_PARTITION_NOT_FOUND; + } + + *starting_block = entry->partitionEntry.FirstBlock; + *ending_block = entry->partitionEntry.LastBlock; + + TRACE("Exiting aaruf_get_tape_partition(%p, %d, %llu, %llu) = AARUF_STATUS_OK", context, partition, *starting_block, + *ending_block); + return AARUF_STATUS_OK; } \ No newline at end of file