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}
161
162impl<DATA: Seek> FatVolume<DATA> {
163 pub fn into_inner(self) -> DATA {
165 self.data.into_inner().data
166 }
167}
168
169impl<DATA: Seek> fmt::Debug for FatVolume<DATA> {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 f.debug_struct("FatVolume")
172 .field("info", &self.info)
173 .field("ext", &self.ext)
174 .field("time_provider", &self.time_provider)
175 .field("oem_converter", &self.oem_converter)
176 .finish_non_exhaustive()
177 }
178}
179
180pub struct FatVolumeBuilder<DATA: Read + Seek> {
187 data: DATA,
188 time_provider: &'static dyn crate::time::TimeProvider,
189 oem_converter: &'static dyn crate::oem::OemCpConverter,
190 #[cfg(feature = "cache")]
192 fat_cache_capacity: Option<usize>,
193}
194
195impl<DATA: Read + Seek> FatVolumeBuilder<DATA> {
196 pub fn new(data: DATA) -> Self {
198 Self {
199 data,
200 time_provider: &crate::time::DEFAULT_TIME_PROVIDER,
201 oem_converter: &crate::oem::DEFAULT_OEM_CONVERTER,
202 #[cfg(feature = "cache")]
203 fat_cache_capacity: None,
204 }
205 }
206
207 pub fn time_provider(
209 mut self,
210 provider: &'static dyn crate::time::TimeProvider,
211 ) -> Self {
212 self.time_provider = provider;
213 self
214 }
215
216 pub fn oem_converter(
218 mut self,
219 converter: &'static dyn crate::oem::OemCpConverter,
220 ) -> Self {
221 self.oem_converter = converter;
222 self
223 }
224
225 #[cfg(feature = "cache")]
239 pub fn fat_cache(mut self, capacity_sectors: usize) -> Self {
240 if capacity_sectors == 0 {
241 self.fat_cache_capacity = None;
242 } else {
243 self.fat_cache_capacity = Some(capacity_sectors);
244 }
245 self
246 }
247
248 pub async fn open(self) -> Result<FatVolume<DATA>> {
250 #[cfg(feature = "cache")]
251 let cap = self.fat_cache_capacity;
252 #[cfg(not(feature = "cache"))]
253 let fs = FatVolume::open_with_providers(self.data, self.time_provider, self.oem_converter).await?;
254 #[cfg(feature = "cache")]
255 let mut fs = FatVolume::open_with_providers(self.data, self.time_provider, self.oem_converter).await?;
256 #[cfg(feature = "cache")]
257 if let Some(capacity) = cap {
258 let (fat_start, fat_size, fat_count, sector_size) = {
260 let data = fs.data.lock();
261 let sector_size = data.sector_size;
262 let (start, size, count) = match &fs.fat {
263 Fat::Fat12(f) => f.cache_layout(),
264 Fat::Fat16(f) => f.cache_layout(),
265 Fat::Fat32(f) => f.cache_layout(),
266 };
267 (start, size, count, sector_size)
268 };
269 let cache = crate::cache::FatSectorCache::new(
270 fat_start, fat_size, fat_count, sector_size, capacity,
271 );
272 fs.fat_cache = Some(Mutex::new(cache));
273 }
274 Ok(fs)
275 }
276}
277
278#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
289#[cfg_attr(feature = "defmt", derive(defmt::Format))]
290pub struct FsStatusFlags {
291 pub dirty: bool,
293 pub io_errors: bool,
295}
296
297pub(crate) const FSINFO_LEAD_SIG: u32 = 0x41615252; pub(crate) const FSINFO_STRUC_SIG: u32 = 0x61417272; pub(crate) const FSINFO_TRAIL_SIG: u32 = 0xAA550000;
301
302impl<DATA> FatVolume<DATA>
304where
305 DATA: Read + Seek,
306{
307 pub async fn open(data: DATA) -> Result<Self> {
314 Self::open_with_providers(
315 data,
316 &crate::time::DEFAULT_TIME_PROVIDER,
317 &crate::oem::DEFAULT_OEM_CONVERTER,
318 )
319 .await
320 }
321
322 pub fn builder(data: DATA) -> FatVolumeBuilder<DATA> {
325 FatVolumeBuilder::new(data)
326 }
327
328 pub(crate) async fn open_with_providers(
331 mut data: DATA,
332 time_provider: &'static dyn crate::time::TimeProvider,
333 oem_converter: &'static dyn crate::oem::OemCpConverter,
334 ) -> Result<Self> {
335 let bpb = data
339 .read_struct::<RawBpb>()
340 .await
341 .map_err(|source| Error::IoContext {
342 op: "boot sector",
343 sector: Some(0),
344 source: source.erase(),
345 })?;
346 let sector_size = bpb.bytes_per_sector.get() as usize;
347 if !matches!(sector_size, 512 | 1024 | 2048 | 4096) {
348 return Err(Error::CorruptFilesystem {
349 context: "BPB bytes_per_sector must be 512, 1024, 2048, or 4096",
350 });
351 }
352 if !bpb.sectors_per_cluster.is_power_of_two() || bpb.sectors_per_cluster > 128 {
353 return Err(Error::CorruptFilesystem {
354 context: "BPB sectors_per_cluster must be a power of two from 1 through 128",
355 });
356 }
357 let cluster_size = (bpb.sectors_per_cluster as usize) * sector_size;
358 if cluster_size > 32 * 1024 {
359 return Err(Error::CorruptFilesystem {
360 context: "BPB cluster size must not exceed 32 KiB",
361 });
362 }
363 let data = SectorCursor::new(data, sector_size, cluster_size);
364
365 let root_entry_count = u16::from_le_bytes(bpb.root_entry_count);
368 let sectors_per_fat_16 = u16::from_le_bytes(bpb.sectors_per_fat_16);
369
370 if root_entry_count == 0 && sectors_per_fat_16 == 0 {
371 Self::open_fat32(data, bpb, time_provider, oem_converter).await
373 } else {
374 Self::open_fat12_16(data, bpb, time_provider, oem_converter).await
376 }
377 }
378
379 async fn open_fat12_16(
381 mut data: SectorCursor<DATA>,
382 bpb: RawBpb,
383 time_provider: &'static dyn crate::time::TimeProvider,
384 oem_converter: &'static dyn crate::oem::OemCpConverter,
385 ) -> Result<Self> {
386 let bpb_ext16 = data
388 .read_struct::<RawBpbExt16>()
389 .await
390 .map_err(|source| Error::IoContext {
391 op: "boot sector (FAT12/16 extended fields)",
392 sector: Some(0),
393 source: source.erase(),
394 })?;
395
396 let signature = u16::from_le_bytes(bpb_ext16.signature_word);
398 if signature != 0xAA55 {
399 return Err(Error::InvalidBootSignature { found: signature });
400 }
401
402 if bpb.fat_count != 1 && bpb.fat_count != 2 {
408 return Err(Error::CorruptFilesystem {
409 context: "BPB fat_count must be 1 or 2",
410 });
411 }
412
413 let sector_size = data.sector_size;
414 #[cfg(feature = "alloc")]
415 let cluster_size = data.cluster_size;
416 let reserved_sectors = bpb.reserved_sector_count.get() as usize;
417 let fat_count = bpb.fat_count as usize;
418 let root_entry_count = u16::from_le_bytes(bpb.root_entry_count);
419 let sectors_per_fat = u16::from_le_bytes(bpb.sectors_per_fat_16) as usize;
420
421 let fat_start = reserved_sectors
426 .checked_mul(sector_size)
427 .ok_or(Error::CorruptFilesystem {
428 context: "reserved_sectors * sector_size",
429 })?;
430 let fat_total_size = fat_count
431 .checked_mul(sectors_per_fat)
432 .and_then(|v| v.checked_mul(sector_size))
433 .ok_or(Error::CorruptFilesystem {
434 context: "fat_count * sectors_per_fat * sector_size",
435 })?;
436 let root_dir_start = fat_start
437 .checked_add(fat_total_size)
438 .ok_or(Error::CorruptFilesystem {
439 context: "fat_start + fat_total_size",
440 })?;
441 let root_dir_size = (root_entry_count as usize) * 32;
442 let root_dir_sectors = root_dir_size.div_ceil(sector_size);
443
444 let data_start = root_dir_start
446 .checked_add(root_dir_sectors * sector_size)
447 .ok_or(Error::CorruptFilesystem {
448 context: "data_start arithmetic",
449 })?;
450
451 let total_sectors = if bpb.total_sectors_16 != [0, 0] {
453 u16::from_le_bytes(bpb.total_sectors_16) as u32
454 } else {
455 u32::from_le_bytes(bpb.total_sectors_32)
456 };
457 let metadata_sectors = reserved_sectors
461 .checked_add(fat_count.checked_mul(sectors_per_fat).ok_or(
462 Error::CorruptFilesystem {
463 context: "fat_count * sectors_per_fat",
464 },
465 )?)
466 .and_then(|v| v.checked_add(root_dir_sectors))
467 .ok_or(Error::CorruptFilesystem {
468 context: "metadata sector total",
469 })?;
470 let data_sectors = (total_sectors as usize).saturating_sub(metadata_sectors);
471 let count_of_clusters = data_sectors / (bpb.sectors_per_cluster as usize);
472
473 let (fat, max_cluster) = if count_of_clusters < 4085 {
475 let fat12 = Fat12::new(
477 fat_start,
478 sectors_per_fat * sector_size,
479 fat_count,
480 (count_of_clusters + 1) as u16, );
482 (Fat::Fat12(fat12), count_of_clusters as u32 + 1)
483 } else {
484 let fat16 = Fat16::new(
486 fat_start,
487 sectors_per_fat * sector_size,
488 fat_count,
489 (count_of_clusters + 1) as u16,
490 );
491 (Fat::Fat16(fat16), count_of_clusters as u32 + 1)
492 };
493 #[cfg(not(feature = "alloc"))]
494 let _ = max_cluster;
495
496 let ext = FatFsExt::Fat12_16(Fat12_16FsExt {
497 root_dir_start,
498 root_dir_size,
499 });
500
501 let info = FatInfo {
502 #[cfg(feature = "alloc")]
503 cluster_size,
504 data_start,
505 #[cfg(feature = "alloc")]
506 max_cluster,
507 };
508
509 let volume_info = VolumeInfo {
511 oem_name: bpb.oem_name,
512 volume_id: u32::from_le_bytes(bpb_ext16.volume_id),
513 volume_label: bpb_ext16.volume_label,
514 fs_type_str: bpb_ext16.fs_type,
515 };
516
517 Ok(Self {
518 data: Mutex::new(data),
519 info,
520 fat,
521 ext,
522 volume_info,
523 time_provider,
524 oem_converter,
525 #[cfg(feature = "cache")]
526 fat_cache: None,
527 })
528 }
529
530 async fn open_fat32(
532 mut data: SectorCursor<DATA>,
533 bpb: RawBpb,
534 time_provider: &'static dyn crate::time::TimeProvider,
535 oem_converter: &'static dyn crate::oem::OemCpConverter,
536 ) -> Result<Self> {
537 let bpb_ext32 = data
538 .read_struct::<RawBpbExt32>()
539 .await
540 .map_err(|source| Error::IoContext {
541 op: "boot sector (FAT32 extended fields)",
542 sector: Some(0),
543 source: source.erase(),
544 })?;
545
546 let signature = bpb_ext32.signature_word.get();
548 if signature != 0xAA55 {
549 return Err(Error::InvalidBootSignature { found: signature });
550 }
551 if bpb_ext32.version != [0, 0] {
552 return Err(Error::CorruptFilesystem {
553 context: "unsupported FAT32 filesystem version",
554 });
555 }
556
557 if bpb.fat_count != 1 && bpb.fat_count != 2 {
561 return Err(Error::CorruptFilesystem {
562 context: "BPB fat_count must be 1 or 2",
563 });
564 }
565
566 let fs_info_sec = Sector(bpb_ext32.fs_info_sector.get());
568 data.seek_sector(fs_info_sec).await?;
569 let fs_info = data
570 .read_struct::<RawFsInfo>()
571 .await
572 .map_err(|source| Error::IoContext {
573 op: "FSInfo",
574 sector: Some(fs_info_sec.0 as u64),
575 source: source.erase(),
576 })?;
577
578 let lead_sig = u32::from_le_bytes(fs_info.signature);
580 if lead_sig != FSINFO_LEAD_SIG {
581 return Err(Error::InvalidFsInfoSignature {
582 field: "FSI_LeadSig",
583 expected: FSINFO_LEAD_SIG,
584 found: lead_sig,
585 });
586 }
587
588 let struc_sig = u32::from_le_bytes(fs_info.structure_signature);
589 if struc_sig != FSINFO_STRUC_SIG {
590 return Err(Error::InvalidFsInfoSignature {
591 field: "FSI_StrucSig",
592 expected: FSINFO_STRUC_SIG,
593 found: struc_sig,
594 });
595 }
596
597 let trail_sig = fs_info.trail_signature.get();
598 if trail_sig != FSINFO_TRAIL_SIG {
599 return Err(Error::InvalidFsInfoSignature {
600 field: "FSI_TrailSig",
601 expected: FSINFO_TRAIL_SIG,
602 found: trail_sig,
603 });
604 }
605
606 let ext = FatFsExt::Fat32(Fat32FsExt {
607 fs_info_sec,
608 root_clus: Cluster(bpb_ext32.root_cluster.get()),
609 free_count: Cell::new(fs_info.free_count.get()),
610 next_free: Cell::new(Cluster(fs_info.next_free.get())),
611 });
612
613 #[cfg(feature = "alloc")]
614 let cluster_size = data.cluster_size;
615 let fat_start = Sector(bpb.reserved_sector_count.get()).to_bytes(data.sector_size);
619 let fat_size_per_fat = (bpb_ext32.sectors_per_fat_32.get() as usize)
620 .checked_mul(data.sector_size)
621 .ok_or(Error::CorruptFilesystem {
622 context: "sectors_per_fat_32 * sector_size",
623 })?;
624 let fat_size = (bpb.fat_count as usize)
625 .checked_mul(fat_size_per_fat)
626 .ok_or(Error::CorruptFilesystem {
627 context: "fat_count * sectors_per_fat_32",
628 })?;
629
630 let total_sectors = if bpb.total_sectors_16 != [0, 0] {
632 u16::from_le_bytes(bpb.total_sectors_16) as u32
633 } else {
634 u32::from_le_bytes(bpb.total_sectors_32)
635 };
636 let metadata_sectors = bpb.reserved_sector_count.get() as u64
638 + bpb_ext32.sectors_per_fat_32.get() as u64 * bpb.fat_count as u64;
639 let data_sectors = (total_sectors as u64).saturating_sub(metadata_sectors);
640 let max_cluster =
641 (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();
647 if !(2..=max_cluster).contains(&root_cluster) {
648 return Err(Error::ClusterOutOfBounds {
649 cluster: root_cluster,
650 max: max_cluster,
651 });
652 }
653
654 let fat = Fat::Fat32(Fat32::new(
655 fat_start,
656 fat_size_per_fat,
657 bpb.fat_count as usize,
658 max_cluster,
659 ));
660
661 let data_start = fat_start
662 .checked_add(fat_size)
663 .ok_or(Error::CorruptFilesystem {
664 context: "fat_start + fat_size",
665 })?;
666
667 let info = FatInfo {
668 #[cfg(feature = "alloc")]
669 cluster_size,
670 data_start,
671 #[cfg(feature = "alloc")]
672 max_cluster,
673 };
674
675 let volume_info = VolumeInfo {
677 oem_name: bpb.oem_name,
678 volume_id: u32::from_le_bytes(bpb_ext32.volume_id),
679 volume_label: bpb_ext32.volume_label,
680 fs_type_str: bpb_ext32.fs_type,
681 };
682
683 Ok(Self {
684 data: Mutex::new(data),
685 info,
686 fat,
687 ext,
688 volume_info,
689 time_provider,
690 oem_converter,
691 #[cfg(feature = "cache")]
692 fat_cache: None,
693 })
694 }
695
696 pub fn time_provider(&self) -> &dyn crate::time::TimeProvider {
698 self.time_provider
699 }
700
701 pub fn oem_converter(&self) -> &dyn crate::oem::OemCpConverter {
703 self.oem_converter
704 }
705
706 pub fn fat(&self) -> &Fat {
713 &self.fat
714 }
715
716 pub fn root_dir(&self) -> FatDir<'_, DATA> {
718 match &self.ext {
719 FatFsExt::Fat12_16(ext) => FatDir {
720 data: self,
721 cluster: Cluster(0), fixed_root: Some((ext.root_dir_start, ext.root_dir_size)),
723 },
724 FatFsExt::Fat32(ext) => FatDir {
725 data: self,
726 cluster: Cluster(ext.root_clus.0 as usize),
727 fixed_root: None,
728 },
729 }
730 }
731
732 pub fn fat_type(&self) -> FatType {
734 self.fat.fat_type()
735 }
736
737 pub fn volume_info(&self) -> &VolumeInfo {
742 &self.volume_info
743 }
744
745 #[cfg(feature = "write")]
749 pub(crate) fn fixed_root_dir_info(&self) -> Option<(usize, usize)> {
750 self.ext.fixed_root_dir()
751 }
752
753 #[cfg(feature = "write")]
759 pub(crate) fn is_fat32_root_cluster(&self, cluster: u32) -> bool {
760 matches!(&self.ext, FatFsExt::Fat32(ext) if ext.root_clus.0 == cluster)
761 }
762
763 pub async fn read_status_flags(&self) -> Result<FsStatusFlags> {
770 let (dirty, io_errors) = self.read_status_flags_routed().await?;
771 Ok(FsStatusFlags { dirty, io_errors })
772 }
773
774 pub async fn read_root_label(&self) -> Result<Option<[u8; 11]>> {
784 match self.find_root_label_entry().await? {
785 Some((_, raw)) => Ok(Some(unsafe { raw.file }.name)),
786 None => Ok(None),
787 }
788 }
789
790 pub(crate) async fn find_root_label_entry(
797 &self,
798 ) -> Result<Option<(usize, crate::raw::RawDirectoryEntry)>> {
799 use crate::raw::{DirEntryAttrFlags, RawDirectoryEntry};
800 let entry_size = core::mem::size_of::<RawDirectoryEntry>();
801 let mut data = self.data.lock();
802
803 let is_label =
804 |attr: u8| DirEntryAttrFlags::from_bits_retain(attr).is_volume_label_entry();
805
806 match &self.ext {
807 FatFsExt::Fat12_16(ext) => {
808 let end = ext.root_dir_start + ext.root_dir_size;
809 let mut pos = ext.root_dir_start;
810 while pos + entry_size <= end {
811 data.seek(SeekFrom::Start(pos as u64)).await?;
812 let raw = data.read_struct::<RawDirectoryEntry>().await?;
813 let bytes = unsafe { raw.bytes };
814 if bytes[0] == 0 {
815 return Ok(None);
816 }
817 if bytes[0] != 0xE5 && is_label(unsafe { raw.file }.attributes) {
818 return Ok(Some((pos, raw)));
819 }
820 pos += entry_size;
821 }
822 Ok(None)
823 }
824 FatFsExt::Fat32(ext) => {
825 let cluster_size = data.cluster_size;
826 let mut current = ext.root_clus.0 as usize;
827 let chain_limit = self.fat.max_cluster();
828 let mut steps: u32 = 0;
829 loop {
830 steps = steps.saturating_add(1);
831 if steps > chain_limit {
832 return Err(Error::ClusterLoop { cluster: current as u32 });
833 }
834 let cluster_start = Cluster(current).to_bytes(self.info.data_start, cluster_size);
835 let mut offset = 0;
836 while offset + entry_size <= cluster_size {
837 let pos = cluster_start + offset;
838 data.seek(SeekFrom::Start(pos as u64)).await?;
839 let raw = data.read_struct::<RawDirectoryEntry>().await?;
840 let bytes = unsafe { raw.bytes };
841 if bytes[0] == 0 {
842 return Ok(None);
843 }
844 if bytes[0] != 0xE5 && is_label(unsafe { raw.file }.attributes) {
845 return Ok(Some((pos, raw)));
846 }
847 offset += entry_size;
848 }
849 drop(data);
853 let next_cluster = self.next_cluster_routed(current).await?;
854 data = self.data.lock();
855 match next_cluster {
856 Some(next) => current = next as usize,
857 None => return Ok(None),
858 }
859 }
860 }
861 }
862 }
863
864 pub async fn open_path(&self, path: &str) -> Result<FileEntry> {
869 let mut current_dir = self.root_dir();
870 let mut last_component = None;
871
872 for component in VPath::new(path).components() {
873 let component = match component {
874 Component::Root | Component::Current => continue,
875 Component::Parent => return Err(Error::InvalidPath),
876 Component::Normal(component) => component,
877 };
878 if let Some(prev) = last_component.take() {
879 current_dir = current_dir.open_dir(prev).await?;
881 }
882 last_component = Some(component);
883 }
884
885 let final_name = last_component.ok_or(Error::InvalidPath)?;
887 current_dir.find(final_name).await?.ok_or(Error::EntryNotFound)
888 }
889
890 pub async fn open_file_path(&self, path: &str) -> Result<FileReader<'_, DATA>> {
895 let entry = self.open_path(path).await?;
896 FileReader::new(self, &entry)
897 }
898
899 pub async fn open_dir_path(&self, path: &str) -> Result<FatDir<'_, DATA>> {
904 let entry = self.open_path(path).await?;
905 if !entry.is_directory() {
906 return Err(Error::NotADirectory);
907 }
908 Ok(FatDir {
910 data: self,
911 cluster: entry.cluster(),
912 fixed_root: None,
913 })
914 }
915
916 pub fn open_dir_entry(&self, entry: &FileEntry) -> Result<FatDir<'_, DATA>> {
920 if !entry.is_directory() {
921 return Err(Error::NotADirectory);
922 }
923 Ok(FatDir {
924 data: self,
925 cluster: entry.cluster(),
926 fixed_root: None,
927 })
928 }
929}
930
931} #[cfg(feature = "cache")]
945sync_only! {
946 impl<DATA> FatVolume<DATA>
947 where
948 DATA: Read + Seek,
949 {
950 pub fn fat_cache(&self) -> Option<&Mutex<crate::cache::FatSectorCache>> {
958 self.fat_cache.as_ref()
959 }
960
961 pub fn with_cached_fat<R>(
994 &self,
995 f: impl FnOnce(&mut crate::cache::CachedFat<'_>, &mut SectorCursor<DATA>) -> R,
996 ) -> Option<R> {
997 let cache_mutex = self.fat_cache.as_ref()?;
998 let mut cache = cache_mutex.lock();
999 let mut data = self.data.lock();
1000 let mut cached = crate::cache::CachedFat::new(&mut cache, &self.fat);
1001 Some(f(&mut cached, &mut *data))
1002 }
1003
1004 pub fn with_fat_cache_locked<R>(
1020 &self,
1021 f: impl FnOnce(&mut crate::cache::FatSectorCache, &mut SectorCursor<DATA>) -> R,
1022 ) -> Option<R> {
1023 let cache_mutex = self.fat_cache.as_ref()?;
1024 let mut cache = cache_mutex.lock();
1025 let mut data = self.data.lock();
1026 Some(f(&mut cache, &mut *data))
1027 }
1028 }
1029}
1030
1031#[cfg(feature = "cache")]
1045sync_only! {
1046 impl<DATA> FatVolume<DATA>
1047 where
1048 DATA: Read + Seek,
1049 {
1050 pub(crate) fn next_cluster_routed(&self, cluster: usize) -> Result<Option<u32>> {
1057 use core::ops::DerefMut;
1058 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1059 let mut data = self.data.lock();
1060 if let Some(cache) = cache_guard.as_mut() {
1061 let mut cached = crate::cache::CachedFat::new(cache, &self.fat);
1062 cached.next_cluster(data.deref_mut(), cluster)
1063 } else {
1064 self.fat.next_cluster(data.deref_mut(), cluster)
1065 }
1066 }
1067
1068 pub(crate) fn read_status_flags_routed(&self) -> Result<(bool, bool)> {
1070 use core::ops::DerefMut;
1071 if matches!(self.fat, Fat::Fat12(_)) {
1074 return Ok((false, false));
1075 }
1076 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1077 let mut data = self.data.lock();
1078 match (&self.fat, cache_guard.as_deref_mut()) {
1079 (Fat::Fat16(_), Some(cache)) => {
1080 let val = cache.read_fat16_entry(data.deref_mut(), 1)?;
1081 Ok((val & 0x8000 == 0, val & 0x4000 == 0))
1082 }
1083 (Fat::Fat32(_), Some(cache)) => {
1084 let val = cache.read_fat32_entry(data.deref_mut(), 1)?;
1085 Ok((val & 0x0800_0000 == 0, val & 0x0400_0000 == 0))
1086 }
1087 _ => self.fat.read_status_flags(data.deref_mut()),
1088 }
1089 }
1090 }
1091}
1092
1093#[cfg(feature = "cache")]
1094async_only! {
1095 impl<DATA> FatVolume<DATA>
1096 where
1097 DATA: Read + Seek,
1098 {
1099 pub(crate) async fn next_cluster_routed(&self, cluster: usize) -> Result<Option<u32>> {
1101 use core::ops::DerefMut;
1102 let mut data = self.data.lock();
1103 self.fat.next_cluster(data.deref_mut(), cluster).await
1104 }
1105
1106 pub(crate) async fn read_status_flags_routed(&self) -> Result<(bool, bool)> {
1108 use core::ops::DerefMut;
1109 let mut data = self.data.lock();
1110 self.fat.read_status_flags(data.deref_mut()).await
1111 }
1112 }
1113}
1114
1115#[cfg(not(feature = "cache"))]
1119io_transform! {
1120 impl<DATA> FatVolume<DATA>
1121 where
1122 DATA: Read + Seek,
1123 {
1124 pub(crate) async fn next_cluster_routed(&self, cluster: usize) -> Result<Option<u32>> {
1125 use core::ops::DerefMut;
1126 let mut data = self.data.lock();
1127 self.fat.next_cluster(data.deref_mut(), cluster).await
1128 }
1129
1130 pub(crate) async fn read_status_flags_routed(&self) -> Result<(bool, bool)> {
1131 use core::ops::DerefMut;
1132 let mut data = self.data.lock();
1133 self.fat.read_status_flags(data.deref_mut()).await
1134 }
1135 }
1136}
1137
1138#[cfg(all(feature = "cache", feature = "write"))]
1157sync_only! {
1158 impl<DATA> FatVolume<DATA>
1159 where
1160 DATA: Read + super::io::Write + Seek,
1161 {
1162 pub(crate) fn write_clus_routed(&self, cluster: usize, value: u32) -> Result<()> {
1164 use core::ops::DerefMut;
1165 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1166 let mut data = self.data.lock();
1167 if let Some(ref mut cache) = cache_guard {
1168 match self.fat.fat_type() {
1169 FatType::Fat12 => cache.write_fat12_entry(data.deref_mut(), cluster, value as u16),
1170 FatType::Fat16 => cache.write_fat16_entry(data.deref_mut(), cluster, value as u16),
1171 FatType::Fat32 => cache.write_fat32_entry(data.deref_mut(), cluster, value),
1172 }
1173 } else {
1174 match &self.fat {
1175 Fat::Fat12(f) => f.write_clus(data.deref_mut(), cluster, value as u16),
1176 Fat::Fat16(f) => f.write_clus(data.deref_mut(), cluster, value as u16),
1177 Fat::Fat32(f) => f.write_clus(data.deref_mut(), cluster, value),
1178 }
1179 }
1180 }
1181
1182 pub(crate) fn allocate_cluster_routed(&self, hint: u32) -> Result<u32> {
1185 use core::ops::DerefMut;
1186 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1187 let mut data = self.data.lock();
1188 if let Some(ref mut cache) = cache_guard {
1189 allocate_cluster_via_cache(cache, &self.fat, data.deref_mut(), hint)
1190 } else {
1191 match &self.fat {
1192 Fat::Fat12(f) => f.allocate_cluster(data.deref_mut(), hint as u16).map(|c| c as u32),
1193 Fat::Fat16(f) => f.allocate_cluster(data.deref_mut(), hint as u16).map(|c| c as u32),
1194 Fat::Fat32(f) => f.allocate_cluster(data.deref_mut(), hint),
1195 }
1196 }
1197 }
1198
1199 pub(crate) fn free_chain_routed(&self, start: u32) -> Result<u32> {
1202 use core::ops::DerefMut;
1203 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1204 let mut data = self.data.lock();
1205 if let Some(ref mut cache) = cache_guard {
1206 free_chain_via_cache(cache, &self.fat, data.deref_mut(), start)
1207 } else {
1208 self.fat.free_chain(data.deref_mut(), start as usize)
1209 }
1210 }
1211
1212 pub(crate) fn truncate_chain_routed(&self, cluster: u32) -> Result<u32> {
1215 use core::ops::DerefMut;
1216 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1217 let mut data = self.data.lock();
1218 if let Some(ref mut cache) = cache_guard {
1219 truncate_chain_via_cache(cache, &self.fat, data.deref_mut(), cluster)
1220 } else {
1221 self.fat.truncate_chain(data.deref_mut(), cluster as usize)
1222 }
1223 }
1224
1225 }
1226}
1227
1228#[cfg(all(feature = "cache", feature = "write"))]
1229async_only! {
1230 impl<DATA> FatVolume<DATA>
1231 where
1232 DATA: Read + super::io::Write + Seek,
1233 {
1234 pub(crate) async fn write_clus_routed(&self, cluster: usize, value: u32) -> Result<()> {
1236 use core::ops::DerefMut;
1237 let mut data = self.data.lock();
1238 match &self.fat {
1239 Fat::Fat12(f) => f.write_clus(data.deref_mut(), cluster, value as u16).await,
1240 Fat::Fat16(f) => f.write_clus(data.deref_mut(), cluster, value as u16).await,
1241 Fat::Fat32(f) => f.write_clus(data.deref_mut(), cluster, value).await,
1242 }
1243 }
1244
1245 pub(crate) async fn allocate_cluster_routed(&self, hint: u32) -> Result<u32> {
1246 use core::ops::DerefMut;
1247 let mut data = self.data.lock();
1248 match &self.fat {
1249 Fat::Fat12(f) => f.allocate_cluster(data.deref_mut(), hint as u16).await.map(|c| c as u32),
1250 Fat::Fat16(f) => f.allocate_cluster(data.deref_mut(), hint as u16).await.map(|c| c as u32),
1251 Fat::Fat32(f) => f.allocate_cluster(data.deref_mut(), hint).await,
1252 }
1253 }
1254
1255 pub(crate) async fn free_chain_routed(&self, start: u32) -> Result<u32> {
1256 use core::ops::DerefMut;
1257 let mut data = self.data.lock();
1258 self.fat.free_chain(data.deref_mut(), start as usize).await
1259 }
1260
1261 pub(crate) async fn truncate_chain_routed(&self, cluster: u32) -> Result<u32> {
1262 use core::ops::DerefMut;
1263 let mut data = self.data.lock();
1264 self.fat.truncate_chain(data.deref_mut(), cluster as usize).await
1265 }
1266
1267 }
1268}
1269
1270#[cfg(all(not(feature = "cache"), feature = "write"))]
1273io_transform! {
1274 impl<DATA> FatVolume<DATA>
1275 where
1276 DATA: Read + super::io::Write + Seek,
1277 {
1278 pub(crate) async fn write_clus_routed(&self, cluster: usize, value: u32) -> Result<()> {
1279 use core::ops::DerefMut;
1280 let mut data = self.data.lock();
1281 match &self.fat {
1282 Fat::Fat12(f) => f.write_clus(data.deref_mut(), cluster, value as u16).await,
1283 Fat::Fat16(f) => f.write_clus(data.deref_mut(), cluster, value as u16).await,
1284 Fat::Fat32(f) => f.write_clus(data.deref_mut(), cluster, value).await,
1285 }
1286 }
1287
1288 pub(crate) async fn allocate_cluster_routed(&self, hint: u32) -> Result<u32> {
1289 use core::ops::DerefMut;
1290 let mut data = self.data.lock();
1291 match &self.fat {
1292 Fat::Fat12(f) => f.allocate_cluster(data.deref_mut(), hint as u16).await.map(|c| c as u32),
1293 Fat::Fat16(f) => f.allocate_cluster(data.deref_mut(), hint as u16).await.map(|c| c as u32),
1294 Fat::Fat32(f) => f.allocate_cluster(data.deref_mut(), hint).await,
1295 }
1296 }
1297
1298 pub(crate) async fn free_chain_routed(&self, start: u32) -> Result<u32> {
1299 use core::ops::DerefMut;
1300 let mut data = self.data.lock();
1301 self.fat.free_chain(data.deref_mut(), start as usize).await
1302 }
1303
1304 pub(crate) async fn truncate_chain_routed(&self, cluster: u32) -> Result<u32> {
1305 use core::ops::DerefMut;
1306 let mut data = self.data.lock();
1307 self.fat.truncate_chain(data.deref_mut(), cluster as usize).await
1308 }
1309
1310 }
1311}
1312
1313#[cfg(all(feature = "cache", feature = "write"))]
1320sync_only! {
1321
1322fn allocate_cluster_via_cache<T>(
1323 cache: &mut crate::cache::FatSectorCache,
1324 fat: &Fat,
1325 data: &mut T,
1326 hint: u32,
1327) -> Result<u32>
1328where
1329 T: super::io::Read + super::io::Write + super::io::Seek,
1330{
1331 const FIRST: u32 = 2;
1332 let max_cluster = fat.max_cluster();
1333 let start = if hint >= FIRST && hint <= max_cluster {
1334 hint
1335 } else {
1336 FIRST
1337 };
1338
1339 let scan = |cache: &mut crate::cache::FatSectorCache,
1340 data: &mut T,
1341 fat: &Fat,
1342 lo: u32,
1343 hi: u32|
1344 -> Result<Option<u32>> {
1345 for c in lo..=hi {
1346 let free = match fat.fat_type() {
1347 FatType::Fat12 => (cache.read_fat12_entry(data, c as usize)? & 0x0FFF) == 0,
1348 FatType::Fat16 => cache.read_fat16_entry(data, c as usize)? == 0,
1349 FatType::Fat32 => (cache.read_fat32_entry(data, c as usize)? & 0x0FFF_FFFF) == 0,
1350 };
1351 if free {
1352 return Ok(Some(c));
1353 }
1354 }
1355 Ok(None)
1356 };
1357
1358 let claim =
1359 |cache: &mut crate::cache::FatSectorCache, data: &mut T, fat: &Fat, c: u32| -> Result<()> {
1360 match fat.fat_type() {
1361 FatType::Fat12 => cache.write_fat12_entry(data, c as usize, 0x0FF8),
1362 FatType::Fat16 => cache.write_fat16_entry(data, c as usize, 0xFFF8),
1363 FatType::Fat32 => cache.write_fat32_entry(data, c as usize, 0x0FFF_FFF8),
1364 }
1365 };
1366
1367 if let Some(c) = scan(cache, data, fat, start, max_cluster)? {
1368 claim(cache, data, fat, c)?;
1369 return Ok(c);
1370 }
1371 if start > FIRST
1372 && let Some(c) = scan(cache, data, fat, FIRST, start - 1)?
1373 {
1374 claim(cache, data, fat, c)?;
1375 return Ok(c);
1376 }
1377 Err(Error::NoFreeSpace)
1378}
1379
1380#[cfg(all(feature = "cache", feature = "write"))]
1381fn free_chain_via_cache<T>(
1382 cache: &mut crate::cache::FatSectorCache,
1383 fat: &Fat,
1384 data: &mut T,
1385 start: u32,
1386) -> Result<u32>
1387where
1388 T: super::io::Read + super::io::Write + super::io::Seek,
1389{
1390 const FIRST: u32 = 2;
1391 let max_cluster = fat.max_cluster();
1392 let mut count = 0u32;
1393 let mut current = start;
1394 loop {
1395 if current < FIRST || current > max_cluster {
1396 break;
1397 }
1398 let next = read_fat_entry_via_cache(cache, fat, data, current as usize)?;
1399 write_fat_entry_via_cache(cache, fat, data, current as usize, 0)?;
1400 count += 1;
1401 if is_eoc(fat.fat_type(), next) || is_bad(fat.fat_type(), next) || next == 0 {
1402 break;
1403 }
1404 current = next;
1405 }
1406 Ok(count)
1407}
1408
1409#[cfg(all(feature = "cache", feature = "write"))]
1410fn truncate_chain_via_cache<T>(
1411 cache: &mut crate::cache::FatSectorCache,
1412 fat: &Fat,
1413 data: &mut T,
1414 cluster: u32,
1415) -> Result<u32>
1416where
1417 T: super::io::Read + super::io::Write + super::io::Seek,
1418{
1419 const FIRST: u32 = 2;
1420 let max_cluster = fat.max_cluster();
1421 if cluster < FIRST || cluster > max_cluster {
1422 return Ok(0);
1423 }
1424 let next = read_fat_entry_via_cache(cache, fat, data, cluster as usize)?;
1425 let eoc = match fat.fat_type() {
1426 FatType::Fat12 => 0x0FF8,
1427 FatType::Fat16 => 0xFFF8,
1428 FatType::Fat32 => 0x0FFF_FFF8,
1429 };
1430 write_fat_entry_via_cache(cache, fat, data, cluster as usize, eoc)?;
1431 if !is_eoc(fat.fat_type(), next) && next >= FIRST && next <= max_cluster {
1432 free_chain_via_cache(cache, fat, data, next)
1433 } else {
1434 Ok(0)
1435 }
1436}
1437
1438#[cfg(all(feature = "cache", feature = "write"))]
1439fn read_fat_entry_via_cache<T>(
1440 cache: &mut crate::cache::FatSectorCache,
1441 fat: &Fat,
1442 data: &mut T,
1443 cluster: usize,
1444) -> Result<u32>
1445where
1446 T: super::io::Read + super::io::Seek,
1447{
1448 Ok(match fat.fat_type() {
1449 FatType::Fat12 => (cache.read_fat12_entry(data, cluster)? & 0x0FFF) as u32,
1450 FatType::Fat16 => cache.read_fat16_entry(data, cluster)? as u32,
1451 FatType::Fat32 => cache.read_fat32_entry(data, cluster)? & 0x0FFF_FFFF,
1452 })
1453}
1454
1455#[cfg(all(feature = "cache", feature = "write"))]
1456fn write_fat_entry_via_cache<T>(
1457 cache: &mut crate::cache::FatSectorCache,
1458 fat: &Fat,
1459 data: &mut T,
1460 cluster: usize,
1461 value: u32,
1462) -> Result<()>
1463where
1464 T: super::io::Read + super::io::Write + super::io::Seek,
1465{
1466 match fat.fat_type() {
1467 FatType::Fat12 => cache.write_fat12_entry(data, cluster, value as u16),
1468 FatType::Fat16 => cache.write_fat16_entry(data, cluster, value as u16),
1469 FatType::Fat32 => cache.write_fat32_entry(data, cluster, value),
1470 }
1471}
1472
1473#[cfg(all(feature = "cache", feature = "write"))]
1474fn is_eoc(ty: FatType, value: u32) -> bool {
1475 match ty {
1476 FatType::Fat12 => value >= 0x0FF8,
1477 FatType::Fat16 => value >= 0xFFF8,
1478 FatType::Fat32 => value >= 0x0FFF_FFF8,
1479 }
1480}
1481
1482#[cfg(all(feature = "cache", feature = "write"))]
1483fn is_bad(ty: FatType, value: u32) -> bool {
1484 match ty {
1485 FatType::Fat12 => value == 0x0FF7,
1486 FatType::Fat16 => value == 0xFFF7,
1487 FatType::Fat32 => value == 0x0FFF_FFF7,
1488 }
1489}
1490
1491} #[cfg(all(feature = "cache", feature = "write"))]
1502sync_only! {
1503 impl<DATA> FatVolume<DATA>
1504 where
1505 DATA: Read + super::io::Write + Seek,
1506 {
1507 pub fn flush(&self) -> Result<()> {
1515 use core::ops::DerefMut;
1516 if let Some(cache_mutex) = &self.fat_cache {
1517 let mut cache = cache_mutex.lock();
1518 let mut data = self.data.lock();
1519 cache.flush(data.deref_mut())?;
1520 }
1521 Ok(())
1522 }
1523 }
1524}