Skip to main content

libcdio_rs/
udf.rs

1// Copyright (C) 2026 Shiva Kiran Koninty <shiva@skran.xyz>
2//
3// This file is part of libcdio-rs.
4//
5// libcdio-rs is free software: you can redistribute it and/or
6// modify it under the terms of the GNU General Public License as
7// published by the Free Software Foundation, either version 3 of the
8// License, or (at your option) any later version.
9//
10// libcdio-rs is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13// General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with libcdio-rs. If not, see <https://www.gnu.org/licenses/>.
17
18//! UDF filesystem.
19
20pub use entry::*;
21
22mod entry;
23
24use thiserror::Error;
25
26use std::{
27    error::Error,
28    ffi::{CString, OsString},
29    path::PathBuf,
30    ptr::NonNull,
31};
32
33use libcdio_sys::udf_t;
34
35use crate::logging;
36
37/// A UDF filesystem instance.
38pub struct Udf {
39    pub(crate) udf: NonNull<udf_t>,
40}
41
42impl Udf {
43    /// The number of bytes in a UDF block.
44    pub const BLOCK_SIZE: usize = 2048;
45
46    /// Opens a UDF filesystem at `path`.
47    pub fn new(path: PathBuf) -> Result<Self, UdfOpenError> {
48        logging::init_logger();
49
50        let path = CString::new(path.into_os_string().as_encoded_bytes())
51            .map_err(|err| UdfOpenError::new(err.clone().into_vec(), Some(err.into())))?;
52        let udf = unsafe { libcdio_sys::udf_open(path.as_ptr()) };
53
54        NonNull::new(udf)
55            .map(|udf| Self { udf })
56            .ok_or_else(|| UdfOpenError::new(path.into_bytes(), None))
57    }
58}
59
60impl Drop for Udf {
61    fn drop(&mut self) {
62        let _ = unsafe { libcdio_sys::udf_close(self.udf.as_mut()) };
63    }
64}
65
66#[derive(Debug, Error)]
67#[error(transparent)]
68pub struct UdfOpenError(Box<Repr>);
69
70#[derive(Debug, Error)]
71#[error("error opening UDF filesystem at `{:?}`", path)]
72struct Repr {
73    path: PathBuf,
74    source: Option<Box<dyn Error + Send + Sync>>,
75}
76
77impl UdfOpenError {
78    /// The path used to open the UDF file.
79    pub fn path(self) -> PathBuf {
80        self.0.path
81    }
82
83    fn new(path_bytes: Vec<u8>, source: Option<Box<dyn Error + Send + Sync>>) -> Self {
84        Self(Box::new(Repr {
85            // SAFETY: path_bytes originate from a `PathBuf`
86            path: unsafe { OsString::from_encoded_bytes_unchecked(path_bytes) }.into(),
87            source,
88        }))
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96    pub fn test_udf_file() -> PathBuf {
97        PathBuf::from("tests/data/udf.iso")
98    }
99
100    #[test]
101    fn new() {
102        let _ = Udf::new(test_udf_file()).unwrap();
103    }
104}