Skip to main content

virtual_file_system/
file.rs

1use super::VirtualFileSystem;
2use crate::{Error, ItemStatic, Result, SynchronousFile, poll};
3use alloc::{vec, vec::Vec};
4use core::mem::forget;
5use embedded_io_async::ErrorType;
6use exported_file_system::{AccessFlags, ControlCommand, CreateFlags, Permissions};
7use file_system::{Context, Flags, Path, Position, Size, StateFlags, Statistics};
8use task::TaskIdentifier;
9use task::block_on;
10use users::{GroupIdentifier, UserIdentifier};
11
12/// File structure.
13///
14/// This structure is used to represent a file in the virtual file system.
15/// This is a wrapper around the virtual file system file identifier.
16#[derive(Debug)]
17pub struct File<'a>(SynchronousFile<'a>);
18
19impl<'a> File<'a> {
20    pub fn as_synchronous_file_mut(&mut self) -> &mut SynchronousFile<'a> {
21        &mut self.0
22    }
23}
24
25impl ErrorType for File<'_> {
26    type Error = Error;
27}
28
29impl embedded_io_async::Write for File<'_> {
30    async fn write(&mut self, buf: &[u8]) -> core::result::Result<usize, Self::Error> {
31        File::write(self, buf).await
32    }
33
34    async fn flush(&mut self) -> core::result::Result<(), Self::Error> {
35        File::flush(self).await
36    }
37}
38
39impl core::fmt::Write for File<'_> {
40    fn write_str(&mut self, s: &str) -> core::fmt::Result {
41        if let Err(e) = block_on(self.write(s.as_bytes())) {
42            log::error!("Error writing string to file: {}", e);
43            return Err(core::fmt::Error);
44        }
45        Ok(())
46    }
47}
48
49impl<'a> File<'a> {
50    pub(crate) fn new(
51        virtual_file_system: &'a VirtualFileSystem,
52        item: ItemStatic,
53        flags: Flags,
54        context: Context,
55    ) -> Self {
56        Self(SynchronousFile::new(
57            virtual_file_system,
58            item,
59            0,
60            flags,
61            context,
62        ))
63    }
64
65    pub async fn open(
66        virtual_file_system: &'a VirtualFileSystem,
67        task: task::TaskIdentifier,
68        path: impl AsRef<Path>,
69        flags: Flags,
70    ) -> Result<Self> {
71        let file_identifier = virtual_file_system.open(&path, flags, task).await?;
72
73        Ok(file_identifier)
74    }
75
76    pub async fn create_unnamed_pipe(
77        file_system: &'a VirtualFileSystem,
78        size: usize,
79        status: StateFlags,
80    ) -> Result<(Self, Self)> {
81        file_system.create_unnamed_pipe(size, status).await
82    }
83
84    pub async fn set_position(&mut self, position: &Position) -> Result<Size> {
85        poll(|| self.0.set_position(position)).await
86    }
87
88    // - Operations
89
90    pub async fn write(&mut self, buffer: &[u8]) -> Result<usize> {
91        poll(|| self.0.write(buffer)).await
92    }
93
94    pub async fn read_slice_from_path(
95        virtual_file_system: &VirtualFileSystem,
96        task: TaskIdentifier,
97        path: impl AsRef<Path>,
98        buffer: &mut [u8],
99    ) -> Result<()> {
100        let mut file = File::open(
101            virtual_file_system,
102            task,
103            path,
104            Flags::new(AccessFlags::Read, None, None),
105        )
106        .await?;
107
108        file.read(buffer).await?;
109
110        file.close(virtual_file_system).await?;
111
112        Ok(())
113    }
114
115    pub async fn read_from_path(
116        virtual_file_system: &VirtualFileSystem,
117        task: TaskIdentifier,
118        path: impl AsRef<Path>,
119        buffer: &mut Vec<u8>,
120    ) -> Result<()> {
121        buffer.clear();
122
123        let mut file = File::open(
124            virtual_file_system,
125            task,
126            path,
127            Flags::new(AccessFlags::Read, None, None),
128        )
129        .await?;
130
131        file.read_to_end(buffer, 256).await?;
132
133        file.close(virtual_file_system).await?;
134
135        Ok(())
136    }
137
138    pub async fn write_to_path(
139        virtual_file_system: &VirtualFileSystem,
140        task: task::TaskIdentifier,
141        path: impl AsRef<Path>,
142        buffer: &[u8],
143    ) -> Result<()> {
144        let mut file = File::open(
145            virtual_file_system,
146            task,
147            path,
148            Flags::new(AccessFlags::Write, Some(CreateFlags::CREATE_TRUNCATE), None),
149        )
150        .await?;
151
152        file.write(buffer).await?;
153
154        file.close(virtual_file_system).await
155    }
156
157    pub async fn write_line(&mut self, buffer: &[u8]) -> Result<usize> {
158        poll(|| self.0.write_line(buffer)).await
159    }
160
161    pub async fn display_content<W: embedded_io_async::Write>(
162        &mut self,
163        w: &mut W,
164        buffer_size: usize,
165    ) -> Result<()> {
166        let mut buffer = vec![0u8; buffer_size];
167        loop {
168            let bytes_read = self.read(&mut buffer).await?;
169
170            if bytes_read == 0 {
171                break;
172            }
173
174            w.write(&buffer[..bytes_read])
175                .await
176                .map_err(|_| Error::FailedToWrite)?;
177        }
178
179        Ok(())
180    }
181
182    pub async fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
183        poll(|| self.0.read(buffer)).await
184    }
185
186    pub async fn read_until(&mut self, buffer: &mut [u8], delimiter: &[u8]) -> Result<usize> {
187        poll(|| self.0.read_until(buffer, delimiter)).await
188    }
189
190    pub async fn read_to_end(&mut self, buffer: &mut Vec<u8>, chunk_size: usize) -> Result<usize> {
191        poll(|| self.0.read_to_end(buffer, chunk_size)).await
192    }
193
194    pub async fn flush(&mut self) -> Result<()> {
195        poll(|| self.0.flush()).await
196    }
197
198    pub async fn duplicate(&self) -> Result<Self> {
199        Ok(Self(poll(|| self.0.duplicate()).await?))
200    }
201
202    pub async fn get_statistics(&mut self) -> Result<Statistics> {
203        poll(|| self.0.get_statistics()).await
204    }
205
206    pub async fn set_owner(
207        &mut self,
208        user: Option<UserIdentifier>,
209        group: Option<GroupIdentifier>,
210    ) -> Result<()> {
211        poll(|| self.0.set_owner(user, group)).await
212    }
213
214    pub async fn set_permissions(&mut self, permissions: Permissions) -> Result<()> {
215        poll(|| self.0.set_permissions(permissions)).await
216    }
217
218    pub async fn control<C>(&mut self, command: C, argument: &C::Input) -> Result<C::Output>
219    where
220        C: ControlCommand,
221        C::Output: Default,
222    {
223        poll(|| self.0.control(command, argument)).await
224    }
225
226    pub fn get_access(&self) -> Result<AccessFlags> {
227        Ok(self.0.flags.get_access())
228    }
229
230    pub async fn close(mut self, virtual_file_system: &VirtualFileSystem) -> crate::Result<()> {
231        let result = virtual_file_system
232            .close(&self.0.item, &mut self.0.context)
233            .await;
234        forget(self);
235
236        result
237    }
238
239    pub fn into_synchronous_file(self) -> SynchronousFile<'a> {
240        self.0
241    }
242}
243
244pub struct FileControlIterator<'a, C> {
245    file: &'a mut File<'a>,
246    get_command: C,
247    index: usize,
248    count: usize,
249}
250
251impl<'a, C> FileControlIterator<'a, C>
252where
253    C: ControlCommand<Input = usize>,
254    C::Output: Default,
255{
256    pub async fn new<Cc>(file: &'a mut File<'a>, count_command: Cc, get_command: C) -> Result<Self>
257    where
258        Cc: ControlCommand<Input = (), Output = usize>,
259    {
260        let count: usize = file.control(count_command, &()).await?;
261
262        Ok(Self {
263            file,
264            get_command,
265            index: 0,
266            count,
267        })
268    }
269
270    pub async fn next(&mut self) -> Result<Option<C::Output>> {
271        if self.index >= self.count {
272            return Ok(None);
273        }
274
275        let result = self.file.control(self.get_command, &self.index).await?;
276
277        self.index += 1;
278
279        Ok(Some(result))
280    }
281}