drivers/standard_library/
loader.rs

1use file_system::{FileSystemTraits, Flags, Mode, Open, Path, PathOwned, Time};
2use std::io;
3use std::prelude::rust_2024::*;
4use std::{fs::File, io::Read, path};
5use task::TaskIdentifier;
6use users::{GroupIdentifier, UserIdentifier};
7
8pub type Result<T> = core::result::Result<T, Error>;
9
10#[derive(Debug)]
11pub enum Error {
12    FileSystemError(file_system::Error),
13    IoError(io::Error),
14}
15
16impl From<file_system::Error> for Error {
17    fn from(error: file_system::Error) -> Self {
18        Self::FileSystemError(error)
19    }
20}
21
22impl From<io::Error> for Error {
23    fn from(error: io::Error) -> Self {
24        Self::IoError(error)
25    }
26}
27
28pub struct Loader<'a> {
29    paths: Vec<(path::PathBuf, PathOwned)>,
30    buffers: Vec<(&'a [u8], PathOwned)>,
31}
32
33impl Default for Loader<'_> {
34    fn default() -> Self {
35        Self::new()
36    }
37}
38
39impl<'a> Loader<'a> {
40    pub fn new() -> Self {
41        Self {
42            paths: vec![],
43            buffers: vec![],
44        }
45    }
46
47    pub fn add_file_from_buffer(mut self, buffer: &'a [u8], destination: impl AsRef<Path>) -> Self {
48        self.buffers.push((buffer, destination.as_ref().to_owned()));
49
50        self
51    }
52
53    pub fn add_files_from_buffers(
54        mut self,
55        buffers: impl IntoIterator<Item = (&'a [u8], PathOwned)>,
56    ) -> Self {
57        for (buffer, destination) in buffers {
58            self = self.add_file_from_buffer(buffer, destination);
59        }
60
61        self
62    }
63
64    pub fn add_file(
65        mut self,
66        source: impl AsRef<path::Path>,
67        destination: impl AsRef<Path>,
68    ) -> Self {
69        self.paths
70            .push((source.as_ref().to_owned(), destination.as_ref().to_owned()));
71
72        self
73    }
74
75    pub fn add_files(
76        mut self,
77        files: impl IntoIterator<Item = (path::PathBuf, PathOwned)>,
78    ) -> Self {
79        for file in files {
80            self = self.add_file(file.0, file.1);
81        }
82
83        self
84    }
85
86    pub fn load(&self, file_system: &mut dyn FileSystemTraits) -> Result<()> {
87        // Open file for reading on host
88        for (source_path, destination_path) in &self.paths {
89            // Open file for reading on host
90            let mut source_file = File::open(source_path)?;
91
92            // Create file on target
93            let destination_file = file_system.open(
94                TaskIdentifier::new(0),
95                destination_path,
96                Flags::new(Mode::READ_ONLY, Some(Open::CREATE), None),
97                Time::new(0),
98                UserIdentifier::ROOT,
99                GroupIdentifier::ROOT,
100            )?;
101
102            // Read and write file content block by block
103            let mut buffer = [0; 1024];
104            loop {
105                let read = source_file.read(&mut buffer)?;
106
107                if read == 0 {
108                    break;
109                }
110
111                file_system.write(destination_file, &buffer[..read], Time::new(0))?;
112            }
113
114            file_system.close(destination_file)?;
115        }
116
117        // Write buffers to file system
118        for (buffer, destination_path) in &self.buffers {
119            let destination_file = file_system.open(
120                TaskIdentifier::new(0),
121                destination_path,
122                Flags::new(Mode::READ_ONLY, Some(Open::CREATE), None),
123                Time::new(0),
124                UserIdentifier::ROOT,
125                GroupIdentifier::ROOT,
126            )?;
127
128            file_system.write(destination_file, buffer, Time::new(0))?;
129            file_system.close(destination_file)?;
130        }
131
132        Ok(())
133    }
134}
135
136#[cfg(test)]
137mod tests {
138    use super::*;
139    use file_system::FileSystemTraits;
140
141    #[test]
142    fn test_loader() {
143        // - Load the file in the file system
144        let source_path = "Cargo.toml";
145        let destination_path = "/Cargo.toml";
146
147        let device =
148            file_system::create_device!(file_system::MemoryDevice::<512>::new(1024 * 1024 * 512));
149
150        little_fs::FileSystem::format(device.clone(), 256).unwrap();
151        let mut file_system = little_fs::FileSystem::new(device, 256).unwrap();
152
153        let loader = Loader::new().add_file(source_path, destination_path);
154
155        loader.load(&mut file_system).unwrap();
156
157        // - Read the file and compare it with the original
158        let test_file = std::fs::read_to_string(source_path).unwrap();
159
160        let mut buffer = vec![0; test_file.len()];
161
162        let file: file_system::LocalFileIdentifier = file_system
163            .open(
164                TaskIdentifier::new(0),
165                Path::new(destination_path),
166                Flags::new(Mode::READ_ONLY, None, None),
167                Time::new(0),
168                UserIdentifier::ROOT,
169                GroupIdentifier::ROOT,
170            )
171            .unwrap();
172
173        let read = file_system.read(file, &mut buffer, Time::new(0)).unwrap();
174
175        assert_eq!(read, test_file.len());
176        assert_eq!(buffer, test_file.as_bytes());
177    }
178}