1pub 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
37pub struct Udf {
39 pub(crate) udf: NonNull<udf_t>,
40}
41
42impl Udf {
43 pub const BLOCK_SIZE: usize = 2048;
45
46 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 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 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}