Add metadata retrieval functions for media and drive attributes

This commit is contained in:
2025-10-08 12:23:46 +01:00
parent cd12ef3504
commit 49d827d07f
3 changed files with 935 additions and 3 deletions

View File

@@ -160,6 +160,19 @@ AARU_EXPORT int32_t AARU_CALL aaruf_set_drive_manufacturer(void *context, const
AARU_EXPORT int32_t AARU_CALL aaruf_set_drive_model(void *context, const uint8_t *data, int32_t length);
AARU_EXPORT int32_t AARU_CALL aaruf_set_drive_serial_number(void *context, const uint8_t *data, int32_t length);
AARU_EXPORT int32_t AARU_CALL aaruf_set_drive_firmware_revision(void *context, const uint8_t *data, int32_t length);
AARU_EXPORT int32_t AARU_CALL aaruf_get_media_sequence(const void *context, int32_t *sequence, int32_t *last_sequence);
AARU_EXPORT int32_t AARU_CALL aaruf_get_creator(const void *context, uint8_t *buffer, int32_t *length);
AARU_EXPORT int32_t AARU_CALL aaruf_get_comments(const void *context, uint8_t *buffer, int32_t *length);
AARU_EXPORT int32_t AARU_CALL aaruf_get_media_title(const void *context, uint8_t *buffer, int32_t *length);
AARU_EXPORT int32_t AARU_CALL aaruf_get_media_manufacturer(const void *context, uint8_t *buffer, int32_t *length);
AARU_EXPORT int32_t AARU_CALL aaruf_get_media_model(const void *context, uint8_t *buffer, int32_t *length);
AARU_EXPORT int32_t AARU_CALL aaruf_get_media_serial_number(const void *context, uint8_t *buffer, int32_t *length);
AARU_EXPORT int32_t AARU_CALL aaruf_get_media_barcode(const void *context, uint8_t *buffer, int32_t *length);
AARU_EXPORT int32_t AARU_CALL aaruf_get_media_part_number(const void *context, uint8_t *buffer, int32_t *length);
AARU_EXPORT int32_t AARU_CALL aaruf_get_drive_manufacturer(const void *context, uint8_t *buffer, int32_t *length);
AARU_EXPORT int32_t AARU_CALL aaruf_get_drive_model(const void *context, uint8_t *buffer, int32_t *length);
AARU_EXPORT int32_t AARU_CALL aaruf_get_drive_serial_number(const void *context, uint8_t *buffer, int32_t *length);
AARU_EXPORT int32_t AARU_CALL aaruf_get_drive_firmware_revision(const void *context, uint8_t *buffer, int32_t *length);
AARU_EXPORT int32_t AARU_CALL aaruf_get_cicm_metadata(const void *context, uint8_t *buffer, size_t *length);
AARU_EXPORT int32_t AARU_CALL aaruf_get_aaru_json_metadata(const void *context, uint8_t *buffer, size_t *length);
AARU_EXPORT int32_t AARU_CALL aaruf_set_aaru_json_metadata(void *context, uint8_t *data, size_t length);

View File

@@ -66,6 +66,7 @@
#define AARUF_ERROR_INVALID_TAG (-27) ///< Invalid or unsupported media or sector tag format.
#define AARUF_ERROR_TAPE_FILE_NOT_FOUND (-28) ///< Requested tape file number not present in image.
#define AARUF_ERROR_TAPE_PARTITION_NOT_FOUND (-29) ///< Requested tape partition not present in image.
#define AARUF_ERROR_METADATA_NOT_PRESENT (-30) ///< Requested metadata not present in image.
/** @} */
/** \name Non-fatal sector status codes (non-negative)

View File

@@ -16,6 +16,7 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stddef.h>
#include <stdint.h>
#include "aaruformat.h"
@@ -1892,7 +1893,7 @@ int32_t aaruf_set_drive_firmware_revision(void *context, const uint8_t *data, co
* - 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:
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer is insufficient. This occurs when:
* - The input *length is less than ctx->cicmBlockHeader.length
* - The *length parameter is updated to contain the required buffer size
* - No data is copied to the buffer
@@ -2039,7 +2040,7 @@ int32_t aaruf_get_cicm_metadata(const void *context, uint8_t *buffer, size_t *le
* - 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:
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer is insufficient. This occurs when:
* - The input *length is less than ctx->jsonBlockHeader.length
* - The *length parameter is updated to contain the required buffer size
* - No data is copied to the buffer
@@ -2300,8 +2301,925 @@ int32_t aaruf_set_aaru_json_metadata(void *context, uint8_t *data, size_t length
if(ctx->jsonBlock != NULL) free(ctx->jsonBlock);
ctx->jsonBlock = copy;
ctx->jsonBlockHeader.identifier = AaruMetadataJsonBlock;
ctx->jsonBlockHeader.length = length;
ctx->jsonBlockHeader.length = (uint32_t)length;
TRACE("Exiting aaruf_set_aaru_json_metadata(%p, %p, %d) = AARUF_STATUS_OK", context, data, length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the media sequence metadata for multi-volume image sets.
*
* Reads the media sequence fields stored in the MetadataBlock header and returns the current media
* number together with the final media number for the complete set. This information indicates the
* position of the imaged medium within a multi-volume collection (for example, "disc 2 of 5"). The
* function operates entirely on in-memory structures populated during aaruf_open(); no additional
* disk I/O is performed.
*
* @param context Pointer to an initialized aaruformat context opened for reading or writing.
* @param sequence Pointer that receives the current media sequence number (typically 1-based).
* @param last_sequence Pointer that receives the total number of media in the set.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Metadata was present and the output parameters were populated.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The provided context pointer is NULL or not an
* aaruformat context (magic mismatch).
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) The MetadataBlock was not present in the image,
* making sequence data unavailable.
*
* @note For standalone media, both sequence and last_sequence are commonly set to 1. Some creators
* may also set them to 0 to indicate the absence of sequence semantics; callers should handle
* either pattern gracefully.
*
* @note The function does not validate logical consistency (e.g., whether sequence <= last_sequence);
* it simply returns the values stored in the image header.
*/
int32_t aaruf_get_media_sequence(const void *context, int32_t *sequence, int32_t *last_sequence)
{
TRACE("Entering aaruf_get_media_sequence(%p, %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;
}
const 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;
}
if(ctx->metadataBlockHeader.identifier != MetadataBlock)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_set_media_sequence() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
*sequence = ctx->metadataBlockHeader.mediaSequence;
*last_sequence = ctx->metadataBlockHeader.lastMediaSequence;
TRACE("Exiting aaruf_set_media_sequence(%p, %d, %d) = AARUF_STATUS_OK", context, *sequence, *last_sequence);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the recorded creator (operator) name from the MetadataBlock.
*
* Copies the UTF-16LE encoded creator string that identifies the person or operator who created the
* image. The function supports the common two-call pattern: the caller first determines the required
* buffer size by passing a buffer that may be NULL or too small, then allocates sufficient memory and
* calls again to obtain the actual data. On success the buffer contains an opaque UTF-16LE string of
* length *length bytes (not null-terminated).
*
* @param context Pointer to a valid aaruformat context opened for reading or writing.
* @param buffer Pointer to the destination buffer that will receive the creator string. May be NULL
* to query the required size.
* @param length Pointer to an int32_t that on input specifies the size of @p buffer in bytes and on
* output receives the actual length of the creator metadata.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) The creator string was copied successfully.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context is NULL or not an aaruformat context.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) Creator metadata has not been recorded in the image.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer was insufficient; *length contains
* the required size and no data was copied.
*
* @note The returned data is UTF-16LE encoded and may contain embedded null characters. Callers
* should treat it as an opaque byte array unless they explicitly handle UTF-16LE strings.
*
* @note The function does not allocate memory. Callers are responsible for ensuring @p buffer is
* large enough before requesting the data.
*/
int32_t aaruf_get_creator(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_creator(%p, %p, %d)", context, buffer, *length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_creator() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformatContext *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_creator() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadataBlockHeader.identifier != MetadataBlock || ctx->imageInfo.Creator == NULL ||
ctx->metadataBlockHeader.creatorLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_creator() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadataBlockHeader.creatorLength)
{
*length = ctx->metadataBlockHeader.creatorLength;
TRACE("Exiting aaruf_get_creator() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->imageInfo.Creator, ctx->metadataBlockHeader.creatorLength);
*length = ctx->metadataBlockHeader.creatorLength;
TRACE("Exiting aaruf_get_creator(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the user comments or notes stored in the MetadataBlock.
*
* Provides access to the UTF-16LE encoded comments associated with the image. Comments are often
* used for provenance notes, imaging details, or curator remarks. The function follows the same
* two-call buffer sizing pattern used by other metadata retrieval APIs: the caller may probe the
* required size before allocating memory.
*
* @param context Pointer to a valid aaruformat context opened with aaruf_open() or aaruf_create().
* @param buffer Destination buffer that receives the comments data. May be NULL when probing size.
* @param length Pointer to an int32_t. On input it contains the size of @p buffer in bytes; on output
* it is updated with the actual comments length.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Comments were available and copied successfully.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid or not a libaaruformat context.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No comments metadata exists in the image.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The supplied buffer was too small. *length is updated with
* the required size and no data is copied.
*
* @note Comments are stored exactly as provided during image creation and may include multi-line text
* or other control characters. No validation or normalization is applied by the library.
*/
int32_t aaruf_get_comments(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_comments(%p, %p, %d)", context, buffer, *length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_comments() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformatContext *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_comments() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadataBlockHeader.identifier != MetadataBlock || ctx->imageInfo.Comments == NULL ||
ctx->metadataBlockHeader.commentsLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_comments() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadataBlockHeader.commentsLength)
{
*length = ctx->metadataBlockHeader.commentsLength;
TRACE("Exiting aaruf_get_comments() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->imageInfo.Comments, ctx->metadataBlockHeader.commentsLength);
*length = ctx->metadataBlockHeader.commentsLength;
TRACE("Exiting aaruf_get_comments(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the media title or label captured during image creation.
*
* Returns the UTF-16LE encoded media title string, representing markings or labels present on the
* original physical media. This function allows applications to present or archive the media title
* alongside the image, preserving contextual information from the physical artifact.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Destination buffer for the UTF-16LE title string. May be NULL when querying size.
* @param length Pointer to an int32_t that on input holds the buffer capacity in bytes and on output
* receives the actual title length.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) The media title was available and copied to @p buffer.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No media title metadata exists.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The supplied buffer was insufficient.
*
* @note Titles may contain international characters, control codes, or mixed casing. The library does
* not attempt to sanitize or interpret the string.
*/
int32_t aaruf_get_media_title(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_media_title(%p, %p, %d)", context, buffer, *length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_title() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformatContext *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_title() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadataBlockHeader.identifier != MetadataBlock || ctx->imageInfo.MediaTitle == NULL ||
ctx->metadataBlockHeader.mediaTitleLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_media_title() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadataBlockHeader.mediaTitleLength)
{
*length = ctx->metadataBlockHeader.mediaTitleLength;
TRACE("Exiting aaruf_get_media_title() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->imageInfo.MediaTitle, ctx->metadataBlockHeader.mediaTitleLength);
*length = ctx->metadataBlockHeader.mediaTitleLength;
TRACE("Exiting aaruf_get_media_title(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the recorded media manufacturer name.
*
* Provides access to the UTF-16LE encoded manufacturer metadata that identifies the company which
* produced the physical medium. This information is taken from the MetadataBlock and mirrors the
* value previously stored via aaruf_set_media_manufacturer().
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Buffer that receives the manufacturer string. May be NULL when probing size.
* @param length Pointer to an int32_t specifying the buffer size on input and receiving the actual
* manufacturer string length on output.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Manufacturer metadata was available and copied.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) The image lacks manufacturer metadata.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer was too small; *length indicates size.
*
* @note Values may include trailing spaces or vendor-specific capitalization. Treat the returned data
* as authoritative and avoid trimming unless required by the consuming application.
*/
int32_t aaruf_get_media_manufacturer(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_media_manufacturer(%p, %p, %d)", context, buffer, *length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_manufacturer() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformatContext *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_manufacturer() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadataBlockHeader.identifier != MetadataBlock || ctx->imageInfo.MediaManufacturer == NULL ||
ctx->metadataBlockHeader.mediaManufacturerLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_media_manufacturer() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadataBlockHeader.mediaManufacturerLength)
{
*length = ctx->metadataBlockHeader.mediaManufacturerLength;
TRACE("Exiting aaruf_get_media_manufacturer() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->imageInfo.MediaManufacturer, ctx->metadataBlockHeader.mediaManufacturerLength);
*length = ctx->metadataBlockHeader.mediaManufacturerLength;
TRACE("Exiting aaruf_get_media_manufacturer(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the media model or product designation metadata.
*
* Returns the UTF-16LE encoded model name that specifies the exact product variant of the physical
* medium. The function mirrors the set counterpart and is useful for accurately documenting media
* specifications during preservation workflows.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Destination buffer for the model string; may be NULL when querying required size.
* @param length Pointer to an int32_t that on input contains the buffer capacity in bytes and on
* output is updated with the actual metadata length.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Model metadata was successfully copied.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No media model metadata is present in the image.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The caller-provided buffer is too small.
*
* @note Model strings often contain performance ratings (e.g., "16x", "LTO-7"). The data is opaque and
* should be handled without modification unless necessary.
*/
int32_t aaruf_get_media_model(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_media_model(%p, %p, %d)", context, buffer, *length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_model() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformatContext *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_model() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadataBlockHeader.identifier != MetadataBlock || ctx->imageInfo.MediaModel == NULL ||
ctx->metadataBlockHeader.mediaModelLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_media_model() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadataBlockHeader.mediaModelLength)
{
*length = ctx->metadataBlockHeader.mediaModelLength;
TRACE("Exiting aaruf_get_media_model() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->imageInfo.MediaModel, ctx->metadataBlockHeader.mediaModelLength);
*length = ctx->metadataBlockHeader.mediaModelLength;
TRACE("Exiting aaruf_get_media_model(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the media serial number recorded in the image metadata.
*
* Copies the UTF-16LE encoded serial number identifying the specific physical medium. Serial numbers
* are particularly important for forensic tracking and archival provenance, enabling correlation
* between the physical item and its digital representation.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Destination buffer for the serial number. May be NULL to determine required size.
* @param length Pointer to an int32_t that on input holds the buffer size and on output receives the
* actual serial number length.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Serial number metadata was copied into @p buffer.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No serial number metadata was stored in the image.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer was too small.
*
* @note Serial numbers may contain spaces, hyphens, or alphanumeric characters. The library does not
* normalize or validate these strings.
*/
int32_t aaruf_get_media_serial_number(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_media_serial_number(%p, %p, %d)", context, buffer, *length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_serial_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformatContext *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_serial_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadataBlockHeader.identifier != MetadataBlock || ctx->imageInfo.MediaSerialNumber == NULL ||
ctx->metadataBlockHeader.mediaSerialNumberLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_media_serial_number() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadataBlockHeader.mediaSerialNumberLength)
{
*length = ctx->metadataBlockHeader.mediaSerialNumberLength;
TRACE("Exiting aaruf_get_media_serial_number() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->imageInfo.MediaSerialNumber, ctx->metadataBlockHeader.mediaSerialNumberLength);
*length = ctx->metadataBlockHeader.mediaSerialNumberLength;
TRACE("Exiting aaruf_get_media_serial_number(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the barcode assigned to the physical media or its packaging.
*
* Returns the UTF-16LE encoded barcode string that was captured when the image was created. Barcodes
* are commonly used in institutional workflows for inventory tracking and automated retrieval.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Buffer that receives the barcode string; may be NULL when probing size requirements.
* @param length Pointer to an int32_t specifying the buffer size on input and receiving the actual
* barcode length on output.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Barcode metadata was present and copied successfully.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No barcode metadata exists in the image.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The supplied buffer was too small.
*
* @note Barcode values can be strict alphanumeric codes (e.g., LTO cartridge IDs) or full strings from
* custom labeling systems. Preserve the returned string exactly for catalog interoperability.
*/
int32_t aaruf_get_media_barcode(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_media_barcode(%p, %p, %d)", context, buffer, *length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_barcode() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformatContext *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_barcode() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadataBlockHeader.identifier != MetadataBlock || ctx->imageInfo.MediaBarcode == NULL ||
ctx->metadataBlockHeader.mediaBarcodeLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_media_barcode() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadataBlockHeader.mediaBarcodeLength)
{
*length = ctx->metadataBlockHeader.mediaBarcodeLength;
TRACE("Exiting aaruf_get_media_barcode() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->imageInfo.MediaBarcode, ctx->metadataBlockHeader.mediaBarcodeLength);
*length = ctx->metadataBlockHeader.mediaBarcodeLength;
TRACE("Exiting aaruf_get_media_barcode(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the media part number recorded in the MetadataBlock.
*
* Provides access to the UTF-16LE encoded part number identifying the precise catalog or ordering
* code for the physical medium. Part numbers help archivists procure exact replacements and document
* specific media variants used during acquisition.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Destination buffer for the part number string. May be NULL while querying size.
* @param length Pointer to an int32_t that supplies the buffer size on input and is updated with the
* actual part number length on output.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Part number metadata was returned successfully.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No part number metadata exists.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer was insufficient; *length contains the
* required size.
*
* @note Part numbers may include manufacturer-specific formatting such as hyphens or suffix letters.
* The library stores and returns the data verbatim.
*/
int32_t aaruf_get_media_part_number(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_media_part_number(%p, %p, %d)", context, buffer, *length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_part_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformatContext *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_media_part_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadataBlockHeader.identifier != MetadataBlock || ctx->imageInfo.MediaPartNumber == NULL ||
ctx->metadataBlockHeader.mediaPartNumberLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_media_part_number() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadataBlockHeader.mediaPartNumberLength)
{
*length = ctx->metadataBlockHeader.mediaPartNumberLength;
TRACE("Exiting aaruf_get_media_part_number() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->imageInfo.MediaPartNumber, ctx->metadataBlockHeader.mediaPartNumberLength);
*length = ctx->metadataBlockHeader.mediaPartNumberLength;
TRACE("Exiting aaruf_get_media_part_number(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the drive manufacturer metadata captured during imaging.
*
* Copies the UTF-16LE encoded manufacturer name of the device used to read or write the medium. This
* information documents the hardware involved in the imaging process, which is crucial for forensic
* reporting and reproducibility studies.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Destination buffer for the manufacturer string. May be NULL when querying required
* length.
* @param length Pointer to an int32_t specifying the buffer size on input and receiving the actual
* metadata length on output.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Drive manufacturer metadata was copied successfully.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) The image lacks drive manufacturer metadata.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer is too small; *length holds the
* required size for a subsequent call.
*
* @note The returned manufacturer string corresponds to the value recorded by aaruf_set_drive_manufacturer()
* and may include branding or OEM designations.
*/
int32_t aaruf_get_drive_manufacturer(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_drive_manufacturer(%p, %p, %d)", context, buffer, *length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_manufacturer() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformatContext *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_manufacturer() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadataBlockHeader.identifier != MetadataBlock || ctx->imageInfo.DriveManufacturer == NULL ||
ctx->metadataBlockHeader.driveManufacturerLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_drive_manufacturer() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadataBlockHeader.driveManufacturerLength)
{
*length = ctx->metadataBlockHeader.driveManufacturerLength;
TRACE("Exiting aaruf_get_drive_manufacturer() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->imageInfo.DriveManufacturer, ctx->metadataBlockHeader.driveManufacturerLength);
*length = ctx->metadataBlockHeader.driveManufacturerLength;
TRACE("Exiting aaruf_get_drive_manufacturer(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the device model information for the imaging drive.
*
* Returns the UTF-16LE encoded model identifier for the drive used during acquisition. The model
* metadata provides finer granularity than the manufacturer name, enabling detailed documentation of
* imaging hardware capabilities and behavior.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Buffer that receives the model string; may be NULL while probing required capacity.
* @param length Pointer to an int32_t indicating buffer size on input and receiving the metadata length
* on output.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Drive model metadata was available and copied.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No drive model metadata exists in the image.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The supplied buffer was insufficient; *length is updated.
*
* @note Model strings can include firmware suffixes, interface hints, or OEM variations. Consume the
* data verbatim to maintain accurate provenance records.
*/
int32_t aaruf_get_drive_model(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_drive_model(%p, %p, %d)", context, buffer, *length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_model() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformatContext *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_model() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadataBlockHeader.identifier != MetadataBlock || ctx->imageInfo.DriveModel == NULL ||
ctx->metadataBlockHeader.driveModelLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_drive_model() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadataBlockHeader.driveModelLength)
{
*length = ctx->metadataBlockHeader.driveModelLength;
TRACE("Exiting aaruf_get_drive_model() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->imageInfo.DriveModel, ctx->metadataBlockHeader.driveModelLength);
*length = ctx->metadataBlockHeader.driveModelLength;
TRACE("Exiting aaruf_get_drive_model(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the imaging drive's serial number metadata.
*
* Copies the UTF-16LE encoded serial number reported for the drive used during the imaging session.
* This metadata enables correlation between images and specific hardware units for forensic chain of
* custody or quality assurance workflows.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Destination buffer for the serial number; may be NULL when querying size.
* @param length Pointer to an int32_t carrying the buffer size on input and receiving the actual
* serial number length on output.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Drive serial number metadata was copied to @p buffer.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No drive serial number metadata is available.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The provided buffer was insufficient.
*
* @note Serial numbers are stored exactly as returned by the imaging hardware and may include leading
* zeros or spacing that should be preserved.
*/
int32_t aaruf_get_drive_serial_number(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_drive_serial_number(%p, %p, %d)", context, buffer, *length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_serial_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformatContext *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_serial_number() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadataBlockHeader.identifier != MetadataBlock || ctx->imageInfo.DriveSerialNumber == NULL ||
ctx->metadataBlockHeader.driveSerialNumberLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_drive_serial_number() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadataBlockHeader.driveSerialNumberLength)
{
*length = ctx->metadataBlockHeader.driveSerialNumberLength;
TRACE("Exiting aaruf_get_drive_serial_number() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->imageInfo.DriveSerialNumber, ctx->metadataBlockHeader.driveSerialNumberLength);
*length = ctx->metadataBlockHeader.driveSerialNumberLength;
TRACE("Exiting aaruf_get_drive_serial_number(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}
/**
* @brief Retrieves the firmware revision metadata for the imaging drive.
*
* Returns the UTF-16LE encoded firmware revision string that was captured when the image was created.
* Firmware information is critical for reproducing imaging environments and diagnosing drive-specific
* behavior or bugs.
*
* @param context Pointer to a valid aaruformat context.
* @param buffer Destination buffer for the firmware revision string. May be NULL when probing size.
* @param length Pointer to an int32_t that specifies the buffer capacity in bytes on input and is
* updated with the actual metadata length on output.
*
* @return Returns one of the following status codes:
* @retval AARUF_STATUS_OK (0) Firmware revision metadata was present and copied successfully.
* @retval AARUF_ERROR_NOT_AARUFORMAT (-1) The context pointer is invalid.
* @retval AARUF_ERROR_METADATA_NOT_PRESENT (-30) No firmware metadata exists in the image.
* @retval AARUF_ERROR_BUFFER_TOO_SMALL (-10) The supplied buffer was too small; *length is updated.
*
* @note Firmware revision formats vary between manufacturers (e.g., numeric, alphanumeric, dot-separated).
* The library stores the data verbatim without attempting normalization.
*/
int32_t aaruf_get_drive_firmware_revision(const void *context, uint8_t *buffer, int32_t *length)
{
TRACE("Entering aaruf_get_drive_firmware_revision(%p, %p, %d)", context, buffer, *length);
// Check context is correct AaruFormat context
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_firmware_revision() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
const aaruformatContext *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_get_drive_firmware_revision() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->metadataBlockHeader.identifier != MetadataBlock || ctx->imageInfo.DriveFirmwareRevision == NULL ||
ctx->metadataBlockHeader.driveFirmwareRevisionLength == 0)
{
FATAL("No metadata block present");
TRACE("Exiting aaruf_get_drive_firmware_revision() = AARUF_ERROR_METADATA_NOT_PRESENT");
return AARUF_ERROR_METADATA_NOT_PRESENT;
}
if(buffer == NULL || *length < ctx->metadataBlockHeader.driveFirmwareRevisionLength)
{
*length = ctx->metadataBlockHeader.driveFirmwareRevisionLength;
TRACE("Exiting aaruf_get_drive_firmware_revision() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Copy opaque UTF-16LE string
memcpy(buffer, ctx->imageInfo.DriveFirmwareRevision, ctx->metadataBlockHeader.driveFirmwareRevisionLength);
*length = ctx->metadataBlockHeader.driveFirmwareRevisionLength;
TRACE("Exiting aaruf_get_drive_firmware_revision(%p, %p, %d) = AARUF_STATUS_OK", context, buffer, *length);
return AARUF_STATUS_OK;
}