1io_transform! {
2
3use core::{cell::Cell, fmt};
4
5use spin::Mutex;
6
7use hadris_common::types::endian::Endian;
8use hadris_path::{Component, VPath};
9
10use crate::error::{Error, Result};
11use crate::raw::{RawBpb, RawBpbExt16, RawBpbExt32, RawFsInfo};
12use super::dir::{FatDir, FileEntry};
13use super::fat_table::{Fat, Fat12, Fat16, Fat32, FatType};
14use super::io::{Cluster, ClusterLike, Read, ReadExt, Sector, SectorCursor, SectorLike, Seek, SeekFrom};
15use super::read::FileReader;
16
17#[derive(Debug, Clone)]
22pub struct VolumeInfo {
23 oem_name: [u8; 8],
25 volume_id: u32,
27 volume_label: [u8; 11],
29 fs_type_str: [u8; 8],
31}
32
33impl VolumeInfo {
34 pub fn oem_name(&self) -> &str {
36 core::str::from_utf8(&self.oem_name)
37 .unwrap_or("")
38 .trim_end()
39 }
40
41 pub fn volume_id(&self) -> u32 {
43 self.volume_id
44 }
45
46 pub fn volume_label(&self) -> &str {
48 core::str::from_utf8(&self.volume_label)
49 .unwrap_or("")
50 .trim_end()
51 }
52
53 pub fn fs_type_str(&self) -> &str {
58 core::str::from_utf8(&self.fs_type_str)
59 .unwrap_or("")
60 .trim_end()
61 }
62
63 pub fn oem_name_raw(&self) -> &[u8; 8] {
65 &self.oem_name
66 }
67
68 pub fn volume_label_raw(&self) -> &[u8; 11] {
70 &self.volume_label
71 }
72
73 pub fn fs_type_str_raw(&self) -> &[u8; 8] {
75 &self.fs_type_str
76 }
77}
78
79#[derive(Debug)]
80pub(crate) struct FatInfo {
81 #[cfg(feature = "alloc")]
82 pub(crate) cluster_size: usize,
83 pub(crate) data_start: usize,
84 #[cfg(feature = "alloc")]
85 pub(crate) max_cluster: u32,
86}
87
88#[derive(Debug)]
90pub(crate) struct Fat12_16FsExt {
91 root_dir_start: usize,
93 root_dir_size: usize,
95}
96
97#[derive(Debug)]
98pub(crate) enum FatFsExt {
99 Fat12_16(Fat12_16FsExt),
100 Fat32(Fat32FsExt),
101}
102
103impl FatFsExt {
104 #[cfg(feature = "write")]
106 fn fixed_root_dir(&self) -> Option<(usize, usize)> {
107 match self {
108 Self::Fat12_16(ext) => Some((ext.root_dir_start, ext.root_dir_size)),
109 Self::Fat32(_) => None,
110 }
111 }
112}
113
114pub(crate) struct Fat32FsExt {
119 pub(crate) fs_info_sec: Sector<u16>,
121 root_clus: Cluster<u32>,
123 pub(crate) free_count: Cell<u32>,
125 pub(crate) next_free: Cell<Cluster<u32>>,
127}
128
129impl fmt::Debug for Fat32FsExt {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 f.debug_struct("Fat32FsExt")
132 .field("fs_info_sec", &self.fs_info_sec)
133 .field("root_clus", &self.root_clus)
134 .field("free_count", &self.free_count.get())
135 .field("next_free", &self.next_free.get())
136 .finish()
137 }
138}
139
140pub struct FatVolume<DATA: Seek> {
142 pub(crate) data: Mutex<SectorCursor<DATA>>,
143 pub(crate) info: FatInfo,
144 pub(crate) fat: Fat,
145 pub(crate) ext: FatFsExt,
146 volume_info: VolumeInfo,
147 time_provider: &'static dyn crate::time::TimeProvider,
150 oem_converter: &'static dyn crate::oem::OemCpConverter,
153 #[cfg(feature = "cache")]
159 pub(crate) fat_cache: Option<Mutex<crate::cache::FatSectorCache>>,
160 #[cfg(feature = "write")]
165 pub(crate) open_writers: Mutex<alloc::vec::Vec<(usize, usize)>>,
166}
167
168impl<DATA: Seek> FatVolume<DATA> {
169 pub fn into_inner(self) -> DATA {
171 self.data.into_inner().data
172 }
173}
174
175impl<DATA: Seek> fmt::Debug for FatVolume<DATA> {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 f.debug_struct("FatVolume")
178 .field("info", &self.info)
179 .field("ext", &self.ext)
180 .field("time_provider", &self.time_provider)
181 .field("oem_converter", &self.oem_converter)
182 .finish_non_exhaustive()
183 }
184}
185
186pub struct FatVolumeBuilder<DATA: Read + Seek> {
193 data: DATA,
194 time_provider: &'static dyn crate::time::TimeProvider,
195 oem_converter: &'static dyn crate::oem::OemCpConverter,
196 #[cfg(feature = "cache")]
198 fat_cache_capacity: Option<usize>,
199}
200
201impl<DATA: Read + Seek> FatVolumeBuilder<DATA> {
202 pub fn new(data: DATA) -> Self {
204 Self {
205 data,
206 time_provider: &crate::time::DEFAULT_TIME_PROVIDER,
207 oem_converter: &crate::oem::DEFAULT_OEM_CONVERTER,
208 #[cfg(feature = "cache")]
209 fat_cache_capacity: None,
210 }
211 }
212
213 pub fn time_provider(
215 mut self,
216 provider: &'static dyn crate::time::TimeProvider,
217 ) -> Self {
218 self.time_provider = provider;
219 self
220 }
221
222 pub fn oem_converter(
224 mut self,
225 converter: &'static dyn crate::oem::OemCpConverter,
226 ) -> Self {
227 self.oem_converter = converter;
228 self
229 }
230
231 #[cfg(feature = "cache")]
245 pub fn fat_cache(mut self, capacity_sectors: usize) -> Self {
246 if capacity_sectors == 0 {
247 self.fat_cache_capacity = None;
248 } else {
249 self.fat_cache_capacity = Some(capacity_sectors);
250 }
251 self
252 }
253
254 pub async fn open(self) -> Result<FatVolume<DATA>> {
256 #[cfg(feature = "cache")]
257 let cap = self.fat_cache_capacity;
258 #[cfg(not(feature = "cache"))]
259 let fs = FatVolume::open_with_providers(self.data, self.time_provider, self.oem_converter).await?;
260 #[cfg(feature = "cache")]
261 let mut fs = FatVolume::open_with_providers(self.data, self.time_provider, self.oem_converter).await?;
262 #[cfg(feature = "cache")]
263 if let Some(capacity) = cap {
264 let (fat_start, fat_size, fat_count, sector_size) = {
266 let data = fs.data.lock();
267 let sector_size = data.sector_size;
268 let (start, size, count) = match &fs.fat {
269 Fat::Fat12(f) => f.cache_layout(),
270 Fat::Fat16(f) => f.cache_layout(),
271 Fat::Fat32(f) => f.cache_layout(),
272 };
273 (start, size, count, sector_size)
274 };
275 let cache = crate::cache::FatSectorCache::new(
276 fat_start, fat_size, fat_count, sector_size, capacity,
277 );
278 fs.fat_cache = Some(Mutex::new(cache));
279 }
280 Ok(fs)
281 }
282}
283
284#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
295#[cfg_attr(feature = "defmt", derive(defmt::Format))]
296pub struct FsStatusFlags {
297 pub dirty: bool,
299 pub io_errors: bool,
301}
302
303pub(crate) const FSINFO_LEAD_SIG: u32 = 0x41615252; pub(crate) const FSINFO_STRUC_SIG: u32 = 0x61417272; pub(crate) const FSINFO_TRAIL_SIG: u32 = 0xAA550000;
307
308impl<DATA> FatVolume<DATA>
310where
311 DATA: Read + Seek,
312{
313 pub async fn open(data: DATA) -> Result<Self> {
320 Self::open_with_providers(
321 data,
322 &crate::time::DEFAULT_TIME_PROVIDER,
323 &crate::oem::DEFAULT_OEM_CONVERTER,
324 )
325 .await
326 }
327
328 pub fn builder(data: DATA) -> FatVolumeBuilder<DATA> {
331 FatVolumeBuilder::new(data)
332 }
333
334 pub(crate) async fn open_with_providers(
337 mut data: DATA,
338 time_provider: &'static dyn crate::time::TimeProvider,
339 oem_converter: &'static dyn crate::oem::OemCpConverter,
340 ) -> Result<Self> {
341 let bpb = data
345 .read_struct::<RawBpb>()
346 .await
347 .map_err(|source| Error::IoContext {
348 op: "boot sector",
349 sector: Some(0),
350 source: source.erase(),
351 })?;
352 let sector_size = bpb.bytes_per_sector.get() as usize;
353 if !matches!(sector_size, 512 | 1024 | 2048 | 4096) {
354 return Err(Error::CorruptFilesystem {
355 context: "BPB bytes_per_sector must be 512, 1024, 2048, or 4096",
356 });
357 }
358 if !bpb.sectors_per_cluster.is_power_of_two() || bpb.sectors_per_cluster > 128 {
359 return Err(Error::CorruptFilesystem {
360 context: "BPB sectors_per_cluster must be a power of two from 1 through 128",
361 });
362 }
363 let cluster_size = (bpb.sectors_per_cluster as usize) * sector_size;
364 if cluster_size > 32 * 1024 {
365 return Err(Error::CorruptFilesystem {
366 context: "BPB cluster size must not exceed 32 KiB",
367 });
368 }
369 let data = SectorCursor::new(data, sector_size, cluster_size);
370
371 let root_entry_count = u16::from_le_bytes(bpb.root_entry_count);
374 let sectors_per_fat_16 = u16::from_le_bytes(bpb.sectors_per_fat_16);
375
376 if root_entry_count == 0 && sectors_per_fat_16 == 0 {
377 Self::open_fat32(data, bpb, time_provider, oem_converter).await
379 } else {
380 Self::open_fat12_16(data, bpb, time_provider, oem_converter).await
382 }
383 }
384
385 async fn open_fat12_16(
387 mut data: SectorCursor<DATA>,
388 bpb: RawBpb,
389 time_provider: &'static dyn crate::time::TimeProvider,
390 oem_converter: &'static dyn crate::oem::OemCpConverter,
391 ) -> Result<Self> {
392 let bpb_ext16 = data
394 .read_struct::<RawBpbExt16>()
395 .await
396 .map_err(|source| Error::IoContext {
397 op: "boot sector (FAT12/16 extended fields)",
398 sector: Some(0),
399 source: source.erase(),
400 })?;
401
402 let signature = u16::from_le_bytes(bpb_ext16.signature_word);
404 if signature != 0xAA55 {
405 return Err(Error::InvalidBootSignature { found: signature });
406 }
407
408 if bpb.fat_count != 1 && bpb.fat_count != 2 {
414 return Err(Error::CorruptFilesystem {
415 context: "BPB fat_count must be 1 or 2",
416 });
417 }
418
419 let sector_size = data.sector_size;
420 #[cfg(feature = "alloc")]
421 let cluster_size = data.cluster_size;
422 let reserved_sectors = bpb.reserved_sector_count.get() as usize;
423 let fat_count = bpb.fat_count as usize;
424 let root_entry_count = u16::from_le_bytes(bpb.root_entry_count);
425 let sectors_per_fat = u16::from_le_bytes(bpb.sectors_per_fat_16) as usize;
426
427 let fat_start = reserved_sectors
432 .checked_mul(sector_size)
433 .ok_or(Error::CorruptFilesystem {
434 context: "reserved_sectors * sector_size",
435 })?;
436 let fat_total_size = fat_count
437 .checked_mul(sectors_per_fat)
438 .and_then(|v| v.checked_mul(sector_size))
439 .ok_or(Error::CorruptFilesystem {
440 context: "fat_count * sectors_per_fat * sector_size",
441 })?;
442 let root_dir_start = fat_start
443 .checked_add(fat_total_size)
444 .ok_or(Error::CorruptFilesystem {
445 context: "fat_start + fat_total_size",
446 })?;
447 let root_dir_size = (root_entry_count as usize) * 32;
448 let root_dir_sectors = root_dir_size.div_ceil(sector_size);
449
450 let data_start = root_dir_start
452 .checked_add(root_dir_sectors * sector_size)
453 .ok_or(Error::CorruptFilesystem {
454 context: "data_start arithmetic",
455 })?;
456
457 let total_sectors = if bpb.total_sectors_16 != [0, 0] {
459 u16::from_le_bytes(bpb.total_sectors_16) as u32
460 } else {
461 u32::from_le_bytes(bpb.total_sectors_32)
462 };
463 let metadata_sectors = reserved_sectors
467 .checked_add(fat_count.checked_mul(sectors_per_fat).ok_or(
468 Error::CorruptFilesystem {
469 context: "fat_count * sectors_per_fat",
470 },
471 )?)
472 .and_then(|v| v.checked_add(root_dir_sectors))
473 .ok_or(Error::CorruptFilesystem {
474 context: "metadata sector total",
475 })?;
476 let data_sectors = (total_sectors as usize).saturating_sub(metadata_sectors);
477 let count_of_clusters = data_sectors / (bpb.sectors_per_cluster as usize);
478
479 let (fat, max_cluster) = if count_of_clusters < 4085 {
481 let fat12 = Fat12::new(
483 fat_start,
484 sectors_per_fat * sector_size,
485 fat_count,
486 (count_of_clusters + 1) as u16, );
488 (Fat::Fat12(fat12), count_of_clusters as u32 + 1)
489 } else {
490 let fat16 = Fat16::new(
492 fat_start,
493 sectors_per_fat * sector_size,
494 fat_count,
495 (count_of_clusters + 1) as u16,
496 );
497 (Fat::Fat16(fat16), count_of_clusters as u32 + 1)
498 };
499 #[cfg(not(feature = "alloc"))]
500 let _ = max_cluster;
501
502 let ext = FatFsExt::Fat12_16(Fat12_16FsExt {
503 root_dir_start,
504 root_dir_size,
505 });
506
507 let info = FatInfo {
508 #[cfg(feature = "alloc")]
509 cluster_size,
510 data_start,
511 #[cfg(feature = "alloc")]
512 max_cluster,
513 };
514
515 let volume_info = VolumeInfo {
517 oem_name: bpb.oem_name,
518 volume_id: u32::from_le_bytes(bpb_ext16.volume_id),
519 volume_label: bpb_ext16.volume_label,
520 fs_type_str: bpb_ext16.fs_type,
521 };
522
523 Ok(Self {
524 data: Mutex::new(data),
525 info,
526 fat,
527 ext,
528 volume_info,
529 time_provider,
530 oem_converter,
531 #[cfg(feature = "cache")]
532 fat_cache: None,
533 #[cfg(feature = "write")]
534 open_writers: Mutex::new(alloc::vec::Vec::new()),
535 })
536 }
537
538 async fn open_fat32(
540 mut data: SectorCursor<DATA>,
541 bpb: RawBpb,
542 time_provider: &'static dyn crate::time::TimeProvider,
543 oem_converter: &'static dyn crate::oem::OemCpConverter,
544 ) -> Result<Self> {
545 let bpb_ext32 = data
546 .read_struct::<RawBpbExt32>()
547 .await
548 .map_err(|source| Error::IoContext {
549 op: "boot sector (FAT32 extended fields)",
550 sector: Some(0),
551 source: source.erase(),
552 })?;
553
554 let signature = bpb_ext32.signature_word.get();
556 if signature != 0xAA55 {
557 return Err(Error::InvalidBootSignature { found: signature });
558 }
559 if bpb_ext32.version != [0, 0] {
560 return Err(Error::CorruptFilesystem {
561 context: "unsupported FAT32 filesystem version",
562 });
563 }
564
565 if bpb.fat_count != 1 && bpb.fat_count != 2 {
569 return Err(Error::CorruptFilesystem {
570 context: "BPB fat_count must be 1 or 2",
571 });
572 }
573
574 let fs_info_sec = Sector(bpb_ext32.fs_info_sector.get());
576 data.seek_sector(fs_info_sec).await?;
577 let fs_info = data
578 .read_struct::<RawFsInfo>()
579 .await
580 .map_err(|source| Error::IoContext {
581 op: "FSInfo",
582 sector: Some(fs_info_sec.0 as u64),
583 source: source.erase(),
584 })?;
585
586 let lead_sig = u32::from_le_bytes(fs_info.signature);
588 if lead_sig != FSINFO_LEAD_SIG {
589 return Err(Error::InvalidFsInfoSignature {
590 field: "FSI_LeadSig",
591 expected: FSINFO_LEAD_SIG,
592 found: lead_sig,
593 });
594 }
595
596 let struc_sig = u32::from_le_bytes(fs_info.structure_signature);
597 if struc_sig != FSINFO_STRUC_SIG {
598 return Err(Error::InvalidFsInfoSignature {
599 field: "FSI_StrucSig",
600 expected: FSINFO_STRUC_SIG,
601 found: struc_sig,
602 });
603 }
604
605 let trail_sig = fs_info.trail_signature.get();
606 if trail_sig != FSINFO_TRAIL_SIG {
607 return Err(Error::InvalidFsInfoSignature {
608 field: "FSI_TrailSig",
609 expected: FSINFO_TRAIL_SIG,
610 found: trail_sig,
611 });
612 }
613
614 let ext = FatFsExt::Fat32(Fat32FsExt {
615 fs_info_sec,
616 root_clus: Cluster(bpb_ext32.root_cluster.get()),
617 free_count: Cell::new(fs_info.free_count.get()),
618 next_free: Cell::new(Cluster(fs_info.next_free.get())),
619 });
620
621 #[cfg(feature = "alloc")]
622 let cluster_size = data.cluster_size;
623 let fat_start = Sector(bpb.reserved_sector_count.get()).to_bytes(data.sector_size);
627 let fat_size_per_fat = (bpb_ext32.sectors_per_fat_32.get() as usize)
628 .checked_mul(data.sector_size)
629 .ok_or(Error::CorruptFilesystem {
630 context: "sectors_per_fat_32 * sector_size",
631 })?;
632 let fat_size = (bpb.fat_count as usize)
633 .checked_mul(fat_size_per_fat)
634 .ok_or(Error::CorruptFilesystem {
635 context: "fat_count * sectors_per_fat_32",
636 })?;
637
638 let total_sectors = if bpb.total_sectors_16 != [0, 0] {
640 u16::from_le_bytes(bpb.total_sectors_16) as u32
641 } else {
642 u32::from_le_bytes(bpb.total_sectors_32)
643 };
644 let metadata_sectors = bpb.reserved_sector_count.get() as u64
646 + bpb_ext32.sectors_per_fat_32.get() as u64 * bpb.fat_count as u64;
647 let data_sectors = (total_sectors as u64).saturating_sub(metadata_sectors);
648 let max_cluster =
649 (data_sectors / bpb.sectors_per_cluster as u64).min(u32::MAX as u64 - 1) as u32 + 1; let root_cluster = bpb_ext32.root_cluster.get();
655 if !(2..=max_cluster).contains(&root_cluster) {
656 return Err(Error::ClusterOutOfBounds {
657 cluster: root_cluster,
658 max: max_cluster,
659 });
660 }
661
662 let fat = Fat::Fat32(Fat32::new(
663 fat_start,
664 fat_size_per_fat,
665 bpb.fat_count as usize,
666 max_cluster,
667 ));
668
669 let data_start = fat_start
670 .checked_add(fat_size)
671 .ok_or(Error::CorruptFilesystem {
672 context: "fat_start + fat_size",
673 })?;
674
675 let info = FatInfo {
676 #[cfg(feature = "alloc")]
677 cluster_size,
678 data_start,
679 #[cfg(feature = "alloc")]
680 max_cluster,
681 };
682
683 let volume_info = VolumeInfo {
685 oem_name: bpb.oem_name,
686 volume_id: u32::from_le_bytes(bpb_ext32.volume_id),
687 volume_label: bpb_ext32.volume_label,
688 fs_type_str: bpb_ext32.fs_type,
689 };
690
691 Ok(Self {
692 data: Mutex::new(data),
693 info,
694 fat,
695 ext,
696 volume_info,
697 time_provider,
698 oem_converter,
699 #[cfg(feature = "cache")]
700 fat_cache: None,
701 #[cfg(feature = "write")]
702 open_writers: Mutex::new(alloc::vec::Vec::new()),
703 })
704 }
705
706 pub fn time_provider(&self) -> &dyn crate::time::TimeProvider {
708 self.time_provider
709 }
710
711 pub fn oem_converter(&self) -> &dyn crate::oem::OemCpConverter {
713 self.oem_converter
714 }
715
716 pub fn fat(&self) -> &Fat {
723 &self.fat
724 }
725
726 pub fn root_dir(&self) -> FatDir<'_, DATA> {
728 match &self.ext {
729 FatFsExt::Fat12_16(ext) => FatDir {
730 data: self,
731 cluster: Cluster(0), fixed_root: Some((ext.root_dir_start, ext.root_dir_size)),
733 #[cfg(feature = "write")]
734 dir_entry: None, },
736 FatFsExt::Fat32(ext) => FatDir {
737 data: self,
738 cluster: Cluster(ext.root_clus.0 as usize),
739 fixed_root: None,
740 #[cfg(feature = "write")]
741 dir_entry: None, },
743 }
744 }
745
746 pub fn fat_type(&self) -> FatType {
748 self.fat.fat_type()
749 }
750
751 pub fn volume_info(&self) -> &VolumeInfo {
756 &self.volume_info
757 }
758
759 #[cfg(feature = "write")]
763 pub(crate) fn fixed_root_dir_info(&self) -> Option<(usize, usize)> {
764 self.ext.fixed_root_dir()
765 }
766
767 #[cfg(feature = "write")]
773 pub(crate) fn is_fat32_root_cluster(&self, cluster: u32) -> bool {
774 matches!(&self.ext, FatFsExt::Fat32(ext) if ext.root_clus.0 == cluster)
775 }
776
777 pub async fn read_status_flags(&self) -> Result<FsStatusFlags> {
784 let (dirty, io_errors) = self.read_status_flags_routed().await?;
785 Ok(FsStatusFlags { dirty, io_errors })
786 }
787
788 pub async fn read_root_label(&self) -> Result<Option<[u8; 11]>> {
798 match self.find_root_label_entry().await? {
799 Some((_, raw)) => Ok(Some(unsafe { raw.file }.name)),
800 None => Ok(None),
801 }
802 }
803
804 pub(crate) async fn find_root_label_entry(
811 &self,
812 ) -> Result<Option<(usize, crate::raw::RawDirectoryEntry)>> {
813 use crate::raw::{DirEntryAttrFlags, RawDirectoryEntry};
814 let entry_size = core::mem::size_of::<RawDirectoryEntry>();
815 let mut data = self.data.lock();
816
817 let is_label =
818 |attr: u8| DirEntryAttrFlags::from_bits_retain(attr).is_volume_label_entry();
819
820 match &self.ext {
821 FatFsExt::Fat12_16(ext) => {
822 let end = ext.root_dir_start + ext.root_dir_size;
823 let mut pos = ext.root_dir_start;
824 while pos + entry_size <= end {
825 data.seek(SeekFrom::Start(pos as u64)).await?;
826 let raw = data.read_struct::<RawDirectoryEntry>().await?;
827 let bytes = unsafe { raw.bytes };
828 if bytes[0] == 0 {
829 return Ok(None);
830 }
831 if bytes[0] != 0xE5 && is_label(unsafe { raw.file }.attributes) {
832 return Ok(Some((pos, raw)));
833 }
834 pos += entry_size;
835 }
836 Ok(None)
837 }
838 FatFsExt::Fat32(ext) => {
839 let cluster_size = data.cluster_size;
840 let mut current = ext.root_clus.0 as usize;
841 let chain_limit = self.fat.max_cluster();
842 let mut steps: u32 = 0;
843 loop {
844 steps = steps.saturating_add(1);
845 if steps > chain_limit {
846 return Err(Error::ClusterLoop { cluster: current as u32 });
847 }
848 let cluster_start = Cluster(current).to_bytes(self.info.data_start, cluster_size);
849 let mut offset = 0;
850 while offset + entry_size <= cluster_size {
851 let pos = cluster_start + offset;
852 data.seek(SeekFrom::Start(pos as u64)).await?;
853 let raw = data.read_struct::<RawDirectoryEntry>().await?;
854 let bytes = unsafe { raw.bytes };
855 if bytes[0] == 0 {
856 return Ok(None);
857 }
858 if bytes[0] != 0xE5 && is_label(unsafe { raw.file }.attributes) {
859 return Ok(Some((pos, raw)));
860 }
861 offset += entry_size;
862 }
863 drop(data);
867 let next_cluster = self.next_cluster_routed(current).await?;
868 data = self.data.lock();
869 match next_cluster {
870 Some(next) => current = next as usize,
871 None => return Ok(None),
872 }
873 }
874 }
875 }
876 }
877
878 pub async fn open_path(&self, path: &str) -> Result<FileEntry> {
883 let mut current_dir = self.root_dir();
884 let mut last_component = None;
885
886 for component in VPath::new(path).components() {
887 let component = match component {
888 Component::Root | Component::Current => continue,
889 Component::Parent => return Err(Error::InvalidPath),
890 Component::Normal(component) => component,
891 };
892 if let Some(prev) = last_component.take() {
893 current_dir = current_dir.open_dir(prev).await?;
895 }
896 last_component = Some(component);
897 }
898
899 let final_name = last_component.ok_or(Error::InvalidPath)?;
901 current_dir.find(final_name).await?.ok_or(Error::EntryNotFound)
902 }
903
904 pub async fn open_file_path(&self, path: &str) -> Result<FileReader<'_, DATA>> {
909 let entry = self.open_path(path).await?;
910 FileReader::new(self, &entry)
911 }
912
913 pub async fn open_dir_path(&self, path: &str) -> Result<FatDir<'_, DATA>> {
918 let entry = self.open_path(path).await?;
919 if !entry.is_directory() {
920 return Err(Error::NotADirectory);
921 }
922 Ok(FatDir {
924 data: self,
925 cluster: entry.cluster(),
926 fixed_root: None,
927 #[cfg(feature = "write")]
928 dir_entry: Some(super::dir::DirSlot::from_entry(&entry)),
929 })
930 }
931
932 pub fn open_dir_entry(&self, entry: &FileEntry) -> Result<FatDir<'_, DATA>> {
936 if !entry.is_directory() {
937 return Err(Error::NotADirectory);
938 }
939 Ok(FatDir {
940 data: self,
941 cluster: entry.cluster(),
942 fixed_root: None,
943 #[cfg(feature = "write")]
944 dir_entry: Some(super::dir::DirSlot::from_entry(entry)),
945 })
946 }
947}
948
949} #[cfg(feature = "cache")]
963sync_only! {
964 impl<DATA> FatVolume<DATA>
965 where
966 DATA: Read + Seek,
967 {
968 pub fn fat_cache(&self) -> Option<&Mutex<crate::cache::FatSectorCache>> {
976 self.fat_cache.as_ref()
977 }
978
979 pub fn with_cached_fat<R>(
1012 &self,
1013 f: impl FnOnce(&mut crate::cache::CachedFat<'_>, &mut SectorCursor<DATA>) -> R,
1014 ) -> Option<R> {
1015 let cache_mutex = self.fat_cache.as_ref()?;
1016 let mut cache = cache_mutex.lock();
1017 let mut data = self.data.lock();
1018 let mut cached = crate::cache::CachedFat::new(&mut cache, &self.fat);
1019 Some(f(&mut cached, &mut *data))
1020 }
1021
1022 pub fn with_fat_cache_locked<R>(
1038 &self,
1039 f: impl FnOnce(&mut crate::cache::FatSectorCache, &mut SectorCursor<DATA>) -> R,
1040 ) -> Option<R> {
1041 let cache_mutex = self.fat_cache.as_ref()?;
1042 let mut cache = cache_mutex.lock();
1043 let mut data = self.data.lock();
1044 Some(f(&mut cache, &mut *data))
1045 }
1046 }
1047}
1048
1049#[cfg(feature = "cache")]
1063sync_only! {
1064 impl<DATA> FatVolume<DATA>
1065 where
1066 DATA: Read + Seek,
1067 {
1068 pub(crate) fn next_cluster_routed(&self, cluster: usize) -> Result<Option<u32>> {
1075 use core::ops::DerefMut;
1076 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1077 let mut data = self.data.lock();
1078 if let Some(cache) = cache_guard.as_mut() {
1079 let mut cached = crate::cache::CachedFat::new(cache, &self.fat);
1080 cached.next_cluster(data.deref_mut(), cluster)
1081 } else {
1082 self.fat.next_cluster(data.deref_mut(), cluster)
1083 }
1084 }
1085
1086 pub(crate) fn read_status_flags_routed(&self) -> Result<(bool, bool)> {
1088 use core::ops::DerefMut;
1089 if matches!(self.fat, Fat::Fat12(_)) {
1092 return Ok((false, false));
1093 }
1094 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1095 let mut data = self.data.lock();
1096 match (&self.fat, cache_guard.as_deref_mut()) {
1097 (Fat::Fat16(_), Some(cache)) => {
1098 let val = cache.read_fat16_entry(data.deref_mut(), 1)?;
1099 Ok((val & 0x8000 == 0, val & 0x4000 == 0))
1100 }
1101 (Fat::Fat32(_), Some(cache)) => {
1102 let val = cache.read_fat32_entry(data.deref_mut(), 1)?;
1103 Ok((val & 0x0800_0000 == 0, val & 0x0400_0000 == 0))
1104 }
1105 _ => self.fat.read_status_flags(data.deref_mut()),
1106 }
1107 }
1108 }
1109}
1110
1111#[cfg(feature = "cache")]
1112async_only! {
1113 impl<DATA> FatVolume<DATA>
1114 where
1115 DATA: Read + Seek,
1116 {
1117 pub(crate) async fn next_cluster_routed(&self, cluster: usize) -> Result<Option<u32>> {
1119 use core::ops::DerefMut;
1120 let mut data = self.data.lock();
1121 self.fat.next_cluster(data.deref_mut(), cluster).await
1122 }
1123
1124 pub(crate) async fn read_status_flags_routed(&self) -> Result<(bool, bool)> {
1126 use core::ops::DerefMut;
1127 let mut data = self.data.lock();
1128 self.fat.read_status_flags(data.deref_mut()).await
1129 }
1130 }
1131}
1132
1133#[cfg(not(feature = "cache"))]
1137io_transform! {
1138 impl<DATA> FatVolume<DATA>
1139 where
1140 DATA: Read + Seek,
1141 {
1142 pub(crate) async fn next_cluster_routed(&self, cluster: usize) -> Result<Option<u32>> {
1143 use core::ops::DerefMut;
1144 let mut data = self.data.lock();
1145 self.fat.next_cluster(data.deref_mut(), cluster).await
1146 }
1147
1148 pub(crate) async fn read_status_flags_routed(&self) -> Result<(bool, bool)> {
1149 use core::ops::DerefMut;
1150 let mut data = self.data.lock();
1151 self.fat.read_status_flags(data.deref_mut()).await
1152 }
1153 }
1154}
1155
1156#[cfg(all(feature = "cache", feature = "write"))]
1175sync_only! {
1176 impl<DATA> FatVolume<DATA>
1177 where
1178 DATA: Read + super::io::Write + Seek,
1179 {
1180 pub(crate) fn write_clus_routed(&self, cluster: usize, value: u32) -> Result<()> {
1182 use core::ops::DerefMut;
1183 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1184 let mut data = self.data.lock();
1185 if let Some(ref mut cache) = cache_guard {
1186 match self.fat.fat_type() {
1187 FatType::Fat12 => cache.write_fat12_entry(data.deref_mut(), cluster, value as u16),
1188 FatType::Fat16 => cache.write_fat16_entry(data.deref_mut(), cluster, value as u16),
1189 FatType::Fat32 => cache.write_fat32_entry(data.deref_mut(), cluster, value),
1190 }
1191 } else {
1192 match &self.fat {
1193 Fat::Fat12(f) => f.write_clus(data.deref_mut(), cluster, value as u16),
1194 Fat::Fat16(f) => f.write_clus(data.deref_mut(), cluster, value as u16),
1195 Fat::Fat32(f) => f.write_clus(data.deref_mut(), cluster, value),
1196 }
1197 }
1198 }
1199
1200 pub(crate) fn allocate_cluster_routed(&self, hint: u32) -> Result<u32> {
1203 use core::ops::DerefMut;
1204 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1205 let mut data = self.data.lock();
1206 if let Some(ref mut cache) = cache_guard {
1207 allocate_cluster_via_cache(cache, &self.fat, data.deref_mut(), hint)
1208 } else {
1209 match &self.fat {
1210 Fat::Fat12(f) => f.allocate_cluster(data.deref_mut(), hint as u16).map(|c| c as u32),
1211 Fat::Fat16(f) => f.allocate_cluster(data.deref_mut(), hint as u16).map(|c| c as u32),
1212 Fat::Fat32(f) => f.allocate_cluster(data.deref_mut(), hint),
1213 }
1214 }
1215 }
1216
1217 pub(crate) fn free_chain_routed(&self, start: u32) -> Result<u32> {
1220 use core::ops::DerefMut;
1221 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1222 let mut data = self.data.lock();
1223 if let Some(ref mut cache) = cache_guard {
1224 free_chain_via_cache(cache, &self.fat, data.deref_mut(), start)
1225 } else {
1226 self.fat.free_chain(data.deref_mut(), start as usize)
1227 }
1228 }
1229
1230 pub(crate) fn truncate_chain_routed(&self, cluster: u32) -> Result<u32> {
1233 use core::ops::DerefMut;
1234 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1235 let mut data = self.data.lock();
1236 if let Some(ref mut cache) = cache_guard {
1237 truncate_chain_via_cache(cache, &self.fat, data.deref_mut(), cluster)
1238 } else {
1239 self.fat.truncate_chain(data.deref_mut(), cluster as usize)
1240 }
1241 }
1242
1243 }
1244}
1245
1246#[cfg(all(feature = "cache", feature = "write"))]
1247async_only! {
1248 impl<DATA> FatVolume<DATA>
1249 where
1250 DATA: Read + super::io::Write + Seek,
1251 {
1252 pub(crate) async fn write_clus_routed(&self, cluster: usize, value: u32) -> Result<()> {
1254 use core::ops::DerefMut;
1255 let mut data = self.data.lock();
1256 match &self.fat {
1257 Fat::Fat12(f) => f.write_clus(data.deref_mut(), cluster, value as u16).await,
1258 Fat::Fat16(f) => f.write_clus(data.deref_mut(), cluster, value as u16).await,
1259 Fat::Fat32(f) => f.write_clus(data.deref_mut(), cluster, value).await,
1260 }
1261 }
1262
1263 pub(crate) async fn allocate_cluster_routed(&self, hint: u32) -> Result<u32> {
1264 use core::ops::DerefMut;
1265 let mut data = self.data.lock();
1266 match &self.fat {
1267 Fat::Fat12(f) => f.allocate_cluster(data.deref_mut(), hint as u16).await.map(|c| c as u32),
1268 Fat::Fat16(f) => f.allocate_cluster(data.deref_mut(), hint as u16).await.map(|c| c as u32),
1269 Fat::Fat32(f) => f.allocate_cluster(data.deref_mut(), hint).await,
1270 }
1271 }
1272
1273 pub(crate) async fn free_chain_routed(&self, start: u32) -> Result<u32> {
1274 use core::ops::DerefMut;
1275 let mut data = self.data.lock();
1276 self.fat.free_chain(data.deref_mut(), start as usize).await
1277 }
1278
1279 pub(crate) async fn truncate_chain_routed(&self, cluster: u32) -> Result<u32> {
1280 use core::ops::DerefMut;
1281 let mut data = self.data.lock();
1282 self.fat.truncate_chain(data.deref_mut(), cluster as usize).await
1283 }
1284
1285 }
1286}
1287
1288#[cfg(all(not(feature = "cache"), feature = "write"))]
1291io_transform! {
1292 impl<DATA> FatVolume<DATA>
1293 where
1294 DATA: Read + super::io::Write + Seek,
1295 {
1296 pub(crate) async fn write_clus_routed(&self, cluster: usize, value: u32) -> Result<()> {
1297 use core::ops::DerefMut;
1298 let mut data = self.data.lock();
1299 match &self.fat {
1300 Fat::Fat12(f) => f.write_clus(data.deref_mut(), cluster, value as u16).await,
1301 Fat::Fat16(f) => f.write_clus(data.deref_mut(), cluster, value as u16).await,
1302 Fat::Fat32(f) => f.write_clus(data.deref_mut(), cluster, value).await,
1303 }
1304 }
1305
1306 pub(crate) async fn allocate_cluster_routed(&self, hint: u32) -> Result<u32> {
1307 use core::ops::DerefMut;
1308 let mut data = self.data.lock();
1309 match &self.fat {
1310 Fat::Fat12(f) => f.allocate_cluster(data.deref_mut(), hint as u16).await.map(|c| c as u32),
1311 Fat::Fat16(f) => f.allocate_cluster(data.deref_mut(), hint as u16).await.map(|c| c as u32),
1312 Fat::Fat32(f) => f.allocate_cluster(data.deref_mut(), hint).await,
1313 }
1314 }
1315
1316 pub(crate) async fn free_chain_routed(&self, start: u32) -> Result<u32> {
1317 use core::ops::DerefMut;
1318 let mut data = self.data.lock();
1319 self.fat.free_chain(data.deref_mut(), start as usize).await
1320 }
1321
1322 pub(crate) async fn truncate_chain_routed(&self, cluster: u32) -> Result<u32> {
1323 use core::ops::DerefMut;
1324 let mut data = self.data.lock();
1325 self.fat.truncate_chain(data.deref_mut(), cluster as usize).await
1326 }
1327
1328 }
1329}
1330
1331#[cfg(all(feature = "cache", feature = "write"))]
1338sync_only! {
1339
1340fn allocate_cluster_via_cache<T>(
1341 cache: &mut crate::cache::FatSectorCache,
1342 fat: &Fat,
1343 data: &mut T,
1344 hint: u32,
1345) -> Result<u32>
1346where
1347 T: super::io::Read + super::io::Write + super::io::Seek,
1348{
1349 const FIRST: u32 = 2;
1350 let max_cluster = fat.max_cluster();
1351 let start = if hint >= FIRST && hint <= max_cluster {
1352 hint
1353 } else {
1354 FIRST
1355 };
1356
1357 let scan = |cache: &mut crate::cache::FatSectorCache,
1358 data: &mut T,
1359 fat: &Fat,
1360 lo: u32,
1361 hi: u32|
1362 -> Result<Option<u32>> {
1363 for c in lo..=hi {
1364 let free = match fat.fat_type() {
1365 FatType::Fat12 => (cache.read_fat12_entry(data, c as usize)? & 0x0FFF) == 0,
1366 FatType::Fat16 => cache.read_fat16_entry(data, c as usize)? == 0,
1367 FatType::Fat32 => (cache.read_fat32_entry(data, c as usize)? & 0x0FFF_FFFF) == 0,
1368 };
1369 if free {
1370 return Ok(Some(c));
1371 }
1372 }
1373 Ok(None)
1374 };
1375
1376 let claim =
1377 |cache: &mut crate::cache::FatSectorCache, data: &mut T, fat: &Fat, c: u32| -> Result<()> {
1378 match fat.fat_type() {
1379 FatType::Fat12 => cache.write_fat12_entry(data, c as usize, 0x0FF8),
1380 FatType::Fat16 => cache.write_fat16_entry(data, c as usize, 0xFFF8),
1381 FatType::Fat32 => cache.write_fat32_entry(data, c as usize, 0x0FFF_FFF8),
1382 }
1383 };
1384
1385 if let Some(c) = scan(cache, data, fat, start, max_cluster)? {
1386 claim(cache, data, fat, c)?;
1387 return Ok(c);
1388 }
1389 if start > FIRST
1390 && let Some(c) = scan(cache, data, fat, FIRST, start - 1)?
1391 {
1392 claim(cache, data, fat, c)?;
1393 return Ok(c);
1394 }
1395 Err(Error::NoFreeSpace)
1396}
1397
1398#[cfg(all(feature = "cache", feature = "write"))]
1399fn free_chain_via_cache<T>(
1400 cache: &mut crate::cache::FatSectorCache,
1401 fat: &Fat,
1402 data: &mut T,
1403 start: u32,
1404) -> Result<u32>
1405where
1406 T: super::io::Read + super::io::Write + super::io::Seek,
1407{
1408 const FIRST: u32 = 2;
1409 let max_cluster = fat.max_cluster();
1410 let mut count = 0u32;
1411 let mut current = start;
1412 loop {
1413 if current < FIRST || current > max_cluster {
1414 break;
1415 }
1416 let next = read_fat_entry_via_cache(cache, fat, data, current as usize)?;
1417 write_fat_entry_via_cache(cache, fat, data, current as usize, 0)?;
1418 count += 1;
1419 if is_eoc(fat.fat_type(), next) || is_bad(fat.fat_type(), next) || next == 0 {
1420 break;
1421 }
1422 current = next;
1423 }
1424 Ok(count)
1425}
1426
1427#[cfg(all(feature = "cache", feature = "write"))]
1428fn truncate_chain_via_cache<T>(
1429 cache: &mut crate::cache::FatSectorCache,
1430 fat: &Fat,
1431 data: &mut T,
1432 cluster: u32,
1433) -> Result<u32>
1434where
1435 T: super::io::Read + super::io::Write + super::io::Seek,
1436{
1437 const FIRST: u32 = 2;
1438 let max_cluster = fat.max_cluster();
1439 if cluster < FIRST || cluster > max_cluster {
1440 return Ok(0);
1441 }
1442 let next = read_fat_entry_via_cache(cache, fat, data, cluster as usize)?;
1443 let eoc = match fat.fat_type() {
1444 FatType::Fat12 => 0x0FF8,
1445 FatType::Fat16 => 0xFFF8,
1446 FatType::Fat32 => 0x0FFF_FFF8,
1447 };
1448 write_fat_entry_via_cache(cache, fat, data, cluster as usize, eoc)?;
1449 if !is_eoc(fat.fat_type(), next) && next >= FIRST && next <= max_cluster {
1450 free_chain_via_cache(cache, fat, data, next)
1451 } else {
1452 Ok(0)
1453 }
1454}
1455
1456#[cfg(all(feature = "cache", feature = "write"))]
1457fn read_fat_entry_via_cache<T>(
1458 cache: &mut crate::cache::FatSectorCache,
1459 fat: &Fat,
1460 data: &mut T,
1461 cluster: usize,
1462) -> Result<u32>
1463where
1464 T: super::io::Read + super::io::Seek,
1465{
1466 Ok(match fat.fat_type() {
1467 FatType::Fat12 => (cache.read_fat12_entry(data, cluster)? & 0x0FFF) as u32,
1468 FatType::Fat16 => cache.read_fat16_entry(data, cluster)? as u32,
1469 FatType::Fat32 => cache.read_fat32_entry(data, cluster)? & 0x0FFF_FFFF,
1470 })
1471}
1472
1473#[cfg(all(feature = "cache", feature = "write"))]
1474fn write_fat_entry_via_cache<T>(
1475 cache: &mut crate::cache::FatSectorCache,
1476 fat: &Fat,
1477 data: &mut T,
1478 cluster: usize,
1479 value: u32,
1480) -> Result<()>
1481where
1482 T: super::io::Read + super::io::Write + super::io::Seek,
1483{
1484 match fat.fat_type() {
1485 FatType::Fat12 => cache.write_fat12_entry(data, cluster, value as u16),
1486 FatType::Fat16 => cache.write_fat16_entry(data, cluster, value as u16),
1487 FatType::Fat32 => cache.write_fat32_entry(data, cluster, value),
1488 }
1489}
1490
1491#[cfg(all(feature = "cache", feature = "write"))]
1492fn is_eoc(ty: FatType, value: u32) -> bool {
1493 match ty {
1494 FatType::Fat12 => value >= 0x0FF8,
1495 FatType::Fat16 => value >= 0xFFF8,
1496 FatType::Fat32 => value >= 0x0FFF_FFF8,
1497 }
1498}
1499
1500#[cfg(all(feature = "cache", feature = "write"))]
1501fn is_bad(ty: FatType, value: u32) -> bool {
1502 match ty {
1503 FatType::Fat12 => value == 0x0FF7,
1504 FatType::Fat16 => value == 0xFFF7,
1505 FatType::Fat32 => value == 0x0FFF_FFF7,
1506 }
1507}
1508
1509} #[cfg(all(feature = "cache", feature = "write"))]
1520sync_only! {
1521 impl<DATA> FatVolume<DATA>
1522 where
1523 DATA: Read + super::io::Write + Seek,
1524 {
1525 pub fn flush(&self) -> Result<()> {
1533 use core::ops::DerefMut;
1534 if let Some(cache_mutex) = &self.fat_cache {
1535 let mut cache = cache_mutex.lock();
1536 let mut data = self.data.lock();
1537 cache.flush(data.deref_mut())?;
1538 }
1539 Ok(())
1540 }
1541 }
1542}