932 Commits

Author SHA1 Message Date
154075578b Set the cache free functions when creating an image
aaruf_create() left block_header_cache.free_func and block_cache.free_func at
the NULL the context was zeroed with, so on the write path every value the
caches evicted or dropped at close was leaked. aaruf_open() has always set
them; do the same here.
2026-09-02 00:04:05 +01:00
86e6b7ed82 Replace the existing value when caching a key that is already present
add_to_cache_uint64() called HASH_ADD without first looking the key up.
uthash keeps both entries in that case, but HASH_FIND only ever reaches the
newer one, so the older entry becomes unreachable and its value stays alive
until free_cache() tears the whole cache down. It also counted twice against
the cache budget.

ec_recover_data_block() reaches this: it caches the recovered BlockHeader for
a block offset that may already be in block_header_cache, because a header
read from the file is cached before the corruption check that sends the read
into erasure recovery.

Look the key up first, and on a hit free the old value and reuse the entry.
2026-09-02 00:03:52 +01:00
598d9224a7 Bound the block caches by bytes held instead of by entry count
The read caches sized themselves as MAX_CACHE_SIZE / (SectorSize << shift),
but ctx->shift is only ever assigned on the DDT v1 path, and the context is
zeroed at open. On every DDT v2 image the divisor therefore collapsed to the
sector size and the limit came out as 262144 entries, while each block_cache
entry holds a whole decompressed data block of SectorSize << dataShift bytes,
8 MiB with the default data_shift of 12. That is a ceiling of roughly 2 TiB
rather than the intended 512 MiB, so the count limit was never reached: a
sequential sector-by-sector pass cached the entire decompressed image and
freed none of it until aaruf_close(). Comparing two 40 GB images this way was
killed by the OOM reaper.

An entry count cannot express a memory budget when the values vary in size,
and here they vary by five orders of magnitude: block_header_cache holds
BlockHeader structs while block_cache holds megabyte payloads, yet both were
given the same limit. Track the byte size of each value instead and evict
least-recently-used entries until the cache is back under budget, and drop the
block geometry from cache initialization entirely. The block cache gets the
512 MiB MAX_CACHE_SIZE it always intended; block headers get a separate 8 MiB
budget, which covers far more blocks than the payload cache can hold.

