1use crate::core;
2use crate::core::cmp;
3use crate::io;
4use crate::io::prelude::*;
5use crate::io::{ErrorKind, SeekFrom};
6
7use crate::dir_entry::DirEntryEditor;
8use crate::error::FatfsError;
9use crate::fs::{FileSystem, ReadWriteSeek};
10use crate::time::{Date, DateTime, TimeProvider};
11
12pub const MAX_FILE_SIZE: u32 = core::u32::MAX;
13
14pub struct File<'a, IO: ReadWriteSeek, TP, OCC> {
18 first_cluster: Option<u32>,
20 current_cluster: Option<u32>,
22 offset: u32,
24 entry: Option<DirEntryEditor>,
26 fs: &'a FileSystem<IO, TP, OCC>,
28}
29
30impl<'a, IO: ReadWriteSeek, TP, OCC> File<'a, IO, TP, OCC> {
31 pub(crate) fn new(
32 first_cluster: Option<u32>,
33 entry: Option<DirEntryEditor>,
34 fs: &'a FileSystem<IO, TP, OCC>,
35 ) -> Self {
36 File {
37 first_cluster,
38 entry,
39 fs,
40 current_cluster: None, offset: 0,
42 }
43 }
44
45 pub fn truncate(&mut self) -> io::Result<()> {
47 if let Some(ref mut e) = self.entry {
48 e.set_size(self.offset);
49 if self.offset == 0 {
50 e.set_first_cluster(None, self.fs.fat_type());
51 }
52 }
53 if self.offset > 0 {
54 debug_assert!(self.current_cluster.is_some());
55 self.fs.truncate_cluster_chain(self.current_cluster.unwrap()) } else {
58 debug_assert!(self.current_cluster.is_none());
59 if let Some(n) = self.first_cluster {
60 self.fs.free_cluster_chain(n)?;
61 self.first_cluster = None;
62 }
63 Ok(())
64 }
65 }
66
67 pub(crate) fn abs_pos(&self) -> Result<Option<u64>, FatfsError> {
68 Ok(match self.current_cluster {
71 Some(n) => {
72 assert!(self.offset > 0); let cluster_size = self.fs.cluster_size();
74 let offset_in_cluster = (self.offset - 1) % cluster_size + 1;
77 let offset_in_fs = self.fs.offset_from_cluster(n)? + (offset_in_cluster as u64);
78 Some(offset_in_fs)
79 }
80 None => None,
81 })
82 }
83
84 pub fn flush_dir_entry(&mut self) -> io::Result<()> {
85 if let Some(ref mut e) = self.entry {
86 e.flush(self.fs)?;
87 }
88 Ok(())
89 }
90
91 #[deprecated]
96 pub fn set_created(&mut self, date_time: DateTime) {
97 if let Some(ref mut e) = self.entry {
98 e.set_created(date_time);
99 }
100 }
101
102 #[deprecated]
107 pub fn set_accessed(&mut self, date: Date) {
108 if let Some(ref mut e) = self.entry {
109 e.set_accessed(date);
110 }
111 }
112
113 #[deprecated]
118 pub fn set_modified(&mut self, date_time: DateTime) {
119 if let Some(ref mut e) = self.entry {
120 e.set_modified(date_time);
121 }
122 }
123
124 pub fn len(&self) -> u32 {
126 match self.entry {
127 Some(ref e) => e.inner().size().unwrap_or(0),
128 None => 0,
129 }
130 }
131
132 pub fn accessed(&self) -> Date {
134 match self.entry {
135 Some(ref e) => e.inner().accessed(),
136 None => Date::epoch(),
137 }
138 }
139
140 pub fn created(&self) -> DateTime {
142 match self.entry {
143 Some(ref e) => e.inner().created(),
144 None => DateTime::epoch(),
145 }
146 }
147
148 pub fn modified(&self) -> DateTime {
150 match self.entry {
151 Some(ref e) => e.inner().modified(),
152 None => DateTime::epoch(),
153 }
154 }
155
156 pub(crate) fn mark_deleted(&mut self) {
159 if let Some(ref mut e) = self.entry {
160 e.mark_deleted();
161 }
162 }
163
164 pub(crate) fn mark_deleted_and_purged(&mut self) {
167 if let Some(ref mut e) = self.entry {
168 e.mark_deleted();
169 self.first_cluster.take();
170 }
171 }
172
173 pub(crate) fn is_deleted(&self) -> bool {
175 if let Some(ref e) = self.entry {
176 e.inner().is_deleted()
177 } else {
178 false
179 }
180 }
181
182 pub fn purge(mut self) -> io::Result<()> {
184 let entry = match self.entry {
185 Some(ref e) => e,
186 None => {
187 return Err(io::Error::new(
188 ErrorKind::InvalidInput,
189 "Can't delete file with no dirent",
190 ))
191 }
192 };
193
194 if !entry.inner().is_deleted() {
195 return Err(io::Error::new(ErrorKind::InvalidInput, "Must call remove_dirent() first"));
196 }
197
198 if let Some(cluster) = self.first_cluster.take() {
199 self.fs.free_cluster_chain(cluster)?;
200 }
201
202 Ok(())
203 }
204
205 pub(crate) fn editor_mut(&mut self) -> Option<&mut DirEntryEditor> {
206 self.entry.as_mut()
207 }
208
209 pub(crate) fn editor(&self) -> Option<&DirEntryEditor> {
210 self.entry.as_ref()
211 }
212
213 fn size(&self) -> Option<u32> {
214 match self.entry {
215 Some(ref e) => e.inner().size(),
216 None => None,
217 }
218 }
219
220 fn is_dir(&self) -> bool {
221 match self.entry {
222 Some(ref e) => e.inner().is_dir(),
223 None => true, }
225 }
226
227 fn bytes_left_in_file(&self) -> Option<usize> {
228 self.size().map(|s| (s - self.offset) as usize)
230 }
231
232 fn set_first_cluster(&mut self, cluster: u32) {
233 self.first_cluster = Some(cluster);
234 if let Some(ref mut e) = self.entry {
235 e.set_first_cluster(self.first_cluster, self.fs.fat_type());
236 }
237 }
238
239 pub(crate) fn first_cluster(&self) -> Option<u32> {
240 self.first_cluster
241 }
242
243 fn flush(&mut self) -> io::Result<()> {
244 self.flush_dir_entry()?;
245 let mut disk = self.fs.disk.borrow_mut();
246 disk.flush()
247 }
248}
249
250impl<IO: ReadWriteSeek, TP: TimeProvider, OCC> File<'_, IO, TP, OCC> {
251 fn update_dir_entry_after_write(&mut self) {
252 let offset = self.offset;
253 if let Some(ref mut e) = self.entry {
254 let now = self.fs.options.time_provider.get_current_date_time();
255 e.set_modified(now);
256 if e.inner().size().map_or(false, |s| offset > s) {
257 e.set_size(offset);
258 }
259 }
260 }
261}
262
263impl<IO: ReadWriteSeek, TP, OCC> Drop for File<'_, IO, TP, OCC> {
264 fn drop(&mut self) {
265 if let Err(err) = self.flush() {
266 error!("flush failed {}", err);
267 }
268
269 if let Some(ref entry) = self.entry {
271 if entry.inner().is_deleted() {
272 if let Some(cluster) = self.first_cluster.take() {
273 let _ = self
274 .fs
275 .free_cluster_chain(cluster)
276 .map_err(|e| error!("free_cluster_chain failed {}", e));
277 }
278 }
279 }
280 }
281}
282
283impl<IO: ReadWriteSeek, TP: TimeProvider, OCC> Read for File<'_, IO, TP, OCC> {
284 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
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 current_cluster = match current_cluster_opt {
303 Some(n) => n,
304 None => return Ok(0),
305 };
306 let offset_in_cluster = self.offset % cluster_size;
307 let bytes_left_in_cluster = (cluster_size - offset_in_cluster) as usize;
308 let bytes_left_in_file = self.bytes_left_in_file().unwrap_or(bytes_left_in_cluster);
309 let read_size = cmp::min(cmp::min(buf.len(), bytes_left_in_cluster), bytes_left_in_file);
310 if read_size == 0 {
311 return Ok(0);
312 }
313 trace!("read {} bytes in cluster {}", read_size, current_cluster);
314 let offset_in_fs =
315 self.fs.offset_from_cluster(current_cluster)? + (offset_in_cluster as u64);
316 let read_bytes = {
317 let mut disk = self.fs.disk.borrow_mut();
318 disk.seek(SeekFrom::Start(offset_in_fs))?;
319 disk.read(&mut buf[..read_size])?
320 };
321 if read_bytes == 0 {
322 return Ok(0);
323 }
324 self.offset += read_bytes as u32;
325 self.current_cluster = Some(current_cluster);
326
327 if let Some(ref mut e) = self.entry {
328 if self.fs.options.update_accessed_date {
329 let now = self.fs.options.time_provider.get_current_date();
330 e.set_accessed(now);
331 }
332 }
333 Ok(read_bytes)
334 }
335}
336
337impl<IO: ReadWriteSeek, TP: TimeProvider, OCC> Write for File<'_, IO, TP, OCC> {
338 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
339 let cluster_size = self.fs.cluster_size();
340 let offset_in_cluster = self.offset % cluster_size;
341 let bytes_left_in_cluster = (cluster_size - offset_in_cluster) as usize;
342 let bytes_left_until_max_file_size = (MAX_FILE_SIZE - self.offset) as usize;
343 let write_size = cmp::min(buf.len(), bytes_left_in_cluster);
344 let write_size = cmp::min(write_size, bytes_left_until_max_file_size);
345 if write_size == 0 {
347 return Ok(0);
348 }
349 self.fs.set_dirty_flag(true)?;
351 let current_cluster = if self.offset % cluster_size == 0 {
353 let next_cluster = match self.current_cluster {
355 None => self.first_cluster,
356 Some(n) => {
357 let r = self.fs.cluster_iter(n).next();
358 match r {
359 Some(Err(err)) => return Err(err),
360 Some(Ok(n)) => Some(n),
361 None => None,
362 }
363 }
364 };
365 match next_cluster {
366 Some(n) => n,
367 None => {
368 let new_cluster = self.fs.alloc_cluster(self.current_cluster, self.is_dir())?;
370 trace!("allocated cluser {}", new_cluster);
371 if self.first_cluster.is_none() {
372 self.set_first_cluster(new_cluster);
373 }
374 new_cluster
375 }
376 }
377 } else {
378 match self.current_cluster {
380 Some(n) => n,
381 None => panic!("Offset inside cluster but no cluster allocated"),
382 }
383 };
384 trace!("write {} bytes in cluster {}", write_size, current_cluster);
385 let offset_in_fs =
386 self.fs.offset_from_cluster(current_cluster)? + (offset_in_cluster as u64);
387 let written_bytes = {
388 let mut disk = self.fs.disk.borrow_mut();
389 disk.seek(SeekFrom::Start(offset_in_fs))?;
390 disk.write(&buf[..write_size])?
391 };
392 if written_bytes == 0 {
393 return Ok(0);
394 }
395 self.offset += written_bytes as u32;
397 self.current_cluster = Some(current_cluster);
398 self.update_dir_entry_after_write();
399 Ok(written_bytes)
400 }
401
402 fn flush(&mut self) -> io::Result<()> {
403 Self::flush(self)
404 }
405}
406
407impl<IO: ReadWriteSeek, TP, OCC> Seek for File<'_, IO, TP, OCC> {
408 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
409 let mut new_pos = match pos {
410 SeekFrom::Current(x) => self.offset as i64 + x,
411 SeekFrom::Start(x) => x as i64,
412 SeekFrom::End(x) => {
413 let size = self.size().expect("cannot seek from end if size is unknown") as i64;
414 size + x
415 }
416 };
417 if new_pos < 0 {
418 return Err(io::Error::new(ErrorKind::InvalidInput, "Seek to a negative offset"));
419 }
420 if let Some(s) = self.size() {
421 if new_pos > s as i64 {
422 trace!("seek beyond end of file");
423 new_pos = s as i64;
424 }
425 }
426 let mut new_pos = new_pos as u32;
427 trace!("file seek {} -> {} - entry {:?}", self.offset, new_pos, self.entry);
428 if new_pos == self.offset {
429 return Ok(self.offset as u64);
431 }
432 let cluster_count = (self.fs.clusters_from_bytes(new_pos as u64) as i32 - 1) as isize;
434 let old_cluster_count =
435 (self.fs.clusters_from_bytes(self.offset as u64) as i32 - 1) as isize;
436 let new_cluster = if new_pos == 0 {
437 None
438 } else if cluster_count == old_cluster_count {
439 self.current_cluster
440 } else {
441 match self.first_cluster {
442 Some(n) => {
443 let mut cluster = n;
444 let mut iter = self.fs.cluster_iter(n);
445 for i in 0..cluster_count {
446 cluster = match iter.next() {
447 Some(r) => r?,
448 None => {
449 new_pos = self.fs.bytes_from_clusters((i + 1) as u32)? as u32;
451 break;
452 }
453 };
454 }
455 Some(cluster)
456 }
457 None => {
458 new_pos = 0;
460 None
461 }
462 }
463 };
464 self.offset = new_pos as u32;
465 self.current_cluster = new_cluster;
466 Ok(self.offset as u64)
467 }
468}