Loading...
Searching...
No Matches
write.c File Reference
`#include <errno.h>`
`#include <limits.h>`
`#include <stdbool.h>`
`#include <stdint.h>`
`#include <stdio.h>`
`#include <stdlib.h>`
`#include <string.h>`
`#include "aaruformat.h"`
`#include "internal.h"`
`#include "log.h"`
`#include "structs/lisa_tag.h"`
`#include "xxhash.h"`

Go to the source code of this file.

## Functions

int32_t | aaruf_write_sector (void *context, uint64_t sector_address, bool negative, const uint8_t *data, uint8_t sector_status, uint32_t length)
| Writes a sector to the AaruFormat image.
int32_t | aaruf_write_sector_long (void *context, uint64_t sector_address, bool negative, const uint8_t *data, uint8_t sector_status, uint32_t length)
| Writes a full ("long") raw sector from optical or block media, parsing structure and validating content.
int32_t | aaruf_close_current_block (aaruformat_context *ctx)
| Finalizes and writes the current data block to the AaruFormat image file.
int32_t | aaruf_write_media_tag (void *context, const uint8_t *data, const int32_t type, const uint32_t length)
| Writes a media tag to the AaruFormat image, storing medium-specific metadata and descriptors.
int32_t | aaruf_write_sector_tag (void *context, const uint64_t sector_address, const bool negative, const uint8_t *data, const size_t length, const int32_t tag)
| Writes per-sector tag data (auxiliary metadata) for a specific sector.

## Function Documentation

## aaruf_close_current_block()

int32_t aaruf_close_current_block | ( | aaruformat_context * | ctx | ) |

Finalizes and writes the current data block to the AaruFormat image file.

This function completes the current writing block by computing checksums, optionally compressing the buffered sector data, writing the block header and data to the image file, updating the index, and cleaning up resources. It is called automatically when a block is full (reaches maximum size determined by dataShift), when sector size changes, or when image finalization begins. The function supports multiple compression algorithms (FLAC for audio, LZMA for data) with automatic fallback to uncompressed storage if compression is ineffective.

Block Finalization Sequence:

1. Context Validation: Verify context is valid and opened for writing
2. Length Calculation: Set block length = currentBlockOffset × sectorSize
3. CRC64 Computation: Calculate checksum of uncompressed block data
4. Compression Processing (if enabled):
   - FLAC: For audio tracks, compress using Red Book audio encoding with configurable block size
   - LZMA: For data tracks, compress using LZMA algorithm with dictionary size optimization
   - Fallback: If compressed size ≥ uncompressed size, use uncompressed storage
5. Compressed CRC64: Calculate checksum of compressed data (if compression was applied)
6. Index Registration: Add IndexEntry to ctx->indexEntries for block lookup
7. File Writing: Write BlockHeader, optional LZMA properties, and block data to image stream
8. Position Update: Calculate next block position with alignment boundary adjustment
9. Resource Cleanup: Free buffers, reset counters, clear block header

Compression Handling:

- None (CompressionType = 0): No compression applied
  - cmpLength = length (uncompressed size)
  - cmpCrc64 = crc64 (same checksum)
  - Direct write of ctx->writingBuffer to file
- FLAC (CompressionType = 2): For CD audio tracks (Red Book format)
  - Allocates 2× length buffer for compressed data
  - Calculates optimal FLAC block size (MIN_FLAKE_BLOCK to MAX_FLAKE_BLOCK range)
  - Pads incomplete blocks with zeros to meet FLAC block size requirements
  - Encoding parameters: mid-side stereo, Hamming apodization, 12 max LPC order
  - Falls back to None if compression ineffective (compressed ≥ uncompressed)
- LZMA (CompressionType = 1): For data tracks and non-audio content
  - Allocates 2× length buffer for compressed data
  - LZMA properties: level 9, dictionary size from ctx->lzma_dict_size
  - Properties stored as 5-byte header: lc=4, lp=0, pb=2, fb=273, threads=8
  - Falls back to None if compression ineffective (compressed ≥ uncompressed)
  - Compressed length includes LZMA_PROPERTIES_LENGTH (5 bytes) overhead

Index Entry Creation:

Each closed block is registered in the index with:

- blockType = DataBlock (0x4B4C4244)
- dataType = UserData (1)
- offset = ctx->nextBlockPosition (file position where block was written)

This enables efficient block lookup during image reading via binary search on index entries.

File Layout:

Written to ctx->imageStream at ctx->nextBlockPosition:

1. BlockHeader (sizeof(BlockHeader) bytes)
2. LZMA properties (5 bytes, only if compression = Lzma)
3. Block data (cmpLength bytes - compressed or uncompressed depending on compression type)

Next Block Position Calculation:

After writing, nextBlockPosition is updated to the next aligned boundary:

- block_total_size = sizeof(BlockHeader) + cmpLength
- alignment_mask = (1 << blockAlignmentShift) - 1
- nextBlockPosition = (currentPosition + block_total_size + alignment_mask) & ~alignment_mask

This ensures all blocks begin on properly aligned file offsets for efficient I/O.

Resource Cleanup:

Before returning, the function:

- Frees ctx->writingBuffer and sets pointer to NULL
- Resets ctx->currentBlockOffset to 0
- Clears ctx->currentBlockHeader (memset to 0)
- Frees ctx->crc64Context
- Resets ctx->writingBufferPosition to 0

This prepares the context for the next block or signals that no block is currently open.

Parameters

  ctx | Pointer to an initialized aaruformatContext in write mode.

Returns
  Returns one of the following status codes:

Return values

  AARUF_STATUS_OK

  (0) Successfully finalized and wrote the block. This is returned when:
  - The context is valid and properly initialized
  - CRC64 computation completed successfully
  - Compression (if applicable) succeeded or fell back appropriately
  - Block header was successfully written to the image file
  - Block data (compressed or uncompressed) was successfully written
  - LZMA properties (if applicable) were successfully written
  - Index entry was added to ctx->indexEntries
  - Next block position was calculated and updated
  - All resources were freed and context reset for next block

  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)

  AARUF_READ_ONLY

  (-22) Attempting to finalize block on read-only image. This occurs when:
  - The context's isWriting flag is false
  - The image was opened in read-only mode with aaruf_open()

  AARUF_ERROR_NOT_ENOUGH_MEMORY

  (-9) Memory allocation failed. This occurs when:
  - Cannot allocate compression buffer (2× block length) for FLAC compression
  - Cannot allocate compression buffer (2× block length) for LZMA compression
  - System is out of memory or memory is severely fragmented

  AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER

  (-23) Failed to write block header. This occurs when:
  - fwrite() for BlockHeader returns != 1 (incomplete write or I/O error)
  - Disk space is insufficient for header
  - File system errors or permissions prevent writing
  - Media errors on the destination storage device

  AARUF_ERROR_CANNOT_WRITE_BLOCK_DATA

  (-24) Failed to write block data. This occurs when:
  - fwrite() for LZMA properties returns != 1 (when compression = Lzma)
  - fwrite() for uncompressed data returns != 1 (when compression = None)
  - fwrite() for compressed data returns != 1 (when compression = Flac/Lzma)
  - Disk space is insufficient for block data
  - File system errors or permissions prevent writing
  - Invalid compression type (not None, Flac, or Lzma)

