Add an error for an image shorter than its recovery data

A recovery resumed against an image that has been truncated since the
previous pass — a full disk, an interrupted transfer, a remount — cannot
repair it: the pass only revisits the ranges the recovery data calls bad,
so everything past the cut stays a hole while the counts still describe a
whole disc. There was no way to say that. Reusing the recovery-data error
would have been wrong, because the recovery data is intact; the image is
not.

Registered in the uniqueness list, the code table and the range check, so
a future variant cannot silently reuse 6015 or map to the wrong code.
This commit is contained in:
Matthew Jackson
2026-08-08 13:35:44 -07:00
parent 03c6d20447
commit 3ff2abbff5
+19
View File
@@ -62,6 +62,7 @@ pub const E_MAPFILE_INVALID: u16 = 6011;
pub const E_SELECTION_PID_UNKNOWN: u16 = 6014; pub const E_SELECTION_PID_UNKNOWN: u16 = 6014;
pub const E_UDF_BUFFER_TOO_SMALL: u16 = 6012; pub const E_UDF_BUFFER_TOO_SMALL: u16 = 6012;
pub const E_UDF_NOT_FILESYSTEM: u16 = 6013; pub const E_UDF_NOT_FILESYSTEM: u16 = 6013;
pub const E_IMAGE_TRUNCATED: u16 = 6015;
// AACS (7xxx) // AACS (7xxx)
pub const E_AACS_NO_KEYS: u16 = 7000; pub const E_AACS_NO_KEYS: u16 = 7000;
@@ -461,6 +462,14 @@ pub enum Error {
MapfileInvalid { MapfileInvalid {
kind: &'static str, kind: &'static str,
}, },
/// The image a mapfile describes is shorter than the mapfile's own total
/// size, so the two no longer agree about the same disc. Resuming against
/// it would treat the absent tail as already recovered. `have` and `want`
/// are byte lengths; a missing file reports `have == 0`.
ImageTruncated {
have: u64,
want: u64,
},
// AACS (7xxx) // AACS (7xxx)
AacsNoKeys, AacsNoKeys,
@@ -859,6 +868,7 @@ impl Error {
Error::NoStreams => E_NO_STREAMS, Error::NoStreams => E_NO_STREAMS,
Error::SelectionPidUnknown { .. } => E_SELECTION_PID_UNKNOWN, Error::SelectionPidUnknown { .. } => E_SELECTION_PID_UNKNOWN,
Error::MapfileInvalid { .. } => E_MAPFILE_INVALID, Error::MapfileInvalid { .. } => E_MAPFILE_INVALID,
Error::ImageTruncated { .. } => E_IMAGE_TRUNCATED,
Error::AacsNoKeys => E_AACS_NO_KEYS, Error::AacsNoKeys => E_AACS_NO_KEYS,
Error::AacsCertShort => E_AACS_CERT_SHORT, Error::AacsCertShort => E_AACS_CERT_SHORT,
Error::AacsAgidAlloc => E_AACS_AGID_ALLOC, Error::AacsAgidAlloc => E_AACS_AGID_ALLOC,
@@ -1634,6 +1644,13 @@ mod tests {
E_PLATFORM_NOT_IMPLEMENTED, E_PLATFORM_NOT_IMPLEMENTED,
), ),
(Error::MapfileInvalid { kind: "hex" }, E_MAPFILE_INVALID), (Error::MapfileInvalid { kind: "hex" }, E_MAPFILE_INVALID),
(
Error::ImageTruncated {
have: 0,
want: 1024,
},
E_IMAGE_TRUNCATED,
),
(Error::DiscUrlNotDirect, E_DISC_URL_NOT_DIRECT), (Error::DiscUrlNotDirect, E_DISC_URL_NOT_DIRECT),
(Error::ExtentNotUnitAligned, E_EXTENT_NOT_UNIT_ALIGNED), (Error::ExtentNotUnitAligned, E_EXTENT_NOT_UNIT_ALIGNED),
// Both CSS no-key verdicts: numeric-only Display, no English. // Both CSS no-key verdicts: numeric-only Display, no English.
@@ -1820,6 +1837,7 @@ mod tests {
E_NO_STREAMS, E_NO_STREAMS,
E_HALTED, E_HALTED,
E_MAPFILE_INVALID, E_MAPFILE_INVALID,
E_IMAGE_TRUNCATED,
E_UDF_BUFFER_TOO_SMALL, E_UDF_BUFFER_TOO_SMALL,
E_UDF_NOT_FILESYSTEM, E_UDF_NOT_FILESYSTEM,
E_AACS_NO_KEYS, E_AACS_NO_KEYS,
@@ -1933,6 +1951,7 @@ mod tests {
assert!((6000..7000).contains(&E_DISC_READ)); assert!((6000..7000).contains(&E_DISC_READ));
assert!((6000..7000).contains(&E_HALTED)); assert!((6000..7000).contains(&E_HALTED));
assert!((6000..7000).contains(&E_MAPFILE_INVALID)); assert!((6000..7000).contains(&E_MAPFILE_INVALID));
assert!((6000..7000).contains(&E_IMAGE_TRUNCATED));
// AACS (7xxx) // AACS (7xxx)
assert!((7000..8000).contains(&E_AACS_NO_KEYS)); assert!((7000..8000).contains(&E_AACS_NO_KEYS));
assert!((7000..8000).contains(&E_NO_DISC_KEY)); assert!((7000..8000).contains(&E_NO_DISC_KEY));