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 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 }
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 let _ = self.close_internal(self.virtual_file_system).map_err(|e| {
277 log::warning!("Failed to close SynchronousFile in Drop: {e}");
278 });
279 }
280}