Note
  Compression Algorithm Selection:
  - Compression type is determined when block is created in aaruf_write_sector()
  - Audio tracks (TrackType = Audio) use FLAC compression if enabled
  - Data tracks use LZMA compression if enabled
  - Special cases (JaguarCD data in audio, VideoNow) force LZMA even for audio tracks
  - Compression can be disabled entirely via ctx->compression_enabled flag
  Compression Fallback Logic:
  - If compressed size ≥ uncompressed size, compression is abandoned
  - Compression buffer is freed and compression type set to None
  - This prevents storage expansion from ineffective compression
  - Fallback is transparent to caller; function still returns success
  FLAC Encoding Parameters:
  - Encoding for Red Book audio (44.1kHz, 16-bit stereo)
  - Block size: auto-selected between MIN_FLAKE_BLOCK and MAX_FLAKE_BLOCK samples
  - Mid-side stereo enabled for better compression on correlated channels
  - Hamming window apodization for LPC analysis
  - Max LPC order: 12, QLP coefficient precision: 15 bits
  - Application ID: "Aaru" with 4-byte signature
  LZMA Encoding Parameters:
  - Compression level: 9 (maximum compression)
  - Dictionary size: from ctx->lzma_dict_size (configurable per context)
  - Literal context bits (lc): 4
  - Literal position bits (lp): 0
  - Position bits (pb): 2
  - Fast bytes (fb): 273
  - Threads: 8 (for multi-threaded compression)
  Index Management:
  - Every closed block gets an index entry for efficient lookup
  - Index entries are stored in ctx->indexEntries (dynamic array)
  - Final index is serialized during aaruf_close() for image finalization
  - Index enables O(log n) block lookup during image reading
  Alignment Requirements:
  - Blocks must start on aligned boundaries per blockAlignmentShift
  - Typical alignment: 512 bytes (shift=9) or 4096 bytes (shift=12)
  - Alignment ensures efficient sector-aligned I/O on modern storage
  - Gap between blocks is implicit; no padding data is written

Warning
  This function assumes ctx->writingBuffer contains valid data for ctx->currentBlockOffset sectors of ctx->currentBlockHeader.sectorSize bytes each.
  Do not call this function when no block is open (ctx->writingBuffer == NULL). This will result in undefined behavior or segmentation fault.
  The function modifies ctx->nextBlockPosition, which affects where subsequent blocks are written. Ensure file positioning is properly managed.
  Memory allocated for compression buffers is freed before returning. Do not retain pointers to compressed data after function completion.
  CRC64 context (ctx->crc64Context) is freed during cleanup. Do not access this pointer after calling this function.

Definition at line 1438 of file write.c.

References AARU_MAGIC, aaruf_crc64_data(), aaruf_crc64_final(), aaruf_crc64_free(), aaruf_crc64_init(), aaruf_crc64_update(), AARUF_ERROR_CANNOT_WRITE_BLOCK_DATA, AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER, AARUF_ERROR_NOT_AARUFORMAT, AARUF_ERROR_NOT_ENOUGH_MEMORY, aaruf_flac_encode_redbook_buffer(), aaruf_lzma_encode_buffer(), AARUF_READ_ONLY, AARUF_STATUS_OK, DdtHeader2::blockAlignmentShift, IndexEntry::blockType, BlockHeader::cmpCrc64, BlockHeader::cmpLength, BlockHeader::compression, BlockHeader::crc64, aaruformat_context::crc64_context, aaruformat_context::current_block_header, aaruformat_context::current_block_offset, DataBlock, IndexEntry::dataType, aaruformat_context::dirty_index_block, FATAL, Flac, aaruformat_context::imageStream, aaruformat_context::index_entries, aaruformat_context::is_writing, BlockHeader::length, Lzma, aaruformat_context::lzma_dict_size, LZMA_PROPERTIES_LENGTH, aaruformat_context::magic, MAX_FLAKE_BLOCK, MIN_FLAKE_BLOCK, aaruformat_context::next_block_position, None, IndexEntry::offset, SAMPLES_PER_SECTOR, BlockHeader::sectorSize, TRACE, aaruformat_context::user_data_ddt_header, UserData, aaruformat_context::writing_buffer, and aaruformat_context::writing_buffer_position.

Referenced by aaruf_close(), aaruf_write_sector(), and set_ddt_multi_level_v2().

## aaruf_write_media_tag()

int32_t aaruf_write_media_tag | ( | void * | context,
|  | const uint8_t * | data,
|  | const int32_t | type,
|  | const uint32_t | length )

Writes a media tag to the AaruFormat image, storing medium-specific metadata and descriptors.

This function stores arbitrary media-specific metadata (media tags) in the AaruFormat image context for later serialization during image finalization. Media tags represent higher-level descriptors and metadata structures that characterize the storage medium beyond sector data, including disc information structures, lead-in/lead-out data, manufacturer identifiers, drive capabilities, and format-specific metadata. The function uses a hash table for efficient tag storage and retrieval, automatically replacing existing tags of the same type and managing memory for tag data.

Supported Media Tag Categories:

Optical Disc Metadata (CD/DVD/BD/HD DVD):

- CD_TOC (0): Table of Contents from READ TOC/PMA/ATIP command (Format 0000b - Formatted TOC)
  - Contains track entries, session boundaries, lead-in/lead-out addressing, and track types
  - Essential for multi-session and mixed-mode CD structure representation
- CD_FullTOC (1): Full TOC (Format 0010b) including session info and point/ADR/control fields
  - Provides complete session structure with ADR field interpretation and sub-Q channel details
- CD_SessionInfo (2): Session information (Format 0001b) for multi-session discs
- CD_TEXT (3): CD-TEXT data from lead-in area (artist, title, performer, songwriter metadata)
- CD_ATIP (4): Absolute Time In Pregroove (CD-R/RW timing calibration and media manufacturer data)
- CD_PMA (5): Power Management Area (CD-R/RW recording session management metadata)
- DVD_PFI (6): Physical Format Information (DVD layer characteristics, book type, linear density)
- DVD_DMI (7): Disc Manufacturing Information (DVD unique identifier and replication metadata)
- DVD_BCA (8): Burst Cutting Area (copy protection and regional management data for DVD-Video)
- BD_DI (28): Disc Information (Blu-ray layer count, recording format, disc size, channel bit length)
- BD_BCA (29): Blu-ray Burst Cutting Area (unique disc identifier and anti-counterfeiting data)

Recordable Media Structures:

- DVDR_RMD (17): Recorded Media Data (last border-out RMD for DVD-R/-RW finalization state)
- DVDR_PreRecordedInfo (18): Pre-recorded information area from lead-in (DVD-R physical specs)
- DVDR_MediaIdentifier (19): Writable media identifier (DVD-R/-RW unique ID from manufacturer)
- BD_DDS (30): Disc Definition Structure (BD-R/RE recording management and spare area allocation)
- BD_SpareArea (32): BD spare area allocation map (defect management for recordable Blu-ray)

Copy Protection and Security:

- AACS_VolumeIdentifier (33): AACS Volume Identifier (content identifier for AACS-protected media)
- AACS_SerialNumber (34): Pre-recorded media serial number (unique per AACS disc pressing)
- AACS_MediaIdentifier (35): AACS Media Identifier (cryptographic binding to physical medium)
- AACS_MKB (36): AACS Media Key Block (encrypted title keys and revocation lists)
- AACS_DataKeys (37): Extracted AACS title/volume keys (when decrypted, for archival purposes)
- AACS_CPRM_MKB (39): CPRM Media Key Block (Content Protection for Recordable Media)

