84 TRACE(
"Entering aaruf_set_erasure_coding(%p, %u, %u, %u)", context, algorithm,
K, M);
102 if(max_payload == 0) max_payload = sectors_per_block * 512;
110 uint8_t **parity = (uint8_t **)calloc((
size_t)
K * M,
sizeof(uint8_t *));
113 for(uint32_t i = 0; i < (uint32_t)
K * M; i++)
115 parity[i] = (uint8_t *)calloc(1, shard_size);
118 for(uint32_t j = 0; j < i; j++) free(parity[j]);
126 uint64_t *offsets = (uint64_t *)calloc((
size_t)
K *
K,
sizeof(uint64_t));
127 uint32_t *sizes = (uint32_t *)calloc((
size_t)
K *
K,
sizeof(uint32_t));
128 uint64_t *crcs = (uint64_t *)calloc((
size_t)
K *
K,
sizeof(uint64_t));
129 uint16_t *counts = (uint16_t *)calloc(
K,
sizeof(uint16_t));
131 if(!offsets || !sizes || !crcs || !counts)
133 free(offsets); free(sizes); free(crcs); free(counts);
134 for(uint32_t i = 0; i < (uint32_t)
K * M; i++) free(parity[i]);
141 UT_array *stripes = NULL;
162 TRACE(
"Erasure coding configured: algorithm=%u K=%u M=%u shard_size=%u", algorithm,
K, M, shard_size);
163 TRACE(
"Exiting aaruf_set_erasure_coding() = 0");
195 TRACE(
"Entering aaruf_set_erasure_coding_auto(%p, %u)", context, recovery_percent);
197 if(recovery_percent == 0 || recovery_percent > 100)
203 uint16_t M = (uint16_t)((20 * (uint32_t)recovery_percent + 50) / 100);
207 uint16_t
K = (uint16_t)(M * 100 / recovery_percent);
209 if(
K + M > 255)
K = 255 - M;
211 TRACE(
"Auto EC: recovery_percent=%u -> K=%u M=%u", recovery_percent,
K, M);
229 const uint8_t *payload, uint32_t payload_size, uint64_t file_offset)
233 const uint16_t
K = ctx->
ec_K;
234 const uint16_t M = ctx->
ec_M;
246 uint32_t actual_size = (uint32_t)
sizeof(
BlockHeader);
249 actual_size += payload_size;
252 uint8_t *shard_buf = (uint8_t *)calloc(1, shard);
253 if(!shard_buf)
return;
256 memcpy(shard_buf, block_header,
sizeof(
BlockHeader));
267 memcpy(shard_buf + offset, payload, payload_size);
273 size_t tracking_idx = (size_t)slot *
K + pos;
279 for(uint16_t m = 0; m < M; m++)
282 size_t parity_idx = (size_t)slot * M + m;
306 const uint16_t
K = ctx->
ec_K;
307 const uint16_t M = ctx->
ec_M;
311 if(actual_k == 0)
return;
320 uint8_t *desc = (uint8_t *)calloc(1, desc_data_size);
326 memcpy(p, &actual_k,
sizeof(uint16_t)); p +=
sizeof(uint16_t);
329 for(uint16_t k = 0; k < actual_k; k++)
331 size_t idx = (size_t)slot *
K + k;
342 for(uint16_t m = 0; m < M; m++)
344 size_t parity_idx = (size_t)slot * M + m;
354 parity_header.
length = shard;
360 uint8_t *cmp_buf = NULL;
365 cmp_buf = (uint8_t *)malloc((
size_t)shard * 2);
372 if(cmp_size > 0 && cmp_size < shard)
375 parity_header.
cmpLength = (uint32_t)cmp_size;
387 size_t dst_size = (size_t)shard * 2;
401 parity_offset = (parity_offset + alignment_mask) & ~alignment_mask;
411 pentry.
offset = parity_offset;
416 .offset = parity_offset};
425 memset(parity_data, 0, shard);
440 parity_offset = (parity_offset + alignment_mask) & ~alignment_mask;
456 pentry.
offset = parity_offset;
469 memset(parity_data, 0, shard);
473 for(
size_t i = 0; i < desc_data_size; i++)
479 for(uint16_t k = 0; k <
K; k++)
481 size_t idx = (size_t)slot *
K + k;
496 const uint64_t *offsets,
const uint32_t *sizes,
497 uint32_t block_count, uint8_t group_type,
498 uint16_t parity_data_type,
499 uint8_t **out_desc,
size_t *out_desc_len,
504 if(block_count == 0)
return;
506 const uint16_t M = ctx->
ec_M;
507 uint16_t actual_k = (uint16_t)(block_count > (uint32_t)(255 - M) ? 255 - M : block_count);
509 uint32_t shard_size = 0;
510 for(uint32_t i = 0; i < actual_k; i++)
511 if(sizes[i] > shard_size) shard_size = sizes[i];
516 uint8_t **parity = (uint8_t **)calloc(M,
sizeof(uint8_t *));
517 if(!parity) {
rs_free(rs);
return; }
518 for(uint16_t m = 0; m < M; m++)
520 parity[m] = (uint8_t *)calloc(1, shard_size);
521 if(!parity[m]) {
for(uint16_t j = 0; j < m; j++) free(parity[j]); free(parity);
rs_free(rs);
return; }
526 uint8_t *desc = (uint8_t *)calloc(1, desc_size);
527 if(!desc) {
for(uint16_t m = 0; m < M; m++) free(parity[m]); free(parity);
rs_free(rs);
return; }
530 memcpy(dp, &actual_k,
sizeof(uint16_t)); dp +=
sizeof(uint16_t);
532 uint8_t *shard_buf = (uint8_t *)calloc(1, shard_size);
533 if(!shard_buf) { free(desc);
for(uint16_t m = 0; m < M; m++) free(parity[m]); free(parity);
rs_free(rs);
return; }
535 for(uint16_t k = 0; k < actual_k; k++)
537 memset(shard_buf, 0, shard_size);
539 uint32_t read_size = sizes[k] > shard_size ? shard_size : sizes[k];
548 for(uint16_t m = 0; m < M; m++)
557 for(uint16_t m = 0; m < M; m++)
560 memset(&ph, 0,
sizeof(ph));
566 uint8_t *write_data = parity[m];
567 uint32_t write_size = shard_size;
568 uint8_t *cmp_buf = NULL;
570 bool used_lzma =
false;
575 cmp_buf = (uint8_t *)malloc((
size_t)shard_size * 2);
581 parity[m], shard_size,
583 if(cmp_size > 0 && cmp_size < shard_size)
589 write_data = cmp_buf;
590 write_size = (uint32_t)cmp_size;
592 else { free(cmp_buf); cmp_buf = NULL; }
596 size_t dst_size = (size_t)shard_size * 2;
599 lzma_props_buf, &props_size, 9,
606 write_data = cmp_buf;
607 write_size = (uint32_t)dst_size;
610 else { free(cmp_buf); cmp_buf = NULL; }
620 fwrite(write_data, write_size, 1, ctx->
imageStream);
634 out_group->
groupType = group_type; out_group->
K = actual_k; out_group->
M = M;
636 *out_desc = desc; *out_desc_len = desc_size;
643 uint64_t **out_offsets, uint32_t **out_sizes, uint32_t *out_count)
645 *out_offsets = NULL; *out_sizes = NULL; *out_count = 0;
650 for(uint32_t i = 0; i < n; i++)
655 if(count == 0)
return;
657 uint64_t *offsets = (uint64_t *)malloc(count *
sizeof(uint64_t));
658 uint32_t *sizes = (uint32_t *)malloc(count *
sizeof(uint32_t));
659 if(!offsets || !sizes) { free(offsets); free(sizes);
return; }
662 for(uint32_t i = 0; i < n && idx < count; i++)
665 if(ie->
blockType != block_type)
continue;
666 offsets[idx] = ie->
offset;
684 *out_offsets = offsets; *out_sizes = sizes; *out_count = idx;
694 const uint16_t
K = ctx->
ec_K;
695 const uint16_t M = ctx->
ec_M;
698 for(uint16_t slot = 0; slot <
K; slot++)
702 uint32_t data_stripe_count = 0;
707 while(base && pos +
sizeof(uint16_t) <= total_bytes)
710 memcpy(&ak, base + pos,
sizeof(uint16_t));
717 memset(&data_group, 0,
sizeof(data_group));
724 uint8_t *ddt_sec_desc = NULL;
size_t ddt_sec_desc_len = 0;
727 uint64_t *off; uint32_t *sz; uint32_t cnt;
733 uint8_t *ddt_pri_desc = NULL;
size_t ddt_pri_desc_len = 0;
736 uint64_t *off; uint32_t *sz; uint32_t cnt;
742 uint8_t *meta_desc = NULL;
size_t meta_desc_len = 0;
747 for(uint32_t i = 0; i < n; i++)
756 if(count > 0 && count <= (uint32_t)(255 - M))
758 uint64_t *off = (uint64_t *)malloc(count *
sizeof(uint64_t));
759 uint32_t *sz = (uint32_t *)malloc(count *
sizeof(uint32_t));
763 for(uint32_t i = 0; i < n && idx < count; i++)
783 uint8_t *idx_desc = NULL;
size_t idx_desc_len = 0;
798 uint8_t group_count = 1;
799 if(ddt_sec_desc) group_count++;
800 if(ddt_pri_desc) group_count++;
801 if(meta_desc) group_count++;
802 if(idx_desc) group_count++;
810 uint8_t *payload = (uint8_t *)malloc(payload_len);
811 if(!payload) { free(ddt_sec_desc); free(ddt_pri_desc); free(meta_desc); free(idx_desc);
return; }
813 uint8_t *wp = payload;
816 if(data_stripe_data_len > 0) { uint8_t *b = (uint8_t *)utarray_front(ctx->
ec_data_stripes);
if(b) { memcpy(wp, b, data_stripe_data_len); wp += data_stripe_data_len; } }
818#define WRITE_GROUP(desc, desc_len, grp) \
819 if(desc) { memcpy(wp, &(grp), sizeof(StripeGroupDescriptor)); wp += sizeof(StripeGroupDescriptor); \
820 memcpy(wp, (desc), (desc_len)); wp += (desc_len); }
822 WRITE_GROUP(ddt_sec_desc, ddt_sec_desc_len, ddt_sec_group)
823 WRITE_GROUP(ddt_pri_desc, ddt_pri_desc_len, ddt_pri_group)
828 free(ddt_sec_desc); free(ddt_pri_desc); free(meta_desc); free(idx_desc);
833 memset(&ecmb, 0,
sizeof(ecmb));
848 uint64_t ecmb2_offset = (ecmb_offset + ecmb_total + alignment_mask) & ~alignment_mask;
856 memset(&footer, 0,
sizeof(footer));
865 TRACE(
"Wrote ECMB at offset %" PRIu64
" (%u groups, %" PRIu64
" bytes), footer at EOF",
866 ecmb_offset, group_count, ecmb_total);
888 for(uint32_t i = 0; i < (uint32_t)ctx->
ec_K * ctx->
ec_M; i++)
913 free(stripes[i].data_entries);
914 free(stripes[i].parity_offsets);
926 HASH_ITER(hh, root, entry, tmp)
928 HASH_DEL(root, entry);
943 TRACE(
"Entering ec_load_ecmb(%p)", (
void *)ctx);
950 TRACE(
"File too small for recovery footer");
959 TRACE(
"Cannot read recovery footer");
975 TRACE(
"Cannot read ECMB header");
981 TRACE(
"ECMB identifier mismatch");
986 if(ecmb.
length == 0 || ecmb.
length > 256 * 1024 * 1024)
return;
988 uint8_t *payload = (uint8_t *)malloc((
size_t)ecmb.
length);
1002 uint8_t *cmp = (uint8_t *)malloc((
size_t)ecmb.
cmpLength);
1003 if(!cmp) { free(payload);
return; }
1004 if(fread(cmp, (
size_t)ecmb.
cmpLength, 1, ctx->
imageStream) != 1) { free(cmp); free(payload);
return; }
1008 size_t out_size = (size_t)ecmb.
length;
1022 if(computed_crc != ecmb.
crc64)
1024 TRACE(
"ECMB payload CRC64 mismatch");
1032 uint8_t *p = payload;
1033 size_t remaining = (size_t)ecmb.
length;
1037 uint32_t data_stripe_count = 0;
1051 if(!grp_stripes)
break;
1056 if(remaining <
sizeof(uint16_t))
break;
1058 memcpy(&ak, p,
sizeof(uint16_t)); p +=
sizeof(uint16_t); remaining -=
sizeof(uint16_t);
1059 if(grp_stripes) grp_stripes[s].
actual_k = ak;
1063 if(remaining < data_bytes + parity_bytes)
break;
1068 if(grp_stripes[s].data_entries)
1069 memcpy(grp_stripes[s].data_entries, p, data_bytes);
1071 grp_stripes[s].
parity_offsets = (uint64_t *)malloc((
size_t)group.
M *
sizeof(uint64_t));
1074 p += data_bytes; remaining -= data_bytes;
1076 for(uint16_t m = 0; m < group.
M; m++)
1081 if(grp_stripes && grp_stripes[s].parity_offsets)
1088 for(uint16_t k = 0; k < ak; k++)
1095 HASH_ADD(hh, lookup_root, block_offset,
sizeof(uint64_t), le);
1103 ctx->
ec_K = group.
K;
1104 ctx->
ec_M = group.
M;
1106 data_stripes = grp_stripes;
1118 free(grp_stripes[s].data_entries);
1119 free(grp_stripes[s].parity_offsets);
1137 TRACE(
"ECMB loaded: %u groups, K=%u M=%u shard_size=%u data_stripes=%u",
1146 uint8_t *data, uint32_t *length, uint8_t sector_status)
1160 uint16_t
K = ctx->
ec_K;
1161 uint16_t M = ctx->
ec_M;
1168 uint16_t total_shards =
K + M;
1171 uint8_t **shards = (uint8_t **)calloc(total_shards,
sizeof(uint8_t *));
1172 uint8_t *present = (uint8_t *)calloc(total_shards, 1);
1175 for(uint16_t i = 0; i < total_shards; i++)
1177 shards[i] = (uint8_t *)calloc(1, shard_size);
1180 for(uint16_t j = 0; j < i; j++) free(shards[j]);
1181 free(shards); free(present);
1188 for(uint16_t k = 0; k < stripe->
actual_k; k++)
1192 if(read_size > shard_size) read_size = shard_size;
1195 if(fread(shards[k], read_size, 1, ctx->
imageStream) != 1)
1203 present[k] = (crc == de->
shardCrc64) ? 1 : 0;
1207 for(uint16_t k = stripe->
actual_k; k <
K; k++)
1211 for(uint16_t m = 0; m < M; m++)
1213 uint16_t shard_idx =
K + m;
1222 present[shard_idx] = 0;
1229 uint32_t to_read = parity_header.
length;
1230 if(to_read > shard_size) to_read = shard_size;
1231 if(fread(shards[shard_idx], to_read, 1, ctx->
imageStream) != 1)
1233 present[shard_idx] = 0;
1243 present[shard_idx] = 0;
1246 uint8_t *cmp = (uint8_t *)malloc(cmp_data_len);
1247 if(!cmp) { present[shard_idx] = 0;
continue; }
1248 if(fread(cmp, cmp_data_len, 1, ctx->
imageStream) != 1) { free(cmp); present[shard_idx] = 0;
continue; }
1250 size_t out_size = shard_size;
1251 size_t lzma_src = (size_t)cmp_data_len;
1257 uint8_t *cmp = (uint8_t *)malloc(parity_header.
cmpLength);
1258 if(!cmp) { present[shard_idx] = 0;
continue; }
1259 if(fread(cmp, parity_header.
cmpLength, 1, ctx->
imageStream) != 1) { free(cmp); present[shard_idx] = 0;
continue; }
1266 present[shard_idx] = 0;
1269 present[shard_idx] = 1;
1276 for(uint16_t i = 0; i < total_shards; i++) free(shards[i]);
1277 free(shards); free(present);
1283 int rc =
rs_decode(rs, shards, present, shard_size);
1287 for(uint16_t i = 0; i < total_shards; i++) free(shards[i]);
1288 free(shards); free(present);
1295 uint8_t *recovered_shard = shards[our_pos];
1299 memcpy(&recovered_header, recovered_shard,
sizeof(
BlockHeader));
1303 uint8_t *recovered_payload = recovered_shard + hdr_size;
1304 uint32_t payload_len = recovered_header.
cmpLength;
1306 uint8_t *block = NULL;
1310 block = (uint8_t *)malloc(recovered_header.
length);
1311 if(block) memcpy(block, recovered_payload, recovered_header.
length);
1315 uint8_t *lzma_props = recovered_payload;
1319 block = (uint8_t *)malloc(recovered_header.
length);
1322 size_t out_size = recovered_header.
length;
1323 size_t lzma_src2 = (size_t)lzma_data_len;
1329 block = (uint8_t *)malloc(recovered_header.
length);
1335 block = (uint8_t *)malloc(recovered_header.
length);
1346 if(block_crc == recovered_header.
crc64)
1349 uint32_t sector_size = recovered_header.
sectorSize;
1350 if(sector_size > 0 && offset * sector_size + sector_size <= recovered_header.
length)
1352 memcpy(data, block + offset * sector_size, sector_size);
1353 *length = sector_size;
1364 memcpy(cached_hdr, &recovered_header,
sizeof(
BlockHeader));
1374 for(uint16_t i = 0; i < total_shards; i++) free(shards[i]);
Core public constants and compile‑time limits for the Aaru container format implementation.
#define AARU_RECOVERY_FOOTER_MAGIC
Magic number at the end of the recovery footer: "AVRECMFR" in ASCII little-endian.
#define LZMA_PROPERTIES_LENGTH
Size in bytes of the fixed LZMA properties header (lc/lp/pb + dictionary size).
#define AARU_MAGIC
Magic identifier for AaruFormat container (ASCII "AARUFRMT").
Central runtime context structures for libaaruformat (image state, caches, checksum buffers).
On-disk layout structures for data-bearing and geometry blocks.
On-disk headers for Deduplication Data Tables (DDT) versions 1 and 2.
int32_t aaruf_lzma_encode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer, size_t src_size, uint8_t *out_props, size_t *out_props_size, int32_t level, uint32_t dict_size, int32_t lc, int32_t lp, int32_t pb, int32_t fb, int32_t num_threads)
Encodes a buffer using LZMA compression.
uint64_t aaruf_crc64_data(const uint8_t *data, uint32_t len)
int32_t aaruf_lzma_decode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer, size_t *src_size, const uint8_t *props, size_t props_size)
Decodes an LZMA-compressed buffer.
size_t aaruf_zstd_encode_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer, size_t src_size, int level, int num_threads)
Encodes a buffer using Zstandard compression.
size_t aaruf_zstd_decode_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer, size_t src_size)
Decodes a Zstandard-compressed buffer.
size_t aaruf_flac_decode_redbook_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer, size_t src_size)
Decodes a FLAC-compressed Red Book audio buffer.
@ kECGroupMetadata
Metadata/media tag blocks.
@ kECGroupIndex
Index block (K=1, M replicas).
@ kECGroupDdtPrimary
Primary DDT (K=1, M replicas).
@ kECGroupData
User data blocks (DBLK).
@ kECGroupDdtSecondary
Secondary DDT subtables.
@ IndexBlock3
Block containing the index v3.
@ DataBlock
Block containing data.
@ IndexBlock2
Block containing the index v2.
@ DeDuplicationTableSecondary
Block containing a secondary deduplication table (v2).
@ IndexBlock
Block containing the index (v1).
@ DeDuplicationTable2
Block containing a deduplication table v2.
@ DeDuplicationTable
Block containing a deduplication table (v1).
@ ErasureCodingMapBlock
Block containing erasure coding stripe map and recovery metadata.
@ AARU_FEATURE_ROCOMPAT_ERASURE
Image contains erasure coding parity blocks and recovery metadata.
@ kErasureCodingRsVandermonde
Reed-Solomon with Vandermonde generator matrix over GF(2^8).
@ kErasureCodingXor
Simple XOR parity (M must be 1).
@ kDataTypeErasureParityDdt
Erasure coding parity shard for DDT secondary blocks.
@ kDataTypeErasureParityDdtPrimary
Erasure coding parity replica for DDT primary block.
@ kDataTypeErasureParityIndex
Erasure coding parity replica for index block.
@ kDataTypeErasureParityMeta
Erasure coding parity shard for metadata blocks.
@ kDataTypeUserData
User (main) data.
@ kDataTypeErasureParity
Erasure coding parity shard for data blocks.
@ AARUF_STATUS_INVALID_CONTEXT
Provided context/handle is invalid.
@ kCompressionLzma
LZMA compression.
@ kCompressionNone
Not compressed.
@ kCompressionZstd
Zstandard compression.
@ kCompressionFlac
FLAC compression.
static void ec_collect_blocks_by_type(aaruformat_context *ctx, uint32_t block_type, uint64_t **out_offsets, uint32_t **out_sizes, uint32_t *out_count)
Collect file offsets and on-disk sizes for index entries matching a block type.
static UT_icd ec_stripe_icd
void ec_load_ecmb(aaruformat_context *ctx)
Try to load the ECMB from the recovery footer at EOF.
void ec_finalize(aaruformat_context *ctx)
Flush all partial data stripes and write parity for all groups + ECMB + recovery footer.
#define WRITE_GROUP(desc, desc_len, grp)
int32_t aaruf_set_erasure_coding_auto(void *context, uint8_t recovery_percent)
Configure erasure coding from a desired recovery percentage.
void ec_accumulate_data_block(aaruformat_context *ctx, const BlockHeader *block_header, const uint8_t *lzma_props, const uint8_t *payload, uint32_t payload_size, uint64_t file_offset)
Accumulate parity for a data block that was just written to disk.
int32_t ec_recover_data_block(aaruformat_context *ctx, uint64_t block_offset, uint64_t offset, uint8_t *data, uint32_t *length, uint8_t sector_status)
Attempt to recover a data block that failed decompression or CRC verification.
int32_t aaruf_set_erasure_coding(void *context, uint8_t algorithm, uint16_t K, uint16_t M)
Configure erasure coding for a newly created image.
void ec_flush_data_stripe(aaruformat_context *ctx, uint32_t slot)
Write M parity blocks for a completed data stripe slot and record the stripe descriptor.
void ec_free(aaruformat_context *ctx)
Free all erasure coding state from the context.
static void ec_write_batch_parity(aaruformat_context *ctx, const uint64_t *offsets, const uint32_t *sizes, uint32_t block_count, uint8_t group_type, uint16_t parity_data_type, uint8_t **out_desc, size_t *out_desc_len, StripeGroupDescriptor *out_group)
Compute and write batch parity for a set of blocks already on disk.
On-disk structures for erasure coding recovery data.
Public error and status code definitions for libaaruformat.
#define AARUF_STATUS_OK
Sector present and read without uncorrectable errors.
#define AARUF_READ_ONLY
Operation requires write mode but context is read-only.
#define AARUF_ERROR_NOT_ENOUGH_MEMORY
Memory allocation failure (critical).
#define AARUF_ERROR_INCORRECT_DATA_SIZE
Data size does not match expected size.
#define AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK
Decompression routine failed or size mismatch.
On‑disk index block header and entry structures (versions 1, 2 and 3).
static int aaruf_fseek(FILE *stream, aaru_off_t offset, int origin)
static aaru_off_t aaruf_ftell(FILE *stream)
#define LZMA_THREADS(ctx)
Clamp num_threads to LZMA's valid range [1, 2].
void add_to_cache_uint64(struct CacheHeader *cache, uint64_t key, void *value)
Adds a value to the cache with a uint64_t key, evicting LRU if full.
void rs_free(rs_context *ctx)
Free a Reed-Solomon codec context.
rs_context * rs_create(uint16_t K, uint16_t M)
Create a Reed-Solomon codec for RS(K, M) over GF(2^8).
void rs_encode_incremental(uint8_t coeff, const uint8_t *data, uint8_t *parity, size_t shard_size)
Incrementally accumulate one data shard's contribution to one parity shard.
uint8_t rs_get_coefficient(const rs_context *ctx, uint16_t m, uint16_t k)
Get the generator matrix coefficient for parity shard m, data shard k.
int rs_decode(const rs_context *ctx, uint8_t **shards, const uint8_t *present, size_t shard_size)
Decode (reconstruct) erased shards.
static const uint32_t K[64]
Hash table entry mapping block file offset -> stripe index + position.
uint64_t block_offset
Key: file offset of the data block.
uint16_t position
Position within the stripe (0..actual_k-1).
uint32_t stripe_index
Index into ec_read_stripes array.
In-memory representation of one data stripe (parsed from ECMB).
StripeDataBlockEntry * data_entries
Array of actual_k entries.
uint16_t actual_k
Number of data blocks in this stripe.
uint64_t * parity_offsets
Array of M parity block file offsets.
Single index entry describing a block's type, (optional) data classification, and file offset.
uint32_t blockType
Block identifier of the referenced block (value from BlockType).
uint64_t offset
Absolute byte offset in the image where the referenced block header begins.
uint16_t dataType
Data classification (value from DataType) or unused for untyped blocks.
Per-data-block metadata within a stripe descriptor.
uint32_t onDiskSize
Actual on-disk bytes (sizeof(header) + cmpLength).
uint64_t offset
Absolute file offset of the block.
uint64_t shardCrc64
CRC64-ECMA of on-disk bytes zero-padded to shardSize.
Describes one protection group within the ECMB payload.
uint32_t shardSize
Fixed shard size in bytes (max possible on-disk block size for this group).
uint16_t K
Number of data blocks per stripe.
uint8_t groupType
Protection group type (ErasureCodingGroupType).
uint16_t interleaveDepth
Interleave depth D (K for full interleave, 1 for consecutive).
uint32_t stripeCount
Number of stripes in this group.
uint16_t M
Number of parity blocks per stripe.
Per-parity-block metadata within a stripe descriptor.
uint64_t offset
Absolute file offset of the parity DBLK.
Master context representing an open or in‑creation Aaru image.
uint64_t * ec_data_shard_crcs
Array of K * K CRC64 values for blocks in active stripes.
DdtHeader2 user_data_ddt_header
Active user data DDT v2 header (primary table meta).
uint32_t * ec_data_block_sizes
Array of K * K actual on-disk sizes for blocks in active stripes.
bool compression_enabled
True if block compression enabled (writing path).
void * ec_rs_ctx
rs_context* (opaque RS codec), NULL if EC disabled.
uint8_t ec_algorithm
ErasureCodingAlgorithm (0=XOR, 1=RS-Vandermonde).
bool ec_recovery_in_progress
Recursion guard for recovery (prevents infinite loops).
struct CacheHeader block_header_cache
LRU/Cache header for block headers.
uint32_t ec_data_shard_size
Max on-disk block size for data blocks (fixed at creation).
uint32_t ec_read_stripe_count
Number of data stripes parsed from ECMB.
struct CacheHeader block_cache
LRU/Cache header for block payloads.
bool dirty_index_block
True if index block should be written during close.
AaruHeaderV2 header
Parsed container header (v2).
UT_array * ec_data_stripes
Completed data stripe descriptors (serialized to ECMB).
bool is_writing
True if context opened/created for writing.
BlockHeader current_block_header
Header for block currently being assembled (write path).
uint64_t magic
File magic (AARU_MAGIC) post-open.
uint64_t next_block_position
Absolute file offset where next block will be written.
uint64_t * ec_data_block_offsets
Array of K * K file offsets for blocks in active stripes.
uint32_t ec_total_data_blocks
Total data blocks written (counter for round-robin assignment).
uint16_t ec_M
Parity blocks per stripe.
bool has_zstd_blocks
True if any block was actually written with Zstandard compression.
int zstd_level
Zstandard compression level (writing path, default 19).
uint16_t * ec_data_stripe_counts
Array of K: blocks accumulated per stripe slot.
void * ec_read_stripes
Parsed EcReadStripe array for data group, NULL if no ECMB.
void * ec_block_lookup
uthash: block file offset → stripe index + position.
FILE * imageStream
Underlying FILE* stream (binary mode).
UT_array * index_entries
Flattened index entries (UT_array of IndexEntry).
int num_threads
Compression worker threads (1 = single-threaded, default).
bool ec_enabled
True if erasure coding is active.
uint8_t ** ec_data_parity
Array of K * M parity buffers (interleaved stripe slots).
bool use_zstd
Use Zstandard instead of LZMA for data blocks.
uint32_t lzma_dict_size
LZMA dictionary size (writing path).
uint16_t ec_K
Data blocks per stripe.
bool ec_recovery_available
True if ECMB loaded and recovery is possible.