Files
libaaruformat/src/metadata.c

3672 lines
167 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2025 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 <stddef.h>
#include <stdint.h>
#include "aaruformat.h"
#include "log.h"
/**
* @brief Retrieves the logical CHS geometry from the AaruFormat image.
*
* Reads the Cylinder-Head-Sector (CHS) geometry information from the image's geometry
* block and returns the values through output parameters. The geometry block contains
* legacy-style logical addressing parameters that describe how the storage medium was
* originally organized in terms of cylinders, heads (tracks per cylinder), and sectors
* per track. This information is essential for software that requires CHS addressing
* or for accurately representing the original medium's logical structure.
*
* @param context Pointer to the aaruformat context (must be a valid, opened image context).
* @param cylinders Pointer to store the number of cylinders. Updated on success.
* @param heads Pointer to store the number of heads (tracks per cylinder). Updated on success.
* @param sectors_per_track Pointer to store the number of sectors per track. Updated on success.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully retrieved geometry information. This is returned when:
* - The context is valid and properly initialized
* - The geometry block is present in the image (identifier == GeometryBlock)
* - All three output parameters are successfully populated with geometry values
* - The cylinders parameter contains the total number of cylinders
* - The heads parameter contains the number of heads per cylinder
* - The sectors_per_track parameter contains the number of sectors per track
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_open() or aaruf_create()
*
* @retval AARUF_ERROR_CANNOT_READ_BLOCK (-6) The geometry block is not present. This occurs when:
* - The image was created without geometry information
* - The geometryBlock.identifier field doesn't equal GeometryBlock
* - The geometry block was not found during image opening
* - The image format doesn't support or require CHS geometry
*
* @note Geometry Interpretation:
* - Total logical sectors = cylinders × heads × sectors_per_track
* - Sector size is not included in the geometry block and must be obtained separately
* (typically 512 bytes for most block devices, but can vary)
* - The geometry represents logical addressing, not necessarily physical medium geometry
* - Modern storage devices often report translated or synthetic geometry values
*
* @note CHS Addressing Context:
* - CHS addressing was historically used for hard disk drives and floppy disks
* - Legacy BIOS and older operating systems relied on CHS parameters
* - LBA (Logical Block Addressing) has largely replaced CHS for modern devices
* - Some disk image formats and emulators still require CHS information
*
* @note Geometry Block Availability:
* - Not all image types contain geometry blocks
* - Optical media (CDs, DVDs) typically don't have CHS geometry
* - Modern large-capacity drives may not have meaningful CHS values
* - Check the return value to determine if geometry is available
*
* @note Parameter Validation:
* - All output parameters must be non-NULL valid pointers
* - The function does not validate the geometry values themselves
* - Geometry values of zero or unusually large values may indicate issues
*
* @warning The output parameters are only modified on success (AARUF_STATUS_OK).
* On error, their values remain unchanged. Initialize them before calling
* if default values are needed on failure.
*
* @warning This function reads from the in-memory geometry block loaded during
* aaruf_open(). It does not perform file I/O operations.
*
* @warning Geometry values may not accurately represent physical device geometry,
* especially for modern drives with zone-based recording or flash storage.
*/
int32_t aaruf_get_geometry(const void *context, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors_per_track)
{
TRACE("Entering aaruf_get_geometry(%p, %p, %p, %p)", context, cylinders, heads, sectors_per_track);
const aaruformat_context *ctx = NULL;
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_geometry() = 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_geometry() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->geometry_block.identifier != GeometryBlock)
{
FATAL("No geometry block present");
TRACE("Exiting aaruf_get_geometry() = AARUF_ERROR_CANNOT_READ_BLOCK");
return AARUF_ERROR_CANNOT_READ_BLOCK;
}
*cylinders = ctx->geometry_block.cylinders;
*heads = ctx->geometry_block.heads;
*sectors_per_track = ctx->geometry_block.sectorsPerTrack;
TRACE("Exiting aaruf_get_geometry(%p, %u, %u, %u) = AARUF_STATUS_OK", context, *cylinders, *heads,
*sectors_per_track);
return AARUF_STATUS_OK;
}
/**
* @brief Sets the logical CHS geometry for the AaruFormat image.
*
* Configures the Cylinder-Head-Sector (CHS) geometry information for the image being
* created or modified. This function populates both the geometry block (used for storage
* in the image file) and the image information structure (used for runtime calculations).
* The geometry block contains legacy-style logical addressing parameters that describe
* how the storage medium should be logically organized in terms of cylinders, heads
* (tracks per cylinder), and sectors per track. This information is crucial for creating
* images that will be used with software requiring CHS addressing or for accurately
* preserving the original medium's logical structure.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param cylinders The number of cylinders to set for the geometry.
* @param heads The number of heads (tracks per cylinder) to set for the geometry.
* @param sectors_per_track The number of sectors per track to set for the geometry.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set geometry information. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - The geometry block identifier is set to GeometryBlock
* - The geometry block fields (cylinders, heads, sectorsPerTrack) are updated
* - The image info fields (Cylinders, Heads, SectorsPerTrack) are synchronized
* - All parameters are stored for subsequent write operations
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @note Dual Storage:
* - Geometry is stored in two locations within the context:
* 1. ctx->geometryBlock: Written to the image file as a GeometryBlock during close
* 2. ctx->imageInfo: Used for runtime calculations and metadata queries
* - Both locations are kept synchronized by this function
*
* @note Geometry Calculation:
* - Total logical sectors = cylinders × heads × sectors_per_track
* - Ensure the product matches the actual sector count in the image
* - Mismatched geometry may cause issues with legacy software or emulators
* - Sector size is separate and should be set via other API calls
*
* @note CHS Addressing Requirements:
* - Required for images intended for legacy BIOS or MBR partition schemes
* - Essential for floppy disk images and older hard disk images
* - May be optional or synthetic for modern large-capacity drives
* - Some virtualization platforms require valid CHS geometry
*
* @note Parameter Constraints:
* - No validation is performed on the geometry values
* - Zero values are technically accepted but may cause issues
* - Extremely large values may overflow in calculations (cylinders × heads × sectors_per_track)
* - Common constraints for legacy systems:
* * Cylinders: typically 1-1024 for BIOS, up to 65535 for modern systems
* * Heads: typically 1-255 for most systems
* * Sectors per track: typically 1-63 for BIOS, up to 255 for modern systems
*
* @note Write Mode Requirement:
* - This function is intended for use during image creation
* - Should be called after aaruf_create() and before writing sector data
* - The geometry block is serialized during aaruf_close()
* - Must be used with a write-enabled context
*
* @note Historical Context:
* - CHS geometry was the original addressing scheme for disk drives
* - Physical CHS reflected actual disk platters, heads, and sector layout
* - Logical CHS often differs from physical due to zone-bit recording and translation
* - Modern drives use LBA (Logical Block Addressing) internally
*
* @warning This function does not validate geometry consistency:
* - Does not check if cylinders × heads × sectors_per_track equals image sector count
* - Does not prevent overflow in the multiplication
* - Caller must ensure geometry values are appropriate for the medium type
* - Invalid geometry may cause boot failures or data access issues
*
* @warning The geometry block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted.
*
* @warning Changing geometry after writing sector data may create inconsistencies.
* Set geometry before beginning sector write operations for best results.
*
* @warning Some image formats and use cases don't require CHS geometry:
* - Optical media (CD/DVD/BD) use different addressing schemes
* - Modern GPT-partitioned disks don't rely on CHS
* - Flash-based storage typically doesn't have meaningful CHS geometry
* - Setting geometry for such media types is harmless but unnecessary
*/
int32_t aaruf_set_geometry(void *context, const uint32_t cylinders, const uint32_t heads,
const uint32_t sectors_per_track)
{
TRACE("Entering aaruf_set_geometry(%p, %u, %u, %u)", context, cylinders, heads, sectors_per_track);
aaruformat_context *ctx = NULL;
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_geometry() = 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_set_geometry() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_write_sector() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
ctx->geometry_block.identifier = GeometryBlock;
ctx->geometry_block.cylinders = cylinders;
ctx->geometry_block.heads = heads;
ctx->geometry_block.sectorsPerTrack = sectors_per_track;
ctx->cylinders = cylinders;
ctx->heads = heads;
ctx->sectors_per_track = sectors_per_track;
TRACE("Exiting aaruf_set_geometry(%p, %u, %u, %u) = AARUF_STATUS_OK", context, cylinders, heads, sectors_per_track);
return AARUF_STATUS_OK;
}
/**
* @brief Sets the media sequence information for multi-volume media sets.
*
* Configures the sequence numbering for media that is part of a larger set, such as
* multi-disk software distributions, backup sets spanning multiple tapes, or optical
* disc sets. This function records both the current media's position in the sequence
* and the total number of media in the complete set. This metadata is essential for
* proper ordering and completeness verification when working with multi-volume archives.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param sequence The sequence number of this media (1-based index indicating position in the set).
* @param last_sequence The total number of media in the complete set (indicates the final sequence number).
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set media sequence information. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - The metadata block header is initialized (identifier set to MetadataBlock)
* - The mediaSequence field is set to the provided sequence value
* - The lastMediaSequence field is set to the provided last_sequence value
* - Both values are stored for serialization during image close
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @note Sequence Numbering:
* - Sequence numbers are typically 1-based (first disc is 1, not 0)
* - The sequence parameter should be in the range [1, last_sequence]
* - last_sequence indicates the total count of media in the set
* - Example: For a 3-disc set, disc 2 would have sequence=2, last_sequence=3
*
* @note Common Use Cases:
* - Multi-CD/DVD software installations (e.g., "Disc 2 of 4")
* - Backup tape sets spanning multiple volumes
* - Split archive formats requiring sequential processing
* - Multi-floppy disk software distributions
* - Large data sets divided across multiple optical discs
*
* @note Metadata Block Initialization:
* - If the metadata block header is not yet initialized, this function initializes it
* - The metadataBlockHeader.identifier is set to MetadataBlock automatically
* - Multiple metadata setter functions can be called to build complete metadata
* - All metadata is written to the image file during aaruf_close()
*
* @note Single Media Images:
* - For standalone media not part of a set, use sequence=1, last_sequence=1
* - Setting both values to 0 may be used to indicate "not part of a sequence"
* - The function does not validate that sequence <= last_sequence
*
* @note Parameter Validation:
* - No validation is performed on sequence numbers
* - Negative values are accepted but may be semantically incorrect
* - sequence > last_sequence is not prevented but indicates an error condition
* - Callers should ensure sequence and last_sequence are logically consistent
*
* @note Archive Integrity:
* - Proper sequence metadata is crucial for multi-volume restoration
* - Archival software may refuse to extract if sequence information is incorrect
* - Missing volumes can be detected by checking sequence completeness
* - Helps prevent data loss from incomplete multi-volume sets
*
* @note Historical Context:
* - Multi-volume sets were common in the floppy disk era due to size constraints
* - CD/DVD sets were used for large software distributions (operating systems, games)
* - Tape backup systems still use multi-volume sets for large archives
* - Modern optical media (BD-R DL) reduced the need for multi-disc sets
*
* @warning This function does not validate the logical consistency of sequence numbers:
* - Does not check if sequence <= last_sequence
* - Does not prevent negative or zero values if semantically inappropriate
* - Caller must ensure values represent a valid sequence relationship
*
* @warning The metadata block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted.
*
* @warning Incorrect sequence information may prevent proper reconstruction:
* - Software relying on sequence numbers may fail to recognize media order
* - Archival systems may incorrectly report missing volumes
* - Restoration processes may fail if sequence is inconsistent
*/
int32_t aaruf_set_media_sequence(void *context, const int32_t sequence, const int32_t last_sequence)
{
TRACE("Entering aaruf_set_media_sequence(%p, %d, %d)", context, sequence, last_sequence);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_sequence() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_sequence() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_media_sequence() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadata_block_header.identifier != MetadataBlock) ctx->metadata_block_header.identifier = MetadataBlock;
ctx->metadata_block_header.mediaSequence = sequence;
ctx->metadata_block_header.lastMediaSequence = last_sequence;
TRACE("Exiting aaruf_set_media_sequence(%p, %d, %d) = AARUF_STATUS_OK", context, sequence, last_sequence);
return AARUF_STATUS_OK;
}
/**
* @brief Sets the creator (person/operator) information for the image.
*
* Records the name of the person or operator who created the AaruFormat image. This
* metadata identifies the individual responsible for the imaging process, which is
* valuable for provenance tracking, accountability, and understanding the human context
* in which the image was created. The creator name is stored in UTF-16LE encoding and
* preserved exactly as provided by the caller.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param data Pointer to the creator name string data in UTF-16LE encoding (opaque byte array).
* @param length Length of the creator data in bytes (must include full UTF-16LE character sequences).
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set creator information. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - Memory allocation for the creator string succeeded
* - The metadata block header is initialized (identifier set to MetadataBlock)
* - The creator data is copied to ctx->imageInfo.Creator
* - The creatorLength field is set in the metadata block header
* - Any previous creator string is properly freed before replacement
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-8) Memory allocation failed. This occurs when:
* - malloc() failed to allocate the required memory for the creator string
* - System is out of memory or memory is severely fragmented
* - The requested allocation size is too large
*
* @note UTF-16LE Encoding:
* - The data parameter must contain a valid UTF-16LE encoded string
* - Length must be in bytes, not character count (UTF-16LE uses 2 or 4 bytes per character)
* - The library treats the data as opaque and does not validate UTF-16LE encoding
* - Null termination is not required; length specifies the exact byte count
* - Ensure even byte lengths to maintain UTF-16LE character alignment
*
* @note Creator Name Format:
* - Typically contains the full name of the person who created the image
* - May include titles, credentials, or institutional affiliations
* - Common formats: "John Smith", "Dr. Jane Doe", "Smith, John (Archivist)"
* - Should identify the individual operator, not the software used
* - May include contact information or employee/operator ID in institutional settings
*
* @note Provenance and Accountability:
* - Identifies who performed the imaging operation
* - Important for establishing chain of custody in forensic contexts
* - Provides contact point for questions about the imaging process
* - Supports institutional recordkeeping and quality assurance
* - May be required for compliance with archival standards
*
* @note Privacy Considerations:
* - Consider privacy implications when recording personal names
* - Some organizations may use operator IDs instead of full names
* - Institutional policies may govern what personal information is recorded
* - GDPR and similar regulations may apply in some jurisdictions
*
* @note Memory Management:
* - The function allocates a new buffer and copies the data
* - If a previous creator string exists, it is freed before replacement
* - The caller retains ownership of the input data buffer
* - The allocated memory is freed when the context is closed or destroyed
*
* @note Metadata Block Initialization:
* - If the metadata block header is not yet initialized, this function initializes it
* - The metadataBlockHeader.identifier is set to MetadataBlock automatically
* - Multiple metadata setter functions can be called to build complete metadata
*
* @warning The data buffer must remain valid for the duration of this function call.
* After the function returns, the caller may free or reuse the data buffer.
*
* @warning Invalid UTF-16LE encoding may cause issues when reading the metadata:
* - The library does not validate UTF-16LE correctness
* - Malformed strings may display incorrectly or cause decoding errors
* - Ensure the data is properly encoded before calling this function
*
* @warning The metadata block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted.
*/
int32_t aaruf_set_creator(void *context, const uint8_t *data, const int32_t length)
{
TRACE("Entering aaruf_set_creator(%p, %p, %d)", context, data, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_creator() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_creator() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_creator() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadata_block_header.identifier != MetadataBlock) ctx->metadata_block_header.identifier = MetadataBlock;
// Reserve memory
uint8_t *copy = malloc(length);
if(copy == NULL)
{
FATAL("Could not allocate memory for creator");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
// Copy opaque UTF-16LE string
memcpy(copy, data, length);
if(ctx->creator != NULL) free(ctx->creator);
ctx->creator = copy;
ctx->metadata_block_header.creatorLength = length;
TRACE("Exiting aaruf_set_creator(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}
/**
* @brief Sets user comments or notes for the image.
*
* Records arbitrary user-provided comments, notes, or annotations associated with the
* AaruFormat image. This metadata field allows users to document the image's purpose,
* provenance, condition, or any other relevant information. Comments are stored in
* UTF-16LE encoding and can contain multi-line text, special characters, and detailed
* descriptions.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param data Pointer to the comments string data in UTF-16LE encoding (opaque byte array).
* @param length Length of the comments data in bytes (must include full UTF-16LE character sequences).
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set comments. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - Memory allocation for the comments string succeeded
* - The metadata block header is initialized (identifier set to MetadataBlock)
* - The comments data is copied to ctx->imageInfo.Comments
* - The commentsLength field is set in the metadata block header
* - Any previous comments string is properly freed before replacement
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-8) Memory allocation failed. This occurs when:
* - malloc() failed to allocate the required memory for the comments string
* - System is out of memory or memory is severely fragmented
* - The requested allocation size is too large
*
* @note UTF-16LE Encoding:
* - The data parameter must contain a valid UTF-16LE encoded string
* - Length must be in bytes, not character count
* - The library treats the data as opaque and does not validate encoding
* - Null termination is not required; length specifies the exact byte count
*
* @note Common Uses for Comments:
* - Documentation of image source and creation date
* - Notes about media condition or read errors encountered
* - Preservation metadata and archival notes
* - User annotations for organizing image collections
* - Workflow status or processing history
*
* @note Memory Management:
* - The function allocates a new buffer and copies the data
* - If previous comments exist, they are freed before replacement
* - The caller retains ownership of the input data buffer
* - The allocated memory is freed when the context is closed or destroyed
*
* @warning The metadata block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted.
*/
int32_t aaruf_set_comments(void *context, const uint8_t *data, const int32_t length)
{
TRACE("Entering aaruf_set_comments(%p, %p, %d)", context, data, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_comments() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_comments() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_comments() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadata_block_header.identifier != MetadataBlock) ctx->metadata_block_header.identifier = MetadataBlock;
// Reserve memory
uint8_t *copy = malloc(length);
if(copy == NULL)
{
FATAL("Could not allocate memory for comments");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
// Copy opaque UTF-16LE string
memcpy(copy, data, length);
if(ctx->comments != NULL) free(ctx->comments);
ctx->comments = copy;
ctx->metadata_block_header.commentsLength = length;
TRACE("Exiting aaruf_set_comments(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}
/**
* @brief Sets the media title or label for the image.
*
* Records the title, label, or name printed or written on the physical storage media.
* This metadata is particularly useful for identifying discs, tapes, or other media
* that have user-applied labels or manufacturer-printed titles. The title is stored
* in UTF-16LE encoding to support international characters and special symbols.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param data Pointer to the media title string data in UTF-16LE encoding (opaque byte array).
* @param length Length of the media title data in bytes (must include full UTF-16LE character sequences).
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set media title. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - Memory allocation for the media title string succeeded
* - The metadata block header is initialized (identifier set to MetadataBlock)
* - The media title data is copied to ctx->imageInfo.MediaTitle
* - The mediaTitleLength field is set in the metadata block header
* - Any previous media title string is properly freed before replacement
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-8) Memory allocation failed. This occurs when:
* - malloc() failed to allocate the required memory for the media title string
* - System is out of memory or memory is severely fragmented
* - The requested allocation size is too large
*
* @note Common Media Title Examples:
* - Handwritten labels on optical discs or tapes
* - Pre-printed software names on distribution media (e.g., "Windows 95 Setup Disk 1")
* - Volume labels or disc names (e.g., "BACKUP_2024", "INSTALL_CD")
* - Game titles printed on cartridges or discs
* - Album or movie titles on multimedia discs
*
* @note Preservation Context:
* - Important for archival purposes to record exactly what appears on the media
* - Helps identify media in large collections
* - May differ from filesystem volume labels
* - Useful for matching physical media to digital images
*
* @note UTF-16LE Encoding:
* - The data parameter must contain a valid UTF-16LE encoded string
* - Length must be in bytes, not character count
* - Supports international characters, emoji, and special symbols
* - Null termination is not required; length specifies the exact byte count
*
* @warning The metadata block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted.
*/
int32_t aaruf_set_media_title(void *context, const uint8_t *data, const int32_t length)
{
TRACE("Entering aaruf_set_media_title(%p, %p, %d)", context, data, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_title() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_title() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_media_title() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadata_block_header.identifier != MetadataBlock) ctx->metadata_block_header.identifier = MetadataBlock;
// Reserve memory
uint8_t *copy = malloc(length);
if(copy == NULL)
{
FATAL("Could not allocate memory for media title");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
// Copy opaque UTF-16LE string
memcpy(copy, data, length);
if(ctx->media_title != NULL) free(ctx->media_title);
ctx->media_title = copy;
ctx->metadata_block_header.mediaTitleLength = length;
TRACE("Exiting aaruf_set_media_title(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}
/**
* @brief Sets the media manufacturer information for the image.
*
* Records the name of the company that manufactured the physical storage media.
* This metadata is valuable for preservation and forensic purposes, as it can help
* identify the media type, quality characteristics, and manufacturing period. The
* manufacturer name is stored in UTF-16LE encoding.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param data Pointer to the media manufacturer string data in UTF-16LE encoding (opaque byte array).
* @param length Length of the media manufacturer data in bytes (must include full UTF-16LE character sequences).
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set media manufacturer. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - Memory allocation for the media manufacturer string succeeded
* - The metadata block header is initialized (identifier set to MetadataBlock)
* - The media manufacturer data is copied to ctx->imageInfo.MediaManufacturer
* - The mediaManufacturerLength field is set in the metadata block header
* - Any previous media manufacturer string is properly freed before replacement
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-8) Memory allocation failed. This occurs when:
* - malloc() failed to allocate the required memory for the media manufacturer string
* - System is out of memory or memory is severely fragmented
* - The requested allocation size is too large
*
* @note Common Media Manufacturers:
* - Optical discs: Verbatim, Sony, Maxell, TDK, Taiyo Yuden
* - Magnetic tapes: Fujifilm, Maxell, Sony, IBM
* - Floppy disks: 3M, Maxell, Sony, Verbatim
* - Flash media: SanDisk, Kingston, Samsung
*
* @note Identification Methods:
* - May be printed on the media surface or packaging
* - Can sometimes be detected from media ID codes (e.g., ATIP for CD-R)
* - Historical records or catalogs may provide this information
* - Important for understanding media quality and longevity characteristics
*
* @note Preservation Value:
* - Helps assess expected media lifespan and degradation patterns
* - Useful for identifying counterfeit or remarked media
* - Aids in research about media quality and failure modes
* - Provides context for archival planning and migration strategies
*
* @warning The metadata block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted.
*/
int32_t aaruf_set_media_manufacturer(void *context, const uint8_t *data, const int32_t length)
{
TRACE("Entering aaruf_set_media_manufacturer(%p, %p, %d)", context, data, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_manufacturer() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_manufacturer() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_media_manufacturer() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadata_block_header.identifier != MetadataBlock) ctx->metadata_block_header.identifier = MetadataBlock;
// Reserve memory
uint8_t *copy = malloc(length);
if(copy == NULL)
{
FATAL("Could not allocate memory for media manufacturer");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
// Copy opaque UTF-16LE string
memcpy(copy, data, length);
if(ctx->media_manufacturer != NULL) free(ctx->media_manufacturer);
ctx->media_manufacturer = copy;
ctx->metadata_block_header.mediaManufacturerLength = length;
TRACE("Exiting aaruf_set_media_manufacturer(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}
/**
* @brief Sets the media model or product designation for the image.
*
* Records the specific model, product line, or type designation of the physical storage
* media. This is more specific than the manufacturer and identifies the exact product
* variant. This metadata helps in identifying specific media characteristics, performance
* specifications, and compatibility information. The model information is stored in
* UTF-16LE encoding.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param data Pointer to the media model string data in UTF-16LE encoding (opaque byte array).
* @param length Length of the media model data in bytes (must include full UTF-16LE character sequences).
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set media model. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - Memory allocation for the media model string succeeded
* - The metadata block header is initialized (identifier set to MetadataBlock)
* - The media model data is copied to ctx->imageInfo.MediaModel
* - The mediaModelLength field is set in the metadata block header
* - Any previous media model string is properly freed before replacement
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-8) Memory allocation failed. This occurs when:
* - malloc() failed to allocate the required memory for the media model string
* - System is out of memory or memory is severely fragmented
* - The requested allocation size is too large
*
* @note Model Designation Examples:
* - Optical discs: "DVD+R 16x", "CD-R 80min", "BD-R DL 50GB"
* - Tapes: "LTO-7", "DLT-IV", "AIT-3"
* - Floppy disks: "HD 1.44MB", "DD 720KB"
* - Flash cards: "SDHC Class 10", "CompactFlash 1000x"
*
* @note Model Information Usage:
* - Identifies specific capacity and speed ratings
* - Indicates format compatibility (e.g., DVD-R vs DVD+R)
* - Helps determine recording characteristics and quality tier
* - Useful for matching replacement media or troubleshooting issues
*
* @warning The metadata block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted.
*/
int32_t aaruf_set_media_model(void *context, const uint8_t *data, const int32_t length)
{
TRACE("Entering aaruf_set_media_model(%p, %p, %d)", context, data, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_model() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_model() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_media_model() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadata_block_header.identifier != MetadataBlock) ctx->metadata_block_header.identifier = MetadataBlock;
// Reserve memory
uint8_t *copy = malloc(length);
if(copy == NULL)
{
FATAL("Could not allocate memory for media model");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
// Copy opaque UTF-16LE string
memcpy(copy, data, length);
if(ctx->media_model != NULL) free(ctx->media_model);
ctx->media_model = copy;
ctx->metadata_block_header.mediaModelLength = length;
TRACE("Exiting aaruf_set_media_model(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}
/**
* @brief Sets the media serial number for the image.
*
* Records the unique serial number assigned to the physical storage media by the
* manufacturer. This metadata provides a unique identifier for the specific piece of
* media, which is invaluable for tracking, authentication, and forensic analysis. Not
* all media types have serial numbers; this is most common with professional-grade
* media and some consumer optical discs. The serial number is stored in UTF-16LE encoding.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param data Pointer to the media serial number string data in UTF-16LE encoding (opaque byte array).
* @param length Length of the media serial number data in bytes (must include full UTF-16LE character sequences).
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set media serial number. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - Memory allocation for the media serial number string succeeded
* - The metadata block header is initialized (identifier set to MetadataBlock)
* - The media serial number data is copied to ctx->imageInfo.MediaSerialNumber
* - The mediaSerialNumberLength field is set in the metadata block header
* - Any previous media serial number string is properly freed before replacement
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-8) Memory allocation failed. This occurs when:
* - malloc() failed to allocate the required memory for the media serial number string
* - System is out of memory or memory is severely fragmented
* - The requested allocation size is too large
*
* @note Serial Number Availability:
* - Professional tape media (LTO, DLT, etc.) typically have printed serial numbers
* - Some optical discs have embedded media IDs that can serve as serial numbers
* - Hard drives and SSDs have electronically-readable serial numbers
* - Consumer recordable media (CD-R, DVD-R) rarely have unique serial numbers
* - May be printed on labels, hubs, or cartridge shells
*
* @note Forensic and Archival Importance:
* - Uniquely identifies the specific physical media instance
* - Critical for chain of custody in forensic investigations
* - Enables tracking of media throughout its lifecycle
* - Helps prevent mix-ups in large media collections
* - Can verify authenticity and detect counterfeits
*
* @note Format Considerations:
* - Serial numbers may be alphanumeric, numeric, or contain special characters
* - Format varies widely between manufacturers and media types
* - May include check digits or formatting separators
* - Should be recorded exactly as it appears on the media
*
* @warning The metadata block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted.
*/
int32_t aaruf_set_media_serial_number(void *context, const uint8_t *data, const int32_t length)
{
TRACE("Entering aaruf_set_media_serial_number(%p, %p, %d)", context, data, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_serial_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_serial_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_media_serial_number() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadata_block_header.identifier != MetadataBlock) ctx->metadata_block_header.identifier = MetadataBlock;
// Reserve memory
uint8_t *copy = malloc(length);
if(copy == NULL)
{
FATAL("Could not allocate memory for media serial number");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
// Copy opaque UTF-16LE string
memcpy(copy, data, length);
if(ctx->media_serial_number != NULL) free(ctx->media_serial_number);
ctx->media_serial_number = copy;
ctx->metadata_block_header.mediaSerialNumberLength = length;
TRACE("Exiting aaruf_set_media_serial_number(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}
/**
* @brief Sets the media barcode information for the image.
*
* Records the barcode affixed to the physical storage media or its packaging. Barcodes
* are commonly used in professional archival and library environments for automated
* inventory management, tracking, and retrieval systems. This metadata enables correlation
* between physical media location systems and digital image files. The barcode is stored
* in UTF-16LE encoding.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param data Pointer to the media barcode string data in UTF-16LE encoding (opaque byte array).
* @param length Length of the media barcode data in bytes (must include full UTF-16LE character sequences).
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set media barcode. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - Memory allocation for the media barcode string succeeded
* - The metadata block header is initialized (identifier set to MetadataBlock)
* - The media barcode data is copied to ctx->imageInfo.MediaBarcode
* - The mediaBarcodeLength field is set in the metadata block header
* - Any previous media barcode string is properly freed before replacement
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-8) Memory allocation failed. This occurs when:
* - malloc() failed to allocate the required memory for the media barcode string
* - System is out of memory or memory is severely fragmented
* - The requested allocation size is too large
*
* @note Common Barcode Uses:
* - Library and archival tape management systems
* - Automated tape library robotics (e.g., LTO tape cartridges)
* - Inventory tracking in large media collections
* - Asset management in corporate or institutional settings
* - Chain of custody tracking in forensic environments
*
* @note Barcode Types and Formats:
* - Code 39 and Code 128 are common for media labeling
* - LTO tapes use specific 6 or 8-character barcode formats
* - May include library-specific prefixes or location codes
* - Some systems use 2D barcodes (QR codes, Data Matrix)
* - Barcode should be recorded exactly as it appears
*
* @note Integration with Physical Systems:
* - Enables automated correlation between physical and digital catalogs
* - Supports robotic tape library operations
* - Facilitates retrieval from off-site storage facilities
* - Links to broader asset management databases
* - Critical for large-scale archival operations
*
* @note Preservation Context:
* - Important for long-term archival planning
* - Helps maintain inventory accuracy over time
* - Supports audit and compliance requirements
* - Enables efficient physical media location and retrieval
*
* @warning The metadata block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted.
*/
int32_t aaruf_set_media_barcode(void *context, const uint8_t *data, const int32_t length)
{
TRACE("Entering aaruf_set_media_barcode(%p, %p, %d)", context, data, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_barcode() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_barcode() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_media_barcode() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadata_block_header.identifier != MetadataBlock) ctx->metadata_block_header.identifier = MetadataBlock;
// Reserve memory
uint8_t *copy = malloc(length);
if(copy == NULL)
{
FATAL("Could not allocate memory for media barcode");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
// Copy opaque UTF-16LE string
memcpy(copy, data, length);
if(ctx->media_barcode != NULL) free(ctx->media_barcode);
ctx->media_barcode = copy;
ctx->metadata_block_header.mediaBarcodeLength = length;
TRACE("Exiting aaruf_set_media_barcode(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}
/**
* @brief Sets the media part number or model designation for the image.
*
* Records the manufacturer's part number or catalog designation for the specific type
* of physical storage media. This is distinct from the media model in that it represents
* the exact ordering or catalog number used for procurement and inventory purposes. Part
* numbers are particularly important for sourcing compatible replacement media and for
* precise identification in technical documentation. The part number is stored in UTF-16LE
* encoding.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param data Pointer to the media part number string data in UTF-16LE encoding (opaque byte array).
* @param length Length of the media part number data in bytes (must include full UTF-16LE character sequences).
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set media part number. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - Memory allocation for the media part number string succeeded
* - The metadata block header is initialized (identifier set to MetadataBlock)
* - The media part number data is copied to ctx->imageInfo.MediaPartNumber
* - The mediaPartNumberLength field is set in the metadata block header
* - Any previous media part number string is properly freed before replacement
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-8) Memory allocation failed. This occurs when:
* - malloc() failed to allocate the required memory for the media part number string
* - System is out of memory or memory is severely fragmented
* - The requested allocation size is too large
*
* @note Part Number Examples:
* - Optical media: "MR-25332" (Verbatim DVD+R), "CDR80JC" (Sony CD-R)
* - Tape media: "C7973A" (HP LTO-3), "TK88" (Maxell DLT-IV)
* - Floppy disks: "MF2HD" (3.5" high-density), "2D" (5.25" double-density)
* - May include regional variations or packaging size indicators
*
* @note Practical Applications:
* - Procurement and ordering of compatible replacement media
* - Cross-referencing with manufacturer specifications and datasheets
* - Identifying specific product revisions or manufacturing batches
* - Ensuring compatibility for archival media migration projects
* - Tracking costs and suppliers in institutional settings
*
* @note Relationship to Model:
* - Part number is more specific than model designation
* - Model might be "DVD+R 16x", part number "MR-25332"
* - Part numbers may vary by region, packaging quantity, or color
* - Critical for exact product identification in catalogs and databases
*
* @note Documentation and Compliance:
* - Useful for creating detailed preservation documentation
* - Supports compliance with archival standards and best practices
* - Enables precise replication of archival environments
* - Facilitates research on media types and failure modes
*
* @warning The metadata block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted.
*/
int32_t aaruf_set_media_part_number(void *context, const uint8_t *data, const int32_t length)
{
TRACE("Entering aaruf_set_media_part_number(%p, %p, %d)", context, data, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_part_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_part_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_media_part_number() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadata_block_header.identifier != MetadataBlock) ctx->metadata_block_header.identifier = MetadataBlock;
// Reserve memory
uint8_t *copy = malloc(length);
if(copy == NULL)
{
FATAL("Could not allocate memory for creator");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
// Copy opaque UTF-16LE string
memcpy(copy, data, length);
if(ctx->media_part_number != NULL) free(ctx->media_part_number);
ctx->media_part_number = copy;
ctx->metadata_block_header.mediaPartNumberLength = length;
TRACE("Exiting aaruf_set_media_part_number(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}
/**
* @brief Sets the drive manufacturer information for the image.
*
* Records the name of the company that manufactured the drive or device used to read
* or write the physical storage media. This metadata provides valuable context about
* the imaging process, as different drives may have different capabilities, error
* handling characteristics, and compatibility with specific media types. The manufacturer
* name is stored in UTF-16LE encoding.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param data Pointer to the drive manufacturer string data in UTF-16LE encoding (opaque byte array).
* @param length Length of the drive manufacturer data in bytes (must include full UTF-16LE character sequences).
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set drive manufacturer. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - Memory allocation for the drive manufacturer string succeeded
* - The metadata block header is initialized (identifier set to MetadataBlock)
* - The drive manufacturer data is copied to ctx->imageInfo.DriveManufacturer
* - The driveManufacturerLength field is set in the metadata block header
* - Any previous drive manufacturer string is properly freed before replacement
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-8) Memory allocation failed. This occurs when:
* - malloc() failed to allocate the required memory for the drive manufacturer string
* - System is out of memory or memory is severely fragmented
* - The requested allocation size is too large
*
* @note Common Drive Manufacturers:
* - Optical drives: Pioneer, Plextor, LG, ASUS, Sony, Samsung
* - Tape drives: HP, IBM, Quantum, Tandberg, Exabyte
* - Hard drives: Seagate, Western Digital, Hitachi, Toshiba
* - Floppy drives: Teac, Panasonic, Mitsumi, Sony
*
* @note Imaging Context and Quality:
* - Different manufacturers have varying error recovery capabilities
* - Some drives are better suited for archival-quality imaging
* - Plextor drives were historically preferred for optical disc preservation
* - Professional-grade drives often have better read accuracy
* - Important for understanding potential limitations in the imaging process
*
* @note Forensic and Provenance Value:
* - Documents the complete imaging environment
* - Helps assess reliability and trustworthiness of the image
* - Useful for troubleshooting or reproducing imaging results
* - May be required for forensic chain of custody
* - Supports quality assurance and validation processes
*
* @warning The metadata block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted.
*/
int32_t aaruf_set_drive_manufacturer(void *context, const uint8_t *data, const int32_t length)
{
TRACE("Entering aaruf_set_drive_manufacturer(%p, %p, %d)", context, data, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_drive_manufacturer() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_drive_manufacturer() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_drive_manufacturer() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadata_block_header.identifier != MetadataBlock) ctx->metadata_block_header.identifier = MetadataBlock;
// Reserve memory
uint8_t *copy = malloc(length);
if(copy == NULL)
{
FATAL("Could not allocate memory for drive manufacturer");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
// Copy opaque UTF-16LE string
memcpy(copy, data, length);
if(ctx->drive_manufacturer != NULL) free(ctx->drive_manufacturer);
ctx->drive_manufacturer = copy;
ctx->metadata_block_header.driveManufacturerLength = length;
TRACE("Exiting aaruf_set_drive_manufacturer(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}
/**
* @brief Sets the drive model information for the image.
*
* Records the specific model or product designation of the drive or device used to read
* or write the physical storage media. This metadata provides detailed information about
* the imaging equipment, which can be important for understanding the capabilities,
* limitations, and characteristics of the imaging process. Different drive models within
* the same manufacturer's product line may have significantly different features and
* performance characteristics. The model information is stored in UTF-16LE encoding.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param data Pointer to the drive model string data in UTF-16LE encoding (opaque byte array).
* @param length Length of the drive model data in bytes (must include full UTF-16LE character sequences).
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set drive model. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - Memory allocation for the drive model string succeeded
* - The metadata block header is initialized (identifier set to MetadataBlock)
* - The drive model data is copied to ctx->imageInfo.DriveModel
* - The driveModelLength field is set in the metadata block header
* - Any previous drive model string is properly freed before replacement
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-8) Memory allocation failed. This occurs when:
* - malloc() failed to allocate the required memory for the drive model string
* - System is out of memory or memory is severely fragmented
* - The requested allocation size is too large
*
* @note Drive Model Examples:
* - Optical drives: "DVR-111D" (Pioneer), "PX-716A" (Plextor), "GH24NSB0" (LG)
* - Tape drives: "Ultrium 7-SCSI" (HP), "TS1140" (IBM), "SDLT600" (Quantum)
* - Hard drives: "ST2000DM008" (Seagate), "WD40EZRZ" (Western Digital)
* - Floppy drives: "FD-235HF" (Teac), "JU-257A633P" (Panasonic)
*
* @note Model-Specific Characteristics:
* - Different models may have different error correction algorithms
* - Some models are known for superior read quality (e.g., Plextor Premium)
* - Certain models may have bugs or quirks in specific firmware versions
* - Professional models often have features not available in consumer versions
* - Important for reproducing imaging conditions or troubleshooting issues
*
* @note Forensic Documentation:
* - Complete drive identification aids in forensic reporting
* - Helps establish the reliability of the imaging process
* - May be required for compliance with forensic standards
* - Supports validation and verification procedures
* - Enables assessment of tool suitability for the imaging task
*
* @note Historical and Research Value:
* - Documents evolution of imaging technology over time
* - Helps identify best practices for specific media types
* - Useful for academic research on digital preservation
* - Aids in understanding drive availability and obsolescence
*
* @warning The metadata block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted.
*/
int32_t aaruf_set_drive_model(void *context, const uint8_t *data, const int32_t length)
{
TRACE("Entering aaruf_set_drive_model(%p, %p, %d)", context, data, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_drive_model() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_drive_model() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_drive_model() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadata_block_header.identifier != MetadataBlock) ctx->metadata_block_header.identifier = MetadataBlock;
// Reserve memory
uint8_t *copy = malloc(length);
if(copy == NULL)
{
FATAL("Could not allocate memory for media model");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
// Copy opaque UTF-16LE string
memcpy(copy, data, length);
if(ctx->drive_model != NULL) free(ctx->drive_model);
ctx->drive_model = copy;
ctx->metadata_block_header.driveModelLength = length;
TRACE("Exiting aaruf_set_drive_model(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}
/**
* @brief Sets the drive serial number for the image.
*
* Records the unique serial number of the drive or device used to read or write the
* physical storage media. This metadata provides a unique identifier for the specific
* piece of hardware used in the imaging process, which is particularly important for
* forensic work, equipment tracking, and quality assurance. The serial number enables
* correlation between multiple images created with the same drive and can help identify
* drive-specific issues or characteristics. The serial number is stored in UTF-16LE encoding.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param data Pointer to the drive serial number string data in UTF-16LE encoding (opaque byte array).
* @param length Length of the drive serial number data in bytes (must include full UTF-16LE character sequences).
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set drive serial number. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - Memory allocation for the drive serial number string succeeded
* - The metadata block header is initialized (identifier set to MetadataBlock)
* - The drive serial number data is copied to ctx->imageInfo.DriveSerialNumber
* - The driveSerialNumberLength field is set in the metadata block header
* - Any previous drive serial number string is properly freed before replacement
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-8) Memory allocation failed. This occurs when:
* - malloc() failed to allocate the required memory for the drive serial number string
* - System is out of memory or memory is severely fragmented
* - The requested allocation size is too large
*
* @note Serial Number Sources:
* - Hard drives and SSDs: Retrieved via ATA/SCSI IDENTIFY commands
* - Optical drives: Available through SCSI inquiry or ATA identify
* - Tape drives: Typically reported via SCSI inquiry data
* - USB devices: May have USB serial numbers or internal device serials
* - Some older or consumer devices may not report serial numbers
*
* @note Forensic Applications:
* - Critical for forensic chain of custody documentation
* - Uniquely identifies the specific hardware used for imaging
* - Enables tracking of drive calibration and maintenance history
* - Supports correlation of images created with the same equipment
* - May be required by forensic standards and best practices
*
* @note Equipment Management:
* - Helps track drive usage and workload for maintenance planning
* - Enables identification of drives requiring replacement or service
* - Supports equipment inventory and asset management systems
* - Useful for identifying drives with known issues or recalls
* - Facilitates warranty and support claim processing
*
* @note Quality Assurance:
* - Enables analysis of drive-specific error patterns
* - Helps identify if multiple imaging issues stem from the same drive
* - Supports statistical quality control processes
* - Aids in evaluating drive reliability over time
* - Can reveal degradation or calibration drift in aging hardware
*
* @warning The metadata block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted.
*/
int32_t aaruf_set_drive_serial_number(void *context, const uint8_t *data, const int32_t length)
{
TRACE("Entering aaruf_set_drive_serial_number(%p, %p, %d)", context, data, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_drive_serial_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_drive_serial_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_drive_serial_number() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadata_block_header.identifier != MetadataBlock) ctx->metadata_block_header.identifier = MetadataBlock;
// Reserve memory
uint8_t *copy = malloc(length);
if(copy == NULL)
{
FATAL("Could not allocate memory for drive serial number");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
// Copy opaque UTF-16LE string
memcpy(copy, data, length);
if(ctx->drive_serial_number != NULL) free(ctx->drive_serial_number);
ctx->drive_serial_number = copy;
ctx->metadata_block_header.driveSerialNumberLength = length;
TRACE("Exiting aaruf_set_drive_serial_number(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}
/**
* @brief Sets the drive firmware revision for the image.
*
* Records the firmware version or revision of the drive or device used to read or write
* the physical storage media. Firmware revisions can significantly affect drive behavior,
* error handling, performance, and compatibility. This metadata is crucial for understanding
* the imaging environment, troubleshooting issues, and ensuring reproducibility. Different
* firmware versions of the same drive model can behave quite differently, making this
* information essential for comprehensive documentation. The firmware revision is stored
* in UTF-16LE encoding.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param data Pointer to the drive firmware revision string data in UTF-16LE encoding (opaque byte array).
* @param length Length of the drive firmware revision data in bytes (must include full UTF-16LE character sequences).
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set drive firmware revision. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - Memory allocation for the drive firmware revision string succeeded
* - The metadata block header is initialized (identifier set to MetadataBlock)
* - The drive firmware revision data is copied to ctx->imageInfo.DriveFirmwareRevision
* - The driveFirmwareRevisionLength field is set in the metadata block header
* - Any previous drive firmware revision string is properly freed before replacement
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-8) Memory allocation failed. This occurs when:
* - malloc() failed to allocate the required memory for the drive firmware revision string
* - System is out of memory or memory is severely fragmented
* - The requested allocation size is too large
*
* @note Firmware Revision Examples:
* - Optical drives: "1.07", "1.00a", "VER A302"
* - Tape drives: "B8S1", "7760", "V4.0"
* - Hard drives: "CC45", "80.00A80", "HPG9"
* - Format varies by manufacturer and device type
*
* @note Firmware Impact on Imaging:
* - Different firmware versions may have different error recovery strategies
* - Bug fixes in newer firmware can improve read reliability
* - Some firmware versions have known issues with specific media types
* - Performance characteristics may vary between firmware revisions
* - Firmware can affect features like C2 error reporting on optical drives
*
* @note Troubleshooting and Support:
* - Essential for diagnosing drive-specific problems
* - Manufacturer support often requires firmware version information
* - Helps identify if issues are resolved in newer firmware
* - Enables correlation of problems with known firmware bugs
* - Supports decision-making about firmware updates
*
* @note Reproducibility and Documentation:
* - Complete environment documentation for scientific reproducibility
* - Important for forensic work requiring detailed equipment records
* - Helps explain variations in imaging results over time
* - Supports compliance with archival and preservation standards
* - Enables future researchers to understand imaging conditions
*
* @note Historical Tracking:
* - Documents firmware changes over the life of imaging equipment
* - Helps assess impact of firmware updates on imaging quality
* - Useful for long-term archival projects spanning years
* - Aids in understanding evolution of drive technology
*
* @warning The metadata block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted.
*
* @warning Firmware revisions are device-specific and format varies widely:
* - No standard format exists across manufacturers
* - May include letters, numbers, dots, or other characters
* - Should be recorded exactly as reported by the device
*/
int32_t aaruf_set_drive_firmware_revision(void *context, const uint8_t *data, const int32_t length)
{
TRACE("Entering aaruf_set_drive_firmware_revision(%p, %p, %d)", context, data, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_drive_firmware_revision() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_drive_firmware_revision() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_drive_firmware_revision() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadata_block_header.identifier != MetadataBlock) ctx->metadata_block_header.identifier = MetadataBlock;
// Reserve memory
uint8_t *copy = malloc(length);
if(copy == NULL)
{
FATAL("Could not allocate memory for creator");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
// Copy opaque UTF-16LE string
memcpy(copy, data, length);
if(ctx->drive_firmware_revision != NULL) free(ctx->drive_firmware_revision);
ctx->drive_firmware_revision = copy;
ctx->metadata_block_header.driveFirmwareRevisionLength = length;
TRACE("Exiting aaruf_set_drive_firmware_revision(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the embedded CICM XML metadata sidecar from the image.
*
* CICM (Canary Islands Computer Museum) XML is a standardized metadata format used for documenting
* preservation and archival information about media and disk images. This function extracts the
* raw CICM XML payload that was embedded in the AaruFormat image during creation. The XML data is
* preserved in its original form without parsing, interpretation, or validation by the library.
* The metadata typically includes detailed information about the physical media, imaging process,
* checksums, device information, and preservation metadata following the CICM schema.
*
* This function supports a two-call pattern for buffer size determination:
* 1. First call with a buffer that may be too small returns AARUF_ERROR_BUFFER_TOO_SMALL
* and sets *length to the required size
* 2. Second call with a properly sized buffer retrieves the actual data
*
* Alternatively, if the caller already knows the buffer is large enough, a single call
* will succeed and populate the buffer with the CICM XML data.
*
* @param context Pointer to the aaruformat context (must be a valid, opened image context).
* @param buffer Pointer to a buffer that will receive the CICM XML metadata. Must be large
* enough to hold the entire XML payload (at least *length bytes on input).
* The buffer will contain raw UTF-8 encoded XML data on success.
* @param length Pointer to a size_t that serves dual purpose:
* - On input: size of the provided buffer in bytes
* - On output: actual size of the CICM XML metadata in bytes
* If the function returns AARUF_ERROR_BUFFER_TOO_SMALL, this will be updated
* to contain the required buffer size for a subsequent successful call.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully retrieved CICM XML metadata. This is returned when:
* - The context is valid and properly initialized
* - The CICM block is present in the image (identifier == CicmBlock)
* - The provided buffer is large enough (>= required length)
* - The CICM XML data is successfully copied to the buffer
* - The *length parameter is set to the actual size of the XML data
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_open() or aaruf_create()
*
* @retval AARUF_ERROR_CANNOT_READ_BLOCK (-6) The CICM block is not present. This occurs when:
* - The image was created without CICM XML metadata
* - ctx->cicmBlock is NULL (no data loaded)
* - ctx->cicmBlockHeader.length is 0 (empty metadata)
* - ctx->cicmBlockHeader.identifier doesn't equal CicmBlock
* - The CICM block was not found during image opening
* - The *length output parameter is set to 0 to indicate no data available
*
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer is insufficient. This occurs when:
* - The input *length is less than ctx->cicmBlockHeader.length
* - The *length parameter is updated to contain the required buffer size
* - No data is copied to the buffer
* - The caller should allocate a larger buffer and call again
*
* @note CICM XML Format:
* - The XML is stored in UTF-8 encoding
* - The payload may or may not be null-terminated
* - The library treats the XML as opaque binary data
* - No XML parsing, interpretation, or validation is performed by libaaruformat
* - Schema validation and XML processing are the caller's responsibility
*
* @note CICM Metadata Purpose:
* - Developed by the Canary Islands Computer Museum for digital preservation
* - Documents comprehensive preservation metadata
* - Includes checksums for data integrity verification
* - Records detailed device and media information
* - Supports archival and long-term preservation requirements
* - Provides standardized metadata for digital preservation workflows
* - Used by cultural heritage institutions and archives
*
* @note Buffer Size Handling:
* - First call with insufficient buffer returns required size in *length
* - Caller allocates properly sized buffer based on returned length
* - Second call with adequate buffer retrieves the actual XML data
* - Single call succeeds if buffer is already large enough
*
* @note Data Availability:
* - CICM blocks are optional in AaruFormat images
* - Not all images will contain CICM metadata
* - The presence of CICM data depends on how the image was created
* - Check return value to handle missing metadata gracefully
*
* @warning The XML data may contain sensitive information about the imaging environment,
* personnel, locations, or media content. Handle appropriately for your use case.
*
* @warning This function reads from the in-memory CICM block loaded during aaruf_open().
* It does not perform file I/O operations. The entire CICM XML is kept in memory
* for the lifetime of the context.
*
* @warning The buffer parameter must be valid and large enough to hold the XML data.
* Passing a buffer smaller than the required size will result in
* AARUF_ERROR_BUFFER_TOO_SMALL with no partial data copied.
*
* @see CicmMetadataBlock for the on-disk structure definition.
* @see aaruf_set_cicm_metadata() for embedding CICM XML during image creation.
*/
int32_t aaruf_get_cicm_metadata(const void *context, uint8_t *buffer, size_t *length)
{
TRACE("Entering aaruf_get_cicm_metadata(%p, %p, %p)", context, buffer, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_cicm_metadata() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_cicm_metadata() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->cicm_block == NULL || ctx->cicm_block_header.length == 0 || ctx->cicm_block_header.identifier != CicmBlock)
{
TRACE("No CICM XML metadata present");
*length = 0;
TRACE("Exiting aaruf_get_cicm_metadata() = AARUF_ERROR_CANNOT_READ_BLOCK");
return AARUF_ERROR_CANNOT_READ_BLOCK;
}
if(*length < ctx->cicm_block_header.length)
{
TRACE("Buffer too small for CICM XML metadata, required %u bytes", ctx->cicm_block_header.length);
*length = ctx->cicm_block_header.length;
TRACE("Exiting aaruf_get_cicm_metadata() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
*length = ctx->cicm_block_header.length;
memcpy(buffer, ctx->cicm_block, ctx->cicm_block_header.length);
TRACE("CICM XML metadata read successfully, length %u", *length);
TRACE("Exiting aaruf_get_cicm_metadata(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the embedded Aaru metadata JSON from the image.
*
* Aaru metadata JSON is a structured metadata format that provides machine-readable, comprehensive
* information about the image, media, imaging session details, hardware configuration, optical disc
* tracks and sessions, checksums, and preservation metadata. This function extracts the raw JSON
* payload that was embedded in the AaruFormat image during creation. The JSON data is preserved in
* its original form without parsing or interpretation by the library, allowing callers to process
* the structured metadata using standard JSON parsing libraries.
*
* This function supports a two-call pattern for buffer size determination:
* 1. First call with a buffer that may be too small returns AARUF_ERROR_BUFFER_TOO_SMALL
* and sets *length to the required size
* 2. Second call with a properly sized buffer retrieves the actual data
*
* Alternatively, if the caller already knows the buffer is large enough, a single call
* will succeed and populate the buffer with the Aaru JSON data.
*
* @param context Pointer to the aaruformat context (must be a valid, opened image context).
* @param buffer Pointer to a buffer that will receive the Aaru metadata JSON. Must be large
* enough to hold the entire JSON payload (at least *length bytes on input).
* The buffer will contain raw UTF-8 encoded JSON data on success.
* @param length Pointer to a size_t that serves dual purpose:
* - On input: size of the provided buffer in bytes
* - On output: actual size of the Aaru metadata JSON in bytes
* If the function returns AARUF_ERROR_BUFFER_TOO_SMALL, this will be updated
* to contain the required buffer size for a subsequent successful call.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully retrieved Aaru metadata JSON. This is returned when:
* - The context is valid and properly initialized
* - The Aaru JSON block is present in the image (identifier == AaruMetadataJsonBlock)
* - The provided buffer is large enough (>= required length)
* - The Aaru JSON data is successfully copied to the buffer
* - The *length parameter is set to the actual size of the JSON data
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_open() or aaruf_create()
*
* @retval AARUF_ERROR_CANNOT_READ_BLOCK (-6) The Aaru JSON block is not present. This occurs when:
* - The image was created without Aaru metadata JSON
* - ctx->jsonBlock is NULL (no data loaded)
* - ctx->jsonBlockHeader.length is 0 (empty metadata)
* - ctx->jsonBlockHeader.identifier doesn't equal AaruMetadataJsonBlock
* - The Aaru JSON block was not found during image opening
* - The *length output parameter is set to 0 to indicate no data available
*
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer is insufficient. This occurs when:
* - The input *length is less than ctx->jsonBlockHeader.length
* - The *length parameter is updated to contain the required buffer size
* - No data is copied to the buffer
* - The caller should allocate a larger buffer and call again
*
* @note Aaru JSON Format and Encoding:
* - The JSON payload is stored in UTF-8 encoding
* - The payload may or may not be null-terminated
* - The library treats the JSON as opaque binary data
* - No JSON parsing, interpretation, or validation is performed by libaaruformat
* - JSON schema validation and parsing are the caller's responsibility
*
* @note Aaru Metadata JSON Purpose:
* - Provides machine-readable structured metadata using modern JSON format
* - Includes comprehensive information about media, sessions, tracks, and checksums
* - Enables programmatic access to metadata without XML parsing overhead
* - Documents imaging session details, hardware configuration, and preservation data
* - Used by Aaru and compatible tools for metadata exchange and analysis
* - Complements or serves as alternative to CICM XML metadata
*
* @note Buffer Size Handling:
* - First call with insufficient buffer returns required size in *length
* - Caller allocates properly sized buffer based on returned length
* - Second call with adequate buffer retrieves the actual JSON data
* - Single call succeeds if buffer is already large enough
*
* @note Data Availability:
* - Aaru JSON blocks are optional in AaruFormat images
* - Not all images will contain Aaru metadata JSON
* - The presence of JSON data depends on how the image was created
* - Check return value to handle missing metadata gracefully
* - Images may contain CICM XML, Aaru JSON, both, or neither
*
* @note Distinction from CICM XML:
* - CICM XML follows the Canary Islands Computer Museum schema (older format)
* - Aaru JSON follows the Aaru-specific metadata schema (newer format)
* - Both can coexist in the same image file
* - Aaru JSON may provide more detailed or different metadata than CICM XML
* - Different tools and workflows may prefer one format over the other
*
* @warning This function reads from the in-memory Aaru JSON block loaded during aaruf_open().
* It does not perform file I/O operations. The entire JSON is kept in memory
* for the lifetime of the context.
*
* @warning The buffer parameter must be valid and large enough to hold the JSON data.
* Passing a buffer smaller than the required size will result in
* AARUF_ERROR_BUFFER_TOO_SMALL with no partial data copied.
*
* @warning This function does not validate JSON syntax or schema. Corrupted JSON data will
* be retrieved successfully and errors will only be detected when attempting to parse.
*
* @see AaruMetadataJsonBlockHeader for the on-disk structure definition.
* @see aaruf_get_cicm_metadata() for retrieving CICM XML metadata.
* @see process_aaru_metadata_json_block() for the loading process during image opening.
*/
int32_t aaruf_get_aaru_json_metadata(const void *context, uint8_t *buffer, size_t *length)
{
TRACE("Entering aaruf_get_aaru_json_metadata(%p, %p, %p)", context, buffer, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_aaru_json_metadata() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_aaru_json_metadata() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->json_block == NULL || ctx->json_block_header.length == 0 ||
ctx->json_block_header.identifier != AaruMetadataJsonBlock)
{
TRACE("No Aaru metadata JSON present");
*length = 0;
TRACE("Exiting aaruf_get_aaru_json_metadata() = AARUF_ERROR_CANNOT_READ_BLOCK");
return AARUF_ERROR_CANNOT_READ_BLOCK;
}
if(*length < ctx->json_block_header.length)
{
TRACE("Buffer too small for Aaru metadata JSON, required %u bytes", ctx->json_block_header.length);
*length = ctx->json_block_header.length;
TRACE("Exiting aaruf_get_aaru_json_metadata() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
*length = ctx->json_block_header.length;
memcpy(buffer, ctx->json_block, ctx->json_block_header.length);
TRACE("Aaru metadata JSON read successfully, length %u", *length);
TRACE("Exiting aaruf_get_aaru_json_metadata(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Sets the Aaru metadata JSON for the image during creation.
*
* Embeds Aaru metadata JSON into the image being created. The Aaru metadata JSON format is a
* structured, machine-readable representation of comprehensive image metadata including media
* information, imaging session details, hardware configuration, optical disc tracks and sessions,
* checksums, and preservation metadata. This function stores the JSON payload in its original form
* without parsing or validation, allowing callers to provide pre-generated JSON conforming to the
* Aaru metadata schema. The JSON data will be written to the image file during aaruf_close() as
* an AaruMetadataJsonBlock.
*
* The function accepts raw UTF-8 encoded JSON data as an opaque byte array and creates an internal
* copy that persists for the lifetime of the context. If Aaru JSON metadata was previously set on
* this context, the old data is freed and replaced with the new JSON. The JSON is treated as opaque
* binary data by the library; no parsing, interpretation, or schema validation is performed during
* the set operation.
*
* @param context Pointer to the aaruformat context (must be a valid, write-enabled image context).
* @param data Pointer to the Aaru metadata JSON data in UTF-8 encoding (opaque byte array).
* The JSON should conform to the Aaru metadata schema, though this is not validated.
* Must not be NULL.
* @param length Length of the JSON data in bytes. The payload may or may not be null-terminated;
* the length should reflect the actual JSON data size.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully set Aaru metadata JSON. This is returned when:
* - The context is valid and properly initialized
* - The context is opened in write mode (ctx->isWriting is true)
* - Memory allocation for the JSON data succeeded
* - The JSON data is copied to ctx->jsonBlock
* - The jsonBlockHeader is initialized with identifier AaruMetadataJsonBlock
* - The jsonBlockHeader.length field is set to the provided length
* - Any previous Aaru JSON data is properly freed before replacement
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_create()
*
* @retval AARUF_READ_ONLY (-13) The context is not opened for writing. This occurs when:
* - The image was opened with aaruf_open() instead of aaruf_create()
* - The context's isWriting flag is false
* - Attempting to modify a read-only image
*
* @retval AARUF_ERROR_NOT_ENOUGH_MEMORY (-8) Memory allocation failed. This occurs when:
* - malloc() failed to allocate the required memory for the JSON data
* - System is out of memory or memory is severely fragmented
* - The requested allocation size is too large
*
* @note Aaru JSON Format and Encoding:
* - The JSON payload must be valid UTF-8 encoded data
* - The payload may or may not be null-terminated
* - The library treats the JSON as opaque binary data
* - No JSON parsing, interpretation, or validation is performed during set
* - Schema compliance is the caller's responsibility
* - Ensure the JSON conforms to the Aaru metadata schema for compatibility
*
* @note Aaru Metadata JSON Purpose:
* - Provides machine-readable structured metadata using modern JSON format
* - Includes comprehensive information about media, sessions, tracks, and checksums
* - Enables programmatic access to metadata without XML parsing overhead
* - Documents imaging session details, hardware configuration, and preservation data
* - Used by Aaru and compatible tools for metadata exchange and analysis
* - Complements or serves as alternative to CICM XML metadata
*
* @note JSON Content Examples:
* - Media type and physical characteristics
* - Track and session information for optical media
* - Partition and filesystem metadata
* - Checksums (MD5, SHA-1, SHA-256, etc.) for integrity verification
* - Hardware information (drive manufacturer, model, firmware)
* - Imaging software version and configuration
* - Timestamps for image creation and modification
*
* @note Memory Management:
* - The function creates an internal copy of the JSON data
* - The caller retains ownership of the input data buffer
* - The caller may free the input data immediately after this function returns
* - The internal copy is freed automatically during aaruf_close()
* - Calling this function multiple times replaces previous JSON data
*
* @note Relationship to CICM XML:
* - Both CICM XML and Aaru JSON can be set on the same image
* - CICM XML follows the Canary Islands Computer Museum schema (older format)
* - Aaru JSON follows the Aaru-specific metadata schema (newer format)
* - Setting one does not affect the other
* - Different tools may prefer one format over the other
* - Consider including both for maximum compatibility
*
* @warning The Aaru JSON block is only written to the image file during aaruf_close().
* Changes made by this function are not immediately persisted to disk.
*
* @warning No validation is performed on the JSON data:
* - Invalid JSON syntax will be stored and only detected during parsing
* - Schema violations will not be caught by this function
* - Ensure JSON is valid and schema-compliant before calling
* - Use a JSON validation library before embedding if correctness is critical
*
* @warning The function accepts any length value:
* - Ensure the length accurately reflects the JSON data size
* - Incorrect length values may cause truncation or include garbage data
* - For null-terminated JSON, length should not include the null terminator
* unless it is intended to be part of the stored data
*
* @see AaruMetadataJsonBlockHeader for the on-disk structure definition.
* @see aaruf_get_aaru_json_metadata() for retrieving Aaru JSON from opened images.
* @see write_aaru_json_block() for the serialization process during image closing.
*/
int32_t aaruf_set_aaru_json_metadata(void *context, uint8_t *data, size_t length)
{
TRACE("Entering aaruf_set_aaru_json_metadata(%p, %p, %d)", context, data, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_aaru_json_metadata() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_aaru_json_metadata() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Check we are writing
if(!ctx->is_writing)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_aaru_json_metadata() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Reserve memory
uint8_t *copy = malloc(length);
if(copy == NULL)
{
FATAL("Could not allocate memory for Aaru metadata JSON");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
// Copy opaque UTF-8 string
memcpy(copy, data, length);
if(ctx->json_block != NULL) free(ctx->json_block);
ctx->json_block = copy;
ctx->json_block_header.identifier = AaruMetadataJsonBlock;
ctx->json_block_header.length = (uint32_t)length;
TRACE("Exiting aaruf_set_aaru_json_metadata(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the media sequence metadata for multi-volume image sets.
*
* Reads the media sequence fields stored in the MetadataBlock header and returns the current media
* number together with the final media number for the complete set. This information indicates the
* position of the imaged medium within a multi-volume collection (for example, "disc 2 of 5"). The
* function operates entirely on in-memory structures populated during aaruf_open(); no additional
* disk I/O is performed.
*
* @param context Pointer to an initialized aaruformat context opened for reading or writing.
* @param sequence Pointer that receives the current media sequence number (typically 1-based).
* @param last_sequence Pointer that receives the total number of media in the set.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Metadata was present and the output parameters were populated.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The provided context pointer is NULL or not an
* aaruformat context (magic mismatch).
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) The MetadataBlock was not present in the image,
* making sequence data unavailable.
*
* @note For standalone media, both sequence and last_sequence are commonly set to 1. Some creators
* may also set them to 0 to indicate the absence of sequence semantics; callers should handle
* either pattern gracefully.
*
* @note The function does not validate logical consistency (e.g., whether sequence <= last_sequence);
* it simply returns the values stored in the image header.
*/
int32_t aaruf_get_media_sequence(const void *context, int32_t *sequence, int32_t *last_sequence)
{
TRACE("Entering aaruf_get_media_sequence(%p, %p, %p)", context, sequence, last_sequence);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_sequence() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_set_media_sequence() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadata_block_header.identifier != MetadataBlock)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_set_media_sequence() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
*sequence = ctx->metadata_block_header.mediaSequence;
*last_sequence = ctx->metadata_block_header.lastMediaSequence;
TRACE("Exiting aaruf_set_media_sequence(%p, %d, %d) = AARUF_STATUS_OK", context, *sequence, *last_sequence);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the recorded creator (operator) name from the MetadataBlock.
*
* Copies the UTF-16LE encoded creator string that identifies the person or operator who created the
* image. The function supports the common two-call pattern: the caller first determines the required
* buffer size by passing a buffer that may be NULL or too small, then allocates sufficient memory and
* calls again to obtain the actual data. On success the buffer contains an opaque UTF-16LE string of
* length *length bytes (not null-terminated).
*
* @param context Pointer to a valid aaruformat context opened for reading or writing.
* @param buffer Pointer to the destination buffer that will receive the creator string. May be NULL
* to query the required size.
* @param length Pointer to an int32_t that on input specifies the size of @p buffer in bytes and on
* output receives the actual length of the creator metadata.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) The creator string was copied successfully.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is NULL or not an aaruformat context.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) Creator metadata has not been recorded in the image.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer was insufficient; *length contains
* the required size and no data was copied.
*
* @note The returned data is UTF-16LE encoded and may contain embedded null characters. Callers
* should treat it as an opaque byte array unless they explicitly handle UTF-16LE strings.
*
* @note The function does not allocate memory. Callers are responsible for ensuring @p buffer is
* large enough before requesting the data.
*/
int32_t aaruf_get_creator(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_creator(%p, %p, %p)", context, buffer, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_creator() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_creator() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadata_block_header.identifier != MetadataBlock || ctx->creator == NULL ||
ctx->metadata_block_header.creatorLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_creator() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadata_block_header.creatorLength)
{
*length = ctx->metadata_block_header.creatorLength;
TRACE("Exiting aaruf_get_creator() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->creator, ctx->metadata_block_header.creatorLength);
*length = ctx->metadata_block_header.creatorLength;
TRACE("Exiting aaruf_get_creator(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the user comments or notes stored in the MetadataBlock.
*
* Provides access to the UTF-16LE encoded comments associated with the image. Comments are often
* used for provenance notes, imaging details, or curator remarks. The function follows the same
* two-call buffer sizing pattern used by other metadata retrieval APIs: the caller may probe the
* required size before allocating memory.
*
* @param context Pointer to a valid aaruformat context opened with aaruf_open() or aaruf_create().
* @param buffer Destination buffer that receives the comments data. May be NULL when probing size.
* @param length Pointer to an int32_t. On input it contains the size of @p buffer in bytes; on output
* it is updated with the actual comments length.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Comments were available and copied successfully.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid or not a libaaruformat context.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No comments metadata exists in the image.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The supplied buffer was too small. *length is updated with
* the required size and no data is copied.
*
* @note Comments are stored exactly as provided during image creation and may include multi-line text
* or other control characters. No validation or normalization is applied by the library.
*/
int32_t aaruf_get_comments(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_comments(%p, %p, %p)", context, buffer, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_comments() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_comments() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadata_block_header.identifier != MetadataBlock || ctx->comments == NULL ||
ctx->metadata_block_header.commentsLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_comments() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadata_block_header.commentsLength)
{
*length = ctx->metadata_block_header.commentsLength;
TRACE("Exiting aaruf_get_comments() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->comments, ctx->metadata_block_header.commentsLength);
*length = ctx->metadata_block_header.commentsLength;
TRACE("Exiting aaruf_get_comments(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the media title or label captured during image creation.
*
* Returns the UTF-16LE encoded media title string, representing markings or labels present on the
* original physical media. This function allows applications to present or archive the media title
* alongside the image, preserving contextual information from the physical artifact.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Destination buffer for the UTF-16LE title string. May be NULL when querying size.
* @param length Pointer to an int32_t that on input holds the buffer capacity in bytes and on output
* receives the actual title length.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) The media title was available and copied to @p buffer.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No media title metadata exists.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The supplied buffer was insufficient.
*
* @note Titles may contain international characters, control codes, or mixed casing. The library does
* not attempt to sanitize or interpret the string.
*/
int32_t aaruf_get_media_title(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_media_title(%p, %p, %p)", context, buffer, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_title() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_title() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadata_block_header.identifier != MetadataBlock || ctx->media_title == NULL ||
ctx->metadata_block_header.mediaTitleLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_media_title() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadata_block_header.mediaTitleLength)
{
*length = ctx->metadata_block_header.mediaTitleLength;
TRACE("Exiting aaruf_get_media_title() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->media_title, ctx->metadata_block_header.mediaTitleLength);
*length = ctx->metadata_block_header.mediaTitleLength;
TRACE("Exiting aaruf_get_media_title(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the recorded media manufacturer name.
*
* Provides access to the UTF-16LE encoded manufacturer metadata that identifies the company which
* produced the physical medium. This information is taken from the MetadataBlock and mirrors the
* value previously stored via aaruf_set_media_manufacturer().
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Buffer that receives the manufacturer string. May be NULL when probing size.
* @param length Pointer to an int32_t specifying the buffer size on input and receiving the actual
* manufacturer string length on output.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Manufacturer metadata was available and copied.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) The image lacks manufacturer metadata.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer was too small; *length indicates size.
*
* @note Values may include trailing spaces or vendor-specific capitalization. Treat the returned data
* as authoritative and avoid trimming unless required by the consuming application.
*/
int32_t aaruf_get_media_manufacturer(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_media_manufacturer(%p, %p, %p)", context, buffer, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_manufacturer() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_manufacturer() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadata_block_header.identifier != MetadataBlock || ctx->media_manufacturer == NULL ||
ctx->metadata_block_header.mediaManufacturerLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_media_manufacturer() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadata_block_header.mediaManufacturerLength)
{
*length = ctx->metadata_block_header.mediaManufacturerLength;
TRACE("Exiting aaruf_get_media_manufacturer() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->media_manufacturer, ctx->metadata_block_header.mediaManufacturerLength);
*length = ctx->metadata_block_header.mediaManufacturerLength;
TRACE("Exiting aaruf_get_media_manufacturer(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the media model or product designation metadata.
*
* Returns the UTF-16LE encoded model name that specifies the exact product variant of the physical
* medium. The function mirrors the set counterpart and is useful for accurately documenting media
* specifications during preservation workflows.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Destination buffer for the model string; may be NULL when querying required size.
* @param length Pointer to an int32_t that on input contains the buffer capacity in bytes and on
* output is updated with the actual metadata length.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Model metadata was successfully copied.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No media model metadata is present in the image.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The caller-provided buffer is too small.
*
* @note Model strings often contain performance ratings (e.g., "16x", "LTO-7"). The data is opaque and
* should be handled without modification unless necessary.
*/
int32_t aaruf_get_media_model(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_media_model(%p, %p, %p)", context, buffer, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_model() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_model() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadata_block_header.identifier != MetadataBlock || ctx->media_model == NULL ||
ctx->metadata_block_header.mediaModelLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_media_model() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadata_block_header.mediaModelLength)
{
*length = ctx->metadata_block_header.mediaModelLength;
TRACE("Exiting aaruf_get_media_model() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->media_model, ctx->metadata_block_header.mediaModelLength);
*length = ctx->metadata_block_header.mediaModelLength;
TRACE("Exiting aaruf_get_media_model(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the media serial number recorded in the image metadata.
*
* Copies the UTF-16LE encoded serial number identifying the specific physical medium. Serial numbers
* are particularly important for forensic tracking and archival provenance, enabling correlation
* between the physical item and its digital representation.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Destination buffer for the serial number. May be NULL to determine required size.
* @param length Pointer to an int32_t that on input holds the buffer size and on output receives the
* actual serial number length.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Serial number metadata was copied into @p buffer.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No serial number metadata was stored in the image.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer was too small.
*
* @note Serial numbers may contain spaces, hyphens, or alphanumeric characters. The library does not
* normalize or validate these strings.
*/
int32_t aaruf_get_media_serial_number(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_media_serial_number(%p, %p, %p)", context, buffer, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_serial_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_serial_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadata_block_header.identifier != MetadataBlock || ctx->media_serial_number == NULL ||
ctx->metadata_block_header.mediaSerialNumberLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_media_serial_number() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadata_block_header.mediaSerialNumberLength)
{
*length = ctx->metadata_block_header.mediaSerialNumberLength;
TRACE("Exiting aaruf_get_media_serial_number() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->media_serial_number, ctx->metadata_block_header.mediaSerialNumberLength);
*length = ctx->metadata_block_header.mediaSerialNumberLength;
TRACE("Exiting aaruf_get_media_serial_number(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the barcode assigned to the physical media or its packaging.
*
* Returns the UTF-16LE encoded barcode string that was captured when the image was created. Barcodes
* are commonly used in institutional workflows for inventory tracking and automated retrieval.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Buffer that receives the barcode string; may be NULL when probing size requirements.
* @param length Pointer to an int32_t specifying the buffer size on input and receiving the actual
* barcode length on output.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Barcode metadata was present and copied successfully.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No barcode metadata exists in the image.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The supplied buffer was too small.
*
* @note Barcode values can be strict alphanumeric codes (e.g., LTO cartridge IDs) or full strings from
* custom labeling systems. Preserve the returned string exactly for catalog interoperability.
*/
int32_t aaruf_get_media_barcode(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_media_barcode(%p, %p, %p)", context, buffer, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_barcode() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_barcode() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadata_block_header.identifier != MetadataBlock || ctx->media_barcode == NULL ||
ctx->metadata_block_header.mediaBarcodeLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_media_barcode() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadata_block_header.mediaBarcodeLength)
{
*length = ctx->metadata_block_header.mediaBarcodeLength;
TRACE("Exiting aaruf_get_media_barcode() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->media_barcode, ctx->metadata_block_header.mediaBarcodeLength);
*length = ctx->metadata_block_header.mediaBarcodeLength;
TRACE("Exiting aaruf_get_media_barcode(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the media part number recorded in the MetadataBlock.
*
* Provides access to the UTF-16LE encoded part number identifying the precise catalog or ordering
* code for the physical medium. Part numbers help archivists procure exact replacements and document
* specific media variants used during acquisition.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Destination buffer for the part number string. May be NULL while querying size.
* @param length Pointer to an int32_t that supplies the buffer size on input and is updated with the
* actual part number length on output.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Part number metadata was returned successfully.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No part number metadata exists.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer was insufficient; *length contains the
* required size.
*
* @note Part numbers may include manufacturer-specific formatting such as hyphens or suffix letters.
* The library stores and returns the data verbatim.
*/
int32_t aaruf_get_media_part_number(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_media_part_number(%p, %p, %p)", context, buffer, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_part_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_part_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadata_block_header.identifier != MetadataBlock || ctx->media_part_number == NULL ||
ctx->metadata_block_header.mediaPartNumberLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_media_part_number() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadata_block_header.mediaPartNumberLength)
{
*length = ctx->metadata_block_header.mediaPartNumberLength;
TRACE("Exiting aaruf_get_media_part_number() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->media_part_number, ctx->metadata_block_header.mediaPartNumberLength);
*length = ctx->metadata_block_header.mediaPartNumberLength;
TRACE("Exiting aaruf_get_media_part_number(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the drive manufacturer metadata captured during imaging.
*
* Copies the UTF-16LE encoded manufacturer name of the device used to read or write the medium. This
* information documents the hardware involved in the imaging process, which is crucial for forensic
* reporting and reproducibility studies.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Destination buffer for the manufacturer string. May be NULL when querying required
* length.
* @param length Pointer to an int32_t specifying the buffer size on input and receiving the actual
* metadata length on output.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Drive manufacturer metadata was copied successfully.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) The image lacks drive manufacturer metadata.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer is too small; *length holds the
* required size for a subsequent call.
*
* @note The returned manufacturer string corresponds to the value recorded by aaruf_set_drive_manufacturer()
* and may include branding or OEM designations.
*/
int32_t aaruf_get_drive_manufacturer(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_drive_manufacturer(%p, %p, %p)", context, buffer, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_manufacturer() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_manufacturer() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadata_block_header.identifier != MetadataBlock || ctx->drive_manufacturer == NULL ||
ctx->metadata_block_header.driveManufacturerLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_drive_manufacturer() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadata_block_header.driveManufacturerLength)
{
*length = ctx->metadata_block_header.driveManufacturerLength;
TRACE("Exiting aaruf_get_drive_manufacturer() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->drive_manufacturer, ctx->metadata_block_header.driveManufacturerLength);
*length = ctx->metadata_block_header.driveManufacturerLength;
TRACE("Exiting aaruf_get_drive_manufacturer(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the device model information for the imaging drive.
*
* Returns the UTF-16LE encoded model identifier for the drive used during acquisition. The model
* metadata provides finer granularity than the manufacturer name, enabling detailed documentation of
* imaging hardware capabilities and behavior.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Buffer that receives the model string; may be NULL while probing required capacity.
* @param length Pointer to an int32_t indicating buffer size on input and receiving the metadata length
* on output.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Drive model metadata was available and copied.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No drive model metadata exists in the image.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The supplied buffer was insufficient; *length is updated.
*
* @note Model strings can include firmware suffixes, interface hints, or OEM variations. Consume the
* data verbatim to maintain accurate provenance records.
*/
int32_t aaruf_get_drive_model(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_drive_model(%p, %p, %p)", context, buffer, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_model() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_model() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadata_block_header.identifier != MetadataBlock || ctx->drive_model == NULL ||
ctx->metadata_block_header.driveModelLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_drive_model() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadata_block_header.driveModelLength)
{
*length = ctx->metadata_block_header.driveModelLength;
TRACE("Exiting aaruf_get_drive_model() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->drive_model, ctx->metadata_block_header.driveModelLength);
*length = ctx->metadata_block_header.driveModelLength;
TRACE("Exiting aaruf_get_drive_model(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the imaging drive's serial number metadata.
*
* Copies the UTF-16LE encoded serial number reported for the drive used during the imaging session.
* This metadata enables correlation between images and specific hardware units for forensic chain of
* custody or quality assurance workflows.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Destination buffer for the serial number; may be NULL when querying size.
* @param length Pointer to an int32_t carrying the buffer size on input and receiving the actual
* serial number length on output.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Drive serial number metadata was copied to @p buffer.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No drive serial number metadata is available.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer was insufficient.
*
* @note Serial numbers are stored exactly as returned by the imaging hardware and may include leading
* zeros or spacing that should be preserved.
*/
int32_t aaruf_get_drive_serial_number(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_drive_serial_number(%p, %p, %p)", context, buffer, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_serial_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_serial_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadata_block_header.identifier != MetadataBlock || ctx->drive_serial_number == NULL ||
ctx->metadata_block_header.driveSerialNumberLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_drive_serial_number() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadata_block_header.driveSerialNumberLength)
{
*length = ctx->metadata_block_header.driveSerialNumberLength;
TRACE("Exiting aaruf_get_drive_serial_number() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->drive_serial_number, ctx->metadata_block_header.driveSerialNumberLength);
*length = ctx->metadata_block_header.driveSerialNumberLength;
TRACE("Exiting aaruf_get_drive_serial_number(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the firmware revision metadata for the imaging drive.
*
* Returns the UTF-16LE encoded firmware revision string that was captured when the image was created.
* Firmware information is critical for reproducing imaging environments and diagnosing drive-specific
* behavior or bugs.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Destination buffer for the firmware revision string. May be NULL when probing size.
* @param length Pointer to an int32_t that specifies the buffer capacity in bytes on input and is
* updated with the actual metadata length on output.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Firmware revision metadata was present and copied successfully.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No firmware metadata exists in the image.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The supplied buffer was too small; *length is updated.
*
* @note Firmware revision formats vary between manufacturers (e.g., numeric, alphanumeric, dot-separated).
* The library stores the data verbatim without attempting normalization.
*/
int32_t aaruf_get_drive_firmware_revision(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_drive_firmware_revision(%p, %p, %p)", context, buffer, length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_firmware_revision() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_firmware_revision() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadata_block_header.identifier != MetadataBlock || ctx->drive_firmware_revision == NULL ||
ctx->metadata_block_header.driveFirmwareRevisionLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_drive_firmware_revision() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadata_block_header.driveFirmwareRevisionLength)
{
*length = ctx->metadata_block_header.driveFirmwareRevisionLength;
TRACE("Exiting aaruf_get_drive_firmware_revision() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->drive_firmware_revision, ctx->metadata_block_header.driveFirmwareRevisionLength);
*length = ctx->metadata_block_header.driveFirmwareRevisionLength;
TRACE("Exiting aaruf_get_drive_firmware_revision(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the total number of user-accessible sectors in the AaruFormat image.
*
* Returns the count of standard user data sectors in the image, excluding any negative (pre-gap)
* or overflow (post-gap) sectors. This represents the primary addressable sector range that contains
* the main user data, typically corresponding to the logical capacity of the storage medium as it
* would be seen by an operating system or file system. For optical media, this excludes lead-in and
* lead-out areas. For hard disks, this represents the standard LBA-addressable range.
*
* @param context Pointer to a valid aaruformat context (must be properly initialized).
* @param sectors Pointer to a uint64_t that receives the total user sector count on success.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully retrieved the user sector count. This is returned when:
* - The context is valid and properly initialized
* - The context magic number matches AARU_MAGIC
* - The sectors parameter is successfully populated with the user sector count
* - The value is taken from ctx->user_data_ddt_header.blocks
* - For block devices: sectors typically equals the total capacity in sectors
* - For optical media: sectors represents the user data area excluding lead-in/lead-out
* - For tape media: sectors may represent the total block count across all files
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_open() or aaruf_create()
*
* @note Sector Range Context:
* - User sectors represent the standard addressable range: 0 to (user_sectors - 1)
* - Total addressable sectors = negative_sectors + user_sectors + overflow_sectors
* - Negative sectors precede user sectors (pre-gap, lead-in)
* - Overflow sectors follow user sectors (post-gap, lead-out)
* - Use aaruf_get_negative_sectors() to get the negative sector count
* - Use aaruf_get_overflow_sectors() to get the overflow sector count
*
* @note Media Type Considerations:
* - **Optical Media (CD/DVD/BD)**: User sectors exclude lead-in and lead-out areas.
* Negative sectors may contain TOC and pre-gap data. Overflow sectors may contain
* post-gap and lead-out data.
* - **Hard Disk Drives**: User sectors represent the full LBA range. Negative and
* overflow sectors are typically zero unless capturing special areas.
* - **Floppy Disks**: User sectors represent the standard formatted capacity.
* - **Tape Media**: User sectors may represent the total block count. Negative and
* overflow sectors are typically not used for tape.
*
* @note DDT Header Source:
* - The value is retrieved from ctx->user_data_ddt_header.blocks
* - The DDT (Deduplication and Data Table) header tracks sector allocation
* - This field is populated during image creation with aaruf_create()
* - The value is fixed for read-only images opened with aaruf_open()
* - For write-enabled images, this represents the allocated capacity
*
* @note Addressing and I/O Operations:
* - When reading/writing sectors with aaruf_read_sector() or aaruf_write_sector():
* - Set negative=false and use sector_address in range [0, user_sectors - 1]
* - For negative sectors: set negative=true, sector_address in [0, negative_sectors - 1]
* - For overflow sectors: set negative=false, sector_address in [user_sectors, user_sectors + overflow_sectors
* - 1]
*
* @note Relationship to Image Creation:
* - The user_sectors value is specified when calling aaruf_create()
* - It should match the logical capacity of the medium being imaged
* - For forensic images, ensure it matches the source medium exactly
* - For virtual disks, set it to the desired capacity
*/
int32_t aaruf_get_user_sectors(const void *context, uint64_t *sectors)
{
TRACE("Entering aaruf_get_user_sectors(%p, %p)", context, sectors);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_user_sectors() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_user_sectors() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
*sectors = ctx->user_data_ddt_header.blocks;
TRACE("Exiting aaruf_get_user_sectors(%p, %llu) = AARUF_STATUS_OK", context, *sectors);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the number of negative (pre-gap) sectors in the AaruFormat image.
*
* Returns the count of negative sectors that precede the standard user data area. Negative sectors
* are used to capture pre-gap data, lead-in areas, and other metadata that exists before the main
* user-accessible storage region. This is particularly important for optical media (CD, DVD, BD)
* where the lead-in contains the Table of Contents (TOC) and other essential disc structures, and
* for audio CDs where pre-gap sectors contain silence or hidden tracks. For most hard disk and
* floppy disk images, this value is typically zero.
*
* @param context Pointer to a valid aaruformat context (must be properly initialized).
* @param sectors Pointer to a uint16_t that receives the negative sector count on success.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully retrieved the negative sector count. This is returned when:
* - The context is valid and properly initialized
* - The context magic number matches AARU_MAGIC
* - The sectors parameter is successfully populated with the negative sector count
* - The value is taken from ctx->user_data_ddt_header.negative
* - For optical media with lead-in data: sectors may be non-zero
* - For standard hard disk/floppy images: sectors is typically 0
* - Maximum value is 65,535 (uint16_t limit)
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_open() or aaruf_create()
*
* @note Negative Sector Addressing:
* - Negative sectors are addressed with the 'negative' flag set to true
* - Sector addresses range from 0 to (negative_sectors - 1)
* - When calling aaruf_read_sector() or aaruf_write_sector():
* - Use negative=true
* - Use sector_address in range [0, negative_sectors - 1]
* - The actual logical position is before the user data area
*
* @note Optical Media Context:
* - **CD-ROM/CD-DA**: Negative sectors contain lead-in area with TOC (Table of Contents).
* The lead-in typically spans LBA -450000 to -1, though only a portion may be captured.
* Pre-gap sectors (usually 150 sectors/2 seconds before each track) may also be stored
* as negative sectors for the first track.
* - **DVD**: May contain lead-in with disc structure information, copyright data, and
* region codes. The lead-in area varies by format (DVD-ROM, DVD-R, DVD+R, etc.).
* - **Blu-ray**: Lead-in contains disc information, burst cutting area (BCA), and other
* metadata. The structure differs between BD-ROM, BD-R, and BD-RE.
*
* @note Hard Disk and Floppy Context:
* - Hard disk drives: Negative sectors are typically zero unless capturing special
* manufacturer reserved areas (HPA, DCO) that precede the standard user area.
* - Floppy disks: Negative sectors are typically zero as floppies have a simple
* linear sector layout without lead-in areas.
*
* @note Audio CD Hidden Tracks:
* - Some audio CDs contain hidden tracks in the pre-gap of the first track
* - These pre-gap sectors can extend up to several minutes before track 1
* - Negative sectors can capture this "hidden" audio data
* - The pre-gap for track 1 typically starts at LBA -150 (2 seconds)
*
* @note DDT Header Source:
* - The value is retrieved from ctx->user_data_ddt_header.negative
* - The DDT (Deduplication and Data Table) header tracks all sector allocation
* - This field is populated during image creation with aaruf_create()
* - The value is fixed for read-only images opened with aaruf_open()
* - Maximum representable value is 65,535 (uint16_t)
*
* @note Total Addressable Space:
* - Total sectors = negative_sectors + user_sectors + overflow_sectors
* - The negative region comes first in logical order
* - Followed by the user region [0, user_sectors - 1]
* - Followed by the overflow region if present
*
* @note Relationship to Image Creation:
* - The negative_sectors value is specified when calling aaruf_create()
* - It should be set based on the medium type and imaging requirements:
* - Optical discs: Set to the number of lead-in sectors captured
* - Hard disks: Typically 0, unless capturing HPA/DCO areas
* - Floppy disks: Typically 0
* - Audio CDs: May be non-zero to capture pre-gap hidden tracks
*
* @warning The sectors parameter is only modified on success (AARUF_STATUS_OK).
* On error, its value remains unchanged. Initialize it before calling
* if a default value is needed on failure.
*
* @warning This function reads from the in-memory DDT header loaded during
* aaruf_open() or set during aaruf_create(). It does not perform file
* I/O operations and executes quickly.
*
* @warning The maximum negative sector count is 65,535 due to the uint16_t storage type.
* If imaging optical media with larger lead-in areas, some data may not be
* representable. This limit is generally sufficient for most practical cases.
*
* @warning Negative sector data may contain copy-protected or encrypted content
* (e.g., CSS on DVDs, AACS on Blu-rays). Handle this data according to
* applicable laws and licensing agreements.
*/
int32_t aaruf_get_negative_sectors(const void *context, uint16_t *sectors)
{
TRACE("Entering aaruf_get_negative_sectors(%p, %p)", context, sectors);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_negative_sectors() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_negative_sectors() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
*sectors = ctx->user_data_ddt_header.negative;
TRACE("Exiting aaruf_get_negative_sectors(%p, %u) = AARUF_STATUS_OK", context, *sectors);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the number of overflow (post-gap) sectors in the AaruFormat image.
*
* Returns the count of overflow sectors that follow the standard user data area. Overflow sectors
* are used to capture post-gap data, lead-out areas, and other metadata that exists after the main
* user-accessible storage region. This is particularly important for optical media (CD, DVD, BD)
* where the lead-out marks the physical end of the recorded data and contains disc finalization
* information, and for multi-session discs where gaps between sessions need to be preserved. For
* most hard disk and floppy disk images, this value is typically zero.
*
* @param context Pointer to a valid aaruformat context (must be properly initialized).
* @param sectors Pointer to a uint16_t that receives the overflow sector count on success.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully retrieved the overflow sector count. This is returned when:
* - The context is valid and properly initialized
* - The context magic number matches AARU_MAGIC
* - The sectors parameter is successfully populated with the overflow sector count
* - The value is taken from ctx->user_data_ddt_header.overflow
* - For optical media with lead-out data: sectors may be non-zero
* - For standard hard disk/floppy images: sectors is typically 0
* - Maximum value is 65,535 (uint16_t limit)
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC (invalid context type)
* - The context was not properly initialized by aaruf_open() or aaruf_create()
*
* @note Overflow Sector Addressing:
* - Overflow sectors are addressed with the 'negative' flag set to false
* - Sector addresses range from user_sectors to (user_sectors + overflow_sectors - 1)
* - When calling aaruf_read_sector() or aaruf_write_sector():
* - Use negative=false
* - Use sector_address in range [user_sectors, user_sectors + overflow_sectors - 1]
* - The actual logical position is after the user data area
*
* @note Optical Media Context:
* - **CD-ROM/CD-DA**: Overflow sectors contain the lead-out area, which marks the physical
* end of the disc's recorded data. The lead-out consists of unreadable sectors filled
* with specific patterns.
* - **DVD**: May contain lead-out with disc finalization data, middle area (for dual-layer),
* and outer zone. DVD+R/RW discs may have substantial lead-out areas.
* - **Blu-ray**: Lead-out contains disc finalization markers and padding. For multi-layer
* discs, may include middle zones and outer areas.
*
* @note Multi-Session and Track Context:
* - Multi-session optical discs have gaps between sessions
* - Audio CDs with post-gap after the last track may use overflow sectors
* - Track post-gaps (silence after audio tracks) typically 2 seconds/150 sectors
*
* @note Hard Disk and Floppy Context:
* - Hard disk drives: Overflow sectors are typically zero unless capturing special
* manufacturer reserved areas (like DCO or HPA) that follow the standard user area.
* - Floppy disks: Overflow sectors are typically zero as floppies have a simple
* linear sector layout without lead-out areas. They may contain mastering information.
* - Some proprietary copy protection schemes may place data beyond the normal
* capacity, which could be captured as overflow sectors.
*
* @note DDT Header Source:
* - The value is retrieved from ctx->user_data_ddt_header.overflow
* - The DDT (Deduplication and Data Table) header tracks all sector allocation
* - This field is populated during image creation with aaruf_create()
* - The value is fixed for read-only images opened with aaruf_open()
* - Maximum representable value is 65,535 (uint16_t)
*
* @note Total Addressable Space:
* - Total sectors = negative_sectors + user_sectors + overflow_sectors
* - The negative region comes first in logical order
* - Followed by the user region [0, user_sectors - 1]
* - Followed by the overflow region at the end
* - Overflow represents the final addressable range in the image
*
* @note Relationship to Image Creation:
* - The overflow_sectors value is specified when calling aaruf_create()
* - It should be set based on the medium type and imaging requirements:
* - Optical discs: Set to the number of lead-out sectors captured
* - Multi-session discs: May include inter-session gaps
* - Hard disks: Typically 0, unless capturing post-user reserved areas
* - Floppy disks: Typically 0
* - Copy-protected media: May be non-zero to capture protection schemes
*
* @note Forensic Imaging Considerations:
* - Some copy protection schemes intentionally place data in overflow regions
* - These "overburn" areas extend beyond the disc's rated capacity
* - Overflow sectors ensure complete forensic capture of all readable data
* - Important for authenticity verification and copy protection analysis
*
* @warning The sectors parameter is only modified on success (AARUF_STATUS_OK).
* On error, its value remains unchanged. Initialize it before calling
* if a default value is needed on failure.
*
* @warning This function reads from the in-memory DDT header loaded during
* aaruf_open() or set during aaruf_create(). It does not perform file
* I/O operations and executes quickly.
*
* @warning The maximum overflow sector count is 65,535 due to the uint16_t storage type.
* If imaging optical media with larger lead-out areas or extensive overburn
* regions, some data may not be representable. This limit is generally
* sufficient for most practical cases.
*
* @warning Overflow sector data may be difficult or impossible to read on some drives,
* as it often resides in lead-out areas or beyond rated capacity. The presence
* of overflow sectors in an image indicates the imaging drive was capable of
* reading these extended areas, but other drives may not be able to access them.
*/
int32_t aaruf_get_overflow_sectors(const void *context, uint16_t *sectors)
{
TRACE("Entering aaruf_get_overflow_sectors(%p, %p)", context, sectors);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_overflow_sectors() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_overflow_sectors() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
*sectors = ctx->user_data_ddt_header.overflow;
TRACE("Exiting aaruf_get_overflow_sectors(%p, %u) = AARUF_STATUS_OK", context, *sectors);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves a deep copy of the ImageInfo structure from the AaruFormat image.
*
* Returns a complete copy of the high-level image information summary containing
* metadata such as image size, sector count, sector size, version information,
* creation timestamps, and media type. This function performs a deep copy of all
* fields including string buffers, ensuring the caller receives a complete,
* independent copy of the image information.
*
* @param context Pointer to the aaruformat context (must be a valid, opened image context).
* @param image_info Pointer to an ImageInfo structure to receive the copied data.
* Must be a valid pointer to allocated memory.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Successfully copied image info. The image_info parameter
* contains a complete copy of all fields including:
* - HasPartitions: Whether image contains partitions/tracks
* - HasSessions: Whether image contains multiple sessions
* - ImageSize: Size of image payload in bytes
* - Sectors: Total count of addressable sectors/blocks
* - SectorSize: Size of each logical sector in bytes
* - Version: Image format version string (NUL-terminated)
* - Application: Creating application name (NUL-terminated)
* - ApplicationVersion: Application version string (NUL-terminated)
* - CreationTime: Image creation timestamp (Windows FILETIME)
* - LastModificationTime: Last modification timestamp (Windows FILETIME)
* - MediaType: Media type identifier
* - MetadataMediaType: Media type for sidecar generation
*
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is invalid. This occurs when:
* - The context parameter is NULL
* - The context magic number doesn't match AARU_MAGIC
* - The context was not properly initialized
*
* @note The ImageInfo structure contains fixed-size character arrays that are
* properly NUL-terminated, making it safe to use as C strings.
*
* @note This function performs a complete deep copy using memcpy, copying all
* fields including strings, integers, and timestamps.
*
* @note The caller is responsible for allocating the ImageInfo structure before
* calling this function. The structure is not dynamically allocated by
* this function.
*
* @warning The image_info parameter must point to valid, allocated memory of
* at least sizeof(ImageInfo) bytes. Passing NULL or invalid pointers
* will result in undefined behavior.
*
* @warning This function reads from the in-memory image_info loaded during
* aaruf_open() or populated during aaruf_create(). It does not perform
* file I/O operations.
*/
int32_t aaruf_get_image_info(const void *context, ImageInfo *image_info)
{
TRACE("Entering aaruf_get_image_info(%p, %p)", context, image_info);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_image_info() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_image_info() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(image_info == NULL)
{
FATAL("image_info parameter is NULL");
TRACE("Exiting aaruf_get_image_info() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
// Perform deep copy of the image_info structure
memcpy(image_info, &ctx->image_info, sizeof(ImageInfo));
TRACE("Exiting aaruf_get_image_info() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}