Device and Drive Information:

- SCSI_INQUIRY (45): SCSI INQUIRY standard data (device type, vendor, model, firmware revision)
- SCSI_MODEPAGE_2A (46): SCSI Mode Page 2Ah (CD/DVD/BD capabilities and supported features)
- ATA_IDENTIFY (47): ATA IDENTIFY DEVICE response (512 bytes of drive capabilities and geometry)
- ATAPI_IDENTIFY (48): ATA PACKET IDENTIFY DEVICE (ATAPI drive identification and features)
- MMC_WriteProtection (41): Write protection status from MMC GET CONFIGURATION command
- MMC_DiscInformation (42): Disc Information (recordable status, erasable flag, last session)

Flash and Solid-State Media:

- SD_CID (50): SecureDigital Card ID register (manufacturer, OEM, product name, serial number)
- SD_CSD (51): SecureDigital Card Specific Data (capacity, speed class, file format)
- SD_SCR (52): SecureDigital Configuration Register (SD spec version, bus widths, security)
- SD_OCR (53): SecureDigital Operation Conditions Register (voltage ranges, capacity type)
- MMC_CID (54): MMC Card ID (similar to SD_CID for eMMC/MMC devices)
- MMC_CSD (55): MMC Card Specific Data (MMC device parameters)
- MMC_ExtendedCSD (57): MMC Extended CSD (512 bytes of extended MMC capabilities)

Gaming Console Media:

- Xbox_SecuritySector (58): Xbox/Xbox 360 Security Sector (SS.bin - anti-piracy signature data)
- Xbox_DMI (66): Xbox Disc Manufacturing Info (manufacturing plant and batch metadata)
- Xbox_PFI (67): Xbox Physical Format Information (Xbox-specific DVD layer configuration)

Specialized Structures:

- CD_FirstTrackPregap (61): First track pregap (index 0 contents, typically silent on audio CDs)
- CD_LeadOut (62): Lead-out area contents (post-data region signaling disc end)
- CD_LeadIn (68): Raw lead-in data (TOC frames and sub-Q channel from pre-data region)
- Floppy_LeadOut (59): Manufacturer/duplication cylinder (floppy copy protection metadata)
- PCMCIA_CIS (49): PCMCIA/CardBus Card Information Structure tuple chain
- USB_Descriptors (65): Concatenated USB descriptors (device/config/interface for USB drives)

Data Processing Pipeline:

1. Context Validation: Verifies context is valid AaruFormat context with write permissions
2. Parameter Validation: Checks data pointer is non-NULL and length is non-zero
3. Memory Allocation: Allocates new buffer for tag data and mediaTagEntry structure
4. Data Copying: Performs deep copy of tag data to ensure context owns the memory
5. Hash Table Insertion: Adds or replaces entry in mediaTags hash table using uthash HASH_REPLACE_INT
6. Cleanup: Frees old media tag entry and data if replacement occurred
7. Return Success: Returns AARUF_STATUS_OK on successful completion

Memory Management Strategy:

- Deep Copy Semantics: Function performs deep copy of input data; caller retains ownership of original buffer
- Automatic Replacement: Existing tag of same type is automatically freed when replaced
- Hash Table Storage: Media tags stored in uthash-based hash table for O(1) lookup by type
- Deferred Serialization: Tag data remains in memory until aaruf_close() serializes to image file
- Cleanup on Close: All media tag memory automatically freed during aaruf_close()

Tag Type Identification: The type parameter accepts MediaTagType enumeration values (0-68) that identify the semantic meaning of the tag data. The library does not validate tag data structure or size against the type identifier - callers are responsible for providing correctly formatted tag data matching the declared type. Type values are preserved as-is and used during serialization to identify tag purpose during image reading.

Replacement Behavior: When a media tag of the same type already exists in the context:

- The old tag entry is removed from the hash table
- The old tag's data buffer is freed
- The old tag entry structure is freed
- The new tag replaces the old tag in the hash table
- No warning or error is generated for replacement This allows incremental updates to media tags during image creation.

Serialization and Persistence: Media tags written via this function are not immediately written to the image file. Instead, they are accumulated in the context's mediaTags hash table and serialized during aaruf_close() as part of the image finalization process. The serialization creates a metadata block in the image file that preserves all media tags with their type identifiers and data lengths.

Thread Safety and Concurrency: This function is NOT thread-safe. The context contains mutable shared state including:

- mediaTags hash table modification
- Memory allocation and deallocation
- No internal locking or synchronization External synchronization required for concurrent access from multiple threads.

Performance Considerations:

- Hash table insertion is O(1) average case for new tags
- Hash table replacement is O(1) for existing tags
- Memory allocation overhead proportional to tag data size
- No disk I/O occurs during this call (deferred to aaruf_close())
- Suitable for frequent tag updates during image creation workflow

Typical Usage Scenarios:

- Optical Disc Imaging: Store TOC, PMA, ATIP, CD-TEXT from READ TOC family commands
- Copy Protection Preservation: Store BCA, AACS structures, media identifiers for archival
- Drive Capabilities: Store INQUIRY, Mode Page 2Ah, IDENTIFY data for forensic metadata
- Flash Card Imaging: Store CID, CSD, SCR, OCR registers from SD/MMC cards
- Console Game Preservation: Store Xbox security sectors and manufacturing metadata
- Recordable Media: Store RMD, media identifiers, spare area maps for write-once media

Validation and Error Handling:

- Context validity checked via magic number comparison (AARU_MAGIC)
- Write permission verified via isWriting flag
- NULL data pointer triggers AARUF_ERROR_INCORRECT_DATA_SIZE
- Zero length triggers AARUF_ERROR_INCORRECT_DATA_SIZE
- Memory allocation failures return AARUF_ERROR_NOT_ENOUGH_MEMORY
- No validation of tag data structure or size against type identifier

Data Format Requirements: The function accepts arbitrary binary data without format validation. Callers must ensure:

- Tag data matches the declared MediaTagType structure and size
- Binary data is properly byte-ordered for the target platform
- Variable-length tags include proper internal length fields if required
- Tag data represents a complete, self-contained structure

Integration with Image Creation Workflow: Media tags should typically be written after creating the image context (aaruf_create()) but before writing sector data. However, tags can be added or updated at any point during the writing process. Common workflow:

1. Create image context with aaruf_create()
2. Set tracks with aaruf_set_tracks() if applicable
3. Write media tags with write_media_tag() for all available metadata
4. Write sector data with aaruf_write_sector() or aaruf_write_sector_long()
5. Close image with aaruf_close() to finalize and serialize all metadata

Parameters

  context | Pointer to a valid aaruformatContext with magic == AARU_MAGIC opened for writing. Must be created via aaruf_create() and not yet closed. The context's isWriting flag must be true, indicating write mode is active.
  data | Pointer to the media tag data buffer to write. Must be a valid non-NULL pointer to a buffer containing the complete tag data. The function performs a deep copy of this data, so the caller retains ownership and may free or modify the source buffer after this call returns. The data format must match the structure expected for the specified type parameter.
  type | Integer identifier specifying the type of media tag (MediaTagType enumeration). Values range from 0 (CD_TOC) to 68 (CD_LeadIn). The type identifies the semantic meaning of the tag data and is preserved in the image file for interpretation during reading. The library does not validate that the data structure matches the declared type - caller responsibility to ensure correctness.
  length | Length in bytes of the media tag data buffer. Must be greater than zero. Specifies how many bytes to copy from the data buffer. No maximum length enforced, but extremely large tags may cause memory allocation failures.

