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);
616 let fat_size_per_fat =
617 Sector(bpb_ext32.sectors_per_fat_32.get()).to_bytes(data.sector_size);
618 let fat_size = bpb.fat_count as usize * fat_size_per_fat;
619
620 let total_sectors = if bpb.total_sectors_16 != [0, 0] {
622 u16::from_le_bytes(bpb.total_sectors_16) as u32
623 } else {
624 u32::from_le_bytes(bpb.total_sectors_32)
625 };
626 let reserved_sectors = bpb.reserved_sector_count.get() as u32;
627 let fat_sectors = bpb_ext32.sectors_per_fat_32.get() * bpb.fat_count as u32;
628 let data_sectors = total_sectors.saturating_sub(reserved_sectors + fat_sectors);
629 let max_cluster = (data_sectors / bpb.sectors_per_cluster as u32) + 1; let fat = Fat::Fat32(Fat32::new(
632 fat_start,
633 fat_size_per_fat,
634 bpb.fat_count as usize,
635 max_cluster,
636 ));
637
638 let info = FatInfo {
639 #[cfg(feature = "alloc")]
640 cluster_size,
641 data_start: fat_start + fat_size,
642 #[cfg(feature = "alloc")]
643 max_cluster,
644 };
645
646 let volume_info = VolumeInfo {
648 oem_name: bpb.oem_name,
649 volume_id: u32::from_le_bytes(bpb_ext32.volume_id),
650 volume_label: bpb_ext32.volume_label,
651 fs_type_str: bpb_ext32.fs_type,
652 };
653
654 Ok(Self {
655 data: Mutex::new(data),
656 info,
657 fat,
658 ext,
659 volume_info,
660 time_provider,
661 oem_converter,
662 #[cfg(feature = "cache")]
663 fat_cache: None,
664 })
665 }
666
667 pub fn time_provider(&self) -> &dyn crate::time::TimeProvider {
669 self.time_provider
670 }
671
672 pub fn oem_converter(&self) -> &dyn crate::oem::OemCpConverter {
674 self.oem_converter
675 }
676
677 pub fn fat(&self) -> &Fat {
684 &self.fat
685 }
686
687 pub fn root_dir(&self) -> FatDir<'_, DATA> {
689 match &self.ext {
690 FatFsExt::Fat12_16(ext) => FatDir {
691 data: self,
692 cluster: Cluster(0), fixed_root: Some((ext.root_dir_start, ext.root_dir_size)),
694 },
695 FatFsExt::Fat32(ext) => FatDir {
696 data: self,
697 cluster: Cluster(ext.root_clus.0 as usize),
698 fixed_root: None,
699 },
700 }
701 }
702
703 pub fn fat_type(&self) -> FatType {
705 self.fat.fat_type()
706 }
707
708 pub fn volume_info(&self) -> &VolumeInfo {
713 &self.volume_info
714 }
715
716 #[cfg(feature = "write")]
720 pub(crate) fn fixed_root_dir_info(&self) -> Option<(usize, usize)> {
721 self.ext.fixed_root_dir()
722 }
723
724 #[cfg(feature = "write")]
730 pub(crate) fn is_fat32_root_cluster(&self, cluster: u32) -> bool {
731 matches!(&self.ext, FatFsExt::Fat32(ext) if ext.root_clus.0 == cluster)
732 }
733
734 pub async fn read_status_flags(&self) -> Result<FsStatusFlags> {
741 let (dirty, io_errors) = self.read_status_flags_routed().await?;
742 Ok(FsStatusFlags { dirty, io_errors })
743 }
744
745 pub async fn read_root_label(&self) -> Result<Option<[u8; 11]>> {
755 match self.find_root_label_entry().await? {
756 Some((_, raw)) => Ok(Some(unsafe { raw.file }.name)),
757 None => Ok(None),
758 }
759 }
760
761 pub(crate) async fn find_root_label_entry(
768 &self,
769 ) -> Result<Option<(usize, crate::raw::RawDirectoryEntry)>> {
770 use crate::raw::{DirEntryAttrFlags, RawDirectoryEntry};
771 let entry_size = core::mem::size_of::<RawDirectoryEntry>();
772 let mut data = self.data.lock();
773
774 let is_label =
775 |attr: u8| DirEntryAttrFlags::from_bits_retain(attr).is_volume_label_entry();
776
777 match &self.ext {
778 FatFsExt::Fat12_16(ext) => {
779 let end = ext.root_dir_start + ext.root_dir_size;
780 let mut pos = ext.root_dir_start;
781 while pos + entry_size <= end {
782 data.seek(SeekFrom::Start(pos as u64)).await?;
783 let raw = data.read_struct::<RawDirectoryEntry>().await?;
784 let bytes = unsafe { raw.bytes };
785 if bytes[0] == 0 {
786 return Ok(None);
787 }
788 if bytes[0] != 0xE5 && is_label(unsafe { raw.file }.attributes) {
789 return Ok(Some((pos, raw)));
790 }
791 pos += entry_size;
792 }
793 Ok(None)
794 }
795 FatFsExt::Fat32(ext) => {
796 let cluster_size = data.cluster_size;
797 let mut current = ext.root_clus.0 as usize;
798 let chain_limit = self.fat.max_cluster();
799 let mut steps: u32 = 0;
800 loop {
801 steps = steps.saturating_add(1);
802 if steps > chain_limit {
803 return Err(Error::ClusterLoop { cluster: current as u32 });
804 }
805 let cluster_start = Cluster(current).to_bytes(self.info.data_start, cluster_size);
806 let mut offset = 0;
807 while offset + entry_size <= cluster_size {
808 let pos = cluster_start + offset;
809 data.seek(SeekFrom::Start(pos as u64)).await?;
810 let raw = data.read_struct::<RawDirectoryEntry>().await?;
811 let bytes = unsafe { raw.bytes };
812 if bytes[0] == 0 {
813 return Ok(None);
814 }
815 if bytes[0] != 0xE5 && is_label(unsafe { raw.file }.attributes) {
816 return Ok(Some((pos, raw)));
817 }
818 offset += entry_size;
819 }
820 drop(data);
824 let next_cluster = self.next_cluster_routed(current).await?;
825 data = self.data.lock();
826 match next_cluster {
827 Some(next) => current = next as usize,
828 None => return Ok(None),
829 }
830 }
831 }
832 }
833 }
834
835 pub async fn open_path(&self, path: &str) -> Result<FileEntry> {
840 let mut current_dir = self.root_dir();
841 let mut last_component = None;
842
843 for component in VPath::new(path).components() {
844 let component = match component {
845 Component::Root | Component::Current => continue,
846 Component::Parent => return Err(Error::InvalidPath),
847 Component::Normal(component) => component,
848 };
849 if let Some(prev) = last_component.take() {
850 current_dir = current_dir.open_dir(prev).await?;
852 }
853 last_component = Some(component);
854 }
855
856 let final_name = last_component.ok_or(Error::InvalidPath)?;
858 current_dir.find(final_name).await?.ok_or(Error::EntryNotFound)
859 }
860
861 pub async fn open_file_path(&self, path: &str) -> Result<FileReader<'_, DATA>> {
866 let entry = self.open_path(path).await?;
867 FileReader::new(self, &entry)
868 }
869
870 pub async fn open_dir_path(&self, path: &str) -> Result<FatDir<'_, DATA>> {
875 let entry = self.open_path(path).await?;
876 if !entry.is_directory() {
877 return Err(Error::NotADirectory);
878 }
879 Ok(FatDir {
881 data: self,
882 cluster: entry.cluster(),
883 fixed_root: None,
884 })
885 }
886
887 pub fn open_dir_entry(&self, entry: &FileEntry) -> Result<FatDir<'_, DATA>> {
891 if !entry.is_directory() {
892 return Err(Error::NotADirectory);
893 }
894 Ok(FatDir {
895 data: self,
896 cluster: entry.cluster(),
897 fixed_root: None,
898 })
899 }
900}
901
902} #[cfg(feature = "cache")]
916sync_only! {
917 impl<DATA> FatVolume<DATA>
918 where
919 DATA: Read + Seek,
920 {
921 pub fn fat_cache(&self) -> Option<&Mutex<crate::cache::FatSectorCache>> {
929 self.fat_cache.as_ref()
930 }
931
932 pub fn with_cached_fat<R>(
965 &self,
966 f: impl FnOnce(&mut crate::cache::CachedFat<'_>, &mut SectorCursor<DATA>) -> R,
967 ) -> Option<R> {
968 let cache_mutex = self.fat_cache.as_ref()?;
969 let mut cache = cache_mutex.lock();
970 let mut data = self.data.lock();
971 let mut cached = crate::cache::CachedFat::new(&mut cache, &self.fat);
972 Some(f(&mut cached, &mut *data))
973 }
974
975 pub fn with_fat_cache_locked<R>(
991 &self,
992 f: impl FnOnce(&mut crate::cache::FatSectorCache, &mut SectorCursor<DATA>) -> R,
993 ) -> Option<R> {
994 let cache_mutex = self.fat_cache.as_ref()?;
995 let mut cache = cache_mutex.lock();
996 let mut data = self.data.lock();
997 Some(f(&mut cache, &mut *data))
998 }
999 }
1000}
1001
1002#[cfg(feature = "cache")]
1016sync_only! {
1017 impl<DATA> FatVolume<DATA>
1018 where
1019 DATA: Read + Seek,
1020 {
1021 pub(crate) fn next_cluster_routed(&self, cluster: usize) -> Result<Option<u32>> {
1028 use core::ops::DerefMut;
1029 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1030 let mut data = self.data.lock();
1031 if let Some(cache) = cache_guard.as_mut() {
1032 let mut cached = crate::cache::CachedFat::new(cache, &self.fat);
1033 cached.next_cluster(data.deref_mut(), cluster)
1034 } else {
1035 self.fat.next_cluster(data.deref_mut(), cluster)
1036 }
1037 }
1038
1039 pub(crate) fn read_status_flags_routed(&self) -> Result<(bool, bool)> {
1041 use core::ops::DerefMut;
1042 if matches!(self.fat, Fat::Fat12(_)) {
1045 return Ok((false, false));
1046 }
1047 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1048 let mut data = self.data.lock();
1049 match (&self.fat, cache_guard.as_deref_mut()) {
1050 (Fat::Fat16(_), Some(cache)) => {
1051 let val = cache.read_fat16_entry(data.deref_mut(), 1)?;
1052 Ok((val & 0x8000 == 0, val & 0x4000 == 0))
1053 }
1054 (Fat::Fat32(_), Some(cache)) => {
1055 let val = cache.read_fat32_entry(data.deref_mut(), 1)?;
1056 Ok((val & 0x0800_0000 == 0, val & 0x0400_0000 == 0))
1057 }
1058 _ => self.fat.read_status_flags(data.deref_mut()),
1059 }
1060 }
1061 }
1062}
1063
1064#[cfg(feature = "cache")]
1065async_only! {
1066 impl<DATA> FatVolume<DATA>
1067 where
1068 DATA: Read + Seek,
1069 {
1070 pub(crate) async fn next_cluster_routed(&self, cluster: usize) -> Result<Option<u32>> {
1072 use core::ops::DerefMut;
1073 let mut data = self.data.lock();
1074 self.fat.next_cluster(data.deref_mut(), cluster).await
1075 }
1076
1077 pub(crate) async fn read_status_flags_routed(&self) -> Result<(bool, bool)> {
1079 use core::ops::DerefMut;
1080 let mut data = self.data.lock();
1081 self.fat.read_status_flags(data.deref_mut()).await
1082 }
1083 }
1084}
1085
1086#[cfg(not(feature = "cache"))]
1090io_transform! {
1091 impl<DATA> FatVolume<DATA>
1092 where
1093 DATA: Read + Seek,
1094 {
1095 pub(crate) async fn next_cluster_routed(&self, cluster: usize) -> Result<Option<u32>> {
1096 use core::ops::DerefMut;
1097 let mut data = self.data.lock();
1098 self.fat.next_cluster(data.deref_mut(), cluster).await
1099 }
1100
1101 pub(crate) async fn read_status_flags_routed(&self) -> Result<(bool, bool)> {
1102 use core::ops::DerefMut;
1103 let mut data = self.data.lock();
1104 self.fat.read_status_flags(data.deref_mut()).await
1105 }
1106 }
1107}
1108
1109#[cfg(all(feature = "cache", feature = "write"))]
1128sync_only! {
1129 impl<DATA> FatVolume<DATA>
1130 where
1131 DATA: Read + super::io::Write + Seek,
1132 {
1133 pub(crate) fn write_clus_routed(&self, cluster: usize, value: u32) -> Result<()> {
1135 use core::ops::DerefMut;
1136 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1137 let mut data = self.data.lock();
1138 if let Some(ref mut cache) = cache_guard {
1139 match self.fat.fat_type() {
1140 FatType::Fat12 => cache.write_fat12_entry(data.deref_mut(), cluster, value as u16),
1141 FatType::Fat16 => cache.write_fat16_entry(data.deref_mut(), cluster, value as u16),
1142 FatType::Fat32 => cache.write_fat32_entry(data.deref_mut(), cluster, value),
1143 }
1144 } else {
1145 match &self.fat {
1146 Fat::Fat12(f) => f.write_clus(data.deref_mut(), cluster, value as u16),
1147 Fat::Fat16(f) => f.write_clus(data.deref_mut(), cluster, value as u16),
1148 Fat::Fat32(f) => f.write_clus(data.deref_mut(), cluster, value),
1149 }
1150 }
1151 }
1152
1153 pub(crate) fn allocate_cluster_routed(&self, hint: u32) -> Result<u32> {
1156 use core::ops::DerefMut;
1157 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1158 let mut data = self.data.lock();
1159 if let Some(ref mut cache) = cache_guard {
1160 allocate_cluster_via_cache(cache, &self.fat, data.deref_mut(), hint)
1161 } else {
1162 match &self.fat {
1163 Fat::Fat12(f) => f.allocate_cluster(data.deref_mut(), hint as u16).map(|c| c as u32),
1164 Fat::Fat16(f) => f.allocate_cluster(data.deref_mut(), hint as u16).map(|c| c as u32),
1165 Fat::Fat32(f) => f.allocate_cluster(data.deref_mut(), hint),
1166 }
1167 }
1168 }
1169
1170 pub(crate) fn free_chain_routed(&self, start: u32) -> Result<u32> {
1173 use core::ops::DerefMut;
1174 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1175 let mut data = self.data.lock();
1176 if let Some(ref mut cache) = cache_guard {
1177 free_chain_via_cache(cache, &self.fat, data.deref_mut(), start)
1178 } else {
1179 self.fat.free_chain(data.deref_mut(), start as usize)
1180 }
1181 }
1182
1183 pub(crate) fn truncate_chain_routed(&self, cluster: u32) -> Result<u32> {
1186 use core::ops::DerefMut;
1187 let mut cache_guard = self.fat_cache.as_ref().map(|m| m.lock());
1188 let mut data = self.data.lock();
1189 if let Some(ref mut cache) = cache_guard {
1190 truncate_chain_via_cache(cache, &self.fat, data.deref_mut(), cluster)
1191 } else {
1192 self.fat.truncate_chain(data.deref_mut(), cluster as usize)
1193 }
1194 }
1195
1196 }
1197}
1198
1199#[cfg(all(feature = "cache", feature = "write"))]
1200async_only! {
1201 impl<DATA> FatVolume<DATA>
1202 where
1203 DATA: Read + super::io::Write + Seek,
1204 {
1205 pub(crate) async fn write_clus_routed(&self, cluster: usize, value: u32) -> Result<()> {
1207 use core::ops::DerefMut;
1208 let mut data = self.data.lock();
1209 match &self.fat {
1210 Fat::Fat12(f) => f.write_clus(data.deref_mut(), cluster, value as u16).await,
1211 Fat::Fat16(f) => f.write_clus(data.deref_mut(), cluster, value as u16).await,
1212 Fat::Fat32(f) => f.write_clus(data.deref_mut(), cluster, value).await,
1213 }
1214 }
1215
1216 pub(crate) async fn allocate_cluster_routed(&self, hint: u32) -> Result<u32> {
1217 use core::ops::DerefMut;
1218 let mut data = self.data.lock();
1219 match &self.fat {
1220 Fat::Fat12(f) => f.allocate_cluster(data.deref_mut(), hint as u16).await.map(|c| c as u32),
1221 Fat::Fat16(f) => f.allocate_cluster(data.deref_mut(), hint as u16).await.map(|c| c as u32),
1222 Fat::Fat32(f) => f.allocate_cluster(data.deref_mut(), hint).await,
1223 }
1224 }
1225
1226 pub(crate) async fn free_chain_routed(&self, start: u32) -> Result<u32> {
1227 use core::ops::DerefMut;
1228 let mut data = self.data.lock();
1229 self.fat.free_chain(data.deref_mut(), start as usize).await
1230 }
1231
1232 pub(crate) async fn truncate_chain_routed(&self, cluster: u32) -> Result<u32> {
1233 use core::ops::DerefMut;
1234 let mut data = self.data.lock();
1235 self.fat.truncate_chain(data.deref_mut(), cluster as usize).await
1236 }
1237
1238 }
1239}
1240
1241#[cfg(all(not(feature = "cache"), feature = "write"))]
1244io_transform! {
1245 impl<DATA> FatVolume<DATA>
1246 where
1247 DATA: Read + super::io::Write + Seek,
1248 {
1249 pub(crate) async fn write_clus_routed(&self, cluster: usize, value: u32) -> Result<()> {
1250 use core::ops::DerefMut;
1251 let mut data = self.data.lock();
1252 match &self.fat {
1253 Fat::Fat12(f) => f.write_clus(data.deref_mut(), cluster, value as u16).await,
1254 Fat::Fat16(f) => f.write_clus(data.deref_mut(), cluster, value as u16).await,
1255 Fat::Fat32(f) => f.write_clus(data.deref_mut(), cluster, value).await,
1256 }
1257 }
1258
1259 pub(crate) async fn allocate_cluster_routed(&self, hint: u32) -> Result<u32> {
1260 use core::ops::DerefMut;
1261 let mut data = self.data.lock();
1262 match &self.fat {
1263 Fat::Fat12(f) => f.allocate_cluster(data.deref_mut(), hint as u16).await.map(|c| c as u32),
1264 Fat::Fat16(f) => f.allocate_cluster(data.deref_mut(), hint as u16).await.map(|c| c as u32),
1265 Fat::Fat32(f) => f.allocate_cluster(data.deref_mut(), hint).await,
1266 }
1267 }
1268
1269 pub(crate) async fn free_chain_routed(&self, start: u32) -> Result<u32> {
1270 use core::ops::DerefMut;
1271 let mut data = self.data.lock();
1272 self.fat.free_chain(data.deref_mut(), start as usize).await
1273 }
1274
1275 pub(crate) async fn truncate_chain_routed(&self, cluster: u32) -> Result<u32> {
1276 use core::ops::DerefMut;
1277 let mut data = self.data.lock();
1278 self.fat.truncate_chain(data.deref_mut(), cluster as usize).await
1279 }
1280
1281 }
1282}
1283
1284#[cfg(all(feature = "cache", feature = "write"))]
1291sync_only! {
1292
1293fn allocate_cluster_via_cache<T>(
1294 cache: &mut crate::cache::FatSectorCache,
1295 fat: &Fat,
1296 data: &mut T,
1297 hint: u32,
1298) -> Result<u32>
1299where
1300 T: super::io::Read + super::io::Write + super::io::Seek,
1301{
1302 const FIRST: u32 = 2;
1303 let max_cluster = fat.max_cluster();
1304 let start = if hint >= FIRST && hint <= max_cluster {
1305 hint
1306 } else {
1307 FIRST
1308 };
1309
1310 let scan = |cache: &mut crate::cache::FatSectorCache,
1311 data: &mut T,
1312 fat: &Fat,
1313 lo: u32,
1314 hi: u32|
1315 -> Result<Option<u32>> {
1316 for c in lo..=hi {
1317 let free = match fat.fat_type() {
1318 FatType::Fat12 => (cache.read_fat12_entry(data, c as usize)? & 0x0FFF) == 0,
1319 FatType::Fat16 => cache.read_fat16_entry(data, c as usize)? == 0,
1320 FatType::Fat32 => (cache.read_fat32_entry(data, c as usize)? & 0x0FFF_FFFF) == 0,
1321 };
1322 if free {
1323 return Ok(Some(c));
1324 }
1325 }
1326 Ok(None)
1327 };
1328
1329 let claim =
1330 |cache: &mut crate::cache::FatSectorCache, data: &mut T, fat: &Fat, c: u32| -> Result<()> {
1331 match fat.fat_type() {
1332 FatType::Fat12 => cache.write_fat12_entry(data, c as usize, 0x0FF8),
1333 FatType::Fat16 => cache.write_fat16_entry(data, c as usize, 0xFFF8),
1334 FatType::Fat32 => cache.write_fat32_entry(data, c as usize, 0x0FFF_FFF8),
1335 }
1336 };
1337
1338 if let Some(c) = scan(cache, data, fat, start, max_cluster)? {
1339 claim(cache, data, fat, c)?;
1340 return Ok(c);
1341 }
1342 if start > FIRST
1343 && let Some(c) = scan(cache, data, fat, FIRST, start - 1)?
1344 {
1345 claim(cache, data, fat, c)?;
1346 return Ok(c);
1347 }
1348 Err(Error::NoFreeSpace)
1349}
1350
1351#[cfg(all(feature = "cache", feature = "write"))]
1352fn free_chain_via_cache<T>(
1353 cache: &mut crate::cache::FatSectorCache,
1354 fat: &Fat,
1355 data: &mut T,
1356 start: u32,
1357) -> Result<u32>
1358where
1359 T: super::io::Read + super::io::Write + super::io::Seek,
1360{
1361 const FIRST: u32 = 2;
1362 let max_cluster = fat.max_cluster();
1363 let mut count = 0u32;
1364 let mut current = start;
1365 loop {
1366 if current < FIRST || current > max_cluster {
1367 break;
1368 }
1369 let next = read_fat_entry_via_cache(cache, fat, data, current as usize)?;
1370 write_fat_entry_via_cache(cache, fat, data, current as usize, 0)?;
1371 count += 1;
1372 if is_eoc(fat.fat_type(), next) || is_bad(fat.fat_type(), next) || next == 0 {
1373 break;
1374 }
1375 current = next;
1376 }
1377 Ok(count)
1378}
1379
1380#[cfg(all(feature = "cache", feature = "write"))]
1381fn truncate_chain_via_cache<T>(
1382 cache: &mut crate::cache::FatSectorCache,
1383 fat: &Fat,
1384 data: &mut T,
1385 cluster: 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 if cluster < FIRST || cluster > max_cluster {
1393 return Ok(0);
1394 }
1395 let next = read_fat_entry_via_cache(cache, fat, data, cluster as usize)?;
1396 let eoc = match fat.fat_type() {
1397 FatType::Fat12 => 0x0FF8,
1398 FatType::Fat16 => 0xFFF8,
1399 FatType::Fat32 => 0x0FFF_FFF8,
1400 };
1401 write_fat_entry_via_cache(cache, fat, data, cluster as usize, eoc)?;
1402 if !is_eoc(fat.fat_type(), next) && next >= FIRST && next <= max_cluster {
1403 free_chain_via_cache(cache, fat, data, next)
1404 } else {
1405 Ok(0)
1406 }
1407}
1408
1409#[cfg(all(feature = "cache", feature = "write"))]
1410fn read_fat_entry_via_cache<T>(
1411 cache: &mut crate::cache::FatSectorCache,
1412 fat: &Fat,
1413 data: &mut T,
1414 cluster: usize,
1415) -> Result<u32>
1416where
1417 T: super::io::Read + super::io::Seek,
1418{
1419 Ok(match fat.fat_type() {
1420 FatType::Fat12 => (cache.read_fat12_entry(data, cluster)? & 0x0FFF) as u32,
1421 FatType::Fat16 => cache.read_fat16_entry(data, cluster)? as u32,
1422 FatType::Fat32 => cache.read_fat32_entry(data, cluster)? & 0x0FFF_FFFF,
1423 })
1424}
1425
1426#[cfg(all(feature = "cache", feature = "write"))]
1427fn write_fat_entry_via_cache<T>(
1428 cache: &mut crate::cache::FatSectorCache,
1429 fat: &Fat,
1430 data: &mut T,
1431 cluster: usize,
1432 value: u32,
1433) -> Result<()>
1434where
1435 T: super::io::Read + super::io::Write + super::io::Seek,
1436{
1437 match fat.fat_type() {
1438 FatType::Fat12 => cache.write_fat12_entry(data, cluster, value as u16),
1439 FatType::Fat16 => cache.write_fat16_entry(data, cluster, value as u16),
1440 FatType::Fat32 => cache.write_fat32_entry(data, cluster, value),
1441 }
1442}
1443
1444#[cfg(all(feature = "cache", feature = "write"))]
1445fn is_eoc(ty: FatType, value: u32) -> bool {
1446 match ty {
1447 FatType::Fat12 => value >= 0x0FF8,
1448 FatType::Fat16 => value >= 0xFFF8,
1449 FatType::Fat32 => value >= 0x0FFF_FFF8,
1450 }
1451}
1452
1453#[cfg(all(feature = "cache", feature = "write"))]
1454fn is_bad(ty: FatType, value: u32) -> bool {
1455 match ty {
1456 FatType::Fat12 => value == 0x0FF7,
1457 FatType::Fat16 => value == 0xFFF7,
1458 FatType::Fat32 => value == 0x0FFF_FFF7,
1459 }
1460}
1461
1462} #[cfg(all(feature = "cache", feature = "write"))]
1473sync_only! {
1474 impl<DATA> FatVolume<DATA>
1475 where
1476 DATA: Read + super::io::Write + Seek,
1477 {
1478 pub fn flush(&self) -> Result<()> {
1486 use core::ops::DerefMut;
1487 if let Some(cache_mutex) = &self.fat_cache {
1488 let mut cache = cache_mutex.lock();
1489 let mut data = self.data.lock();
1490 cache.flush(data.deref_mut())?;
1491 }
1492 Ok(())
1493 }
1494 }
1495}