embedded_fat/fat/
volume.rs

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