Returns
  Returns one of the following status codes:

Return values

  AARUF_STATUS_OK

  (0) Successfully wrote the media tag. This is returned when:
  - Context is valid with correct magic number (AARU_MAGIC)
  - Context is in writing mode (isWriting == true)
  - Data pointer is non-NULL and length is non-zero
  - Memory allocation succeeded for both tag data and entry structure
  - Tag entry successfully inserted into mediaTags hash table
  - If replacing existing tag, old tag successfully freed

  AARUF_ERROR_NOT_AARUFORMAT

  (-1) Invalid context provided. This occurs when:
  - context parameter is NULL (no context provided)
  - Context magic number != AARU_MAGIC (wrong context type, corrupted context, or uninitialized)
  - Context was not created by aaruf_create() or has been corrupted

  AARUF_READ_ONLY

  (-22) Attempting to write to read-only image. This occurs when:
  - Context isWriting flag is false
  - Image was opened with aaruf_open() instead of aaruf_create()
  - Context is in read-only mode and modifications are not permitted

  AARUF_ERROR_INCORRECT_DATA_SIZE

  (-26) Invalid data or length parameters. This occurs when:
  - data parameter is NULL (no tag data provided)
  - length parameter is zero (no data to write)
  - Parameters indicate invalid or empty tag data

  AARUF_ERROR_NOT_ENOUGH_MEMORY

  (-9) Memory allocation failed. This occurs when:
  - Failed to allocate buffer for tag data copy (malloc(length) failed)
  - Failed to allocate mediaTagEntry structure (malloc(sizeof(mediaTagEntry)) failed)
  - System is out of available memory for requested allocation size
  - Memory allocation fails due to resource exhaustion or fragmentation

Note
  Cross-References: This function is the write counterpart to aaruf_read_media_tag(). See also:
  - aaruf_read_media_tag(): Reads media tag data from opened image
  - aaruf_create(): Creates writable image context required for this function
  - aaruf_close(): Serializes media tags to image file and frees tag memory
  - MediaTagType enumeration in aaru.h: Defines valid type identifier values
  Memory Ownership: The function performs a deep copy of tag data. After successful return, the context owns the copied tag data and the caller may free or modify the original data buffer. On failure, no memory is retained by the context - caller maintains full ownership of input buffer regardless of success or failure.
  Tag Uniqueness: Only one media tag of each type can exist in an image. Writing a tag with a type that already exists will replace the previous tag, freeing its memory and using the new tag data. No error or warning is generated for replacements.
  Deferred Serialization: Media tags are not written to disk until aaruf_close() is called. All tags remain in memory throughout the image creation process. For images with many or large media tags, memory usage may be significant.
  No Type Validation: The library does not validate that tag data matches the declared type. Callers must ensure data structure correctness. Mismatched data may cause reading applications to fail or misinterpret tag contents.

Warning
  Memory Growth: Each media tag consumes memory equal to tag data size plus mediaTagEntry structure overhead. Large tags or many tags can significantly increase memory usage. Monitor memory consumption when writing extensive metadata.
  Type Correctness: No validation occurs for tag data format against type identifier. Providing incorrectly formatted data or mismatched type identifiers will create a valid image file with invalid tag data that may cause failures when reading. Ensure data format matches MediaTagType specification requirements.
  Replacement Silent: Replacing an existing tag does not generate warnings or errors. Applications expecting to detect duplicate tag writes must track this externally. The most recent write_media_tag() call for each type determines the final tag value.

See also
  aaruf_read_media_tag() for corresponding media tag reading functionality
  aaruf_create() for image context creation in write mode
  aaruf_close() for media tag serialization and memory cleanup
  MediaTagType enumeration for valid type identifier values and meanings

Definition at line 1836 of file write.c.

References AARU_CALL, AARU_EXPORT, AARU_MAGIC, AARUF_ERROR_INCORRECT_DATA_SIZE, AARUF_ERROR_NOT_AARUFORMAT, AARUF_ERROR_NOT_ENOUGH_MEMORY, AARUF_READ_ONLY, AARUF_STATUS_OK, mediaTagEntry::data, aaruformat_context::dirty_media_tags, FATAL, aaruformat_context::is_writing, mediaTagEntry::length, aaruformat_context::magic, aaruformat_context::mediaTags, TRACE, and mediaTagEntry::type.

## aaruf_write_sector()

int32_t aaruf_write_sector | ( | void * | context,
|  | uint64_t | sector_address,
|  | bool | negative,
|  | const uint8_t * | data,
|  | uint8_t | sector_status,
|  | uint32_t | length )

Writes a sector to the AaruFormat image.

Writes the given data to the specified sector address in the image, with the given status and length. This function handles buffering data into blocks, automatically closing blocks when necessary (sector size changes or block size limits are reached), and managing the deduplication table (DDT) entries.

Parameters

  context | Pointer to the aaruformat context.
  sector_address | Logical sector address to write.
  negative | Indicates if the sector address is negative.
  data | Pointer to the data buffer to write.
  sector_status | Status of the sector to write.
  length | Length of the data buffer.

Returns
  Returns one of the following status codes:

Return values

  AARUF_STATUS_OK

  (0) Successfully wrote the sector data. This is returned when:
  - The sector data is successfully copied to the writing buffer
  - The DDT entry is successfully updated for the sector address
  - Block management operations complete successfully
  - Buffer positions and offsets are properly updated

  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)

  AARUF_READ_ONLY

  (-22) Attempting to write to a read-only image. This occurs when:
  - The context's isWriting flag is false
  - The image was opened in read-only mode

  AARUF_ERROR_NOT_ENOUGH_MEMORY

  (-9) Memory allocation failed. This occurs when:
  - Failed to allocate memory for the writing buffer when creating a new block
  - The system is out of available memory for buffer allocation

  AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER

  (-23) Failed to write block header to the image file. This can occur during automatic block closure when:
  - The fwrite() call for the block header fails
  - Disk space is insufficient or file system errors occur

  AARUF_ERROR_CANNOT_WRITE_BLOCK_DATA

  (-24) Failed to write block data to the image file. This can occur during automatic block closure when:
  - The fwrite() call for the block data fails
  - Disk space is insufficient or file system errors occur

  AARUF_ERROR_CANNOT_SET_DDT_ENTRY

  (-25) Failed to update the deduplication table (DDT) entry. This occurs when:
  - The DDT entry for the specified sector address could not be set or updated
  - Internal DDT management functions return failure
  - DDT table corruption or memory issues prevent entry updates

Note
  Block Management:
  - The function automatically closes the current block when sector size changes
  - Blocks are also closed when they reach the maximum size (determined by dataShift)
  - New blocks are created automatically when needed with appropriate headers
  Memory Management:
  - Writing buffers are allocated on-demand when creating new blocks
  - Buffer memory is freed when blocks are closed
  - Buffer size is calculated based on sector size and data shift parameters
  DDT Updates:
  - Each written sector updates the corresponding DDT entry
  - DDT entries track block offset, position, and sector status
  - Uses DDT version 2 format for entries