The entry just inserted is never evicted, so callers may keep using the
pointer they handed over for the rest of the call. That also removes the
use-after-free that a zero limit used to cause: the old eviction loop started
at the hash head and could free the entry just added, after which the caller
read from freed memory.
2026-09-02 00:03:22 +01:00
c8de84871d Add repair-cd-arena tool command
Recovers CD sector prefix/suffix arenas in a v2 image whose resumed dump
sessions left the final deduplication table referencing slots past the
shrunken data block. Scans the file for every prefix/suffix generation,
rebuilds a fresh compact arena and DDT2 for the final table by sourcing
each custom slot from the generation that held it, and rewrites the index.
Supports --dry-run to report recoverable/lost slots without writing.
2026-09-01 14:56:21 +01:00
29bdba9c66 Add CD prefix/suffix resume and header-classification regression tests
Covers custom prefix/suffix bytes surviving a resumed dump session, a
resume that adds no new customs keeping the arena intact, and non-BCD
headers being stored verbatim rather than regenerated.
2026-09-01 14:56:13 +01:00
f3cf5f729c Report correct DDT status and encode NotDumped entries with the status shift
The Mode 1 user-data DDT entry was always written as Mode1Correct even
when the prefix or ECC/EDC was wrong; report Errored in that case like the
Mode 2 paths. The all-zero paths assigned SectorStatusNotDumped without
the <<60 status shift (harmless only because it is zero) and the Mode 2
all-zero path never marked its DDTs dirty, so an all-blank Mode 2 track
wrote no DDT at all; shift the status and set the dirty flags. Also widen
a truncating (uint32_t) cast on the Mode 2 prefix slot index to uint64_t.
2026-09-01 14:55:56 +01:00
03b2494fa6 Grow CD prefix/suffix arenas safely and zero unused slot bytes
The arenas were malloc'd and grown by doubling with realloc into the same
pointer: doubling could not grow a zero-length buffer, a failed realloc
leaked and lost the only pointer, and the Mode 2 Form 1/Form 2 paths left
part of each 288-byte slot uninitialized, writing heap garbage into the
image. Add a grow_arena() helper that grows before appending, keeps the
pointer on failure, and zeroes new capacity; allocate the arenas with
calloc and zero partial slots before copying.
2026-09-01 14:55:10 +01:00
e40922c5a0 Store CD headers that are non-BCD or on negative LBAs instead of regenerating
The write path decoded the MSF header with a naive nibble multiply and
compared against the positive sector address, so a header that was not
valid BCD but aliased the expected address (e.g. 0x1A vs 0x20) was
classified correct and silently rewritten as canonical BCD on read, and
lead-in (negative) sectors never matched. Validate BCD nibbles and range
via cd_header_matches_lba() using the signed LBA, and reconstruct the
prefix from the signed LBA on read.
2026-09-01 14:53:27 +01:00
21cc80f48a Bounds-check CD prefix/suffix arena reads and fix legacy over-reads
A DDT2 entry whose slot index points past the stored prefix/suffix block
(e.g. a resume-damaged or corrupt image) caused an out-of-bounds heap
read that was silently returned as sector data. Validate the pointer and
index against the arena length before copying, returning
AARUF_ERROR_CANNOT_READ_BLOCK with an Errored status instead. Also clamp
the two legacy Mode 2 fallback copies to the actual bare-sector length.
2026-09-01 14:52:45 +01:00
718c35c7a0 Restore CD sector prefix/suffix arena offsets when resuming a dump
On aaruf_open(resume_mode=true) the loaded prefix/suffix arena blocks had
their lengths recorded but the append offsets were left at zero, so a
resumed dump session re-appended custom sync/ECC bytes from offset 0,
overwriting existing slots and leaving the DDT2 pointing past the
rewritten (shrunken) block. Record the block length on load and set the
append offset to it on resume so new customs append after existing slots.
2026-09-01 14:51:17 +01:00
a9241a5fbd Bump version to 1.0.0-beta.1.1 in nuspec file 2026-09-01 13:07:46 +01:00
48dedd54d1 Merge branch 'devel' of https://github.com/aaru-dps/libaaruformat into devel 2026-07-31 08:58:18 +01:00
bbb0403e3d Fix double free: null metadata/cicm/json block pointers after error-path frees 2026-07-31 08:57:29 +01:00
105e07ac84 Merge pull request #44 from MSSonline/MSSonline-patch-1
Add missing PS5BD/UHDBD to OpticalDisc
2026-07-27 22:07:14 +01:00
Michael Stadelmann-Steinert
b42205440e Add missing PS5BD/UHDBD to mediatype OpticalDisc
## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] New filesystem, test images in [url]
- [ ] New media image, test images in [url]
- [ ] New partition scheme, test images in [url]
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [x] I have read the **CONTRIBUTING** document.
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.

Add missing media types PS5BD and UHDBD to aaruf_get_xml_mediatype for optical discs.

