+ Partclone: read and write format 0002 images, verified by partclone - #414
Merged
Merged
Conversation
Hawkynt
force-pushed
the
feat/partclone-write
branch
from
September 30, 2026 12:25
efd9023 to
1a07e08
Compare
Hawkynt
force-pushed
the
feat/partclone-write
branch
4 times, most recently
from
September 30, 2026 20:05
977a8fb to
118f61f
Compare
Partclone containers could be inspected and reconstructed but not created, so the archive descriptor exposed no write capability. Add a v2 writer that consumes the extracted raw image, metadata and allocation map, preserving allocated zero blocks and emitting supported CRC32 or XXH64 strips. Retain filesystem geometry and checksum parameters in metadata and add round-trip coverage.
Changing bitmap encoding previously rejected the original map and checksum-mode overrides retained the source mode's parameters. Translate maps between packed-bit and byte-per-block forms and select compatible size/strip defaults whenever the checksum mode changes.
Partclone's BM_NONE mode represents every block as present without a bitmap. The writer previously treated that legal mode as unsupported; emit all blocks and preserve the same semantics when converting to bitmap-backed modes.
Symptom: CI did not compile (CS0173 in PartcloneFormatDescriptor.Create). Past that, none of the partclone code could read an image partclone writes, and partclone could not read what the new writer produced. The tests passed only because their synthetic builder shared the reader's mistakes. Root cause: the reader, the writer and the test builder all modelled a layout that does not exist: - image_head is 36 bytes (16-byte NUL-terminated magic, 14-byte version, "0002", endianess), not 31; file_system_info is 52 bytes with a 16-byte fs field and superBlockUsedBlocks BEFORE usedblocks; image_options is 18 bytes and is followed by a separate header CRC (110 bytes in all). - The header CRC was never computed or checked. - On-disk checksum modes are 0x20 (CRC32) / 0x30 (XXH64), not the 1/2 that partclone's -a option and IMAGE_FORMATS.md show; BM_BYTE is 0x08. - The bitmap is always followed by a 4-byte CRC (whenever a bitmap exists), not by checksum_size bytes only when data checksums are on. - partclone's CRC32 is the register without the final inversion. Fix: - PartcloneReader parses the real descriptor, verifies the header CRC, the bitmap CRC and every strip checksum (CRC32 and XXH64, reseed and no-reseed), refuses format 0001 and big-endian images with NotSupportedException, and accepts a byte map with either trailer. - PartcloneWriter writes the same layout: CRC32 or no checksum, bit map or no map, partclone's default strip (1 MiB / block size). Byte maps are refused because partclone writes a CRC after them but reads them back expecting "BiTmAgIc", so it cannot restore such an image; XXH64 output is refused because no available partclone build could verify it. - Create refuses anything but image.img (+ metadata.ini, allocation.map) with ArgumentException; List no longer throws on a damaged image and lists a metadata.ini with parse_status = partial instead. - Tests are rebuilt on reference images from partclone 0.3.27: header fields, reconstruction, byte-identical re-creation from the extracted entries, and one equivalence class per kind of damage. - New ExternalInterop fixture: partclone.chkimg accepts our images and partclone.restore reproduces the partition (CRC32 strips of 1/7/256 blocks, no reseed, no checksum, no map), and chkimg rejects a damaged one. Sourcing: rung 2 then 3. partclone is GPL-2.0, so its IMAGE_FORMATS.md and struct definitions were read as a specification only and nothing was carried over; where the document disagrees with partclone's own output (checksum mode numbers), the images partclone 0.3.27 wrote are the reference. Those images are committed as gzip vectors, and partclone 0.3.27 is the oracle for the external fixture.
… when the branch was rebased
Hawkynt
force-pushed
the
feat/partclone-write
branch
from
September 30, 2026 20:59
118f61f to
7542269
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
image.img(+ themetadata.iniandallocation.mapan extraction produced) with CRC32 or no checksum and a bit map or no map. Byte maps are refused (partclone writes a CRC after them but reads them back expecting "BiTmAgIc", so it cannot restore them); XXH64 output is refused (no available partclone build could verify it).The reader on main modelled a layout that does not exist (31/51/22-byte structures, wrong checksum mode numbers) and could not read any image partclone writes; this branch replaces it.
Verification
partclone.chkimgaccepts our images andpartclone.restorereproduces the partition (strips of 1/7/256 blocks, no reseed, no checksum, no map); chkimg rejects a damaged one. Green locally against partclone 0.3.27 in WSL.