Warning
  The function may trigger automatic block closure, which can result in disk I/O operations and potential write errors even for seemingly simple sector writes.

Definition at line 99 of file write.c.

References AARU_CALL, AARU_EXPORT, AARU_MAGIC, aaruf_close_current_block(), AARUF_ERROR_CANNOT_SET_DDT_ENTRY, AARUF_ERROR_INVALID_SECTOR_LENGTH, AARUF_ERROR_NOT_AARUFORMAT, AARUF_ERROR_NOT_ENOUGH_MEMORY, AARUF_ERROR_SECTOR_OUT_OF_BOUNDS, aaruf_md5_update(), AARUF_READ_ONLY, aaruf_sha1_update(), aaruf_sha256_update(), aaruf_spamsum_update(), AARUF_STATUS_OK, Audio, AaruHeaderV2::biggestSectorSize, aaruformat_context::blake3_context, aaruformat_context::block_zero_written, aaruformat_context::calculating_blake3, aaruformat_context::calculating_md5, aaruformat_context::calculating_sha1, aaruformat_context::calculating_sha256, aaruformat_context::calculating_spamsum, BlockHeader::compression, aaruformat_context::compression_enabled, aaruformat_context::current_block_header, aaruformat_context::current_block_offset, aaruformat_context::current_track_type, Data, DataBlock, DdtHeader2::dataShift, aaruformat_context::deduplicate, aaruformat_context::dirty_checksum_block, TrackEntry::end, TracksHeader::entries, FATAL, Flac, aaruformat_context::header, BlockHeader::identifier, aaruformat_context::image_info, insert_map(), aaruformat_context::is_writing, JaguarCD, aaruformat_context::last_written_block, lookup_map(), Lzma, aaruformat_context::magic, aaruformat_context::md5_context, ImageInfo::MediaType, ImageInfo::MetadataMediaType, DdtHeader2::negative, aaruformat_context::next_block_position, None, OpticalDisc, DdtHeader2::overflow, aaruformat_context::rewinded, aaruformat_context::sector_hash_map, ImageInfo::Sectors, BlockHeader::sectorSize, TrackEntry::sequence, TrackEntry::session, set_ddt_entry_v2(), aaruformat_context::sha1_context, aaruformat_context::sha256_context, aaruformat_context::spamsum_context, TrackEntry::start, TRACE, aaruformat_context::track_entries, aaruformat_context::tracks_header, BlockHeader::type, TrackEntry::type, aaruformat_context::user_data_ddt_header, UserData, VideoNow, VideoNowColor, VideoNowXp, aaruformat_context::writing_buffer, aaruformat_context::writing_buffer_position, and aaruformat_context::writing_long.

Referenced by aaruf_write_sector_long().

## aaruf_write_sector_long()

int32_t aaruf_write_sector_long | ( | void * | context,
|  | uint64_t | sector_address,
|  | bool | negative,
|  | const uint8_t * | data,
|  | uint8_t | sector_status,
|  | uint32_t | length )

Writes a full ("long") raw sector from optical or block media, parsing structure and validating content.

This function processes complete raw sectors including structural metadata, error correction codes, and subchannel information. It is the primary entry point for ingesting raw sector data where the caller provides the complete sector including synchronization patterns, headers, user data, and error correction information. The function intelligently parses the sector structure based on media type and track information, validates correctness, and delegates user data writing to aaruf_write_sector().

Supported Media Types and Sector Formats:

Optical Disc Media (2352-byte sectors):

- Audio tracks: Raw PCM audio data (2352 bytes) passed directly to aaruf_write_sector()
- Data tracks: Raw data sectors passed directly to aaruf_write_sector()
- CD Mode 1: Sync(12) + Header(4) + UserData(2048) + EDC(4) + Reserved(8) + ECC_P(172) + ECC_Q(104)
  - Validates sync pattern (00 FF FF FF FF FF FF FF FF FF FF 00), mode byte (01), and MSF timing
  - Checks EDC/ECC correctness using aaruf_ecc_cd_is_suffix_correct()
  - Stores anomalous prefixes/suffixes in separate buffers with mini-DDT indexing
- CD Mode 2 Form 1: Sync(12) + Header(4) + Subheader(8) + UserData(2048) + EDC(4) + ECC_P(172) + ECC_Q(104)
  - Validates sync pattern, mode byte (02), and Form 1 identification in subheader
  - Checks both EDC and ECC correctness for Form 1 sectors
  - Extracts and stores 8-byte subheader separately in mode2_subheaders buffer
- CD Mode 2 Form 2: Sync(12) + Header(4) + Subheader(8) + UserData(2324) + EDC(4)
  - Validates sync pattern, mode byte (02), and Form 2 identification in subheader
  - Checks EDC correctness, handles missing EDC (zero) as valid state
  - No ECC validation for Form 2 sectors (not present in format)
- CD Mode 2 Formless: Similar to Form 2 but without form determination from subheader

Block Media (512+ byte sectors with tags):

- Apple Profile/FileWare: 512-byte sectors + 20-byte Profile tags
- Apple Sony SS/DS: 512-byte sectors + 12-byte Sony tags
- Apple Widget: 512-byte sectors with tag conversion support
- Priam DataTower: 512-byte sectors + 24-byte Priam tags
- Supports automatic tag format conversion between Sony (12), Profile (20), and Priam (24) byte formats
- Tag data stored in sector_subchannel buffer for preservation

Data Processing Pipeline:

1. Context and Parameter Validation: Verifies context magic, write permissions, and sector bounds
2. Track Resolution: Locates track entry covering the sector address to determine track type
3. Rewind Detection: Detects out-of-order writing and disables hash calculations to maintain integrity
4. Hash Updates: Updates MD5, SHA1, SHA256, SpamSum, and BLAKE3 contexts for user-range sectors
5. Structure Parsing: Splits raw sector into prefix, user data, and suffix components
6. Validation: Checks sync patterns, timing fields, EDC/ECC correctness, and format compliance
7. Metadata Storage: Stores anomalous or non-standard components in dedicated buffers
8. User Data Delegation: Calls aaruf_write_sector() with extracted user data and derived status

Memory Management Strategy:

- DDT Arrays: Lazily allocated 64-bit arrays sized for total addressable space (negative + user + overflow)
  - sectorPrefixDdt2: Tracks prefix status and buffer offsets (high 4 bits = status, low 60 bits = offset/16)
  - sectorSuffixDdt2: Tracks suffix status and buffer offsets (high 4 bits = status, low 60 bits = offset/288)
- Prefix Buffer: Dynamically growing buffer storing non-standard 16-byte CD prefixes
- Suffix Buffer: Dynamically growing buffer storing non-standard CD suffixes (288 bytes for Mode 1, 4 bytes for Mode 2 Form 2, 280 bytes for Mode 2 Form 1)
- Subheader Buffer: Fixed-size buffer (8 bytes per sector) for Mode 2 subheaders
- Subchannel Buffer: Fixed-size buffer for block media tag data
- All buffers use doubling reallocation strategy when capacity exceeded

Address Space Management: The function handles three logical address regions:

- Negative Region: Pre-gap sectors (sector_address < negative region size, negative=true)
- User Region: Main data sectors (0 ≤ sector_address < Sectors, negative=false)
- Overflow Region: Post-data sectors (sector_address ≥ Sectors, negative=false) Internal corrected_sector_address provides linear indexing: corrected = address ± negative_size

