mirror of
https://github.com/aaru-dps/libaaruformat.git
synced 2026-07-08 18:06:18 +00:00
554 lines
24 KiB
C
554 lines
24 KiB
C
/*
|
|
* This file is part of the Aaru Data Preservation Suite.
|
|
* Copyright (c) 2019-2026 Natalia Portillo.
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as
|
|
* published by the Free Software Foundation; either version 2.1 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <limits.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "aaruformat.h"
|
|
#include "internal.h"
|
|
#include "log.h"
|
|
#include "utarray.h"
|
|
|
|
static bool add_subindex_entries(aaruformat_context *ctx, UT_array *index_entries, const IndexEntry *subindex_entry);
|
|
|
|
/**
|
|
* @brief Processes an index block (version 3) from the image stream.
|
|
*
|
|
* Reads and parses an index block (version 3) from the image, returning an array of index entries.
|
|
* This function handles the advanced index format used in current AaruFormat versions, supporting
|
|
* hierarchical subindex structures for improved scalability. It reads the IndexHeader3 structure
|
|
* followed by index entries, recursively processing any subindex blocks encountered to create
|
|
* a flattened array of all index entries.
|
|
*
|
|
* @param ctx Pointer to the aaruformat context containing the image stream and header information.
|
|
*
|
|
* @return Returns one of the following values:
|
|
* @retval UT_array* Successfully processed the index block and all subindexes. This is returned when:
|
|
* - The context and image stream are valid
|
|
* - The index header is successfully read from the position specified in ctx->header.indexOffset
|
|
* - The index identifier matches IndexBlock3 (version 3 format identifier)
|
|
* - All index entries are successfully read and stored in the UT_array
|
|
* - Any subindex blocks (IndexBlock3 entries) are recursively processed via add_subindex_entries()
|
|
* - Memory allocation for the index entries array succeeds
|
|
* - The returned array contains all index entries from the main index and all subindexes
|
|
*
|
|
* @retval NULL Index processing failed. This occurs when:
|
|
* - The context parameter is NULL
|
|
* - The image stream (ctx->imageStream) is NULL or invalid
|
|
* - Cannot read the IndexHeader3 structure from the image stream
|
|
* - The index identifier doesn't match IndexBlock3 (incorrect format or corruption)
|
|
* - Memory allocation fails for the UT_array structure
|
|
* - File I/O errors occur while reading index entries
|
|
* - Recursive subindex processing fails (errors in add_subindex_entries())
|
|
*
|
|
* @note Index Structure (Version 3):
|
|
* - IndexHeader3: Contains identifier (IndexBlock3), entry count, and advanced metadata
|
|
* - IndexEntry array: May contain regular entries and subindex references (IndexBlock3 type)
|
|
* - Hierarchical support: Subindex entries are recursively processed to flatten the structure
|
|
* - No CRC validation is performed during processing (use verify_index_v3 for validation)
|
|
* - Supports scalable index organization for large image files
|
|
*
|
|
* @note Subindex Processing:
|
|
* - When an IndexEntry has blockType == IndexBlock3, it references a subindex
|
|
* - Subindexes are recursively processed using add_subindex_entries()
|
|
* - All entries from subindexes are flattened into the main index entries array
|
|
* - Supports arbitrary nesting depth of subindexes
|
|
*
|
|
* @note Memory Management:
|
|
* - Returns a newly allocated UT_array that must be freed by the caller using utarray_free()
|
|
* - On error, any partially allocated memory is cleaned up before returning NULL
|
|
* - Each IndexEntry is copied into the array (no reference to original stream data)
|
|
* - Memory usage scales with total entries across all subindexes
|
|
*
|
|
* @note Version Compatibility:
|
|
* - Supports only IndexBlock3 format (not IndexBlock or IndexBlock2)
|
|
* - Compatible with current generation AaruFormat image files
|
|
* - Backward compatible with images that don't use subindexes
|
|
*
|
|
* @warning The caller is responsible for freeing the returned UT_array using utarray_free().
|
|
* Failure to free the array will result in memory leaks.
|
|
*
|
|
* @warning This function does not validate the CRC integrity of the index data.
|
|
* Use verify_index_v3() to ensure index integrity before processing.
|
|
*
|
|
* @warning Recursive subindex processing may cause significant memory usage and processing
|
|
* time for images with deeply nested or numerous subindexes.
|
|
*
|
|
* @warning The function assumes ctx->header.indexOffset points to a valid index block.
|
|
* Invalid offsets may cause file access errors or reading incorrect data.
|
|
*/
|
|
UT_array *process_index_v3(aaruformat_context *ctx)
|
|
{
|
|
TRACE("Entering process_index_v3(%p)", ctx);
|
|
|
|
UT_array *index_entries = NULL;
|
|
IndexEntry entry;
|
|
|
|
if(ctx == NULL || ctx->imageStream == NULL) return NULL;
|
|
|
|
// Initialize the index entries array
|
|
const UT_icd index_entry_icd = {sizeof(IndexEntry), NULL, NULL, NULL};
|
|
|
|
utarray_new(index_entries, &index_entry_icd);
|
|
|
|
if(index_entries == NULL)
|
|
{
|
|
FATAL("Could not allocate memory for index entries array.");
|
|
TRACE("Exiting process_index_v3() = NULL");
|
|
return NULL;
|
|
}
|
|
|
|
// Read the index header
|
|
TRACE("Reading index header at position %llu", ctx->header.indexOffset);
|
|
if(aaruf_fseek(ctx->imageStream, (aaru_off_t)ctx->header.indexOffset, SEEK_SET) != 0)
|
|
{
|
|
FATAL("Could not seek to index header at %llu.", ctx->header.indexOffset);
|
|
utarray_free(index_entries);
|
|
|
|
TRACE("Exiting process_index_v3() = NULL");
|
|
return NULL;
|
|
}
|
|
IndexHeader3 idx_header;
|
|
if(fread(&idx_header, sizeof(IndexHeader3), 1, ctx->imageStream) != 1)
|
|
{
|
|
FATAL("Could not read index header at %llu.", ctx->header.indexOffset);
|
|
utarray_free(index_entries);
|
|
|
|
TRACE("Exiting process_index_v3() = NULL");
|
|
return NULL;
|
|
}
|
|
|
|
// Check if the index header is valid
|
|
if(idx_header.identifier != IndexBlock3)
|
|
{
|
|
FATAL("Incorrect index identifier.");
|
|
utarray_free(index_entries);
|
|
|
|
TRACE("Exiting process_index_v3() = NULL");
|
|
return NULL;
|
|
}
|
|
|
|
for(uint64_t i = 0; i < idx_header.entries; i++)
|
|
{
|
|
if(fread(&entry, sizeof(IndexEntry), 1, ctx->imageStream) != 1)
|
|
{
|
|
FATAL("Could not read index entry %llu at %llu.", (unsigned long long)i, ctx->header.indexOffset);
|
|
utarray_free(index_entries);
|
|
|
|
TRACE("Exiting process_index_v3() = NULL");
|
|
return NULL;
|
|
}
|
|
|
|
if(entry.blockType == IndexBlock3)
|
|
{
|
|
// If the entry is a subindex, we need to read its entries
|
|
if(!add_subindex_entries(ctx, index_entries, &entry))
|
|
{
|
|
utarray_free(index_entries);
|
|
|
|
TRACE("Exiting process_index_v3() = NULL");
|
|
return NULL;
|
|
}
|
|
continue;
|
|
}
|
|
utarray_push_back(index_entries, &entry);
|
|
}
|
|
|
|
TRACE("Read %llu index entries from index block at position %llu", (unsigned long long)idx_header.entries,
|
|
ctx->header.indexOffset);
|
|
return index_entries;
|
|
}
|
|
|
|
/**
|
|
* @brief Adds entries from a subindex block (version 3) to the main index entries array.
|
|
*
|
|
* Recursively reads subindex blocks and appends their entries to the main index entries array.
|
|
* This function is a critical component of the hierarchical index system in AaruFormat version 3,
|
|
* enabling scalable index organization for large image files. It performs recursive traversal
|
|
* of subindex structures, flattening the hierarchy into a single array while maintaining
|
|
* entry order and handling nested subindex references.
|
|
*
|
|
* @param ctx Pointer to the aaruformat context containing the image stream.
|
|
* @param index_entries Pointer to the UT_array of main index entries to append to.
|
|
* @param subindex_entry Pointer to the IndexEntry describing the subindex location and metadata.
|
|
*
|
|
* @return Returns true when entries are appended successfully, false when an error occurs.
|
|
*
|
|
* @note Function Behavior:
|
|
* - Successfully appends subindex entries when all parameters are valid and file I/O succeeds
|
|
* - Recursively processes nested subindexes when entries have blockType == IndexBlock3
|
|
* - Returns false without modifying the array when validation fails or errors occur
|
|
* - Does not perform error reporting beyond logging (errors are handled gracefully)
|
|
*
|
|
* @note Success Conditions - Entries are added when:
|
|
* - All input parameters (ctx, index_entries, subindex_entry) are non-NULL
|
|
* - The image stream is valid and accessible
|
|
* - File positioning succeeds to subindex_entry->offset
|
|
* - The subindex header is successfully read from the image stream
|
|
* - The subindex identifier matches IndexBlock3 (correct format)
|
|
* - All entries in the subindex are successfully read and processed
|
|
* - Recursive calls for nested subindexes complete successfully
|
|
*
|
|
* @note Failure Conditions - Function returns false when:
|
|
* - Any input parameter is NULL (ctx, index_entries, or subindex_entry)
|
|
* - The image stream (ctx->imageStream) is NULL or invalid
|
|
* - File I/O errors prevent reading the subindex header or entries
|
|
* - The subindex identifier doesn't match IndexBlock3 (format mismatch or corruption)
|
|
* - Memory operations fail during UT_array manipulation
|
|
*
|
|
* @note Recursive Processing:
|
|
* - When an entry has blockType == IndexBlock3, it indicates another subindex
|
|
* - The function recursively calls itself to process nested subindexes
|
|
* - Supports arbitrary nesting depth limited only by stack space and file structure
|
|
* - All entries are flattened into the main index_entries array regardless of nesting level
|
|
*
|
|
* @note Memory and Performance:
|
|
* - Memory usage scales with the total number of entries across all processed subindexes
|
|
* - File I/O is performed for each subindex block accessed
|
|
* - Processing time increases with the depth and breadth of subindex hierarchies
|
|
* - No internal memory allocation - uses existing UT_array structure
|
|
*
|
|
* @note Error Handling:
|
|
* - Designed for graceful degradation - errors don't propagate to callers
|
|
* - Invalid subindexes are skipped without affecting other processing
|
|
* - Partial success is possible when some subindexes fail but others succeed
|
|
* - Logging provides visibility into processing failures for debugging
|
|
*
|
|
* @warning This function modifies the index_entries array by appending new entries.
|
|
* Ensure the array has sufficient capacity and is properly initialized.
|
|
*
|
|
* @warning Recursive processing can cause significant stack usage for deeply nested
|
|
* subindex structures. Very deep hierarchies may cause stack overflow.
|
|
*
|
|
* @warning The function assumes subindex_entry->offset points to a valid subindex block.
|
|
* Invalid offsets will cause file access errors but are handled gracefully.
|
|
*
|
|
* @warning No validation is performed on individual IndexEntry contents - only
|
|
* structural validation of subindex headers is done.
|
|
*/
|
|
static bool add_subindex_entries(aaruformat_context *ctx, UT_array *index_entries, const IndexEntry *subindex_entry)
|
|
{
|
|
TRACE("Entering add_subindex_entries(%p, %p, %p)", ctx, index_entries, subindex_entry);
|
|
|
|
IndexHeader3 subindex_header;
|
|
IndexEntry entry;
|
|
|
|
if(ctx == NULL || ctx->imageStream == NULL || index_entries == NULL || subindex_entry == NULL)
|
|
{
|
|
TRACE("Exiting add_subindex_entries() = false (invalid parameters)");
|
|
return false;
|
|
}
|
|
|
|
// Seek to the subindex
|
|
if(aaruf_fseek(ctx->imageStream, (aaru_off_t)subindex_entry->offset, SEEK_SET) != 0)
|
|
{
|
|
FATAL("Could not seek to subindex header at %llu.", (unsigned long long)subindex_entry->offset);
|
|
TRACE("Exiting add_subindex_entries() = false (seek failed)");
|
|
return false;
|
|
}
|
|
|
|
// Read the subindex header
|
|
if(fread(&subindex_header, sizeof(IndexHeader3), 1, ctx->imageStream) != 1)
|
|
{
|
|
FATAL("Could not read subindex header at %llu.", (unsigned long long)subindex_entry->offset);
|
|
TRACE("Exiting add_subindex_entries() = false (header read failed)");
|
|
return false;
|
|
}
|
|
|
|
// Check if the subindex header is valid
|
|
if(subindex_header.identifier != IndexBlock3)
|
|
{
|
|
FATAL("Incorrect subindex identifier.");
|
|
|
|
TRACE("Exiting add_subindex_entries() = false (invalid identifier)");
|
|
return false;
|
|
}
|
|
|
|
if(subindex_header.entries != 0 && subindex_header.entries > SIZE_MAX / sizeof(IndexEntry))
|
|
{
|
|
FATAL("Subindex entry count %llu is too large to process.", (unsigned long long)subindex_header.entries);
|
|
TRACE("Exiting add_subindex_entries() = false (entry count overflow)");
|
|
return false;
|
|
}
|
|
|
|
// Read each entry in the subindex and add it to the main index entries array
|
|
for(uint64_t i = 0; i < subindex_header.entries; i++)
|
|
{
|
|
if(fread(&entry, sizeof(IndexEntry), 1, ctx->imageStream) != 1)
|
|
{
|
|
FATAL("Could not read subindex entry %llu at %llu.", (unsigned long long)i,
|
|
(unsigned long long)subindex_entry->offset);
|
|
TRACE("Exiting add_subindex_entries() = false (entry read failed)");
|
|
return false;
|
|
}
|
|
if(entry.blockType == IndexBlock3)
|
|
{
|
|
// If the entry is a subindex, we need to read its entries
|
|
if(!add_subindex_entries(ctx, index_entries, &entry))
|
|
{
|
|
TRACE("Exiting add_subindex_entries() = false (nested subindex failed)");
|
|
return false;
|
|
}
|
|
continue;
|
|
}
|
|
utarray_push_back(index_entries, &entry);
|
|
}
|
|
|
|
TRACE("Exiting add_subindex_entries() = true after appending %llu entries",
|
|
(unsigned long long)subindex_header.entries);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @brief Verifies the integrity of an index block (version 3) in the image stream.
|
|
*
|
|
* Checks the CRC64 of the index block and all subindexes without decompressing them. This function
|
|
* performs comprehensive validation of the advanced version 3 index structure including header
|
|
* validation, data integrity verification, and version-specific CRC calculation. Note that this
|
|
* function validates only the main index block's CRC and does not recursively validate subindex
|
|
* CRCs, focusing on the primary index structure integrity.
|
|
*
|
|
* @param ctx Pointer to the aaruformat context containing image stream and header information.
|
|
*
|
|
* @return Returns one of the following status codes:
|
|
* @retval AARUF_STATUS_OK (0) Successfully verified index integrity. This is returned when:
|
|
* - The context and image stream are valid
|
|
* - The index header is successfully read from ctx->header.indexOffset
|
|
* - The index identifier matches IndexBlock3 (version 3 format)
|
|
* - Memory allocation for index entries succeeds
|
|
* - All index entries are successfully read from the image stream
|
|
* - CRC64 calculation completes successfully with version-specific endianness handling
|
|
* - The calculated CRC64 matches the expected CRC64 in the index header
|
|
*
|
|
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) Invalid context or stream. This occurs when:
|
|
* - The context parameter is NULL
|
|
* - The image stream (ctx->imageStream) is NULL or invalid
|
|
*
|
|
* @retval AARUF_ERROR_CANNOT_READ_HEADER (-6) Index header reading failed. This occurs when:
|
|
* - Cannot read the complete IndexHeader3 structure from the image stream
|
|
* - File I/O errors prevent accessing the header at ctx->header.indexOffset
|
|
* - Insufficient data available at the specified index offset
|
|
*
|
|
* @retval AARUF_ERROR_CANNOT_READ_INDEX (-19) Index format or data access errors. This occurs when:
|
|
* - The index identifier doesn't match IndexBlock3 (wrong format or corruption)
|
|
* - Cannot read all index entries from the image stream
|
|
* - File I/O errors during index entry reading
|
|
* - Index structure is corrupted or truncated
|
|
*
|
|
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-9) Memory allocation failed. This occurs when:
|
|
* - Cannot allocate memory for the index entries array
|
|
* - System memory exhaustion prevents loading index data for verification
|
|
*
|
|
* @retval AARUF_ERROR_INVALID_BLOCK_CRC (-18) CRC64 validation failed. This occurs when:
|
|
* - The calculated CRC64 doesn't match the expected CRC64 in the index header
|
|
* - Index data corruption is detected
|
|
* - Data integrity verification fails indicating potential file damage
|
|
*
|
|
* @note CRC64 Validation Process:
|
|
* - Reads all main index entries into memory for CRC calculation
|
|
* - Calculates CRC64 over the complete main index entries array
|
|
* - Applies version-specific endianness conversion for compatibility
|
|
* - For imageMajorVersion <= AARUF_VERSION_V1: Uses bswap_64() for byte order correction
|
|
* - Compares calculated CRC64 with the value stored in the IndexHeader3
|
|
*
|
|
* @note Version 3 Specific Features:
|
|
* - Uses IndexHeader3 structure with hierarchical subindex support
|
|
* - Maintains compatibility with legacy endianness handling
|
|
* - Supports advanced index entry organization with subindex references
|
|
* - Only validates the main index block CRC - subindex CRCs are not recursively checked
|
|
*
|
|
* @note Validation Scope:
|
|
* - Validates main index header structure and identifier
|
|
* - Verifies data integrity of the primary index entries through CRC64 calculation
|
|
* - Does not validate individual IndexEntry contents or block references
|
|
* - Does not check for logical consistency of referenced blocks
|
|
* - Does not recursively validate subindex blocks (unlike hierarchical processing)
|
|
*
|
|
* @note Memory Management:
|
|
* - Allocates temporary memory for index entries during verification
|
|
* - Automatically frees allocated memory on both success and error conditions
|
|
* - Memory usage is proportional to the number of entries in the main index only
|
|
*
|
|
* @note Subindex Validation Limitation:
|
|
* - This function does not recursively validate subindex CRCs
|
|
* - Each subindex block contains its own CRC that would need separate validation
|
|
* - For complete integrity verification, subindex blocks should be validated individually
|
|
* - The main index CRC only covers the primary index entries, not the subindex content
|
|
*
|
|
* @warning This function reads only the main index into memory for CRC calculation.
|
|
* Subindex blocks are not loaded or validated by this function.
|
|
*
|
|
* @warning The function assumes ctx->header.indexOffset points to a valid index location.
|
|
* Invalid offsets will cause file access errors or incorrect validation.
|
|
*
|
|
* @warning CRC validation failure indicates potential data corruption in the main index
|
|
* and may suggest the image file is damaged or has been modified outside of library control.
|
|
*
|
|
* @warning For complete integrity verification of hierarchical indexes, additional validation
|
|
* of subindex blocks may be required beyond this function's scope.
|
|
*/
|
|
int32_t verify_index_v3(aaruformat_context *ctx)
|
|
{
|
|
TRACE("Entering verify_index_v3(%p)", ctx);
|
|
|
|
size_t read_bytes = 0;
|
|
IndexHeader3 index_header;
|
|
uint64_t crc64 = 0;
|
|
IndexEntry *index_entries = NULL;
|
|
|
|
if(ctx == NULL || ctx->imageStream == NULL)
|
|
{
|
|
FATAL("Invalid context or image stream.");
|
|
|
|
TRACE("Exiting verify_index_v3() = AARUF_ERROR_NOT_AARUFORMAT");
|
|
return AARUF_ERROR_NOT_AARUFORMAT;
|
|
}
|
|
|
|
// This will traverse all blocks and check their CRC64 without uncompressing them
|
|
TRACE("Checking index integrity at %llu.", ctx->header.indexOffset);
|
|
if(aaruf_fseek(ctx->imageStream, (aaru_off_t)ctx->header.indexOffset, SEEK_SET) != 0)
|
|
{
|
|
FATAL("Could not seek to index header at %llu.", ctx->header.indexOffset);
|
|
|
|
TRACE("Exiting verify_index_v3() = AARUF_ERROR_CANNOT_READ_HEADER");
|
|
return AARUF_ERROR_CANNOT_READ_HEADER;
|
|
}
|
|
|
|
// Read the index header
|
|
TRACE("Reading index header at position %llu", ctx->header.indexOffset);
|
|
read_bytes = fread(&index_header, 1, sizeof(IndexHeader3), ctx->imageStream);
|
|
|
|
if(read_bytes != sizeof(IndexHeader3))
|
|
{
|
|
FATAL("Could not read index header.");
|
|
|
|
TRACE("Exiting verify_index_v3() = AARUF_ERROR_CANNOT_READ_HEADER");
|
|
return AARUF_ERROR_CANNOT_READ_HEADER;
|
|
}
|
|
|
|
if(index_header.identifier != IndexBlock3)
|
|
{
|
|
FATAL("Incorrect index identifier.");
|
|
|
|
TRACE("Exiting verify_index_v3() = AARUF_ERROR_CANNOT_READ_INDEX");
|
|
return AARUF_ERROR_CANNOT_READ_INDEX;
|
|
}
|
|
|
|
TRACE("Index at %llu contains %llu entries.", ctx->header.indexOffset, (unsigned long long)index_header.entries);
|
|
|
|
if(index_header.entries != 0 && index_header.entries > SIZE_MAX / sizeof(IndexEntry))
|
|
{
|
|
FATAL("Index entry count %llu is too large to process.", (unsigned long long)index_header.entries);
|
|
|
|
TRACE("Exiting verify_index_v3() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
|
|
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
const size_t entries_size = (size_t)index_header.entries * sizeof(IndexEntry);
|
|
|
|
if(entries_size > 0)
|
|
{
|
|
index_entries = malloc(entries_size);
|
|
|
|
if(index_entries == NULL)
|
|
{
|
|
FATAL("Cannot allocate memory for index entries.");
|
|
|
|
TRACE("Exiting verify_index_v3() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
|
|
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
read_bytes = fread(index_entries, 1, entries_size, ctx->imageStream);
|
|
|
|
if(read_bytes != entries_size)
|
|
{
|
|
FATAL("Could not read index entries.");
|
|
free(index_entries);
|
|
|
|
TRACE("Exiting verify_index_v3() = AARUF_ERROR_CANNOT_READ_INDEX");
|
|
return AARUF_ERROR_CANNOT_READ_INDEX;
|
|
}
|
|
}
|
|
|
|
crc64_ctx *crc_ctx = aaruf_crc64_init();
|
|
|
|
if(crc_ctx == NULL)
|
|
{
|
|
FATAL("Cannot initialize CRC64 context.");
|
|
free(index_entries);
|
|
|
|
TRACE("Exiting verify_index_v3() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
|
|
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if(entries_size > 0)
|
|
{
|
|
const uint8_t *cursor = (const uint8_t *)index_entries;
|
|
size_t remaining = entries_size;
|
|
|
|
while(remaining > 0)
|
|
{
|
|
const uint32_t chunk = remaining > UINT32_MAX ? UINT32_MAX : (uint32_t)remaining;
|
|
|
|
if(aaruf_crc64_update(crc_ctx, cursor, chunk) != 0)
|
|
{
|
|
FATAL("Failed to update index CRC.");
|
|
aaruf_crc64_free(crc_ctx);
|
|
free(index_entries);
|
|
|
|
TRACE("Exiting verify_index_v3() = AARUF_ERROR_CANNOT_READ_INDEX");
|
|
return AARUF_ERROR_CANNOT_READ_INDEX;
|
|
}
|
|
|
|
cursor += chunk;
|
|
remaining -= chunk;
|
|
}
|
|
}
|
|
|
|
if(aaruf_crc64_final(crc_ctx, &crc64) != 0)
|
|
{
|
|
FATAL("Failed to finalize index CRC.");
|
|
aaruf_crc64_free(crc_ctx);
|
|
free(index_entries);
|
|
|
|
TRACE("Exiting verify_index_v3() = AARUF_ERROR_CANNOT_READ_INDEX");
|
|
return AARUF_ERROR_CANNOT_READ_INDEX;
|
|
}
|
|
|
|
aaruf_crc64_free(crc_ctx);
|
|
|
|
// Due to how C# wrote it, it is effectively reversed
|
|
if(ctx->header.imageMajorVersion <= AARUF_VERSION_V1) crc64 = bswap_64(crc64);
|
|
|
|
if(crc64 != index_header.crc64)
|
|
{
|
|
FATAL("Expected index CRC 0x%16llX but got 0x%16llX.", index_header.crc64, crc64);
|
|
free(index_entries);
|
|
|
|
TRACE("Exiting verify_index_v3() = AARUF_ERROR_INVALID_BLOCK_CRC");
|
|
return AARUF_ERROR_INVALID_BLOCK_CRC;
|
|
}
|
|
|
|
free(index_entries);
|
|
|
|
TRACE("Exiting verify_index_v3() = AARUF_OK");
|
|
return AARUF_STATUS_OK;
|
|
} |