compact_pack() and merge_packs() copy pack bytes into a new pack via store.defrag, and the new pack is named by the hash of what was copied. Neither consults cache/checked-packs or verifies the source pack. A corrupt pack therefore becomes a correctly named pack, and check's prune() drops its corrupt record as "gone".
Reproduced on master (0dd454d), aes256-ocb:
borg create a s3 # s3/keep (200 kB), s3/drop (30 kB), one pack
borg create b s3k # s3k/keep only, dedups against a
borg delete -a a # s3/drop's chunk is now unused
# flip one byte in the data slot of keep's chunk
borg check # rc 1, corrupt pack
borg compact --threshold 0 # rewrites the pack, keeping keep's chunk
borg check # rc 0
borg extract b # rc 113, s3k/keep: 1 chunk missing or corrupted, replaced by all-zero data
Proposal: compact skips packs recorded corrupt and tells the user to run borg check --repair. A pack that was never checked can still be laundered; verifying the hash of every source pack before copying would close that too, at the cost of reading it once more. Which one do you prefer?
Refs #10026.
compact_pack()andmerge_packs()copy pack bytes into a new pack viastore.defrag, and the new pack is named by the hash of what was copied. Neither consultscache/checked-packsor verifies the source pack. A corrupt pack therefore becomes a correctly named pack, andcheck'sprune()drops its corrupt record as "gone".Reproduced on master (0dd454d), aes256-ocb:
Proposal: compact skips packs recorded corrupt and tells the user to run
borg check --repair. A pack that was never checked can still be laundered; verifying the hash of every source pack before copying would close that too, at the cost of reading it once more. Which one do you prefer?Refs #10026.