Sector Status Classification: Status codes stored in high nibble of mini-DDT entries:

- SectorStatusMode1Correct: Valid Mode 1 sector with correct sync, timing, EDC, and ECC
- SectorStatusMode2Form1Ok: Valid Mode 2 Form 1 with correct subheader, EDC, and ECC
- SectorStatusMode2Form2Ok: Valid Mode 2 Form 2 with correct subheader and EDC
- SectorStatusMode2Form2NoCrc: Mode 2 Form 2 with zero EDC (acceptable state)
- SectorStatusErrored: Sector with validation errors, anomalous data stored in buffers
- SectorStatusNotDumped: All-zero sectors treated as not dumped

Deduplication Integration: Long sector processing does not directly perform deduplication - this occurs in the delegated aaruf_write_sector() call for the extracted user data portion. The prefix/suffix/subheader metadata is stored separately and not subject to deduplication.

Hash Calculation Behavior:

- Hashes computed on complete raw sector data (all 2352 bytes for optical, full tag+data for block)
- Only performed for sectors in user address range (not negative or overflow regions)
- Permanently disabled upon rewind detection to prevent corrupted streaming digests
- Supports MD5, SHA1, SHA256, SpamSum, and BLAKE3 simultaneously when enabled

Error Recovery and Validation:

- Sync pattern validation for optical sectors (CD standard 12-byte sync)
- MSF timing validation (Minutes:Seconds:Frames converted to LBA must match sector_address)
- Mode byte validation (01 for Mode 1, 02 for Mode 2)
- EDC validation using aaruf_edc_cd_compute() for computed vs stored comparison
- ECC validation using aaruf_ecc_cd_is_suffix_correct() and aaruf_ecc_cd_is_suffix_correct_mode2()
- Form determination from subheader flags (bit 5 of bytes 18 and 22)
- Tag format validation and conversion for block media

Thread Safety and Concurrency: This function is NOT thread-safe. The context contains mutable shared state including:

- Buffer pointers and offsets
- Hash computation contexts
- Rewind detection state
- DDT modification operations External synchronization required for concurrent access.

Performance Considerations:

- Buffer allocation occurs lazily on first use
- Buffer growth uses doubling strategy to amortize allocation cost
- Validation operations are optimized for common cases (correct sectors)
- Memory copying minimized for standard compliant sectors
- Hash updates operate on full sector to maintain streaming performance

Parameters

  context | Pointer to a valid aaruformatContext with magic == AARU_MAGIC opened for writing.
  sector_address | Logical Block Address (LBA) for the sector. For negative regions, this is the negative-space address; for user/overflow regions, this is the standard 0-based LBA.
  negative | true if sector_address refers to the negative (pre-gap) region; false for user or overflow regions.

  data

  Pointer to the complete raw sector buffer. Must contain:
  - For optical: exactly 2352 bytes of raw sector data
  - For block media: 512 bytes + tag data (12, 20, or 24 bytes depending on format)

  sector_status | Initial sector status hint from caller. May be overridden based on validation results when delegating to aaruf_write_sector().
  length | Length in bytes of the data buffer. Must be exactly 2352 for optical discs. For block media: 512 (no tags), 524 (Sony), 532 (Profile), or 536 (Priam).

Returns
  Returns one of the following status codes:

Return values

  AARUF_STATUS_OK

  (0) Sector successfully processed and user data written. This occurs when:
  - Raw sector structure parsed and validated successfully
  - Prefix/suffix/subheader metadata stored appropriately
  - User data portion successfully delegated to aaruf_write_sector()
  - All buffer allocations and DDT updates completed successfully

  AARUF_ERROR_NOT_AARUFORMAT

  (-1) Invalid context provided. This occurs when:
  - context parameter is NULL
  - Context magic number != AARU_MAGIC (wrong context type or corruption)

  AARUF_READ_ONLY

  (-22) Attempting to write to read-only image. This occurs when:
  - Context isWriting flag is false
  - Image was opened without write permissions

  AARUF_ERROR_SECTOR_OUT_OF_BOUNDS

  (-5) Sector address outside valid ranges. This occurs when:
  - negative=true and sector_address >= negative region size
  - negative=false and sector_address >= (Sectors + overflow region size)

  AARUF_ERROR_INCORRECT_DATA_SIZE

  (-26) Invalid sector size for media type. This occurs when:
  - length != 2352 for optical disc media
  - length not in {512, 524, 532, 536} for supported block media types

  AARUF_ERROR_NOT_ENOUGH_MEMORY

  (-9) Memory allocation failed. This occurs when:
  - Failed to allocate mini-DDT arrays (sectorPrefixDdt2, sectorSuffixDdt2)
  - Failed to allocate or grow prefix buffer (sector_prefix)
  - Failed to allocate or grow suffix buffer (sector_suffix)
  - Failed to allocate subheader buffer (mode2_subheaders)
  - Failed to allocate subchannel buffer (sector_subchannel)
  - System out of memory during buffer reallocation

  AARUF_ERROR_INCORRECT_MEDIA_TYPE

  (-12) Unsupported media type for long sectors. This occurs when:
  - Media type is not OpticalDisc or supported BlockMedia variant
  - Block media type does not support the provided tag format

  AARUF_ERROR_CANNOT_SET_DDT_ENTRY

  (-25) DDT update failed. Propagated from aaruf_write_sector() when:
  - User data DDT entry could not be updated
  - DDT table corruption prevents entry modification

  AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER

  (-23) Block header write failed. Propagated from aaruf_write_sector() when:
  - Automatic block closure triggered by user data write fails
  - File system error prevents header write

  AARUF_ERROR_CANNOT_WRITE_BLOCK_DATA

  (-24) Block data write failed. Propagated from aaruf_write_sector() when:
  - User data portion write fails during block flush
  - Insufficient disk space or I/O error occurs

Note
  Cross-References: This function is the primary companion to aaruf_write_sector() for raw sector ingestion. See also:
  - aaruf_write_sector(): Handles user data portion writing and deduplication
  - aaruf_ecc_cd_is_suffix_correct(): CD Mode 1 ECC validation
  - aaruf_ecc_cd_is_suffix_correct_mode2(): CD Mode 2 Form 1 ECC validation
  - aaruf_edc_cd_compute(): EDC calculation and validation for all CD modes
  - aaruf_close(): Serializes prefix/suffix/subheader metadata to image file
  Buffer Management: All dynamically allocated buffers (prefix, suffix, subheader, subchannel) are automatically freed during aaruf_close(). Applications should not attempt to access these buffers directly or free them manually.
  Metadata Persistence: Prefix, suffix, and subheader data captured by this function is serialized to the image file during aaruf_close() as separate metadata blocks with corresponding mini-DDT tables for efficient access during reading.
  Tag Format Conversion: For block media, automatic conversion between Sony, Profile, and Priam tag formats ensures compatibility regardless of source format. Conversion preserves all semantic information while adapting to target media type requirements.

Warning
  Rewind Detection: Writing sectors out of strictly increasing order triggers rewind detection, permanently disabling hash calculations for the session. This prevents corrupted streaming digests but means hash values will be unavailable if non-sequential writing occurs. Plan sector writing order carefully if digest calculation is required.
  Memory Growth: Prefix and suffix buffers grow dynamically and can consume significant memory for images with many non-standard sectors. Monitor memory usage when processing damaged or non-compliant optical media.
  Media Type Constraints: This function only supports OpticalDisc and specific BlockMedia types. Other media types will return AARUF_ERROR_INCORRECT_MEDIA_TYPE. Use aaruf_write_sector() directly for unsupported media types.

