84 TRACE(
"Entering aaruf_set_erasure_coding(%p, %u, %u, %u)", context, algorithm, K, M);
106 uint64_t *offsets = (uint64_t *)calloc((
size_t)K * K,
sizeof(uint64_t));
107 uint32_t *sizes = (uint32_t *)calloc((
size_t)K * K,
sizeof(uint32_t));
108 uint64_t *crcs = (uint64_t *)calloc((
size_t)K * K,
sizeof(uint64_t));
109 uint16_t *counts = (uint16_t *)calloc(K,
sizeof(uint16_t));
111 if(!offsets || !sizes || !crcs || !counts)
113 free(offsets); free(sizes); free(crcs); free(counts);
119 UT_array *stripes = NULL;
143 TRACE(
"Erasure coding configured: algorithm=%u K=%u M=%u (parity buffers deferred)", algorithm, K, M);
144 TRACE(
"Exiting aaruf_set_erasure_coding() = 0");
176 TRACE(
"Entering aaruf_set_erasure_coding_auto(%p, %u)", context, recovery_percent);
178 if(recovery_percent == 0 || recovery_percent > 100)
184 uint16_t M = (uint16_t)((20 * (uint32_t)recovery_percent + 50) / 100);
188 uint16_t K = (uint16_t)(M * 100 / recovery_percent);
190 if(K + M > 255) K = 255 - M;
192 TRACE(
"Auto EC: recovery_percent=%u -> K=%u M=%u", recovery_percent, K, M);
210 const uint8_t *payload, uint32_t payload_size, uint64_t file_offset)
214 const uint16_t K = ctx->
ec_K;
215 const uint16_t M = ctx->
ec_M;
228 uint32_t actual_size = (uint32_t)
sizeof(
BlockHeader);
231 actual_size += payload_size;
240 ctx->
ec_data_parity = (uint8_t **)calloc((
size_t)K * M,
sizeof(uint8_t *));
242 for(uint32_t i = 0; i < (uint32_t)K * M; i++)
254 uint32_t new_size = actual_size + actual_size / 4;
255 TRACE(
"EC parity buffers growing: %u → %u bytes", old_size, new_size);
256 for(uint32_t i = 0; i < (uint32_t)K * M; i++)
258 uint8_t *grown = (uint8_t *)realloc(ctx->
ec_data_parity[i], new_size);
260 memset(grown + old_size, 0, new_size - old_size);
269 uint8_t *shard_buf = (uint8_t *)calloc(1, shard);
270 if(!shard_buf)
return;
273 memcpy(shard_buf, block_header,
sizeof(
BlockHeader));
284 memcpy(shard_buf + offset, payload, payload_size);
290 size_t tracking_idx = (size_t)slot * K + pos;
298 for(uint16_t m = 0; m < M; m++)
301 size_t parity_idx = (size_t)slot * M + m;
325 const uint16_t K = ctx->
ec_K;
326 const uint16_t M = ctx->
ec_M;
330 if(actual_k == 0)
return;
339 uint8_t *desc = (uint8_t *)calloc(1, desc_data_size);
345 memcpy(p, &actual_k,
sizeof(uint16_t)); p +=
sizeof(uint16_t);
348 for(uint16_t k = 0; k < actual_k; k++)
350 size_t idx = (size_t)slot * K + k;
363 uint32_t max_block_size = 0;
364 for(uint16_t k = 0; k < actual_k; k++)
366 size_t idx = (size_t)slot * K + k;
370 if(max_block_size == 0) max_block_size = shard;
374 for(uint16_t m = 0; m < M; m++)
376 size_t parity_idx = (size_t)slot * M + m;
385 parity_header.
length = max_block_size;
386 parity_header.
cmpLength = max_block_size;
392 parity_offset = (parity_offset + alignment_mask) & ~alignment_mask;
396 fwrite(parity_data, max_block_size, 1, ctx->
imageStream);
400 pentry.
offset = parity_offset;
413 memset(parity_data, 0, shard);
417 for(
size_t i = 0; i < desc_data_size; i++)
423 for(uint16_t k = 0; k < K; k++)
425 size_t idx = (size_t)slot * K + k;
440 const uint64_t *offsets,
const uint32_t *sizes,
441 uint32_t block_count, uint8_t group_type,
442 uint16_t parity_data_type,
443 uint8_t **out_desc,
size_t *out_desc_len,
448 if(block_count == 0)
return;
450 const uint16_t M = ctx->
ec_M;
451 uint16_t actual_k = (uint16_t)(block_count > (uint32_t)(255 - M) ? 255 - M : block_count);
453 uint32_t shard_size = 0;
454 for(uint32_t i = 0; i < actual_k; i++)
455 if(sizes[i] > shard_size) shard_size = sizes[i];
460 uint8_t **parity = (uint8_t **)calloc(M,
sizeof(uint8_t *));
461 if(!parity) {
rs_free(rs);
return; }
462 for(uint16_t m = 0; m < M; m++)
464 parity[m] = (uint8_t *)calloc(1, shard_size);
465 if(!parity[m]) {
for(uint16_t j = 0; j < m; j++) free(parity[j]); free(parity);
rs_free(rs);
return; }
470 uint8_t *desc = (uint8_t *)calloc(1, desc_size);
471 if(!desc) {
for(uint16_t m = 0; m < M; m++) free(parity[m]); free(parity);
rs_free(rs);
return; }
474 memcpy(dp, &actual_k,
sizeof(uint16_t)); dp +=
sizeof(uint16_t);
476 uint8_t *shard_buf = (uint8_t *)calloc(1, shard_size);
477 if(!shard_buf) { free(desc);
for(uint16_t m = 0; m < M; m++) free(parity[m]); free(parity);
rs_free(rs);
return; }
479 for(uint16_t k = 0; k < actual_k; k++)
481 memset(shard_buf, 0, shard_size);
483 uint32_t read_size = sizes[k] > shard_size ? shard_size : sizes[k];
492 for(uint16_t m = 0; m < M; m++)
503 for(uint16_t m = 0; m < M; m++)
506 memset(&ph, 0,
sizeof(ph));
516 fwrite(parity[m], shard_size, 1, ctx->
imageStream);
529 out_group->
groupType = group_type; out_group->
K = actual_k; out_group->
M = M;
531 *out_desc = desc; *out_desc_len = desc_size;
538 uint64_t **out_offsets, uint32_t **out_sizes, uint32_t *out_count)
540 *out_offsets = NULL; *out_sizes = NULL; *out_count = 0;
545 for(uint32_t i = 0; i < n; i++)
550 if(count == 0)
return;
552 uint64_t *offsets = (uint64_t *)malloc(count *
sizeof(uint64_t));
553 uint32_t *sizes = (uint32_t *)malloc(count *
sizeof(uint32_t));
554 if(!offsets || !sizes) { free(offsets); free(sizes);
return; }
557 for(uint32_t i = 0; i < n && idx < count; i++)
560 if(ie->
blockType != block_type)
continue;
561 offsets[idx] = ie->
offset;
579 *out_offsets = offsets; *out_sizes = sizes; *out_count = idx;
589 const uint16_t K = ctx->
ec_K;
590 const uint16_t M = ctx->
ec_M;
593 for(uint16_t slot = 0; slot < K; slot++)
597 uint32_t data_stripe_count = 0;
602 while(base && pos +
sizeof(uint16_t) <= total_bytes)
605 memcpy(&ak, base + pos,
sizeof(uint16_t));
612 memset(&data_group, 0,
sizeof(data_group));
619 uint8_t *ddt_sec_desc = NULL;
size_t ddt_sec_desc_len = 0;
622 uint64_t *off; uint32_t *sz; uint32_t cnt;
628 uint8_t *ddt_pri_desc = NULL;
size_t ddt_pri_desc_len = 0;
631 uint64_t *off; uint32_t *sz; uint32_t cnt;
645 uint8_t *meta_desc = NULL;
size_t meta_desc_len = 0;
652 for(uint32_t i = 0; i < n; i++)
666 if(count > 0 && count <= (uint32_t)(255 - M))
668 uint64_t *off = (uint64_t *)malloc(count *
sizeof(uint64_t));
669 uint32_t *sz = (uint32_t *)calloc(count,
sizeof(uint32_t));
670 uint32_t *bt = (uint32_t *)malloc(count *
sizeof(uint32_t));
675 for(uint32_t i = 0; i < n && idx < count; i++)
692 for(uint32_t i = 0; i < idx; i++)
709 uint64_t next_offset = UINT64_MAX;
710 for(uint32_t j = 0; j < n; j++)
716 if(next_offset != UINT64_MAX)
717 sz[i] = (uint32_t)(next_offset - off[i]);
730 &meta_desc, &meta_desc_len, &meta_group);
732 free(off); free(sz); free(bt);
737 uint8_t *idx_desc = NULL;
size_t idx_desc_len = 0;
752 uint8_t group_count = 1;
753 if(ddt_sec_desc) group_count++;
754 if(ddt_pri_desc) group_count++;
755 if(meta_desc) group_count++;
756 if(idx_desc) group_count++;
764 uint8_t *payload = (uint8_t *)malloc(payload_len);
765 if(!payload) { free(ddt_sec_desc); free(ddt_pri_desc); free(meta_desc); free(idx_desc);
return; }
767 uint8_t *wp = payload;
770 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; } }
772#define WRITE_GROUP(desc, desc_len, grp) \
773 if(desc) { memcpy(wp, &(grp), sizeof(StripeGroupDescriptor)); wp += sizeof(StripeGroupDescriptor); \
774 memcpy(wp, (desc), (desc_len)); wp += (desc_len); }
776 WRITE_GROUP(ddt_sec_desc, ddt_sec_desc_len, ddt_sec_group)
777 WRITE_GROUP(ddt_pri_desc, ddt_pri_desc_len, ddt_pri_group)
782 free(ddt_sec_desc); free(ddt_pri_desc); free(meta_desc); free(idx_desc);
787 memset(&ecmb, 0,
sizeof(ecmb));
802 uint64_t ecmb2_offset = (ecmb_offset + ecmb_total + alignment_mask) & ~alignment_mask;
810 memset(&footer, 0,
sizeof(footer));
819 TRACE(
"Wrote ECMB at offset %" PRIu64
" (%u groups, %" PRIu64
" bytes), footer at EOF",
820 ecmb_offset, group_count, ecmb_total);
828 uint8_t **recovered_data, uint32_t *recovered_size,
829 void *stripes_ptr, uint32_t stripe_count,
void *lookup_ptr,
830 uint16_t group_K, uint16_t group_M, uint32_t group_shard_size)
832 *recovered_data = NULL;
845 uint16_t total_shards = group_K + group_M;
847 uint8_t **shards = (uint8_t **)calloc(total_shards,
sizeof(uint8_t *));
848 uint8_t *present = (uint8_t *)calloc(total_shards, 1);
851 for(uint16_t i = 0; i < total_shards; i++)
853 shards[i] = (uint8_t *)calloc(1, group_shard_size);
858 for(uint16_t k = 0; k < stripe->
actual_k; k++)
863 if(fread(shards[k], read_size, 1, ctx->
imageStream) != 1) { present[k] = 0;
continue; }
868 for(uint16_t k = stripe->
actual_k; k < group_K; k++)
872 for(uint16_t m = 0; m < group_M; m++)
874 uint16_t si = group_K + m;
878 uint32_t to_read = ph.
length > group_shard_size ? group_shard_size : ph.
length;
879 if(fread(shards[si], to_read, 1, ctx->
imageStream) != 1) { present[si] = 0;
continue; }
886 int rc =
rs_decode(rs, shards, present, group_shard_size);
894 *recovered_data = (uint8_t *)malloc(sz);
897 memcpy(*recovered_data, shards[pos], sz);
898 *recovered_size = sz;
903 for(uint16_t i = 0; i < total_shards; i++) free(shards[i]);
904 free(shards); free(present);
910 uint8_t **recovered_data, uint32_t *recovered_size)
919 uint8_t **recovered_data, uint32_t *recovered_size)
948 for(uint32_t i = 0; i < (uint32_t)ctx->
ec_K * ctx->
ec_M; i++)
974 free(stripes[i].data_entries);
975 free(stripes[i].parity_offsets);
987 HASH_ITER(hh, root, entry, tmp)
989 HASH_DEL(root, entry);
1001 free(stripes[i].data_entries);
1002 free(stripes[i].parity_offsets);
1013 HASH_ITER(hh, root, entry, tmp) { HASH_DEL(root, entry); free(entry); }
1023 free(stripes[i].data_entries);
1024 free(stripes[i].parity_offsets);
1035 HASH_ITER(hh, root, entry, tmp) { HASH_DEL(root, entry); free(entry); }
1048 TRACE(
"Entering ec_load_ecmb(%p)", (
void *)ctx);
1055 TRACE(
"File too small for recovery footer");
1064 TRACE(
"Cannot read recovery footer");
1070 TRACE(
"Recovery footer magic mismatch: 0x%016" PRIx64, footer.
footerMagic);
1080 TRACE(
"Cannot read ECMB header");
1086 TRACE(
"ECMB identifier mismatch");
1091 if(ecmb.
length == 0 || ecmb.
length > 256 * 1024 * 1024)
return;
1093 uint8_t *payload = (uint8_t *)malloc((
size_t)ecmb.
length);
1094 if(!payload)
return;
1107 uint8_t *cmp = (uint8_t *)malloc((
size_t)ecmb.
cmpLength);
1108 if(!cmp) { free(payload);
return; }
1109 if(fread(cmp, (
size_t)ecmb.
cmpLength, 1, ctx->
imageStream) != 1) { free(cmp); free(payload);
return; }
1113 size_t out_size = (size_t)ecmb.
length;
1127 if(computed_crc != ecmb.
crc64)
1129 TRACE(
"ECMB payload CRC64 mismatch");
1137 uint8_t *p = payload;
1138 size_t remaining = (size_t)ecmb.
length;
1142 uint32_t data_stripe_count = 0;
1156 if(!grp_stripes)
break;
1161 if(remaining <
sizeof(uint16_t))
break;
1163 memcpy(&ak, p,
sizeof(uint16_t)); p +=
sizeof(uint16_t); remaining -=
sizeof(uint16_t);
1164 if(grp_stripes) grp_stripes[s].
actual_k = ak;
1168 if(remaining < data_bytes + parity_bytes)
break;
1173 if(grp_stripes[s].data_entries)
1174 memcpy(grp_stripes[s].data_entries, p, data_bytes);
1176 grp_stripes[s].
parity_offsets = (uint64_t *)malloc((
size_t)group.
M *
sizeof(uint64_t));
1179 p += data_bytes; remaining -= data_bytes;
1181 for(uint16_t m = 0; m < group.
M; m++)
1186 if(grp_stripes && grp_stripes[s].parity_offsets)
1193 for(uint16_t k = 0; k < ak; k++)
1200 HASH_ADD(hh, lookup_root, block_offset,
sizeof(uint64_t), le);
1208 ctx->
ec_K = group.
K;
1209 ctx->
ec_M = group.
M;
1211 data_stripes = grp_stripes;
1222 if(!grp_stripes[s].data_entries)
continue;
1223 for(uint16_t k = 0; k < grp_stripes[s].
actual_k; k++)
1230 HASH_ADD(hh, ddt_lookup_root, block_offset,
sizeof(uint64_t), le);
1249 if(!grp_stripes[s].data_entries)
continue;
1250 for(uint16_t k = 0; k < grp_stripes[s].
actual_k; k++)
1257 HASH_ADD(hh, meta_lookup_root, block_offset,
sizeof(uint64_t), le);
1275 free(grp_stripes[s].data_entries);
1276 free(grp_stripes[s].parity_offsets);
1295 TRACE(
"ECMB loaded: %u groups, K=%u M=%u shard_size=%u data_stripes=%u",
1304 uint8_t *data, uint32_t *length, uint8_t sector_status)
1318 uint16_t K = ctx->
ec_K;
1319 uint16_t M = ctx->
ec_M;
1326 uint16_t total_shards = K + M;
1329 uint8_t **shards = (uint8_t **)calloc(total_shards,
sizeof(uint8_t *));
1330 uint8_t *present = (uint8_t *)calloc(total_shards, 1);
1333 for(uint16_t i = 0; i < total_shards; i++)
1335 shards[i] = (uint8_t *)calloc(1, shard_size);
1338 for(uint16_t j = 0; j < i; j++) free(shards[j]);
1339 free(shards); free(present);
1346 for(uint16_t k = 0; k < stripe->
actual_k; k++)
1350 if(read_size > shard_size) read_size = shard_size;
1353 if(fread(shards[k], read_size, 1, ctx->
imageStream) != 1)
1361 present[k] = (crc == de->
shardCrc64) ? 1 : 0;
1365 for(uint16_t k = stripe->
actual_k; k < K; k++)
1369 for(uint16_t m = 0; m < M; m++)
1371 uint16_t shard_idx = K + m;
1380 present[shard_idx] = 0;
1387 uint32_t to_read = parity_header.
length;
1388 if(to_read > shard_size) to_read = shard_size;
1389 if(fread(shards[shard_idx], to_read, 1, ctx->
imageStream) != 1)
1391 present[shard_idx] = 0;
1401 present[shard_idx] = 0;
1404 uint8_t *cmp = (uint8_t *)malloc(cmp_data_len);
1405 if(!cmp) { present[shard_idx] = 0;
continue; }
1406 if(fread(cmp, cmp_data_len, 1, ctx->
imageStream) != 1) { free(cmp); present[shard_idx] = 0;
continue; }
1408 size_t out_size = shard_size;
1409 size_t lzma_src = (size_t)cmp_data_len;
1415 uint8_t *cmp = (uint8_t *)malloc(parity_header.
cmpLength);
1416 if(!cmp) { present[shard_idx] = 0;
continue; }
1417 if(fread(cmp, parity_header.
cmpLength, 1, ctx->
imageStream) != 1) { free(cmp); present[shard_idx] = 0;
continue; }
1424 present[shard_idx] = 0;
1427 present[shard_idx] = 1;
1434 for(uint16_t i = 0; i < total_shards; i++) free(shards[i]);
1435 free(shards); free(present);
1441 int rc =
rs_decode(rs, shards, present, shard_size);
1445 for(uint16_t i = 0; i < total_shards; i++) free(shards[i]);
1446 free(shards); free(present);
1453 uint8_t *recovered_shard = shards[our_pos];
1457 memcpy(&recovered_header, recovered_shard,
sizeof(
BlockHeader));
1461 uint8_t *recovered_payload = recovered_shard + hdr_size;
1462 uint32_t payload_len = recovered_header.
cmpLength;
1464 uint8_t *block = NULL;
1468 block = (uint8_t *)malloc(recovered_header.
length);
1469 if(block) memcpy(block, recovered_payload, recovered_header.
length);
1473 uint8_t *lzma_props = recovered_payload;
1477 block = (uint8_t *)malloc(recovered_header.
length);
1480 size_t out_size = recovered_header.
length;
1481 size_t lzma_src2 = (size_t)lzma_data_len;
1487 block = (uint8_t *)malloc(recovered_header.
length);
1493 block = (uint8_t *)malloc(recovered_header.
length);
1504 if(block_crc == recovered_header.
crc64)
1507 uint32_t sector_size = recovered_header.
sectorSize;
1508 if(sector_size > 0 && offset * sector_size + sector_size <= recovered_header.
length)
1510 memcpy(data, block + offset * sector_size, sector_size);
1511 *length = sector_size;
1522 memcpy(cached_hdr, &recovered_header,
sizeof(
BlockHeader));
1532 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.
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.
int32_t aaruf_set_erasure_coding_auto(void *context, uint8_t recovery_percent)
Configure erasure coding from a desired recovery percentage.
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.
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
#define WRITE_GROUP(desc, desc_len, grp)
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.
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.
int32_t ec_recover_ddt_block(aaruformat_context *ctx, uint64_t block_offset, uint8_t **recovered_data, uint32_t *recovered_size)
Attempt to recover a DDT secondary block at a given file offset.
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 ec_recover_meta_block(aaruformat_context *ctx, uint64_t block_offset, uint8_t **recovered_data, uint32_t *recovered_size)
Attempt to recover a metadata/media-tag block at a given file offset.
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.
int32_t ec_recover_raw_block(aaruformat_context *ctx, uint64_t block_offset, uint8_t **recovered_data, uint32_t *recovered_size, void *stripes, uint32_t stripe_count, void *lookup, uint16_t group_K, uint16_t group_M, uint32_t group_shard_size)
Attempt to recover a raw block at a given file offset using a specified stripe group.
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_CANNOT_READ_BLOCK
Generic block read failure (seek/read error).
#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)
void add_to_cache_uint64(struct CacheHeader *cache, uint64_t key, void *value, size_t size)
Adds a value to the cache with a uint64_t key, evicting LRU entries if over budget.
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.
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.
void * ec_rs_ctx
rs_context* (opaque RS codec), NULL if EC disabled.
uint32_t ec_meta_stripe_count
Number of metadata stripes.
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.
uint32_t ec_ddt_stripe_count
Number of DDT-secondary stripes.
struct CacheHeader block_cache
LRU/Cache header for block payloads.
uint32_t ec_meta_shard_size
Shard size for metadata group.
void * ec_ddt_block_lookup
uthash: block file offset → stripe index + position (DDT group).
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.
uint16_t ec_ddt_M
M for DDT-secondary group.
uint64_t magic
File magic (AARU_MAGIC) post-open.
uint16_t ec_meta_M
M for metadata group.
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.
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 (data group).
void * ec_ddt_stripes
Parsed EcReadStripe array for DDT-secondary group.
FILE * imageStream
Underlying FILE* stream (binary mode).
void * ec_meta_block_lookup
uthash: block file offset → stripe index + position (metadata group).
UT_array * index_entries
Flattened index entries (UT_array of IndexEntry).
uint32_t ec_ddt_shard_size
Shard size for DDT-secondary group.
bool ec_enabled
True if erasure coding is active.
uint8_t ** ec_data_parity
Array of K * M parity buffers (interleaved stripe slots).
uint16_t ec_ddt_K
K for DDT-secondary group.
void * ec_meta_stripes
Parsed EcReadStripe array for metadata group.
uint16_t ec_meta_K
K for metadata group.
uint16_t ec_K
Data blocks per stripe.
bool ec_recovery_available
True if ECMB loaded and recovery is possible.