exfat/cluster_heap/
root.rs

1use core::fmt::Debug;
2use core::mem;
3use core::ops::Deref;
4
5use alloc::rc::Rc;
6use alloc::vec::Vec;
7
8use super::directory::Directory;
9use super::metadata::Metadata;
10use super::{
11    allocation_bitmap::AllocationBitmap,
12    context::{Context, OpenedEntries},
13    meta::MetaFileDirectory,
14};
15use crate::endian::Little as LE;
16use crate::error::{DataError, Error, OperationError};
17use crate::fat::Info as FAT;
18use crate::file::FileOptions;
19use crate::fs::{Info as FS, SectorIndex};
20use crate::io::{self, Block, Wrap};
21use crate::region;
22use crate::region::data::entry_type::{EntryType, RawEntryType};
23use crate::region::data::entryset::RawEntry;
24use crate::sync::Shared;
25use crate::types::{ClusterID, SectorID};
26
27pub struct RootDirectory<B: Deref<Target = [Block]>, E: Debug, IO>
28where
29    IO: io::IO<Block<'static> = B, Error = E>,
30{
31    meta: MetaFileDirectory<IO>,
32    upcase_table_data: Rc<crate::upcase_table::UpcaseTable>,
33    upcase_table: region::data::UpcaseTable,
34    volumn_label: Option<heapless::String<22>>,
35}
36
37#[cfg_attr(not(feature = "async"), maybe_async::must_be_sync)]
38impl<B: Deref<Target = [Block]>, E: Debug, IO> RootDirectory<B, E, IO>
39where
40    IO: io::IO<Block<'static> = B, Error = E>,
41{
42    pub(crate) async fn new(
43        io: Shared<IO>,
44        fat: FAT,
45        fs: FS,
46        cluster_id: ClusterID,
47    ) -> Result<Self, Error<E>> {
48        let mut volumn_label: Option<heapless::String<22>> = None;
49        let mut upcase_table: Option<region::data::UpcaseTable> = None;
50        let mut allocation_bitmap: Option<region::data::AllocationBitmap> = None;
51        let sector_index = SectorIndex::new(cluster_id, 0);
52        let mut borrow_io = io.acquire().await.wrap();
53        let sector = borrow_io.read(sector_index.id(&fs)).await?;
54        let entries: &[RawEntry; 16] = unsafe { mem::transmute(&sector[0]) };
55        // FIXME: should walk through all entries till all data found.
56        for entry in entries.iter() {
57            let raw_type = RawEntryType::from(entry[0]);
58            match raw_type.entry_type() {
59                Ok(EntryType::AllocationBitmap) => {
60                    let bitmap: &region::data::AllocationBitmap = unsafe { mem::transmute(entry) };
61                    allocation_bitmap = Some(*bitmap)
62                }
63                Ok(EntryType::VolumnLabel) => {
64                    let label: &region::data::VolumnLabel = unsafe { mem::transmute(entry) };
65                    volumn_label = Some((*label).into())
66                }
67                Ok(EntryType::UpcaseTable) => {
68                    let table: &region::data::UpcaseTable = unsafe { mem::transmute(entry) };
69                    upcase_table = Some(*table)
70                }
71                _ if raw_type.is_end_of_directory() => break,
72                _ => continue,
73            };
74        }
75        drop(borrow_io);
76
77        let upcase_table = upcase_table.ok_or(DataError::UpcaseTableMissing)?;
78        let context = {
79            let region = allocation_bitmap.ok_or(DataError::AllocationBitmapMissing)?;
80            let first_cluster = region.first_cluster.to_ne();
81            let sector_offset = (first_cluster - 2) * fs.sectors_per_cluster();
82            let base = SectorID::from((fs.heap_offset + sector_offset) as u64);
83            let size = region.data_length.to_ne() as u32;
84            debug!("Allocation bitmap found at cluster {} length {}", first_cluster, size);
85            let meta = super::allocation_bitmap::Meta::new(io.clone(), size).await?;
86            let bitmap = AllocationBitmap::new(io.clone(), base, fat, meta).await;
87            Shared::new(Context {
88                allocation_bitmap: bitmap,
89                opened_entries: OpenedEntries { entries: Vec::with_capacity(4) },
90            })
91        };
92        let cluster_id = upcase_table.first_cluster.to_ne();
93        let length = upcase_table.data_length.to_ne();
94        debug!("Upcase table found at cluster {} length {}", cluster_id, length);
95        let mut borrow_io = io.acquire().await.wrap();
96        let sector = borrow_io.read(SectorIndex::new(cluster_id.into(), 0).id(&fs)).await?;
97        let array: &[LE<u16>; 128] = unsafe { mem::transmute(&sector[0]) };
98        let mut metadata = Metadata::new(Default::default());
99        let options = FileOptions::default();
100        metadata.stream_extension.general_secondary_flags.set_fat_chain();
101        let upcase_table_data = Rc::new((*array).into());
102        drop(borrow_io);
103        let meta = MetaFileDirectory { io, context, fat, fs, metadata, options, sector_index };
104        Ok(Self { meta, upcase_table_data, upcase_table, volumn_label })
105    }
106
107    /// Traversing allocation bitmap and gather precise usage info
108    pub async fn update_usage(&mut self) -> Result<(), Error<E>> {
109        self.meta.context.acquire().await.allocation_bitmap.update_usage().await
110    }
111
112    pub async fn validate_upcase_table_checksum(&mut self) -> Result<(), Error<E>> {
113        let mut checksum = region::data::Checksum::default();
114        let first_cluster = self.upcase_table.first_cluster.to_ne();
115        let fs_info = &self.meta.fs;
116        let first_sector = SectorIndex::new(first_cluster.into(), 0).id(&fs_info);
117        let data_length = self.upcase_table.data_length.to_ne();
118        let sector_size = fs_info.sector_size();
119        let num_sectors = data_length / sector_size as u64;
120        let mut io = self.meta.io.acquire().await.wrap();
121        for i in 0..num_sectors {
122            let sector = io.read(first_sector + i).await?;
123            checksum.write(crate::io::flatten(&*sector));
124        }
125        let remain = (data_length - num_sectors * sector_size as u64) as usize;
126        if remain > 0 {
127            let sector_index = first_sector + num_sectors;
128            let sector = io.read(sector_index).await?;
129            checksum.write(&crate::io::flatten(&*sector)[..remain]);
130        }
131        if checksum.sum() != self.upcase_table.table_checksum.to_ne() {
132            return Err(DataError::UpcaseTableChecksum.into());
133        }
134        Ok(())
135    }
136
137    pub fn volumn_label(&self) -> Option<&str> {
138        self.volumn_label.as_ref().map(|label| label.as_str())
139    }
140
141    pub async fn open(&mut self) -> Result<Directory<B, E, IO>, Error<E>> {
142        let meta = self.meta.clone();
143        let mut context = self.meta.context.acquire().await;
144        if !context.opened_entries.add(meta.id()) {
145            return Err(OperationError::AlreadyOpen.into());
146        }
147        trace!("Open root directory sector {}", meta.sector_index);
148        Ok(Directory::new(meta, self.upcase_table_data.clone()))
149    }
150}