Files
libaaruformat/docs/html/close_8c.html

2072 lines
226 KiB
HTML
Raw Normal View History

2025-10-11 01:35:43 +01:00
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen 1.14.0"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>libaaruformat: src/close.c File Reference</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<script type="text/javascript" src="clipboard.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript" src="cookie.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr id="projectrow">
<td id="projectalign">
<div id="projectname">libaaruformat<span id="projectnumber">&#160;1.0</span>
</div>
<div id="projectbrief">Aaru Data Preservation Suite - Format Library</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.14.0 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search/",'.html');
</script>
<script type="text/javascript">
$(function() { codefold.init(); });
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
$(function() {
initMenu('',true,false,'search.php','Search',true);
$(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
<div id="nav-tree">
<div id="nav-tree-contents">
<div id="nav-sync" class="sync"></div>
</div>
</div>
<div id="splitbar" style="-moz-user-select:none;"
class="ui-resizable-handle">
</div>
</div>
<script type="text/javascript">
$(function(){initNavTree('close_8c.html','',''); });
</script>
<div id="container">
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<div id="MSearchResults">
<div class="SRPage">
<div id="SRIndex">
<div id="SRResults"></div>
<div class="SRStatus" id="Loading">Loading...</div>
<div class="SRStatus" id="Searching">Searching...</div>
<div class="SRStatus" id="NoMatches">No Matches</div>
</div>
</div>
</div>
</div>
<div class="header">
<div class="headertitle"><div class="title">close.c File Reference</div></div>
</div><!--header-->
<div class="contents">
<p>Implements image finalization and resource cleanup for libaaruformat.
<a href="#details">More...</a></p>
<div class="textblock"><code>#include &lt;errno.h&gt;</code><br />
<code>#include &lt;stdio.h&gt;</code><br />
<code>#include &lt;stdlib.h&gt;</code><br />
<code>#include &lt;<a class="el" href="aaruformat_8h_source.html">aaruformat.h</a>&gt;</code><br />
<code>#include &quot;<a class="el" href="internal_8h_source.html">internal.h</a>&quot;</code><br />
<code>#include &quot;<a class="el" href="log_8h_source.html">log.h</a>&quot;</code><br />
</div>
<p><a href="close_8c_source.html">Go to the source code of this file.</a></p>
<table class="memberdecls">
<tr class="heading"><td colspan="2"><h2 id="header-func-members" class="groupheader"><a id="func-members" name="func-members"></a>
Functions</h2></td></tr>
<tr class="memitem:af0f89d22c6e2bdca261223bbdda7654c" id="r_af0f89d22c6e2bdca261223bbdda7654c"><td class="memItemLeft" align="right" valign="top">static int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#af0f89d22c6e2bdca261223bbdda7654c">write_cached_secondary_ddt</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:af0f89d22c6e2bdca261223bbdda7654c"><td class="mdescLeft">&#160;</td><td class="mdescRight">Flush a cached secondary (child) DeDuplication Table (DDT) to the image. <br /></td></tr>
<tr class="memitem:a1bb181171eb9d0b0016cf4091ed831d7" id="r_a1bb181171eb9d0b0016cf4091ed831d7"><td class="memItemLeft" align="right" valign="top">static int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#a1bb181171eb9d0b0016cf4091ed831d7">write_primary_ddt</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:a1bb181171eb9d0b0016cf4091ed831d7"><td class="mdescLeft">&#160;</td><td class="mdescRight">Write (flush) the multi-level primary DDT table header and data back to its file offset. <br /></td></tr>
<tr class="memitem:a7314de0d71768709fa4ba2db7f89cdb9" id="r_a7314de0d71768709fa4ba2db7f89cdb9"><td class="memItemLeft" align="right" valign="top">static int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#a7314de0d71768709fa4ba2db7f89cdb9">write_single_level_ddt</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:a7314de0d71768709fa4ba2db7f89cdb9"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize a single-level DDT (tableShift == 0) directly after its header. <br /></td></tr>
<tr class="memitem:aed9f90614002b887ae9f3ef2333de16a" id="r_aed9f90614002b887ae9f3ef2333de16a"><td class="memItemLeft" align="right" valign="top">static int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#aed9f90614002b887ae9f3ef2333de16a">write_tape_ddt</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:aed9f90614002b887ae9f3ef2333de16a"><td class="mdescLeft">&#160;</td><td class="mdescRight">Converts tape DDT hash table to array format and writes it as a single-level DDT. <br /></td></tr>
<tr class="memitem:a84f08d3fe750b46dad183b12bb3927c5" id="r_a84f08d3fe750b46dad183b12bb3927c5"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#a84f08d3fe750b46dad183b12bb3927c5">write_checksum_block</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:a84f08d3fe750b46dad183b12bb3927c5"><td class="mdescLeft">&#160;</td><td class="mdescRight">Finalize any active checksum calculations and append a checksum block. <br /></td></tr>
<tr class="memitem:aa2451e6c0fc8d4db3bfb9874f2ca990c" id="r_aa2451e6c0fc8d4db3bfb9874f2ca990c"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#aa2451e6c0fc8d4db3bfb9874f2ca990c">write_tracks_block</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:aa2451e6c0fc8d4db3bfb9874f2ca990c"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the tracks metadata block and add it to the index. <br /></td></tr>
<tr class="memitem:ade7f81cbae198dbbea937551bf670a4f" id="r_ade7f81cbae198dbbea937551bf670a4f"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#ade7f81cbae198dbbea937551bf670a4f">write_mode2_subheaders_block</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:ade7f81cbae198dbbea937551bf670a4f"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize a MODE 2 (XA) subheaders data block. <br /></td></tr>
<tr class="memitem:af383051987456d1295862e395027ffa8" id="r_af383051987456d1295862e395027ffa8"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#af383051987456d1295862e395027ffa8">write_sector_prefix</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:af383051987456d1295862e395027ffa8"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the optional CD sector prefix block. <br /></td></tr>
<tr class="memitem:a8ea54bc4597be4246f2be361a5854251" id="r_a8ea54bc4597be4246f2be361a5854251"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#a8ea54bc4597be4246f2be361a5854251">write_sector_suffix</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:a8ea54bc4597be4246f2be361a5854251"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the optional CD sector suffix block (EDC/ECC region capture). <br /></td></tr>
<tr class="memitem:ae5ee36ba745233583773cd7a644c8aa7" id="r_ae5ee36ba745233583773cd7a644c8aa7"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#ae5ee36ba745233583773cd7a644c8aa7">write_sector_prefix_ddt</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:ae5ee36ba745233583773cd7a644c8aa7"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the per-sector CD prefix status / index DeDuplication Table (DDT v2, prefix variant). <br /></td></tr>
<tr class="memitem:a9d0eb026d1fa544b554493e780b7fbc1" id="r_a9d0eb026d1fa544b554493e780b7fbc1"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#a9d0eb026d1fa544b554493e780b7fbc1">write_sector_suffix_ddt</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:a9d0eb026d1fa544b554493e780b7fbc1"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the per-sector CD suffix status / index DeDuplication Table (DDT v2, suffix variant). <br /></td></tr>
2025-12-12 12:25:02 +00:00
<tr class="memitem:a2b849af94084e38d2040eca1d520478a" id="r_a2b849af94084e38d2040eca1d520478a"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#a2b849af94084e38d2040eca1d520478a">write_sector_subchannel</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:a2b849af94084e38d2040eca1d520478a"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the per-sector subchannel or tag data block. <br /></td></tr>
2025-10-11 01:35:43 +01:00
<tr class="memitem:a13f6c475294969c1eb8c59ff53c91af9" id="r_a13f6c475294969c1eb8c59ff53c91af9"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#a13f6c475294969c1eb8c59ff53c91af9">write_dvd_long_sector_blocks</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:a13f6c475294969c1eb8c59ff53c91af9"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize DVD long sector auxiliary data blocks to the image file. <br /></td></tr>
2025-12-12 12:25:02 +00:00
<tr class="memitem:a5e2cce0d9661697c767d9312224fd340" id="r_a5e2cce0d9661697c767d9312224fd340"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#a5e2cce0d9661697c767d9312224fd340">write_dvd_title_key_decrypted_block</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:a5e2cce0d9661697c767d9312224fd340"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the DVD decrypted title key data block to the image file. <br /></td></tr>
<tr class="memitem:a3decc41ec145e8b153a23de6389b3782" id="r_a3decc41ec145e8b153a23de6389b3782"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#a3decc41ec145e8b153a23de6389b3782">write_media_tags</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:a3decc41ec145e8b153a23de6389b3782"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize all accumulated media tags to the image file. <br /></td></tr>
<tr class="memitem:a742ec2b4d57e32fa856033b1e4a04e9f" id="r_a742ec2b4d57e32fa856033b1e4a04e9f"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#a742ec2b4d57e32fa856033b1e4a04e9f">write_tape_file_block</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:a742ec2b4d57e32fa856033b1e4a04e9f"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the tape file metadata block to the image file. <br /></td></tr>
<tr class="memitem:ae333a9d69b81891b260907fd7d0665e1" id="r_ae333a9d69b81891b260907fd7d0665e1"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#ae333a9d69b81891b260907fd7d0665e1">write_tape_partition_block</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:ae333a9d69b81891b260907fd7d0665e1"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the tape partition metadata block to the image file. <br /></td></tr>
<tr class="memitem:ada8f13126103c0077ddcf5e6120aea53" id="r_ada8f13126103c0077ddcf5e6120aea53"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#ada8f13126103c0077ddcf5e6120aea53">write_geometry_block</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:ada8f13126103c0077ddcf5e6120aea53"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the geometry metadata block to the image file. <br /></td></tr>
2025-10-11 01:35:43 +01:00
<tr class="memitem:af36ba67be5e488713558202feef0eeef" id="r_af36ba67be5e488713558202feef0eeef"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#af36ba67be5e488713558202feef0eeef">write_metadata_block</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:af36ba67be5e488713558202feef0eeef"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the metadata block containing image and media descriptive information. <br /></td></tr>
<tr class="memitem:a796034966c1e918152e652635431dc39" id="r_a796034966c1e918152e652635431dc39"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#a796034966c1e918152e652635431dc39">write_dumphw_block</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:a796034966c1e918152e652635431dc39"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the dump hardware block containing acquisition environment information. <br /></td></tr>
2025-12-12 12:25:02 +00:00
<tr class="memitem:a2308f1f7356e94d85c057a3d0d4ed343" id="r_a2308f1f7356e94d85c057a3d0d4ed343"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#a2308f1f7356e94d85c057a3d0d4ed343">write_cicm_block</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:a2308f1f7356e94d85c057a3d0d4ed343"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the CICM XML metadata block to the image file. <br /></td></tr>
<tr class="memitem:ad94331170e773c67845daa357c6ecb42" id="r_ad94331170e773c67845daa357c6ecb42"><td class="memItemLeft" align="right" valign="top">static void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#ad94331170e773c67845daa357c6ecb42">write_aaru_json_block</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:ad94331170e773c67845daa357c6ecb42"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the Aaru metadata JSON block to the image file. <br /></td></tr>
2025-10-11 01:35:43 +01:00
<tr class="memitem:a3532372fac3d5bb2619900820a26632e" id="r_a3532372fac3d5bb2619900820a26632e"><td class="memItemLeft" align="right" valign="top">static int32_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#a3532372fac3d5bb2619900820a26632e">write_index_block</a> (<a class="el" href="structaaruformat__context.html">aaruformat_context</a> *ctx)</td></tr>
<tr class="memdesc:a3532372fac3d5bb2619900820a26632e"><td class="mdescLeft">&#160;</td><td class="mdescRight">Serialize the accumulated index entries at the end of the image and back-patch the header. <br /></td></tr>
<tr class="memitem:a6823e139f81a9dfd08efcb0e9b213a49" id="r_a6823e139f81a9dfd08efcb0e9b213a49"><td class="memItemLeft" align="right" valign="top">int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#a6823e139f81a9dfd08efcb0e9b213a49">aaruf_close</a> (void *context)</td></tr>
<tr class="memdesc:a6823e139f81a9dfd08efcb0e9b213a49"><td class="mdescLeft">&#160;</td><td class="mdescRight">Close an Aaru image context, flushing pending data structures and releasing resources. <br /></td></tr>
</table>
<a name="details" id="details"></a><h2 id="header-details" class="groupheader">Detailed Description</h2>
<div class="textblock"><p>Implements image finalization and resource cleanup for libaaruformat. </p>
<p>This translation unit contains the logic that flushes any remaining in-memory structures (deduplication tables, checksum information, track metadata, MODE 2 subheaders, sector prefix data and the global index) to the on-disk Aaru image when closing a context opened for writing. It also performs orderly teardown of dynamically allocated resources regardless of read or write mode.</p>
<p>Helper (static) functions perform discrete serialization steps; the public entry point is <a class="el" href="#a6823e139f81a9dfd08efcb0e9b213a49" title="Close an Aaru image context, flushing pending data structures and releasing resources.">aaruf_close()</a>. All write helpers assume that the caller has already validated the context magic and (for write mode) written the initial provisional header at offset 0. Functions return libaaruformat status codes (AARUF_STATUS_OK on success or an AARUF_ERROR_* constant) except for <a class="el" href="#a6823e139f81a9dfd08efcb0e9b213a49" title="Close an Aaru image context, flushing pending data structures and releasing resources.">aaruf_close()</a>, which returns 0 on success and -1 on failure while setting errno. </p>
<p class="definition">Definition in file <a class="el" href="close_8c_source.html">close.c</a>.</p>
</div><a name="doc-func-members" id="doc-func-members"></a><h2 id="header-doc-func-members" class="groupheader">Function Documentation</h2>
<a id="a6823e139f81a9dfd08efcb0e9b213a49" name="a6823e139f81a9dfd08efcb0e9b213a49"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a6823e139f81a9dfd08efcb0e9b213a49">&#9670;&#160;</a></span>aaruf_close()</h2>
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">int aaruf_close </td>
<td>(</td>
<td class="paramtype">void *</td> <td class="paramname"><span class="paramname"><em>context</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</div><div class="memdoc">
<p>Close an Aaru image context, flushing pending data structures and releasing resources. </p>
<p>Public API entry point used to finalize an image being written or simply dispose of a context opened for reading. For write-mode contexts (ctx-&gt;isWriting true) the function performs the following ordered steps:</p><ol type="1">
<li>Rewrite the (possibly updated) main header at offset 0.</li>
<li>Close any open data block via <a class="el" href="internal_8h.html#a2402812f5e04ba16765208c0b70fa6c5" title="Finalizes and writes the current data block to the AaruFormat image file.">aaruf_close_current_block()</a>.</li>
<li>Flush a cached secondary DDT (multi-level) if pending.</li>
<li>Flush either the primary DDT (multi-level) or the single-level DDT table.</li>
<li>Finalize and append checksum block(s) for all enabled algorithms.</li>
<li>Write auxiliary metadata blocks: tracks, MODE 2 subheaders, sector prefix.</li>
<li>Serialize the global index and patch header.indexOffset.</li>
<li>Clear deduplication hash map if used.</li>
</ol>
<p>Afterwards (or for read-mode contexts) all dynamically allocated buffers, arrays, hash tables and mapping structures are freed/unmapped. Media tags are removed from their hash table.</p>
<p>Error Handling:</p><ul>
<li>Returns -1 with errno = EINVAL if the provided pointer is NULL or not a valid context.</li>
<li>Returns -1 with errno set to AARUF_ERROR_CANNOT_WRITE_HEADER if a header write fails.</li>
<li>If any intermediate serialization helper returns an error status, that error value is propagated (converted to -1 with errno set accordingly by the caller if desired). In the current implementation <a class="el" href="#a6823e139f81a9dfd08efcb0e9b213a49" title="Close an Aaru image context, flushing pending data structures and releasing resources.">aaruf_close()</a> directly returns the negative error code for helper failures to preserve detail.</li>
</ul>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">context</td><td>Opaque pointer returned by earlier open/create calls (must be an aaruformatContext). </td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>0 on success; -1 or negative libaaruformat error code on failure. </dd></dl>
<dl class="retval"><dt>Return values</dt><dd>
<table class="retval">
<tr><td class="paramname">0</td><td>All pending data flushed (if writing) and resources released successfully. </td></tr>
<tr><td class="paramname">-1</td><td>Invalid context pointer or initial header rewrite failure (errno = EINVAL or AARUF_ERROR_CANNOT_WRITE_HEADER). </td></tr>
<tr><td class="paramname">AARUF_ERROR_CANNOT_WRITE_HEADER</td><td>A later write helper (e.g., index, DDT) failed and returned this code directly. </td></tr>
<tr><td class="paramname">&lt;other</td><td>negative libaaruformat code&gt; Propagated from a write helper if future helpers add more error codes. </td></tr>
</table>
</dd>
</dl>
<dl class="section note"><dt>Note</dt><dd>On success the context memory itself is freed; the caller must not reuse the pointer. </dd></dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l04059">4059</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="decls_8h_source.html#l00045">AARU_CALL</a>, <a class="el" href="decls_8h_source.html#l00054">AARU_EXPORT</a>, <a class="el" href="consts_8h_source.html#l00064">AARU_MAGIC</a>, <a class="el" href="write_8c_source.html#l01427">aaruf_close_current_block()</a>, <a class="el" href="errors_8h_source.html#l00060">AARUF_ERROR_CANNOT_WRITE_HEADER</a>, <a class="el" href="errors_8h_source.html#l00075">AARUF_STATUS_OK</a>, <a class="el" href="context_8h_source.html#l00269">aaruformat_context::checksums</a>, <a class="el" href="context_8h_source.html#l00214">aaruformat_context::cicm_block</a>, <a class="el" href="context_8h_source.html#l00120">mediaTagEntry::data</a>, <a class="el" href="context_8h_source.html#l00299">aaruformat_context::deduplicate</a>, <a class="el" href="context_8h_source.html#l00311">aaruformat_context::dirty_checksum_block</a>, <a class="el" href="context_8h_source.html#l00328">aaruformat_context::dirty_cicm_block</a>, <a class="el" href="context_8h_source.html#l00327">aaruformat_context::dirty_dumphw_block</a>, <a class="el" href="context_8h_source.html#l00319">aaruformat_context::dirty_dvd_long_sector_blocks</a>, <a class="el" href="context_8h_source.html#l00320">aaruformat_context::dirty_dvd_title_key_decrypted_block</a>, <a class="el" href="context_8h_source.html#l00325">aaruformat_context::dirty_geometry_block</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="context_8h_source.html#l00329">aaruformat_context::dirty_json_block</a>, <a class="el" href="context_8h_source.html#l00321">aaruformat_context::dirty_media_tags</a>, <a class="el" href="context_8h_source.html#l00326">aaruformat_context::dirty_metadata_block</a>, <a class="el" href="context_8h_source.html#l00313">aaruformat_context::dirty_mode2_subheaders_block</a>, <a class="el" href="context_8h_source.html#l00309">aaruformat_context::dirty_primary_ddt</a>, <a class="el" href="context_8h_source.html#l00308">aaruformat_context::dirty_secondary_ddt</a>, <a class="el" href="context_8h_source.html#l00314">aaruformat_context::dirty_sector_prefix_block</a>, <a class="el" href="context_8h_source.html#l00315">aaruformat_context::dirty_sector_prefix_ddt</a>, <a class="el" href="context_8h_source.html#l00318">aaruformat_context::dirty_sector_subchannel_block</a>, <a class="el" href="context_8h_source.html#l00316">aaruformat_context::dirty_sector_suffix_block</a>, <a class="el" href="context_8h_source.html#l00317">aaruformat_context::dirty_sector_suffix_ddt</a>, <a class="el" href="context_8h_source.html#l00310">aaruformat_context::dirty_single_level_ddt</a>, <a class="el" href="context_8h_source.html#l00322">aaruformat_context::dirty_tape_ddt</a>, <a class="el" href="context_8h_source.html#l00323">aaruformat_context::dirty_tape_file_block</a>, <a class="el" href="context_8h_source.html#l00324">aaruformat_context::dirty_tape_partition_block</a>, <a class="el" href="context_8h_source.html#l00312">aaruformat_context::dirty_tracks_block</a>, <a class="el" href="context_8h_source.html#l00212">aaruformat_context::dump_hardware_entries_with_data</a>, <a class="el" href="context_8h_source.html#l00232">aaruformat_context::dump_hardware_header</a>, <a class="el" href="context_8h_source.html#l00248">aaruformat_context::ecc_cd_context</a>, <a class="el" href="dump_8h_source.html#l00093">DumpHardwareHeader::entries</a>, <a class="el" href="context_8h_source.html#l00342">DumpHardwareEntriesWithData::extents</a>, <a class="el" href="log_8h_source.html#l00040">FATAL</a>, <a class="el" href="context_8h_source.html#l00346">DumpHardwareEntriesWithData::firmware</a>, <a class="el" href="hash__map_8c_source.html#l00073">free_map()</a>, <a class="el" href="context_8h_source.html#l00175">aaruformat_context::header</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00196">aaruformat_context::in_memory_ddt</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::
2025-10-11 01:35:43 +01:00
2025-10-21 14:23:35 +01:00
<p class="reference">Referenced by <a class="el" href="open_8c_source.html#l00223">aaruf_open()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
2025-12-12 12:25:02 +00:00
<a id="ad94331170e773c67845daa357c6ecb42" name="ad94331170e773c67845daa357c6ecb42"></a>
<h2 class="memtitle"><span class="permalink"><a href="#ad94331170e773c67845daa357c6ecb42">&#9670;&#160;</a></span>write_aaru_json_block()</h2>
2025-10-11 01:35:43 +01:00
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_aaru_json_block </td>
<td>(</td>
2025-12-12 12:25:02 +00:00
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
2025-10-11 01:35:43 +01:00
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the Aaru metadata JSON block to the image file. </p>
<p>This function writes an AaruMetadataJsonBlock containing embedded Aaru metadata JSON to the Aaru image file. The Aaru metadata JSON format is a structured, machine-readable representation of comprehensive image metadata including media information, imaging session details, hardware configuration, optical disc tracks and sessions, checksums, and preservation metadata. The JSON payload is stored in its original form without parsing, interpretation, or validation by the library, preserving the exact structure and content provided during image creation.</p>
<p>The Aaru JSON block is optional; if no Aaru JSON metadata has been populated (jsonBlock is NULL, length is zero, or identifier is not set to AaruMetadataJsonBlock), the function returns immediately without writing anything. This no-op behavior allows the close operation to proceed gracefully whether or not Aaru JSON metadata was included during image creation.</p>
<p><b>Block structure:</b> The serialized block consists of:</p><ol type="1">
<li><a class="el" href="structAaruMetadataJsonBlockHeader.html" title="Header for an Aaru metadata JSON block (identifier == BlockType::AaruMetadataJsonBlock).">AaruMetadataJsonBlockHeader</a> (8 bytes: identifier + length)</li>
<li>Variable-length JSON payload: the raw UTF-8 encoded Aaru metadata JSON data</li>
</ol>
<p>The header contains:</p><ul>
<li>identifier: Always set to AaruMetadataJsonBlock (0x444D534A, "JSMD" in ASCII)</li>
<li>length: Size in bytes of the JSON payload that immediately follows the header</li>
</ul>
<p><b>Alignment and file positioning:</b> Before writing the block, the file position is moved to EOF and then aligned forward to the next boundary satisfying (position &amp; alignment_mask) == 0, where alignment_mask is derived from ctx-&gt;userDataDdtHeader.blockAlignmentShift. This ensures the Aaru JSON block begins on a properly aligned offset for efficient I/O and compliance with the Aaru format specification.</p>
<p><b>Write sequence:</b> The function performs a two-stage write operation:</p><ol type="1">
<li>Write the <a class="el" href="structAaruMetadataJsonBlockHeader.html" title="Header for an Aaru metadata JSON block (identifier == BlockType::AaruMetadataJsonBlock).">AaruMetadataJsonBlockHeader</a> (sizeof(AaruMetadataJsonBlockHeader) bytes)</li>
<li>Write the JSON payload (ctx-&gt;jsonBlockHeader.length bytes)</li>
</ol>
<p>Both writes must succeed for the block to be considered successfully written. If the header write fails, the payload write is skipped. Only if both writes succeed is an index entry added.</p>
<p><b>Index registration:</b> After successfully writing both the header and JSON payload, an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> is appended to ctx-&gt;indexEntries with:</p><ul>
<li>blockType = AaruMetadataJsonBlock</li>
<li>dataType = 0 (Aaru JSON blocks have no subtype)</li>
<li>offset = the aligned file position where the <a class="el" href="structAaruMetadataJsonBlockHeader.html" title="Header for an Aaru metadata JSON block (identifier == BlockType::AaruMetadataJsonBlock).">AaruMetadataJsonBlockHeader</a> was written</li>
</ul>
<p><b>Error handling:</b> Write errors (fwrite returning &lt; 1) are silently ignored; no index entry is added if either write fails. Diagnostic TRACE logs report success or failure. The function does not propagate error codes; higher-level close logic must validate overall integrity if needed.</p>
<p><b>No-op conditions:</b></p><ul>
<li>ctx-&gt;jsonBlock is NULL (no JSON data loaded) OR</li>
<li>ctx-&gt;jsonBlockHeader.length == 0 (empty metadata) OR</li>
<li>ctx-&gt;jsonBlockHeader.identifier != AaruMetadataJsonBlock (block not properly initialized)</li>
</ul>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. Must not be NULL. ctx-&gt;jsonBlockHeader contains the header with identifier and length fields. ctx-&gt;jsonBlock points to the actual UTF-8 encoded JSON data (may be NULL if no Aaru JSON metadata was provided). ctx-&gt;imageStream must be open and writable. ctx-&gt;indexEntries must be initialized (utarray) to accept new index entries.</td></tr>
</table>
</dd>
</dl>
<dl class="section note"><dt>Note</dt><dd>JSON Encoding and Format:<ul>
<li>The JSON payload is stored in UTF-8 encoding</li>
<li>The payload may or may not be null-terminated</li>
<li>The library treats the JSON as opaque binary data</li>
<li>No JSON parsing, interpretation, or validation is performed during write</li>
<li>Schema compliance is the responsibility of the code that set the Aaru JSON metadata</li>
</ul>
</dd>
<dd>
Aaru Metadata JSON Purpose:<ul>
<li>Provides machine-readable structured metadata using modern JSON format</li>
<li>Includes comprehensive information about media, sessions, tracks, and checksums</li>
<li>Enables programmatic access to metadata without XML parsing overhead</li>
<li>Documents imaging session details, hardware configuration, and preservation data</li>
<li>Used by Aaru and compatible tools for metadata exchange and analysis</li>
<li>Complements or serves as alternative to CICM XML metadata</li>
</ul>
</dd>
<dd>
Memory Management:<ul>
<li>The function does not allocate or free any memory</li>
<li>ctx-&gt;jsonBlock memory is managed by the caller (typically freed during aaruf_close)</li>
<li>The JSON data is written directly from the existing buffer</li>
</ul>
</dd>
<dd>
Unlike data blocks (which may be compressed and include CRC64 checksums), the Aaru JSON block is written without compression or explicit integrity checking. The JSON payload is written verbatim as provided, relying on file-level integrity mechanisms.</dd>
<dd>
Order in Close Sequence:<ul>
<li>Aaru JSON blocks are typically written after CICM blocks but before the index</li>
<li>The exact position in the file depends on what other blocks precede it</li>
<li>The index entry ensures the Aaru JSON block can be located during subsequent opens</li>
</ul>
</dd>
<dd>
Distinction from CICM XML:<ul>
<li>Both CICM XML and Aaru JSON blocks can be written to the same image</li>
<li>CICM XML follows the Canary Islands Computer Museum schema (older format)</li>
<li>Aaru JSON follows the Aaru-specific metadata schema (newer format)</li>
<li>They serve similar purposes but with different structures and consumers</li>
<li>Including both provides maximum compatibility across different tools</li>
</ul>
</dd></dl>
<dl class="section see"><dt>See also</dt><dd><a class="el" href="structAaruMetadataJsonBlockHeader.html" title="Header for an Aaru metadata JSON block (identifier == BlockType::AaruMetadataJsonBlock).">AaruMetadataJsonBlockHeader</a> for the on-disk structure definition. </dd>
<dd>
<a class="el" href="decls_8h.html#a8090a039e00ee003569939332d21094e" title="Sets the Aaru metadata JSON for the image during creation.">aaruf_set_aaru_json_metadata()</a> for setting Aaru JSON during image creation. </dd>
<dd>
<a class="el" href="decls_8h.html#a01cf0abe0b137236d4be0b91a29d4818" title="Retrieves the embedded Aaru metadata JSON from the image.">aaruf_get_aaru_json_metadata()</a> for retrieving Aaru JSON from opened images. </dd>
<dd>
2025-12-12 12:25:02 +00:00
<a class="el" href="#a2308f1f7356e94d85c057a3d0d4ed343" title="Serialize the CICM XML metadata block to the image file.">write_cicm_block()</a> for the similar function that writes CICM XML blocks. </dd></dl>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l03875">3875</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="enums_8h_source.html#l00159">AaruMetadataJsonBlock</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="metadata_8h_source.html#l00121">AaruMetadataJsonBlockHeader::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="context_8h_source.html#l00215">aaruformat_context::json_block</a>, <a class="el" href="context_8h_source.html#l00233">aaruformat_context::json_block_header</a>, <a class="el" href="metadata_8h_source.html#l00122">AaruMetadataJsonBlockHeader::length</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="af0f89d22c6e2bdca261223bbdda7654c" name="af0f89d22c6e2bdca261223bbdda7654c"></a>
<h2 class="memtitle"><span class="permalink"><a href="#af0f89d22c6e2bdca261223bbdda7654c">&#9670;&#160;</a></span>write_cached_secondary_ddt()</h2>
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">int32_t write_cached_secondary_ddt </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Flush a cached secondary (child) DeDuplication Table (DDT) to the image. </p>
<p>When working with a multi-level DDT (i.e. primary table with tableShift &gt; 0), a single secondary table may be cached in memory while sectors belonging to its range are written. This function serializes the currently cached secondary table (if any) at the end of the file, aligning the write position to the DDT block alignment, and updates the corresponding primary table entry to point to the new block-aligned location. The primary table itself is then re-written in-place (only its data array portion) to persist the updated pointer. The index is updated by removing any previous index entry for the same secondary table offset and inserting a new one for the freshly written table.</p>
<p>CRC64 is computed for the serialized table contents and stored in crc64; cmpCrc64 stores the checksum of compressed data or equals crc64 if compression is not applied or not effective.</p>
<p>On return the cached secondary table buffers and bookkeeping fields (cachedSecondaryDdtSmall, cachedSecondaryDdtBig, cachedDdtOffset) are cleared.</p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. </td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>AARUF_STATUS_OK on success, or AARUF_ERROR_CANNOT_WRITE_HEADER if the secondary table or updated primary table cannot be flushed. </dd></dl>
<dl class="retval"><dt>Return values</dt><dd>
<table class="retval">
<tr><td class="paramname">AARUF_STATUS_OK</td><td>Success or no cached secondary DDT needed flushing. </td></tr>
<tr><td class="paramname">AARUF_ERROR_CANNOT_WRITE_HEADER</td><td>Failed writing secondary table or rewriting primary table. </td></tr>
</table>
</dd>
</dl>
<dl class="section note"><dt>Note</dt><dd>If no cached secondary DDT is pending (detected via tableShift and cache pointers), the function is a no-op returning AARUF_STATUS_OK. </dd></dl>
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l00077">77</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00160">aaruf_crc64_data()</a>, <a class="el" href="crc64_8c_source.html#l00141">aaruf_crc64_final()</a>, <a class="el" href="crc64_8c_source.html#l00032">aaruf_crc64_init()</a>, <a class="el" href="crc64_8c_source.html#l00055">aaruf_crc64_update()</a>, <a class="el" href="errors_8h_source.html#l00060">AARUF_ERROR_CANNOT_WRITE_HEADER</a>, <a class="el" href="errors_8h_source.html#l00048">AARUF_ERROR_NOT_ENOUGH_MEMORY</a>, <a class="el" href="lzma_8c_source.html#l00065">aaruf_lzma_encode_buffer()</a>, <a class="el" href="errors_8h_source.html#l00075">AARUF_STATUS_OK</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="ddt_8h_source.html#l00150">DdtHeader2::blocks</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="context_8h_source.html#l00190">aaruformat_context::cached_ddt_offset</a>, <a class="el" href="context_8h_source.html#l00191">aaruformat_context::cached_ddt_position</a>, <a class="el" href="context_8h_source.html#l00188">aaruformat_context::cached_secondary_ddt2</a>, <a class="el" href="ddt_8h_source.html#l00161">DdtHeader2::cmpCrc64</a>, <a class="el" href="ddt_8h_source.html#l00159">DdtHeader2::cmpLength</a>, <a class="el" href="ddt_8h_source.html#l00145">DdtHeader2::compression</a>, <a class="el" href="context_8h_source.html#l00300">aaruformat_context::compression_enabled</a>, <a class="el" href="ddt_8h_source.html#l00162">DdtHeader2::crc64</a>, <a class="el" href="ddt_8h_source.html#l00155">DdtHeader2::dataShift</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="enums_8h_source.html#l00144">DeDuplicationTableSecondary</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="ddt_8h_source.html#l00158">DdtHeader2::entries</a>, <a class="el" href="ddt_8h_source.html#l00143">DdtHeader2::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="ddt_8h_source.html#l00160">DdtHeader2::length</a>, <a class="el" href="ddt_8h_source.html#l00146">DdtHeader2::levels</a>, <a class="el" href="enums_8h_source.html#l00034">Lzma</a>, <a class="el" href="context_8h_source.html#l00298">aaruformat_context::lzma_dict_size</a>, <a class="el" href="consts_8h_source.html#l00082">LZMA_PROPERTIES_LENGTH</a>, <a class="el" href="ddt_8h_source.html#l00149">DdtHeader2::negative</a>, <a class="el" href="enums_8h_source.html#l00033">None</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="ddt_8h_source.html#l00151">DdtHeader2::overflow</a>, <a class="el" href="ddt_8h_source.html#l00148">DdtHeader2::previousLevelOffset</a>, <a class="el" href="context_8h_source.html#l00192">aaruformat_context::primary_ddt_offset</a>, <a class="el" href="ddt_8h_source.html#l00153">DdtHeader2::start</a>, <a class="el" href="ddt_8h_source.html#l00147">DdtHeader2::tableLevel</a>, <a class="el" href="ddt_8h_source.html#l00156">DdtHeader2::tableShift</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="ddt_8h_source.html#l00144">DdtHeader2::type</a>, <a class="el" href="context_8h_source.html#l00187">aaruformat_context::user_data_ddt2</a>, <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>, and <a class="el" href="enums_8h_source.html#l00046">UserData</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="a84f08d3fe750b46dad183b12bb3927c5" name="a84f08d3fe750b46dad183b12bb3927c5"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a84f08d3fe750b46dad183b12bb3927c5">&#9670;&#160;</a></span>write_checksum_block()</h2>
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_checksum_block </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Finalize any active checksum calculations and append a checksum block. </p>
<p>This routine completes pending hash contexts (MD5, SHA-1, SHA-256, SpamSum, BLAKE3), marks the presence flags in ctx-&gt;checksums, and if at least one checksum exists writes a ChecksumBlock at the end of the image (block-aligned). Individual <a class="el" href="structChecksumEntry.html" title="Per-checksum metadata immediately followed by the digest / signature bytes.">ChecksumEntry</a> records are serialized for each available algorithm and the block is indexed. Feature flags (e.g. AARU_FEATURE_RW_BLAKE3) are updated if required.</p>
<p>Memory ownership: for SpamSum a buffer is allocated here if a digest was being computed and is subsequently written without being freed inside this function (it will be freed during close). The BLAKE3 context is freed after finalization.</p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. </td></tr>
</table>
</dd>
</dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l00681">681</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="enums_8h_source.html#l00265">AARU_FEATURE_RW_BLAKE3</a>, <a class="el" href="md5_8c_source.html#l00485">aaruf_md5_final()</a>, <a class="el" href="sha1_8c_source.html#l00124">aaruf_sha1_final()</a>, <a class="el" href="sha256_8c_source.html#l00115">aaruf_sha256_final()</a>, <a class="el" href="spamsum_8c_source.html#l00191">aaruf_spamsum_final()</a>, <a class="el" href="spamsum_8c_source.html#l00075">aaruf_spamsum_free()</a>, <a class="el" href="enums_8h_source.html#l00173">Blake3</a>, <a class="el" href="context_8h_source.html#l00109">Checksums::blake3</a>, <a class="el" href="context_8h_source.html#l00268">aaruformat_context::blake3_context</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="context_8h_source.html#l00277">aaruformat_context::calculating_blake3</a>, <a class="el" href="context_8h_source.html#l00273">aaruformat_context::calculating_md5</a>, <a class="el" href="context_8h_source.html#l00274">aaruformat_context::calculating_sha1</a>, <a class="el" href="context_8h_source.html#l00275">aaruformat_context::calculating_sha256</a>, <a class="el" href="context_8h_source.html#l00276">aaruformat_context::calculating_spamsum</a>, <a class="el" href="enums_8h_source.html#l00152">ChecksumBlock</a>, <a class="el" href="context_8h_source.html#l00269">aaruformat_context::checksums</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="checksum_8h_source.html#l00077">ChecksumHeader::entries</a>, <a class="el" href="header_8h_source.html#l00122">AaruHeaderV2::featureCompatible</a>, <a class="el" href="spamsum_8h_source.html#l00030">FUZZY_MAX_RESULT</a>, <a class="el" href="context_8h_source.html#l00104">Checksums::hasBlake3</a>, <a class="el" href="context_8h_source.html#l00101">Checksums::hasMd5</a>, <a class="el" href="context_8h_source.html#l00102">Checksums::hasSha1</a>, <a class="el" href="context_8h_source.html#l00103">Checksums::hasSha256</a>, <a class="el" href="context_8h_source.html#l00105">Checksums::hasSpamSum</a>, <a class="el" href="context_8h_source.html#l00175">aaruformat_context::header</a>, <a class="el" href="checksum_8h_source.html#l00075">ChecksumHeader::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="checksum_8h_source.html#l00093">ChecksumEntry::length</a>, <a class="el" href="checksum_8h_source.html#l00076">ChecksumHeader::length</a>, <a class="el" href="enums_8h_source.html#l00169">Md5</a>, <a class="el" href="context_8h_source.html#l00106">Checksums::md5</a>, <a class="el" href="context_8h_source.html#l00270">aaruformat_context::md5_context</a>, <a class="el" href="context_8h_source.html#l00069">MD5_DIGEST_LENGTH</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="enums_8h_source.html#l00170">Sha1</a>, <a class="el" href="context_8h_source.html#l00107">Checksums::sha1</a>, <a class="el" href="context_8h_source.html#l00271">aaruformat_context::sha1_context</a>, <a class="el" href="sha1_8h_source.html#l00039">SHA1_DIGEST_LENGTH</a>, <a class="el" href="enums_8h_source.html#l00171">Sha256</a>, <a class="el" href="context_8h_source.html#l00108">Checksums::sha256</a>, <a class="el" href="context_8h_source.html#l00272">aaruformat_context::sha256_context</a>, <a class="el" href="sha256_8h_source.html#l00038">SHA256_DIGEST_LENGTH</a>, <a class="el" href="enums_8h_source.html#l00172">SpamSum</a>, <a class="el" href="context_8h_source.html#l00110">Checksums::spamsum</a>, <a class="el" href="context_8h_source.html#l00267">aaruformat_context::spamsum_context</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="checksum_8h_source.html#l00092">ChecksumEn
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
2025-12-12 12:25:02 +00:00
<a id="a2308f1f7356e94d85c057a3d0d4ed343" name="a2308f1f7356e94d85c057a3d0d4ed343"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a2308f1f7356e94d85c057a3d0d4ed343">&#9670;&#160;</a></span>write_cicm_block()</h2>
2025-10-11 01:35:43 +01:00
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_cicm_block </td>
<td>(</td>
2025-12-12 12:25:02 +00:00
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
2025-10-11 01:35:43 +01:00
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the CICM XML metadata block to the image file. </p>
<p>This function writes a CicmBlock containing embedded CICM (Canary Islands Computer Museum) XML metadata to the Aaru image file. The CICM XML format is a standardized metadata schema used for documenting preservation and archival information about media and disk images. The XML payload is stored in its original form without parsing, interpretation, or validation by the library, preserving the exact structure and content provided during image creation.</p>
<p>The CICM block is optional; if no CICM metadata has been populated (cicmBlock is NULL, length is zero, or identifier is not set to CicmBlock), the function returns immediately without writing anything. This no-op behavior allows the close operation to proceed gracefully whether or not CICM metadata was included during image creation.</p>
<p><b>Block structure:</b> The serialized block consists of:</p><ol type="1">
<li><a class="el" href="structCicmMetadataBlock.html" title="Header for a CICM XML metadata block (identifier == BlockType::CicmBlock).">CicmMetadataBlock</a> header (8 bytes: identifier + length)</li>
<li>Variable-length XML payload: the raw UTF-8 encoded CICM XML data</li>
</ol>
<p>The header contains:</p><ul>
<li>identifier: Always set to CicmBlock (0x4D434943, "CICM" in ASCII)</li>
<li>length: Size in bytes of the XML payload that immediately follows the header</li>
</ul>
<p><b>Alignment and file positioning:</b> Before writing the block, the file position is moved to EOF and then aligned forward to the next boundary satisfying (position &amp; alignment_mask) == 0, where alignment_mask is derived from ctx-&gt;userDataDdtHeader.blockAlignmentShift. This ensures the CICM block begins on a properly aligned offset for efficient I/O and compliance with the Aaru format specification.</p>
<p><b>Write sequence:</b> The function performs a two-stage write operation:</p><ol type="1">
<li>Write the <a class="el" href="structCicmMetadataBlock.html" title="Header for a CICM XML metadata block (identifier == BlockType::CicmBlock).">CicmMetadataBlock</a> header (sizeof(CicmMetadataBlock) bytes)</li>
<li>Write the XML payload (ctx-&gt;cicmBlockHeader.length bytes)</li>
</ol>
<p>Both writes must succeed for the block to be considered successfully written. If the header write fails, the payload write is skipped. Only if both writes succeed is an index entry added.</p>
<p><b>Index registration:</b> After successfully writing both the header and XML payload, an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> is appended to ctx-&gt;indexEntries with:</p><ul>
<li>blockType = CicmBlock</li>
<li>dataType = 0 (CICM blocks have no subtype)</li>
<li>offset = the aligned file position where the <a class="el" href="structCicmMetadataBlock.html" title="Header for a CICM XML metadata block (identifier == BlockType::CicmBlock).">CicmMetadataBlock</a> header was written</li>
</ul>
<p><b>Error handling:</b> Write errors (fwrite returning &lt; 1) are silently ignored; no index entry is added if either write fails. Diagnostic TRACE logs report success or failure. The function does not propagate error codes; higher-level close logic must validate overall integrity if needed.</p>
<p><b>No-op conditions:</b></p><ul>
<li>ctx-&gt;cicmBlock is NULL (no XML data loaded) OR</li>
<li>ctx-&gt;cicmBlockHeader.length == 0 (empty metadata) OR</li>
<li>ctx-&gt;cicmBlockHeader.identifier != CicmBlock (block not properly initialized)</li>
</ul>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. Must not be NULL. ctx-&gt;cicmBlockHeader contains the header with identifier and length fields. ctx-&gt;cicmBlock points to the actual UTF-8 encoded XML data (may be NULL if no CICM metadata was provided). ctx-&gt;imageStream must be open and writable. ctx-&gt;indexEntries must be initialized (utarray) to accept new index entries.</td></tr>
</table>
</dd>
</dl>
<dl class="section note"><dt>Note</dt><dd>XML Encoding and Format:<ul>
<li>The XML payload is stored in UTF-8 encoding</li>
<li>The payload may or may not be null-terminated</li>
<li>The library treats the XML as opaque binary data</li>
<li>No XML parsing, interpretation, or validation is performed during write</li>
<li>Schema compliance is the responsibility of the code that set the CICM metadata</li>
</ul>
</dd>
<dd>
CICM Metadata Purpose:<ul>
<li>Developed by the Canary Islands Computer Museum for digital preservation</li>
<li>Documents comprehensive preservation metadata following a standardized schema</li>
<li>Includes checksums for data integrity verification</li>
<li>Records detailed device and media information</li>
<li>Supports archival and long-term preservation requirements</li>
<li>Used by cultural heritage institutions and archives</li>
</ul>
</dd>
<dd>
Memory Management:<ul>
<li>The function does not allocate or free any memory</li>
<li>ctx-&gt;cicmBlock memory is managed by the caller (typically freed during aaruf_close)</li>
<li>The XML data is written directly from the existing buffer</li>
</ul>
</dd>
<dd>
Unlike data blocks (which may be compressed and include CRC64 checksums), the CICM block is written without compression or explicit integrity checking. The XML payload is written verbatim as provided, relying on file-level integrity mechanisms.</dd>
<dd>
Order in Close Sequence:<ul>
<li>CICM blocks are typically written after structural data blocks but before the index</li>
<li>The exact position in the file depends on what other blocks precede it</li>
<li>The index entry ensures the CICM block can be located during subsequent opens</li>
</ul>
</dd></dl>
<dl class="section see"><dt>See also</dt><dd><a class="el" href="structCicmMetadataBlock.html" title="Header for a CICM XML metadata block (identifier == BlockType::CicmBlock).">CicmMetadataBlock</a> for the on-disk structure definition. </dd>
<dd>
<a class="el" href="decls_8h.html#a42f191c2ea4c70c9d7b373c19b59c812" title="Retrieves the embedded CICM XML metadata sidecar from the image.">aaruf_get_cicm_metadata()</a> for retrieving CICM XML from opened images. </dd></dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l03737">3737</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="context_8h_source.html#l00214">aaruformat_context::cicm_block</a>, <a class="el" href="context_8h_source.html#l00231">aaruformat_context::cicm_block_header</a>, <a class="el" href="enums_8h_source.html#l00151">CicmBlock</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="metadata_8h_source.html#l00109">CicmMetadataBlock::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="metadata_8h_source.html#l00110">CicmMetadataBlock::length</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="a796034966c1e918152e652635431dc39" name="a796034966c1e918152e652635431dc39"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a796034966c1e918152e652635431dc39">&#9670;&#160;</a></span>write_dumphw_block()</h2>
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_dumphw_block </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the dump hardware block containing acquisition environment information. </p>
<p>This function writes a DumpHardwareBlock to the image file, documenting the hardware and software environments used to create the image. A dump hardware block records one or more "dump environments" typically combinations of physical devices (drives, controllers, adapters) and the software stacks that performed the read operations. This metadata is essential for understanding the imaging context, validating acquisition integrity, reproducing imaging conditions, and supporting forensic or archival documentation requirements.</p>
<p>Each environment entry includes hardware identification (manufacturer, model, revision, firmware, serial number), software identification (name, version, operating system), and optional extent ranges that specify which logical sectors or units were contributed by that particular environment. This structure supports complex imaging scenarios where multiple devices or software configurations were used to create a composite image.</p>
<p>The dump hardware block is optional; if no dump hardware information has been populated (dumpHardwareEntriesWithData is NULL, entries count is zero, or identifier is not set to DumpHardwareBlock), the function returns immediately without writing anything. This no-op behavior allows the close operation to proceed gracefully whether or not dump hardware metadata was included during image creation.</p>
<p><b>Block structure:</b> The serialized block consists of:</p><ol type="1">
<li><a class="el" href="structDumpHardwareHeader.html" title="Header that precedes a sequence of dump hardware entries and their variable-length payload.">DumpHardwareHeader</a> (16 bytes: identifier, entries count, payload length, CRC64)</li>
<li>For each dump hardware entry (variable size):<ul>
<li><a class="el" href="structDumpHardwareEntry.html" title="Per-environment length table describing subsequent UTF-8 strings and optional extent array.">DumpHardwareEntry</a> (36 bytes: length fields for all strings and extent count)</li>
<li>Variable-length UTF-8 strings in order: manufacturer, model, revision, firmware, serial, software name, software version, software operating system</li>
<li>Array of <a class="el" href="structDumpExtent.html" title="Inclusive [start,end] logical sector range contributed by a single hardware environment.">DumpExtent</a> structures (16 bytes each) if extent count &gt; 0</li>
</ul>
</li>
</ol>
<p>All strings are UTF-8 encoded and NOT null-terminated in the serialized block. String lengths are measured in bytes, not character counts.</p>
<p><b>Serialization process:</b></p><ol type="1">
<li>Allocate a temporary buffer sized to hold the complete block (header + all payload data)</li>
<li>Iterate through all dump hardware entries in ctx-&gt;dumpHardwareEntriesWithData</li>
<li>For each entry, copy the <a class="el" href="structDumpHardwareEntry.html" title="Per-environment length table describing subsequent UTF-8 strings and optional extent array.">DumpHardwareEntry</a> structure followed by each non-NULL string (only if the corresponding length &gt; 0), then copy the extent array (if extents &gt; 0)</li>
<li>Calculate CRC64-ECMA over the payload (everything after the header)</li>
<li>Copy the <a class="el" href="structDumpHardwareHeader.html" title="Header that precedes a sequence of dump hardware entries and their variable-length payload.">DumpHardwareHeader</a> with calculated CRC64 to the beginning of the buffer</li>
<li>Align file position to block boundary</li>
<li>Write the complete buffer to the image file</li>
<li>Add index entry on successful write</li>
<li>Free the temporary buffer</li>
</ol>
<p><b>Alignment and file positioning:</b> Before writing the block, the file position is moved to EOF and then aligned forward to the next boundary satisfying (position &amp; alignment_mask) == 0, where alignment_mask is derived from ctx-&gt;userDataDdtHeader.blockAlignmentShift. This ensures the dump hardware block begins on a properly aligned offset for efficient I/O and compliance with the Aaru format specification.</p>
<p><b>CRC64 calculation:</b> The function calculates CRC64-ECMA over the payload portion of the buffer (everything after the <a class="el" href="structDumpHardwareHeader.html" title="Header that precedes a sequence of dump hardware entries and their variable-length payload.">DumpHardwareHeader</a>) and stores it in the header before writing. This checksum allows verification of dump hardware block integrity when reading the image.</p>
<p><b>Index registration:</b> After successfully writing the complete block, an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> is appended to ctx-&gt;indexEntries with:</p><ul>
<li>blockType = DumpHardwareBlock</li>
<li>dataType = 0 (dump hardware blocks have no subtype)</li>
<li>offset = the aligned file position where the block was written</li>
</ul>
<p><b>Error handling:</b> Memory allocation failures (calloc returning NULL) cause immediate return without writing. Bounds checking is performed during serialization; if calculated entry sizes exceed the allocated buffer, the buffer is freed and the function returns without writing. Write errors (fwrite returning &lt; 1) are silently ignored; no index entry is added if the write fails. Diagnostic TRACE logs report success or failure. The function does not propagate error codes; higher-level close logic must validate overall integrity if needed.</p>
<p><b>No-op conditions:</b></p><ul>
<li>ctx-&gt;dumpHardwareEntriesWithData is NULL (no hardware data loaded) OR</li>
<li>ctx-&gt;dumpHardwareHeader.entries == 0 (no entries to write) OR</li>
<li>ctx-&gt;dumpHardwareHeader.identifier != DumpHardwareBlock (block not properly initialized)</li>
</ul>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. Must not be NULL. ctx-&gt;dumpHardwareHeader contains the header with identifier, entry count, and total payload length. ctx-&gt;dumpHardwareEntriesWithData contains the array of dump hardware entries with their associated string data and extents (may be NULL if no dump hardware was added). ctx-&gt;imageStream must be open and writable. ctx-&gt;indexEntries must be initialized (utarray) to accept new index entries.</td></tr>
</table>
</dd>
</dl>
<dl class="section note"><dt>Note</dt><dd>Dump Hardware Environments:<ul>
<li>Each entry represents one hardware/software combination used during imaging</li>
<li>Multiple entries support scenarios where different devices contributed different sectors</li>
<li>Extent arrays specify which logical sector ranges each environment contributed</li>
<li>Empty extent arrays (extents == 0) indicate the environment dumped the entire medium</li>
<li>Overlapping extents between entries may indicate verification passes or redundancy</li>
</ul>
</dd>
<dd>
Hardware Identification Fields:<ul>
<li>manufacturer: Device manufacturer (e.g., "Plextor", "Sony", "Samsung")</li>
<li>model: Device model number (e.g., "PX-716A", "DRU-820A")</li>
<li>revision: Hardware revision identifier</li>
<li>firmware: Firmware version (e.g., "1.11", "KY08")</li>
<li>serial: Device serial number for unique identification</li>
</ul>
</dd>
<dd>
Software Identification Fields:<ul>
<li>softwareName: Dumping software name (e.g., "Aaru", "ddrescue", "IsoBuster")</li>
<li>softwareVersion: Software version (e.g., "5.3.0", "1.25")</li>
<li>softwareOperatingSystem: Host OS (e.g., "Linux 5.10.0", "Windows 10", "macOS 12.0")</li>
</ul>
</dd>
<dd>
String Encoding:<ul>
<li>All strings are UTF-8 encoded</li>
<li>Strings are NOT null-terminated in the serialized block</li>
<li>String lengths in <a class="el" href="structDumpHardwareEntry.html" title="Per-environment length table describing subsequent UTF-8 strings and optional extent array.">DumpHardwareEntry</a> are in bytes, not character counts</li>
<li>The library maintains null-terminated strings in memory for convenience</li>
<li>Only non-null-terminated data is written to the file</li>
</ul>
</dd>
<dd>
Memory Management:<ul>
<li>The function allocates a temporary buffer to serialize the entire block</li>
<li>The buffer is freed before the function returns, regardless of success or failure</li>
<li>The source data in ctx-&gt;dumpHardwareEntriesWithData is not modified</li>
<li>The source data is freed later during context cleanup (aaruf_close)</li>
</ul>
</dd>
<dd>
Use Cases:<ul>
<li>Forensic documentation requiring complete equipment chain of custody</li>
<li>Archival metadata for long-term preservation requirements</li>
<li>Reproducing imaging conditions for verification or re-imaging</li>
<li>Identifying firmware-specific issues or drive-specific behaviors</li>
<li>Multi-device imaging scenario documentation</li>
<li>Correlating imaging artifacts with specific hardware/software combinations</li>
</ul>
</dd>
<dd>
Order in Close Sequence:<ul>
<li>Dump hardware blocks are typically written after sector data but before metadata blocks</li>
<li>The exact position in the file depends on what other blocks precede it</li>
<li>The index entry ensures the dump hardware block can be located during subsequent opens</li>
</ul>
</dd></dl>
<dl class="section warning"><dt>Warning</dt><dd>The temporary buffer allocation may fail on systems with limited memory or when the dump hardware block is extremely large (many entries with long strings and extents). Allocation failures result in silent no-op; the image is created without dump hardware.</dd>
<dd>
Bounds checking during serialization protects against buffer overruns. If calculated entry sizes exceed the allocated buffer length (which should never occur if the header's length field is correct), the function aborts without writing. This is a sanity check against data corruption.</dd></dl>
<dl class="section see"><dt>See also</dt><dd><a class="el" href="structDumpHardwareHeader.html" title="Header that precedes a sequence of dump hardware entries and their variable-length payload.">DumpHardwareHeader</a> for the block header structure definition. </dd>
<dd>
<a class="el" href="structDumpHardwareEntry.html" title="Per-environment length table describing subsequent UTF-8 strings and optional extent array.">DumpHardwareEntry</a> for the per-environment entry structure definition. </dd>
<dd>
<a class="el" href="structDumpExtent.html" title="Inclusive [start,end] logical sector range contributed by a single hardware environment.">DumpExtent</a> for the extent range structure definition. </dd>
<dd>
<a class="el" href="decls_8h.html#a36af83897e131ba792c51ae8caec9984" title="Retrieves the dump hardware block containing acquisition environment information.">aaruf_get_dumphw()</a> for retrieving dump hardware from opened images. </dd>
<dd>
<a class="el" href="internal_8h.html#a0e2cfc858c0551bc9bef11d5bdb85aac" title="Processes a dump hardware block from the image stream.">process_dumphw_block()</a> for the loading process during image opening. </dd></dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l03506">3506</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00160">aaruf_crc64_data()</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="dump_8h_source.html#l00095">DumpHardwareHeader::crc64</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="context_8h_source.html#l00212">aaruformat_context::dump_hardware_entries_with_data</a>, <a class="el" href="context_8h_source.html#l00232">aaruformat_context::dump_hardware_header</a>, <a class="el" href="enums_8h_source.html#l00156">DumpHardwareBlock</a>, <a class="el" href="dump_8h_source.html#l00093">DumpHardwareHeader::entries</a>, <a class="el" href="context_8h_source.html#l00341">DumpHardwareEntriesWithData::entry</a>, <a class="el" href="context_8h_source.html#l00342">DumpHardwareEntriesWithData::extents</a>, <a class="el" href="dump_8h_source.html#l00122">DumpHardwareEntry::extents</a>, <a class="el" href="log_8h_source.html#l00040">FATAL</a>, <a class="el" href="context_8h_source.html#l00346">DumpHardwareEntriesWithData::firmware</a>, <a class="el" href="dump_8h_source.html#l00117">DumpHardwareEntry::firmwareLength</a>, <a class="el" href="dump_8h_source.html#l00092">DumpHardwareHeader::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="dump_8h_source.html#l00094">DumpHardwareHeader::length</a>, <a class="el" href="context_8h_source.html#l00343">DumpHardwareEntriesWithData::manufacturer</a>, <a class="el" href="dump_8h_source.html#l00114">DumpHardwareEntry::manufacturerLength</a>, <a class="el" href="context_8h_source.html#l00344">DumpHardwareEntriesWithData::model</a>, <a class="el" href="dump_8h_source.html#l00115">DumpHardwareEntry::modelLength</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="context_8h_source.html#l00345">DumpHardwareEntriesWithData::revision</a>, <a class="el" href="dump_8h_source.html#l00116">DumpHardwareEntry::revisionLength</a>, <a class="el" href="context_8h_source.html#l00347">DumpHardwareEntriesWithData::serial</a>, <a class="el" href="dump_8h_source.html#l00118">DumpHardwareEntry::serialLength</a>, <a class="el" href="context_8h_source.html#l00348">DumpHardwareEntriesWithData::softwareName</a>, <a class="el" href="dump_8h_source.html#l00119">DumpHardwareEntry::softwareNameLength</a>, <a class="el" href="context_8h_source.html#l00350">DumpHardwareEntriesWithData::softwareOperatingSystem</a>, <a class="el" href="dump_8h_source.html#l00121">DumpHardwareEntry::softwareOperatingSystemLength</a>, <a class="el" href="context_8h_source.html#l00349">DumpHardwareEntriesWithData::softwareVersion</a>, <a class="el" href="dump_8h_source.html#l00120">DumpHardwareEntry::softwareVersionLength</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="a13f6c475294969c1eb8c59ff53c91af9" name="a13f6c475294969c1eb8c59ff53c91af9"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a13f6c475294969c1eb8c59ff53c91af9">&#9670;&#160;</a></span>write_dvd_long_sector_blocks()</h2>
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">void write_dvd_long_sector_blocks </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize DVD long sector auxiliary data blocks to the image file. </p>
<p>This function writes four separate data blocks containing DVD-specific auxiliary information extracted from "long" DVD sectors. DVD long sectors contain additional fields beyond the 2048 bytes of user data, including sector identification, error detection, and copy protection information. When writing DVD images with long sector support, these auxiliary fields are stored separately from the main user data to optimize storage and enable selective access.</p>
<p>The function is only invoked if all four auxiliary buffers have been populated during image creation (sector_id, sector_ied, sector_cpr_mai, sector_edc). If any buffer is NULL, the function returns immediately without writing anything, allowing DVD images without long sector data to be created normally.</p>
<p><b>Four auxiliary data blocks written:</b></p>
<ol type="1">
<li><b>DVD Sector ID Block (DvdSectorId)</b>: 4 bytes per sector<ul>
<li>Contains the sector ID field from DVD long sectors</li>
<li>Used for sector identification and addressing validation</li>
</ul>
</li>
<li><b>DVD Sector IED Block (DvdSectorIed)</b>: 2 bytes per sector<ul>
<li>Contains the IED (ID Error Detection) field from DVD long sectors</li>
<li>Used for detecting errors in the sector ID field</li>
</ul>
</li>
<li><b>DVD Sector CPR/MAI Block (DvdSectorCprMai)</b>: 6 bytes per sector<ul>
<li>Contains the CPR_MAI (Copyright Management Information) field</li>
<li>Used for copy protection and media authentication information</li>
</ul>
</li>
<li><b>DVD Sector EDC Block (DvdSectorEdc)</b>: 4 bytes per sector<ul>
<li>Contains the EDC (Error Detection Code) field from DVD long sectors</li>
<li>Used for detecting errors in the sector data</li>
</ul>
</li>
</ol>
<p><b>Block structure for each auxiliary block:</b> Each block consists of:</p><ol type="1">
<li><a class="el" href="structBlockHeader.html" title="Header preceding the compressed data payload of a data block (BlockType::DataBlock).">BlockHeader</a> containing identifier (DataBlock), type (DvdSectorId/IED/CprMai/Edc), compression (None), lengths, and CRC64 checksums</li>
<li>Raw auxiliary data: concatenated fields from all sectors (including negative, normal, and overflow sectors)</li>
</ol>
<p>The total number of sectors includes negative sectors (for lead-in), normal image sectors, and overflow sectors (for lead-out), calculated as: total_sectors = negative + Sectors + overflow</p>
<p><b>Write sequence for each block:</b></p><ol type="1">
<li>Seek to end of file</li>
<li>Align file position to block boundary (using blockAlignmentShift)</li>
<li>Construct <a class="el" href="structBlockHeader.html" title="Header preceding the compressed data payload of a data block (BlockType::DataBlock).">BlockHeader</a> with appropriate type and calculated length</li>
<li>Calculate CRC64 over the auxiliary data buffer</li>
<li>Write <a class="el" href="structBlockHeader.html" title="Header preceding the compressed data payload of a data block (BlockType::DataBlock).">BlockHeader</a> (sizeof(BlockHeader) bytes)</li>
<li>Write auxiliary data buffer (length bytes)</li>
<li>On success, add <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> to ctx-&gt;indexEntries</li>
</ol>
<p><b>Alignment and file positioning:</b> Before writing each block, the file position is moved to EOF and then aligned forward to the next boundary satisfying (position &amp; alignment_mask) == 0, where alignment_mask is derived from ctx-&gt;userDataDdtHeader.blockAlignmentShift. This ensures all blocks begin on properly aligned offsets for efficient I/O and compliance with the Aaru format specification.</p>
<p><b>Index registration:</b> After successfully writing each block's header and data, an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> is appended to ctx-&gt;indexEntries with:</p><ul>
<li>blockType = DataBlock</li>
<li>dataType = DvdSectorId, DvdSectorIed, DvdSectorCprMai, or DvdSectorEdc</li>
<li>offset = the aligned file position where the <a class="el" href="structBlockHeader.html" title="Header preceding the compressed data payload of a data block (BlockType::DataBlock).">BlockHeader</a> was written</li>
</ul>
<p><b>Error handling:</b> Write errors (fwrite returning &lt; 1) are silently ignored for individual blocks; no index entry is added if a write fails, but iteration continues to attempt writing remaining blocks. Diagnostic TRACE logs report success or failure for each block. The function does not propagate error codes; higher-level close logic must validate overall integrity if needed.</p>
<p><b>No-op conditions:</b> If any of the four auxiliary buffers is NULL, the function returns immediately without writing anything. This is an all-or-nothing operation - either all four blocks are written or none.</p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. Must not be NULL. ctx-&gt;sector_id contains the ID fields from all DVD long sectors (may be NULL). ctx-&gt;sector_ied contains the IED fields from all DVD long sectors (may be NULL). ctx-&gt;sector_cpr_mai contains the CPR/MAI fields from all DVD long sectors (may be NULL). ctx-&gt;sector_edc contains the EDC fields from all DVD long sectors (may be NULL). ctx-&gt;imageStream must be open and writable. ctx-&gt;indexEntries must be initialized (utarray) to accept new index entries.</td></tr>
</table>
</dd>
</dl>
<dl class="section note"><dt>Note</dt><dd>DVD Long Sector Format:<ul>
<li>Standard DVD sectors contain 2048 bytes of user data</li>
<li>Long DVD sectors include additional fields for error detection and copy protection</li>
<li>Total long sector size varies by DVD format (typically 2064-2076 bytes)</li>
<li>These auxiliary fields are critical for forensic imaging and copy-protected media</li>
</ul>
</dd>
<dd>
Sector Coverage:<ul>
<li>Negative sectors: Lead-in area before sector 0 (if present)</li>
<li>Normal sectors: Main data area (sectors 0 to Sectors-1)</li>
<li>Overflow sectors: Lead-out area after the main data (if present)</li>
<li>All three areas are included in the auxiliary data blocks</li>
</ul>
</dd>
<dd>
Field Sizes:<ul>
<li>ID field: 4 bytes per sector (sector identification)</li>
<li>IED field: 2 bytes per sector (ID error detection)</li>
<li>CPR/MAI field: 6 bytes per sector (copyright management)</li>
<li>EDC field: 4 bytes per sector (error detection code)</li>
<li>Total auxiliary data: 16 bytes per sector across all four blocks</li>
</ul>
</dd>
<dd>
Memory Management:<ul>
<li>The function allocates temporary buffers for compression when enabled</li>
<li>Auxiliary data buffers are managed by the caller</li>
<li>Compression buffers are freed after each block is written</li>
<li>Source data memory is freed later during context cleanup (aaruf_close)</li>
</ul>
</dd>
<dd>
Use Cases:<ul>
<li>Forensic imaging of DVD media requiring complete sector data</li>
<li>Preservation of copy-protected DVD content</li>
<li>Analysis of DVD error detection and correction information</li>
<li>Validation of DVD sector structure and integrity</li>
<li>Research into DVD copy protection mechanisms</li>
</ul>
</dd>
<dd>
Order in Close Sequence:<ul>
<li>DVD long sector blocks are typically written after user data but before metadata</li>
<li>The exact position in the file depends on what other blocks precede them</li>
<li>Index entries ensure blocks can be located during subsequent opens</li>
<li>All four blocks are written consecutively if present</li>
</ul>
</dd></dl>
<dl class="section warning"><dt>Warning</dt><dd>The auxiliary data buffers must contain data for ALL sectors (negative + normal + overflow). Partial buffers or mismatched sizes will cause incorrect data to be written or buffer overruns.</dd>
<dd>
Compression is applied if enabled. The blocks may be stored compressed or uncompressed depending on the compression_enabled setting and compression effectiveness.</dd>
<dd>
If any of the four auxiliary buffers is NULL, the entire function is skipped. This is an all-or-nothing operation - either all four blocks are written or none.</dd></dl>
<dl class="section see"><dt>See also</dt><dd><a class="el" href="decls_8h.html#a69ca66242c0becf7640b3d1cc8da8f9c" title="Writes a full (&quot;long&quot;) raw sector from optical or block media, parsing structure and validating conte...">aaruf_write_sector_long()</a> for writing individual DVD long sectors that populate these buffers. </dd>
<dd>
<a class="el" href="structBlockHeader.html" title="Header preceding the compressed data payload of a data block (BlockType::DataBlock).">BlockHeader</a> for the block header structure definition. </dd></dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l01851">1851</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00160">aaruf_crc64_data()</a>, <a class="el" href="lzma_8c_source.html#l00065">aaruf_lzma_encode_buffer()</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="data_8h_source.html#l00078">BlockHeader::cmpCrc64</a>, <a class="el" href="data_8h_source.html#l00076">BlockHeader::cmpLength</a>, <a class="el" href="data_8h_source.html#l00074">BlockHeader::compression</a>, <a class="el" href="context_8h_source.html#l00300">aaruformat_context::compression_enabled</a>, <a class="el" href="data_8h_source.html#l00079">BlockHeader::crc64</a>, <a class="el" href="enums_8h_source.html#l00141">DataBlock</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="enums_8h_source.html#l00126">DvdSectorCprMai</a>, <a class="el" href="enums_8h_source.html#l00130">DvdSectorEdc</a>, <a class="el" href="enums_8h_source.html#l00128">DvdSectorId</a>, <a class="el" href="enums_8h_source.html#l00129">DvdSectorIed</a>, <a class="el" href="data_8h_source.html#l00072">BlockHeader::identifier</a>, <a class="el" href="context_8h_source.html#l00260">aaruformat_context::image_info</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="data_8h_source.html#l00077">BlockHeader::length</a>, <a class="el" href="enums_8h_source.html#l00034">Lzma</a>, <a class="el" href="context_8h_source.html#l00298">aaruformat_context::lzma_dict_size</a>, <a class="el" href="consts_8h_source.html#l00082">LZMA_PROPERTIES_LENGTH</a>, <a class="el" href="ddt_8h_source.html#l00149">DdtHeader2::negative</a>, <a class="el" href="enums_8h_source.html#l00033">None</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="ddt_8h_source.html#l00151">DdtHeader2::overflow</a>, <a class="el" href="context_8h_source.html#l00207">aaruformat_context::sector_cpr_mai</a>, <a class="el" href="context_8h_source.html#l00208">aaruformat_context::sector_edc</a>, <a class="el" href="context_8h_source.html#l00205">aaruformat_context::sector_id</a>, <a class="el" href="context_8h_source.html#l00206">aaruformat_context::sector_ied</a>, <a class="el" href="aaru_8h_source.html#l00926">ImageInfo::Sectors</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="data_8h_source.html#l00073">BlockHeader::type</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
2025-12-12 12:25:02 +00:00
<a id="a5e2cce0d9661697c767d9312224fd340" name="a5e2cce0d9661697c767d9312224fd340"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a5e2cce0d9661697c767d9312224fd340">&#9670;&#160;</a></span>write_dvd_title_key_decrypted_block()</h2>
2025-10-11 01:35:43 +01:00
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_dvd_title_key_decrypted_block </td>
<td>(</td>
2025-12-12 12:25:02 +00:00
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
2025-10-11 01:35:43 +01:00
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the DVD decrypted title key data block to the image file. </p>
<p>This function writes a data block containing decrypted DVD title keys for all sectors in the image. DVD title keys are used in the Content Scrambling System (CSS) encryption scheme to decrypt sector data on encrypted DVDs. When imaging encrypted DVD media, if the decryption keys are available, they can be stored alongside the encrypted data to enable future decryption without requiring the original disc or authentication process.</p>
<p>The function is only invoked if the decrypted title key buffer has been populated during image creation (ctx-&gt;sector_decrypted_title_key != NULL). If the buffer is NULL, the function returns immediately without writing anything, allowing DVD images without decrypted title keys to be created normally. This is typical for non-encrypted DVDs or when keys were not available during imaging.</p>
<p><b>Data block structure:</b></p>
<ul>
<li><b>Block Type</b>: DataBlock with type DvdSectorTitleKeyDecrypted</li>
<li><b>Size</b>: 5 bytes per sector (total_sectors × 5 bytes)<ul>
<li>total_sectors = negative sectors + user sectors + overflow sectors</li>
</ul>
</li>
<li><b>Compression</b>: Applied if enabled (LZMA compression)</li>
<li><b>CRC64</b>: Computed over the decrypted title key buffer</li>
<li><b>Alignment</b>: Block-aligned according to ctx-&gt;userDataDdtHeader.blockAlignmentShift</li>
</ul>
<p><b>Block write sequence:</b></p>
<ol type="1">
<li>Check if ctx-&gt;sector_decrypted_title_key is NULL; return early if so</li>
<li>Seek to end of file to determine write position</li>
<li>Align file position forward to next block boundary (if needed)</li>
<li>Construct <a class="el" href="structBlockHeader.html" title="Header preceding the compressed data payload of a data block (BlockType::DataBlock).">BlockHeader</a> with:<ul>
<li>identifier = DataBlock</li>
<li>type = DvdSectorTitleKeyDecrypted</li>
<li>compression = ctx-&gt;compression_enabled ? Lzma : None</li>
<li>length = (negative + sectors + overflow) × 5</li>
<li>cmpLength = compressed size or original size if compression not effective</li>
<li>crc64 = CRC64 of original key buffer</li>
<li>cmpCrc64 = CRC64 of compressed data or same as crc64 if uncompressed</li>
</ul>
</li>
<li>Write <a class="el" href="structBlockHeader.html" title="Header preceding the compressed data payload of a data block (BlockType::DataBlock).">BlockHeader</a> (sizeof(BlockHeader) bytes)</li>
<li>Write LZMA properties if compressed (LZMA_PROPERTIES_LENGTH bytes)</li>
<li>Write decrypted title key data buffer (compressed or uncompressed)</li>
<li>Create and append <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> to ctx-&gt;indexEntries:<ul>
<li>blockType = DataBlock</li>
<li>dataType = DvdSectorTitleKeyDecrypted</li>
<li>offset = aligned block position</li>
</ul>
</li>
</ol>
<p><b>Alignment and file positioning:</b></p>
<p>Before writing the block, the file position is moved to EOF and then aligned forward to the next boundary satisfying (position &amp; alignment_mask) == 0, where alignment_mask is derived from the blockAlignmentShift. This ensures that all structural blocks begin on properly aligned offsets for efficient I/O and compliance with the Aaru format specification.</p>
<p><b>Index registration:</b></p>
<p>After successful write, an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> is created and added to ctx-&gt;indexEntries using utarray_push_back(). This allows the block to be located efficiently during image reading via the index lookup mechanism. The index stores the exact file offset where the <a class="el" href="structBlockHeader.html" title="Header preceding the compressed data payload of a data block (BlockType::DataBlock).">BlockHeader</a> was written.</p>
<p><b>Title Key Format:</b></p>
<p>Each sector's title key is exactly 5 bytes. The keys are stored sequentially in sector order (negative sectors first, then user sectors, then overflow sectors). The corrected sector addressing scheme is used to index into the buffer:</p><ul>
<li>Negative sector N: index = (N - negative)</li>
<li>User sector U: index = (negative + U)</li>
<li>Overflow sector O: index = (negative + Sectors + O)</li>
</ul>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode.</td></tr>
</table>
</dd>
</dl>
<dl class="section note"><dt>Note</dt><dd>This is a static helper function called during image finalization (aaruf_close). It is not part of the public API.</dd>
<dd>
The function performs no error handling beyond checking for NULL buffer. Write failures are silently ignored, consistent with other optional metadata serialization routines in the finalization sequence.</dd>
<dd>
Decrypted title keys are sensitive cryptographic material. Applications should consider access control and security implications when storing and distributing images containing decrypted keys.</dd>
<dd>
The function uses <a class="el" href="log_8h.html#a21cc0459b78d5f2d7bd737e5aae1278a">TRACE()</a> macros for diagnostic logging of write progress, file positions, and index entry creation.</dd></dl>
<dl class="section warning"><dt>Warning</dt><dd>This function assumes ctx-&gt;imageStream is open and writable. Calling it with a read-only or closed stream will result in undefined behavior.</dd>
<dd>
The function does not validate that ctx-&gt;sector_decrypted_title_key contains exactly (negative + sectors + overflow) × 5 bytes. Buffer overruns may occur if the buffer was improperly allocated.</dd>
<dd>
Do not call this function directly. It is invoked automatically by <a class="el" href="#a6823e139f81a9dfd08efcb0e9b213a49" title="Close an Aaru image context, flushing pending data structures and releasing resources.">aaruf_close()</a> as part of the image finalization sequence. </dd></dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l02296">2296</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00160">aaruf_crc64_data()</a>, <a class="el" href="lzma_8c_source.html#l00065">aaruf_lzma_encode_buffer()</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="data_8h_source.html#l00078">BlockHeader::cmpCrc64</a>, <a class="el" href="data_8h_source.html#l00076">BlockHeader::cmpLength</a>, <a class="el" href="data_8h_source.html#l00074">BlockHeader::compression</a>, <a class="el" href="context_8h_source.html#l00300">aaruformat_context::compression_enabled</a>, <a class="el" href="data_8h_source.html#l00079">BlockHeader::crc64</a>, <a class="el" href="enums_8h_source.html#l00141">DataBlock</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="enums_8h_source.html#l00127">DvdSectorTitleKeyDecrypted</a>, <a class="el" href="data_8h_source.html#l00072">BlockHeader::identifier</a>, <a class="el" href="context_8h_source.html#l00260">aaruformat_context::image_info</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="data_8h_source.html#l00077">BlockHeader::length</a>, <a class="el" href="enums_8h_source.html#l00034">Lzma</a>, <a class="el" href="context_8h_source.html#l00298">aaruformat_context::lzma_dict_size</a>, <a class="el" href="consts_8h_source.html#l00082">LZMA_PROPERTIES_LENGTH</a>, <a class="el" href="ddt_8h_source.html#l00149">DdtHeader2::negative</a>, <a class="el" href="enums_8h_source.html#l00033">None</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="ddt_8h_source.html#l00151">DdtHeader2::overflow</a>, <a class="el" href="context_8h_source.html#l00209">aaruformat_context::sector_decrypted_title_key</a>, <a class="el" href="aaru_8h_source.html#l00926">ImageInfo::Sectors</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="data_8h_source.html#l00073">BlockHeader::type</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
2025-12-12 12:25:02 +00:00
<a id="ada8f13126103c0077ddcf5e6120aea53" name="ada8f13126103c0077ddcf5e6120aea53"></a>
<h2 class="memtitle"><span class="permalink"><a href="#ada8f13126103c0077ddcf5e6120aea53">&#9670;&#160;</a></span>write_geometry_block()</h2>
2025-10-11 01:35:43 +01:00
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_geometry_block </td>
<td>(</td>
2025-12-12 12:25:02 +00:00
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
2025-10-11 01:35:43 +01:00
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the geometry metadata block to the image file. </p>
<p>This function writes a <a class="el" href="structGeometryBlockHeader.html" title="Legacy CHS style logical geometry metadata (BlockType::GeometryBlock).">GeometryBlockHeader</a> containing legacy CHS (Cylinder-Head-Sector) style logical geometry metadata to the Aaru image file. The geometry block records the physical/logical layout of media that can be addressed using classical CHS parameters (cylinders, heads, sectors per track) common to legacy hard disk drives and some optical media formats.</p>
<p>The geometry information is optional; if no geometry metadata was previously set (detected by checking ctx-&gt;geometryBlock.identifier != GeometryBlock), the function returns immediately as a no-op. When present, the block is written at the end of the image file, aligned to the DDT block boundary specified by blockAlignmentShift, and an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> is appended to ctx-&gt;indexEntries so readers can locate it during image parsing.</p>
<p>Block layout:</p><ul>
<li><a class="el" href="structGeometryBlockHeader.html" title="Legacy CHS style logical geometry metadata (BlockType::GeometryBlock).">GeometryBlockHeader</a> (16 bytes):<ul>
<li>identifier (4 bytes): BlockType::GeometryBlock magic constant</li>
<li>cylinders (4 bytes): Number of cylinders</li>
<li>heads (4 bytes): Number of heads (tracks per cylinder)</li>
<li>sectorsPerTrack (4 bytes): Number of sectors per track</li>
</ul>
</li>
<li>No additional payload follows the header in current format versions.</li>
</ul>
<p>Total logical sectors implied by the geometry: cylinders × heads × sectorsPerTrack. Sector size is not encoded in this block and must be derived from other metadata (e.g., from the media type or explicitly stored elsewhere in the image).</p>
<p>Alignment strategy:</p><ul>
<li>The write position is obtained via fseek(SEEK_END) + ftell().</li>
<li>If the position is not aligned to (1 &lt;&lt; blockAlignmentShift), it is advanced to the next aligned boundary by computing: (position + alignment_mask) &amp; ~alignment_mask.</li>
<li>This ensures the geometry block starts on a block-aligned offset for efficient access.</li>
</ul>
<p>Error handling:</p><ul>
<li>If fwrite() fails to write the <a class="el" href="structGeometryBlockHeader.html" title="Legacy CHS style logical geometry metadata (BlockType::GeometryBlock).">GeometryBlockHeader</a>, the function silently returns without updating the index. This is consistent with other optional metadata writers in this module that use opportunistic writes (failures logged via TRACE but not propagated as errors).</li>
<li>The caller (aaruf_close) will continue finalizing other blocks even if geometry write fails.</li>
</ul>
<p>Indexing:</p><ul>
<li>On successful write, an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> with blockType = GeometryBlock, dataType = 0, and offset = block_position is pushed to ctx-&gt;indexEntries.</li>
<li>The index will be serialized later by <a class="el" href="#a3532372fac3d5bb2619900820a26632e" title="Serialize the accumulated index entries at the end of the image and back-patch the header.">write_index_block()</a> and allows readers to quickly locate the geometry metadata without scanning the entire file.</li>
</ul>
<p>Use cases:</p><ul>
<li>Preserving original CHS geometry for disk images from legacy systems (e.g., IDE/PATA drives, floppy disks, early SCSI devices) where BIOS or firmware relied on CHS addressing.</li>
<li>Documenting physical layout of optical media that may have track/sector organization.</li>
<li>Supporting forensic/archival workflows that need complete metadata fidelity.</li>
</ul>
<p>Thread safety: This function is not thread-safe; it modifies shared ctx state (imageStream file position, indexEntries array) and must only be called during single-threaded finalization (within aaruf_close).</p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. Must not be NULL. The geometryBlock field must be pre-populated if geometry metadata is desired. The imageStream must be open and writable. </td></tr>
</table>
</dd>
</dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l03083">3083</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="context_8h_source.html#l00229">aaruformat_context::geometry_block</a>, <a class="el" href="enums_8h_source.html#l00148">GeometryBlock</a>, <a class="el" href="data_8h_source.html#l00092">GeometryBlockHeader::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="a3532372fac3d5bb2619900820a26632e" name="a3532372fac3d5bb2619900820a26632e"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a3532372fac3d5bb2619900820a26632e">&#9670;&#160;</a></span>write_index_block()</h2>
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">int32_t write_index_block </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the accumulated index entries at the end of the image and back-patch the header. </p>
<p>All previously written structural blocks push their <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> into ctx-&gt;indexEntries. This function collects them, writes an <a class="el" href="structIndexHeader3.html" title="Index header (version 3) adding hierarchical chaining (identifier == IndexBlock3).">IndexHeader3</a> followed by each <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a>, computes CRC64 over the entries, and then updates the main <a class="el" href="structAaruHeaderV2.html" title="Version 2 container header with GUID, alignment shifts, and feature negotiation bitmaps.">AaruHeaderV2</a> (at offset 0) with the index offset. The index itself is aligned to the DDT block boundary. No previous index chaining is currently implemented (index_header.previous = 0).</p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. </td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>AARUF_STATUS_OK on success; AARUF_ERROR_CANNOT_WRITE_HEADER if the index header, any entry, or the header back-patch fails. </dd></dl>
<dl class="retval"><dt>Return values</dt><dd>
<table class="retval">
<tr><td class="paramname">AARUF_STATUS_OK</td><td>Index written and header updated. </td></tr>
<tr><td class="paramname">AARUF_ERROR_CANNOT_WRITE_HEADER</td><td>Failed writing index header, entries, or updating main header. </td></tr>
</table>
</dd>
</dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l03926">3926</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00141">aaruf_crc64_final()</a>, <a class="el" href="crc64_8c_source.html#l00032">aaruf_crc64_init()</a>, <a class="el" href="crc64_8c_source.html#l00055">aaruf_crc64_update()</a>, <a class="el" href="errors_8h_source.html#l00060">AARUF_ERROR_CANNOT_WRITE_HEADER</a>, <a class="el" href="errors_8h_source.html#l00075">AARUF_STATUS_OK</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="index_8h_source.html#l00096">IndexHeader3::crc64</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="index_8h_source.html#l00095">IndexHeader3::entries</a>, <a class="el" href="context_8h_source.html#l00175">aaruformat_context::header</a>, <a class="el" href="index_8h_source.html#l00094">IndexHeader3::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="enums_8h_source.html#l00147">IndexBlock3</a>, <a class="el" href="header_8h_source.html#l00115">AaruHeaderV2::indexOffset</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="index_8h_source.html#l00097">IndexHeader3::previous</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
2025-12-12 12:25:02 +00:00
<a id="a3decc41ec145e8b153a23de6389b3782" name="a3decc41ec145e8b153a23de6389b3782"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a3decc41ec145e8b153a23de6389b3782">&#9670;&#160;</a></span>write_media_tags()</h2>
2025-10-11 01:35:43 +01:00
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_media_tags </td>
<td>(</td>
2025-12-12 12:25:02 +00:00
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
2025-10-11 01:35:43 +01:00
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize all accumulated media tags to the image file. </p>
<p>Media tags represent arbitrary metadata or descriptor blobs associated with the entire medium (as opposed to per-sector or per-track metadata). Examples include proprietary drive firmware information, TOC descriptors, ATIP data, PMA/Lead-in content, or manufacturer-specific binary structures that do not fit the standard track or sector model. Each tag is identified by a numeric type field interpreted by upper layers or external tooling.</p>
<p>This function traverses the ctx-&gt;mediaTags hash table (keyed by tag type) using HASH_ITER and writes each tag as an independent DataBlock. Each block is:</p><ul>
<li>Aligned to the DDT block boundary (controlled by ctx-&gt;userDataDdtHeader.blockAlignmentShift)</li>
<li>Prefixed with a <a class="el" href="structBlockHeader.html" title="Header preceding the compressed data payload of a data block (BlockType::DataBlock).">BlockHeader</a> containing the identifier DataBlock and a data type derived from the tag's type field via <a class="el" href="decls_8h.html#a8d042b26980b56b5dd872f21fa33de70" title="Converts an Aaru media tag type to an image data type.">aaruf_get_datatype_for_media_tag_type()</a></li>
<li>Compressed if enabled (compression = ctx-&gt;compression_enabled ? Lzma : None)</li>
<li>CRC64-protected: the checksum is computed over the raw tag data and stored in crc64; cmpCrc64 stores the checksum of compressed data or equals crc64 if uncompressed</li>
<li>Followed immediately by the tag's data payload (compressed or uncompressed)</li>
</ul>
<p>After successfully writing a tag's header and data, an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> is appended to ctx-&gt;indexEntries with:</p><ul>
<li>blockType = DataBlock</li>
<li>dataType = the converted tag type (from aaruf_get_datatype_for_media_tag_type)</li>
<li>offset = the aligned file position where the <a class="el" href="structBlockHeader.html" title="Header preceding the compressed data payload of a data block (BlockType::DataBlock).">BlockHeader</a> was written</li>
</ul>
<p><b>Alignment and file positioning:</b> Before writing each tag, the file position is moved to EOF and then aligned forward to the next boundary satisfying (position &amp; alignment_mask) == 0, where alignment_mask is derived from the blockAlignmentShift. This ensures that all structural blocks (including media tags) begin on properly aligned offsets for efficient I/O and compliance with the Aaru format specification.</p>
<p><b>Order of operations for each tag:</b></p><ol type="1">
<li>Seek to end of file</li>
<li>Align file position to block boundary</li>
<li>Construct <a class="el" href="structBlockHeader.html" title="Header preceding the compressed data payload of a data block (BlockType::DataBlock).">BlockHeader</a> with identifier, type, compression setting, length, CRC64</li>
<li>Compress tag data if enabled and compression is effective</li>
<li>Write <a class="el" href="structBlockHeader.html" title="Header preceding the compressed data payload of a data block (BlockType::DataBlock).">BlockHeader</a> (sizeof(BlockHeader) bytes)</li>
<li>Write LZMA properties if compressed (LZMA_PROPERTIES_LENGTH bytes)</li>
<li>Write tag data (compressed or uncompressed)</li>
<li>On success, push <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> to ctx-&gt;indexEntries</li>
</ol>
<p><b>Error handling:</b> Write errors (fwrite returning &lt; 1) are silently ignored for individual tags; no index entry is added if a write fails, but iteration continues. Diagnostic TRACE logs report success or failure for each tag. The function does not propagate error codes; higher-level close logic must validate overall integrity if needed.</p>
<p><b>Hash table iteration:</b> The function uses HASH_ITER(hh, ctx-&gt;mediaTags, media_tag, tmp_media_tag) from uthash to safely iterate all entries. The tmp_media_tag parameter provides deletion-safe traversal, though this function does not delete entries (cleanup is handled during context teardown).</p>
<p><b>No-op conditions:</b> If ctx-&gt;mediaTags is NULL (no tags were added during image creation), the function returns immediately without writing anything or modifying the index.</p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. Must not be NULL. ctx-&gt;mediaTags contains the hash table of media tags to serialize (may be NULL if no tags exist). ctx-&gt;imageStream must be open and writable. ctx-&gt;indexEntries must be initialized (utarray) to accept new index entries.</td></tr>
</table>
</dd>
</dl>
<dl class="section note"><dt>Note</dt><dd>Media tags are format-agnostic at this layer. The tag type-to-datatype mapping is delegated to <a class="el" href="decls_8h.html#a8d042b26980b56b5dd872f21fa33de70" title="Converts an Aaru media tag type to an image data type.">aaruf_get_datatype_for_media_tag_type()</a>, which consults internal tables or enumerations defined elsewhere in the library.</dd></dl>
<dl class="section see"><dt>See also</dt><dd><a class="el" href="decls_8h.html#aa041a789fbae70c1e1ec3e38f1ab369d" title="Writes a media tag to the AaruFormat image, storing medium-specific metadata and descriptors.">aaruf_write_media_tag()</a> for adding tags to the context during image creation. </dd>
<dd>
<a class="el" href="decls_8h.html#a8d042b26980b56b5dd872f21fa33de70" title="Converts an Aaru media tag type to an image data type.">aaruf_get_datatype_for_media_tag_type()</a> for type conversion logic. </dd>
<dd>
<a class="el" href="structmediaTagEntry.html" title="Hash table entry for an arbitrary media tag (e.g., proprietary drive/medium descriptor).">mediaTagEntry</a> for the hash table entry structure. </dd></dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l02462">2462</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00160">aaruf_crc64_data()</a>, <a class="el" href="helpers_8c_source.html#l00197">aaruf_get_datatype_for_media_tag_type()</a>, <a class="el" href="lzma_8c_source.html#l00065">aaruf_lzma_encode_buffer()</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="data_8h_source.html#l00078">BlockHeader::cmpCrc64</a>, <a class="el" href="data_8h_source.html#l00076">BlockHeader::cmpLength</a>, <a class="el" href="data_8h_source.html#l00074">BlockHeader::compression</a>, <a class="el" href="context_8h_source.html#l00300">aaruformat_context::compression_enabled</a>, <a class="el" href="data_8h_source.html#l00079">BlockHeader::crc64</a>, <a class="el" href="context_8h_source.html#l00120">mediaTagEntry::data</a>, <a class="el" href="enums_8h_source.html#l00141">DataBlock</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="data_8h_source.html#l00072">BlockHeader::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="data_8h_source.html#l00077">BlockHeader::length</a>, <a class="el" href="context_8h_source.html#l00122">mediaTagEntry::length</a>, <a class="el" href="enums_8h_source.html#l00034">Lzma</a>, <a class="el" href="context_8h_source.html#l00298">aaruformat_context::lzma_dict_size</a>, <a class="el" href="consts_8h_source.html#l00082">LZMA_PROPERTIES_LENGTH</a>, <a class="el" href="context_8h_source.html#l00264">aaruformat_context::mediaTags</a>, <a class="el" href="enums_8h_source.html#l00033">None</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="data_8h_source.html#l00073">BlockHeader::type</a>, <a class="el" href="context_8h_source.html#l00121">mediaTagEntry::type</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="af36ba67be5e488713558202feef0eeef" name="af36ba67be5e488713558202feef0eeef"></a>
<h2 class="memtitle"><span class="permalink"><a href="#af36ba67be5e488713558202feef0eeef">&#9670;&#160;</a></span>write_metadata_block()</h2>
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_metadata_block </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the metadata block containing image and media descriptive information. </p>
<p>This function writes a MetadataBlock containing human-readable and machine-readable metadata strings that describe the image creation context, the physical media being preserved, and the drive used for acquisition. The metadata block stores variable-length UTF-16LE strings for fields such as creator identification, user comments, media identification (title, manufacturer, model, serial number, barcode, part number), and drive identification (manufacturer, model, serial number, firmware revision). Each string is stored sequentially in a single contiguous buffer, with the <a class="el" href="structMetadataBlockHeader.html" title="Header for a metadata block containing offsets and lengths to UTF-16LE descriptive strings.">MetadataBlockHeader</a> recording both the offset (relative to the start of the buffer) and length of each field.</p>
<p>The metadata block is optional; if no metadata fields have been populated (all string pointers are NULL and sequence numbers are zero), the function returns immediately without writing anything. This no-op behavior is detected by checking that the identifier has not been explicitly set to MetadataBlock and all relevant imageInfo string fields are NULL.</p>
<p><b>Block structure:</b> The serialized block consists of:</p><ol type="1">
<li><a class="el" href="structMetadataBlockHeader.html" title="Header for a metadata block containing offsets and lengths to UTF-16LE descriptive strings.">MetadataBlockHeader</a> (fixed size, containing identifier, sequence numbers, field offsets and lengths for all metadata strings)</li>
<li>Variable-length payload: concatenated UTF-16LE string data for all non-NULL fields</li>
</ol>
<p>The total blockSize is computed as sizeof(MetadataBlockHeader) plus the sum of all populated string lengths (creatorLength, commentsLength, mediaTitleLength, etc.). Note that lengths are in bytes, not character counts.</p>
<p><b>Field packing order:</b> Non-NULL strings from ctx-&gt;imageInfo are copied into the buffer in the following order:</p><ol type="1">
<li>Creator</li>
<li>Comments</li>
<li>MediaTitle</li>
<li>MediaManufacturer</li>
<li>MediaModel</li>
<li>MediaSerialNumber</li>
<li>MediaBarcode</li>
<li>MediaPartNumber</li>
<li>DriveManufacturer</li>
<li>DriveModel</li>
<li>DriveSerialNumber</li>
<li>DriveFirmwareRevision</li>
</ol>
<p>As each field is copied, its offset (relative to the buffer start, which begins after the header) is recorded in the corresponding offset field of ctx-&gt;metadataBlockHeader, and the position pointer is advanced by the field's length.</p>
<p><b>Alignment and file positioning:</b> Before writing the block, the file position is moved to EOF and then aligned forward to the next boundary satisfying (position &amp; alignment_mask) == 0, where alignment_mask is derived from ctx-&gt;userDataDdtHeader.blockAlignmentShift. This ensures the metadata block begins on a properly aligned offset for efficient I/O and compliance with the Aaru format specification.</p>
<p><b>Index registration:</b> After successfully writing the metadata block, an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> is appended to ctx-&gt;indexEntries with:</p><ul>
<li>blockType = MetadataBlock</li>
<li>dataType = 0 (metadata blocks have no subtype)</li>
<li>offset = the aligned file position where the block was written</li>
</ul>
<p><b>Memory management:</b> The function allocates a temporary buffer (via calloc) sized to hold the entire block payload. If allocation fails, the function returns immediately without writing anything. The buffer is freed before the function returns, regardless of write success or failure.</p>
<p><b>Error handling:</b> Write errors (fwrite returning &lt; 1) are silently ignored; no index entry is added if the write fails, but the temporary buffer is still freed. Diagnostic TRACE logs report success or failure. The function does not propagate error codes; higher-level close logic must validate overall integrity if needed.</p>
<p><b>No-op conditions:</b></p><ul>
<li>ctx-&gt;metadataBlockHeader.identifier is not MetadataBlock AND</li>
<li>ctx-&gt;metadataBlockHeader.mediaSequence == 0 AND</li>
<li>ctx-&gt;metadataBlockHeader.lastMediaSequence == 0 AND</li>
<li>All ctx-&gt;imageInfo string fields (Creator, Comments, MediaTitle, etc.) are NULL</li>
</ul>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. Must not be NULL. ctx-&gt;metadataBlockHeader contains the header template with pre-populated field lengths and sequence numbers (if applicable). ctx-&gt;imageInfo contains pointers to the actual UTF-16LE string data (may be NULL for unpopulated fields). ctx-&gt;imageStream must be open and writable. ctx-&gt;indexEntries must be initialized (utarray) to accept new index entries.</td></tr>
</table>
</dd>
</dl>
<dl class="section note"><dt>Note</dt><dd>UTF-16LE Encoding:<ul>
<li>All metadata strings use UTF-16LE encoding to support international characters</li>
<li>Field lengths are in bytes, not character counts (UTF-16LE uses 2 or 4 bytes per character)</li>
<li>The library treats string data as opaque and does not validate UTF-16LE encoding</li>
<li>Ensure even byte lengths to maintain UTF-16LE character alignment</li>
</ul>
</dd>
<dd>
Unlike data blocks (which include CRC64 checksums), the metadata block does not currently include integrity checking beyond the implicit file-level checksums. The header itself stores offsets/lengths but not CRCs for individual string fields.</dd>
<dd>
Media sequence numbers (mediaSequence, lastMediaSequence) support multi-volume image sets (e.g., spanning multiple optical discs). Single-volume images typically set both to 0 or leave them uninitialized.</dd></dl>
<dl class="section see"><dt>See also</dt><dd><a class="el" href="structMetadataBlockHeader.html" title="Header for a metadata block containing offsets and lengths to UTF-16LE descriptive strings.">MetadataBlockHeader</a> for the on-disk structure definition. </dd>
<dd>
<a class="el" href="decls_8h.html#a1da2dd0571762fa7c13bc956ec12dfab" title="Sets the creator (person/operator) information for the image.">aaruf_set_creator()</a> for populating the creator field. </dd>
<dd>
<a class="el" href="decls_8h.html#af7fcca1ab5ff0422ec81ec6e99001b38" title="Sets user comments or notes for the image.">aaruf_set_comments()</a> for populating the comments field. </dd>
<dd>
<a class="el" href="decls_8h.html#a37f50b38ceaee7db0b7731ee978b8241" title="Sets the media title or label for the image.">aaruf_set_media_title()</a> for populating the media title field. </dd></dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l03220">3220</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="metadata_8h_source.html#l00071">MetadataBlockHeader::blockSize</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="context_8h_source.html#l00218">aaruformat_context::comments</a>, <a class="el" href="metadata_8h_source.html#l00078">MetadataBlockHeader::commentsLength</a>, <a class="el" href="metadata_8h_source.html#l00077">MetadataBlockHeader::commentsOffset</a>, <a class="el" href="context_8h_source.html#l00216">aaruformat_context::creator</a>, <a class="el" href="metadata_8h_source.html#l00076">MetadataBlockHeader::creatorLength</a>, <a class="el" href="metadata_8h_source.html#l00075">MetadataBlockHeader::creatorOffset</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="context_8h_source.html#l00228">aaruformat_context::drive_firmware_revision</a>, <a class="el" href="context_8h_source.html#l00224">aaruformat_context::drive_manufacturer</a>, <a class="el" href="context_8h_source.html#l00225">aaruformat_context::drive_model</a>, <a class="el" href="context_8h_source.html#l00226">aaruformat_context::drive_serial_number</a>, <a class="el" href="metadata_8h_source.html#l00098">MetadataBlockHeader::driveFirmwareRevisionLength</a>, <a class="el" href="metadata_8h_source.html#l00097">MetadataBlockHeader::driveFirmwareRevisionOffset</a>, <a class="el" href="metadata_8h_source.html#l00092">MetadataBlockHeader::driveManufacturerLength</a>, <a class="el" href="metadata_8h_source.html#l00091">MetadataBlockHeader::driveManufacturerOffset</a>, <a class="el" href="metadata_8h_source.html#l00094">MetadataBlockHeader::driveModelLength</a>, <a class="el" href="metadata_8h_source.html#l00093">MetadataBlockHeader::driveModelOffset</a>, <a class="el" href="metadata_8h_source.html#l00096">MetadataBlockHeader::driveSerialNumberLength</a>, <a class="el" href="metadata_8h_source.html#l00095">MetadataBlockHeader::driveSerialNumberOffset</a>, <a class="el" href="metadata_8h_source.html#l00070">MetadataBlockHeader::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="metadata_8h_source.html#l00074">MetadataBlockHeader::lastMediaSequence</a>, <a class="el" href="context_8h_source.html#l00222">aaruformat_context::media_barcode</a>, <a class="el" href="context_8h_source.html#l00219">aaruformat_context::media_manufacturer</a>, <a class="el" href="context_8h_source.html#l00220">aaruformat_context::media_model</a>, <a class="el" href="context_8h_source.html#l00223">aaruformat_context::media_part_number</a>, <a class="el" href="context_8h_source.html#l00221">aaruformat_context::media_serial_number</a>, <a class="el" href="context_8h_source.html#l00217">aaruformat_context::media_title</a>, <a class="el" href="metadata_8h_source.html#l00088">MetadataBlockHeader::mediaBarcodeLength</a>, <a class="el" href="metadata_8h_source.html#l00087">MetadataBlockHeader::mediaBarcodeOffset</a>, <a class="el" href="metadata_8h_source.html#l00082">MetadataBlockHeader::mediaManufacturerLength</a>, <a class="el" href="metadata_8h_source.html#l00081">MetadataBlockHeader::mediaManufacturerOffset</a>, <a class="el" href="metadata_8h_source.html#l00084">MetadataBlockHeader::mediaModelLength</a>, <a class="el" href="metadata_8h_source.html#l00083">MetadataBlockHeader::mediaModelOffset</a>, <a class="el" href="metadata_8h_source.html#l00090">MetadataBlockHeader::mediaPartNumberLength</a>, <a class="el" href="metadata_8h_source.html#l00089">MetadataBlockHeader::mediaPartNumberOffset</a>, <a class="el" href="metadata_8h_source.html#l00072">MetadataBlockHeader::mediaSequence</a>, <a class="el" href="metadata_8h_source.html#l00086">MetadataBlockHeader::mediaSerialNumberLength</a>, <a class="el" href="me
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="ade7f81cbae198dbbea937551bf670a4f" name="ade7f81cbae198dbbea937551bf670a4f"></a>
<h2 class="memtitle"><span class="permalink"><a href="#ade7f81cbae198dbbea937551bf670a4f">&#9670;&#160;</a></span>write_mode2_subheaders_block()</h2>
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_mode2_subheaders_block </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize a MODE 2 (XA) subheaders data block. </p>
<p>When Compact Disc Mode 2 form sectors are present, optional 8-byte subheaders (one per logical sector including negative / overflow ranges) are stored in an in-memory buffer. This function writes that buffer as a DataBlock of type CompactDiscMode2Subheader with CRC64 (compression enabled if configured) and adds an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a>.</p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode; ctx-&gt;mode2_subheaders must point to a buffer sized for the described sector span. </td></tr>
</table>
</dd>
</dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l00879">879</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00160">aaruf_crc64_data()</a>, <a class="el" href="lzma_8c_source.html#l00065">aaruf_lzma_encode_buffer()</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="data_8h_source.html#l00078">BlockHeader::cmpCrc64</a>, <a class="el" href="data_8h_source.html#l00076">BlockHeader::cmpLength</a>, <a class="el" href="enums_8h_source.html#l00123">CompactDiscMode2Subheader</a>, <a class="el" href="data_8h_source.html#l00074">BlockHeader::compression</a>, <a class="el" href="context_8h_source.html#l00300">aaruformat_context::compression_enabled</a>, <a class="el" href="data_8h_source.html#l00079">BlockHeader::crc64</a>, <a class="el" href="enums_8h_source.html#l00141">DataBlock</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="data_8h_source.html#l00072">BlockHeader::identifier</a>, <a class="el" href="context_8h_source.html#l00260">aaruformat_context::image_info</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="data_8h_source.html#l00077">BlockHeader::length</a>, <a class="el" href="enums_8h_source.html#l00034">Lzma</a>, <a class="el" href="context_8h_source.html#l00298">aaruformat_context::lzma_dict_size</a>, <a class="el" href="consts_8h_source.html#l00082">LZMA_PROPERTIES_LENGTH</a>, <a class="el" href="context_8h_source.html#l00204">aaruformat_context::mode2_subheaders</a>, <a class="el" href="ddt_8h_source.html#l00149">DdtHeader2::negative</a>, <a class="el" href="enums_8h_source.html#l00033">None</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="ddt_8h_source.html#l00151">DdtHeader2::overflow</a>, <a class="el" href="aaru_8h_source.html#l00926">ImageInfo::Sectors</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="data_8h_source.html#l00073">BlockHeader::type</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="a1bb181171eb9d0b0016cf4091ed831d7" name="a1bb181171eb9d0b0016cf4091ed831d7"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a1bb181171eb9d0b0016cf4091ed831d7">&#9670;&#160;</a></span>write_primary_ddt()</h2>
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">int32_t write_primary_ddt </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Write (flush) the multi-level primary DDT table header and data back to its file offset. </p>
<p>This function is applicable only when a multi-level DDT is in use (tableShift &gt; 0). It updates the header fields (identifier, type, compression, CRC, lengths) and writes first the header and then the entire primary table data block at ctx-&gt;primaryDdtOffset. The function also pushes an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> for the primary DDT into the in-memory index array so that later <a class="el" href="#a3532372fac3d5bb2619900820a26632e" title="Serialize the accumulated index entries at the end of the image and back-patch the header.">write_index_block()</a> will serialize it.</p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. </td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>AARUF_STATUS_OK on success; AARUF_ERROR_CANNOT_WRITE_HEADER if either the header or the table body cannot be written. Returns AARUF_STATUS_OK immediately if no primary table should be written (single-level DDT or table buffers absent). </dd></dl>
<dl class="retval"><dt>Return values</dt><dd>
<table class="retval">
<tr><td class="paramname">AARUF_STATUS_OK</td><td>Success or nothing to do (no multi-level primary table present). </td></tr>
<tr><td class="paramname">AARUF_ERROR_CANNOT_WRITE_HEADER</td><td>Failed writing header or primary table data. </td></tr>
</table>
</dd>
</dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l00284">284</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00141">aaruf_crc64_final()</a>, <a class="el" href="crc64_8c_source.html#l00032">aaruf_crc64_init()</a>, <a class="el" href="crc64_8c_source.html#l00055">aaruf_crc64_update()</a>, <a class="el" href="errors_8h_source.html#l00060">AARUF_ERROR_CANNOT_WRITE_HEADER</a>, <a class="el" href="errors_8h_source.html#l00075">AARUF_STATUS_OK</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="ddt_8h_source.html#l00161">DdtHeader2::cmpCrc64</a>, <a class="el" href="ddt_8h_source.html#l00159">DdtHeader2::cmpLength</a>, <a class="el" href="ddt_8h_source.html#l00145">DdtHeader2::compression</a>, <a class="el" href="ddt_8h_source.html#l00162">DdtHeader2::crc64</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="enums_8h_source.html#l00143">DeDuplicationTable2</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="ddt_8h_source.html#l00158">DdtHeader2::entries</a>, <a class="el" href="ddt_8h_source.html#l00143">DdtHeader2::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="ddt_8h_source.html#l00160">DdtHeader2::length</a>, <a class="el" href="enums_8h_source.html#l00033">None</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="context_8h_source.html#l00192">aaruformat_context::primary_ddt_offset</a>, <a class="el" href="ddt_8h_source.html#l00156">DdtHeader2::tableShift</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="ddt_8h_source.html#l00144">DdtHeader2::type</a>, <a class="el" href="context_8h_source.html#l00187">aaruformat_context::user_data_ddt2</a>, <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>, and <a class="el" href="enums_8h_source.html#l00046">UserData</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="af383051987456d1295862e395027ffa8" name="af383051987456d1295862e395027ffa8"></a>
<h2 class="memtitle"><span class="permalink"><a href="#af383051987456d1295862e395027ffa8">&#9670;&#160;</a></span>write_sector_prefix()</h2>
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_sector_prefix </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the optional CD sector prefix block. </p>
<p>The sector prefix corresponds to the leading bytes of a raw CD sector (synchronization pattern, address / header in MSF format and the mode byte) that precede the user data and any ECC/ECCP fields. It is unrelated to subchannel (PW) data, which is handled separately. If prefix data was collected (ctx-&gt;sector_prefix != NULL), this writes a DataBlock of type CdSectorPrefix containing exactly the bytes accumulated up to sector_prefix_offset. The block is CRC64 protected, compressed if enabled, aligned to the DDT block boundary and indexed.</p>
<p>Typical raw Mode 1 / Mode 2 sector layout (2352 bytes total): 12-byte sync pattern (00 FF FF FF FF FF FF FF FF FF FF 00) 3-byte address (Minute, Second, Frame in BCD) 1-byte mode (e.g., 0x01, 0x02) ... user data ... ... ECC / EDC ... The stored prefix encompasses the first 16 bytes (sync + address + mode) or whatever subset was gathered by the writer.</p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. </td></tr>
</table>
</dd>
</dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l00997">997</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00160">aaruf_crc64_data()</a>, <a class="el" href="lzma_8c_source.html#l00065">aaruf_lzma_encode_buffer()</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="enums_8h_source.html#l00114">CdSectorPrefix</a>, <a class="el" href="data_8h_source.html#l00078">BlockHeader::cmpCrc64</a>, <a class="el" href="data_8h_source.html#l00076">BlockHeader::cmpLength</a>, <a class="el" href="data_8h_source.html#l00074">BlockHeader::compression</a>, <a class="el" href="context_8h_source.html#l00300">aaruformat_context::compression_enabled</a>, <a class="el" href="data_8h_source.html#l00079">BlockHeader::crc64</a>, <a class="el" href="enums_8h_source.html#l00141">DataBlock</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="data_8h_source.html#l00072">BlockHeader::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="data_8h_source.html#l00077">BlockHeader::length</a>, <a class="el" href="enums_8h_source.html#l00034">Lzma</a>, <a class="el" href="context_8h_source.html#l00298">aaruformat_context::lzma_dict_size</a>, <a class="el" href="consts_8h_source.html#l00082">LZMA_PROPERTIES_LENGTH</a>, <a class="el" href="enums_8h_source.html#l00033">None</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="context_8h_source.html#l00199">aaruformat_context::sector_prefix</a>, <a class="el" href="context_8h_source.html#l00286">aaruformat_context::sector_prefix_offset</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="data_8h_source.html#l00073">BlockHeader::type</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="ae5ee36ba745233583773cd7a644c8aa7" name="ae5ee36ba745233583773cd7a644c8aa7"></a>
<h2 class="memtitle"><span class="permalink"><a href="#ae5ee36ba745233583773cd7a644c8aa7">&#9670;&#160;</a></span>write_sector_prefix_ddt()</h2>
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_sector_prefix_ddt </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the per-sector CD prefix status / index DeDuplication Table (DDT v2, prefix variant). </p>
<p>This DDT records for each logical sector (including negative and overflow ranges) an optional index into the stored 16byte prefix capture buffer plus a 4-bit status code. It is written only if at least one prefix status or captured prefix was recorded (i.e., the in-memory DDT array exists).</p>
<p>Encoding: Bits 63..61 : <a class="el" href="enums_8h.html#a74e216af87b18a5fbf0204a52dd1bba0" title="Acquisition / content status for one or more sectors.">SectorStatus</a> enum value (see <a class="el" href="enums_8h.html">enums.h</a>, values already positioned for v2 layout). Bits 60..0 : Index of the 16-byte prefix chunk inside the CdSectorPrefix data block, or 0 when no external prefix bytes were stored (status applies to a generated/implicit prefix).</p>
<p>Notes:</p><ul>
<li>Unlike DDT v1, there are no CD_XFIX_MASK / CD_DFIX_MASK macros used here. The bit layout is compact and directly encoded when writing (status values are pre-shifted where needed in <a class="el" href="write_8c.html">write.c</a>).</li>
<li>The table length equals (negative + Sectors + overflow) * entrySize.</li>
<li>dataShift is set to 4 (2^4 = 16) expressing the granularity of referenced prefix units.</li>
<li>Compression is applied if enabled; crc64/cmpCrc64 protect the raw table bytes.</li>
<li>Idempotent: if an index entry of type DeDuplicationTable2 + CdSectorPrefixCorrected already exists the function returns immediately.</li>
</ul>
<p>Alignment: The table is block-aligned using the same blockAlignmentShift as user data DDTs. Indexing: An <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> is appended on success so readers can locate and parse the table.</p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to a valid aaruformatContext in write mode (must not be NULL). </td></tr>
</table>
</dd>
</dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l01241">1241</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00160">aaruf_crc64_data()</a>, <a class="el" href="lzma_8c_source.html#l00065">aaruf_lzma_encode_buffer()</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="ddt_8h_source.html#l00150">DdtHeader2::blocks</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="enums_8h_source.html#l00114">CdSectorPrefix</a>, <a class="el" href="ddt_8h_source.html#l00161">DdtHeader2::cmpCrc64</a>, <a class="el" href="ddt_8h_source.html#l00159">DdtHeader2::cmpLength</a>, <a class="el" href="ddt_8h_source.html#l00145">DdtHeader2::compression</a>, <a class="el" href="context_8h_source.html#l00300">aaruformat_context::compression_enabled</a>, <a class="el" href="ddt_8h_source.html#l00162">DdtHeader2::crc64</a>, <a class="el" href="ddt_8h_source.html#l00155">DdtHeader2::dataShift</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="enums_8h_source.html#l00143">DeDuplicationTable2</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="ddt_8h_source.html#l00158">DdtHeader2::entries</a>, <a class="el" href="ddt_8h_source.html#l00143">DdtHeader2::identifier</a>, <a class="el" href="context_8h_source.html#l00260">aaruformat_context::image_info</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="ddt_8h_source.html#l00160">DdtHeader2::length</a>, <a class="el" href="ddt_8h_source.html#l00146">DdtHeader2::levels</a>, <a class="el" href="enums_8h_source.html#l00034">Lzma</a>, <a class="el" href="context_8h_source.html#l00298">aaruformat_context::lzma_dict_size</a>, <a class="el" href="consts_8h_source.html#l00082">LZMA_PROPERTIES_LENGTH</a>, <a class="el" href="ddt_8h_source.html#l00149">DdtHeader2::negative</a>, <a class="el" href="enums_8h_source.html#l00033">None</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="ddt_8h_source.html#l00151">DdtHeader2::overflow</a>, <a class="el" href="context_8h_source.html#l00185">aaruformat_context::sector_prefix_ddt2</a>, <a class="el" href="aaru_8h_source.html#l00926">ImageInfo::Sectors</a>, <a class="el" href="ddt_8h_source.html#l00153">DdtHeader2::start</a>, <a class="el" href="ddt_8h_source.html#l00147">DdtHeader2::tableLevel</a>, <a class="el" href="ddt_8h_source.html#l00156">DdtHeader2::tableShift</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="ddt_8h_source.html#l00144">DdtHeader2::type</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
2025-12-12 12:25:02 +00:00
<a id="a2b849af94084e38d2040eca1d520478a" name="a2b849af94084e38d2040eca1d520478a"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a2b849af94084e38d2040eca1d520478a">&#9670;&#160;</a></span>write_sector_subchannel()</h2>
2025-10-11 01:35:43 +01:00
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_sector_subchannel </td>
<td>(</td>
2025-12-12 12:25:02 +00:00
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
2025-10-11 01:35:43 +01:00
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the per-sector subchannel or tag data block. </p>
<p>This routine writes out the accumulated subchannel or tag metadata that accompanies each logical sector (including negative pregap and overflow ranges). The exact interpretation and size depend on the media type:</p>
<p><b>Optical Disc (CD) subchannel:</b></p><ul>
<li>Type: CdSectorSubchannel</li>
<li>Contains the deinterleaved P through W subchannel data (96 bytes per sector).</li>
<li>Covers: (negative + Sectors + overflow) sectors.</li>
<li>The P channel marks pause boundaries; Q encodes track/index/time information (MCN, ISRC).</li>
<li>RW channels are typically used for CD+G graphics or CD-TEXT.</li>
</ul>
<p><b>Apple block media tags:</b></p><ul>
<li><b>AppleProfile / AppleFileWare:</b> 20 bytes per sector (AppleProfileTag).</li>
<li><b>AppleSonyDS / AppleSonySS:</b> 12 bytes per sector (AppleSonyTag).</li>
<li><b>PriamDataTower:</b> 24 bytes per sector (PriamDataTowerTag).</li>
<li>Tags encode filesystem metadata, allocation state, or device-specific control information.</li>
<li>Only positive sectors (0 through Sectors-1) and overflow are included; no negative range.</li>
</ul>
<p>The block size is computed as (applicable_sector_count) × (bytes_per_sector_for_media_type). Compression is conditionally applied based on media type and compression settings:</p><ul>
<li><b>Optical Disc:</b> When compression is enabled, applies Claunia Subchannel Transform (CST) followed by LZMA compression (LzmaClauniaSubchannelTransform). If the compressed size is not smaller than the original, falls back to uncompressed storage.</li>
<li><b>Block Media:</b> Always attempts LZMA compression for tag data. If the compressed size is not smaller than the original, falls back to uncompressed storage. The data is written after a DataBlock header with CRC64 integrity protection. The write position is aligned to the DDT block boundary (2^blockAlignmentShift) before serialization begins.</li>
</ul>
<p><b>Media type validation:</b> The function only proceeds if <a class="el" href="enums_8h.html#abaa37b51ab0a4cc3d5d1a0b4820c8466" title="Enumeration of media types defined in CICM metadata.">XmlMediaType</a> is OpticalDisc or BlockMedia and (for block media) the specific <a class="el" href="group__MediaTypes.html#ga1499e9f8a76cb81b43b7a4b0dbe7e44a" title="Enumerates every recognized media / cartridge / optical / tape / card / disk format.">MediaType</a> matches one of the supported Apple or Priam variants. Any other media type causes an immediate silent return (logged at TRACE level).</p>
<p><b>Alignment &amp; indexing:</b> The block is aligned using the same alignment shift as the user data DDT. An <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> (blockType = DataBlock, dataType = subchannel_block.type, offset = aligned file position) is appended to ctx-&gt;indexEntries on successful write, enabling readers to locate the subchannel or tag data.</p>
<p><b>Thread / reentrancy:</b> This function is invoked once during finalization (aaruf_close) in a single-threaded context. No synchronization is performed.</p>
<p><b>Error handling:</b> Write errors are logged but not explicitly propagated as return codes. If the write succeeds an index entry is added; if it fails no entry is added and diagnostics appear in TRACE logs. Higher level close logic determines overall success or failure.</p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. Must not be NULL. ctx-&gt;sector_subchannel must point to a fully populated buffer sized appropriately for the media type and sector count. </td></tr>
</table>
</dd>
</dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l01547">1547</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00160">aaruf_crc64_data()</a>, <a class="el" href="cst_8c_source.html#l00035">aaruf_cst_transform()</a>, <a class="el" href="lzma_8c_source.html#l00065">aaruf_lzma_encode_buffer()</a>, <a class="el" href="aaru_8h_source.html#l00249">AppleFileWare</a>, <a class="el" href="aaru_8h_source.html#l00698">AppleProfile</a>, <a class="el" href="enums_8h_source.html#l00117">AppleProfileTag</a>, <a class="el" href="aaru_8h_source.html#l00248">AppleSonyDS</a>, <a class="el" href="aaru_8h_source.html#l00247">AppleSonySS</a>, <a class="el" href="enums_8h_source.html#l00118">AppleSonyTag</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="enums_8h_source.html#l00219">BlockMedia</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="enums_8h_source.html#l00116">CdSectorSubchannel</a>, <a class="el" href="data_8h_source.html#l00078">BlockHeader::cmpCrc64</a>, <a class="el" href="data_8h_source.html#l00076">BlockHeader::cmpLength</a>, <a class="el" href="data_8h_source.html#l00074">BlockHeader::compression</a>, <a class="el" href="context_8h_source.html#l00300">aaruformat_context::compression_enabled</a>, <a class="el" href="data_8h_source.html#l00079">BlockHeader::crc64</a>, <a class="el" href="enums_8h_source.html#l00141">DataBlock</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="data_8h_source.html#l00072">BlockHeader::identifier</a>, <a class="el" href="context_8h_source.html#l00260">aaruformat_context::image_info</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="data_8h_source.html#l00077">BlockHeader::length</a>, <a class="el" href="enums_8h_source.html#l00034">Lzma</a>, <a class="el" href="context_8h_source.html#l00298">aaruformat_context::lzma_dict_size</a>, <a class="el" href="consts_8h_source.html#l00082">LZMA_PROPERTIES_LENGTH</a>, <a class="el" href="enums_8h_source.html#l00036">LzmaClauniaSubchannelTransform</a>, <a class="el" href="aaru_8h_source.html#l00933">ImageInfo::MediaType</a>, <a class="el" href="aaru_8h_source.html#l00934">ImageInfo::MetadataMediaType</a>, <a class="el" href="ddt_8h_source.html#l00149">DdtHeader2::negative</a>, <a class="el" href="enums_8h_source.html#l00033">None</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="enums_8h_source.html#l00218">OpticalDisc</a>, <a class="el" href="ddt_8h_source.html#l00151">DdtHeader2::overflow</a>, <a class="el" href="aaru_8h_source.html#l00701">PriamDataTower</a>, <a class="el" href="enums_8h_source.html#l00119">PriamDataTowerTag</a>, <a class="el" href="context_8h_source.html#l00203">aaruformat_context::sector_subchannel</a>, <a class="el" href="aaru_8h_source.html#l00926">ImageInfo::Sectors</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="data_8h_source.html#l00073">BlockHeader::type</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="a8ea54bc4597be4246f2be361a5854251" name="a8ea54bc4597be4246f2be361a5854251"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a8ea54bc4597be4246f2be361a5854251">&#9670;&#160;</a></span>write_sector_suffix()</h2>
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_sector_suffix </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the optional CD sector suffix block (EDC/ECC region capture). </p>
<p>The sector suffix contains trailing integrity and redundancy bytes of a raw CD sector that follow the user data area. Depending on the mode this includes:</p><ul>
<li>Mode 1: 4-byte EDC, 8-byte reserved, 276 bytes (P/Q layers) ECC = 288 bytes total.</li>
<li>Mode 2 Form 1: 4-byte EDC, 8 reserved, 276 ECC = 288 bytes.</li>
<li>Mode 2 Form 2: 4-byte EDC only (no ECC) but when an error is detected the implementation may still store a 288-byte suffix container for uniformity when capturing errored data.</li>
</ul>
<p>During writing, when an error or uncorrectable condition is detected for a sector's suffix, the 288-byte trailing portion (starting at offset 2064 for Mode 1 / Form 1 or 2348/2349 for other layouts) is copied into an in-memory expandable buffer pointed to by ctx-&gt;sector_suffix. The per-sector DDT entry encodes either an inlined status (OK / No CRC / etc.) or an index to the stored suffix (ctx-&gt;sector_suffix_offset / 288). This function serializes the accumulated suffix buffer as a DataBlock of type CdSectorSuffix if any suffix bytes were stored.</p>
<p>Layout considerations:</p><ul>
<li>The block length is exactly the number of bytes copied (ctx-&gt;sector_suffix_offset).</li>
<li>Compression is applied if enabled; CRC64 is calculated on the raw suffix stream for integrity.</li>
<li>The write position is aligned to the DDT block alignment (2^blockAlignmentShift).</li>
</ul>
<p>Indexing: An <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> is appended so later readers can locate the suffix collection. Absence of this block implies no per-sector suffix captures were required (all suffixes considered OK).</p>
<p>Thread / reentrancy: This routine is called only once during finalization (aaruf_close) in a single-threaded context; no synchronization is performed.</p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. Must not be NULL. </td></tr>
</table>
</dd>
</dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l01121">1121</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00160">aaruf_crc64_data()</a>, <a class="el" href="lzma_8c_source.html#l00065">aaruf_lzma_encode_buffer()</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="enums_8h_source.html#l00115">CdSectorSuffix</a>, <a class="el" href="data_8h_source.html#l00078">BlockHeader::cmpCrc64</a>, <a class="el" href="data_8h_source.html#l00076">BlockHeader::cmpLength</a>, <a class="el" href="data_8h_source.html#l00074">BlockHeader::compression</a>, <a class="el" href="context_8h_source.html#l00300">aaruformat_context::compression_enabled</a>, <a class="el" href="data_8h_source.html#l00079">BlockHeader::crc64</a>, <a class="el" href="enums_8h_source.html#l00141">DataBlock</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="data_8h_source.html#l00072">BlockHeader::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="data_8h_source.html#l00077">BlockHeader::length</a>, <a class="el" href="enums_8h_source.html#l00034">Lzma</a>, <a class="el" href="context_8h_source.html#l00298">aaruformat_context::lzma_dict_size</a>, <a class="el" href="consts_8h_source.html#l00082">LZMA_PROPERTIES_LENGTH</a>, <a class="el" href="enums_8h_source.html#l00033">None</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="context_8h_source.html#l00201">aaruformat_context::sector_suffix</a>, <a class="el" href="context_8h_source.html#l00287">aaruformat_context::sector_suffix_offset</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="data_8h_source.html#l00073">BlockHeader::type</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="a9d0eb026d1fa544b554493e780b7fbc1" name="a9d0eb026d1fa544b554493e780b7fbc1"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a9d0eb026d1fa544b554493e780b7fbc1">&#9670;&#160;</a></span>write_sector_suffix_ddt()</h2>
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_sector_suffix_ddt </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the per-sector CD suffix status / index DeDuplication Table (DDT v2, suffix variant). </p>
<p>This routine emits the DDT v2 table that maps each logical sector (including negative pregap and overflow ranges) to (a) a 4-bit <a class="el" href="enums_8h.html#a74e216af87b18a5fbf0204a52dd1bba0" title="Acquisition / content status for one or more sectors.">SectorStatus</a> code and (b) a 12-bit index pointing into the captured suffix data block (CdSectorSuffix). The suffix bytes (typically the 288-byte EDC/ECC region for Mode 1 or Mode 2 Form 1, or shorter EDC-only for Form 2) are stored separately by <a class="el" href="#a8ea54bc4597be4246f2be361a5854251" title="Serialize the optional CD sector suffix block (EDC/ECC region capture).">write_sector_suffix()</a>. When a sector's suffix was captured because it differed from the expected generated values (e.g., uncorrectable, intentionally preserved corruption, or variant layout), the in-memory mini entry records the index of its 16 * 18 (288) byte chunk. If no suffix bytes were explicitly stored for a sector the index field is zero and only the status applies.</p>
<p>Encoding (DDT v2 semantics): Bits 63..61 : <a class="el" href="enums_8h.html#a74e216af87b18a5fbf0204a52dd1bba0" title="Acquisition / content status for one or more sectors.">SectorStatus</a> enumeration (already aligned for direct storage; no legacy masks used). Bits 60..0 : Index referencing a suffix unit of size 288 bytes (2^dataShift granularity), or 0 when the sector uses an implicit / regenerated suffix (no external data captured).</p>
<p>Characteristics &amp; constraints:</p><ul>
<li>Only DDT v2 is supported here; no fallback or mixed-mode emission with v1 occurs.</li>
<li>Table length = (negative + total Sectors + overflow) * sizeof(uint16_t).</li>
<li>dataShift mirrors userDataDdtHeader.dataShift (expressing granularity for index referencing).</li>
<li>Single-level table (levels = 1, tableLevel = 0, tableShift = 0).</li>
<li>Compression is applied if enabled; CRC64 protects the table bytes.</li>
<li>Alignment: The table is aligned to 2^(blockAlignmentShift) before writing to guarantee block boundary access.</li>
<li>Idempotence: If sectorSuffixDdt2 is NULL the function is a no-op (indicating no suffix anomalies captured).</li>
</ul>
<p>Index integration: On success an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> (blockType = DeDuplicationTable2, dataType = CdSectorSuffix, offset = file position) is appended to ctx-&gt;indexEntries enabling later readers to locate and parse the suffix DDT.</p>
<p>Error handling &amp; assumptions:</p><ul>
<li>The function does not explicitly propagate write failures upward; partial write errors simply omit the index entry (TRACE logs provide diagnostics). Higher level close logic determines overall success.</li>
<li>Executed in a single-threaded finalization path; no locking is performed or required.</li>
</ul>
<p>Preconditions:</p><ul>
<li>ctx must be a valid non-NULL pointer opened for writing.</li>
<li>ctx-&gt;sectorSuffixDdt2 must point to a fully populated contiguous array of uint16_t entries.</li>
</ul>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Active aaruformatContext being finalized. </td></tr>
</table>
</dd>
</dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l01387">1387</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00160">aaruf_crc64_data()</a>, <a class="el" href="lzma_8c_source.html#l00065">aaruf_lzma_encode_buffer()</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="ddt_8h_source.html#l00150">DdtHeader2::blocks</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="enums_8h_source.html#l00115">CdSectorSuffix</a>, <a class="el" href="ddt_8h_source.html#l00161">DdtHeader2::cmpCrc64</a>, <a class="el" href="ddt_8h_source.html#l00159">DdtHeader2::cmpLength</a>, <a class="el" href="ddt_8h_source.html#l00145">DdtHeader2::compression</a>, <a class="el" href="context_8h_source.html#l00300">aaruformat_context::compression_enabled</a>, <a class="el" href="ddt_8h_source.html#l00162">DdtHeader2::crc64</a>, <a class="el" href="ddt_8h_source.html#l00155">DdtHeader2::dataShift</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="enums_8h_source.html#l00143">DeDuplicationTable2</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="ddt_8h_source.html#l00158">DdtHeader2::entries</a>, <a class="el" href="ddt_8h_source.html#l00143">DdtHeader2::identifier</a>, <a class="el" href="context_8h_source.html#l00260">aaruformat_context::image_info</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="ddt_8h_source.html#l00160">DdtHeader2::length</a>, <a class="el" href="ddt_8h_source.html#l00146">DdtHeader2::levels</a>, <a class="el" href="enums_8h_source.html#l00034">Lzma</a>, <a class="el" href="context_8h_source.html#l00298">aaruformat_context::lzma_dict_size</a>, <a class="el" href="consts_8h_source.html#l00082">LZMA_PROPERTIES_LENGTH</a>, <a class="el" href="ddt_8h_source.html#l00149">DdtHeader2::negative</a>, <a class="el" href="enums_8h_source.html#l00033">None</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="ddt_8h_source.html#l00151">DdtHeader2::overflow</a>, <a class="el" href="context_8h_source.html#l00186">aaruformat_context::sector_suffix_ddt2</a>, <a class="el" href="aaru_8h_source.html#l00926">ImageInfo::Sectors</a>, <a class="el" href="ddt_8h_source.html#l00153">DdtHeader2::start</a>, <a class="el" href="ddt_8h_source.html#l00147">DdtHeader2::tableLevel</a>, <a class="el" href="ddt_8h_source.html#l00156">DdtHeader2::tableShift</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="ddt_8h_source.html#l00144">DdtHeader2::type</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="a7314de0d71768709fa4ba2db7f89cdb9" name="a7314de0d71768709fa4ba2db7f89cdb9"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a7314de0d71768709fa4ba2db7f89cdb9">&#9670;&#160;</a></span>write_single_level_ddt()</h2>
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">int32_t write_single_level_ddt </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize a single-level DDT (tableShift == 0) directly after its header. </p>
<p>For single-level DDT configurations the entire table of sector references is contiguous. This routine computes a CRC64 for the table, populates all header metadata, writes the header at ctx-&gt;primaryDdtOffset followed immediately by the table, and registers the block in the index.</p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode with tableShift == 0. </td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>AARUF_STATUS_OK on success; AARUF_ERROR_CANNOT_WRITE_HEADER if serialization fails. Returns AARUF_STATUS_OK without action when the context represents a multi-level DDT or the table buffers are NULL. </dd></dl>
<dl class="retval"><dt>Return values</dt><dd>
<table class="retval">
<tr><td class="paramname">AARUF_STATUS_OK</td><td>Success or nothing to do (not single-level / buffers missing). </td></tr>
<tr><td class="paramname">AARUF_ERROR_CANNOT_WRITE_HEADER</td><td>Failed writing header or table data. </td></tr>
</table>
</dd>
</dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l00383">383</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00160">aaruf_crc64_data()</a>, <a class="el" href="errors_8h_source.html#l00060">AARUF_ERROR_CANNOT_WRITE_HEADER</a>, <a class="el" href="errors_8h_source.html#l00048">AARUF_ERROR_NOT_ENOUGH_MEMORY</a>, <a class="el" href="lzma_8c_source.html#l00065">aaruf_lzma_encode_buffer()</a>, <a class="el" href="errors_8h_source.html#l00075">AARUF_STATUS_OK</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="ddt_8h_source.html#l00161">DdtHeader2::cmpCrc64</a>, <a class="el" href="ddt_8h_source.html#l00159">DdtHeader2::cmpLength</a>, <a class="el" href="ddt_8h_source.html#l00145">DdtHeader2::compression</a>, <a class="el" href="context_8h_source.html#l00300">aaruformat_context::compression_enabled</a>, <a class="el" href="ddt_8h_source.html#l00162">DdtHeader2::crc64</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="enums_8h_source.html#l00143">DeDuplicationTable2</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="ddt_8h_source.html#l00158">DdtHeader2::entries</a>, <a class="el" href="ddt_8h_source.html#l00143">DdtHeader2::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="ddt_8h_source.html#l00160">DdtHeader2::length</a>, <a class="el" href="ddt_8h_source.html#l00146">DdtHeader2::levels</a>, <a class="el" href="enums_8h_source.html#l00034">Lzma</a>, <a class="el" href="context_8h_source.html#l00298">aaruformat_context::lzma_dict_size</a>, <a class="el" href="consts_8h_source.html#l00082">LZMA_PROPERTIES_LENGTH</a>, <a class="el" href="enums_8h_source.html#l00033">None</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="ddt_8h_source.html#l00148">DdtHeader2::previousLevelOffset</a>, <a class="el" href="ddt_8h_source.html#l00147">DdtHeader2::tableLevel</a>, <a class="el" href="ddt_8h_source.html#l00156">DdtHeader2::tableShift</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="ddt_8h_source.html#l00144">DdtHeader2::type</a>, <a class="el" href="context_8h_source.html#l00187">aaruformat_context::user_data_ddt2</a>, <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>, and <a class="el" href="enums_8h_source.html#l00046">UserData</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>, and <a class="el" href="close_8c_source.html#l00623">write_tape_ddt()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="aed9f90614002b887ae9f3ef2333de16a" name="aed9f90614002b887ae9f3ef2333de16a"></a>
<h2 class="memtitle"><span class="permalink"><a href="#aed9f90614002b887ae9f3ef2333de16a">&#9670;&#160;</a></span>write_tape_ddt()</h2>
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">int32_t write_tape_ddt </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Converts tape DDT hash table to array format and writes it as a single-level DDT. </p>
<p>This function is specifically designed for tape media images where sectors have been tracked using a sparse hash table (UTHASH) during write operations. It converts the hash-based tape DDT into a traditional array-based DDT structure suitable for serialization to disk. The function performs a complete transformation from the sparse hash representation to a dense array representation, then delegates the actual write operation to <a class="el" href="#a7314de0d71768709fa4ba2db7f89cdb9" title="Serialize a single-level DDT (tableShift == 0) directly after its header.">write_single_level_ddt()</a>.</p>
<p>The conversion process involves:</p><ol type="1">
<li>Validating the context is for tape media</li>
<li>Scanning the hash table to determine the maximum sector address (key)</li>
<li>Allocating a contiguous array large enough to hold all entries up to max_key</li>
<li>Populating the array by copying hash table entries to their corresponding indices</li>
<li>Initializing a DDT v2 header with appropriate metadata</li>
<li>Calling <a class="el" href="#a7314de0d71768709fa4ba2db7f89cdb9" title="Serialize a single-level DDT (tableShift == 0) directly after its header.">write_single_level_ddt()</a> to serialize the DDT to disk</li>
</ol>
<p><b>Hash Table to Array Conversion:</b> The tape DDT hash table uses sector addresses as keys and DDT entries as values. This function creates a zero-initialized array of size (max_key + 1) and copies each hash entry to array[entry-&gt;key] = entry-&gt;value. Sectors not present in the hash table remain as zero entries in the array, which indicates SectorStatusNotDumped in the DDT format.</p>
<p><b>Memory Allocation:</b> The function always uses BigDdtSizeType (32-bit entries) for tape DDTs, allocating (max_key + 1) * sizeof(uint32_t) bytes. This provides sufficient capacity for the 28-bit data + 4-bit status encoding used in tape DDT entries.</p>
<p><b>DDT Header Configuration:</b> The userDataDdtHeader is configured for a single-level DDT v2 structure:</p><ul>
<li>identifier: DeDuplicationTable2</li>
<li>type: UserData</li>
<li>compression: Determined by ctx-&gt;compression_enabled (Lzma or None)</li>
<li>levels: 1 (single-level structure)</li>
<li>tableLevel: 0 (top-level table)</li>
<li>tableShift: 0 (no multi-level indirection)</li>
<li>sizeType: BigDdtSizeType (32-bit entries)</li>
<li>entries/blocks: max_key + 1</li>
<li>negative/overflow: 0 (not used for tape)</li>
</ul>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to the aaruformat context. Must not be NULL and must be in write mode. The context must have is_tape set to true and tapeDdt hash table populated. The ctx-&gt;userDataDdtBig array will be allocated and populated by this function. The ctx-&gt;userDataDdtHeader will be initialized with DDT metadata.</td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>Returns one of the following status codes: </dd></dl>
<dl class="retval"><dt>Return values</dt><dd>
<table class="retval">
<tr><td class="paramname">AARUF_STATUS_OK</td><td>(0) Successfully converted and wrote the tape DDT. This occurs when:<ul>
<li>The context is valid and is_tape is true</li>
<li>Memory allocation for the DDT array succeeds</li>
<li>The hash table entries are successfully copied to the array</li>
<li><a class="el" href="#a7314de0d71768709fa4ba2db7f89cdb9" title="Serialize a single-level DDT (tableShift == 0) directly after its header.">write_single_level_ddt()</a> completes successfully</li>
<li>The DDT is written to disk and indexed</li>
</ul>
</td></tr>
<tr><td class="paramname">AARUF_STATUS_INVALID_CONTEXT</td><td>(-2) The context is not for tape media. This occurs when:<ul>
<li>ctx-&gt;is_tape is false</li>
<li>This function was called for a disk/optical image instead of tape</li>
</ul>
</td></tr>
2025-10-21 14:23:35 +01:00
<tr><td class="paramname">AARUF_ERROR_NOT_ENOUGH_MEMORY</td><td>(-9) Memory allocation failed. This occurs when:<ul>
2025-10-11 01:35:43 +01:00
<li>calloc() fails to allocate the userDataDdtBig array</li>
<li>Insufficient system memory for (max_key + 1) * 4 bytes</li>
</ul>
</td></tr>
2025-10-21 14:23:35 +01:00
<tr><td class="paramname">AARUF_ERROR_CANNOT_WRITE_HEADER</td><td>(-21) Writing the DDT failed. This can occur when:<ul>
2025-10-11 01:35:43 +01:00
<li><a class="el" href="#a7314de0d71768709fa4ba2db7f89cdb9" title="Serialize a single-level DDT (tableShift == 0) directly after its header.">write_single_level_ddt()</a> fails to write the DDT header</li>
<li>File I/O errors prevent writing the DDT data</li>
<li>Disk full or other storage errors</li>
<li>This error is propagated from <a class="el" href="#a7314de0d71768709fa4ba2db7f89cdb9" title="Serialize a single-level DDT (tableShift == 0) directly after its header.">write_single_level_ddt()</a></li>
</ul>
</td></tr>
</table>
</dd>
</dl>
<dl class="section note"><dt>Note</dt><dd>This function is only called during image finalization (aaruf_close) for tape images. It should not be called for disk or optical media images.</dd>
<dd>
Hash Table Iteration:<ul>
<li>Uses HASH_ITER macro from UTHASH to safely traverse all entries</li>
<li>Finds maximum key in first pass to determine array size</li>
<li>Copies entries in second pass to populate the array</li>
<li>Empty (zero) array slots represent sectors not written to tape</li>
</ul>
</dd>
<dd>
Memory Ownership:<ul>
<li>Allocates ctx-&gt;userDataDdtBig which becomes owned by the context</li>
<li>The allocated array is freed during context cleanup (not in this function)</li>
<li>The original hash table (ctx-&gt;tapeDdt) is freed separately during cleanup</li>
</ul>
</dd>
<dd>
Single-Level DDT Choice:<ul>
<li>Tape DDTs always use single-level structure (tableShift = 0)</li>
<li>Multi-level DDTs are not used because tape access patterns are typically sparse</li>
<li>The hash table already provides efficient sparse storage during write</li>
<li>Conversion to dense array only happens once at close time</li>
</ul>
</dd>
<dd>
Compression:<ul>
<li>The actual compression is handled by <a class="el" href="#a7314de0d71768709fa4ba2db7f89cdb9" title="Serialize a single-level DDT (tableShift == 0) directly after its header.">write_single_level_ddt()</a></li>
<li>Compression type is determined by ctx-&gt;compression_enabled flag</li>
<li>If enabled, LZMA compression is applied to the DDT array</li>
<li>Compression may be disabled if it doesn't reduce size</li>
</ul>
</dd></dl>
<dl class="section warning"><dt>Warning</dt><dd>The function assumes tapeDdt hash table is properly populated. An empty hash table will result in a DDT with a single zero entry (max_key = 0, entries = 1).</dd>
<dd>
This function modifies ctx-&gt;userDataDdtHeader and ctx-&gt;userDataDdtBig. These must not be modified by other code during the close operation.</dd>
<dd>
The allocated array size is (max_key + 1), which could be very large if tape sectors have high addresses with sparse distribution. Memory usage should be considered.</dd></dl>
<dl class="section see"><dt>See also</dt><dd><a class="el" href="internal_8h.html#a8241636367dc185ee88d1dc5af9caf59" title="Sets a DDT entry for tape media using a hash-based lookup table.">set_ddt_tape()</a> for how entries are added to the hash table during write operations </dd>
<dd>
<a class="el" href="#a7314de0d71768709fa4ba2db7f89cdb9" title="Serialize a single-level DDT (tableShift == 0) directly after its header.">write_single_level_ddt()</a> for the actual DDT serialization logic </dd>
<dd>
<a class="el" href="structTapeDdtHashEntry.html">TapeDdtHashEntry</a> for the hash table entry structure </dd></dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l00623">623</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="errors_8h_source.html#l00048">AARUF_ERROR_NOT_ENOUGH_MEMORY</a>, <a class="el" href="enums_8h_source.html#l00209">AARUF_STATUS_INVALID_CONTEXT</a>, <a class="el" href="ddt_8h_source.html#l00150">DdtHeader2::blocks</a>, <a class="el" href="ddt_8h_source.html#l00159">DdtHeader2::cmpLength</a>, <a class="el" href="ddt_8h_source.html#l00145">DdtHeader2::compression</a>, <a class="el" href="context_8h_source.html#l00300">aaruformat_context::compression_enabled</a>, <a class="el" href="enums_8h_source.html#l00143">DeDuplicationTable2</a>, <a class="el" href="ddt_8h_source.html#l00158">DdtHeader2::entries</a>, <a class="el" href="ddt_8h_source.html#l00143">DdtHeader2::identifier</a>, <a class="el" href="context_8h_source.html#l00305">aaruformat_context::is_tape</a>, <a class="el" href="context_8h_source.html#l00142">TapeDdtHashEntry::key</a>, <a class="el" href="ddt_8h_source.html#l00160">DdtHeader2::length</a>, <a class="el" href="ddt_8h_source.html#l00146">DdtHeader2::levels</a>, <a class="el" href="enums_8h_source.html#l00034">Lzma</a>, <a class="el" href="ddt_8h_source.html#l00149">DdtHeader2::negative</a>, <a class="el" href="enums_8h_source.html#l00033">None</a>, <a class="el" href="ddt_8h_source.html#l00151">DdtHeader2::overflow</a>, <a class="el" href="ddt_8h_source.html#l00148">DdtHeader2::previousLevelOffset</a>, <a class="el" href="ddt_8h_source.html#l00153">DdtHeader2::start</a>, <a class="el" href="ddt_8h_source.html#l00147">DdtHeader2::tableLevel</a>, <a class="el" href="ddt_8h_source.html#l00156">DdtHeader2::tableShift</a>, <a class="el" href="context_8h_source.html#l00182">aaruformat_context::tape_ddt</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="ddt_8h_source.html#l00144">DdtHeader2::type</a>, <a class="el" href="context_8h_source.html#l00187">aaruformat_context::user_data_ddt2</a>, <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>, <a class="el" href="enums_8h_source.html#l00046">UserData</a>, <a class="el" href="context_8h_source.html#l00143">TapeDdtHashEntry::value</a>, and <a class="el" href="close_8c_source.html#l00383">write_single_level_ddt()</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
2025-12-12 12:25:02 +00:00
<a id="a742ec2b4d57e32fa856033b1e4a04e9f" name="a742ec2b4d57e32fa856033b1e4a04e9f"></a>
<h2 class="memtitle"><span class="permalink"><a href="#a742ec2b4d57e32fa856033b1e4a04e9f">&#9670;&#160;</a></span>write_tape_file_block()</h2>
2025-10-11 01:35:43 +01:00
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_tape_file_block </td>
<td>(</td>
2025-12-12 12:25:02 +00:00
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
2025-10-11 01:35:43 +01:00
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the tape file metadata block to the image file. </p>
<p>This function writes a TapeFileBlock containing the complete tape file structure metadata to the Aaru image file. The tape file block documents all logical files present on the tape medium, recording each file's partition number, file number, and block range (first and last block addresses). This metadata enables random access to specific files within the tape image and preserves the original tape's logical organization for archival purposes.</p>
<p>The tape file block is optional; if no tape file metadata has been populated (ctx-&gt;tapeFiles hash table is NULL or empty), the function returns immediately without writing anything. This no-op behavior allows the close operation to proceed gracefully whether or not tape file structure metadata was included during image creation.</p>
<p><b>Block Structure:</b> The serialized block consists of: </p><div class="fragment"><div class="line">+-------------------------+</div>
<div class="line">| <a class="code hl_typedef" href="tape_8h.html#a0ce39d637f56346a0d859f94b8fc1f40">TapeFileHeader</a> (24 B) | &lt;- identifier, entries, length, crc64</div>
<div class="line">+-------------------------+</div>
<div class="line">| <a class="code hl_struct" href="structTapeFileEntry.html">TapeFileEntry</a> 0 (21 B) | &lt;- File, Partition, FirstBlock, LastBlock</div>
<div class="line">| <a class="code hl_struct" href="structTapeFileEntry.html">TapeFileEntry</a> 1 (21 B) |</div>
<div class="line">| ... |</div>
<div class="line">| <a class="code hl_typedef" href="tape_8h.html#ade8125364d763d57d167c0b521beaf64">TapeFileEntry</a> (n-1) |</div>
<div class="line">+-------------------------+</div>
<div class="ttc" id="astructTapeFileEntry_html"><div class="ttname"><a href="structTapeFileEntry.html">TapeFileEntry</a></div><div class="ttdoc">Describes a single logical file on a tape medium.</div><div class="ttdef"><b>Definition</b> <a href="tape_8h_source.html#l00133">tape.h:134</a></div></div>
<div class="ttc" id="atape_8h_html_a0ce39d637f56346a0d859f94b8fc1f40"><div class="ttname"><a href="tape_8h.html#a0ce39d637f56346a0d859f94b8fc1f40">TapeFileHeader</a></div><div class="ttdeci">struct TapeFileHeader TapeFileHeader</div></div>
<div class="ttc" id="atape_8h_html_ade8125364d763d57d167c0b521beaf64"><div class="ttname"><a href="tape_8h.html#ade8125364d763d57d167c0b521beaf64">TapeFileEntry</a></div><div class="ttdeci">struct TapeFileEntry TapeFileEntry</div></div>
</div><!-- fragment --><p><b>Processing Flow:</b></p><ol type="1">
<li><b>Entry Enumeration:</b> Iterate through ctx-&gt;tapeFiles hash table to count entries</li>
<li><b>Buffer Allocation:</b> Allocate temporary buffer for all <a class="el" href="structTapeFileEntry.html" title="Describes a single logical file on a tape medium.">TapeFileEntry</a> structures</li>
<li><b>Data Copying:</b> Copy each file entry from hash table to buffer sequentially</li>
<li><b>Header Construction:</b> Build <a class="el" href="structTapeFileHeader.html" title="Header for a tape file metadata block containing file layout information.">TapeFileHeader</a> with entry count and CRC64 checksum</li>
<li><b>Alignment:</b> Seek to EOF and align to block boundary (blockAlignmentShift)</li>
<li><b>Write Operations:</b> Write header followed by entry array to image stream</li>
<li><b>Indexing:</b> Add <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> pointing to this block for fast location during reads</li>
<li><b>Cleanup:</b> Free temporary buffer</li>
</ol>
<p><b>Hash Table Iteration:</b> The function uses UTHASH's HASH_ITER macro to safely traverse ctx-&gt;tapeFiles:</p><ul>
<li>First pass: Count total entries in the hash table</li>
<li>Second pass: Copy each <a class="el" href="structTapeFileEntry.html" title="Describes a single logical file on a tape medium.">TapeFileEntry</a> to the output buffer</li>
<li>The iteration order depends on hash table internals, not insertion order</li>
<li>For deterministic output, entries could be sorted before writing (not currently done)</li>
</ul>
<p><b>CRC64 Integrity Protection:</b> A CRC64-ECMA checksum is computed over the complete array of <a class="el" href="structTapeFileEntry.html" title="Describes a single logical file on a tape medium.">TapeFileEntry</a> structures using <a class="el" href="decls_8h.html#a0fee4834bf0747bcd933c4e754aa4692">aaruf_crc64_data()</a>. This checksum is stored in the <a class="el" href="structTapeFileHeader.html" title="Header for a tape file metadata block containing file layout information.">TapeFileHeader</a> and verified during image opening by <a class="el" href="internal_8h.html#a829bbac3c17b60efd8f93188a8de8278" title="Processes a tape file metadata block from the image stream.">process_tape_files_block()</a> to detect corruption in the file table. The checksum covers only the entry data, not the header itself.</p>
<p><b>Alignment Strategy:</b> Before writing, the file position is:</p><ol type="1">
<li>Moved to EOF using fseek(SEEK_END)</li>
<li>Aligned forward to next boundary: (position + alignment_mask) &amp; ~alignment_mask</li>
<li>Where alignment_mask = (1 &lt;&lt; blockAlignmentShift) - 1 This ensures the tape file block starts on a properly aligned offset for efficient I/O and compliance with the Aaru format specification.</li>
</ol>
<p><b>Write Sequence:</b> The function performs a two-stage write operation:</p><ol type="1">
<li>Write <a class="el" href="structTapeFileHeader.html" title="Header for a tape file metadata block containing file layout information.">TapeFileHeader</a> (sizeof(TapeFileHeader) = 24 bytes)</li>
<li>Write <a class="el" href="structTapeFileEntry.html" title="Describes a single logical file on a tape medium.">TapeFileEntry</a> array (tape_file_block.length bytes)</li>
</ol>
<p>Both writes must succeed for the index entry to be added. If either write fails, the block is incomplete but the function continues (no error propagation).</p>
<p><b>Indexing:</b> On successful write, an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> is created and pushed to ctx-&gt;indexEntries:</p><ul>
<li>blockType = TapeFileBlock (identifies this as tape file metadata)</li>
<li>dataType = 0 (tape file blocks have no subtype)</li>
<li>offset = file position where <a class="el" href="structTapeFileHeader.html" title="Header for a tape file metadata block containing file layout information.">TapeFileHeader</a> was written</li>
</ul>
<p>This index entry enables <a class="el" href="internal_8h.html#a829bbac3c17b60efd8f93188a8de8278" title="Processes a tape file metadata block from the image stream.">process_tape_files_block()</a> to quickly locate the tape file metadata during subsequent image opens without scanning the entire file.</p>
<p><b>Entry Order:</b> The current implementation writes entries in hash table iteration order, which is non-deterministic and depends on the hash function and insertion sequence. For better compatibility and reproducibility, entries should ideally be sorted by:</p><ol type="1">
<li>Partition number (ascending)</li>
<li>File number within partition (ascending) However, the current implementation does not enforce this ordering.</li>
</ol>
<p><b>Error Handling:</b> The function handles errors gracefully without propagating them:</p><ul>
<li>NULL hash table: Return immediately (no tape files to write)</li>
<li>Memory allocation failure: Log via TRACE and return (block not written)</li>
<li>Write failures: Silent (index entry not added, block incomplete)</li>
</ul>
<p>This opportunistic approach ensures that tape file metadata write failures do not prevent the image from being created, though the resulting image will lack file structure metadata.</p>
<p><b>Memory Management:</b></p><ul>
<li>Allocates temporary buffer sized to hold all <a class="el" href="structTapeFileEntry.html" title="Describes a single logical file on a tape medium.">TapeFileEntry</a> structures</li>
<li>Buffer is zero-initialized with memset for consistent padding bytes</li>
<li>Buffer is always freed before the function returns, even on write failure</li>
<li>Source data in ctx-&gt;tapeFiles is not modified and is freed later during cleanup</li>
</ul>
<p><b>Thread Safety:</b> This function is NOT thread-safe. It modifies shared ctx state (imageStream file position, indexEntries array) and must only be called during single-threaded finalization (within aaruf_close).</p>
<p><b>Use Cases:</b></p><ul>
<li>Preserving tape file structure for archival and forensic purposes</li>
<li>Enabling random access to specific files within tape images</li>
<li>Documenting multi-file tape organization for analysis tools</li>
<li>Supporting tape formats with complex file/partition layouts</li>
<li>Facilitating tape image validation and structure verification</li>
</ul>
<p><b>Relationship to Other Functions:</b></p><ul>
<li>File entries are added via <a class="el" href="decls_8h.html#a01c915ab49a4b47fd6768a2055208c48" title="Sets or updates the block range for a specific tape file in an Aaru tape image.">aaruf_set_tape_file()</a> during image creation</li>
<li>Entries are stored in ctx-&gt;tapeFiles hash table until image close</li>
<li>This function serializes the hash table to disk during <a class="el" href="#a6823e139f81a9dfd08efcb0e9b213a49" title="Close an Aaru image context, flushing pending data structures and releasing resources.">aaruf_close()</a></li>
2025-12-12 12:25:02 +00:00
<li><a class="el" href="internal_8h.html#a829bbac3c17b60efd8f93188a8de8278" title="Processes a tape file metadata block from the image stream.">process_tape_files_block()</a> reads and reconstructs the hash table during <a class="el" href="decls_8h.html#a5cea94dcb9c08a646f7f7160ec8418de" title="Opens an existing AaruFormat image file.">aaruf_open()</a></li>
2025-10-11 01:35:43 +01:00
</ul>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. Must not be NULL. The tapeFiles hash table should be populated if tape file metadata exists. The imageStream must be open and writable. The indexEntries array must be initialized for adding the index entry.</td></tr>
</table>
</dd>
</dl>
<dl class="section note"><dt>Note</dt><dd>The tape file block is written near the end of the image file, after sector data and before the final index block. The exact position depends on what other metadata blocks are present in the image.</dd>
<dd>
If ctx-&gt;tapeFiles is NULL or empty, the function returns immediately without writing anything. This is not an error condition - it simply means the image contains no tape file structure metadata.</dd>
<dd>
Memory allocation failure during buffer creation results in no tape file block being written, but does not prevent the image from being successfully created. The image will simply lack tape file metadata.</dd>
<dd>
The <a class="el" href="structTapeFileHeader.html#a319aea86a448c0b969de944f22e551c0" title="Number of file entries following this header.">TapeFileHeader.entries</a> field is intentionally set to tape_file_count, not stored separately. The count is derived dynamically from the hash table size.</dd>
<dd>
Entry ordering is not guaranteed to match insertion order or logical order. Reading applications should sort entries by partition/file number if ordered access is required.</dd></dl>
<dl class="section warning"><dt>Warning</dt><dd>Write failures (fwrite returns != 1) are silently ignored. The function does not return an error code or set errno. Partial writes may leave the block incomplete, which will be detected during subsequent reads via CRC mismatch.</dd>
<dd>
The temporary buffer allocation may fail on systems with limited memory or when the tape has an extremely large number of files. Allocation failures result in silent no-op; the image is created without tape file metadata.</dd>
<dd>
Bounds checking during iteration protects against buffer overruns. If index exceeds tape_file_count (which should never occur), the loop breaks early as a sanity check.</dd></dl>
<dl class="section see"><dt>See also</dt><dd><a class="el" href="structTapeFileHeader.html" title="Header for a tape file metadata block containing file layout information.">TapeFileHeader</a> for the block header structure definition </dd>
<dd>
<a class="el" href="structTapeFileEntry.html" title="Describes a single logical file on a tape medium.">TapeFileEntry</a> for individual file entry structure definition </dd>
<dd>
<a class="el" href="context_8h.html#a5ba965cb003bc2d68a9f9e1c11225494">tapeFileHashEntry</a> for the hash table entry structure </dd>
<dd>
<a class="el" href="decls_8h.html#a01c915ab49a4b47fd6768a2055208c48" title="Sets or updates the block range for a specific tape file in an Aaru tape image.">aaruf_set_tape_file()</a> for adding tape files during image creation </dd>
<dd>
<a class="el" href="internal_8h.html#a829bbac3c17b60efd8f93188a8de8278" title="Processes a tape file metadata block from the image stream.">process_tape_files_block()</a> for the loading process during image opening </dd>
<dd>
<a class="el" href="decls_8h.html#a1c8d4faf14212a4c46c1fb47bf25ac1e" title="Retrieves the block range for a specific tape file from an Aaru tape image.">aaruf_get_tape_file()</a> for retrieving tape file information from opened images </dd></dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l02724">2724</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00160">aaruf_crc64_data()</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="tape_8h_source.html#l00245">TapeFileHeader::crc64</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="context_8h_source.html#l00129">TapeFileHashEntry::fileEntry</a>, <a class="el" href="tape_8h_source.html#l00239">TapeFileHeader::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="tape_8h_source.html#l00243">TapeFileHeader::length</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="context_8h_source.html#l00303">aaruformat_context::tape_files</a>, <a class="el" href="enums_8h_source.html#l00157">TapeFileBlock</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
2025-12-12 12:25:02 +00:00
<a id="ae333a9d69b81891b260907fd7d0665e1" name="ae333a9d69b81891b260907fd7d0665e1"></a>
<h2 class="memtitle"><span class="permalink"><a href="#ae333a9d69b81891b260907fd7d0665e1">&#9670;&#160;</a></span>write_tape_partition_block()</h2>
2025-10-11 01:35:43 +01:00
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_tape_partition_block </td>
<td>(</td>
2025-12-12 12:25:02 +00:00
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
2025-10-11 01:35:43 +01:00
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the tape partition metadata block to the image file. </p>
<p>This function writes a TapePartitionBlock containing the complete tape partition structure metadata to the Aaru image file. The tape partition block documents all physical partitions present on the tape medium, recording each partition's partition number and block range (first and last block addresses). This metadata enables proper interpretation of tape file locations, validation of partition boundaries, and preservation of the original tape's physical organization for archival purposes.</p>
<p>The tape partition block is optional; if no tape partition metadata has been populated (ctx-&gt;tapePartitions hash table is NULL or empty), the function returns immediately without writing anything. This no-op behavior allows the close operation to proceed gracefully whether or not tape partition structure metadata was included during image creation.</p>
<p><b>Block Structure:</b> The serialized block consists of: </p><div class="fragment"><div class="line">+-----------------------------+</div>
<div class="line">| <a class="code hl_typedef" href="tape_8h.html#a4f28f93bd2166f390ec24f1c3525584f">TapePartitionHeader</a> (24 B) | &lt;- identifier, entries, length, crc64</div>
<div class="line">+-----------------------------+</div>
<div class="line">| <a class="code hl_struct" href="structTapePartitionEntry.html">TapePartitionEntry</a> 0 (17 B) | &lt;- Number, FirstBlock, LastBlock</div>
<div class="line">| <a class="code hl_struct" href="structTapePartitionEntry.html">TapePartitionEntry</a> 1 (17 B) |</div>
<div class="line">| ... |</div>
<div class="line">| <a class="code hl_typedef" href="tape_8h.html#af947dbe92eb87a6bba23183f14686539">TapePartitionEntry</a> (n-1) |</div>
<div class="line">+-----------------------------+</div>
<div class="ttc" id="astructTapePartitionEntry_html"><div class="ttname"><a href="structTapePartitionEntry.html">TapePartitionEntry</a></div><div class="ttdoc">Describes a single physical partition on a tape medium.</div><div class="ttdef"><b>Definition</b> <a href="tape_8h_source.html#l00319">tape.h:320</a></div></div>
<div class="ttc" id="atape_8h_html_a4f28f93bd2166f390ec24f1c3525584f"><div class="ttname"><a href="tape_8h.html#a4f28f93bd2166f390ec24f1c3525584f">TapePartitionHeader</a></div><div class="ttdeci">struct TapePartitionHeader TapePartitionHeader</div></div>
<div class="ttc" id="atape_8h_html_af947dbe92eb87a6bba23183f14686539"><div class="ttname"><a href="tape_8h.html#af947dbe92eb87a6bba23183f14686539">TapePartitionEntry</a></div><div class="ttdeci">struct TapePartitionEntry TapePartitionEntry</div></div>
</div><!-- fragment --><p><b>Processing Flow:</b></p><ol type="1">
<li><b>Entry Enumeration:</b> Iterate through ctx-&gt;tapePartitions hash table to count entries</li>
<li><b>Buffer Allocation:</b> Allocate temporary buffer for all <a class="el" href="structTapePartitionEntry.html" title="Describes a single physical partition on a tape medium.">TapePartitionEntry</a> structures</li>
<li><b>Data Copying:</b> Copy each partition entry from hash table to buffer sequentially</li>
<li><b>Header Construction:</b> Build <a class="el" href="structTapePartitionHeader.html" title="Header for a tape partition metadata block containing partition layout information.">TapePartitionHeader</a> with entry count and CRC64 checksum</li>
<li><b>Alignment:</b> Seek to EOF and align to block boundary (blockAlignmentShift)</li>
<li><b>Write Operations:</b> Write header followed by entry array to image stream</li>
<li><b>Indexing:</b> Add <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> pointing to this block for fast location during reads</li>
<li><b>Cleanup:</b> Free temporary buffer</li>
</ol>
<p><b>Hash Table Iteration:</b> The function uses UTHASH's HASH_ITER macro to safely traverse ctx-&gt;tapePartitions:</p><ul>
<li>First pass: Count total entries in the hash table</li>
<li>Second pass: Copy each <a class="el" href="structTapePartitionEntry.html" title="Describes a single physical partition on a tape medium.">TapePartitionEntry</a> to the output buffer</li>
<li>The iteration order depends on hash table internals, not insertion order</li>
<li>For deterministic output, entries could be sorted by partition number (not currently done)</li>
</ul>
<p><b>CRC64 Integrity Protection:</b> A CRC64-ECMA checksum is computed over the complete array of <a class="el" href="structTapePartitionEntry.html" title="Describes a single physical partition on a tape medium.">TapePartitionEntry</a> structures using <a class="el" href="decls_8h.html#a0fee4834bf0747bcd933c4e754aa4692">aaruf_crc64_data()</a>. This checksum is stored in the <a class="el" href="structTapePartitionHeader.html" title="Header for a tape partition metadata block containing partition layout information.">TapePartitionHeader</a> and verified during image opening by <a class="el" href="internal_8h.html#aa76718b0402b1a28be3d563d5e62028e" title="Processes a tape partition metadata block from the image stream.">process_tape_partitions_block()</a> to detect corruption in the partition table. The checksum covers only the entry data, not the header itself.</p>
<p><b>Alignment Strategy:</b> Before writing, the file position is:</p><ol type="1">
<li>Moved to EOF using fseek(SEEK_END)</li>
<li>Aligned forward to next boundary: (position + alignment_mask) &amp; ~alignment_mask</li>
<li>Where alignment_mask = (1 &lt;&lt; blockAlignmentShift) - 1 This ensures the tape partition block starts on a properly aligned offset for efficient I/O and compliance with the Aaru format specification.</li>
</ol>
<p><b>Write Sequence:</b> The function performs a two-stage write operation:</p><ol type="1">
<li>Write <a class="el" href="structTapePartitionHeader.html" title="Header for a tape partition metadata block containing partition layout information.">TapePartitionHeader</a> (sizeof(TapePartitionHeader) = 24 bytes)</li>
<li>Write <a class="el" href="structTapePartitionEntry.html" title="Describes a single physical partition on a tape medium.">TapePartitionEntry</a> array (tape_partition_block.length bytes)</li>
</ol>
<p>Both writes must succeed for the index entry to be added. If either write fails, the block is incomplete but the function continues (no error propagation).</p>
<p><b>Indexing:</b> On successful write, an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> is created and pushed to ctx-&gt;indexEntries:</p><ul>
<li>blockType = TapePartitionBlock (identifies this as tape partition metadata)</li>
<li>dataType = 0 (tape partition blocks have no subtype)</li>
<li>offset = file position where <a class="el" href="structTapePartitionHeader.html" title="Header for a tape partition metadata block containing partition layout information.">TapePartitionHeader</a> was written</li>
</ul>
<p>This index entry enables <a class="el" href="internal_8h.html#aa76718b0402b1a28be3d563d5e62028e" title="Processes a tape partition metadata block from the image stream.">process_tape_partitions_block()</a> to quickly locate the tape partition metadata during subsequent image opens without scanning the entire file.</p>
<p><b>Entry Order:</b> The current implementation writes entries in hash table iteration order, which is non-deterministic and depends on the hash function and insertion sequence. For better compatibility and reproducibility, entries should ideally be sorted by partition number (ascending). However, the current implementation does not enforce this ordering.</p>
<p><b>Partition Block Ranges:</b> Each partition entry defines an independent block address space:</p><ul>
<li>FirstBlock: Starting block address (often 0, but format-dependent)</li>
<li>LastBlock: Ending block address (inclusive)</li>
<li>Block count: (LastBlock - FirstBlock + 1)</li>
</ul>
<p>Different partitions may have overlapping logical block numbers (e.g., partition 0 and partition 1 can both have blocks 0-1000). The partition metadata is essential for correctly interpreting tape file locations, as files reference partition numbers in their definitions.</p>
<p><b>Error Handling:</b> The function handles errors gracefully without propagating them:</p><ul>
<li>NULL hash table: Return immediately (no tape partitions to write)</li>
<li>Memory allocation failure: Log via TRACE and return (block not written)</li>
<li>Write failures: Silent (index entry not added, block incomplete)</li>
</ul>
<p>This opportunistic approach ensures that tape partition metadata write failures do not prevent the image from being created, though the resulting image will lack partition structure metadata.</p>
<p><b>Memory Management:</b></p><ul>
<li>Allocates temporary buffer sized to hold all <a class="el" href="structTapePartitionEntry.html" title="Describes a single physical partition on a tape medium.">TapePartitionEntry</a> structures</li>
<li>Buffer is zero-initialized with memset for consistent padding bytes</li>
<li>Buffer is always freed before the function returns, even on write failure</li>
<li>Source data in ctx-&gt;tapePartitions is not modified and is freed later during cleanup</li>
</ul>
<p><b>Thread Safety:</b> This function is NOT thread-safe. It modifies shared ctx state (imageStream file position, indexEntries array) and must only be called during single-threaded finalization (within aaruf_close).</p>
<p><b>Use Cases:</b></p><ul>
<li>Preserving tape partition structure for archival and forensic purposes</li>
<li>Documenting multi-partition tape layouts (LTO, DLT, AIT formats)</li>
<li>Enabling validation of file block ranges against partition boundaries</li>
<li>Supporting tape formats with complex partition organizations</li>
<li>Facilitating tape image validation and structure verification</li>
</ul>
<p><b>Relationship to Other Functions:</b></p><ul>
<li>Partition entries are added via <a class="el" href="decls_8h.html#a9daeeb54c74dd2707d95ab47e8ab0a00" title="Sets or updates the block range for a specific tape partition in an Aaru tape image.">aaruf_set_tape_partition()</a> during image creation</li>
<li>Entries are stored in ctx-&gt;tapePartitions hash table until image close</li>
<li>This function serializes the hash table to disk during <a class="el" href="#a6823e139f81a9dfd08efcb0e9b213a49" title="Close an Aaru image context, flushing pending data structures and releasing resources.">aaruf_close()</a></li>
2025-12-12 12:25:02 +00:00
<li><a class="el" href="internal_8h.html#aa76718b0402b1a28be3d563d5e62028e" title="Processes a tape partition metadata block from the image stream.">process_tape_partitions_block()</a> reads and reconstructs the hash table during <a class="el" href="decls_8h.html#a5cea94dcb9c08a646f7f7160ec8418de" title="Opens an existing AaruFormat image file.">aaruf_open()</a></li>
2025-10-11 01:35:43 +01:00
<li>Tape files (written by write_tape_file_block) reference these partitions</li>
</ul>
<p><b>Format Considerations:</b></p><ul>
<li>Single-partition tapes: May omit TapePartitionBlock entirely (partition 0 implied)</li>
<li>Multi-partition tapes: Should include complete partition layout for proper file access</li>
<li>Block addresses are local to each partition in most tape formats</li>
<li>Partition metadata is primarily informational and used for validation</li>
</ul>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. Must not be NULL. The tapePartitions hash table should be populated if tape partition metadata exists. The imageStream must be open and writable. The indexEntries array must be initialized for adding the index entry.</td></tr>
</table>
</dd>
</dl>
<dl class="section note"><dt>Note</dt><dd>The tape partition block is written near the end of the image file, after sector data and before the final index block. The exact position depends on what other metadata blocks are present in the image.</dd>
<dd>
If ctx-&gt;tapePartitions is NULL or empty, the function returns immediately without writing anything. This is not an error condition - it simply means the image contains no tape partition structure metadata (typical for single-partition tapes).</dd>
<dd>
Memory allocation failure during buffer creation results in no tape partition block being written, but does not prevent the image from being successfully created. The image will simply lack tape partition metadata.</dd>
<dd>
The partition metadata should be consistent with file metadata. Files should only reference partitions that have been defined, and their block ranges should fall within the partition boundaries, though no automatic validation is performed.</dd></dl>
<dl class="section warning"><dt>Warning</dt><dd>Write failures are not propagated as errors. If the write operation fails, the index entry is not added, but <a class="el" href="#a6823e139f81a9dfd08efcb0e9b213a49" title="Close an Aaru image context, flushing pending data structures and releasing resources.">aaruf_close()</a> continues with other finalization tasks. The resulting image may be incomplete or missing partition metadata.</dd></dl>
2025-12-12 12:25:02 +00:00
<dl class="section see"><dt>See also</dt><dd><a class="el" href="#a742ec2b4d57e32fa856033b1e4a04e9f" title="Serialize the tape file metadata block to the image file.">write_tape_file_block()</a> for writing tape file metadata (which references partitions) </dd>
2025-10-11 01:35:43 +01:00
<dd>
<a class="el" href="internal_8h.html#aa76718b0402b1a28be3d563d5e62028e" title="Processes a tape partition metadata block from the image stream.">process_tape_partitions_block()</a> for reading partition metadata during image open </dd>
<dd>
<a class="el" href="decls_8h.html#a9daeeb54c74dd2707d95ab47e8ab0a00" title="Sets or updates the block range for a specific tape partition in an Aaru tape image.">aaruf_set_tape_partition()</a> for adding partition entries during image creation </dd>
<dd>
<a class="el" href="structTapePartitionHeader.html" title="Header for a tape partition metadata block containing partition layout information.">TapePartitionHeader</a> for the block header structure </dd>
<dd>
<a class="el" href="structTapePartitionEntry.html" title="Describes a single physical partition on a tape medium.">TapePartitionEntry</a> for individual partition entry structure </dd></dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l02957">2957</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="crc64_8c_source.html#l00160">aaruf_crc64_data()</a>, <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="tape_8h_source.html#l00448">TapePartitionHeader::crc64</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="tape_8h_source.html#l00442">TapePartitionHeader::identifier</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="tape_8h_source.html#l00446">TapePartitionHeader::length</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="context_8h_source.html#l00136">TapePartitionHashEntry::partitionEntry</a>, <a class="el" href="context_8h_source.html#l00304">aaruformat_context::tape_partitions</a>, <a class="el" href="enums_8h_source.html#l00158">TapePartitionBlock</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
<a id="aa2451e6c0fc8d4db3bfb9874f2ca990c" name="aa2451e6c0fc8d4db3bfb9874f2ca990c"></a>
<h2 class="memtitle"><span class="permalink"><a href="#aa2451e6c0fc8d4db3bfb9874f2ca990c">&#9670;&#160;</a></span>write_tracks_block()</h2>
<div class="memitem">
<div class="memproto">
<table class="mlabels">
<tr>
<td class="mlabels-left">
<table class="memname">
<tr>
<td class="memname">void write_tracks_block </td>
<td>(</td>
<td class="paramtype"><a class="el" href="structaaruformat__context.html">aaruformat_context</a> *</td> <td class="paramname"><span class="paramname"><em>ctx</em></span></td><td>)</td>
<td></td>
</tr>
</table>
</td>
<td class="mlabels-right">
<span class="mlabels"><span class="mlabel static">static</span></span> </td>
</tr>
</table>
</div><div class="memdoc">
<p>Serialize the tracks metadata block and add it to the index. </p>
<p>Writes a <a class="el" href="structTracksHeader.html" title="Header for an optical tracks block listing track entries.">TracksHeader</a> followed by the array of <a class="el" href="structTrackEntry.html" title="Single optical disc track descriptor (sequence, type, LBAs, session, ISRC, flags).">TrackEntry</a> structures if any track entries are present (tracksHeader.entries &gt; 0 and trackEntries not NULL). The block is aligned to the DDT block boundary and an <a class="el" href="structIndexEntry.html" title="Single index entry describing a block&#39;s type, (optional) data classification, and file offset.">IndexEntry</a> is appended.</p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">ctx</td><td>Pointer to an initialized aaruformatContext in write mode. </td></tr>
</table>
</dd>
</dl>
2025-12-12 12:25:02 +00:00
<p class="definition">Definition at line <a class="el" href="close_8c_source.html#l00826">826</a> of file <a class="el" href="close_8c_source.html">close.c</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">References <a class="el" href="ddt_8h_source.html#l00154">DdtHeader2::blockAlignmentShift</a>, <a class="el" href="index_8h_source.html#l00110">IndexEntry::blockType</a>, <a class="el" href="index_8h_source.html#l00111">IndexEntry::dataType</a>, <a class="el" href="context_8h_source.html#l00330">aaruformat_context::dirty_index_block</a>, <a class="el" href="optical_8h_source.html#l00064">TracksHeader::entries</a>, <a class="el" href="context_8h_source.html#l00176">aaruformat_context::imageStream</a>, <a class="el" href="context_8h_source.html#l00252">aaruformat_context::index_entries</a>, <a class="el" href="index_8h_source.html#l00112">IndexEntry::offset</a>, <a class="el" href="log_8h_source.html#l00025">TRACE</a>, <a class="el" href="context_8h_source.html#l00242">aaruformat_context::track_entries</a>, <a class="el" href="context_8h_source.html#l00244">aaruformat_context::tracks_header</a>, <a class="el" href="enums_8h_source.html#l00150">TracksBlock</a>, and <a class="el" href="context_8h_source.html#l00189">aaruformat_context::user_data_ddt_header</a>.</p>
2025-10-11 01:35:43 +01:00
2025-12-12 12:25:02 +00:00
<p class="reference">Referenced by <a class="el" href="close_8c_source.html#l04059">aaruf_close()</a>.</p>
2025-10-11 01:35:43 +01:00
</div>
</div>
</div><!-- contents -->
</div><!-- doc-content -->
<div id="page-nav" class="page-nav-panel">
<div id="page-nav-resize-handle"></div>
<div id="page-nav-tree">
<div id="page-nav-contents">
</div><!-- page-nav-contents -->
</div><!-- page-nav-tree -->
</div><!-- page-nav -->
</div><!-- container -->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
<li class="navelem"><a href="dir_68267d1309a1af8e8297ef4c3efbcdba.html">src</a></li><li class="navelem"><a href="close_8c.html">close.c</a></li>
<li class="footer">Generated by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.14.0 </li>
</ul>
</div>
</body>
</html>