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