1use crate::{
2 filesystem::{ClusterId, DirEntry, SearchId},
3 Error, RawVolume, VolumeManager,
4};
5
6#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
23#[derive(Debug, Copy, Clone, PartialEq, Eq)]
24pub struct RawFile(pub(crate) SearchId);
25
26impl RawFile {
27 pub fn to_file<D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize>(
29 self,
30 volume_mgr: &mut VolumeManager<D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>,
31 ) -> File<D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>
32 where
33 D: crate::BlockDevice,
34 T: crate::TimeSource,
35 {
36 File::new(self, volume_mgr)
37 }
38}
39
40pub struct File<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize>
49where
50 D: crate::BlockDevice,
51 T: crate::TimeSource,
52{
53 raw_file: RawFile,
54 volume_mgr: &'a mut VolumeManager<D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>,
55}
56
57impl<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize>
58 File<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>
59where
60 D: crate::BlockDevice,
61 T: crate::TimeSource,
62{
63 pub fn new(
65 raw_file: RawFile,
66 volume_mgr: &'a mut VolumeManager<D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>,
67 ) -> File<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES> {
68 File {
69 raw_file,
70 volume_mgr,
71 }
72 }
73
74 pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize, crate::Error<D::Error>> {
78 self.volume_mgr.read(self.raw_file, buffer)
79 }
80
81 pub fn write(&mut self, buffer: &[u8]) -> Result<(), crate::Error<D::Error>> {
83 self.volume_mgr.write(self.raw_file, buffer)
84 }
85
86 pub fn is_eof(&self) -> bool {
88 self.volume_mgr
89 .file_eof(self.raw_file)
90 .expect("Corrupt file ID")
91 }
92
93 pub fn seek_from_current(&mut self, offset: i32) -> Result<(), crate::Error<D::Error>> {
95 self.volume_mgr
96 .file_seek_from_current(self.raw_file, offset)
97 }
98
99 pub fn seek_from_start(&mut self, offset: u32) -> Result<(), crate::Error<D::Error>> {
101 self.volume_mgr.file_seek_from_start(self.raw_file, offset)
102 }
103
104 pub fn seek_from_end(&mut self, offset: u32) -> Result<(), crate::Error<D::Error>> {
106 self.volume_mgr.file_seek_from_end(self.raw_file, offset)
107 }
108
109 pub fn length(&self) -> u32 {
111 self.volume_mgr
112 .file_length(self.raw_file)
113 .expect("Corrupt file ID")
114 }
115
116 pub fn offset(&self) -> u32 {
118 self.volume_mgr
119 .file_offset(self.raw_file)
120 .expect("Corrupt file ID")
121 }
122
123 pub fn to_raw_file(self) -> RawFile {
125 let f = self.raw_file;
126 core::mem::forget(self);
127 f
128 }
129
130 pub fn flush(&mut self) -> Result<(), Error<D::Error>> {
132 self.volume_mgr.flush_file(self.raw_file)
133 }
134
135 pub fn close(self) -> Result<(), Error<D::Error>> {
140 let result = self.volume_mgr.close_file(self.raw_file);
141 core::mem::forget(self);
142 result
143 }
144}
145
146impl<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize> Drop
147 for File<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>
148where
149 D: crate::BlockDevice,
150 T: crate::TimeSource,
151{
152 fn drop(&mut self) {
153 _ = self.volume_mgr.close_file(self.raw_file);
154 }
155}
156
157impl<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize>
158 core::fmt::Debug for File<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>
159where
160 D: crate::BlockDevice,
161 T: crate::TimeSource,
162{
163 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
164 write!(f, "File({})", self.raw_file.0 .0)
165 }
166}
167
168#[cfg(feature = "defmt-log")]
169impl<'a, D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize>
170 defmt::Format for File<'a, D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>
171where
172 D: crate::BlockDevice,
173 T: crate::TimeSource,
174{
175 fn format(&self, fmt: defmt::Formatter) {
176 defmt::write!(fmt, "File({})", self.raw_file.0 .0)
177 }
178}
179
180#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
183pub enum FileError {
184 InvalidOffset,
186}
187
188#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
190#[derive(Debug, PartialEq, Eq, Copy, Clone)]
191pub enum Mode {
192 ReadOnly,
194 ReadWriteAppend,
196 ReadWriteTruncate,
198 ReadWriteCreate,
200 ReadWriteCreateOrTruncate,
202 ReadWriteCreateOrAppend,
204}
205
206#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
208#[derive(Debug, Clone)]
209pub(crate) struct FileInfo {
210 pub(crate) file_id: RawFile,
212 pub(crate) volume_id: RawVolume,
214 pub(crate) current_cluster: (u32, ClusterId),
219 pub(crate) current_offset: u32,
221 pub(crate) mode: Mode,
223 pub(crate) entry: DirEntry,
225 pub(crate) dirty: bool,
227}
228
229impl FileInfo {
230 pub fn eof(&self) -> bool {
232 self.current_offset == self.entry.size
233 }
234
235 pub fn length(&self) -> u32 {
237 self.entry.size
238 }
239
240 pub fn seek_from_start(&mut self, offset: u32) -> Result<(), FileError> {
242 if offset > self.entry.size {
243 return Err(FileError::InvalidOffset);
244 }
245 self.current_offset = offset;
246 Ok(())
247 }
248
249 pub fn seek_from_end(&mut self, offset: u32) -> Result<(), FileError> {
251 if offset > self.entry.size {
252 return Err(FileError::InvalidOffset);
253 }
254 self.current_offset = self.entry.size - offset;
255 Ok(())
256 }
257
258 pub fn seek_from_current(&mut self, offset: i32) -> Result<(), FileError> {
260 let new_offset = i64::from(self.current_offset) + i64::from(offset);
261 if new_offset < 0 || new_offset > i64::from(self.entry.size) {
262 return Err(FileError::InvalidOffset);
263 }
264 self.current_offset = new_offset as u32;
265 Ok(())
266 }
267
268 pub fn left(&self) -> u32 {
270 self.entry.size - self.current_offset
271 }
272
273 pub(crate) fn update_length(&mut self, new: u32) {
275 self.entry.size = new;
276 }
277}
278
279