Maybe the "xml" function should replaced by some generic meaning (e.g. aaruf_get_metadata_mediatype), since export is in .json file.
2026-07-27 21:45:13 +02:00
a95fea12ec Bump version v1.0.0-beta.1 2026-07-14 18:39:45 +01:00
6c05b4548e Merge pull request #43 from Cacodemon345/c-standard-fixes
Fixes to make it compile with `-Werror=strict-prototype`
2026-07-12 23:57:44 +01:00
78bc7faf0c Merge pull request #42 from Cacodemon345/patch-2
blake3.cmake: Match uppercase `CMAKE_SYSTEM_PROCESSOR` identifiers on AArch64
2026-07-12 23:56:59 +01:00
Cacodemon345
11d667ec9b Fixes to make it compile with -Werror=strict-prototype
Also ensures that some IDE warnings get ignored only on Clang
2026-07-13 02:45:17 +06:00
Cacodemon345
125392006a lzma.cmake: Match uppercase CMAKE_SYSTEM_PROCESSOR identifiers on AArch64 2026-07-12 13:54:32 +06:00
Cacodemon345
34404b532e blake3.cmake: Match uppercase CMAKE_SYSTEM_PROCESSOR identifiers 2026-07-12 13:41:13 +06:00
10e5f4d4a1 Add docker files 2026-07-11 14:12:45 +01:00
964e99cafd Add docker files 2026-07-11 14:11:54 +01:00
9e1420e8ec Update to alpha 42. 2026-07-11 12:16:14 +01:00
a1dd1f307a Allow track 0 to be a valid data track. 2026-07-11 12:15:24 +01:00
5925860c33 Merge pull request #41 from Cacodemon345/patch-1
crc64_clmul: Fix builds on Clang compilers
2026-07-10 21:26:16 +01:00
Cacodemon345
093638bee9 crc64_clmul: Fix builds on Clang compilers
`_mm_cvtsi64x_si128` is not defined on Clang's headers; use the normal name instead.
2026-07-11 00:19:56 +06:00
aeb2f54a41 Merge pull request #40 from FakeShemp/fakeshemp/flux-only
Handle flux-only images more gracefully
2026-05-02 00:54:26 +01:00
Rebecca Wallander
a6345b7efc Handle flux-only images 2026-05-01 09:14:06 +02:00
8b0f8a37fe Bump version to 1.0.0-alpha.41 in nuspec file v1.0.0-alpha.41 2026-04-13 08:55:48 +01:00
04413974bb Update specification. 2026-04-12 14:53:32 +01:00
2676d8fe0c Merge branch 'devel' of github.com:aaru-dps/libaaruformat into devel 2026-04-12 14:49:24 +01:00
540538426e Merge pull request #39 from FakeShemp/fakeshemp/write-long
Actually write the BD sector tags to file
2026-04-12 14:49:13 +01:00
a5bd3279f5 Do EC recovery on secondary level DDT2 reading. 2026-04-12 14:45:52 +01:00
1f7532b0ee Add EC recovery of non-data blocks. 2026-04-12 14:37:54 +01:00
5066715bd7 Bump version to 1.0.0-alpha.40 in nuspec file v1.0.0-alpha.40 2026-04-12 14:21:01 +01:00
a4fac9c9e4 Update 010editor template. 2026-04-12 14:19:47 +01:00
81c367995f Update recovery footer size and related documentation for AaruRecoveryFooter 2026-04-12 14:17:56 +01:00
Rebecca Wallander
71f1ab5290 Actually write the BD sector tags to file 2026-04-12 15:09:38 +02:00
4573ae8f1b Update imhex pattern. 2026-04-12 14:05:29 +01:00
c7a72bce13 Update specification. 2026-04-12 13:23:39 +01:00
651ad79a23 Fix bug in calculation of metadata block size when erasure coding. 2026-04-12 11:52:22 +01:00
9b87f90833 Write only needed shard size uncompressed. 2026-04-12 10:39:01 +01:00
60435e1fa4 Use correct sector size. 2026-04-12 10:38:35 +01:00
6aa55d7e3f Updated README (again). 2026-04-12 00:01:18 +01:00
3c646c3c24 Updated README. 2026-04-11 23:57:22 +01:00
33fb233316 Update AGENTS.md 2026-04-11 23:51:39 +01:00
cb4225c564 Fix building on Windows. 2026-04-11 23:48:11 +01:00
67fffced6e Add SIMD for GF for ARM32. 2026-04-11 23:27:12 +01:00
dff3968134 Update gitignore. 2026-04-11 23:23:13 +01:00