embedded_sdmmc/fat/
volume.rs

1//! FAT-specific volume support.
2
3use crate::{
4    debug,
5    fat::{
6        Bpb, Fat16Info, Fat32Info, FatSpecificInfo, FatType, InfoSector, OnDiskDirEntry,
7        RESERVED_ENTRIES,
8    },
9    trace, warn, Attributes, Block, BlockCount, BlockDevice, BlockIdx, ClusterId, DirEntry,
10    DirectoryInfo, Error, ShortFileName, TimeSource, VolumeType,
11};
12use byteorder::{ByteOrder, LittleEndian};
13use core::convert::TryFrom;
14
15use super::BlockCache;
16
17/// The name given to a particular FAT formatted volume.
18#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
19#[derive(Clone, PartialEq, Eq)]
20pub struct VolumeName {
21    data: [u8; 11],
22}
23
24impl VolumeName {
25    /// Create a new VolumeName
26    pub fn new(data: [u8; 11]) -> VolumeName {
27        VolumeName { data }
28    }
29}
30
31impl core::fmt::Debug for VolumeName {
32    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
33        match core::str::from_utf8(&self.data) {
34            Ok(s) => write!(fmt, "{:?}", s),
35            Err(_e) => write!(fmt, "{:?}", &self.data),
36        }
37    }
38}
39
40/// Identifies a FAT16 or FAT32 Volume on the disk.
41#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
42#[derive(Debug, PartialEq, Eq)]
43pub struct FatVolume {
44    /// The block number of the start of the partition. All other BlockIdx values are relative to this.
45    pub(crate) lba_start: BlockIdx,
46    /// The number of blocks in this volume
47    pub(crate) num_blocks: BlockCount,
48    /// The name of this volume
49    pub(crate) name: VolumeName,
50    /// Number of 512 byte blocks (or Blocks) in a cluster
51    pub(crate) blocks_per_cluster: u8,
52    /// The block the data starts in. Relative to start of partition (so add
53    /// `self.lba_offset` before passing to volume manager)
54    pub(crate) first_data_block: BlockCount,
55    /// The block the FAT starts in. Relative to start of partition (so add
56    /// `self.lba_offset` before passing to volume manager)
57    pub(crate) fat_start: BlockCount,
58    /// The block the second FAT starts in (if present). Relative to start of
59    /// partition (so add `self.lba_offset` before passing to volume manager)
60    pub(crate) second_fat_start: Option<BlockCount>,
61    /// Expected number of free clusters
62    pub(crate) free_clusters_count: Option<u32>,
63    /// Number of the next expected free cluster
64    pub(crate) next_free_cluster: Option<ClusterId>,
65    /// Total number of clusters
66    pub(crate) cluster_count: u32,
67    /// Type of FAT
68    pub(crate) fat_specific_info: FatSpecificInfo,
69}
70
71impl FatVolume {
72    /// Write a new entry in the FAT
73    pub fn update_info_sector<D>(&mut self, block_device: &D) -> Result<(), Error<D::Error>>
74    where
75        D: BlockDevice,
76    {
77        match &self.fat_specific_info {
78            FatSpecificInfo::Fat16(_) => {
79                // FAT16 volumes don't have an info sector
80            }
81            FatSpecificInfo::Fat32(fat32_info) => {
82                if self.free_clusters_count.is_none() && self.next_free_cluster.is_none() {
83                    return Ok(());
84                }
85                let mut blocks = [Block::new()];
86                block_device
87                    .read(&mut blocks, fat32_info.info_location, "read_info_sector")
88                    .map_err(Error::DeviceError)?;
89                let block = &mut blocks[0];
90                if let Some(count) = self.free_clusters_count {
91                    block[488..492].copy_from_slice(&count.to_le_bytes());
92                }
93                if let Some(next_free_cluster) = self.next_free_cluster {
94                    block[492..496].copy_from_slice(&next_free_cluster.0.to_le_bytes());
95                }
96                block_device
97                    .write(&blocks, fat32_info.info_location)
98                    .map_err(Error::DeviceError)?;
99            }
100        }
101        Ok(())
102    }
103
104    /// Get the type of FAT this volume is
105    pub(crate) fn get_fat_type(&self) -> FatType {
106        match &self.fat_specific_info {
107            FatSpecificInfo::Fat16(_) => FatType::Fat16,
108            FatSpecificInfo::Fat32(_) => FatType::Fat32,
109        }
110    }
111
112    /// Write a new entry in the FAT
113    fn update_fat<D>(
114        &mut self,
115        block_device: &D,
116        cluster: ClusterId,
117        new_value: ClusterId,
118    ) -> Result<(), Error<D::Error>>
119    where
120        D: BlockDevice,
121    {
122        let mut blocks = [Block::new()];
123        let this_fat_block_num;
124        let mut second_fat_block_num = None;
125        match &self.fat_specific_info {
126            FatSpecificInfo::Fat16(_fat16_info) => {
127                let fat_offset = cluster.0 * 2;
128                this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
129                if let Some(fat_start) = self.second_fat_start {
130                    second_fat_block_num =
131                        Some(self.lba_start + fat_start.offset_bytes(fat_offset));
132                }
133                let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
134                block_device
135                    .read(&mut blocks, this_fat_block_num, "read_fat")
136                    .map_err(Error::DeviceError)?;
137                // See <https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system>
138                let entry = match new_value {
139                    ClusterId::INVALID => 0xFFF6,
140                    ClusterId::BAD => 0xFFF7,
141                    ClusterId::EMPTY => 0x0000,
142                    ClusterId::END_OF_FILE => 0xFFFF,
143                    _ => new_value.0 as u16,
144                };
145                LittleEndian::write_u16(
146                    &mut blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 1],
147                    entry,
148                );
149            }
150            FatSpecificInfo::Fat32(_fat32_info) => {
151                // FAT32 => 4 bytes per entry
152                let fat_offset = cluster.0 * 4;
153                this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
154                if let Some(fat_start) = self.second_fat_start {
155                    second_fat_block_num =
156                        Some(self.lba_start + fat_start.offset_bytes(fat_offset));
157                }
158                let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
159                block_device
160                    .read(&mut blocks, this_fat_block_num, "read_fat")
161                    .map_err(Error::DeviceError)?;
162                let entry = match new_value {
163                    ClusterId::INVALID => 0x0FFF_FFF6,
164                    ClusterId::BAD => 0x0FFF_FFF7,
165                    ClusterId::EMPTY => 0x0000_0000,
166                    _ => new_value.0,
167                };
168                let existing = LittleEndian::read_u32(
169                    &blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 3],
170                );
171                let new = (existing & 0xF000_0000) | (entry & 0x0FFF_FFFF);
172                LittleEndian::write_u32(
173                    &mut blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 3],
174                    new,
175                );
176            }
177        }
178        block_device
179            .write(&blocks, this_fat_block_num)
180            .map_err(Error::DeviceError)?;
181        if let Some(second_fat_block_num) = second_fat_block_num {
182            block_device
183                .write(&blocks, second_fat_block_num)
184                .map_err(Error::DeviceError)?;
185        }
186        Ok(())
187    }
188
189    /// Look in the FAT to see which cluster comes next.
190    pub(crate) fn next_cluster<D>(
191        &self,
192        block_device: &D,
193        cluster: ClusterId,
194        fat_block_cache: &mut BlockCache,
195    ) -> Result<ClusterId, Error<D::Error>>
196    where
197        D: BlockDevice,
198    {
199        if cluster.0 > (u32::MAX / 4) {
200            panic!("next_cluster called on invalid cluster {:x?}", cluster);
201        }
202        match &self.fat_specific_info {
203            FatSpecificInfo::Fat16(_fat16_info) => {
204                let fat_offset = cluster.0 * 2;
205                let this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
206                let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
207                let block =
208                    fat_block_cache.read(block_device, this_fat_block_num, "next_cluster")?;
209                let fat_entry =
210                    LittleEndian::read_u16(&block[this_fat_ent_offset..=this_fat_ent_offset + 1]);
211                match fat_entry {
212                    0xFFF7 => {
213                        // Bad cluster
214                        Err(Error::BadCluster)
215                    }
216                    0xFFF8..=0xFFFF => {
217                        // There is no next cluster
218                        Err(Error::EndOfFile)
219                    }
220                    f => {
221                        // Seems legit
222                        Ok(ClusterId(u32::from(f)))
223                    }
224                }
225            }
226            FatSpecificInfo::Fat32(_fat32_info) => {
227                let fat_offset = cluster.0 * 4;
228                let this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
229                let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
230                let block =
231                    fat_block_cache.read(block_device, this_fat_block_num, "next_cluster")?;
232                let fat_entry =
233                    LittleEndian::read_u32(&block[this_fat_ent_offset..=this_fat_ent_offset + 3])
234                        & 0x0FFF_FFFF;
235                match fat_entry {
236                    0x0000_0000 => {
237                        // Jumped to free space
238                        Err(Error::UnterminatedFatChain)
239                    }
240                    0x0FFF_FFF7 => {
241                        // Bad cluster
242                        Err(Error::BadCluster)
243                    }
244                    0x0000_0001 | 0x0FFF_FFF8..=0x0FFF_FFFF => {
245                        // There is no next cluster
246                        Err(Error::EndOfFile)
247                    }
248                    f => {
249                        // Seems legit
250                        Ok(ClusterId(f))
251                    }
252                }
253            }
254        }
255    }
256
257    /// Number of bytes in a cluster.
258    pub(crate) fn bytes_per_cluster(&self) -> u32 {
259        u32::from(self.blocks_per_cluster) * Block::LEN_U32
260    }
261
262    /// Converts a cluster number (or `Cluster`) to a block number (or
263    /// `BlockIdx`). Gives an absolute `BlockIdx` you can pass to the
264    /// volume manager.
265    pub(crate) fn cluster_to_block(&self, cluster: ClusterId) -> BlockIdx {
266        match &self.fat_specific_info {
267            FatSpecificInfo::Fat16(fat16_info) => {
268                let block_num = match cluster {
269                    ClusterId::ROOT_DIR => fat16_info.first_root_dir_block,
270                    ClusterId(c) => {
271                        // FirstSectorofCluster = ((N – 2) * BPB_SecPerClus) + FirstDataSector;
272                        let first_block_of_cluster =
273                            BlockCount((c - 2) * u32::from(self.blocks_per_cluster));
274                        self.first_data_block + first_block_of_cluster
275                    }
276                };
277                self.lba_start + block_num
278            }
279            FatSpecificInfo::Fat32(fat32_info) => {
280                let cluster_num = match cluster {
281                    ClusterId::ROOT_DIR => fat32_info.first_root_dir_cluster.0,
282                    c => c.0,
283                };
284                // FirstSectorofCluster = ((N – 2) * BPB_SecPerClus) + FirstDataSector;
285                let first_block_of_cluster =
286                    BlockCount((cluster_num - 2) * u32::from(self.blocks_per_cluster));
287                self.lba_start + self.first_data_block + first_block_of_cluster
288            }
289        }
290    }
291
292    /// Finds a empty entry space and writes the new entry to it, allocates a new cluster if it's
293    /// needed
294    pub(crate) fn write_new_directory_entry<D, T>(
295        &mut self,
296        block_device: &D,
297        time_source: &T,
298        dir_cluster: ClusterId,
299        name: ShortFileName,
300        attributes: Attributes,
301    ) -> Result<DirEntry, Error<D::Error>>
302    where
303        D: BlockDevice,
304        T: TimeSource,
305    {
306        match &self.fat_specific_info {
307            FatSpecificInfo::Fat16(fat16_info) => {
308                // Root directories on FAT16 have a fixed size, because they use
309                // a specially reserved space on disk (see
310                // `first_root_dir_block`). Other directories can have any size
311                // as they are made of regular clusters.
312                let mut current_cluster = Some(dir_cluster);
313                let mut first_dir_block_num = match dir_cluster {
314                    ClusterId::ROOT_DIR => self.lba_start + fat16_info.first_root_dir_block,
315                    _ => self.cluster_to_block(dir_cluster),
316                };
317                let dir_size = match dir_cluster {
318                    ClusterId::ROOT_DIR => {
319                        let len_bytes =
320                            u32::from(fat16_info.root_entries_count) * OnDiskDirEntry::LEN_U32;
321                        BlockCount::from_bytes(len_bytes)
322                    }
323                    _ => BlockCount(u32::from(self.blocks_per_cluster)),
324                };
325
326                // Walk the directory
327                let mut blocks = [Block::new()];
328                while let Some(cluster) = current_cluster {
329                    for block in first_dir_block_num.range(dir_size) {
330                        block_device
331                            .read(&mut blocks, block, "read_dir")
332                            .map_err(Error::DeviceError)?;
333                        let entries_per_block = Block::LEN / OnDiskDirEntry::LEN;
334                        for entry in 0..entries_per_block {
335                            let start = entry * OnDiskDirEntry::LEN;
336                            let end = (entry + 1) * OnDiskDirEntry::LEN;
337                            let dir_entry = OnDiskDirEntry::new(&blocks[0][start..end]);
338                            // 0x00 or 0xE5 represents a free entry
339                            if !dir_entry.is_valid() {
340                                let ctime = time_source.get_timestamp();
341                                let entry = DirEntry::new(
342                                    name,
343                                    attributes,
344                                    ClusterId::EMPTY,
345                                    ctime,
346                                    block,
347                                    start as u32,
348                                );
349                                blocks[0][start..start + 32]
350                                    .copy_from_slice(&entry.serialize(FatType::Fat16)[..]);
351                                block_device
352                                    .write(&blocks, block)
353                                    .map_err(Error::DeviceError)?;
354                                return Ok(entry);
355                            }
356                        }
357                    }
358                    if cluster != ClusterId::ROOT_DIR {
359                        let mut block_cache = BlockCache::empty();
360                        current_cluster =
361                            match self.next_cluster(block_device, cluster, &mut block_cache) {
362                                Ok(n) => {
363                                    first_dir_block_num = self.cluster_to_block(n);
364                                    Some(n)
365                                }
366                                Err(Error::EndOfFile) => {
367                                    let c =
368                                        self.alloc_cluster(block_device, Some(cluster), true)?;
369                                    first_dir_block_num = self.cluster_to_block(c);
370                                    Some(c)
371                                }
372                                _ => None,
373                            };
374                    } else {
375                        current_cluster = None;
376                    }
377                }
378                Err(Error::NotEnoughSpace)
379            }
380            FatSpecificInfo::Fat32(fat32_info) => {
381                // All directories on FAT32 have a cluster chain but the root
382                // dir starts in a specified cluster.
383                let mut current_cluster = match dir_cluster {
384                    ClusterId::ROOT_DIR => Some(fat32_info.first_root_dir_cluster),
385                    _ => Some(dir_cluster),
386                };
387                let mut first_dir_block_num = self.cluster_to_block(dir_cluster);
388                let mut blocks = [Block::new()];
389
390                let dir_size = BlockCount(u32::from(self.blocks_per_cluster));
391                // Walk the cluster chain until we run out of clusters
392                while let Some(cluster) = current_cluster {
393                    // Loop through the blocks in the cluster
394                    for block in first_dir_block_num.range(dir_size) {
395                        // Read a block of directory entries
396                        block_device
397                            .read(&mut blocks, block, "read_dir")
398                            .map_err(Error::DeviceError)?;
399                        // Are any entries in the block we just loaded blank? If so
400                        // we can use them.
401                        for entry in 0..Block::LEN / OnDiskDirEntry::LEN {
402                            let start = entry * OnDiskDirEntry::LEN;
403                            let end = (entry + 1) * OnDiskDirEntry::LEN;
404                            let dir_entry = OnDiskDirEntry::new(&blocks[0][start..end]);
405                            // 0x00 or 0xE5 represents a free entry
406                            if !dir_entry.is_valid() {
407                                let ctime = time_source.get_timestamp();
408                                let entry = DirEntry::new(
409                                    name,
410                                    attributes,
411                                    ClusterId(0),
412                                    ctime,
413                                    block,
414                                    start as u32,
415                                );
416                                blocks[0][start..start + 32]
417                                    .copy_from_slice(&entry.serialize(FatType::Fat32)[..]);
418                                block_device
419                                    .write(&blocks, block)
420                                    .map_err(Error::DeviceError)?;
421                                return Ok(entry);
422                            }
423                        }
424                    }
425                    // Well none of the blocks in that cluster had any space in
426                    // them, let's fetch another one.
427                    let mut block_cache = BlockCache::empty();
428                    current_cluster =
429                        match self.next_cluster(block_device, cluster, &mut block_cache) {
430                            Ok(n) => {
431                                first_dir_block_num = self.cluster_to_block(n);
432                                Some(n)
433                            }
434                            Err(Error::EndOfFile) => {
435                                let c = self.alloc_cluster(block_device, Some(cluster), true)?;
436                                first_dir_block_num = self.cluster_to_block(c);
437                                Some(c)
438                            }
439                            _ => None,
440                        };
441                }
442                // We ran out of clusters in the chain, and apparently we weren't
443                // able to make the chain longer, so the disk must be full.
444                Err(Error::NotEnoughSpace)
445            }
446        }
447    }
448
449    /// Calls callback `func` with every valid entry in the given directory.
450    /// Useful for performing directory listings.
451    pub(crate) fn iterate_dir<D, F>(
452        &self,
453        block_device: &D,
454        dir: &DirectoryInfo,
455        func: F,
456    ) -> Result<(), Error<D::Error>>
457    where
458        F: FnMut(&DirEntry),
459        D: BlockDevice,
460    {
461        match &self.fat_specific_info {
462            FatSpecificInfo::Fat16(fat16_info) => {
463                self.iterate_fat16(dir, fat16_info, block_device, func)
464            }
465            FatSpecificInfo::Fat32(fat32_info) => {
466                self.iterate_fat32(dir, fat32_info, block_device, func)
467            }
468        }
469    }
470
471    fn iterate_fat16<D, F>(
472        &self,
473        dir: &DirectoryInfo,
474        fat16_info: &Fat16Info,
475        block_device: &D,
476        mut func: F,
477    ) -> Result<(), Error<D::Error>>
478    where
479        F: FnMut(&DirEntry),
480        D: BlockDevice,
481    {
482        // Root directories on FAT16 have a fixed size, because they use
483        // a specially reserved space on disk (see
484        // `first_root_dir_block`). Other directories can have any size
485        // as they are made of regular clusters.
486        let mut current_cluster = Some(dir.cluster);
487        let mut first_dir_block_num = match dir.cluster {
488            ClusterId::ROOT_DIR => self.lba_start + fat16_info.first_root_dir_block,
489            _ => self.cluster_to_block(dir.cluster),
490        };
491        let dir_size = match dir.cluster {
492            ClusterId::ROOT_DIR => {
493                let len_bytes = u32::from(fat16_info.root_entries_count) * OnDiskDirEntry::LEN_U32;
494                BlockCount::from_bytes(len_bytes)
495            }
496            _ => BlockCount(u32::from(self.blocks_per_cluster)),
497        };
498
499        let mut block_cache = BlockCache::empty();
500        while let Some(cluster) = current_cluster {
501            for block_idx in first_dir_block_num.range(dir_size) {
502                let block = block_cache.read(block_device, block_idx, "read_dir")?;
503                for entry in 0..Block::LEN / OnDiskDirEntry::LEN {
504                    let start = entry * OnDiskDirEntry::LEN;
505                    let end = (entry + 1) * OnDiskDirEntry::LEN;
506                    let dir_entry = OnDiskDirEntry::new(&block[start..end]);
507                    if dir_entry.is_end() {
508                        // Can quit early
509                        return Ok(());
510                    } else if dir_entry.is_valid() && !dir_entry.is_lfn() {
511                        // Safe, since Block::LEN always fits on a u32
512                        let start = u32::try_from(start).unwrap();
513                        let entry = dir_entry.get_entry(FatType::Fat16, block_idx, start);
514                        func(&entry);
515                    }
516                }
517            }
518            if cluster != ClusterId::ROOT_DIR {
519                current_cluster = match self.next_cluster(block_device, cluster, &mut block_cache) {
520                    Ok(n) => {
521                        first_dir_block_num = self.cluster_to_block(n);
522                        Some(n)
523                    }
524                    _ => None,
525                };
526            } else {
527                current_cluster = None;
528            }
529        }
530        Ok(())
531    }
532
533    fn iterate_fat32<D, F>(
534        &self,
535        dir: &DirectoryInfo,
536        fat32_info: &Fat32Info,
537        block_device: &D,
538        mut func: F,
539    ) -> Result<(), Error<D::Error>>
540    where
541        F: FnMut(&DirEntry),
542        D: BlockDevice,
543    {
544        // All directories on FAT32 have a cluster chain but the root
545        // dir starts in a specified cluster.
546        let mut current_cluster = match dir.cluster {
547            ClusterId::ROOT_DIR => Some(fat32_info.first_root_dir_cluster),
548            _ => Some(dir.cluster),
549        };
550        let mut blocks = [Block::new()];
551        let mut block_cache = BlockCache::empty();
552        while let Some(cluster) = current_cluster {
553            let block_idx = self.cluster_to_block(cluster);
554            for block in block_idx.range(BlockCount(u32::from(self.blocks_per_cluster))) {
555                block_device
556                    .read(&mut blocks, block, "read_dir")
557                    .map_err(Error::DeviceError)?;
558                for entry in 0..Block::LEN / OnDiskDirEntry::LEN {
559                    let start = entry * OnDiskDirEntry::LEN;
560                    let end = (entry + 1) * OnDiskDirEntry::LEN;
561                    let dir_entry = OnDiskDirEntry::new(&blocks[0][start..end]);
562                    if dir_entry.is_end() {
563                        // Can quit early
564                        return Ok(());
565                    } else if dir_entry.is_valid() && !dir_entry.is_lfn() {
566                        // Safe, since Block::LEN always fits on a u32
567                        let start = u32::try_from(start).unwrap();
568                        let entry = dir_entry.get_entry(FatType::Fat32, block, start);
569                        func(&entry);
570                    }
571                }
572            }
573            current_cluster = match self.next_cluster(block_device, cluster, &mut block_cache) {
574                Ok(n) => Some(n),
575                _ => None,
576            };
577        }
578        Ok(())
579    }
580
581    /// Get an entry from the given directory
582    pub(crate) fn find_directory_entry<D>(
583        &self,
584        block_device: &D,
585        dir: &DirectoryInfo,
586        match_name: &ShortFileName,
587    ) -> Result<DirEntry, Error<D::Error>>
588    where
589        D: BlockDevice,
590    {
591        match &self.fat_specific_info {
592            FatSpecificInfo::Fat16(fat16_info) => {
593                // Root directories on FAT16 have a fixed size, because they use
594                // a specially reserved space on disk (see
595                // `first_root_dir_block`). Other directories can have any size
596                // as they are made of regular clusters.
597                let mut current_cluster = Some(dir.cluster);
598                let mut first_dir_block_num = match dir.cluster {
599                    ClusterId::ROOT_DIR => self.lba_start + fat16_info.first_root_dir_block,
600                    _ => self.cluster_to_block(dir.cluster),
601                };
602                let dir_size = match dir.cluster {
603                    ClusterId::ROOT_DIR => {
604                        let len_bytes =
605                            u32::from(fat16_info.root_entries_count) * OnDiskDirEntry::LEN_U32;
606                        BlockCount::from_bytes(len_bytes)
607                    }
608                    _ => BlockCount(u32::from(self.blocks_per_cluster)),
609                };
610
611                let mut block_cache = BlockCache::empty();
612                while let Some(cluster) = current_cluster {
613                    for block in first_dir_block_num.range(dir_size) {
614                        match self.find_entry_in_block(
615                            block_device,
616                            FatType::Fat16,
617                            match_name,
618                            block,
619                        ) {
620                            Err(Error::NotFound) => continue,
621                            x => return x,
622                        }
623                    }
624                    if cluster != ClusterId::ROOT_DIR {
625                        current_cluster =
626                            match self.next_cluster(block_device, cluster, &mut block_cache) {
627                                Ok(n) => {
628                                    first_dir_block_num = self.cluster_to_block(n);
629                                    Some(n)
630                                }
631                                _ => None,
632                            };
633                    } else {
634                        current_cluster = None;
635                    }
636                }
637                Err(Error::NotFound)
638            }
639            FatSpecificInfo::Fat32(fat32_info) => {
640                let mut current_cluster = match dir.cluster {
641                    ClusterId::ROOT_DIR => Some(fat32_info.first_root_dir_cluster),
642                    _ => Some(dir.cluster),
643                };
644                let mut block_cache = BlockCache::empty();
645                while let Some(cluster) = current_cluster {
646                    let block_idx = self.cluster_to_block(cluster);
647                    for block in block_idx.range(BlockCount(u32::from(self.blocks_per_cluster))) {
648                        match self.find_entry_in_block(
649                            block_device,
650                            FatType::Fat32,
651                            match_name,
652                            block,
653                        ) {
654                            Err(Error::NotFound) => continue,
655                            x => return x,
656                        }
657                    }
658                    current_cluster =
659                        match self.next_cluster(block_device, cluster, &mut block_cache) {
660                            Ok(n) => Some(n),
661                            _ => None,
662                        }
663                }
664                Err(Error::NotFound)
665            }
666        }
667    }
668
669    /// Finds an entry in a given block of directory entries.
670    fn find_entry_in_block<D>(
671        &self,
672        block_device: &D,
673        fat_type: FatType,
674        match_name: &ShortFileName,
675        block: BlockIdx,
676    ) -> Result<DirEntry, Error<D::Error>>
677    where
678        D: BlockDevice,
679    {
680        let mut blocks = [Block::new()];
681        block_device
682            .read(&mut blocks, block, "read_dir")
683            .map_err(Error::DeviceError)?;
684        for entry in 0..Block::LEN / OnDiskDirEntry::LEN {
685            let start = entry * OnDiskDirEntry::LEN;
686            let end = (entry + 1) * OnDiskDirEntry::LEN;
687            let dir_entry = OnDiskDirEntry::new(&blocks[0][start..end]);
688            if dir_entry.is_end() {
689                // Can quit early
690                break;
691            } else if dir_entry.matches(match_name) {
692                // Found it
693                // Safe, since Block::LEN always fits on a u32
694                let start = u32::try_from(start).unwrap();
695                return Ok(dir_entry.get_entry(fat_type, block, start));
696            }
697        }
698        Err(Error::NotFound)
699    }
700
701    /// Delete an entry from the given directory
702    pub(crate) fn delete_directory_entry<D>(
703        &self,
704        block_device: &D,
705        dir: &DirectoryInfo,
706        match_name: &ShortFileName,
707    ) -> Result<(), Error<D::Error>>
708    where
709        D: BlockDevice,
710    {
711        match &self.fat_specific_info {
712            FatSpecificInfo::Fat16(fat16_info) => {
713                // Root directories on FAT16 have a fixed size, because they use
714                // a specially reserved space on disk (see
715                // `first_root_dir_block`). Other directories can have any size
716                // as they are made of regular clusters.
717                let mut current_cluster = Some(dir.cluster);
718                let mut first_dir_block_num = match dir.cluster {
719                    ClusterId::ROOT_DIR => self.lba_start + fat16_info.first_root_dir_block,
720                    _ => self.cluster_to_block(dir.cluster),
721                };
722                let dir_size = match dir.cluster {
723                    ClusterId::ROOT_DIR => {
724                        let len_bytes =
725                            u32::from(fat16_info.root_entries_count) * OnDiskDirEntry::LEN_U32;
726                        BlockCount::from_bytes(len_bytes)
727                    }
728                    _ => BlockCount(u32::from(self.blocks_per_cluster)),
729                };
730
731                // Walk the directory
732                while let Some(cluster) = current_cluster {
733                    // Scan the cluster / root dir a block at a time
734                    for block in first_dir_block_num.range(dir_size) {
735                        match self.delete_entry_in_block(block_device, match_name, block) {
736                            Err(Error::NotFound) => {
737                                // Carry on
738                            }
739                            x => {
740                                // Either we deleted it OK, or there was some
741                                // catastrophic error reading/writing the disk.
742                                return x;
743                            }
744                        }
745                    }
746                    // if it's not the root dir, find the next cluster so we can keep looking
747                    if cluster != ClusterId::ROOT_DIR {
748                        let mut block_cache = BlockCache::empty();
749                        current_cluster =
750                            match self.next_cluster(block_device, cluster, &mut block_cache) {
751                                Ok(n) => {
752                                    first_dir_block_num = self.cluster_to_block(n);
753                                    Some(n)
754                                }
755                                _ => None,
756                            };
757                    } else {
758                        current_cluster = None;
759                    }
760                }
761                // Ok, give up
762            }
763            FatSpecificInfo::Fat32(fat32_info) => {
764                // Root directories on FAT32 start at a specified cluster, but
765                // they can have any length.
766                let mut current_cluster = match dir.cluster {
767                    ClusterId::ROOT_DIR => Some(fat32_info.first_root_dir_cluster),
768                    _ => Some(dir.cluster),
769                };
770                // Walk the directory
771                while let Some(cluster) = current_cluster {
772                    // Scan the cluster a block at a time
773                    let block_idx = self.cluster_to_block(cluster);
774                    for block in block_idx.range(BlockCount(u32::from(self.blocks_per_cluster))) {
775                        match self.delete_entry_in_block(block_device, match_name, block) {
776                            Err(Error::NotFound) => {
777                                // Carry on
778                                continue;
779                            }
780                            x => {
781                                // Either we deleted it OK, or there was some
782                                // catastrophic error reading/writing the disk.
783                                return x;
784                            }
785                        }
786                    }
787                    // Find the next cluster
788                    let mut block_cache = BlockCache::empty();
789                    current_cluster =
790                        match self.next_cluster(block_device, cluster, &mut block_cache) {
791                            Ok(n) => Some(n),
792                            _ => None,
793                        }
794                }
795                // Ok, give up
796            }
797        }
798        // If we get here we never found the right entry in any of the
799        // blocks that made up the directory
800        Err(Error::NotFound)
801    }
802
803    /// Deletes a directory entry from a block of directory entries.
804    ///
805    /// Entries are marked as deleted by setting the first byte of the file name
806    /// to a special value.
807    fn delete_entry_in_block<D>(
808        &self,
809        block_device: &D,
810        match_name: &ShortFileName,
811        block: BlockIdx,
812    ) -> Result<(), Error<D::Error>>
813    where
814        D: BlockDevice,
815    {
816        let mut blocks = [Block::new()];
817        block_device
818            .read(&mut blocks, block, "read_dir")
819            .map_err(Error::DeviceError)?;
820        for entry in 0..Block::LEN / OnDiskDirEntry::LEN {
821            let start = entry * OnDiskDirEntry::LEN;
822            let end = (entry + 1) * OnDiskDirEntry::LEN;
823            let dir_entry = OnDiskDirEntry::new(&blocks[0][start..end]);
824            if dir_entry.is_end() {
825                // Can quit early
826                break;
827            } else if dir_entry.matches(match_name) {
828                let mut blocks = blocks;
829                blocks[0].contents[start] = 0xE5;
830                return block_device
831                    .write(&blocks, block)
832                    .map_err(Error::DeviceError);
833            }
834        }
835        Err(Error::NotFound)
836    }
837
838    /// Finds the next free cluster after the start_cluster and before end_cluster
839    pub(crate) fn find_next_free_cluster<D>(
840        &self,
841        block_device: &D,
842        start_cluster: ClusterId,
843        end_cluster: ClusterId,
844    ) -> Result<ClusterId, Error<D::Error>>
845    where
846        D: BlockDevice,
847    {
848        let mut blocks = [Block::new()];
849        let mut current_cluster = start_cluster;
850        match &self.fat_specific_info {
851            FatSpecificInfo::Fat16(_fat16_info) => {
852                while current_cluster.0 < end_cluster.0 {
853                    trace!(
854                        "current_cluster={:?}, end_cluster={:?}",
855                        current_cluster,
856                        end_cluster
857                    );
858                    let fat_offset = current_cluster.0 * 2;
859                    trace!("fat_offset = {:?}", fat_offset);
860                    let this_fat_block_num =
861                        self.lba_start + self.fat_start.offset_bytes(fat_offset);
862                    trace!("this_fat_block_num = {:?}", this_fat_block_num);
863                    let mut this_fat_ent_offset = usize::try_from(fat_offset % Block::LEN_U32)
864                        .map_err(|_| Error::ConversionError)?;
865                    trace!("Reading block {:?}", this_fat_block_num);
866                    block_device
867                        .read(&mut blocks, this_fat_block_num, "next_cluster")
868                        .map_err(Error::DeviceError)?;
869
870                    while this_fat_ent_offset <= Block::LEN - 2 {
871                        let fat_entry = LittleEndian::read_u16(
872                            &blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 1],
873                        );
874                        if fat_entry == 0 {
875                            return Ok(current_cluster);
876                        }
877                        this_fat_ent_offset += 2;
878                        current_cluster += 1;
879                    }
880                }
881            }
882            FatSpecificInfo::Fat32(_fat32_info) => {
883                while current_cluster.0 < end_cluster.0 {
884                    trace!(
885                        "current_cluster={:?}, end_cluster={:?}",
886                        current_cluster,
887                        end_cluster
888                    );
889                    let fat_offset = current_cluster.0 * 4;
890                    trace!("fat_offset = {:?}", fat_offset);
891                    let this_fat_block_num =
892                        self.lba_start + self.fat_start.offset_bytes(fat_offset);
893                    trace!("this_fat_block_num = {:?}", this_fat_block_num);
894                    let mut this_fat_ent_offset = usize::try_from(fat_offset % Block::LEN_U32)
895                        .map_err(|_| Error::ConversionError)?;
896                    trace!("Reading block {:?}", this_fat_block_num);
897                    block_device
898                        .read(&mut blocks, this_fat_block_num, "next_cluster")
899                        .map_err(Error::DeviceError)?;
900
901                    while this_fat_ent_offset <= Block::LEN - 4 {
902                        let fat_entry = LittleEndian::read_u32(
903                            &blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 3],
904                        ) & 0x0FFF_FFFF;
905                        if fat_entry == 0 {
906                            return Ok(current_cluster);
907                        }
908                        this_fat_ent_offset += 4;
909                        current_cluster += 1;
910                    }
911                }
912            }
913        }
914        warn!("Out of space...");
915        Err(Error::NotEnoughSpace)
916    }
917
918    /// Tries to allocate a cluster
919    pub(crate) fn alloc_cluster<D>(
920        &mut self,
921        block_device: &D,
922        prev_cluster: Option<ClusterId>,
923        zero: bool,
924    ) -> Result<ClusterId, Error<D::Error>>
925    where
926        D: BlockDevice,
927    {
928        debug!("Allocating new cluster, prev_cluster={:?}", prev_cluster);
929        let end_cluster = ClusterId(self.cluster_count + RESERVED_ENTRIES);
930        let start_cluster = match self.next_free_cluster {
931            Some(cluster) if cluster.0 < end_cluster.0 => cluster,
932            _ => ClusterId(RESERVED_ENTRIES),
933        };
934        trace!(
935            "Finding next free between {:?}..={:?}",
936            start_cluster,
937            end_cluster
938        );
939        let new_cluster =
940            match self.find_next_free_cluster(block_device, start_cluster, end_cluster) {
941                Ok(cluster) => cluster,
942                Err(_) if start_cluster.0 > RESERVED_ENTRIES => {
943                    debug!(
944                        "Retrying, finding next free between {:?}..={:?}",
945                        ClusterId(RESERVED_ENTRIES),
946                        end_cluster
947                    );
948                    self.find_next_free_cluster(
949                        block_device,
950                        ClusterId(RESERVED_ENTRIES),
951                        end_cluster,
952                    )?
953                }
954                Err(e) => return Err(e),
955            };
956        self.update_fat(block_device, new_cluster, ClusterId::END_OF_FILE)?;
957        if let Some(cluster) = prev_cluster {
958            trace!(
959                "Updating old cluster {:?} to {:?} in FAT",
960                cluster,
961                new_cluster
962            );
963            self.update_fat(block_device, cluster, new_cluster)?;
964        }
965        trace!(
966            "Finding next free between {:?}..={:?}",
967            new_cluster,
968            end_cluster
969        );
970        self.next_free_cluster =
971            match self.find_next_free_cluster(block_device, new_cluster, end_cluster) {
972                Ok(cluster) => Some(cluster),
973                Err(_) if new_cluster.0 > RESERVED_ENTRIES => {
974                    match self.find_next_free_cluster(
975                        block_device,
976                        ClusterId(RESERVED_ENTRIES),
977                        end_cluster,
978                    ) {
979                        Ok(cluster) => Some(cluster),
980                        Err(e) => return Err(e),
981                    }
982                }
983                Err(e) => return Err(e),
984            };
985        debug!("Next free cluster is {:?}", self.next_free_cluster);
986        if let Some(ref mut number_free_cluster) = self.free_clusters_count {
987            *number_free_cluster -= 1;
988        };
989        if zero {
990            let blocks = [Block::new()];
991            let first_block = self.cluster_to_block(new_cluster);
992            let num_blocks = BlockCount(u32::from(self.blocks_per_cluster));
993            for block in first_block.range(num_blocks) {
994                block_device
995                    .write(&blocks, block)
996                    .map_err(Error::DeviceError)?;
997            }
998        }
999        debug!("All done, returning {:?}", new_cluster);
1000        Ok(new_cluster)
1001    }
1002
1003    /// Marks the input cluster as an EOF and all the subsequent clusters in the chain as free
1004    pub(crate) fn truncate_cluster_chain<D>(
1005        &mut self,
1006        block_device: &D,
1007        cluster: ClusterId,
1008    ) -> Result<(), Error<D::Error>>
1009    where
1010        D: BlockDevice,
1011    {
1012        if cluster.0 < RESERVED_ENTRIES {
1013            // file doesn't have any valid cluster allocated, there is nothing to do
1014            return Ok(());
1015        }
1016        let mut next = {
1017            let mut block_cache = BlockCache::empty();
1018            match self.next_cluster(block_device, cluster, &mut block_cache) {
1019                Ok(n) => n,
1020                Err(Error::EndOfFile) => return Ok(()),
1021                Err(e) => return Err(e),
1022            }
1023        };
1024        if let Some(ref mut next_free_cluster) = self.next_free_cluster {
1025            if next_free_cluster.0 > next.0 {
1026                *next_free_cluster = next;
1027            }
1028        } else {
1029            self.next_free_cluster = Some(next);
1030        }
1031        self.update_fat(block_device, cluster, ClusterId::END_OF_FILE)?;
1032        loop {
1033            let mut block_cache = BlockCache::empty();
1034            match self.next_cluster(block_device, next, &mut block_cache) {
1035                Ok(n) => {
1036                    self.update_fat(block_device, next, ClusterId::EMPTY)?;
1037                    next = n;
1038                }
1039                Err(Error::EndOfFile) => {
1040                    self.update_fat(block_device, next, ClusterId::EMPTY)?;
1041                    break;
1042                }
1043                Err(e) => return Err(e),
1044            }
1045            if let Some(ref mut number_free_cluster) = self.free_clusters_count {
1046                *number_free_cluster += 1;
1047            };
1048        }
1049        Ok(())
1050    }
1051
1052    /// Writes a Directory Entry to the disk
1053    pub(crate) fn write_entry_to_disk<D>(
1054        &self,
1055        block_device: &D,
1056        entry: &DirEntry,
1057    ) -> Result<(), Error<D::Error>>
1058    where
1059        D: BlockDevice,
1060    {
1061        let fat_type = match self.fat_specific_info {
1062            FatSpecificInfo::Fat16(_) => FatType::Fat16,
1063            FatSpecificInfo::Fat32(_) => FatType::Fat32,
1064        };
1065        let mut blocks = [Block::new()];
1066        block_device
1067            .read(&mut blocks, entry.entry_block, "read")
1068            .map_err(Error::DeviceError)?;
1069        let block = &mut blocks[0];
1070
1071        let start = usize::try_from(entry.entry_offset).map_err(|_| Error::ConversionError)?;
1072        block[start..start + 32].copy_from_slice(&entry.serialize(fat_type)[..]);
1073
1074        block_device
1075            .write(&blocks, entry.entry_block)
1076            .map_err(Error::DeviceError)?;
1077        Ok(())
1078    }
1079}
1080
1081/// Load the boot parameter block from the start of the given partition and
1082/// determine if the partition contains a valid FAT16 or FAT32 file system.
1083pub fn parse_volume<D>(
1084    block_device: &D,
1085    lba_start: BlockIdx,
1086    num_blocks: BlockCount,
1087) -> Result<VolumeType, Error<D::Error>>
1088where
1089    D: BlockDevice,
1090    D::Error: core::fmt::Debug,
1091{
1092    let mut blocks = [Block::new()];
1093    block_device
1094        .read(&mut blocks, lba_start, "read_bpb")
1095        .map_err(Error::DeviceError)?;
1096    let block = &blocks[0];
1097    let bpb = Bpb::create_from_bytes(block).map_err(Error::FormatError)?;
1098    match bpb.fat_type {
1099        FatType::Fat16 => {
1100            if bpb.bytes_per_block() as usize != Block::LEN {
1101                return Err(Error::BadBlockSize(bpb.bytes_per_block()));
1102            }
1103            // FirstDataSector = BPB_ResvdSecCnt + (BPB_NumFATs * FATSz) + RootDirSectors;
1104            let root_dir_blocks = ((u32::from(bpb.root_entries_count()) * OnDiskDirEntry::LEN_U32)
1105                + (Block::LEN_U32 - 1))
1106                / Block::LEN_U32;
1107            let fat_start = BlockCount(u32::from(bpb.reserved_block_count()));
1108            let first_root_dir_block =
1109                fat_start + BlockCount(u32::from(bpb.num_fats()) * bpb.fat_size());
1110            let first_data_block = first_root_dir_block + BlockCount(root_dir_blocks);
1111            let mut volume = FatVolume {
1112                lba_start,
1113                num_blocks,
1114                name: VolumeName { data: [0u8; 11] },
1115                blocks_per_cluster: bpb.blocks_per_cluster(),
1116                first_data_block: (first_data_block),
1117                fat_start: BlockCount(u32::from(bpb.reserved_block_count())),
1118                second_fat_start: if bpb.num_fats() == 2 {
1119                    Some(BlockCount(
1120                        u32::from(bpb.reserved_block_count()) + bpb.fat_size(),
1121                    ))
1122                } else {
1123                    None
1124                },
1125                free_clusters_count: None,
1126                next_free_cluster: None,
1127                cluster_count: bpb.total_clusters(),
1128                fat_specific_info: FatSpecificInfo::Fat16(Fat16Info {
1129                    root_entries_count: bpb.root_entries_count(),
1130                    first_root_dir_block,
1131                }),
1132            };
1133            volume.name.data[..].copy_from_slice(bpb.volume_label());
1134            Ok(VolumeType::Fat(volume))
1135        }
1136        FatType::Fat32 => {
1137            // FirstDataSector = BPB_ResvdSecCnt + (BPB_NumFATs * FATSz);
1138            let first_data_block = u32::from(bpb.reserved_block_count())
1139                + (u32::from(bpb.num_fats()) * bpb.fat_size());
1140
1141            // Safe to unwrap since this is a Fat32 Type
1142            let info_location = bpb.fs_info_block().unwrap();
1143            let mut info_blocks = [Block::new()];
1144            block_device
1145                .read(
1146                    &mut info_blocks,
1147                    lba_start + info_location,
1148                    "read_info_sector",
1149                )
1150                .map_err(Error::DeviceError)?;
1151            let info_block = &info_blocks[0];
1152            let info_sector =
1153                InfoSector::create_from_bytes(info_block).map_err(Error::FormatError)?;
1154
1155            let mut volume = FatVolume {
1156                lba_start,
1157                num_blocks,
1158                name: VolumeName { data: [0u8; 11] },
1159                blocks_per_cluster: bpb.blocks_per_cluster(),
1160                first_data_block: BlockCount(first_data_block),
1161                fat_start: BlockCount(u32::from(bpb.reserved_block_count())),
1162                second_fat_start: if bpb.num_fats() == 2 {
1163                    Some(BlockCount(
1164                        u32::from(bpb.reserved_block_count()) + bpb.fat_size(),
1165                    ))
1166                } else {
1167                    None
1168                },
1169                free_clusters_count: info_sector.free_clusters_count(),
1170                next_free_cluster: info_sector.next_free_cluster(),
1171                cluster_count: bpb.total_clusters(),
1172                fat_specific_info: FatSpecificInfo::Fat32(Fat32Info {
1173                    info_location: lba_start + info_location,
1174                    first_root_dir_cluster: ClusterId(bpb.first_root_dir_cluster()),
1175                }),
1176            };
1177            volume.name.data[..].copy_from_slice(bpb.volume_label());
1178            Ok(VolumeType::Fat(volume))
1179        }
1180    }
1181}
1182
1183// ****************************************************************************
1184//
1185// End Of File
1186//
1187// ****************************************************************************