See also
  aaruf_write_sector() for user data writing and deduplication
  aaruf_read_sector_long() for corresponding long sector reading functionality
  aaruf_close() for metadata serialization and cleanup

Definition at line 555 of file write.c.

References AARU_CALL, AARU_EXPORT, AARU_MAGIC, aaruf_ecc_cd_is_suffix_correct(), aaruf_ecc_cd_is_suffix_correct_mode2(), aaruf_edc_cd_compute(), AARUF_ERROR_INCORRECT_DATA_SIZE, AARUF_ERROR_INCORRECT_MEDIA_TYPE, AARUF_ERROR_NOT_AARUFORMAT, AARUF_ERROR_NOT_ENOUGH_MEMORY, AARUF_ERROR_SECTOR_OUT_OF_BOUNDS, aaruf_md5_update(), AARUF_READ_ONLY, aaruf_sha1_update(), aaruf_sha256_update(), aaruf_spamsum_update(), aaruf_write_sector(), AppleFileWare, AppleProfile, AppleSonyDS, AppleSonySS, AppleWidget, Audio, aaruformat_context::blake3_context, aaruformat_context::block_zero_written, BlockMedia, bytes_to_priam_tag(), bytes_to_profile_tag(), bytes_to_sony_tag(), aaruformat_context::calculating_blake3, aaruformat_context::calculating_md5, aaruformat_context::calculating_sha1, aaruformat_context::calculating_sha256, aaruformat_context::calculating_spamsum, CdMode1, CdMode2Form1, CdMode2Form2, CdMode2Formless, Data, aaruformat_context::dirty_mode2_subheaders_block, aaruformat_context::dirty_sector_prefix_block, aaruformat_context::dirty_sector_prefix_ddt, aaruformat_context::dirty_sector_subchannel_block, aaruformat_context::dirty_sector_suffix_block, aaruformat_context::dirty_sector_suffix_ddt, DVDDownload, DVDPR, DVDPRDL, DVDPRW, DVDPRWDL, DVDR, DVDRAM, DVDRDL, DVDROM, DVDRW, DVDRWDL, aaruformat_context::ecc_cd_context, TrackEntry::end, TracksHeader::entries, FATAL, aaruformat_context::image_info, aaruformat_context::is_writing, aaruformat_context::last_written_block, aaruformat_context::magic, aaruformat_context::md5_context, ImageInfo::MediaType, ImageInfo::MetadataMediaType, aaruformat_context::mode2_subheaders, DdtHeader2::negative, Nuon, OpticalDisc, DdtHeader2::overflow, priam_tag_to_bytes(), priam_tag_to_profile(), priam_tag_to_sony(), PriamDataTower, profile_tag_to_bytes(), profile_tag_to_priam(), profile_tag_to_sony(), PS2DVD, PS3DVD, aaruformat_context::rewinded, SACD, aaruformat_context::sector_cpr_mai, aaruformat_context::sector_edc, aaruformat_context::sector_id, aaruformat_context::sector_ied, aaruformat_context::sector_prefix, aaruformat_context::sector_prefix_ddt2, aaruformat_context::sector_prefix_length, aaruformat_context::sector_prefix_offset, aaruformat_context::sector_subchannel, aaruformat_context::sector_suffix, aaruformat_context::sector_suffix_ddt2, aaruformat_context::sector_suffix_length, aaruformat_context::sector_suffix_offset, ImageInfo::Sectors, SectorStatusErrored, SectorStatusMode1Correct, SectorStatusMode2Form1Ok, SectorStatusMode2Form2NoCrc, SectorStatusMode2Form2Ok, SectorStatusNotDumped, TrackEntry::sequence, aaruformat_context::sha1_context, aaruformat_context::sha256_context, sony_tag_to_bytes(), sony_tag_to_priam(), sony_tag_to_profile(), aaruformat_context::spamsum_context, TrackEntry::start, TRACE, aaruformat_context::track_entries, aaruformat_context::tracks_header, TrackEntry::type, aaruformat_context::user_data_ddt_header, and aaruformat_context::writing_long.

## aaruf_write_sector_tag()

int32_t aaruf_write_sector_tag | ( | void * | context,
|  | const uint64_t | sector_address,
|  | const bool | negative,
|  | const uint8_t * | data,
|  | const size_t | length,
|  | const int32_t | tag )

Writes per-sector tag data (auxiliary metadata) for a specific sector.

This function stores auxiliary metadata associated with individual sectors, such as CD subchannel data, DVD auxiliary fields, track metadata, or proprietary tag formats used by specific storage systems. Unlike media tags (which apply to the entire medium), sector tags are per-sector metadata that provide additional context, error correction, copy protection, or device-specific information for each individual sector.

The function validates the tag type against the media type, verifies the data size matches the expected length for that tag type, allocates buffers as needed, and stores the tag data at the appropriate offset within the tag buffer. Some tags (like track flags and ISRC) update track metadata rather than per-sector buffers.

Supported tag types and their characteristics:

Optical Disc (CD/DVD) Tags:

- CdTrackFlags (1 byte): Track control flags for CD tracks
  - Updates track metadata in ctx->trackEntries for the track containing the sector
  - Includes flags like copy permitted, data track, four-channel audio, etc.
- CdTrackIsrc (12 bytes): International Standard Recording Code for CD tracks
  - Updates track metadata in ctx->trackEntries for the track containing the sector
  - Identifies the recording for copyright and royalty purposes
- CdSectorSubchannel (96 bytes): CD subchannel data (P-W subchannels)
  - Stored in ctx->sector_subchannel buffer
  - Contains control information, track numbers, timecodes, and CD-TEXT data
- DvdSectorCprMai (6 bytes): DVD Copyright Management Information
  - Stored in ctx->sector_cpr_mai buffer
  - Contains copy protection and media authentication information
- DvdSectorInformation (1 byte): DVD sector information field
  - Stored in first byte of ctx->sector_id buffer (4 bytes per sector)
  - Contains sector type and layer information
- DvdSectorNumber (3 bytes): DVD sector number field
  - Stored in bytes 1-3 of ctx->sector_id buffer (4 bytes per sector)
  - Physical sector address encoded in the sector header
- DvdSectorIed (2 bytes): DVD ID Error Detection field
  - Stored in ctx->sector_ied buffer
  - Error detection code for the sector ID field
- DvdSectorEdc (4 bytes): DVD Error Detection Code
  - Stored in ctx->sector_edc buffer
  - Error detection code for the entire sector
- DvdDiscKeyDecrypted (5 bytes): Decrypted DVD title key
  - Stored in ctx->sector_decrypted_title_key buffer
  - Used for accessing encrypted DVD content

Block Media (Proprietary Format) Tags:

- AppleSonyTag (12 bytes): Apple II Sony 3.5" disk tag data
  - Stored in ctx->sector_subchannel buffer
  - Contains file system metadata used by Apple II systems
- AppleProfileTag (20 bytes): Apple ProFile/FileWare hard drive tag data
  - Stored in ctx->sector_subchannel buffer
  - Contains file system and bad block metadata
- PriamDataTowerTag (24 bytes): Priam Data Tower hard drive tag data
  - Stored in ctx->sector_subchannel buffer
  - Contains proprietary metadata used by Priam drives

