From 1022cc9d8452074da62cb9b0614826566c993daa Mon Sep 17 00:00:00 2001 From: Shiva Kiran Koninty Date: Thu, 16 Jul 2026 11:12:38 +0530 Subject: [PATCH 1/2] lib/cdio: Replace `Cdio::new()` with `Cdio::with_device()` There are two major types of drivers in Cdio. - OS - Images Thus, rather than have a generic `new()` method with multiple (unused) initialization options, have two methods `with_device()` and `with_image()`. This commit introduces `with_device()`. --- libcdio-rs/src/cdio.rs | 21 ++++++++++++++------- libcdio-rs/src/drive.rs | 7 ++++--- libcdio-rs/src/mmc.rs | 4 ++-- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/libcdio-rs/src/cdio.rs b/libcdio-rs/src/cdio.rs index a46e447..cd3645b 100644 --- a/libcdio-rs/src/cdio.rs +++ b/libcdio-rs/src/cdio.rs @@ -32,22 +32,29 @@ pub(crate) struct Cdio { } impl Cdio { - /// Create a new Cdio object with the given parameters. - pub(crate) fn new(device: Option<&CStr>, driver: driver_id_t) -> Option { + /// Initialize a hardware Cdio resource with read-write access. + pub(crate) fn with_device(device: Option<&CStr>) -> Option { let source = device.map(|s| s.as_ptr()).unwrap_or(ptr::null()); - NonNull::new(Self::open(source, driver)).map(|cdio| Self { cdio }) + NonNull::new(Self::open(true, source, driver_id_t_DRIVER_DEVICE)).map(|cdio| Self { cdio }) } - fn open(source: *const c_char, driver: driver_id_t) -> *mut CdIo_t { + fn open(allow_writes: bool, source: *const c_char, driver: driver_id_t) -> *mut CdIo_t { logging::init_logger(); + let access_mode = if allow_writes { + RW_ACCESS_MODE.as_ptr() + } else { + ptr::null() + }; // SAFETY: This invokes cdio_init(), which mutates a static variable. // CDIO_LAST_DRIVER_LOCK is held to prevent data races. let _lock = CDIO_LAST_DRIVER_LOCK.lock().unwrap(); - unsafe { libcdio_sys::cdio_open(source, driver) } - } + return unsafe { libcdio_sys::cdio_open_am(source, driver, access_mode) }; - pub(crate) const DEVICE_DRIVER: driver_id_t = driver_id_t_DRIVER_DEVICE; + /// Although prefixed "MMC", this does imply read-write for all + /// operations + static RW_ACCESS_MODE: &CStr = c"MMC_RDWR"; + } } impl Deref for Cdio { diff --git a/libcdio-rs/src/drive.rs b/libcdio-rs/src/drive.rs index cea98df..ab88260 100644 --- a/libcdio-rs/src/drive.rs +++ b/libcdio-rs/src/drive.rs @@ -40,7 +40,8 @@ impl Drive { /// Get a list of connected drives. /// The values could be used with [`Self::with_drive()`]. pub fn drives() -> Vec { - let drive_list = unsafe { libcdio_sys::cdio_get_devices(Cdio::DEVICE_DRIVER) }; + let drive_list = + unsafe { libcdio_sys::cdio_get_devices(libcdio_sys::driver_id_t_DRIVER_DEVICE) }; if drive_list.is_null() { return vec![]; } @@ -72,7 +73,7 @@ impl Drive { /// # Errors /// If there are no drives connected, or the drive could not be opened. pub fn new() -> Result { - Cdio::new(None, Cdio::DEVICE_DRIVER) + Cdio::with_device(None) .ok_or(DriveNotFoundError) .map(|cdio| Self { cdio }) } @@ -91,7 +92,7 @@ impl Drive { source: WithDriveErrorKind::DriveHasNullChar(err), } })?; - let cdio = Cdio::new(Some(&drive), Cdio::DEVICE_DRIVER).ok_or_else(|| WithDriveError { + let cdio = Cdio::with_device(Some(&drive)).ok_or_else(|| WithDriveError { drive: os_string_from_bytes_safe(drive.into_bytes()).into(), source: WithDriveErrorKind::CouldNotOpenAsDrive, })?; diff --git a/libcdio-rs/src/mmc.rs b/libcdio-rs/src/mmc.rs index 36e09d5..bdfadef 100644 --- a/libcdio-rs/src/mmc.rs +++ b/libcdio-rs/src/mmc.rs @@ -71,7 +71,7 @@ impl Mmc { /// # Errors /// If an MMC capable device could not be found. pub fn new() -> Result { - Cdio::new(None, Cdio::DEVICE_DRIVER) + Cdio::with_device(None) .map(|cdio| Self { cdio }) .filter(|mmc| mmc.level().is_ok()) .ok_or(MmcNotFoundError) @@ -89,7 +89,7 @@ impl Mmc { source: WithDeviceErrorKind::DeviceHasNullChar(err), } })?; - let Some(cdio) = Cdio::new(Some(&device), Cdio::DEVICE_DRIVER) else { + let Some(cdio) = Cdio::with_device(Some(&device)) else { return Err(WithDeviceError { device: os_string_from_bytes_safe(device.into_bytes()).into(), source: WithDeviceErrorKind::CouldNotOpenDevice, From 508ab6fa6bd724d32c8334203e2631532ced0cdb Mon Sep 17 00:00:00 2001 From: Shiva Kiran Koninty Date: Thu, 16 Jul 2026 12:49:21 +0530 Subject: [PATCH 2/2] lib/mmc: Add routines for `PREVENT ALLOW MEDIUM REMOVAL` --- libcdio-rs/src/mmc.rs | 3 + .../src/mmc/prevent_allow_medium_removal.rs | 73 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 libcdio-rs/src/mmc/prevent_allow_medium_removal.rs diff --git a/libcdio-rs/src/mmc.rs b/libcdio-rs/src/mmc.rs index bdfadef..4a0cbfb 100644 --- a/libcdio-rs/src/mmc.rs +++ b/libcdio-rs/src/mmc.rs @@ -25,10 +25,12 @@ use std::{ pub use get_config::*; pub use get_event_status::*; +pub use prevent_allow_medium_removal::*; pub use read_subchannel::*; mod get_config; mod get_event_status; +mod prevent_allow_medium_removal; mod read_subchannel; use docsplay::Display; @@ -359,6 +361,7 @@ pub enum OsError { #[derive(Clone, Copy, Debug)] enum MmcCommand { GetConfiguration = 0x46, + PreventAllowMediumRemoval = 0x1E, } #[cfg(test)] diff --git a/libcdio-rs/src/mmc/prevent_allow_medium_removal.rs b/libcdio-rs/src/mmc/prevent_allow_medium_removal.rs new file mode 100644 index 0000000..e79af32 --- /dev/null +++ b/libcdio-rs/src/mmc/prevent_allow_medium_removal.rs @@ -0,0 +1,73 @@ +// Copyright (C) 2026 Shiva Kiran Koninty +// +// This file is part of libcdio-rs. +// +// libcdio-rs is free software: you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// libcdio-rs is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with libcdio-rs. If not, see . + +//! Routines based on MMC `PREVENT ALLOW MEDIUM REMOVAL`. + +use displaydoc::Display; +use thiserror::Error; + +use crate::{ + Mmc, + mmc::{Cdb, MmcCommand, MmcDirection, MmcError}, +}; + +/// Routines based on MMC `PREVENT ALLOW MEDIUM REMOVAL` +impl Mmc { + /// Allow media removal. + pub fn allow_media_removal(&self) -> Result<(), MmcMediaRemovalError> { + self.prevent_allow_medium_removal(PreventOption::Clear) + } + + /// Prevent media removal. + pub fn prevent_media_removal(&self) -> Result<(), MmcMediaRemovalError> { + self.prevent_allow_medium_removal(PreventOption::Set) + } + + fn prevent_allow_medium_removal( + &self, + prevent: PreventOption, + ) -> Result<(), MmcMediaRemovalError> { + let mut cdb = Cdb::default(); + cdb[0] = MmcCommand::PreventAllowMediumRemoval as u8; + cdb[4] = prevent as u8; + + self.run_command(Some(MmcDirection::Write), &mut [], cdb)?; + + Ok(()) + } +} + +/// error from a `PREVENT ALLOW MEDIUM REMOVAL` command. +#[non_exhaustive] +#[derive(Debug, Display, Error)] +pub struct MmcMediaRemovalError { + #[from] + pub source: MmcError, +} + +/// Operations of the `PREVENT ALLOW MEDIUM REMOVAL` command +#[allow(unused)] +#[repr(u8)] +#[derive(Clone, Copy, Debug)] +enum PreventOption { + Clear = 0b00, + Set = 0b01, + ClearPersistent = 0b10, + SetPersistent = 0b11, +} + +// TODO: add manual tests