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