xdvdfs/write/fs/
mod.rs

1use core::fmt::Debug;
2use core::slice::Iter;
3use std::borrow::ToOwned;
4use std::format;
5use std::path::{Path, PathBuf};
6
7use alloc::boxed::Box;
8use alloc::string::String;
9use alloc::vec::Vec;
10
11use crate::blockdev::BlockDeviceWrite;
12
13use maybe_async::maybe_async;
14
15mod remap;
16mod sector_linear;
17mod xdvdfs;
18
19pub use remap::*;
20pub use sector_linear::*;
21pub use xdvdfs::*;
22
23#[cfg(not(target_family = "wasm"))]
24mod stdfs;
25
26#[cfg(not(target_family = "wasm"))]
27pub use stdfs::*;
28
29#[derive(Copy, Clone, Debug)]
30pub enum FileType {
31    File,
32    Directory,
33}
34
35#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
36pub struct PathVec {
37    components: Vec<String>,
38}
39
40type PathVecIter<'a> = Iter<'a, String>;
41
42#[derive(Clone, Debug)]
43pub struct FileEntry {
44    pub name: String,
45    pub file_type: FileType,
46    pub len: u64,
47}
48
49#[derive(Clone, Debug)]
50pub struct DirectoryTreeEntry {
51    pub dir: PathVec,
52    pub listing: Vec<FileEntry>,
53}
54
55impl PathVec {
56    pub fn as_path_buf(&self, prefix: &Path) -> PathBuf {
57        let suffix = PathBuf::from_iter(self.components.iter());
58        prefix.join(suffix)
59    }
60
61    pub fn is_root(&self) -> bool {
62        self.components.is_empty()
63    }
64
65    pub fn iter(&self) -> PathVecIter {
66        self.components.iter()
67    }
68
69    pub fn from_base(prefix: &Self, suffix: &str) -> Self {
70        let mut path = prefix.clone();
71        path.components.push(suffix.to_owned());
72        path
73    }
74
75    pub fn as_string(&self) -> String {
76        format!("/{}", self.components.join("/"))
77    }
78
79    pub fn suffix(&self, prefix: &Self) -> Self {
80        let mut components = Vec::new();
81        let mut i1 = self.iter();
82        let mut i2 = prefix.iter();
83
84        loop {
85            let c1 = i1.next();
86            let c2 = i2.next();
87
88            if let Some(component) = c1 {
89                if let Some(component2) = c2 {
90                    assert_eq!(component, component2);
91                } else {
92                    components.push(component.clone());
93                }
94            } else {
95                return Self { components };
96            }
97        }
98    }
99}
100
101impl<'a> FromIterator<&'a str> for PathVec {
102    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
103        let components = iter
104            .into_iter()
105            .filter(|s| !s.is_empty())
106            .map(|s| s.to_owned())
107            .collect();
108        Self { components }
109    }
110}
111
112#[maybe_async]
113pub trait Filesystem<RawHandle: BlockDeviceWrite<RHError>, E, RHError: Into<E> = E>:
114    Send + Sync
115{
116    /// Read a directory, and return a list of entries within it
117    ///
118    /// Other functions in this trait are guaranteed to be called with PathVecs
119    /// returned from this function call, possibly with the FileEntry name appended.
120    async fn read_dir(&mut self, path: &PathVec) -> Result<Vec<FileEntry>, E>;
121
122    /// Copy the entire contents of file `src` into `dest` at the specified offset
123    async fn copy_file_in(
124        &mut self,
125        src: &PathVec,
126        dest: &mut RawHandle,
127        offset: u64,
128        size: u64,
129    ) -> Result<u64, E>;
130
131    /// Copy the contents of file `src` into `buf` at the specified offset
132    /// Not required for normal usage
133    async fn copy_file_buf(
134        &mut self,
135        _src: &PathVec,
136        _buf: &mut [u8],
137        _offset: u64,
138    ) -> Result<u64, E>;
139
140    /// Display a filesystem path as a String
141    fn path_to_string(&self, path: &PathVec) -> String {
142        path.as_string()
143    }
144}
145
146#[maybe_async]
147impl<E: Send + Sync, R: BlockDeviceWrite<E>> Filesystem<R, E> for Box<dyn Filesystem<R, E>> {
148    async fn read_dir(&mut self, path: &PathVec) -> Result<Vec<FileEntry>, E> {
149        self.as_mut().read_dir(path).await
150    }
151
152    async fn copy_file_in(
153        &mut self,
154        src: &PathVec,
155        dest: &mut R,
156        offset: u64,
157        size: u64,
158    ) -> Result<u64, E> {
159        self.as_mut().copy_file_in(src, dest, offset, size).await
160    }
161
162    async fn copy_file_buf(
163        &mut self,
164        src: &PathVec,
165        buf: &mut [u8],
166        offset: u64,
167    ) -> Result<u64, E> {
168        self.as_mut().copy_file_buf(src, buf, offset).await
169    }
170}