libcdio_rs/mmc/
read_disc_info.rs1use displaydoc::Display;
21use thiserror::Error;
22
23use crate::{
24 Mmc,
25 mmc::{Cdb, MmcCommand, MmcDirection, MmcError},
26};
27
28impl Mmc {
30 pub fn is_disc_erasable(&self) -> Result<bool, MmcReadDiscInfoError> {
33 let data = self.read_disc_information(DiscInfoKind::Standard)?;
34 Ok(data[2] & 1 << 4 != 0)
35 }
36
37 fn read_disc_information(&self, kind: DiscInfoKind) -> Result<Vec<u8>, MmcReadDiscInfoError> {
38 let mut buf = vec![0; INITIAL_BUFFER_SIZE];
39 let mut cdb = Cdb::default();
40 cdb[0] = MmcCommand::ReadDiscInfo as u8;
41 cdb[1] = kind as u8 & 0b111;
42 cdb[7..9].copy_from_slice(&(buf.len() as u16).to_be_bytes());
43
44 self.run_command(Some(MmcDirection::Read), buf.as_mut_slice(), cdb)?;
45
46 let data_length = buf[0..2]
47 .try_into()
48 .map(u16::from_be_bytes)
49 .map(|len| usize::from(len) + DATA_LEN_FIELDSIZE)
50 .expect("initial buffer length is greater than two bytes");
51 if buf.len() < data_length {
52 buf.resize(data_length, 0);
53 cdb[7..9].copy_from_slice(&(buf.len() as u16).to_be_bytes());
54 self.run_command(Some(MmcDirection::Read), buf.as_mut_slice(), cdb)?;
55 }
56 buf.truncate(data_length);
57 tracing::debug!(?buf, len = buf.len());
58
59 return Ok(buf);
60
61 const INITIAL_BUFFER_SIZE: usize = 64;
62 const DATA_LEN_FIELDSIZE: usize = 2;
63 }
64}
65
66#[allow(unused)]
67#[repr(u8)]
68#[derive(Clone, Copy, Debug)]
69enum DiscInfoKind {
70 Standard = 0b000,
72
73 TrackResources = 0b001,
75
76 PowResources = 0b010,
78}
79
80#[derive(Debug, Display, Error)]
82pub enum MmcReadDiscInfoError {
83 Os(#[from] MmcError),
85
86 InvalidResponse(String),
88}
89
90#[cfg(test)]
91mod tests {
92 use tracing::info;
93
94 use super::*;
95
96 #[test_log::test(test)]
97 #[ignore = "requires a drive with mmc"]
98 fn is_disc_erasable() {
99 let is_disc_erasable = Mmc::new().unwrap().is_disc_erasable().unwrap();
100 info!(is_disc_erasable);
101 }
102}