1use super::*;
2
3use crate::{error::*, path::*, utils};
4
5use core::{
6 cell::{Ref, RefCell},
7 cmp, iter, num, ops,
8};
9
10#[cfg(not(feature = "std"))]
11use alloc::{boxed::Box, string::ToString, vec, vec::Vec};
12
13use ::time;
14use embedded_io::*;
15use time::PrimitiveDateTime;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum FATType {
24 FAT12,
30 FAT16,
35 FAT32,
40 ExFAT,
45}
46
47impl FATType {
48 #[inline]
49 fn bits_per_entry(&self) -> u8 {
51 match self {
52 FATType::FAT12 => 12,
53 FATType::FAT16 => 16,
54 FATType::FAT32 => 32,
56 FATType::ExFAT => 32,
57 }
58 }
59
60 #[inline]
61 fn entry_size(&self) -> u8 {
63 self.bits_per_entry().next_power_of_two() / 8
64 }
65}
66
67const RESERVED_FAT_ENTRIES: FATEntryCount = 2;
69
70#[derive(Debug, Clone, PartialEq)]
71pub(crate) enum FATEntry {
72 Free,
74 Allocated(ClusterIndex),
76 Reserved,
78 Bad,
80 Eof,
82}
83
84impl From<FATEntry> for FATEntryValue {
85 fn from(value: FATEntry) -> Self {
86 Self::from(&value)
87 }
88}
89
90impl From<&FATEntry> for FATEntryValue {
91 fn from(value: &FATEntry) -> Self {
92 match value {
93 FATEntry::Free => FATEntryValue::MIN,
94 FATEntry::Allocated(cluster) => *cluster,
95 FATEntry::Reserved => 0xFFFFFF6,
96 FATEntry::Bad => 0xFFFFFF7,
97 FATEntry::Eof => FATEntryValue::MAX,
98 }
99 }
100}
101
102struct FATEntryProps {
104 fat_sector: SectorIndex,
106 sector_offset: usize,
107}
108
109impl FATEntryProps {
110 pub fn new<S>(n: FATEntryIndex, fs: &FileSystem<S>) -> Self
112 where
113 S: Read + Seek,
114 {
115 let fat_byte_offset: u64 = u64::from(n) * u64::from(fs.fat_type.bits_per_entry()) / 8;
116 let fat_sector = SectorIndex::try_from(
117 u64::from(fs.props.first_fat_sector)
118 + fat_byte_offset / u64::from(fs.props.sector_size),
119 )
120 .expect("this should fit into a u32");
121 let sector_offset: usize =
122 usize::try_from(fat_byte_offset % u64::from(fs.props.sector_size))
123 .expect("this should fit into a usize");
124
125 FATEntryProps {
126 fat_sector,
127 sector_offset,
128 }
129 }
130}
131
132pub(crate) type FATOffset = u8;
134
135struct FATSectorProps {
137 #[allow(unused)]
139 fat_offset: FATOffset,
140 sector_offset: SectorIndex,
142}
143
144impl FATSectorProps {
145 pub fn new<S>(sector: SectorIndex, fs: &FileSystem<S>) -> Option<Self>
147 where
148 S: Read + Seek,
149 {
150 if !fs.sector_belongs_to_FAT(sector) {
151 return None;
152 }
153
154 let sector_offset_from_first_fat = sector - SectorIndex::from(fs.props.first_fat_sector);
155 let fat_offset =
156 FATOffset::try_from(sector_offset_from_first_fat / fs.props.fat_sector_size)
157 .expect("this should fit in a u89");
158 let sector_offset = sector_offset_from_first_fat % fs.props.fat_sector_size;
159
160 Some(FATSectorProps {
161 fat_offset,
162 sector_offset,
163 })
164 }
165
166 #[allow(non_snake_case)]
167 pub fn get_corresponding_FAT_sectors<S>(&self, fs: &FileSystem<S>) -> Box<[SectorIndex]>
168 where
169 S: Read + Seek,
170 {
171 let mut vec = Vec::with_capacity(fs.props.fat_table_count.into());
172
173 for i in 0..fs.props.fat_table_count {
174 vec.push(
175 SectorIndex::from(fs.props.first_fat_sector)
176 + SectorCount::from(i) * fs.props.fat_sector_size
177 + self.sector_offset,
178 )
179 }
180
181 vec.into_boxed_slice()
182 }
183}
184
185#[derive(Debug, Clone)]
186pub(crate) struct DirInfo {
187 pub(crate) path: PathBuf,
188 pub(crate) chain_start: EntryLocationUnit,
189 pub(crate) chain_end: Option<EntryLocation>,
193}
194
195impl DirInfo {
196 pub(crate) fn at_root_dir(boot_record: &BootRecord) -> Self {
197 DirInfo {
198 path: PathBuf::from(path_consts::SEPARATOR_STR),
200 chain_start: match boot_record {
201 BootRecord::Fat(boot_record_fat) => match &boot_record_fat.ebr {
202 Ebr::FAT12_16(_ebr_fat12_16) => EntryLocationUnit::RootDirSector(0),
204 Ebr::FAT32(ebr_fat32, _) => {
205 EntryLocationUnit::DataCluster(ebr_fat32.root_cluster)
206 }
207 },
208 BootRecord::ExFAT(_boot_record_exfat) => todo!(),
209 },
210 chain_end: None,
211 }
212 }
213}
214
215impl<S> iter::FusedIterator for ReadDir<'_, S> where S: Read + Seek {}
216
217pub(crate) trait OffsetConversions {
218 fn sector_size(&self) -> u16;
219 fn cluster_size(&self) -> u32;
220 fn first_data_sector(&self) -> SectorIndex;
221
222 #[inline]
223 fn cluster_to_sector(&self, cluster: ClusterIndex) -> SectorIndex {
224 cluster * ClusterIndex::from(self.sectors_per_cluster())
225 }
226
227 #[inline]
228 fn sectors_per_cluster(&self) -> u8 {
229 (self.cluster_size() / u32::from(self.sector_size()))
230 .try_into()
231 .expect("the SecPerClus field is 1 byte long (u8)")
232 }
233
234 #[inline]
235 fn sector_to_partition_offset(&self, sector: SectorIndex) -> u64 {
236 u64::from(sector) * u64::from(self.sector_size())
237 }
238
239 #[inline]
240 fn data_cluster_to_partition_sector(&self, cluster: ClusterIndex) -> SectorIndex {
241 self.cluster_to_sector(cluster - RESERVED_FAT_ENTRIES) + self.first_data_sector()
242 }
243
244 #[inline]
245 fn partition_sector_to_data_cluster(&self, sector: SectorIndex) -> ClusterIndex {
246 (sector - self.first_data_sector()) / ClusterIndex::from(self.sectors_per_cluster())
247 + RESERVED_FAT_ENTRIES
248 }
249}
250
251impl<S> OffsetConversions for FileSystem<S>
252where
253 S: Read + Seek,
254{
255 #[inline]
256 fn sector_size(&self) -> u16 {
257 self.props.sector_size
258 }
259
260 #[inline]
261 fn cluster_size(&self) -> u32 {
262 self.props.cluster_size
263 }
264
265 #[inline]
266 fn first_data_sector(&self) -> SectorIndex {
267 self.props.first_data_sector
268 }
269
270 #[inline]
271 fn sectors_per_cluster(&self) -> u8 {
272 self.props.sec_per_clus
273 }
274}
275
276#[derive(Debug)]
278pub(crate) struct FSProperties {
279 pub(crate) sector_size: u16,
280 pub(crate) cluster_size: u32,
281 pub(crate) sec_per_clus: u8,
282 pub(crate) total_sectors: SectorCount,
283 pub(crate) total_clusters: ClusterCount,
284 pub(crate) fat_table_count: u8,
286 pub(crate) fat_sector_size: u32,
287 pub(crate) first_fat_sector: u16,
288 pub(crate) first_root_dir_sector: SectorIndex,
289 pub(crate) first_data_sector: SectorIndex,
290}
291
292impl From<&BootRecord> for FSProperties {
293 fn from(value: &BootRecord) -> Self {
294 let sector_size = match value {
295 BootRecord::Fat(boot_record_fat) => boot_record_fat.bpb.bytes_per_sector,
296 BootRecord::ExFAT(boot_record_exfat) => 1 << boot_record_exfat.sector_shift,
297 };
298 let cluster_size = match value {
299 BootRecord::Fat(boot_record_fat) => {
300 u32::from(boot_record_fat.bpb.sectors_per_cluster) * u32::from(sector_size)
301 }
302 BootRecord::ExFAT(boot_record_exfat) => {
303 1 << (boot_record_exfat.sector_shift + boot_record_exfat.cluster_shift)
304 }
305 };
306 let sec_per_clus = match value {
307 BootRecord::Fat(boot_record_fat) => boot_record_fat.bpb.sectors_per_cluster,
308 BootRecord::ExFAT(_boot_record_exfat) => todo!("ExFAT is not yet implemented"),
309 };
310 let total_sectors = match value {
311 BootRecord::Fat(boot_record_fat) => boot_record_fat.total_sectors(),
312 BootRecord::ExFAT(_boot_record_exfat) => todo!("ExFAT is not yet implemented"),
313 };
314 let total_clusters = match value {
315 BootRecord::Fat(boot_record_fat) => boot_record_fat.total_clusters(),
316 BootRecord::ExFAT(_boot_record_exfat) => todo!("ExFAT is not yet implemented"),
317 };
318 let fat_table_count = match value {
319 BootRecord::Fat(boot_record_fat) => boot_record_fat.bpb.table_count,
320 BootRecord::ExFAT(_boot_record_exfat) => todo!("ExFAT is not yet implemented"),
321 };
322 let fat_sector_size = match value {
323 BootRecord::Fat(boot_record_fat) => boot_record_fat.fat_sector_size(),
324 BootRecord::ExFAT(_boot_record_exfat) => todo!("ExFAT not yet implemented"),
325 };
326 let first_fat_sector = match value {
327 BootRecord::Fat(boot_record_fat) => boot_record_fat.first_fat_sector(),
328 BootRecord::ExFAT(_boot_record_exfat) => todo!("ExFAT not yet implemented"),
329 };
330 let first_root_dir_sector = match value {
331 BootRecord::Fat(boot_record_fat) => boot_record_fat.first_root_dir_sector(),
332 BootRecord::ExFAT(_boot_record_exfat) => todo!("ExFAT is not yet implemented"),
333 };
334 let first_data_sector = match value {
335 BootRecord::Fat(boot_record_fat) => boot_record_fat.first_data_sector(),
336 BootRecord::ExFAT(_boot_record_exfat) => todo!("ExFAT is not yet implemented"),
337 };
338
339 FSProperties {
340 sector_size,
341 cluster_size,
342 sec_per_clus,
343 fat_table_count,
344 fat_sector_size,
345 first_fat_sector,
346 total_sectors,
347 total_clusters,
348 first_root_dir_sector,
349 first_data_sector,
350 }
351 }
352}
353
354#[derive(Debug, Clone)]
357pub(crate) struct FileFilter {
358 show_hidden: bool,
359 show_systen: bool,
360}
361
362impl FileFilter {
363 pub(crate) fn filter(&self, item: &RawProperties) -> bool {
364 let is_hidden = item.attributes.contains(RawAttributes::HIDDEN);
365 let is_system = item.attributes.contains(RawAttributes::SYSTEM);
366 let should_filter = !self.show_hidden && is_hidden || !self.show_systen && is_system;
367
368 !should_filter
369 }
370}
371
372#[allow(clippy::derivable_impls)]
373impl Default for FileFilter {
374 fn default() -> Self {
375 FileFilter {
377 show_hidden: false,
378 show_systen: false,
379 }
380 }
381}
382
383type SyncSectorBufferFn<S> = fn(&FileSystem<S>) -> Result<(), <S as ErrorType>::Error>;
384type UnmountFn<S> = fn(&FileSystem<S>) -> FSResult<(), <S as ErrorType>::Error>;
385
386#[derive(Debug)]
388pub struct FileSystem<S>
389where
390 S: Read + Seek,
391{
392 storage: RefCell<S>,
394
395 pub(crate) sector_buffer: RefCell<SectorBuffer>,
397 fsinfo_modified: RefCell<bool>,
398
399 pub(crate) dir_info: RefCell<DirInfo>,
400
401 sync_f: RefCell<Option<SyncSectorBufferFn<S>>>,
402 unmount_f: RefCell<Option<UnmountFn<S>>>,
403
404 pub(crate) options: FSOptions,
405
406 pub(crate) boot_record: RefCell<BootRecord>,
407 fat_type: FATType,
409 pub(crate) props: FSProperties,
410 first_free_cluster: RefCell<ClusterIndex>,
413
414 pub(crate) filter: RefCell<FileFilter>,
415}
416
417impl<S> FileSystem<S>
419where
420 S: Read + Seek,
421{
422 pub fn fat_type(&self) -> FATType {
424 self.fat_type
425 }
426}
427
428impl<S> FileSystem<S>
430where
431 S: Read + Seek,
432{
433 #[inline]
437 pub fn show_hidden(&self, show: bool) {
438 self.filter.borrow_mut().show_hidden = show;
439 }
440
441 #[inline]
445 pub fn show_system(&self, show: bool) {
446 self.filter.borrow_mut().show_systen = show;
447 }
448}
449
450impl<S> FileSystem<S>
452where
453 S: Read + Seek,
454{
455 pub fn new(mut storage: S, options: FSOptions) -> FSResult<Self, S::Error> {
460 use utils::bincode::BINCODE_CONFIG;
461
462 let mut buffer = [0u8; MAX_SECTOR_SIZE];
465
466 let bytes_read = storage.read(&mut buffer)?;
467 let mut stored_sector = 0;
468
469 if bytes_read < MIN_SECTOR_SIZE {
470 return Err(FSError::InternalFSError(InternalFSError::StorageTooSmall));
471 }
472
473 let bpb: BpbFat = bincode::decode_from_slice(&buffer[..BPBFAT_SIZE], BINCODE_CONFIG)
474 .map(|(v, _)| v)
475 .map_err(utils::bincode::map_err_dec)?;
476
477 let ebr = if bpb.table_size_16 == 0 {
478 let ebr_fat32: EBRFAT32 = bincode::decode_from_slice(
479 &buffer[BPBFAT_SIZE..BPBFAT_SIZE + EBR_SIZE],
480 BINCODE_CONFIG,
481 )
482 .map(|(v, _)| v)
483 .map_err(utils::bincode::map_err_dec)?;
484
485 storage.seek(SeekFrom::Start(
486 u64::from(ebr_fat32.fat_info) * u64::from(bpb.bytes_per_sector),
487 ))?;
488 stored_sector = ebr_fat32.fat_info.into();
489 storage.read_exact(&mut buffer[..usize::from(bpb.bytes_per_sector)])?;
490 let fsinfo: FSInfoFAT32 = bincode::decode_from_slice(
491 &buffer[..usize::from(bpb.bytes_per_sector)],
492 BINCODE_CONFIG,
493 )
494 .map(|(v, _)| v)
495 .map_err(utils::bincode::map_err_dec)?;
496
497 if !fsinfo.verify_signature() {
498 log::error!("FAT32 FSInfo has invalid signature(s)");
499 return Err(FSError::InternalFSError(InternalFSError::InvalidFSInfoSig));
500 }
501
502 Ebr::FAT32(ebr_fat32, fsinfo)
503 } else {
504 Ebr::FAT12_16(
505 bincode::decode_from_slice(
506 &buffer[BPBFAT_SIZE..BPBFAT_SIZE + EBR_SIZE],
507 BINCODE_CONFIG,
508 )
509 .map(|(v, _)| v)
510 .map_err(utils::bincode::map_err_dec)?,
511 )
512 };
513
514 let boot_record = BootRecord::Fat(BootRecordFAT { bpb, ebr });
516
517 let fat_type = boot_record.fat_type();
519
520 if fat_type == FATType::ExFAT {
521 log::error!("Filesystem is ExFAT, which is currently unsupported");
522 return Err(FSError::UnsupportedFS);
523 }
524
525 log::info!("The FAT type of the filesystem is {fat_type:?}");
526
527 match &boot_record {
528 BootRecord::Fat(boot_record_fat) => {
529 if boot_record_fat.verify_signature() {
530 log::error!("FAT boot record has invalid signature(s)");
531 return Err(FSError::InternalFSError(InternalFSError::InvalidBPBSig));
532 }
533 }
534 BootRecord::ExFAT(_boot_record_exfat) => todo!("ExFAT not yet implemented"),
535 };
536
537 let props = FSProperties::from(&boot_record);
538
539 let fs = Self {
540 storage: storage.into(),
541 sector_buffer: SectorBuffer::new(
542 Box::from(&buffer[..usize::from(props.sector_size)]),
543 stored_sector,
544 )
545 .into(),
546 fsinfo_modified: false.into(),
547 options,
548 dir_info: DirInfo::at_root_dir(&boot_record).into(),
549 sync_f: None.into(),
550 unmount_f: None.into(),
551 boot_record: boot_record.into(),
552 fat_type,
553 props,
554 first_free_cluster: RESERVED_FAT_ENTRIES.into(),
555 filter: FileFilter::default().into(),
556 };
557
558 if !fs.FAT_tables_are_identical()? {
559 return Err(FSError::InternalFSError(
560 InternalFSError::MismatchingFATTables,
561 ));
562 }
563
564 Ok(fs)
565 }
566}
567
568impl<S> FileSystem<S>
570where
571 S: Read + Seek,
572{
573 pub(crate) fn process_current_dir<'a>(&'a self) -> ReadDirInt<'a, S> {
574 ReadDirInt::new(self, &self.dir_info.borrow().chain_start)
575 }
576
577 fn _go_to_parent_dir(&self) -> FSResult<(), S::Error> {
581 if let Some(parent_path) = self.dir_info.borrow().path.parent() {
582 let parent_pathbuf = parent_path.to_path_buf();
583
584 let mut entries = self.process_current_dir();
585
586 let parent_entry = entries
589 .nth(NONROOT_MIN_DIRENTRIES - 1)
590 .transpose()?
591 .filter(|entry| entry.is_dir && entry.name == path_consts::PARENT_DIR_STR)
592 .ok_or(FSError::InternalFSError(
593 InternalFSError::MalformedEntryChain,
594 ))?;
595
596 self.dir_info.borrow_mut().path = parent_pathbuf;
597 self.dir_info.borrow_mut().chain_start =
598 EntryLocationUnit::DataCluster(parent_entry.data_cluster);
599 self.dir_info.borrow_mut().chain_end = None;
600 } else {
601 self._go_to_root_directory();
602 }
603
604 Ok(())
605 }
606
607 fn _go_to_child_dir(&self, name: &str) -> FSResult<(), S::Error> {
611 let mut entries = self.process_current_dir();
612
613 let child_entry = loop {
614 let entry = entries.next().ok_or(FSError::NotFound)??;
615
616 if entry.name == name {
617 break entry;
618 }
619 };
620
621 if !child_entry.is_dir {
622 return Err(FSError::NotADirectory);
623 }
624
625 self.dir_info.borrow_mut().path.push(&child_entry.name);
626 self.dir_info.borrow_mut().chain_start =
627 EntryLocationUnit::DataCluster(child_entry.data_cluster);
628 self.dir_info.borrow_mut().chain_end = None;
629
630 Ok(())
631 }
632
633 fn _go_to_root_directory(&self) {
634 *self.dir_info.borrow_mut() = DirInfo::at_root_dir(&self.boot_record.borrow());
635 }
636
637 fn _go_up_till_target<P>(&self, target: P) -> FSResult<(), S::Error>
639 where
640 P: AsRef<Path>,
641 {
642 let target = target.as_ref();
643
644 while self.dir_info.borrow().path != target {
645 self._go_to_parent_dir()?;
646 }
647
648 Ok(())
649 }
650
651 fn _go_down_till_target<P>(&self, target: P) -> FSResult<(), S::Error>
653 where
654 P: AsRef<Path>,
655 {
656 let target = target.as_ref();
657
658 let common_path_prefix = find_common_path_prefix(&self.dir_info.borrow().path, target);
659 let common_components = common_path_prefix
660 .normalize()
661 .components()
662 .filter(keep_path_normals)
663 .count();
664
665 for dir_name in target
666 .components()
667 .filter(keep_path_normals)
668 .skip(common_components)
669 {
670 self._go_to_child_dir(dir_name.as_str())?;
671 }
672
673 Ok(())
674 }
675
676 fn _go_to_cached_dir(&self) -> FSResult<(), S::Error> {
679 let dir_chain = self.dir_info.borrow().chain_start;
680 let target_sector = dir_chain.get_entry_sector(self);
681
682 if target_sector != self.sector_buffer.borrow().stored_sector {
683 self.load_nth_sector(target_sector)?;
684 }
685
686 Ok(())
687 }
688
689 pub(crate) fn go_to_dir<P>(&self, target: P) -> FSResult<(), S::Error>
697 where
698 P: AsRef<Path>,
699 {
700 let target = target.as_ref();
701
702 if !target.is_valid() {
703 return Err(FSError::MalformedPath);
704 }
705
706 if self.dir_info.borrow().path == target {
707 self._go_to_cached_dir()?;
710
711 return Ok(());
712 }
713
714 let common_path_prefix = find_common_path_prefix(&self.dir_info.borrow().path, target);
715
716 let distance_from_root = common_path_prefix.ancestors().count() - 1;
718 let distance_from_current_path =
719 (self.dir_info.borrow().path.ancestors().count() - 1) - distance_from_root;
720
721 if distance_from_root <= distance_from_current_path {
722 self._go_to_root_directory();
723
724 self._go_down_till_target(target)?;
725 } else {
726 self._go_up_till_target(common_path_prefix)?;
727
728 self._go_down_till_target(target)?;
729 }
730
731 Ok(())
732 }
733
734 pub(crate) fn next_free_cluster(&self) -> Result<Option<ClusterIndex>, S::Error> {
737 let start_cluster = match *self.boot_record.borrow() {
738 BootRecord::Fat(ref boot_record_fat) => {
739 let mut first_free_cluster = *self.first_free_cluster.borrow();
740
741 if let Ebr::FAT32(_, fsinfo) = &boot_record_fat.ebr {
742 if fsinfo.first_free_cluster != ClusterIndex::MAX
746 && fsinfo.first_free_cluster <= self.props.total_sectors
747 {
748 first_free_cluster =
749 cmp::min(first_free_cluster, fsinfo.first_free_cluster);
750 }
751 }
752
753 first_free_cluster
754 }
755 BootRecord::ExFAT(_) => todo!("ExFAT not yet implemented"),
756 };
757
758 let mut current_cluster = start_cluster;
759
760 while current_cluster < self.props.total_clusters {
761 if self.read_nth_FAT_entry(current_cluster)? == FATEntry::Free {
762 *self.first_free_cluster.borrow_mut() = current_cluster;
763
764 match *self.boot_record.borrow_mut() {
765 BootRecord::Fat(ref mut boot_record_fat) => {
766 if let Ebr::FAT32(_, fsinfo) = &mut boot_record_fat.ebr {
767 fsinfo.first_free_cluster = current_cluster;
768 *self.fsinfo_modified.borrow_mut() = true;
769 }
770 }
771 BootRecord::ExFAT(_) => todo!("ExFAT not yet implemented"),
772 }
773
774 return Ok(Some(current_cluster));
775 }
776 current_cluster += 1;
777 }
778
779 *self.first_free_cluster.borrow_mut() = self.props.total_clusters - 1;
780 Ok(None)
781 }
782
783 pub(crate) fn get_next_cluster(
785 &self,
786 cluster: ClusterIndex,
787 ) -> Result<Option<ClusterIndex>, S::Error> {
788 Ok(match self.read_nth_FAT_entry(cluster)? {
789 FATEntry::Allocated(next_cluster) => Some(next_cluster),
790 _ => None,
792 })
793 }
794
795 #[allow(non_snake_case)]
796 pub(crate) fn FAT_tables_are_identical(&self) -> Result<bool, S::Error> {
798 assert_ne!(
800 self.fat_type,
801 FATType::ExFAT,
802 "this function doesn't work with ExFAT"
803 );
804
805 const MAX_PROBE_SIZE: u32 = 1 << 20;
807
808 let fat_byte_size = match &*self.boot_record.borrow() {
809 BootRecord::Fat(boot_record_fat) => boot_record_fat.fat_sector_size(),
810 BootRecord::ExFAT(_) => unreachable!(),
811 };
812
813 for nth_iteration in 0..fat_byte_size.div_ceil(MAX_PROBE_SIZE) {
814 let mut tables: Vec<Vec<u8>> = Vec::new();
815
816 for i in 0..self.props.fat_table_count {
817 let fat_start = u32::try_from(
818 self.sector_to_partition_offset(self.boot_record.borrow().nth_FAT_table_sector(i)),
819 )
820 .expect("there's no way the FAT is more that 4GBs away from the start of the storage medium");
821 let current_offset = fat_start + nth_iteration * MAX_PROBE_SIZE;
822 let bytes_left = fat_byte_size - nth_iteration * MAX_PROBE_SIZE;
823
824 self.storage
825 .borrow_mut()
826 .seek(SeekFrom::Start(current_offset.into()))?;
827 let mut buf = vec![
828 0_u8;
829 usize::try_from(cmp::min(MAX_PROBE_SIZE, bytes_left))
830 .unwrap_or(usize::MAX)
831 ];
832 self.storage
833 .borrow_mut()
834 .read_exact(buf.as_mut_slice())
835 .map_err(|e| match e {
836 ReadExactError::UnexpectedEof => {
837 panic!("Unexpected EOF while reading FAT table")
838 }
839 ReadExactError::Other(e) => e,
840 })?;
841 tables.push(buf);
842 }
843
844 if !tables.iter().skip(1).all(|buf| buf == &tables[0]) {
846 return Ok(false);
847 }
848 }
849
850 Ok(true)
851 }
852
853 #[allow(non_snake_case)]
854 pub(crate) fn sector_belongs_to_FAT(&self, sector: SectorIndex) -> bool {
855 match &*self.boot_record.borrow() {
856 BootRecord::Fat(boot_record_fat) => (boot_record_fat.first_fat_sector().into()
857 ..boot_record_fat.first_root_dir_sector())
858 .contains(§or),
859 BootRecord::ExFAT(_boot_record_exfat) => todo!("ExFAT not yet implemented"),
860 }
861 }
862
863 pub(crate) fn load_nth_sector(&self, n: SectorIndex) -> Result<Ref<'_, [u8]>, S::Error> {
867 if n >= self.props.total_sectors {
869 panic!(concat!(
870 "seeked past end of device medium. ",
871 "This is most likely an internal error, please report it: ",
872 "https://github.com/Oakchris1955/simple-fatfs/issues"
873 ));
874 }
875
876 let stored_sector = self.sector_buffer.borrow().stored_sector;
878 if n != stored_sector {
879 let sync_sector_option = *self.sync_f.borrow();
881 if let Some(sync_sector_buffer) = sync_sector_option {
882 log::debug!("Syncing sector {stored_sector}");
883
884 sync_sector_buffer(self)?;
885
886 *self.sync_f.borrow_mut() = None;
889 }
890 self.storage
891 .borrow_mut()
892 .seek(SeekFrom::Start(self.sector_to_partition_offset(n)))?;
893 self.storage
894 .borrow_mut()
895 .read_exact(&mut self.sector_buffer.borrow_mut())
896 .map_err(|e| match e {
897 ReadExactError::UnexpectedEof => {
898 panic!("Unexpected EOF while reading sector {n}\n\
899 This is most likely an interal error, please report it: https://github.com/Oakchris1955/simple-fatfs/issues")
900 }
901 ReadExactError::Other(e) => e,
902 })?;
903 self.storage
904 .borrow_mut()
905 .seek(SeekFrom::Current(-i64::from(self.props.sector_size)))?;
906
907 self.sector_buffer.borrow_mut().stored_sector = n;
908 }
909
910 Ok(Ref::map(self.sector_buffer.borrow(), |s| &**s))
911 }
912
913 #[allow(non_snake_case)]
914 pub(crate) fn read_nth_FAT_entry(&self, n: FATEntryIndex) -> Result<FATEntry, S::Error> {
915 let entry_size = self.fat_type.entry_size();
917 let entry_props = FATEntryProps::new(n, self);
918
919 self.load_nth_sector(entry_props.fat_sector)?;
920
921 let mut value_bytes = [0_u8; 4];
922 let bytes_to_read: usize = cmp::min(
923 entry_props.sector_offset + usize::from(entry_size),
924 usize::from(self.sector_size()),
925 ) - entry_props.sector_offset;
926 value_bytes[..bytes_to_read].copy_from_slice(
927 &self.sector_buffer.borrow_mut()
928 [entry_props.sector_offset..entry_props.sector_offset + bytes_to_read],
929 ); if self.fat_type == FATType::FAT12 && bytes_to_read < usize::from(entry_size) {
933 self.load_nth_sector(entry_props.fat_sector + 1)?;
934
935 value_bytes[bytes_to_read..usize::from(entry_size)].copy_from_slice(
936 &self.sector_buffer.borrow_mut()[..(usize::from(entry_size) - bytes_to_read)],
937 );
938 };
939
940 let mut value = FATEntryValue::from_le_bytes(value_bytes);
941 match self.fat_type {
942 FATType::FAT12 => {
944 if n & 1 != 0 {
945 value >>= 4
946 } else {
947 value &= 0xFFF
948 }
949 }
950 FATType::FAT32 => value &= 0x0FFFFFFF,
952 _ => (),
953 }
954
955 Ok(match self.fat_type {
963 FATType::FAT12 => match value {
964 0x000 => FATEntry::Free,
965 0xFF7 => FATEntry::Bad,
966 #[allow(clippy::manual_range_patterns)]
967 0xFF8..=0xFFE | 0xFFF => FATEntry::Eof,
968 _ => {
969 if (0x002..(self.props.total_clusters + 1)).contains(&value) {
970 FATEntry::Allocated(value)
971 } else {
972 FATEntry::Reserved
973 }
974 }
975 },
976 FATType::FAT16 => match value {
977 0x0000 => FATEntry::Free,
978 0xFFF7 => FATEntry::Bad,
979 #[allow(clippy::manual_range_patterns)]
980 0xFFF8..=0xFFFE | 0xFFFF => FATEntry::Eof,
981 _ => {
982 if (0x0002..(self.props.total_clusters + 1)).contains(&value) {
983 FATEntry::Allocated(value)
984 } else {
985 FATEntry::Reserved
986 }
987 }
988 },
989 FATType::FAT32 => match value {
990 0x00000000 => FATEntry::Free,
991 0x0FFFFFF7 => FATEntry::Bad,
992 #[allow(clippy::manual_range_patterns)]
993 0x0FFFFFF8..=0xFFFFFFE | 0x0FFFFFFF => FATEntry::Eof,
994 _ => {
995 if (0x00000002..(self.props.total_clusters + 1)).contains(&value) {
996 FATEntry::Allocated(value)
997 } else {
998 FATEntry::Reserved
999 }
1000 }
1001 },
1002 FATType::ExFAT => todo!("ExFAT not yet implemented"),
1003 })
1004 }
1005}
1006
1007impl<S> FileSystem<S>
1009where
1010 S: Read + Write + Seek,
1011{
1012 #[allow(non_snake_case)]
1013 pub(crate) fn write_nth_FAT_entry(
1014 &self,
1015 n: FATEntryIndex,
1016 entry: FATEntry,
1017 ) -> Result<(), S::Error> {
1018 let entry_size = self.fat_type.entry_size();
1020 let entry_props = FATEntryProps::new(n, self);
1021
1022 let mask = utils::bits::setbits_u32_lo(self.fat_type.bits_per_entry());
1023 let mut value: FATEntryValue = FATEntryValue::from(entry.clone()) & mask;
1024
1025 if self.fat_type == FATType::FAT32 {
1026 value &= 0x0FFFFFFF;
1028 }
1029
1030 match self.fat_type {
1031 FATType::FAT12 => {
1032 let should_shift = n & 1 != 0;
1033 if should_shift {
1034 value <<= 4;
1036 }
1037
1038 self.load_nth_sector(entry_props.fat_sector)?;
1039
1040 let value_bytes = value.to_le_bytes();
1041
1042 let mut first_byte = value_bytes[0];
1043
1044 if should_shift {
1045 let mut old_byte = self.sector_buffer.borrow()[entry_props.sector_offset];
1046 old_byte &= 0x0F;
1048 first_byte |= old_byte;
1050 }
1051
1052 self.sector_buffer.borrow_mut()[entry_props.sector_offset] = first_byte; self.set_modified();
1054
1055 let bytes_left_on_sector: usize = cmp::min(
1056 usize::from(entry_size),
1057 usize::from(self.sector_size()) - entry_props.sector_offset,
1058 );
1059
1060 if bytes_left_on_sector < entry_size.into() {
1061 self.load_nth_sector(entry_props.fat_sector + 1)?;
1063 }
1064
1065 let mut second_byte = value_bytes[1];
1066 let second_byte_index =
1067 (entry_props.sector_offset + 1) % usize::from(self.sector_size());
1068 if !should_shift {
1069 let mut old_byte = self.sector_buffer.borrow()[second_byte_index];
1070 old_byte &= 0xF0;
1072 second_byte |= old_byte;
1074 }
1075
1076 self.sector_buffer.borrow_mut()[second_byte_index] = second_byte; self.set_modified();
1078 }
1079 FATType::FAT16 | FATType::FAT32 => {
1080 self.load_nth_sector(entry_props.fat_sector)?;
1081
1082 let value_bytes = value.to_le_bytes();
1083
1084 self.sector_buffer.borrow_mut()[entry_props.sector_offset
1085 ..entry_props.sector_offset + usize::from(entry_size)]
1086 .copy_from_slice(&value_bytes[..usize::from(entry_size)]); self.set_modified();
1088 }
1089 FATType::ExFAT => todo!("ExFAT not yet implemented"),
1090 };
1091
1092 if entry == FATEntry::Free && n < *self.first_free_cluster.borrow() {
1093 *self.first_free_cluster.borrow_mut() = n;
1094 }
1095
1096 if let BootRecord::Fat(boot_record_fat) = &mut *self.boot_record.borrow_mut() {
1098 if let Ebr::FAT32(_, fsinfo) = &mut boot_record_fat.ebr {
1099 match entry {
1100 FATEntry::Free => {
1101 fsinfo.free_cluster_count += 1;
1102 if n < fsinfo.first_free_cluster {
1103 fsinfo.first_free_cluster = n;
1104 }
1105 }
1106 _ => fsinfo.free_cluster_count -= 1,
1107 };
1108 *self.fsinfo_modified.borrow_mut() = true;
1109 }
1110 }
1111
1112 Ok(())
1113 }
1114
1115 pub(crate) fn allocate_nth_entries(
1120 &self,
1121 n: num::NonZero<EntryCount>,
1122 ) -> FSResult<EntryLocation, S::Error> {
1123 self._go_to_cached_dir()?;
1125
1126 let mut first_entry = self.dir_info.borrow().chain_end.unwrap_or_else(|| {
1129 let stored_sector = self.sector_buffer.borrow().stored_sector;
1130 EntryLocation::from_partition_sector(stored_sector, self)
1131 });
1132
1133 let mut last_entry = first_entry;
1134
1135 let mut chain_len = 0;
1136 let mut entry_count: EntryCount = 0;
1137
1138 loop {
1139 let entry_status = last_entry.entry_status(self)?;
1140 entry_count += 1;
1141 match entry_status {
1142 EntryStatus::Unused | EntryStatus::LastUnused => chain_len += 1,
1143 EntryStatus::Used => chain_len = 0,
1144 }
1145
1146 if chain_len >= n.get() {
1147 return Ok(first_entry);
1148 }
1149
1150 if entry_status == EntryStatus::LastUnused {
1151 break;
1152 }
1153
1154 if last_entry.unit.get_next_unit(self)?.is_none()
1157 && last_entry.index + 1 >= last_entry.unit.get_max_offset(self)
1158 {
1159 break;
1160 }
1161
1162 #[allow(clippy::absurd_extreme_comparisons)]
1164 if entry_count + n.get() >= DIRENTRY_LIMIT {
1165 let new_entry_count = self.defragment_entry_chain()?;
1168
1169 if new_entry_count + n.get() >= DIRENTRY_LIMIT {
1170 return Err(FSError::DirEntryLimitReached);
1171 }
1172
1173 return self.allocate_nth_entries(n);
1176 }
1177
1178 last_entry = last_entry
1179 .next_entry(self)?
1180 .ok_or(FSError::InternalFSError(
1181 InternalFSError::MalformedEntryChain,
1182 ))?;
1183
1184 if entry_status == EntryStatus::Used {
1185 first_entry = last_entry;
1186 }
1187 }
1188
1189 self.dir_info.borrow_mut().chain_end = Some(last_entry);
1191
1192 match last_entry.unit {
1195 EntryLocationUnit::RootDirSector(_) => {
1196 let remaining_sectors: SectorCount = match &*self.boot_record.borrow() {
1197 BootRecord::Fat(boot_record_fat) => {
1198 boot_record_fat.first_root_dir_sector()
1199 + SectorCount::from(boot_record_fat.root_dir_sectors())
1200 - last_entry.unit.get_entry_sector(self)
1201 }
1202 BootRecord::ExFAT(_boot_record_exfat) => todo!("ExFAT not yet implemented"),
1203 };
1204
1205 let entries_per_sector = self.props.sector_size
1206 / u16::try_from(DIRENTRY_SIZE).expect("32 can fit in a u16");
1207 let remaining_entries = EntryCount::try_from(
1208 remaining_sectors * SectorCount::from(entries_per_sector)
1209 + (SectorCount::from(entries_per_sector)
1210 - SectorCount::from(last_entry.index)
1211 + 1),
1212 )
1213 .unwrap();
1214
1215 if remaining_entries < n.get() - chain_len {
1216 Err(FSError::RootDirectoryFull)
1217 } else {
1218 Ok(first_entry)
1219 }
1220 }
1221 EntryLocationUnit::DataCluster(cluster) => {
1222 let entries_per_cluster = u16::try_from(
1224 self.props.cluster_size
1225 / u32::try_from(DIRENTRY_SIZE).expect("32 can fit into u32"),
1226 )
1227 .expect("a cluster can have a max of ~16k entries");
1228
1229 let entries_left = n.get() - chain_len;
1230 let free_entries_on_current_cluster = entries_per_cluster - (last_entry.index + 1);
1231
1232 if free_entries_on_current_cluster < entries_left {
1234 let clusters_to_allocate = (entries_left - free_entries_on_current_cluster)
1235 .div_ceil(entries_per_cluster);
1236
1237 let first_cluster = self.allocate_clusters(
1238 num::NonZero::new(clusters_to_allocate.into())
1239 .expect("this should be at least 1"),
1240 Some(cluster),
1241 )?;
1242
1243 if chain_len == 0 {
1245 first_entry.unit = EntryLocationUnit::DataCluster(first_cluster);
1246 first_entry.index = 0;
1247 }
1248
1249 for cluster in
1251 first_cluster..(first_cluster + ClusterCount::from(clusters_to_allocate))
1252 {
1253 let first_sector = self.data_cluster_to_partition_sector(cluster);
1254
1255 for sector in first_sector
1256 ..(first_sector + SectorCount::from(self.sectors_per_cluster()))
1257 {
1258 self.load_nth_sector(sector)?;
1259 self.sector_buffer.borrow_mut().fill(0);
1260 self.set_modified();
1261 }
1262 }
1263 }
1264
1265 Ok(first_entry)
1266 }
1267 }
1268 }
1269
1270 pub(crate) fn create_entry_chain(
1275 &self,
1276 parent: EntryLocationUnit,
1277 datetime: PrimitiveDateTime,
1278 ) -> FSResult<u32, S::Error> {
1279 let dir_cluster = self.allocate_clusters(num::NonZero::new(1).unwrap(), None)?;
1281
1282 let entries = Box::from([
1283 MinProperties {
1284 name: Box::from(typed_path::constants::windows::CURRENT_DIR_STR),
1285 sfn: CURRENT_DIR_SFN,
1286 attributes: RawAttributes::empty() | RawAttributes::DIRECTORY,
1288 created: Some(datetime),
1289 modified: datetime,
1290 accessed: Some(datetime.date()),
1291 file_size: 0,
1292 data_cluster: dir_cluster,
1293 },
1294 MinProperties {
1295 name: Box::from(typed_path::constants::windows::PARENT_DIR_STR),
1296 sfn: PARENT_DIR_SFN,
1297 attributes: RawAttributes::empty() | RawAttributes::DIRECTORY,
1299 created: Some(datetime),
1300 modified: datetime,
1301 accessed: Some(datetime.date()),
1302 file_size: 0,
1303 data_cluster: match parent {
1304 EntryLocationUnit::DataCluster(cluster) => cluster,
1305 EntryLocationUnit::RootDirSector(_) => 0,
1306 },
1307 },
1308 ]);
1309
1310 let entries_iter = EntryComposer::new(entries, &self.options.codepage);
1312
1313 self.load_nth_sector(self.data_cluster_to_partition_sector(dir_cluster))?;
1314
1315 self.sector_buffer.borrow_mut().fill(0);
1317
1318 let mut entry_location = EntryLocation {
1319 unit: EntryLocationUnit::DataCluster(dir_cluster),
1320 index: 0,
1321 };
1322
1323 for (i, bytes) in entries_iter.enumerate() {
1324 entry_location.set_bytes(self, bytes)?;
1325
1326 if i < NONROOT_MIN_DIRENTRIES {
1327 entry_location = entry_location
1328 .next_entry(self)?
1329 .expect("this will only be called once");
1330 }
1331 }
1332
1333 self.set_modified();
1334
1335 let stored_sector = self.sector_buffer.borrow().stored_sector;
1337 for sector in
1338 (stored_sector + 1)..(stored_sector + SectorCount::from(self.sectors_per_cluster()))
1339 {
1340 self.load_nth_sector(sector)?;
1341 self.sector_buffer.borrow_mut().fill(0);
1342 self.set_modified();
1343 }
1344
1345 Ok(dir_cluster)
1346 }
1347
1348 pub(crate) fn insert_to_entry_chain(
1354 &self,
1355 entries: Box<[MinProperties]>,
1356 ) -> FSResult<DirEntryChain, S::Error> {
1357 let mut entries_needed = 0;
1358
1359 self._go_to_cached_dir()?;
1360
1361 for entry in &entries {
1362 entries_needed += calc_entries_needed(&*entry.name, &self.options.codepage).get();
1363 }
1364
1365 let first_entry = self.allocate_nth_entries(
1366 num::NonZero::new(entries_needed).expect("The entries array shouldn't be empty"),
1367 )?;
1368
1369 let mut entries_iter = EntryComposer::new(entries, &self.options.codepage);
1370
1371 let mut current_entry = first_entry;
1372 let mut entry_bytes = entries_iter
1373 .next()
1374 .expect("this iterator is guaranteed to return at least once");
1375
1376 loop {
1377 current_entry.set_bytes(self, entry_bytes)?;
1378
1379 match entries_iter.next() {
1380 Some(bytes) => entry_bytes = bytes,
1381 None => break,
1382 };
1383
1384 current_entry = current_entry
1385 .next_entry(self)?
1386 .expect("This entry chain should be valid, we just generated it");
1387 }
1388
1389 Ok(DirEntryChain {
1390 len: entries_needed,
1391 location: first_entry,
1392 })
1393 }
1394
1395 pub(crate) fn defragment_entry_chain(&self) -> FSResult<EntryCount, S::Error> {
1399 let mut current_entry_loc = EntryLocation {
1400 unit: self.dir_info.borrow().chain_start,
1401 index: 0,
1402 };
1403 let mut new_chain_end = current_entry_loc;
1404 let mut entry_count: EntryCount = 0;
1405
1406 loop {
1407 match current_entry_loc.entry_status(self)? {
1408 EntryStatus::Used => {
1409 if current_entry_loc != new_chain_end {
1411 let bytes = current_entry_loc.get_bytes(self)?;
1413
1414 new_chain_end.set_bytes(self, bytes)?;
1415
1416 #[allow(clippy::absurd_extreme_comparisons)]
1418 if entry_count >= DIRENTRY_LIMIT {
1419 break;
1420 }
1421
1422 current_entry_loc.free_entry(self, false)?;
1424 }
1425
1426 entry_count += 1;
1427
1428 new_chain_end = new_chain_end
1430 .next_entry(self)?
1431 .expect("we just pushed an entry to this chain")
1432 }
1433 EntryStatus::LastUnused => break,
1434 _ => (),
1435 }
1436
1437 current_entry_loc = match current_entry_loc.next_entry(self)? {
1438 Some(entry) => entry,
1439 None => break,
1440 }
1441 }
1442
1443 new_chain_end.free_entry(self, true)?;
1445
1446 self.dir_info.borrow_mut().chain_end = Some(new_chain_end);
1447
1448 Ok(entry_count)
1449 }
1450
1451 pub(crate) fn remove_entry_chain(&self, chain: &DirEntryChain) -> Result<(), S::Error> {
1455 let mut entries_freed = 0;
1456 let mut current_entry = chain.location;
1457
1458 loop {
1459 current_entry.free_entry(self, false)?;
1460
1461 entries_freed += 1;
1462
1463 if entries_freed >= chain.len {
1464 break;
1465 }
1466
1467 current_entry = match current_entry.next_entry(self)? {
1468 Some(current_entry) => current_entry,
1469 None => unreachable!(
1470 concat!("It is guaranteed that at least as many entries ",
1471 "as there are in chain exist, since we counted them when initializing the struct")
1472 ),
1473 };
1474 }
1475
1476 Ok(())
1477 }
1478
1479 pub(crate) fn free_cluster_chain(&self, first_cluster: u32) -> Result<(), S::Error> {
1481 let mut current_cluster = first_cluster;
1482
1483 loop {
1484 let next_cluster_option = self.get_next_cluster(current_cluster)?;
1485
1486 self.write_nth_FAT_entry(current_cluster, FATEntry::Free)?;
1488
1489 match next_cluster_option {
1491 Some(next_cluster) => current_cluster = next_cluster,
1492 None => break,
1493 }
1494 }
1495
1496 Ok(())
1497 }
1498
1499 pub(crate) fn allocate_clusters(
1504 &self,
1505 n: num::NonZero<ClusterCount>,
1506 first_cluster: Option<ClusterIndex>,
1507 ) -> FSResult<ClusterIndex, S::Error> {
1508 let mut last_cluster_in_chain = first_cluster;
1509 let mut first_allocated_cluster = None;
1510
1511 for i in 0..n.into() {
1512 match self.next_free_cluster()? {
1513 Some(next_free_cluster) => {
1514 if i == 0 {
1520 first_allocated_cluster = Some(next_free_cluster);
1521 }
1522
1523 if let Some(last_cluster_in_chain) = last_cluster_in_chain {
1525 self.write_nth_FAT_entry(
1526 last_cluster_in_chain,
1527 FATEntry::Allocated(next_free_cluster),
1528 )?;
1529 }
1530 self.write_nth_FAT_entry(next_free_cluster, FATEntry::Eof)?;
1532 if let Some(last_cluster_in_chain) = last_cluster_in_chain {
1533 log::trace!(
1534 "cluster {last_cluster_in_chain} now points to {next_free_cluster}"
1535 );
1536 }
1537 last_cluster_in_chain = Some(next_free_cluster);
1539 }
1540 None => {
1541 log::error!("storage medium full while attempting to allocate more clusters");
1542 return Err(FSError::StorageFull);
1543 }
1544 }
1545 }
1546
1547 Ok(first_allocated_cluster.expect("This should have Some value by now"))
1548 }
1549
1550 fn _sync_current_sector(&self) -> Result<(), S::Error> {
1552 self.storage
1553 .borrow_mut()
1554 .write_all(&self.sector_buffer.borrow())?;
1555 self.storage
1556 .borrow_mut()
1557 .seek(SeekFrom::Current(-i64::from(self.props.sector_size)))?;
1558
1559 Ok(())
1560 }
1561
1562 #[allow(non_snake_case)]
1564 fn _sync_FAT_sector(&self, fat_sector_props: &FATSectorProps) -> Result<(), S::Error> {
1565 let current_offset = self.storage.borrow_mut().stream_position()?;
1566
1567 for sector in fat_sector_props.get_corresponding_FAT_sectors(self) {
1568 self.storage.borrow_mut().seek(SeekFrom::Start(u64::from(
1569 sector * u32::from(self.props.sector_size),
1570 )))?;
1571 self.storage
1572 .borrow_mut()
1573 .write_all(&self.sector_buffer.borrow())?;
1574 }
1575
1576 self.storage
1577 .borrow_mut()
1578 .seek(SeekFrom::Start(current_offset))?;
1579
1580 Ok(())
1581 }
1582
1583 pub(crate) fn set_modified(&self) {
1585 *self.sync_f.borrow_mut() = Some(Self::sync_sector_buffer);
1586 *self.unmount_f.borrow_mut() = Some(Self::unmount);
1587 }
1588
1589 pub(crate) fn sync_sector_buffer(&self) -> Result<(), S::Error> {
1590 let stored_sector = self.sector_buffer.borrow().stored_sector;
1592 if let Some(fat_sector_props) = FATSectorProps::new(stored_sector, self) {
1593 log::trace!("syncing FAT sector {}", fat_sector_props.sector_offset,);
1594 match &*self.boot_record.borrow() {
1595 BootRecord::Fat(boot_record_fat) => match &boot_record_fat.ebr {
1596 Ebr::FAT12_16(_) => {
1597 self._sync_FAT_sector(&fat_sector_props)?;
1598 }
1599 Ebr::FAT32(ebr_fat32, _) => {
1600 if ebr_fat32.extended_flags.mirroring_disabled() {
1601 self._sync_current_sector()?;
1602 } else {
1603 self._sync_FAT_sector(&fat_sector_props)?;
1604 }
1605 }
1606 },
1607 BootRecord::ExFAT(_boot_record_exfat) => todo!("ExFAT not yet implemented"),
1608 }
1609 } else {
1610 log::trace!(
1611 "syncing sector {}",
1612 self.sector_buffer.borrow().stored_sector
1613 );
1614 self._sync_current_sector()?;
1615 }
1616
1617 *self.sync_f.borrow_mut() = None;
1619
1620 Ok(())
1621 }
1622
1623 pub(crate) fn sync_fsinfo(&self) -> FSResult<(), S::Error> {
1626 use utils::bincode::BINCODE_CONFIG;
1627
1628 if *self.fsinfo_modified.borrow() {
1629 if let BootRecord::Fat(boot_record_fat) = &*self.boot_record.borrow() {
1630 if let Ebr::FAT32(ebr_fat32, fsinfo) = &boot_record_fat.ebr {
1631 self.load_nth_sector(ebr_fat32.fat_info.into())?;
1632
1633 bincode::encode_into_slice(
1634 fsinfo,
1635 &mut self.sector_buffer.borrow_mut()[..FSINFO_SIZE],
1636 BINCODE_CONFIG,
1637 )
1638 .map_err(utils::bincode::map_err_enc)?;
1639 }
1640 }
1641
1642 *self.fsinfo_modified.borrow_mut() = false;
1643 }
1644
1645 Ok(())
1646 }
1647
1648 fn get_rw_file_unchecked<P: AsRef<Path>>(&self, path: P) -> FSResult<RWFile<'_, S>, S::Error> {
1652 let ro_file = self.get_ro_file(path)?;
1653
1654 Ok(ro_file.into())
1655 }
1656}
1657
1658impl<S> FileSystem<S>
1660where
1661 S: Read + Seek,
1662{
1663 pub fn read_dir<P: AsRef<Path>>(&self, path: P) -> FSResult<ReadDir<'_, S>, S::Error> {
1667 let path = path.as_ref();
1669
1670 if !path.is_valid() {
1671 return Err(FSError::MalformedPath);
1672 }
1673
1674 let path = path.normalize();
1675
1676 self.go_to_dir(&path)?;
1677
1678 Ok(ReadDir::new(
1679 self,
1680 &self.dir_info.borrow().chain_start,
1681 &self.dir_info.borrow().path,
1682 ))
1683 }
1684
1685 pub fn get_ro_file<P: AsRef<Path>>(&self, path: P) -> FSResult<ROFile<'_, S>, S::Error> {
1689 let path = path.as_ref();
1690
1691 if !path.is_valid() {
1692 return Err(FSError::MalformedPath);
1693 }
1694
1695 if let Some(file_name) = path.file_name() {
1696 let parent_dir = self.read_dir(
1697 path.parent()
1698 .expect("we aren't in the root directory, this shouldn't panic"),
1699 )?;
1700
1701 let mut entry = None;
1703
1704 for dir_entry in parent_dir {
1705 let dir_entry = dir_entry?;
1706
1707 if dir_entry
1708 .path()
1709 .file_name()
1710 .is_some_and(|entry_name| entry_name == file_name)
1711 {
1712 entry = Some(dir_entry.entry);
1713
1714 break;
1715 }
1716 }
1717
1718 match entry {
1719 Some(entry) => {
1720 let mut file = ROFile::from_props(
1721 FileProps {
1722 offset: 0,
1723 current_cluster: entry.data_cluster,
1724 entry,
1725 },
1726 self,
1727 );
1728
1729 if file.cluster_chain_is_healthy()? {
1730 Ok(file)
1731 } else {
1732 log::error!("The cluster chain of a file is malformed");
1733 Err(FSError::InternalFSError(
1734 InternalFSError::MalformedClusterChain,
1735 ))
1736 }
1737 }
1738 None => {
1739 log::error!("ROFile {path} not found");
1740
1741 Err(FSError::NotFound)
1742 }
1743 }
1744 } else {
1745 log::error!("Is a directory (not a file)");
1746 Err(FSError::IsADirectory)
1747 }
1748 }
1749}
1750
1751impl<S> FileSystem<S>
1753where
1754 S: Read + Write + Seek,
1755{
1756 #[inline]
1758 pub fn create_file<P: AsRef<Path>>(&self, path: P) -> FSResult<RWFile<'_, S>, S::Error> {
1759 let path = path.as_ref();
1760
1761 if !path.is_valid() {
1762 return Err(FSError::MalformedPath);
1763 }
1764
1765 let target = path.normalize();
1766
1767 let parent_dir = match target.parent() {
1768 Some(parent) => parent,
1769 None => return Err(FSError::IsADirectory),
1771 };
1772
1773 let file_name = target
1774 .file_name()
1775 .expect("the path is normalized and it isn't the root directory either");
1776
1777 self.go_to_dir(parent_dir)?;
1778
1779 for entry in self.process_current_dir() {
1781 let entry = entry?;
1782
1783 if entry.name == file_name {
1784 return Err(FSError::AlreadyExists);
1785 }
1786 }
1787
1788 let file_cluster = self.allocate_clusters(num::NonZero::new(1).expect("1 != 0"), None)?;
1789
1790 let sfn = utils::string::gen_sfn(file_name, self, parent_dir)?;
1791
1792 let now = self.options.clock.now();
1793
1794 let raw_properties = MinProperties {
1796 name: file_name.into(),
1797 sfn,
1798 attributes: RawAttributes::empty() | RawAttributes::ARCHIVE,
1800 created: Some(now),
1801 modified: now,
1802 accessed: Some(now.date()),
1803 file_size: 0,
1804 data_cluster: file_cluster,
1805 };
1806
1807 let entries = [raw_properties.clone()];
1808 let chain = self.insert_to_entry_chain(Box::new(entries))?;
1809
1810 Ok(RWFile::from_props(
1811 FileProps {
1812 current_cluster: raw_properties.data_cluster,
1813 entry: Properties::from_raw(
1814 RawProperties::from_chain(raw_properties, chain),
1815 path.into(),
1816 self.options.codepage,
1817 ),
1818 offset: 0,
1819 },
1820 self,
1821 ))
1822 }
1823
1824 #[inline]
1826 pub fn create_dir<P: AsRef<Path>>(&self, path: P) -> FSResult<(), S::Error> {
1827 let path = path.as_ref();
1828
1829 if !path.is_valid() {
1830 return Err(FSError::MalformedPath);
1831 }
1832
1833 let target = path.normalize();
1834
1835 let parent_dir = match target.parent() {
1836 Some(parent) => parent,
1837 None => return Err(FSError::AlreadyExists),
1839 };
1840
1841 let file_name = target
1842 .file_name()
1843 .expect("the path is normalized and it isn't the root directory either");
1844
1845 for entry in self.process_current_dir() {
1847 let entry = entry?;
1848
1849 if entry.name == file_name {
1850 return Err(FSError::AlreadyExists);
1851 }
1852 }
1853
1854 let now = self.options.clock.now();
1855
1856 let dir_cluster = self.create_entry_chain(self.dir_info.borrow().chain_start, now)?;
1857
1858 let sfn = utils::string::gen_sfn(file_name, self, parent_dir)?;
1862
1863 let raw_properties = MinProperties {
1865 name: file_name.into(),
1866 sfn,
1867 attributes: RawAttributes::empty() | RawAttributes::DIRECTORY,
1868 created: Some(now),
1869 modified: now,
1870 accessed: Some(now.date()),
1871 file_size: 0,
1872 data_cluster: dir_cluster,
1873 };
1874
1875 let entries = [raw_properties];
1876
1877 self.go_to_dir(parent_dir)?;
1878
1879 self.insert_to_entry_chain(Box::new(entries))?;
1880
1881 Ok(())
1882 }
1883
1884 pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(&self, from: P, to: Q) -> FSResult<(), S::Error> {
1886 let from = from.as_ref();
1887 let to = to.as_ref();
1888
1889 if !from.is_valid() || !to.is_valid() {
1890 return Err(FSError::MalformedPath);
1891 }
1892
1893 let from = from.normalize();
1894 let to = to.normalize();
1895
1896 let parent_from = match from.parent() {
1897 Some(parent) => parent,
1898 None => return Err(FSError::PermissionDenied),
1900 };
1901 let parent_to = match to.parent() {
1902 Some(parent) => parent,
1903 None => return Err(FSError::PermissionDenied),
1905 };
1906
1907 let entry_from = {
1908 let mut entry_from = None;
1909
1910 for entry in self.read_dir(parent_from)? {
1911 let entry = entry?;
1912
1913 if *entry.path() == from {
1914 entry_from = Some(entry);
1915
1916 break;
1917 }
1918 }
1919
1920 match entry_from {
1921 Some(entry) => entry,
1922 None => return Err(FSError::NotFound),
1923 }
1924 };
1925
1926 for entry in self.read_dir(parent_to)? {
1927 let entry = entry?;
1928
1929 if *entry.path() == to {
1930 return Err(FSError::AlreadyExists);
1931 }
1932 }
1933
1934 self.go_to_dir(parent_to)?;
1944
1945 let now = self.options.clock.now();
1946
1947 if entry_from.is_dir() {
1948 let parent_entry = MinProperties {
1952 name: Box::from(typed_path::constants::windows::PARENT_DIR_STR),
1953 sfn: PARENT_DIR_SFN,
1954 attributes: RawAttributes::empty() | RawAttributes::DIRECTORY,
1956 created: Some(now),
1957 modified: now,
1958 accessed: Some(now.date()),
1959 file_size: 0,
1960 data_cluster: match self.dir_info.borrow().chain_start {
1961 EntryLocationUnit::DataCluster(cluster) => cluster,
1962 EntryLocationUnit::RootDirSector(_) => 0,
1963 },
1964 };
1965
1966 let entry_location = EntryLocation {
1968 unit: EntryLocationUnit::DataCluster(entry_from.data_cluster),
1969 index: 1,
1970 };
1971
1972 use utils::bincode::BINCODE_CONFIG;
1973
1974 self._go_to_cached_dir()?;
1975 let mut bytes: [u8; DIRENTRY_SIZE] = [0; DIRENTRY_SIZE];
1976
1977 bincode::encode_into_slice(FATDirEntry::from(parent_entry), &mut bytes, BINCODE_CONFIG)
1978 .map_err(utils::bincode::map_err_enc)?;
1979
1980 entry_location.set_bytes(self, bytes)?;
1981 }
1982
1983 let old_chain = entry_from.chain;
1984 let old_props: MinProperties = entry_from.into();
1985 let to_filename = to.file_name().expect("this path is normalized");
1986 let sfn = utils::string::gen_sfn(to_filename, self, parent_to)?;
1987
1988 let props = MinProperties {
1989 name: Box::from(to_filename),
1990 sfn,
1991 attributes: old_props.attributes,
1992 created: Some(now),
1993 modified: now,
1994 accessed: Some(now.date()),
1995 file_size: old_props.file_size,
1996 data_cluster: old_props.data_cluster,
1997 };
1998 self.insert_to_entry_chain(Box::from([props]))?;
1999
2000 self.remove_entry_chain(&old_chain)?;
2001
2002 Ok(())
2003 }
2004
2005 #[inline]
2009 pub fn remove_file<P: AsRef<Path>>(&self, path: P) -> FSResult<(), S::Error> {
2010 self.get_rw_file(path)?.remove()?;
2011
2012 Ok(())
2013 }
2014
2015 #[inline]
2019 pub fn remove_file_unchecked<P: AsRef<Path>>(&self, path: P) -> FSResult<(), S::Error> {
2020 self.get_rw_file_unchecked(path)?.remove()?;
2021
2022 Ok(())
2023 }
2024
2025 pub fn remove_empty_dir<P: AsRef<Path>>(&self, path: P) -> FSResult<(), S::Error> {
2029 let path = path.as_ref();
2030
2031 if !path.is_valid() {
2032 return Err(FSError::MalformedPath);
2033 }
2034
2035 if path
2036 .components()
2037 .next_back()
2038 .expect("this iterator will always yield at least the root directory")
2039 == WindowsComponent::root()
2040 {
2041 return Err(FSError::InvalidInput);
2043 }
2044
2045 if self.read_dir(path)?.next().is_some() {
2046 return Err(FSError::DirectoryNotEmpty);
2047 }
2048
2049 let parent_path = path
2050 .parent()
2051 .expect("we aren't in the root directory, this shouldn't panic");
2052
2053 let parent_dir_entries = self.read_dir(parent_path)?;
2054
2055 let entry = {
2056 let mut entry = None;
2057
2058 for ent in parent_dir_entries {
2059 let ent = ent?;
2060
2061 if ent.path() == path {
2062 entry = Some(ent);
2063
2064 break;
2065 }
2066 }
2067
2068 entry.ok_or(FSError::NotFound)?
2069 };
2070
2071 self.remove_entry_chain(&entry.chain)?;
2073
2074 self.free_cluster_chain(entry.data_cluster)?;
2076
2077 Ok(())
2078 }
2079
2080 pub fn remove_dir_all<P: AsRef<Path>>(&self, path: P) -> FSResult<(), S::Error> {
2088 if self.check_for_readonly_files(&path)? {
2092 log::error!(concat!(
2093 "A read-only file has been found ",
2094 "in a directory pending deletion."
2095 ));
2096 return Err(FSError::ReadOnlyFile);
2097 }
2098
2099 self.remove_dir_all_unchecked(&path)?;
2101
2102 Ok(())
2103 }
2104
2105 pub fn remove_dir_all_unchecked<P: AsRef<Path>>(&self, path: P) -> FSResult<(), S::Error> {
2110 let path = path.as_ref();
2111
2112 if !path.is_valid() {
2113 return Err(FSError::MalformedPath);
2114 }
2115
2116 let mut read_dir = self.read_dir(path)?;
2117 loop {
2118 let entry = match read_dir.next() {
2119 Some(entry) => entry?,
2120 None => break,
2121 };
2122
2123 if entry.is_dir() {
2124 self.remove_dir_all_unchecked(&entry.path)?;
2125 } else if entry.is_file() {
2126 self.remove_file_unchecked(&entry.path)?;
2127 } else {
2128 unreachable!()
2129 }
2130 }
2131
2132 self.remove_empty_dir(path)?;
2133
2134 Ok(())
2135 }
2136
2137 pub fn check_for_readonly_files<P: AsRef<Path>>(&self, path: P) -> FSResult<bool, S::Error> {
2142 let path = path.as_ref();
2143
2144 if !path.is_valid() {
2145 return Err(FSError::MalformedPath);
2146 }
2147
2148 let mut read_dir = self.read_dir(path)?;
2149
2150 loop {
2151 let entry = match read_dir.next() {
2152 Some(entry) => entry?,
2153 None => break,
2154 };
2155
2156 let read_only_found = if entry.is_dir() {
2157 self.check_for_readonly_files(&entry.path)?
2158 } else if entry.is_file() {
2159 entry.attributes.read_only
2160 } else {
2161 unreachable!()
2162 };
2163
2164 if read_only_found {
2165 return Ok(true);
2168 }
2169 }
2170
2171 Ok(false)
2172 }
2173
2174 pub fn get_rw_file<P: AsRef<Path>>(&self, path: P) -> FSResult<RWFile<'_, S>, S::Error> {
2178 let rw_file = self.get_rw_file_unchecked(path)?;
2179
2180 if rw_file.attributes.read_only {
2181 return Err(FSError::ReadOnlyFile);
2182 }
2183
2184 Ok(rw_file)
2185 }
2186
2187 pub fn unmount(&self) -> FSResult<(), S::Error> {
2192 self.sync_fsinfo()?;
2193 let should_sync_buffer = self.sync_f.borrow().is_some();
2194 if should_sync_buffer {
2195 self.sync_sector_buffer()?;
2196 }
2197 self.storage.borrow_mut().flush()?;
2198
2199 Ok(())
2200 }
2201}
2202
2203impl<S> ops::Drop for FileSystem<S>
2204where
2205 S: Read + Seek,
2206{
2207 fn drop(&mut self) {
2208 if let Some(unmount) = *self.unmount_f.borrow() {
2209 let _ = unmount(self);
2211 }
2212 }
2213}