Reject a short READ CAPACITY reply, and count only entry marks as chapters

Two cases of the same shape: one policy implemented twice, with only one
copy hardened.

Disc::read_capacity decoded buf[0..4] from READ CAPACITY (10) without
checking that the transport actually delivered four bytes, even though its
comment claims to mirror decode_read_capacity — which has exactly that
check, and documents why. A drive answering GOOD with an empty data phase
leaves the buffer zeroed, so last_lba decodes to 0 and the probe reports a
one-sector disc instead of an error. It now calls the shared decoder rather
than re-deriving it.

collect_chapter_summary filtered chapters on mark_type <= 1, counting the
reserved type 0. PlaylistMark's own doc says filters must test == 1, and
disc/bluray.rs did; the labels path did not, inflating the public
chapter_count and letting a playlist whose only marks are reserved pass the
chapter_count == 0 skip. Both sites now share PlaylistMark::is_chapter_mark
so the copies cannot drift again.

Both fixes were confirmed red before green.
This commit is contained in:
Matthew Jackson
2026-08-01 11:00:49 -07:00
parent e0ff0cfeb4
commit fb321f51eb
5 changed files with 81 additions and 12 deletions
+2 -2
View File
@@ -158,7 +158,7 @@ impl Drive {
/// fallback) so command-builder/response-parser logic can be exercised
/// against a scripted mock transport.
#[cfg(test)]
fn from_transport_for_test(scsi: Box<dyn ScsiTransport>) -> Self {
pub(crate) fn from_transport_for_test(scsi: Box<dyn ScsiTransport>) -> Self {
Drive {
scsi,
unlocker_name: None,
@@ -1291,7 +1291,7 @@ fn build_error_recovery_select_payload(sense: &[u8]) -> Option<Vec<u8>> {
/// 32-bit" sentinel, whose `last_lba + 1` overflows `u32`, is reported as the
/// distinct [`Error::DiscCapacityOverflow`] so callers can tell an unusable
/// response apart from an over-large disc.
fn decode_read_capacity(buf: &[u8; 8], bytes_transferred: usize) -> Result<u32> {
pub(crate) fn decode_read_capacity(buf: &[u8; 8], bytes_transferred: usize) -> Result<u32> {
if bytes_transferred < 4 {
return Err(Error::DiscCapacityMalformed);
}