1use core::convert::TryFrom;
2
3use crate::dir_entry::DirEntryEditor;
4use crate::error::Error;
5use crate::fs::{FileSystem, ReadWriteSeek};
6use crate::io::{IoBase, Read, Seek, SeekFrom, Write};
7use crate::time::{Date, DateTime, TimeProvider};
8
9const MAX_FILE_SIZE: u32 = u32::MAX;
10
11pub struct File<'a, IO: ReadWriteSeek, TP, OCC> {
15 first_cluster: Option<u32>,
17 current_cluster: Option<u32>,
19 offset: u32,
21 entry: Option<DirEntryEditor>,
23 fs: &'a FileSystem<IO, TP, OCC>,
25}
26
27#[derive(Clone, Debug)]
33pub struct Extent {
34 pub offset: u64,
35 pub size: u32,
36}
37
38impl<'a, IO: ReadWriteSeek, TP, OCC> File<'a, IO, TP, OCC> {
39 pub(crate) fn new(
40 first_cluster: Option<u32>,
41 entry: Option<DirEntryEditor>,
42 fs: &'a FileSystem<IO, TP, OCC>,
43 ) -> Self {
44 File {
45 first_cluster,
46 entry,
47 fs,
48 current_cluster: None, offset: 0,
50 }
51 }
52
53 pub fn truncate(&mut self) -> Result<(), Error<IO::Error>> {
63 trace!("File::truncate");
64 if let Some(ref mut e) = self.entry {
65 e.set_size(self.offset);
66 if self.offset == 0 {
67 e.set_first_cluster(None, self.fs.fat_type());
68 }
69 } else {
70 panic!("Trying to truncate a file without an entry");
72 }
73 if let Some(current_cluster) = self.current_cluster {
74 debug_assert!(self.offset > 0);
76 self.fs.truncate_cluster_chain(current_cluster)
77 } else {
78 debug_assert!(self.offset == 0);
79 if let Some(n) = self.first_cluster {
80 self.fs.free_cluster_chain(n)?;
81 self.first_cluster = None;
82 }
83 Ok(())
84 }
85 }
86
87 pub fn extents(&mut self) -> impl Iterator<Item = Result<Extent, Error<IO::Error>>> + 'a {
92 let fs = self.fs;
93 let cluster_size = fs.cluster_size();
94 let Some(mut bytes_left) = self.size() else {
95 return None.into_iter().flatten();
96 };
97 let Some(first) = self.first_cluster else {
98 return None.into_iter().flatten();
99 };
100
101 Some(
102 core::iter::once(Ok(first))
103 .chain(fs.cluster_iter(first))
104 .map(move |cluster_err| match cluster_err {
105 Ok(cluster) => {
106 let size = cluster_size.min(bytes_left);
107 bytes_left -= size;
108 Ok(Extent {
109 offset: fs.offset_from_cluster(cluster),
110 size,
111 })
112 }
113 Err(e) => Err(e),
114 }),
115 )
116 .into_iter()
117 .flatten()
118 }
119
120 pub(crate) fn abs_pos(&self) -> Option<u64> {
121 match self.current_cluster {
124 Some(n) => {
125 let cluster_size = self.fs.cluster_size();
126 let offset_mod_cluster_size = self.offset % cluster_size;
127 let offset_in_cluster = if offset_mod_cluster_size == 0 {
128 cluster_size
131 } else {
132 offset_mod_cluster_size
133 };
134 let offset_in_fs = self.fs.offset_from_cluster(n) + u64::from(offset_in_cluster);
135 Some(offset_in_fs)
136 }
137 None => None,
138 }
139 }
140
141 fn flush_dir_entry(&mut self) -> Result<(), Error<IO::Error>> {
142 if let Some(ref mut e) = self.entry {
143 e.flush(self.fs)?;
144 }
145 Ok(())
146 }
147
148 #[deprecated]
152 pub fn set_created(&mut self, date_time: DateTime) {
153 if let Some(ref mut e) = self.entry {
154 e.set_created(date_time);
155 }
156 }
157
158 #[deprecated]
162 pub fn set_accessed(&mut self, date: Date) {
163 if let Some(ref mut e) = self.entry {
164 e.set_accessed(date);
165 }
166 }
167
168 #[deprecated]
172 pub fn set_modified(&mut self, date_time: DateTime) {
173 if let Some(ref mut e) = self.entry {
174 e.set_modified(date_time);
175 }
176 }
177
178 pub fn accessed(&self) -> Date {
180 match self.entry {
181 Some(ref e) => e.inner().accessed(),
182 None => Date::decode(0),
183 }
184 }
185
186 pub fn created(&self) -> DateTime {
188 match self.entry {
189 Some(ref e) => e.inner().created(),
190 None => DateTime::decode(0, 0, 0),
191 }
192 }
193
194 pub fn modified(&self) -> DateTime {
196 match self.entry {
197 Some(ref e) => e.inner().modified(),
198 None => DateTime::decode(0, 0, 0),
199 }
200 }
201
202 pub fn size(&self) -> Option<u32> {
203 match self.entry {
204 Some(ref e) => e.inner().size(),
205 None => None,
206 }
207 }
208
209 fn is_dir(&self) -> bool {
210 match self.entry {
211 Some(ref e) => e.inner().is_dir(),
212 None => true, }
214 }
215
216 fn bytes_left_in_file(&self) -> Option<usize> {
217 self.size().map(|s| (s - self.offset) as usize)
219 }
220
221 fn set_first_cluster(&mut self, cluster: u32) {
222 self.first_cluster = Some(cluster);
223 if let Some(ref mut e) = self.entry {
224 e.set_first_cluster(self.first_cluster, self.fs.fat_type());
225 }
226 }
227
228 pub(crate) fn first_cluster(&self) -> Option<u32> {
229 self.first_cluster
230 }
231
232 fn flush(&mut self) -> Result<(), Error<IO::Error>> {
233 self.flush_dir_entry()?;
234 let mut disk = self.fs.disk.borrow_mut();
235 disk.flush()?;
236 Ok(())
237 }
238
239 pub(crate) fn is_root_dir(&self) -> bool {
240 self.entry.is_none()
241 }
242}
243
244impl<IO: ReadWriteSeek, TP: TimeProvider, OCC> File<'_, IO, TP, OCC> {
245 fn update_dir_entry_after_write(&mut self) {
246 let offset = self.offset;
247 if let Some(ref mut e) = self.entry {
248 let now = self.fs.options.time_provider.get_current_date_time();
249 e.set_modified(now);
250 if e.inner().size().map_or(false, |s| offset > s) {
251 e.set_size(offset);
252 }
253 }
254 }
255}
256
257impl<IO: ReadWriteSeek, TP, OCC> Drop for File<'_, IO, TP, OCC> {
258 fn drop(&mut self) {
259 if let Err(err) = self.flush() {
260 error!("flush failed {:?}", err);
261 }
262 }
263}
264
265impl<IO: ReadWriteSeek, TP, OCC> Clone for File<'_, IO, TP, OCC> {
267 fn clone(&self) -> Self {
268 File {
269 first_cluster: self.first_cluster,
270 current_cluster: self.current_cluster,
271 offset: self.offset,
272 entry: self.entry.clone(),
273 fs: self.fs,
274 }
275 }
276}
277
278impl<IO: ReadWriteSeek, TP, OCC> IoBase for File<'_, IO, TP, OCC> {
279 type Error = Error<IO::Error>;
280}
281
282impl<IO: ReadWriteSeek, TP: TimeProvider, OCC> Read for File<'_, IO, TP, OCC> {
283 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
284 trace!("File::read");
285 let cluster_size = self.fs.cluster_size();
286 let current_cluster_opt = if self.offset % cluster_size == 0 {
287 match self.current_cluster {
289 None => self.first_cluster,
290 Some(n) => {
291 let r = self.fs.cluster_iter(n).next();
292 match r {
293 Some(Err(err)) => return Err(err),
294 Some(Ok(n)) => Some(n),
295 None => None,
296 }
297 }
298 }
299 } else {
300 self.current_cluster
301 };
302 let Some(current_cluster) = current_cluster_opt else {
303 return Ok(0);
304 };
305 let offset_in_cluster = self.offset % cluster_size;
306 let bytes_left_in_cluster = (cluster_size - offset_in_cluster) as usize;
307 let bytes_left_in_file = self.bytes_left_in_file().unwrap_or(bytes_left_in_cluster);
308 let read_size = buf.len().min(bytes_left_in_cluster).min(bytes_left_in_file);
309 if read_size == 0 {
310 return Ok(0);
311 }
312 trace!("read {} bytes in cluster {}", read_size, current_cluster);
313 let offset_in_fs = self.fs.offset_from_cluster(current_cluster) + u64::from(offset_in_cluster);
314 let read_bytes = {
315 let mut disk = self.fs.disk.borrow_mut();
316 disk.seek(SeekFrom::Start(offset_in_fs))?;
317 disk.read(&mut buf[..read_size])?
318 };
319 if read_bytes == 0 {
320 return Ok(0);
321 }
322 self.offset += read_bytes as u32;
323 self.current_cluster = Some(current_cluster);
324
325 if let Some(ref mut e) = self.entry {
326 if self.fs.options.update_accessed_date {
327 let now = self.fs.options.time_provider.get_current_date();
328 e.set_accessed(now);
329 }
330 }
331 Ok(read_bytes)
332 }
333}
334
335#[cfg(feature = "std")]
336impl<IO: ReadWriteSeek, TP: TimeProvider, OCC> std::io::Read for File<'_, IO, TP, OCC>
337where
338 std::io::Error: From<Error<IO::Error>>,
339{
340 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
341 Ok(Read::read(self, buf)?)
342 }
343}
344
345impl<IO: ReadWriteSeek, TP: TimeProvider, OCC> Write for File<'_, IO, TP, OCC> {
346 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
347 trace!("File::write");
348 let cluster_size = self.fs.cluster_size();
349 let offset_in_cluster = self.offset % cluster_size;
350 let bytes_left_in_cluster = (cluster_size - offset_in_cluster) as usize;
351 let bytes_left_until_max_file_size = (MAX_FILE_SIZE - self.offset) as usize;
352 let write_size = buf.len().min(bytes_left_in_cluster).min(bytes_left_until_max_file_size);
353 if write_size == 0 {
355 return Ok(0);
356 }
357 self.fs.set_dirty_flag(true)?;
359 let current_cluster = if self.offset % cluster_size == 0 {
361 let next_cluster = match self.current_cluster {
363 None => self.first_cluster,
364 Some(n) => {
365 let r = self.fs.cluster_iter(n).next();
366 match r {
367 Some(Err(err)) => return Err(err),
368 Some(Ok(n)) => Some(n),
369 None => None,
370 }
371 }
372 };
373 if let Some(n) = next_cluster {
374 n
375 } else {
376 let new_cluster = self.fs.alloc_cluster(self.current_cluster, self.is_dir())?;
378 trace!("allocated cluster {}", new_cluster);
379 if self.first_cluster.is_none() {
380 self.set_first_cluster(new_cluster);
381 }
382 new_cluster
383 }
384 } else {
385 match self.current_cluster {
387 Some(n) => n,
388 None => panic!("Offset inside cluster but no cluster allocated"),
389 }
390 };
391 trace!("write {} bytes in cluster {}", write_size, current_cluster);
392 let offset_in_fs = self.fs.offset_from_cluster(current_cluster) + u64::from(offset_in_cluster);
393 let written_bytes = {
394 let mut disk = self.fs.disk.borrow_mut();
395 disk.seek(SeekFrom::Start(offset_in_fs))?;
396 disk.write(&buf[..write_size])?
397 };
398 if written_bytes == 0 {
399 return Ok(0);
400 }
401 self.offset += written_bytes as u32;
403 self.current_cluster = Some(current_cluster);
404 self.update_dir_entry_after_write();
405 Ok(written_bytes)
406 }
407
408 fn flush(&mut self) -> Result<(), Self::Error> {
409 Self::flush(self)
410 }
411}
412
413#[cfg(feature = "std")]
414impl<IO: ReadWriteSeek, TP: TimeProvider, OCC> std::io::Write for File<'_, IO, TP, OCC>
415where
416 std::io::Error: From<Error<IO::Error>>,
417{
418 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
419 Ok(Write::write(self, buf)?)
420 }
421
422 fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
423 Ok(Write::write_all(self, buf)?)
424 }
425
426 fn flush(&mut self) -> std::io::Result<()> {
427 Ok(Write::flush(self)?)
428 }
429}
430
431impl<IO: ReadWriteSeek, TP, OCC> Seek for File<'_, IO, TP, OCC> {
432 fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error> {
433 trace!("File::seek");
434 let size_opt = self.size();
435 let new_offset_opt: Option<u32> = match pos {
436 SeekFrom::Current(x) => i64::from(self.offset)
437 .checked_add(x)
438 .and_then(|n| u32::try_from(n).ok()),
439 SeekFrom::Start(x) => u32::try_from(x).ok(),
440 SeekFrom::End(o) => size_opt
441 .and_then(|s| i64::from(s).checked_add(o))
442 .and_then(|n| u32::try_from(n).ok()),
443 };
444 let Some(mut new_offset) = new_offset_opt else {
445 error!("Invalid seek offset");
446 return Err(Error::InvalidInput);
447 };
448 if let Some(size) = size_opt {
449 if new_offset > size {
450 warn!("Seek beyond the end of the file");
451 new_offset = size;
452 }
453 }
454 trace!("file seek {} -> {} - entry {:?}", self.offset, new_offset, self.entry);
455 if new_offset == self.offset {
456 return Ok(u64::from(self.offset));
458 }
459 let new_offset_in_clusters = self.fs.clusters_from_bytes(u64::from(new_offset));
460 let old_offset_in_clusters = self.fs.clusters_from_bytes(u64::from(self.offset));
461 let new_cluster = if new_offset == 0 {
462 None
463 } else if new_offset_in_clusters == old_offset_in_clusters {
464 self.current_cluster
465 } else if let Some(first_cluster) = self.first_cluster {
466 debug_assert!(new_offset_in_clusters > 0);
470 let clusters_to_skip = new_offset_in_clusters - 1;
471 let mut cluster = first_cluster;
472 let mut iter = self.fs.cluster_iter(first_cluster);
473 for i in 0..clusters_to_skip {
474 cluster = if let Some(r) = iter.next() {
475 r?
476 } else {
477 new_offset = self.fs.bytes_from_clusters(i + 1) as u32;
479 break;
480 };
481 }
482 Some(cluster)
483 } else {
484 new_offset = 0;
486 None
487 };
488 self.offset = new_offset;
489 self.current_cluster = new_cluster;
490 Ok(u64::from(self.offset))
491 }
492}
493
494#[cfg(feature = "std")]
495impl<IO: ReadWriteSeek, TP: TimeProvider, OCC> std::io::Seek for File<'_, IO, TP, OCC>
496where
497 std::io::Error: From<Error<IO::Error>>,
498{
499 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
500 Ok(Seek::seek(self, pos.into())?)
501 }
502}