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
+6 -2
View File
@@ -865,7 +865,7 @@ pub fn analyze(reader: &mut dyn SectorSource, udf: &UdfFs) -> LabelAnalysis {
}
/// Scan `/BDMV/PLAYLIST/*.mpls`, parse each, return a row per playlist
/// with chapter count (mark_type ≤ 1) and total duration. Sorted by
/// with chapter count (entry marks only) and total duration. Sorted by
/// playlist filename. Skipped entries (read error, parse error, no
/// marks) silently dropped — this is a diagnostic field, not a
/// correctness-critical one.
@@ -890,7 +890,11 @@ fn collect_chapter_summary(reader: &mut dyn SectorSource, udf: &UdfFs) -> Vec<Ch
let Ok(playlist) = crate::mpls::parse(&data) else {
continue;
};
let chapter_count = playlist.marks.iter().filter(|m| m.mark_type <= 1).count();
let chapter_count = playlist
.marks
.iter()
.filter(|m| m.is_chapter_mark())
.count();
if chapter_count == 0 {
continue;
}