Files
libaaruformat/src/metadata.c

2308 lines
107 KiB
C
Raw Normal View History

/*
* 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 <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, %u, %u, %u)", context, *cylinders, *heads, *sectors_per_track);
const aaruformatContext *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->geometryBlock.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->geometryBlock.cylinders;
*heads = ctx->geometryBlock.heads;
*sectors_per_track = ctx->geometryBlock.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);
aaruformatContext *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->isWriting)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_write_sector() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
ctx->geometryBlock.identifier = GeometryBlock;
ctx->geometryBlock.cylinders = cylinders;
ctx->geometryBlock.heads = heads;
ctx->geometryBlock.sectorsPerTrack = sectors_per_track;
ctx->imageInfo.Cylinders = cylinders;
ctx->imageInfo.Heads = heads;
ctx->imageInfo.SectorsPerTrack = 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;
}
aaruformatContext *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->isWriting)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_media_sequence() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadataBlockHeader.identifier != MetadataBlock) ctx->metadataBlockHeader.identifier = MetadataBlock;
ctx->metadataBlockHeader.mediaSequence = sequence;
ctx->metadataBlockHeader.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;
}
aaruformatContext *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->isWriting)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_creator() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadataBlockHeader.identifier != MetadataBlock) ctx->metadataBlockHeader.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->imageInfo.Creator != NULL) free(ctx->imageInfo.Creator);
ctx->imageInfo.Creator = copy;
ctx->metadataBlockHeader.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;
}
aaruformatContext *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->isWriting)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_comments() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadataBlockHeader.identifier != MetadataBlock) ctx->metadataBlockHeader.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->imageInfo.Comments != NULL) free(ctx->imageInfo.Comments);
ctx->imageInfo.Comments = copy;
ctx->metadataBlockHeader.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;
}
aaruformatContext *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->isWriting)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_media_title() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadataBlockHeader.identifier != MetadataBlock) ctx->metadataBlockHeader.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->imageInfo.MediaTitle != NULL) free(ctx->imageInfo.MediaTitle);
ctx->imageInfo.MediaTitle = copy;
ctx->metadataBlockHeader.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;
}
aaruformatContext *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->isWriting)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_media_manufacturer() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadataBlockHeader.identifier != MetadataBlock) ctx->metadataBlockHeader.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->imageInfo.MediaManufacturer != NULL) free(ctx->imageInfo.MediaManufacturer);
ctx->imageInfo.MediaManufacturer = copy;
ctx->metadataBlockHeader.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;
}
aaruformatContext *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->isWriting)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_media_model() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadataBlockHeader.identifier != MetadataBlock) ctx->metadataBlockHeader.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->imageInfo.MediaModel != NULL) free(ctx->imageInfo.MediaModel);
ctx->imageInfo.MediaModel = copy;
ctx->metadataBlockHeader.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;
}
aaruformatContext *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->isWriting)
{
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->metadataBlockHeader.identifier != MetadataBlock) ctx->metadataBlockHeader.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->imageInfo.MediaSerialNumber != NULL) free(ctx->imageInfo.MediaSerialNumber);
ctx->imageInfo.MediaSerialNumber = copy;
ctx->metadataBlockHeader.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;
}
aaruformatContext *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->isWriting)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_media_barcode() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadataBlockHeader.identifier != MetadataBlock) ctx->metadataBlockHeader.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->imageInfo.MediaBarcode != NULL) free(ctx->imageInfo.MediaBarcode);
ctx->imageInfo.MediaBarcode = copy;
ctx->metadataBlockHeader.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;
}
aaruformatContext *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->isWriting)
{
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->metadataBlockHeader.identifier != MetadataBlock) ctx->metadataBlockHeader.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->imageInfo.MediaPartNumber != NULL) free(ctx->imageInfo.MediaPartNumber);
ctx->imageInfo.MediaPartNumber = copy;
ctx->metadataBlockHeader.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;
}
aaruformatContext *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->isWriting)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_drive_manufacturer() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadataBlockHeader.identifier != MetadataBlock) ctx->metadataBlockHeader.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->imageInfo.DriveManufacturer != NULL) free(ctx->imageInfo.DriveManufacturer);
ctx->imageInfo.DriveManufacturer = copy;
ctx->metadataBlockHeader.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;
}
aaruformatContext *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->isWriting)
{
FATAL("Trying to write a read-only image");
TRACE("Exiting aaruf_set_drive_model() = AARUF_READ_ONLY");
return AARUF_READ_ONLY;
}
// Initialize
if(ctx->metadataBlockHeader.identifier != MetadataBlock) ctx->metadataBlockHeader.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->imageInfo.DriveModel != NULL) free(ctx->imageInfo.DriveModel);
ctx->imageInfo.DriveModel = copy;
ctx->metadataBlockHeader.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;
}
aaruformatContext *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->isWriting)
{
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->metadataBlockHeader.identifier != MetadataBlock) ctx->metadataBlockHeader.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->imageInfo.DriveSerialNumber != NULL) free(ctx->imageInfo.DriveSerialNumber);
ctx->imageInfo.DriveSerialNumber = copy;
ctx->metadataBlockHeader.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;
}
aaruformatContext *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->isWriting)
{
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->metadataBlockHeader.identifier != MetadataBlock) ctx->metadataBlockHeader.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->imageInfo.DriveFirmwareRevision != NULL) free(ctx->imageInfo.DriveFirmwareRevision);
ctx->imageInfo.DriveFirmwareRevision = copy;
ctx->metadataBlockHeader.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 (-12) 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, %d)", 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 aaruformatContext *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->cicmBlock == NULL || ctx->cicmBlockHeader.length == 0 || ctx->cicmBlockHeader.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->cicmBlockHeader.length)
{
TRACE("Buffer too small for CICM XML metadata, required %u bytes", ctx->cicmBlockHeader.length);
*length = ctx->cicmBlockHeader.length;
TRACE("Exiting aaruf_get_cicm_metadata() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
*length = ctx->cicmBlockHeader.length;
memcpy(buffer, ctx->cicmBlock, ctx->cicmBlockHeader.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 (-12) 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, %d)", 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 aaruformatContext *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->jsonBlock == NULL || ctx->jsonBlockHeader.length == 0 ||
ctx->jsonBlockHeader.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->jsonBlockHeader.length)
{
TRACE("Buffer too small for Aaru metadata JSON, required %u bytes", ctx->jsonBlockHeader.length);
*length = ctx->jsonBlockHeader.length;
TRACE("Exiting aaruf_get_aaru_json_metadata() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
*length = ctx->jsonBlockHeader.length;
memcpy(buffer, ctx->jsonBlock, ctx->jsonBlockHeader.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;
}
aaruformatContext *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->isWriting)
{
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->jsonBlock != NULL) free(ctx->jsonBlock);
ctx->jsonBlock = copy;
ctx->jsonBlockHeader.identifier = AaruMetadataJsonBlock;
ctx->jsonBlockHeader.length = length;
TRACE("Exiting aaruf_set_aaru_json_metadata(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}