Sector addressing: The function supports both positive and negative sector addressing:

- Negative sectors: Lead-in area before sector 0 (for optical media)
- Positive sectors: Main data area and lead-out overflow area
- Internal correction adjusts addresses to buffer offsets

Buffer allocation: Tag buffers are allocated on-demand when the first tag of a given type is written. Buffers are sized to accommodate all sectors (negative + normal + overflow) and persist for the lifetime of the context. Memory is freed during aaruf_close().

Parameters

  context | Pointer to the aaruformat context (must be a valid, write-enabled image context).
  sector_address | The logical sector number to write the tag for. Must be within valid bounds for the image (0 to Sectors-1 for positive, 0 to negative-1 when using negative addressing).
  negative | If true, sector_address refers to a negative (lead-in) sector; if false, it refers to a positive sector (main data or overflow area).
  data | Pointer to the tag data to write. Must not be NULL. The data size must exactly match the expected size for the tag type.
  length | Length of the tag data in bytes. Must match the required size for the tag type.
  tag | Tag type identifier (from the tag enumeration). Determines which buffer to write to and the expected data size.

Returns
  Returns one of the following status codes:

Return values

  AARUF_STATUS_OK

  (0) Successfully wrote sector tag. This is returned when:
  - The context is valid and properly initialized
  - The context is opened in write mode (ctx->isWriting is true)
  - The sector address is within valid bounds
  - The tag type is supported and appropriate for the media type
  - The data length matches the required size for the tag type
  - Memory allocation succeeded (if buffer needed to be created)
  - Tag data was copied to the appropriate buffer or track metadata updated

  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()

  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

  AARUF_ERROR_SECTOR_OUT_OF_BOUNDS

  (-5) Sector address is invalid. This occurs when:
  - negative is true and sector_address > negative-1
  - negative is false and sector_address > Sectors+overflow-1
  - Attempting to write beyond the image boundaries

  AARUF_ERROR_INCORRECT_DATA_SIZE

  (-26) Invalid data or length. This occurs when:
  - The data parameter is NULL
  - The length parameter is 0
  - The length doesn't match the required size for the tag type
  - Tag size validation failed

  AARUF_ERROR_INCORRECT_MEDIA_TYPE

  (-12) Invalid media type for tag. This occurs when:
  - Attempting to write optical disc tags (CD/DVD) to block media
  - Attempting to write block media tags to optical disc
  - Tag type is incompatible with ctx->imageInfo.XmlMediaType

  AARUF_ERROR_NOT_ENOUGH_MEMORY

  (-9) Memory allocation failed. This occurs when:
  - calloc() failed to allocate buffer for tag data
  - System is out of memory or memory is severely fragmented
  - Buffer allocation is required but cannot be satisfied

  AARUF_ERROR_TRACK_NOT_FOUND

  (-13) Track not found for sector. This occurs when:
  - Writing CdTrackFlags or CdTrackIsrc tags
  - The specified sector is not contained within any defined track
  - Track metadata has not been initialized

  AARUF_ERROR_INVALID_TAG

  (-27) Unsupported or unknown tag type. This occurs when:
  - The tag parameter doesn't match any known tag type
  - The tag type is not implemented
  - Invalid tag identifier provided

Note
  Tag Data Persistence:
  - Tag data is stored in memory until aaruf_close() is called
  - Tags are written as separate data blocks during image finalization
  - CD subchannel and DVD auxiliary fields are written by dedicated block writers
  - Track metadata (flags, ISRC) is written as part of the tracks block
  Buffer Reuse:
  - Some tag types share the same buffer (ctx->sector_subchannel)
  - CD subchannel uses 96 bytes per sector
  - Apple Sony tag uses 12 bytes per sector
  - Apple Profile tag uses 20 bytes per sector
  - Priam Data Tower tag uses 24 bytes per sector
  - Ensure consistent tag type usage within a single image
  DVD Sector ID Split:
  - DVD sector ID is 4 bytes but written as two separate tags
  - DvdSectorInformation writes byte 0 (sector info)
  - DvdSectorNumber writes bytes 1-3 (sector number)
  - Both tags share ctx->sector_id buffer
  Tag Size Validation:
  - Each tag type has a fixed expected size
  - Size mismatches are rejected with AARUF_ERROR_INCORRECT_DATA_SIZE
  - This prevents partial writes and buffer corruption
  Media Type Validation:
  - Optical disc tags require XmlMediaType == OpticalDisc
  - Block media tags require XmlMediaType == BlockMedia
  - This prevents incompatible tag types from being written
  Multiple Writes to Same Sector:
  - Writing the same tag type to the same sector multiple times replaces the previous value
  - No warning or error is generated for overwrites
  - Last write wins

Warning
  Tag data is not immediately written to disk. All tag data is buffered in memory and written during aaruf_close(). Ensure sufficient memory is available for large images with extensive tag data.
  Mixing incompatible tag types that share buffers (e.g., CD subchannel and Apple tags) will cause data corruption. Only use tag types appropriate for your media format.
  For track-based tags (CdTrackFlags, CdTrackIsrc), tracks must be defined before writing tags. Call aaruf_set_tracks() to initialize track metadata first.

See also
  aaruf_write_media_tag() for writing whole-medium tags.
  aaruf_write_sector_long() for writing sectors with embedded tag data.
  write_sector_subchannel() for the serialization of CD subchannel data.
  write_dvd_long_sector_blocks() for the serialization of DVD auxiliary data.

Definition at line 2106 of file write.c.

References AARU_CALL, AARU_EXPORT, AARU_MAGIC, AARUF_ERROR_INCORRECT_DATA_SIZE, AARUF_ERROR_INCORRECT_MEDIA_TYPE, AARUF_ERROR_INVALID_TAG, AARUF_ERROR_NOT_AARUFORMAT, AARUF_ERROR_NOT_ENOUGH_MEMORY, AARUF_ERROR_SECTOR_OUT_OF_BOUNDS, AARUF_ERROR_TRACK_NOT_FOUND, AARUF_READ_ONLY, AARUF_STATUS_OK, AppleProfileTagAaru, AppleSonyTagAaru, BlockMedia, CdSectorSubchannelAaru, CdTrackFlags, CdTrackIsrc, aaruformat_context::dirty_dvd_long_sector_blocks, aaruformat_context::dirty_dvd_title_key_decrypted_block, aaruformat_context::dirty_sector_subchannel_block, aaruformat_context::dirty_tracks_block, DvdCmi, DvdSectorEdcAaru, DvdSectorIedAaru, DvdSectorInformation, DvdSectorNumber, DvdTitleKeyDecrypted, TracksHeader::entries, FATAL, TrackEntry::flags, aaruformat_context::image_info, aaruformat_context::is_writing, TrackEntry::isrc, aaruformat_context::magic, ImageInfo::MetadataMediaType, DdtHeader2::negative, OpticalDisc, DdtHeader2::overflow, PriamDataTowerTagAaru, aaruformat_context::sector_cpr_mai, aaruformat_context::sector_decrypted_title_key, aaruformat_context::sector_edc, aaruformat_context::sector_id, aaruformat_context::sector_ied, aaruformat_context::sector_subchannel, ImageInfo::Sectors, TrackEntry::start, TRACE, aaruformat_context::track_entries, aaruformat_context::tracks_header, and aaruformat_context::user_data_ddt_header.