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