fatfs/
fs.rs

1use crate::core::cell::{Cell, RefCell};
2use crate::core::char;
3use crate::core::cmp;
4use crate::core::fmt::Debug;
5use crate::core::iter::FromIterator;
6use crate::core::u32;
7use crate::io;
8use crate::io::prelude::*;
9use crate::io::{Error, ErrorKind, SeekFrom};
10#[cfg(all(not(feature = "std"), feature = "alloc"))]
11use alloc::string::String;
12
13use crate::byteorder_ext::{ReadBytesExt, WriteBytesExt};
14use byteorder::LittleEndian;
15
16use crate::boot_sector::{format_boot_sector, BiosParameterBlock, BootSector};
17use crate::dir::{Dir, DirRawStream};
18use crate::dir_entry::{SFN_PADDING, SFN_SIZE};
19use crate::error::FatfsError;
20use crate::file::File;
21use crate::table::{
22    alloc_cluster, count_free_clusters, format_fat, read_fat_flags, ClusterIterator,
23    RESERVED_FAT_ENTRIES,
24};
25use crate::time::{DefaultTimeProvider, TimeProvider};
26use crate::transaction::TransactionManager;
27
28// FAT implementation based on:
29//   http://wiki.osdev.org/FAT
30//   https://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html
31
32/// A type of FAT filesystem.
33///
34/// `FatType` values are based on the size of File Allocation Table entry.
35#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
36pub enum FatType {
37    /// 12 bits per FAT entry
38    Fat12,
39    /// 16 bits per FAT entry
40    Fat16,
41    /// 32 bits per FAT entry
42    Fat32,
43}
44
45impl FatType {
46    const FAT16_MIN_CLUSTERS: u32 = 4085;
47    const FAT32_MIN_CLUSTERS: u32 = 65525;
48    const FAT32_MAX_CLUSTERS: u32 = 0x0FFF_FFF4;
49
50    pub(crate) fn from_clusters(total_clusters: u32) -> FatType {
51        if total_clusters < Self::FAT16_MIN_CLUSTERS {
52            FatType::Fat12
53        } else if total_clusters < Self::FAT32_MIN_CLUSTERS {
54            FatType::Fat16
55        } else {
56            FatType::Fat32
57        }
58    }
59
60    pub(crate) fn bits_per_fat_entry(&self) -> u32 {
61        match self {
62            FatType::Fat12 => 12,
63            FatType::Fat16 => 16,
64            FatType::Fat32 => 32,
65        }
66    }
67
68    pub(crate) fn min_clusters(&self) -> u32 {
69        match self {
70            FatType::Fat12 => 0,
71            FatType::Fat16 => Self::FAT16_MIN_CLUSTERS,
72            FatType::Fat32 => Self::FAT32_MIN_CLUSTERS,
73        }
74    }
75
76    pub(crate) fn max_clusters(&self) -> u32 {
77        match self {
78            FatType::Fat12 => Self::FAT16_MIN_CLUSTERS - 1,
79            FatType::Fat16 => Self::FAT32_MIN_CLUSTERS - 1,
80            FatType::Fat32 => Self::FAT32_MAX_CLUSTERS,
81        }
82    }
83}
84
85/// A FAT volume status flags retrived from the Boot Sector and the allocation table second entry.
86#[derive(Copy, Clone, Eq, PartialEq, Debug)]
87pub struct FsStatusFlags {
88    pub(crate) dirty: bool,
89    pub(crate) io_error: bool,
90}
91
92impl FsStatusFlags {
93    /// Checks if the volume is marked as dirty.
94    ///
95    /// Dirty flag means volume has been suddenly ejected from filesystem without unmounting.
96    pub fn dirty(&self) -> bool {
97        self.dirty
98    }
99
100    /// Checks if the volume has the IO Error flag active.
101    pub fn io_error(&self) -> bool {
102        self.io_error
103    }
104
105    fn encode(&self) -> u8 {
106        let mut res = 0u8;
107        if self.dirty {
108            res |= 1;
109        }
110        if self.io_error {
111            res |= 2;
112        }
113        res
114    }
115
116    pub(crate) fn decode(flags: u8) -> Self {
117        FsStatusFlags { dirty: flags & 1 != 0, io_error: flags & 2 != 0 }
118    }
119}
120
121/// A sum of `Read` and `Seek` traits.
122pub trait ReadSeek: Read + Seek {}
123impl<T: Read + Seek> ReadSeek for T {}
124
125/// A sum of `Read`, `Write` and `Seek` traits.
126pub trait ReadWriteSeek: Read + Write + Seek {}
127impl<T: Read + Write + Seek> ReadWriteSeek for T {}
128
129#[derive(Clone, Default, Debug)]
130struct FsInfoSector {
131    free_cluster_count: Option<u32>,
132    next_free_cluster: Option<u32>,
133    dirty: bool,
134}
135
136impl FsInfoSector {
137    const LEAD_SIG: u32 = 0x41615252;
138    const STRUC_SIG: u32 = 0x61417272;
139    const TRAIL_SIG: u32 = 0xAA550000;
140
141    fn deserialize<R: Read>(rdr: &mut R) -> io::Result<FsInfoSector> {
142        let lead_sig = rdr.read_u32::<LittleEndian>()?;
143        if lead_sig != Self::LEAD_SIG {
144            return Err(Error::new(ErrorKind::Other, FatfsError::InvalidLeadSig));
145        }
146        let mut reserved = [0u8; 480];
147        rdr.read_exact(&mut reserved)?;
148        let struc_sig = rdr.read_u32::<LittleEndian>()?;
149        if struc_sig != Self::STRUC_SIG {
150            return Err(Error::new(ErrorKind::Other, FatfsError::InvalidStrucSig));
151        }
152        let free_cluster_count = match rdr.read_u32::<LittleEndian>()? {
153            0xFFFFFFFF => None,
154            // Note: value is validated in FileSystem::new function using values from BPB
155            n => Some(n),
156        };
157        let next_free_cluster = match rdr.read_u32::<LittleEndian>()? {
158            0xFFFFFFFF => None,
159            0 | 1 => {
160                warn!("invalid next_free_cluster in FsInfo sector (values 0 and 1 are reserved)");
161                None
162            }
163            // Note: other values are validated in FileSystem::new function using values from BPB
164            n => Some(n),
165        };
166        let mut reserved2 = [0u8; 12];
167        rdr.read_exact(&mut reserved2)?;
168        let trail_sig = rdr.read_u32::<LittleEndian>()?;
169        if trail_sig != Self::TRAIL_SIG {
170            return Err(Error::new(ErrorKind::Other, FatfsError::InvalidTrailSig));
171        }
172        Ok(FsInfoSector { free_cluster_count, next_free_cluster, dirty: false })
173    }
174
175    fn serialize<W: Write>(&self, wrt: &mut W) -> io::Result<()> {
176        wrt.write_u32::<LittleEndian>(Self::LEAD_SIG)?;
177        let reserved = [0u8; 480];
178        wrt.write_all(&reserved)?;
179        wrt.write_u32::<LittleEndian>(Self::STRUC_SIG)?;
180        wrt.write_u32::<LittleEndian>(self.free_cluster_count.unwrap_or(0xFFFFFFFF))?;
181        wrt.write_u32::<LittleEndian>(self.next_free_cluster.unwrap_or(0xFFFFFFFF))?;
182        let reserved2 = [0u8; 12];
183        wrt.write_all(&reserved2)?;
184        wrt.write_u32::<LittleEndian>(Self::TRAIL_SIG)?;
185        Ok(())
186    }
187
188    fn validate_and_fix(&mut self, total_clusters: u32) {
189        let max_valid_cluster_number = total_clusters + RESERVED_FAT_ENTRIES;
190        if let Some(n) = self.free_cluster_count {
191            if n > total_clusters {
192                warn!(
193                    "invalid free_cluster_count ({}) in fs_info exceeds total cluster count ({})",
194                    n, total_clusters
195                );
196                self.free_cluster_count = None;
197            }
198        }
199        if let Some(n) = self.next_free_cluster {
200            if n > max_valid_cluster_number {
201                warn!(
202                    "invalid free_cluster_count ({}) in fs_info exceeds maximum cluster number ({})",
203                    n, max_valid_cluster_number
204                );
205                self.next_free_cluster = None;
206            }
207        }
208    }
209
210    fn add_free_clusters(&mut self, free_clusters: i32) {
211        if let Some(n) = self.free_cluster_count {
212            self.free_cluster_count = Some((n as i32 + free_clusters) as u32);
213            self.dirty = true;
214        }
215    }
216
217    fn set_next_free_cluster(&mut self, cluster: u32) {
218        self.next_free_cluster = Some(cluster);
219        self.dirty = true;
220    }
221
222    fn set_free_cluster_count(&mut self, free_cluster_count: u32) {
223        self.free_cluster_count = Some(free_cluster_count);
224        self.dirty = true;
225    }
226}
227
228/// A FAT filesystem mount options.
229///
230/// Options are specified as an argument for `FileSystem::new` method.
231#[derive(Copy, Clone, Debug)]
232pub struct FsOptions<TP, OCC> {
233    pub(crate) update_accessed_date: bool,
234    pub(crate) oem_cp_converter: OCC,
235    pub(crate) time_provider: TP,
236}
237
238impl FsOptions<DefaultTimeProvider, LossyOemCpConverter> {
239    /// Creates a `FsOptions` struct with default options.
240    pub fn new() -> Self {
241        FsOptions {
242            update_accessed_date: false,
243            oem_cp_converter: LossyOemCpConverter::new(),
244            time_provider: DefaultTimeProvider::new(),
245        }
246    }
247}
248
249impl<TP: TimeProvider, OCC: OemCpConverter> FsOptions<TP, OCC> {
250    /// If enabled accessed date field in directory entry is updated when reading or writing a file.
251    pub fn update_accessed_date(mut self, enabled: bool) -> Self {
252        self.update_accessed_date = enabled;
253        self
254    }
255
256    /// Changes default OEM code page encoder-decoder.
257    pub fn oem_cp_converter<OCC2: OemCpConverter>(
258        self,
259        oem_cp_converter: OCC2,
260    ) -> FsOptions<TP, OCC2> {
261        FsOptions::<TP, OCC2> {
262            update_accessed_date: self.update_accessed_date,
263            oem_cp_converter,
264            time_provider: self.time_provider,
265        }
266    }
267
268    /// Changes default time provider.
269    pub fn time_provider<TP2: TimeProvider>(self, time_provider: TP2) -> FsOptions<TP2, OCC> {
270        FsOptions::<TP2, OCC> {
271            update_accessed_date: self.update_accessed_date,
272            oem_cp_converter: self.oem_cp_converter,
273            time_provider,
274        }
275    }
276}
277
278/// A FAT volume statistics.
279#[derive(Copy, Clone, Eq, PartialEq, Debug)]
280pub struct FileSystemStats {
281    sector_size: u16,
282    cluster_size: u32,
283    total_clusters: u32,
284    free_clusters: u32,
285}
286
287impl FileSystemStats {
288    /// Sector size in bytes.
289    pub fn sector_size(&self) -> u16 {
290        self.sector_size
291    }
292
293    /// Cluster size in bytes
294    pub fn cluster_size(&self) -> u32 {
295        self.cluster_size
296    }
297
298    /// Number of total clusters in filesystem usable for file allocation
299    pub fn total_clusters(&self) -> u32 {
300        self.total_clusters
301    }
302
303    /// Number of free clusters
304    pub fn free_clusters(&self) -> u32 {
305        self.free_clusters
306    }
307}
308
309/// A FAT filesystem object.
310///
311/// `FileSystem` struct is representing a state of a mounted FAT volume.
312pub struct FileSystem<IO: ReadWriteSeek, TP, OCC> {
313    pub(crate) disk: RefCell<TransactionManager<IO>>,
314    pub(crate) options: FsOptions<TP, OCC>,
315    fat_type: FatType,
316    bpb: BiosParameterBlock,
317    first_data_sector: u32,
318    root_dir_sectors: u32,
319    total_clusters: u32,
320    fs_info: RefCell<FsInfoSector>,
321    current_status_flags: Cell<FsStatusFlags>,
322}
323
324impl<IO: ReadWriteSeek, TP, OCC> FileSystem<IO, TP, OCC> {
325    /// Creates a new filesystem object instance.
326    ///
327    /// Supplied `disk` parameter cannot be seeked. If there is a need to read a fragment of disk
328    /// image (e.g. partition) library user should wrap the file struct in a struct limiting
329    /// access to partition bytes only e.g. `fscommon::StreamSlice`.
330    ///
331    /// Note: creating multiple filesystem objects with one underlying device/disk image can
332    /// cause a filesystem corruption.
333    pub fn new(mut disk: IO, options: FsOptions<TP, OCC>) -> io::Result<Self> {
334        // Make sure given image is not seeked
335        trace!("FileSystem::new");
336        debug_assert!(disk.seek(SeekFrom::Current(0))? == 0);
337
338        // read boot sector
339        let bpb = {
340            let boot = BootSector::deserialize(&mut disk)?;
341            boot.validate()?;
342            boot.bpb
343        };
344
345        let root_dir_sectors = bpb.root_dir_sectors();
346        let first_data_sector = bpb.first_data_sector();
347        let total_clusters = bpb.total_clusters();
348        let fat_type = FatType::from_clusters(total_clusters);
349
350        // read FSInfo sector if this is FAT32
351        let mut fs_info = if fat_type == FatType::Fat32 {
352            disk.seek(SeekFrom::Start(bpb.bytes_from_sectors(bpb.fs_info_sector())))?;
353            FsInfoSector::deserialize(&mut disk)?
354        } else {
355            FsInfoSector::default()
356        };
357
358        // if dirty flag is set completly ignore free_cluster_count in FSInfo
359        if bpb.status_flags().dirty {
360            fs_info.free_cluster_count = None;
361        }
362
363        // Validate the numbers stored in the free_cluster_count and next_free_cluster are within bounds for volume
364        fs_info.validate_and_fix(total_clusters);
365
366        // return FileSystem struct
367        let status_flags = bpb.status_flags();
368        trace!("FileSystem::new end");
369        Ok(FileSystem {
370            disk: RefCell::new(TransactionManager::new(disk)),
371            options,
372            fat_type,
373            bpb,
374            first_data_sector,
375            root_dir_sectors,
376            total_clusters,
377            fs_info: RefCell::new(fs_info),
378            current_status_flags: Cell::new(status_flags),
379        })
380    }
381
382    pub fn with_disk<F, T>(&self, func: F) -> T
383    where
384        F: FnOnce(&IO) -> T,
385    {
386        func(self.disk.borrow().borrow_inner())
387    }
388
389    /// Returns a type of File Allocation Table (FAT) used by this filesystem.
390    pub fn fat_type(&self) -> FatType {
391        self.fat_type
392    }
393
394    /// Returns a volume identifier read from BPB in the Boot Sector.
395    pub fn volume_id(&self) -> u32 {
396        self.bpb.volume_id
397    }
398
399    /// Returns a volume label from BPB in the Boot Sector as byte array slice.
400    ///
401    /// Label is encoded in the OEM codepage.
402    /// Note: This function returns label stored in the BPB block. Use `read_volume_label_from_root_dir_as_bytes` to
403    /// read label from the root directory.
404    pub fn volume_label_as_bytes(&self) -> &[u8] {
405        let full_label_slice = &self.bpb.volume_label;
406        let len =
407            full_label_slice.iter().rposition(|b| *b != SFN_PADDING).map(|p| p + 1).unwrap_or(0);
408        &full_label_slice[..len]
409    }
410
411    fn offset_from_sector(&self, sector: u32) -> u64 {
412        self.bpb.bytes_from_sectors(sector)
413    }
414
415    fn sector_from_cluster(&self, cluster: u32) -> Result<u32, FatfsError> {
416        if cluster < RESERVED_FAT_ENTRIES {
417            return Err(FatfsError::InvalidClusterNumber);
418        }
419
420        Ok(self
421            .first_data_sector
422            .checked_add(self.bpb.sectors_from_clusters(cluster - RESERVED_FAT_ENTRIES)?)
423            .ok_or(FatfsError::InvalidClusterNumber)?)
424    }
425
426    pub fn cluster_size(&self) -> u32 {
427        self.bpb.cluster_size()
428    }
429
430    pub(crate) fn offset_from_cluster(&self, cluster: u32) -> Result<u64, FatfsError> {
431        Ok(self.offset_from_sector(self.sector_from_cluster(cluster)?))
432    }
433
434    pub(crate) fn bytes_from_clusters(&self, clusters: u32) -> Result<u64, FatfsError> {
435        Ok(self.bpb.bytes_from_sectors(self.bpb.sectors_from_clusters(clusters)?))
436    }
437
438    pub(crate) fn clusters_from_bytes(&self, bytes: u64) -> u32 {
439        self.bpb.clusters_from_bytes(bytes)
440    }
441
442    fn fat_slice<'a>(&'a self) -> DiskSlice<FsIoAdapter<'a, IO, TP, OCC>> {
443        let io = FsIoAdapter { fs: self };
444        fat_slice(io, &self.bpb)
445    }
446
447    pub(crate) fn cluster_iter<'a>(
448        &'a self,
449        cluster: u32,
450    ) -> ClusterIterator<DiskSlice<FsIoAdapter<'a, IO, TP, OCC>>> {
451        let disk_slice = self.fat_slice();
452        ClusterIterator::new(disk_slice, self.fat_type, cluster)
453    }
454
455    pub(crate) fn truncate_cluster_chain(&self, cluster: u32) -> io::Result<()> {
456        let mut iter = self.cluster_iter(cluster);
457        let num_free = iter.truncate()?;
458        let mut fs_info = self.fs_info.borrow_mut();
459        fs_info.add_free_clusters(num_free as i32);
460        Ok(())
461    }
462
463    pub(crate) fn free_cluster_chain(&self, cluster: u32) -> io::Result<()> {
464        let mut iter = self.cluster_iter(cluster);
465        let num_free = iter.free()?;
466        let mut fs_info = self.fs_info.borrow_mut();
467        fs_info.add_free_clusters(num_free as i32);
468        Ok(())
469    }
470
471    pub(crate) fn alloc_cluster(&self, prev_cluster: Option<u32>, zero: bool) -> io::Result<u32> {
472        trace!("alloc_cluster");
473        let hint = self.fs_info.borrow().next_free_cluster;
474        let cluster = {
475            let mut fat = self.fat_slice();
476            alloc_cluster(&mut fat, self.fat_type, prev_cluster, hint, self.total_clusters)?
477        };
478        if zero {
479            let mut disk = self.disk.borrow_mut();
480            disk.seek(SeekFrom::Start(self.offset_from_cluster(cluster)?))?;
481            write_zeros(&mut *disk, self.cluster_size() as u64)?;
482        }
483        let mut fs_info = self.fs_info.borrow_mut();
484        fs_info.set_next_free_cluster(cluster + 1);
485        fs_info.add_free_clusters(-1);
486        Ok(cluster)
487    }
488
489    /// Returns status flags for this volume.
490    pub fn read_status_flags(&self) -> io::Result<FsStatusFlags> {
491        let bpb_status = self.bpb.status_flags();
492        let fat_status = read_fat_flags(&mut self.fat_slice(), self.fat_type)?;
493        Ok(FsStatusFlags {
494            dirty: bpb_status.dirty || fat_status.dirty,
495            io_error: bpb_status.io_error || fat_status.io_error,
496        })
497    }
498
499    /// Returns filesystem statistics like number of total and free clusters.
500    ///
501    /// For FAT32 volumes number of free clusters from FSInfo sector is returned (may be incorrect).
502    /// For other FAT variants number is computed on the first call to this method and cached for later use.
503    pub fn stats(&self) -> io::Result<FileSystemStats> {
504        let free_clusters_option = self.fs_info.borrow().free_cluster_count;
505        let free_clusters = match free_clusters_option {
506            Some(n) => n,
507            _ => self.recalc_free_clusters()?,
508        };
509        Ok(FileSystemStats {
510            sector_size: self.bpb.bytes_per_sector,
511            cluster_size: self.cluster_size(),
512            total_clusters: self.total_clusters,
513            free_clusters,
514        })
515    }
516
517    /// Forces free clusters recalculation.
518    fn recalc_free_clusters(&self) -> io::Result<u32> {
519        let mut fat = self.fat_slice();
520        let free_cluster_count = count_free_clusters(&mut fat, self.fat_type, self.total_clusters)?;
521        self.fs_info.borrow_mut().set_free_cluster_count(free_cluster_count);
522        Ok(free_cluster_count)
523    }
524
525    /// Unmounts the filesystem.
526    ///
527    /// Updates FSInfo sector if needed.
528    pub fn unmount(self) -> io::Result<()> {
529        self.flush()
530    }
531
532    /// Flushes the filesystem and marks it clean.
533    pub fn flush(&self) -> io::Result<()> {
534        self.flush_fs_info()?;
535        self.set_dirty_flag(false)?;
536        self.disk.borrow_mut().flush()?;
537        Ok(())
538    }
539
540    /// Returns true if the disk is currently dirty (i.e. has writes that need to be flush()ed).
541    /// Note that this differs from the return value of read_status_flags() as it returns
542    /// the current state of the filesystem in memory, not whether or not the disk was unmounted in
543    /// a dirty state.
544    pub fn is_dirty(&self) -> bool {
545        self.current_status_flags.get().dirty()
546    }
547
548    fn flush_fs_info(&self) -> io::Result<()> {
549        let mut fs_info = self.fs_info.borrow_mut();
550        if self.fat_type == FatType::Fat32 && fs_info.dirty {
551            let mut disk = self.disk.borrow_mut();
552            disk.seek(SeekFrom::Start(self.offset_from_sector(self.bpb.fs_info_sector as u32)))?;
553            fs_info.serialize(&mut *disk)?;
554            fs_info.dirty = false;
555        }
556        Ok(())
557    }
558
559    pub(crate) fn set_dirty_flag(&self, dirty: bool) -> io::Result<()> {
560        // Do not overwrite flags read from BPB on mount
561        let mut flags = self.bpb.status_flags();
562        flags.dirty |= dirty;
563        // Check if flags has changed
564        let current_flags = self.current_status_flags.get();
565        if flags == current_flags {
566            // Nothing to do
567            return Ok(());
568        }
569        let encoded = flags.encode();
570        // Note: only one field is written to avoid rewriting entire boot-sector which could be dangerous
571        // Compute reserver_1 field offset and write new flags
572        let offset = if self.fat_type() == FatType::Fat32 { 0x041 } else { 0x025 };
573        let mut disk = self.disk.borrow_mut();
574        disk.seek(io::SeekFrom::Start(offset))?;
575        disk.write_u8(encoded)?;
576        self.current_status_flags.set(flags);
577        Ok(())
578    }
579
580    /// Returns a root directory object allowing for futher penetration of a filesystem structure.
581    pub fn root_dir<'a>(&'a self) -> Dir<'a, IO, TP, OCC> {
582        trace!("root_dir");
583        let root_rdr = {
584            match self.fat_type {
585                FatType::Fat12 | FatType::Fat16 => DirRawStream::Root(DiskSlice::from_sectors(
586                    self.first_data_sector - self.root_dir_sectors,
587                    self.root_dir_sectors,
588                    1,
589                    &self.bpb,
590                    FsIoAdapter { fs: self },
591                )),
592                _ => DirRawStream::File(Some(File::new(
593                    Some(self.bpb.root_dir_first_cluster),
594                    None,
595                    self,
596                ))),
597            }
598        };
599        Dir::new(root_rdr, self, true)
600    }
601
602    pub(crate) fn begin_transaction(&self) -> Option<Transaction<'_, IO, TP, OCC>> {
603        if self.disk.borrow_mut().begin_transaction() {
604            Some(Transaction::new(self))
605        } else {
606            None
607        }
608    }
609
610    pub(crate) fn commit(&self, mut transaction: Transaction<'_, IO, TP, OCC>) -> io::Result<()> {
611        transaction.active = false;
612        self.disk.borrow_mut().commit()
613    }
614}
615
616impl<IO: ReadWriteSeek, TP, OCC: OemCpConverter> FileSystem<IO, TP, OCC> {
617    /// Returns a volume label from BPB in the Boot Sector as `String`.
618    ///
619    /// Non-ASCII characters are replaced by the replacement character (U+FFFD).  Note: This
620    /// function returns label stored in the BPB block.  Use `read_volume_label_from_root_dir` to
621    /// read label from the root directory.
622    #[cfg(feature = "alloc")]
623    pub fn volume_label(&self) -> String {
624        // Decode volume label from OEM codepage
625        let volume_label_iter = self.volume_label_as_bytes().iter().cloned();
626        let char_iter = volume_label_iter.map(|c| self.options.oem_cp_converter.decode(c));
627        // Build string from character iterator
628        String::from_iter(char_iter)
629    }
630}
631
632impl<IO: ReadWriteSeek, TP: TimeProvider, OCC: OemCpConverter> FileSystem<IO, TP, OCC> {
633    /// Returns a volume label from root directory as `String`.
634    ///
635    /// It finds file with `VOLUME_ID` attribute and returns its short name.
636    #[cfg(feature = "alloc")]
637    pub fn read_volume_label_from_root_dir(&self) -> io::Result<Option<String>> {
638        // Note: DirEntry::file_short_name() cannot be used because it interprets name as 8.3
639        // (adds dot before an extension)
640        let volume_label_opt = self.read_volume_label_from_root_dir_as_bytes()?;
641        if let Some(volume_label) = volume_label_opt {
642            // Strip label padding
643            let len =
644                volume_label.iter().rposition(|b| *b != SFN_PADDING).map(|p| p + 1).unwrap_or(0);
645            let label_slice = &volume_label[..len];
646            // Decode volume label from OEM codepage
647            let volume_label_iter = label_slice.iter().cloned();
648            let char_iter = volume_label_iter.map(|c| self.options.oem_cp_converter.decode(c));
649            // Build string from character iterator
650            Ok(Some(String::from_iter(char_iter)))
651        } else {
652            Ok(None)
653        }
654    }
655
656    /// Returns a volume label from root directory as byte array.
657    ///
658    /// Label is encoded in the OEM codepage.
659    /// It finds file with `VOLUME_ID` attribute and returns its short name.
660    pub fn read_volume_label_from_root_dir_as_bytes(&self) -> io::Result<Option<[u8; SFN_SIZE]>> {
661        let entry_opt = self.root_dir().find_volume_entry()?;
662        Ok(entry_opt.map(|e| *e.raw_short_name()))
663    }
664}
665
666/// `Drop` implementation tries to unmount the filesystem when dropping.
667impl<IO: ReadWriteSeek, TP, OCC> Drop for FileSystem<IO, TP, OCC> {
668    fn drop(&mut self) {
669        if let Err(err) = self.flush() {
670            error!("unmount failed {}", err);
671        }
672    }
673}
674
675pub(crate) struct FsIoAdapter<'a, IO: ReadWriteSeek, TP, OCC> {
676    fs: &'a FileSystem<IO, TP, OCC>,
677}
678
679impl<IO: ReadWriteSeek, TP, OCC> Read for FsIoAdapter<'_, IO, TP, OCC> {
680    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
681        self.fs.disk.borrow_mut().read(buf)
682    }
683}
684
685impl<IO: ReadWriteSeek, TP, OCC> Write for FsIoAdapter<'_, IO, TP, OCC> {
686    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
687        let size = self.fs.disk.borrow_mut().write(buf)?;
688        if size > 0 {
689            self.fs.set_dirty_flag(true)?;
690        }
691        Ok(size)
692    }
693
694    fn flush(&mut self) -> io::Result<()> {
695        self.fs.disk.borrow_mut().flush()
696    }
697}
698
699impl<IO: ReadWriteSeek, TP, OCC> Seek for FsIoAdapter<'_, IO, TP, OCC> {
700    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
701        self.fs.disk.borrow_mut().seek(pos)
702    }
703}
704
705// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925
706impl<IO: ReadWriteSeek, TP, OCC> Clone for FsIoAdapter<'_, IO, TP, OCC> {
707    fn clone(&self) -> Self {
708        FsIoAdapter { fs: self.fs }
709    }
710}
711
712fn fat_slice<IO: ReadWriteSeek>(io: IO, bpb: &BiosParameterBlock) -> DiskSlice<IO> {
713    let sectors_per_fat = bpb.sectors_per_fat();
714    let mirroring_enabled = bpb.mirroring_enabled();
715    let (fat_first_sector, mirrors) = if mirroring_enabled {
716        (bpb.reserved_sectors(), bpb.fats)
717    } else {
718        let active_fat = bpb.active_fat() as u32;
719        let fat_first_sector = (bpb.reserved_sectors()) + active_fat * sectors_per_fat;
720        (fat_first_sector, 1)
721    };
722    DiskSlice::from_sectors(fat_first_sector, sectors_per_fat, mirrors, bpb, io)
723}
724
725pub(crate) struct DiskSlice<IO> {
726    begin: u64,
727    size: u64,
728    offset: u64,
729    mirrors: u8,
730    inner: IO,
731}
732
733impl<IO> DiskSlice<IO> {
734    pub(crate) fn new(begin: u64, size: u64, mirrors: u8, inner: IO) -> Self {
735        DiskSlice { begin, size, mirrors, inner, offset: 0 }
736    }
737
738    fn from_sectors(
739        first_sector: u32,
740        sector_count: u32,
741        mirrors: u8,
742        bpb: &BiosParameterBlock,
743        inner: IO,
744    ) -> Self {
745        Self::new(
746            bpb.bytes_from_sectors(first_sector),
747            bpb.bytes_from_sectors(sector_count),
748            mirrors,
749            inner,
750        )
751    }
752
753    pub(crate) fn abs_pos(&self) -> u64 {
754        self.begin + self.offset
755    }
756}
757
758// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925
759impl<IO: Clone> Clone for DiskSlice<IO> {
760    fn clone(&self) -> Self {
761        DiskSlice {
762            begin: self.begin,
763            size: self.size,
764            offset: self.offset,
765            mirrors: self.mirrors,
766            inner: self.inner.clone(),
767        }
768    }
769}
770
771impl<IO: Read + Seek> Read for DiskSlice<IO> {
772    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
773        let offset = self.begin + self.offset;
774        let read_size = cmp::min((self.size - self.offset) as usize, buf.len());
775        self.inner.seek(SeekFrom::Start(offset))?;
776        let size = self.inner.read(&mut buf[..read_size])?;
777        self.offset += size as u64;
778        Ok(size)
779    }
780}
781
782impl<IO: Write + Seek> Write for DiskSlice<IO> {
783    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
784        let offset = self.begin + self.offset;
785        let write_size = cmp::min((self.size - self.offset) as usize, buf.len());
786        if write_size == 0 {
787            return Ok(0);
788        }
789        // Write data
790        for i in 0..self.mirrors {
791            self.inner.seek(SeekFrom::Start(offset + i as u64 * self.size))?;
792            self.inner.write_all(&buf[..write_size])?;
793        }
794        self.offset += write_size as u64;
795        Ok(write_size)
796    }
797
798    fn flush(&mut self) -> io::Result<()> {
799        self.inner.flush()
800    }
801}
802
803impl<IO> Seek for DiskSlice<IO> {
804    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
805        let new_offset = match pos {
806            SeekFrom::Current(x) => self.offset as i64 + x,
807            SeekFrom::Start(x) => x as i64,
808            SeekFrom::End(x) => self.size as i64 + x,
809        };
810        if new_offset < 0 || new_offset as u64 > self.size {
811            Err(io::Error::new(ErrorKind::InvalidInput, "Seek to a negative offset"))
812        } else {
813            self.offset = new_offset as u64;
814            Ok(self.offset)
815        }
816    }
817}
818
819/// An OEM code page encoder/decoder.
820///
821/// Provides a custom implementation for a short name encoding/decoding.
822/// `OemCpConverter` is specified by the `oem_cp_converter` property in `FsOptions` struct.
823pub trait OemCpConverter: Debug {
824    fn decode(&self, oem_char: u8) -> char;
825    fn encode(&self, uni_char: char) -> Option<u8>;
826}
827
828/// Default implementation of `OemCpConverter` that changes all non-ASCII characters to the replacement character (U+FFFD).
829#[derive(Debug, Clone, Copy)]
830pub struct LossyOemCpConverter {
831    _dummy: (),
832}
833
834impl LossyOemCpConverter {
835    pub fn new() -> Self {
836        Self { _dummy: () }
837    }
838}
839
840impl OemCpConverter for LossyOemCpConverter {
841    fn decode(&self, oem_char: u8) -> char {
842        if oem_char <= 0x7F {
843            oem_char as char
844        } else {
845            '\u{FFFD}'
846        }
847    }
848    fn encode(&self, uni_char: char) -> Option<u8> {
849        if uni_char <= '\x7F' {
850            Some(uni_char as u8)
851        } else {
852            None
853        }
854    }
855}
856
857pub(crate) fn write_zeros<IO: ReadWriteSeek>(mut disk: IO, mut len: u64) -> io::Result<()> {
858    const ZEROS: [u8; 512] = [0u8; 512];
859    while len > 0 {
860        let write_size = cmp::min(len, ZEROS.len() as u64) as usize;
861        disk.write_all(&ZEROS[..write_size])?;
862        len -= write_size as u64;
863    }
864    Ok(())
865}
866
867fn write_zeros_until_end_of_sector<IO: ReadWriteSeek>(
868    mut disk: IO,
869    bytes_per_sector: u16,
870) -> io::Result<()> {
871    let pos = disk.seek(SeekFrom::Current(0))?;
872    let total_bytes_to_write = bytes_per_sector as u64 - (pos % bytes_per_sector as u64);
873    if total_bytes_to_write != bytes_per_sector as u64 {
874        write_zeros(disk, total_bytes_to_write)?;
875    }
876    Ok(())
877}
878
879/// A FAT filesystem formatting options
880///
881/// This struct implements a builder pattern.
882/// Options are specified as an argument for `format_volume` function.
883#[derive(Default, Debug, Clone)]
884pub struct FormatVolumeOptions {
885    pub(crate) bytes_per_sector: Option<u16>,
886    pub(crate) total_sectors: Option<u32>,
887    pub(crate) bytes_per_cluster: Option<u32>,
888    pub(crate) fat_type: Option<FatType>,
889    pub(crate) max_root_dir_entries: Option<u16>,
890    pub(crate) fats: Option<u8>,
891    pub(crate) media: Option<u8>,
892    pub(crate) sectors_per_track: Option<u16>,
893    pub(crate) heads: Option<u16>,
894    pub(crate) drive_num: Option<u8>,
895    pub(crate) volume_id: Option<u32>,
896    pub(crate) volume_label: Option<[u8; SFN_SIZE]>,
897}
898
899impl FormatVolumeOptions {
900    /// Create options struct for `format_volume` function
901    ///
902    /// Allows to overwrite many filesystem parameters.
903    /// In normal use-case defaults should suffice.
904    pub fn new() -> Self {
905        FormatVolumeOptions { ..Default::default() }
906    }
907
908    /// Set size of cluster in bytes (must be dividable by sector size)
909    ///
910    /// Cluster size must be a power of two and be greater or equal to sector size.
911    /// If option is not specified optimal cluster size is selected based on partition size and
912    /// optionally FAT type override (if specified using `fat_type` method).
913    pub fn bytes_per_cluster(mut self, bytes_per_cluster: u32) -> Self {
914        assert!(
915            bytes_per_cluster.count_ones() == 1 && bytes_per_cluster >= 512,
916            "Invalid bytes_per_cluster"
917        );
918        self.bytes_per_cluster = Some(bytes_per_cluster);
919        self
920    }
921
922    /// Set File Allocation Table type
923    ///
924    /// Option allows to override File Allocation Table (FAT) entry size.
925    /// It is unrecommended to set this option unless you know what you are doing.
926    /// Note: FAT type is determined from total number of clusters. Changing this option can cause formatting to fail
927    /// if the volume cannot be divided into proper number of clusters for selected FAT type.
928    pub fn fat_type(mut self, fat_type: FatType) -> Self {
929        self.fat_type = Some(fat_type);
930        self
931    }
932
933    /// Set sector size in bytes
934    ///
935    /// Sector size must be a power of two and be in range 512 - 4096.
936    /// Default is `512`.
937    pub fn bytes_per_sector(mut self, bytes_per_sector: u16) -> Self {
938        assert!(
939            bytes_per_sector.count_ones() == 1 && bytes_per_sector >= 512,
940            "Invalid bytes_per_sector"
941        );
942        self.bytes_per_sector = Some(bytes_per_sector);
943        self
944    }
945
946    /// Set total number of sectors
947    ///
948    /// If option is not specified total number of sectors is calculated as storage device size divided by sector size.
949    pub fn total_sectors(mut self, total_sectors: u32) -> Self {
950        self.total_sectors = Some(total_sectors);
951        self
952    }
953
954    /// Set maximal numer of entries in root directory for FAT12/FAT16 volumes
955    ///
956    /// Total root directory size should be dividable by sectors size so keep it a multiple of 16 (for default sector
957    /// size).
958    /// Note: this limit is not used on FAT32 volumes.
959    /// Default is `512`.
960    pub fn max_root_dir_entries(mut self, max_root_dir_entries: u16) -> Self {
961        self.max_root_dir_entries = Some(max_root_dir_entries);
962        self
963    }
964
965    /// Set number of File Allocation Tables
966    ///
967    /// The only allowed values are `1` and `2`. If value `2` is used the FAT is mirrored.
968    /// Default is `2`.
969    pub fn fats(mut self, fats: u8) -> Self {
970        assert!(fats >= 1 && fats <= 2, "Invalid number of FATs");
971        self.fats = Some(fats);
972        self
973    }
974
975    /// Set media field for Bios Parameters Block
976    ///
977    /// Default is `0xF8`.
978    pub fn media(mut self, media: u8) -> Self {
979        self.media = Some(media);
980        self
981    }
982
983    /// Set number of physical sectors per track for Bios Parameters Block (INT 13h CHS geometry)
984    ///
985    /// Default is `0x20`.
986    pub fn sectors_per_track(mut self, sectors_per_track: u16) -> Self {
987        self.sectors_per_track = Some(sectors_per_track);
988        self
989    }
990
991    /// Set number of heads for Bios Parameters Block (INT 13h CHS geometry)
992    ///
993    /// Default is `0x40`.
994    pub fn heads(mut self, heads: u16) -> Self {
995        self.heads = Some(heads);
996        self
997    }
998
999    /// Set drive number for Bios Parameters Block
1000    ///
1001    /// Default is `0` for FAT12, `0x80` for FAT16/FAT32.
1002    pub fn drive_num(mut self, drive_num: u8) -> Self {
1003        self.drive_num = Some(drive_num);
1004        self
1005    }
1006
1007    /// Set volume ID for Bios Parameters Block
1008    ///
1009    /// Default is `0x12345678`.
1010    pub fn volume_id(mut self, volume_id: u32) -> Self {
1011        self.volume_id = Some(volume_id);
1012        self
1013    }
1014
1015    /// Set volume label
1016    ///
1017    /// Default is empty label.
1018    pub fn volume_label(mut self, volume_label: [u8; SFN_SIZE]) -> Self {
1019        self.volume_label = Some(volume_label);
1020        self
1021    }
1022}
1023
1024/// Create FAT filesystem on a disk or partition (format a volume)
1025///
1026/// Warning: this function overrides internal FAT filesystem structures and causes a loss of all data on provided
1027/// partition. Please use it with caution.
1028/// Only quick formatting is supported. To achieve a full format zero entire partition before calling this function.
1029/// Supplied `disk` parameter cannot be seeked (internal pointer must be on position 0).
1030/// To format a fragment of a disk image (e.g. partition) library user should wrap the file struct in a struct
1031/// limiting access to partition bytes only e.g. `fscommon::StreamSlice`.
1032pub fn format_volume<IO: ReadWriteSeek>(
1033    mut disk: IO,
1034    options: FormatVolumeOptions,
1035) -> io::Result<()> {
1036    trace!("format_volume");
1037    debug_assert!(disk.seek(SeekFrom::Current(0))? == 0);
1038
1039    let bytes_per_sector = options.bytes_per_sector.unwrap_or(512);
1040    let total_sectors = if let Some(total_sectors) = options.total_sectors {
1041        total_sectors
1042    } else {
1043        let total_bytes: u64 = disk.seek(SeekFrom::End(0))?;
1044        let total_sectors_64 = total_bytes / u64::from(bytes_per_sector);
1045        disk.seek(SeekFrom::Start(0))?;
1046        if total_sectors_64 > u64::from(u32::MAX) {
1047            return Err(Error::new(ErrorKind::Other, FatfsError::TooManySectors));
1048        }
1049        total_sectors_64 as u32
1050    };
1051
1052    // Create boot sector, validate and write to storage device
1053    let (boot, fat_type) = format_boot_sector(&options, total_sectors, bytes_per_sector)?;
1054    boot.validate()?;
1055    boot.serialize(&mut disk)?;
1056    // Make sure entire logical sector is updated (serialize method always writes 512 bytes)
1057    let bytes_per_sector = boot.bpb.bytes_per_sector;
1058    write_zeros_until_end_of_sector(&mut disk, bytes_per_sector)?;
1059
1060    if boot.bpb.is_fat32() {
1061        // FSInfo sector
1062        let fs_info_sector =
1063            FsInfoSector { free_cluster_count: None, next_free_cluster: None, dirty: false };
1064        disk.seek(SeekFrom::Start(boot.bpb.bytes_from_sectors(boot.bpb.fs_info_sector())))?;
1065        fs_info_sector.serialize(&mut disk)?;
1066        write_zeros_until_end_of_sector(&mut disk, bytes_per_sector)?;
1067
1068        // backup boot sector
1069        disk.seek(SeekFrom::Start(boot.bpb.bytes_from_sectors(boot.bpb.backup_boot_sector())))?;
1070        boot.serialize(&mut disk)?;
1071        write_zeros_until_end_of_sector(&mut disk, bytes_per_sector)?;
1072    }
1073
1074    // format File Allocation Table
1075    let reserved_sectors = boot.bpb.reserved_sectors();
1076    let fat_pos = boot.bpb.bytes_from_sectors(reserved_sectors);
1077    let sectors_per_all_fats = boot.bpb.sectors_per_all_fats();
1078    disk.seek(SeekFrom::Start(fat_pos))?;
1079    write_zeros(&mut disk, boot.bpb.bytes_from_sectors(sectors_per_all_fats))?;
1080    {
1081        let mut fat_slice = fat_slice(&mut disk, &boot.bpb);
1082        let sectors_per_fat = boot.bpb.sectors_per_fat();
1083        let bytes_per_fat = boot.bpb.bytes_from_sectors(sectors_per_fat);
1084        format_fat(
1085            &mut fat_slice,
1086            fat_type,
1087            boot.bpb.media,
1088            bytes_per_fat,
1089            boot.bpb.total_clusters(),
1090        )?;
1091    }
1092
1093    // init root directory - zero root directory region for FAT12/16 and alloc first root directory cluster for FAT32
1094    let root_dir_first_sector = reserved_sectors + sectors_per_all_fats;
1095    let root_dir_sectors = boot.bpb.root_dir_sectors();
1096    let root_dir_pos = boot.bpb.bytes_from_sectors(root_dir_first_sector);
1097    disk.seek(SeekFrom::Start(root_dir_pos))?;
1098    write_zeros(&mut disk, boot.bpb.bytes_from_sectors(root_dir_sectors))?;
1099    if fat_type == FatType::Fat32 {
1100        let root_dir_first_cluster = {
1101            let mut fat_slice = fat_slice(&mut disk, &boot.bpb);
1102            alloc_cluster(&mut fat_slice, fat_type, None, None, 1)?
1103        };
1104        assert!(root_dir_first_cluster == boot.bpb.root_dir_first_cluster);
1105        let first_data_sector = reserved_sectors + sectors_per_all_fats + root_dir_sectors;
1106        let root_dir_first_sector = first_data_sector
1107            + boot.bpb.sectors_from_clusters(root_dir_first_cluster - RESERVED_FAT_ENTRIES)?;
1108        let root_dir_pos = boot.bpb.bytes_from_sectors(root_dir_first_sector);
1109        disk.seek(SeekFrom::Start(root_dir_pos))?;
1110        write_zeros(&mut disk, boot.bpb.cluster_size() as u64)?;
1111    }
1112
1113    // TODO: create volume label dir entry if volume label is set
1114
1115    disk.seek(SeekFrom::Start(0))?;
1116    trace!("format_volume end");
1117    Ok(())
1118}
1119
1120pub(crate) struct Transaction<'a, IO: ReadWriteSeek, TP, OCC> {
1121    fs: &'a FileSystem<IO, TP, OCC>,
1122    original_fs_info: FsInfoSector,
1123    active: bool,
1124}
1125
1126impl<'a, IO: ReadWriteSeek, TP, OCC> Transaction<'a, IO, TP, OCC> {
1127    fn new(fs: &'a FileSystem<IO, TP, OCC>) -> Self {
1128        Transaction { fs, original_fs_info: fs.fs_info.borrow_mut().clone(), active: true }
1129    }
1130}
1131
1132impl<IO: ReadWriteSeek, TP, OCC> Drop for Transaction<'_, IO, TP, OCC> {
1133    fn drop(&mut self) {
1134        if self.active {
1135            self.fs.disk.borrow_mut().revert();
1136            *self.fs.fs_info.borrow_mut() = self.original_fs_info.clone();
1137            self.active = false;
1138        }
1139    }
1140}