Skip to main content

virtual_file_system/
synchronous_file.rs

1use core::{fmt::Debug, mem::forget};
2
3use crate::{Error, ItemStatic, Result, VirtualFileSystem};
4use alloc::{vec, vec::Vec};
5use exported_file_system::StateFlags;
6use exported_file_system::{ControlCommand, Permissions};
7use file_system::{
8    AccessFlags, AttributeFlags, Attributes, Context, Flags, Path, Position, Size, Statistics,
9};
10use shared::AnyByLayout;
11use task::TaskIdentifier;
12use task::block_on;
13use users::{GroupIdentifier, UserIdentifier};
14
15pub struct SynchronousFile<'a> {
16    virtual_file_system: &'a VirtualFileSystem,
17    pub(crate) item: ItemStatic,
18    pub(crate) position: Size,
19    pub(crate) flags: Flags,
20    pub(crate) context: Context,
21}
22
23impl Debug for SynchronousFile<'_> {
24    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
25        f.debug_struct("SynchronousFile")
26            .field("item", &self.item)
27            .field("position", &self.position)
28            .field("flags", &self.flags)
29            .finish()
30    }
31}
32
33impl<'a> SynchronousFile<'a> {
34    pub(crate) const fn new(
35        virtual_file_system: &'a VirtualFileSystem,
36        item: ItemStatic,
37        position: Size,
38        flags: Flags,
39        context: Context,
40    ) -> Self {
41        Self {
42            virtual_file_system,
43            item,
44            position,
45            flags,
46            context,
47        }
48    }
49
50    pub fn open(
51        virtual_file_system: &'a VirtualFileSystem,
52        task: TaskIdentifier,
53        path: impl AsRef<Path>,
54        flags: Flags,
55    ) -> Result<Self> {
56        let file_identifier = block_on(virtual_file_system.open(&path, flags, task))?;
57
58        Ok(file_identifier.into_synchronous_file())
59    }
60
61    pub fn set_position(&mut self, position: &Position) -> Result<Size> {
62        self.position = self
63            .item
64            .as_base_operations()
65            .ok_or(Error::UnsupportedOperation)?
66            .set_position(&mut self.context, self.position, position)?;
67
68        Ok(self.position)
69    }
70
71    // - Operations
72
73    pub fn write(&mut self, buffer: &[u8]) -> Result<usize> {
74        if !self.flags.get_access().contains(AccessFlags::Write) {
75            return Err(Error::InvalidMode);
76        }
77
78        let size = self
79            .item
80            .as_base_operations()
81            .ok_or(Error::UnsupportedOperation)?
82            .write(&mut self.context, buffer, self.position)?;
83
84        self.position += size as Size;
85
86        Ok(size)
87    }
88
89    pub fn write_vectored(&mut self, buffers: &[&[u8]]) -> Result<usize> {
90        if !self.flags.get_access().contains(AccessFlags::Write) {
91            return Err(Error::InvalidMode);
92        }
93
94        let size = self
95            .item
96            .as_base_operations()
97            .ok_or(Error::UnsupportedOperation)?
98            .write_vectored(&mut self.context, buffers, self.position)?;
99
100        self.position += size as Size;
101
102        Ok(size)
103    }
104
105    pub fn write_line(&mut self, buffer: &[u8]) -> Result<usize> {
106        let size = self.write(buffer)? + self.write(b"\n")?;
107
108        Ok(size)
109    }
110
111    pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
112        let size = self
113            .item
114            .as_base_operations()
115            .ok_or(Error::UnsupportedOperation)?
116            .read(&mut self.context, buffer, self.position)?;
117
118        self.position += size as Size;
119
120        Ok(size)
121    }
122
123    pub fn read_until(&mut self, buffer: &mut [u8], delimiter: &[u8]) -> Result<usize> {
124        let size = self
125            .item
126            .as_base_operations()
127            .ok_or(Error::UnsupportedOperation)?
128            .read_until(&mut self.context, buffer, self.position, delimiter)?;
129
130        self.position += size as Size;
131
132        Ok(size)
133    }
134
135    pub fn read_to_end(&mut self, buffer: &mut Vec<u8>, chunk_size: usize) -> Result<usize> {
136        let mut total_read_size = 0;
137
138        let mut chunk = vec![0u8; chunk_size];
139        loop {
140            let read_size = self
141                .item
142                .as_base_operations()
143                .ok_or(Error::UnsupportedOperation)?
144                .read(&mut self.context, &mut chunk, self.position)?;
145
146            if read_size == 0 {
147                break;
148            }
149
150            self.position += read_size as Size;
151
152            total_read_size += read_size;
153
154            buffer.extend_from_slice(&chunk[..read_size]);
155
156            // Yield to allow other tasks to run.
157            //yield_now().await;
158        }
159
160        Ok(total_read_size)
161    }
162
163    pub fn flush(&mut self) -> Result<()> {
164        self.item
165            .as_base_operations()
166            .ok_or(Error::UnsupportedOperation)?
167            .flush(&mut self.context)?;
168
169        Ok(())
170    }
171
172    pub fn duplicate(&self) -> Result<Self> {
173        let context = self
174            .item
175            .as_base_operations()
176            .ok_or(Error::UnsupportedOperation)?
177            .clone_context(&self.context)?;
178
179        Ok(Self {
180            virtual_file_system: self.virtual_file_system,
181            item: self.item.clone(),
182            position: self.position,
183            flags: self.flags,
184            context,
185        })
186    }
187
188    pub fn get_statistics(&mut self) -> Result<Statistics> {
189        let mut attributes = Attributes::new().set_mask(AttributeFlags::All);
190
191        self.item
192            .as_attributes_operations()
193            .ok_or(Error::UnsupportedOperation)?
194            .get_attributes(&mut self.context, &mut attributes)?;
195
196        Statistics::from_attributes(&attributes).ok_or(Error::MissingAttribute)
197    }
198
199    pub fn set_owner(
200        &mut self,
201        user: Option<UserIdentifier>,
202        group: Option<GroupIdentifier>,
203    ) -> Result<()> {
204        let mut attributes = Attributes::new();
205
206        if let Some(user) = user {
207            attributes = attributes.set_user(user);
208        }
209
210        if let Some(group) = group {
211            attributes = attributes.set_group(group);
212        }
213
214        self.item
215            .as_attributes_operations()
216            .ok_or(Error::UnsupportedOperation)?
217            .set_attributes(&mut self.context, &attributes)?;
218
219        Ok(())
220    }
221
222    pub fn set_permissions(&mut self, permissions: Permissions) -> Result<()> {
223        let attributes = Attributes::new().set_permissions(permissions);
224
225        self.item
226            .as_attributes_operations()
227            .ok_or(Error::UnsupportedOperation)?
228            .set_attributes(&mut self.context, &attributes)?;
229
230        Ok(())
231    }
232
233    pub fn control<C>(&mut self, _command: C, argument: &C::Input) -> Result<C::Output>
234    where
235        C: ControlCommand,
236        C::Output: Default,
237    {
238        let mut output = C::Output::default();
239
240        self.item
241            .as_base_operations()
242            .ok_or(Error::UnsupportedOperation)?
243            .control(
244                &mut self.context,
245                C::IDENTIFIER,
246                AnyByLayout::from(argument),
247                AnyByLayout::from_mutable(&mut output),
248            )?;
249
250        Ok(output)
251    }
252
253    pub fn get_access(&self) -> Result<AccessFlags> {
254        Ok(self.flags.get_access())
255    }
256
257    pub fn get_state(&self) -> Result<StateFlags> {
258        Ok(self.flags.get_state())
259    }
260
261    pub fn close_internal(&mut self, virtual_file_system: &VirtualFileSystem) -> crate::Result<()> {
262        block_on(virtual_file_system.close(&self.item, &mut self.context))
263    }
264
265    pub fn close(mut self, virtual_file_system: &VirtualFileSystem) -> crate::Result<()> {
266        let result = self.close_internal(virtual_file_system);
267        forget(self);
268
269        result
270    }
271}
272
273impl Drop for SynchronousFile<'_> {
274    fn drop(&mut self) {
275        // Note: We cannot use async in Drop, so we just ignore errors here.
276        let _ = self.close_internal(self.virtual_file_system).map_err(|e| {
277            log::warning!("Failed to close SynchronousFile in Drop: {e}");
278        });
279    }
280}