Skip to main content

embedded_sdmmc/fat/
volume.rs

1//! FAT-specific volume support.
2
3use core::convert::TryFrom;
4use core::ops::ControlFlow;
5
6use byteorder::{ByteOrder, LittleEndian};
7
8use crate::{
9    Attributes, Block, BlockCache, BlockCount, BlockDevice, BlockIdx, ClusterId, DirEntry,
10    DirectoryInfo, Error, LfnBuffer, ShortFileName, TimeSource, VolumeType, debug,
11    fat::{
12        Bpb, Fat16Info, Fat32Info, FatSpecificInfo, FatType, InfoSector, OnDiskDirEntry,
13        RESERVED_ENTRIES,
14    },
15    filesystem::FilenameError,
16    trace, warn,
17};
18
19/// An MS-DOS 11 character volume label.
20///
21/// ISO-8859-1 encoding is assumed. Trailing spaces are trimmed. Reserved
22/// characters are not allowed. There is no file extension, unlike with a
23/// filename.
24///
25/// Volume labels can be found in the BIOS Parameter Block, and in a root
26/// directory entry with the 'Volume Label' bit set. Both places should have the
27/// same contents, but they can get out of sync.
28///
29/// MS-DOS FDISK would show you the one in the BPB, but DIR would show you the
30/// one in the root directory.
31#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
32#[derive(PartialEq, Eq, Clone)]
33pub struct VolumeName {
34    pub(crate) contents: [u8; Self::TOTAL_LEN],
35}
36
37impl VolumeName {
38    const TOTAL_LEN: usize = 11;
39
40    /// Get name
41    pub fn name(&self) -> &[u8] {
42        let mut bytes = &self.contents[..];
43        while let [rest @ .., last] = bytes {
44            if last.is_ascii_whitespace() {
45                bytes = rest;
46            } else {
47                break;
48            }
49        }
50        bytes
51    }
52
53    /// Create a new MS-DOS volume label.
54    pub fn create_from_str(name: &str) -> Result<VolumeName, FilenameError> {
55        let mut sfn = VolumeName {
56            contents: [b' '; Self::TOTAL_LEN],
57        };
58
59        let mut idx = 0;
60        for ch in name.chars() {
61            match ch {
62                // Microsoft say these are the invalid characters
63                '\u{0000}'..='\u{001F}'
64                | '"'
65                | '*'
66                | '+'
67                | ','
68                | '/'
69                | ':'
70                | ';'
71                | '<'
72                | '='
73                | '>'
74                | '?'
75                | '['
76                | '\\'
77                | ']'
78                | '.'
79                | '|' => {
80                    return Err(FilenameError::InvalidCharacter);
81                }
82                x if x > '\u{00FF}' => {
83                    // We only handle ISO-8859-1 which is Unicode Code Points
84                    // \U+0000 to \U+00FF. This is above that.
85                    return Err(FilenameError::InvalidCharacter);
86                }
87                _ => {
88                    let b = ch as u8;
89                    if idx < Self::TOTAL_LEN {
90                        sfn.contents[idx] = b;
91                    } else {
92                        return Err(FilenameError::NameTooLong);
93                    }
94                    idx += 1;
95                }
96            }
97        }
98        if idx == 0 {
99            return Err(FilenameError::FilenameEmpty);
100        }
101        Ok(sfn)
102    }
103
104    /// Convert to a Short File Name
105    ///
106    /// # Safety
107    ///
108    /// Volume Labels can contain things that Short File Names cannot, so only
109    /// do this conversion if you are creating the name of a directory entry
110    /// with the 'Volume Label' attribute.
111    pub unsafe fn to_short_filename(self) -> ShortFileName {
112        ShortFileName {
113            contents: self.contents,
114        }
115    }
116}
117
118impl core::fmt::Display for VolumeName {
119    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
120        let mut printed = 0;
121        for &c in self.name().iter() {
122            // converting a byte to a codepoint means you are assuming
123            // ISO-8859-1 encoding, because that's how Unicode was designed.
124            write!(f, "{}", c as char)?;
125            printed += 1;
126        }
127        if let Some(mut width) = f.width() {
128            if width > printed {
129                width -= printed;
130                for _ in 0..width {
131                    write!(f, "{}", f.fill())?;
132                }
133            }
134        }
135        Ok(())
136    }
137}
138
139impl core::fmt::Debug for VolumeName {
140    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
141        write!(f, "VolumeName(\"{}\")", self)
142    }
143}
144
145/// Identifies a FAT16 or FAT32 Volume on the disk.
146#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
147#[derive(Debug, PartialEq, Eq)]
148pub struct FatVolume {
149    /// The block number of the start of the partition. All other BlockIdx values are relative to this.
150    pub(crate) lba_start: BlockIdx,
151    /// The number of blocks in this volume
152    pub(crate) num_blocks: BlockCount,
153    /// The name of this volume
154    pub(crate) name: VolumeName,
155    /// Number of 512 byte blocks (or Blocks) in a cluster
156    pub(crate) blocks_per_cluster: u8,
157    /// The block the data starts in. Relative to start of partition (so add
158    /// `self.lba_offset` before passing to volume manager)
159    pub(crate) first_data_block: BlockCount,
160    /// The block the FAT starts in. Relative to start of partition (so add
161    /// `self.lba_offset` before passing to volume manager)
162    pub(crate) fat_start: BlockCount,
163    /// The block the second FAT starts in. Relative to start of partition (so add
164    /// `self.lba_offset` before passing to volume manager)
165    pub(crate) second_fat_start: Option<BlockCount>,
166    /// Expected number of free clusters
167    pub(crate) free_clusters_count: Option<u32>,
168    /// Number of the next expected free cluster
169    pub(crate) next_free_cluster: Option<ClusterId>,
170    /// Total number of clusters
171    pub(crate) cluster_count: u32,
172    /// Type of FAT
173    pub(crate) fat_specific_info: FatSpecificInfo,
174}
175
176impl FatVolume {
177    /// Write a new entry in the FAT
178    pub fn update_info_sector<D>(
179        &mut self,
180        block_cache: &mut BlockCache<D>,
181    ) -> Result<(), Error<D::Error>>
182    where
183        D: BlockDevice,
184    {
185        match &self.fat_specific_info {
186            FatSpecificInfo::Fat16(_) => {
187                // FAT16 volumes don't have an info sector
188            }
189            FatSpecificInfo::Fat32(fat32_info) => {
190                if self.free_clusters_count.is_none() && self.next_free_cluster.is_none() {
191                    return Ok(());
192                }
193                trace!("Reading info sector");
194                let block = block_cache
195                    .read_mut(fat32_info.info_location)
196                    .map_err(Error::DeviceError)?;
197                if let Some(count) = self.free_clusters_count {
198                    block[488..492].copy_from_slice(&count.to_le_bytes());
199                }
200                if let Some(next_free_cluster) = self.next_free_cluster {
201                    block[492..496].copy_from_slice(&next_free_cluster.0.to_le_bytes());
202                }
203                trace!("Writing info sector");
204                block_cache.write_back()?;
205            }
206        }
207        Ok(())
208    }
209
210    /// Get the type of FAT this volume is
211    pub(crate) fn get_fat_type(&self) -> FatType {
212        match &self.fat_specific_info {
213            FatSpecificInfo::Fat16(_) => FatType::Fat16,
214            FatSpecificInfo::Fat32(_) => FatType::Fat32,
215        }
216    }
217
218    /// Write a new entry in the FAT
219    fn update_fat<D>(
220        &mut self,
221        block_cache: &mut BlockCache<D>,
222        cluster: ClusterId,
223        new_value: ClusterId,
224    ) -> Result<(), Error<D::Error>>
225    where
226        D: BlockDevice,
227    {
228        let mut second_fat_block_num = None;
229        match &self.fat_specific_info {
230            FatSpecificInfo::Fat16(_fat16_info) => {
231                let fat_offset = cluster.0 * 2;
232                let this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
233                if let Some(second_fat_start) = self.second_fat_start {
234                    second_fat_block_num =
235                        Some(self.lba_start + second_fat_start.offset_bytes(fat_offset));
236                }
237                let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
238                trace!("Reading FAT for update");
239                let block = block_cache
240                    .read_mut(this_fat_block_num)
241                    .map_err(Error::DeviceError)?;
242                // See <https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system>
243                let entry = match new_value {
244                    ClusterId::INVALID => 0xFFF6,
245                    ClusterId::BAD => 0xFFF7,
246                    ClusterId::EMPTY => 0x0000,
247                    ClusterId::END_OF_FILE => 0xFFFF,
248                    _ => new_value.0 as u16,
249                };
250                LittleEndian::write_u16(
251                    &mut block[this_fat_ent_offset..=this_fat_ent_offset + 1],
252                    entry,
253                );
254            }
255            FatSpecificInfo::Fat32(_fat32_info) => {
256                // FAT32 => 4 bytes per entry
257                let fat_offset = cluster.0 * 4;
258                let this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
259                if let Some(second_fat_start) = self.second_fat_start {
260                    second_fat_block_num =
261                        Some(self.lba_start + second_fat_start.offset_bytes(fat_offset));
262                }
263                let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
264                trace!("Reading FAT for update");
265                let block = block_cache
266                    .read_mut(this_fat_block_num)
267                    .map_err(Error::DeviceError)?;
268                let entry = match new_value {
269                    ClusterId::INVALID => 0x0FFF_FFF6,
270                    ClusterId::BAD => 0x0FFF_FFF7,
271                    ClusterId::EMPTY => 0x0000_0000,
272                    _ => new_value.0,
273                };
274                let existing =
275                    LittleEndian::read_u32(&block[this_fat_ent_offset..=this_fat_ent_offset + 3]);
276                let new = (existing & 0xF000_0000) | (entry & 0x0FFF_FFFF);
277                LittleEndian::write_u32(
278                    &mut block[this_fat_ent_offset..=this_fat_ent_offset + 3],
279                    new,
280                );
281            }
282        }
283        trace!("Updating FAT");
284        if let Some(duplicate) = second_fat_block_num {
285            block_cache.write_back_with_duplicate(duplicate)?;
286        } else {
287            block_cache.write_back()?;
288        }
289        Ok(())
290    }
291
292    /// Look in the FAT to see which cluster comes next.
293    pub(crate) fn next_cluster<D>(
294        &self,
295        block_cache: &mut BlockCache<D>,
296        cluster: ClusterId,
297    ) -> Result<ClusterId, Error<D::Error>>
298    where
299        D: BlockDevice,
300    {
301        if cluster.0 > (u32::MAX / 4) {
302            panic!("next_cluster called on invalid cluster {:x?}", cluster);
303        }
304        match &self.fat_specific_info {
305            FatSpecificInfo::Fat16(_fat16_info) => {
306                let fat_offset = cluster.0 * 2;
307                let this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
308                let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
309                trace!("Walking FAT");
310                let block = block_cache.read(this_fat_block_num)?;
311                let fat_entry =
312                    LittleEndian::read_u16(&block[this_fat_ent_offset..=this_fat_ent_offset + 1]);
313                match fat_entry {
314                    0xFFF7 => {
315                        // Bad cluster
316                        Err(Error::BadCluster)
317                    }
318                    0xFFF8..=0xFFFF => {
319                        // There is no next cluster
320                        Err(Error::EndOfFile)
321                    }
322                    f => {
323                        // Seems legit
324                        Ok(ClusterId(u32::from(f)))
325                    }
326                }
327            }
328            FatSpecificInfo::Fat32(_fat32_info) => {
329                let fat_offset = cluster.0 * 4;
330                let this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
331                let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
332                trace!("Walking FAT");
333                let block = block_cache.read(this_fat_block_num)?;
334                let fat_entry =
335                    LittleEndian::read_u32(&block[this_fat_ent_offset..=this_fat_ent_offset + 3])
336                        & 0x0FFF_FFFF;
337                match fat_entry {
338                    0x0000_0000 => {
339                        // Jumped to free space
340                        Err(Error::UnterminatedFatChain)
341                    }
342                    0x0FFF_FFF7 => {
343                        // Bad cluster
344                        Err(Error::BadCluster)
345                    }
346                    0x0000_0001 | 0x0FFF_FFF8..=0x0FFF_FFFF => {
347                        // There is no next cluster
348                        Err(Error::EndOfFile)
349                    }
350                    f => {
351                        // Seems legit
352                        Ok(ClusterId(f))
353                    }
354                }
355            }
356        }
357    }
358
359    /// Number of bytes in a cluster.
360    pub(crate) fn bytes_per_cluster(&self) -> u32 {
361        u32::from(self.blocks_per_cluster) * Block::LEN_U32
362    }
363
364    /// Converts a cluster number (or `Cluster`) to a block number (or
365    /// `BlockIdx`). Gives an absolute `BlockIdx` you can pass to the
366    /// volume manager.
367    pub(crate) fn cluster_to_block(&self, cluster: ClusterId) -> BlockIdx {
368        match &self.fat_specific_info {
369            FatSpecificInfo::Fat16(fat16_info) => {
370                let block_num = match cluster {
371                    ClusterId::ROOT_DIR => fat16_info.first_root_dir_block,
372                    ClusterId(c) => {
373                        // FirstSectorofCluster = ((N – 2) * BPB_SecPerClus) + FirstDataSector;
374                        let first_block_of_cluster =
375                            BlockCount((c - 2) * u32::from(self.blocks_per_cluster));
376                        self.first_data_block + first_block_of_cluster
377                    }
378                };
379                self.lba_start + block_num
380            }
381            FatSpecificInfo::Fat32(fat32_info) => {
382                let cluster_num = match cluster {
383                    ClusterId::ROOT_DIR => fat32_info.first_root_dir_cluster.0,
384                    c => c.0,
385                };
386                // FirstSectorofCluster = ((N – 2) * BPB_SecPerClus) + FirstDataSector;
387                let first_block_of_cluster =
388                    BlockCount((cluster_num - 2) * u32::from(self.blocks_per_cluster));
389                self.lba_start + self.first_data_block + first_block_of_cluster
390            }
391        }
392    }
393
394    /// Finds a empty entry space and writes the new entry to it, allocates a new cluster if it's
395    /// needed
396    pub(crate) fn write_new_directory_entry<D, T>(
397        &mut self,
398        block_cache: &mut BlockCache<D>,
399        time_source: &T,
400        dir_cluster: ClusterId,
401        name: ShortFileName,
402        attributes: Attributes,
403    ) -> Result<DirEntry, Error<D::Error>>
404    where
405        D: BlockDevice,
406        T: TimeSource,
407    {
408        match &self.fat_specific_info {
409            FatSpecificInfo::Fat16(fat16_info) => {
410                // Root directories on FAT16 have a fixed size, because they use
411                // a specially reserved space on disk (see
412                // `first_root_dir_block`). Other directories can have any size
413                // as they are made of regular clusters.
414                let mut current_cluster = Some(dir_cluster);
415                let mut first_dir_block_num = match dir_cluster {
416                    ClusterId::ROOT_DIR => self.lba_start + fat16_info.first_root_dir_block,
417                    _ => self.cluster_to_block(dir_cluster),
418                };
419                let dir_size = match dir_cluster {
420                    ClusterId::ROOT_DIR => {
421                        let len_bytes =
422                            u32::from(fat16_info.root_entries_count) * OnDiskDirEntry::LEN_U32;
423                        BlockCount::from_bytes(len_bytes)
424                    }
425                    _ => BlockCount(u32::from(self.blocks_per_cluster)),
426                };
427
428                // Walk the directory
429                while let Some(cluster) = current_cluster {
430                    for block_idx in first_dir_block_num.range(dir_size) {
431                        trace!("Reading directory");
432                        let block = block_cache
433                            .read_mut(block_idx)
434                            .map_err(Error::DeviceError)?;
435                        for (i, dir_entry_bytes) in
436                            block.chunks_exact_mut(OnDiskDirEntry::LEN).enumerate()
437                        {
438                            let dir_entry = OnDiskDirEntry::new(dir_entry_bytes);
439                            // 0x00 or 0xE5 represents a free entry
440                            if !dir_entry.is_valid() {
441                                let ctime = time_source.get_timestamp();
442                                let entry = DirEntry::new(
443                                    name,
444                                    attributes,
445                                    ClusterId::EMPTY,
446                                    ctime,
447                                    block_idx,
448                                    (i * OnDiskDirEntry::LEN) as u32,
449                                );
450                                dir_entry_bytes
451                                    .copy_from_slice(&entry.serialize(FatType::Fat16)[..]);
452                                trace!("Updating directory");
453                                block_cache.write_back()?;
454                                return Ok(entry);
455                            }
456                        }
457                    }
458                    if cluster != ClusterId::ROOT_DIR {
459                        current_cluster = match self.next_cluster(block_cache, cluster) {
460                            Ok(n) => {
461                                first_dir_block_num = self.cluster_to_block(n);
462                                Some(n)
463                            }
464                            Err(Error::EndOfFile) => {
465                                let c = self.alloc_cluster(block_cache, Some(cluster), true)?;
466                                first_dir_block_num = self.cluster_to_block(c);
467                                Some(c)
468                            }
469                            _ => None,
470                        };
471                    } else {
472                        current_cluster = None;
473                    }
474                }
475                Err(Error::NotEnoughSpace)
476            }
477            FatSpecificInfo::Fat32(fat32_info) => {
478                // All directories on FAT32 have a cluster chain but the root
479                // dir starts in a specified cluster.
480                let mut current_cluster = match dir_cluster {
481                    ClusterId::ROOT_DIR => Some(fat32_info.first_root_dir_cluster),
482                    _ => Some(dir_cluster),
483                };
484                let mut first_dir_block_num = self.cluster_to_block(dir_cluster);
485
486                let dir_size = BlockCount(u32::from(self.blocks_per_cluster));
487                // Walk the cluster chain until we run out of clusters
488                while let Some(cluster) = current_cluster {
489                    // Loop through the blocks in the cluster
490                    for block_idx in first_dir_block_num.range(dir_size) {
491                        // Read a block of directory entries
492                        trace!("Reading directory");
493                        let block = block_cache
494                            .read_mut(block_idx)
495                            .map_err(Error::DeviceError)?;
496                        // Are any entries in the block we just loaded blank? If so
497                        // we can use them.
498                        for (i, dir_entry_bytes) in
499                            block.chunks_exact_mut(OnDiskDirEntry::LEN).enumerate()
500                        {
501                            let dir_entry = OnDiskDirEntry::new(dir_entry_bytes);
502                            // 0x00 or 0xE5 represents a free entry
503                            if !dir_entry.is_valid() {
504                                let ctime = time_source.get_timestamp();
505                                let entry = DirEntry::new(
506                                    name,
507                                    attributes,
508                                    ClusterId(0),
509                                    ctime,
510                                    block_idx,
511                                    (i * OnDiskDirEntry::LEN) as u32,
512                                );
513                                dir_entry_bytes
514                                    .copy_from_slice(&entry.serialize(FatType::Fat32)[..]);
515                                trace!("Updating directory");
516                                block_cache.write_back()?;
517                                return Ok(entry);
518                            }
519                        }
520                    }
521                    // Well none of the blocks in that cluster had any space in
522                    // them, let's fetch another one.
523                    current_cluster = match self.next_cluster(block_cache, cluster) {
524                        Ok(n) => {
525                            first_dir_block_num = self.cluster_to_block(n);
526                            Some(n)
527                        }
528                        Err(Error::EndOfFile) => {
529                            let c = self.alloc_cluster(block_cache, Some(cluster), true)?;
530                            first_dir_block_num = self.cluster_to_block(c);
531                            Some(c)
532                        }
533                        _ => None,
534                    };
535                }
536                // We ran out of clusters in the chain, and apparently we weren't
537                // able to make the chain longer, so the disk must be full.
538                Err(Error::NotEnoughSpace)
539            }
540        }
541    }
542
543    /// Calls callback `func` with every valid entry in the given directory.
544    /// Useful for performing directory listings.
545    pub(crate) fn iterate_dir<D, F>(
546        &self,
547        block_cache: &mut BlockCache<D>,
548        dir_info: &DirectoryInfo,
549        mut func: F,
550    ) -> Result<(), Error<D::Error>>
551    where
552        F: FnMut(&DirEntry) -> ControlFlow<()>,
553        D: BlockDevice,
554    {
555        match &self.fat_specific_info {
556            FatSpecificInfo::Fat16(fat16_info) => {
557                self.iterate_fat16(dir_info, fat16_info, block_cache, |de, _| func(de))
558            }
559            FatSpecificInfo::Fat32(fat32_info) => {
560                self.iterate_fat32(dir_info, fat32_info, block_cache, |de, _| func(de))
561            }
562        }
563    }
564
565    /// Calls callback `func` with every valid entry in the given directory, plus its ODDE.
566    fn iterate_dir_internal<D, F>(
567        &self,
568        block_cache: &mut BlockCache<D>,
569        dir_info: &DirectoryInfo,
570        func: F,
571    ) -> Result<(), Error<D::Error>>
572    where
573        F: FnMut(&DirEntry, &OnDiskDirEntry) -> ControlFlow<()>,
574        D: BlockDevice,
575    {
576        match &self.fat_specific_info {
577            FatSpecificInfo::Fat16(fat16_info) => {
578                self.iterate_fat16(dir_info, fat16_info, block_cache, func)
579            }
580            FatSpecificInfo::Fat32(fat32_info) => {
581                self.iterate_fat32(dir_info, fat32_info, block_cache, func)
582            }
583        }
584    }
585
586    /// Calls callback `func` with every valid entry in the given directory,
587    /// including the Long File Name.
588    ///
589    /// Useful for performing directory listings.
590    pub(crate) fn iterate_dir_lfn<D, F>(
591        &self,
592        block_cache: &mut BlockCache<D>,
593        lfn_buffer: &mut LfnBuffer<'_>,
594        dir_info: &DirectoryInfo,
595        mut func: F,
596    ) -> Result<(), Error<D::Error>>
597    where
598        F: FnMut(&DirEntry, Option<&str>) -> ControlFlow<()>,
599        D: BlockDevice,
600    {
601        #[derive(Clone, Copy)]
602        enum SeqState {
603            Waiting,
604            Remaining { csum: u8, next: u8 },
605            Complete { csum: u8 },
606        }
607
608        impl SeqState {
609            fn update(
610                self,
611                lfn_buffer: &mut LfnBuffer<'_>,
612                start: bool,
613                sequence: u8,
614                csum: u8,
615                buffer: [u16; 13],
616            ) -> Self {
617                #[cfg(feature = "log")]
618                debug!("LFN Contents {start} {sequence} {csum:02x} {buffer:04x?}");
619                #[cfg(feature = "defmt-log")]
620                debug!(
621                    "LFN Contents {=bool} {=u8} {=u8:02x} {=[?; 13]:#04x}",
622                    start, sequence, csum, buffer
623                );
624                match (start, sequence, self) {
625                    (true, 0x01, _) => {
626                        lfn_buffer.clear();
627                        lfn_buffer.push(&buffer);
628                        SeqState::Complete { csum }
629                    }
630                    (true, sequence, _) if (0x02..0x14).contains(&sequence) => {
631                        lfn_buffer.clear();
632                        lfn_buffer.push(&buffer);
633                        SeqState::Remaining {
634                            csum,
635                            next: sequence - 1,
636                        }
637                    }
638                    (false, 0x01, SeqState::Remaining { csum, next }) if next == sequence => {
639                        lfn_buffer.push(&buffer);
640                        SeqState::Complete { csum }
641                    }
642                    (false, sequence, SeqState::Remaining { csum, next })
643                        if (0x01..0x13).contains(&sequence) && next == sequence =>
644                    {
645                        lfn_buffer.push(&buffer);
646                        SeqState::Remaining {
647                            csum,
648                            next: sequence - 1,
649                        }
650                    }
651                    _ => {
652                        // this seems wrong
653                        lfn_buffer.clear();
654                        SeqState::Waiting
655                    }
656                }
657            }
658        }
659
660        let mut seq_state = SeqState::Waiting;
661        self.iterate_dir_internal(block_cache, dir_info, |de, odde| {
662            if let Some((start, this_seqno, csum, buffer)) = odde.lfn_contents() {
663                seq_state = seq_state.update(lfn_buffer, start, this_seqno, csum, buffer);
664                ControlFlow::Continue(())
665            } else if let SeqState::Complete { csum } = seq_state {
666                if csum == de.name.csum() {
667                    // Checksum is good, and all the pieces are there
668                    func(de, Some(lfn_buffer.as_str()))
669                } else {
670                    // Checksum was bad
671                    func(de, None)
672                }
673            } else {
674                func(de, None)
675            }
676        })
677    }
678
679    /// Calls callback `func` with every valid entry in the given FAT16 directory.
680    ///
681    /// Useful for performing directory listings.
682    fn iterate_fat16<D, F>(
683        &self,
684        dir_info: &DirectoryInfo,
685        fat16_info: &Fat16Info,
686        block_cache: &mut BlockCache<D>,
687        mut func: F,
688    ) -> Result<(), Error<D::Error>>
689    where
690        F: for<'odde> FnMut(&DirEntry, &OnDiskDirEntry<'odde>) -> ControlFlow<()>,
691        D: BlockDevice,
692    {
693        // Root directories on FAT16 have a fixed size, because they use
694        // a specially reserved space on disk (see
695        // `first_root_dir_block`). Other directories can have any size
696        // as they are made of regular clusters.
697        let mut current_cluster = Some(dir_info.cluster);
698        let mut first_dir_block_num = match dir_info.cluster {
699            ClusterId::ROOT_DIR => self.lba_start + fat16_info.first_root_dir_block,
700            _ => self.cluster_to_block(dir_info.cluster),
701        };
702        let dir_size = match dir_info.cluster {
703            ClusterId::ROOT_DIR => {
704                let len_bytes = u32::from(fat16_info.root_entries_count) * OnDiskDirEntry::LEN_U32;
705                BlockCount::from_bytes(len_bytes)
706            }
707            _ => BlockCount(u32::from(self.blocks_per_cluster)),
708        };
709
710        'outer: while let Some(cluster) = current_cluster {
711            for block_idx in first_dir_block_num.range(dir_size) {
712                trace!("Reading FAT");
713                let block = block_cache.read(block_idx)?;
714                for (i, dir_entry_bytes) in block.chunks_exact(OnDiskDirEntry::LEN).enumerate() {
715                    let dir_entry = OnDiskDirEntry::new(dir_entry_bytes);
716                    if dir_entry.is_end() {
717                        // Can quit early
718                        break 'outer;
719                    } else if dir_entry.is_valid() {
720                        // Safe, since Block::LEN always fits on a u32
721                        let start = (i * OnDiskDirEntry::LEN) as u32;
722                        let entry = dir_entry.get_entry(FatType::Fat16, block_idx, start);
723                        if func(&entry, &dir_entry) == ControlFlow::Break(()) {
724                            break 'outer;
725                        }
726                    }
727                }
728            }
729            if cluster != ClusterId::ROOT_DIR {
730                current_cluster = match self.next_cluster(block_cache, cluster) {
731                    Ok(n) => {
732                        first_dir_block_num = self.cluster_to_block(n);
733                        Some(n)
734                    }
735                    _ => None,
736                };
737            } else {
738                current_cluster = None;
739            }
740        }
741        Ok(())
742    }
743
744    /// Calls callback `func` with every valid entry in the given FAT32 directory.
745    ///
746    /// Useful for performing directory listings.
747    fn iterate_fat32<D, F>(
748        &self,
749        dir_info: &DirectoryInfo,
750        fat32_info: &Fat32Info,
751        block_cache: &mut BlockCache<D>,
752        mut func: F,
753    ) -> Result<(), Error<D::Error>>
754    where
755        F: for<'odde> FnMut(&DirEntry, &OnDiskDirEntry<'odde>) -> ControlFlow<()>,
756        D: BlockDevice,
757    {
758        // All directories on FAT32 have a cluster chain but the root
759        // dir starts in a specified cluster.
760        let mut current_cluster = match dir_info.cluster {
761            ClusterId::ROOT_DIR => Some(fat32_info.first_root_dir_cluster),
762            _ => Some(dir_info.cluster),
763        };
764        'outer: while let Some(cluster) = current_cluster {
765            let start_block_idx = self.cluster_to_block(cluster);
766            for block_idx in start_block_idx.range(BlockCount(u32::from(self.blocks_per_cluster))) {
767                trace!("Reading FAT");
768                let block = block_cache.read(block_idx).map_err(Error::DeviceError)?;
769                for (i, dir_entry_bytes) in block.chunks_exact(OnDiskDirEntry::LEN).enumerate() {
770                    let dir_entry = OnDiskDirEntry::new(dir_entry_bytes);
771                    if dir_entry.is_end() {
772                        // Can quit early
773                        break 'outer;
774                    } else if dir_entry.is_valid() {
775                        // Safe, since Block::LEN always fits on a u32
776                        let start = (i * OnDiskDirEntry::LEN) as u32;
777                        let entry = dir_entry.get_entry(FatType::Fat32, block_idx, start);
778                        if let ControlFlow::Break(_) = func(&entry, &dir_entry) {
779                            // Can quit early
780                            break 'outer;
781                        }
782                    }
783                }
784            }
785            current_cluster = self.next_cluster(block_cache, cluster).ok();
786        }
787        Ok(())
788    }
789
790    /// Get an entry from the given directory
791    pub(crate) fn find_directory_entry<D>(
792        &self,
793        block_cache: &mut BlockCache<D>,
794        dir_info: &DirectoryInfo,
795        match_name: &ShortFileName,
796    ) -> Result<DirEntry, Error<D::Error>>
797    where
798        D: BlockDevice,
799    {
800        let mut result = Err(Error::NotFound);
801        self.iterate_dir(block_cache, dir_info, |de| {
802            if de.name == *match_name {
803                result = Ok(de.clone());
804                ControlFlow::Break(())
805            } else {
806                ControlFlow::Continue(())
807            }
808        })?;
809        result
810    }
811
812    /// Get an entry from the given directory
813    pub(crate) fn find_directory_entry_by_lfn<D>(
814        &self,
815        block_cache: &mut BlockCache<D>,
816        dir_info: &DirectoryInfo,
817        match_name: &str,
818    ) -> Result<DirEntry, Error<D::Error>>
819    where
820        D: BlockDevice,
821    {
822        let mut result = Err(Error::NotFound);
823        enum SeqState<'a> {
824            /// Looking for the first entry in an LFN sequence
825            Waiting,
826            /// Scanning through an LFN sequence
827            Scanning {
828                remaining: &'a str,
829                sequence: u8,
830                csum: u8,
831            },
832            /// Found an entry we like
833            Found { csum: u8 },
834        }
835
836        let mut state = SeqState::Waiting;
837        self.iterate_dir_internal(block_cache, dir_info, |de, odde| {
838            match state {
839                SeqState::Waiting => {
840                    debug!("Am waiting for LFN start");
841                    let mut remaining = match_name;
842                    if let Some((true, sequence, csum, buffer)) = odde.lfn_contents() {
843                        #[cfg(feature = "defmt-log")]
844                        debug!("{:02x} {:02x} {:04x}", sequence, csum, buffer);
845                        #[cfg(feature = "log")]
846                        debug!("{:02x} {:02x} {:04x?}", sequence, csum, buffer);
847                        // trim padding and NUL words off the end of the file name (which is the part that comes first)
848                        for word in buffer
849                            .iter()
850                            .rev()
851                            .skip_while(|b| **b == 0xFFFF)
852                            .skip_while(|b| **b == 0x0000)
853                        {
854                            debug!("Looking at word {:04x}", *word);
855                            // UCS-2 16-bit values are valid Unicode code points - we do not expect surrogate pairs but if we find then, we give up.
856                            let Some(c) = char::from_u32(*word as u32) else {
857                                return ControlFlow::Continue(());
858                            };
859                            debug!("Looking at char '{}'", c);
860                            let Some(r) = remaining.strip_suffix(c) else {
861                                debug!("No, didn't want that");
862                                return ControlFlow::Continue(());
863                            };
864                            debug!("Liked it! {:?} is left", r);
865                            remaining = r;
866                        }
867                        if sequence == 1 {
868                            // last piece
869                            if remaining.is_empty() {
870                                // found it
871                                state = SeqState::Found { csum }
872                            } else {
873                                // no, we have characters left over
874                                state = SeqState::Waiting
875                            }
876                        } else {
877                            // keep looking
878                            state = SeqState::Scanning {
879                                remaining,
880                                sequence: sequence - 1,
881                                csum,
882                            };
883                        }
884                    }
885                }
886                SeqState::Scanning {
887                    remaining,
888                    sequence,
889                    csum,
890                } => {
891                    debug!(
892                        "Am waiting for more LFN sequence={:02x}, csum={:02x}",
893                        sequence, csum
894                    );
895                    let mut remaining = remaining;
896                    if let Some((false, this_sequence, this_csum, buffer)) = odde.lfn_contents() {
897                        #[cfg(feature = "defmt-log")]
898                        debug!("{:02x} {:02x} {:04x}", sequence, csum, buffer);
899                        #[cfg(feature = "log")]
900                        debug!("{:02x} {:02x} {:04x?}", sequence, csum, buffer);
901                        if (this_sequence != sequence) || (this_csum != csum) {
902                            // not what we wanted
903                            debug!(
904                                "No! Got sequence={:02x}, csum={:02x}",
905                                this_sequence, this_csum
906                            );
907                            state = SeqState::Waiting;
908                            return ControlFlow::Continue(());
909                        }
910                        for word in buffer.iter().rev() {
911                            // UCS-2 16-bit values are valid Unicode code points - we do not expect surrogate pairs but if we find then, we give up.
912                            debug!("Looking at word {:04x}", *word);
913                            let Some(c) = char::from_u32(*word as u32) else {
914                                return ControlFlow::Continue(());
915                            };
916                            debug!("Looking at char '{}'", c);
917                            let Some(r) = remaining.strip_suffix(c) else {
918                                debug!("No, didn't want that");
919                                return ControlFlow::Continue(());
920                            };
921                            debug!("Liked it! {:?} is left", r);
922                            remaining = r;
923                        }
924                        if sequence == 1 {
925                            // last piece
926                            if remaining.is_empty() {
927                                // found it
928                                state = SeqState::Found { csum }
929                            } else {
930                                // no, we have characters left over
931                                state = SeqState::Waiting
932                            }
933                        } else {
934                            // keep looking
935                            state = SeqState::Scanning {
936                                remaining,
937                                sequence: sequence - 1,
938                                csum,
939                            };
940                        }
941                    }
942                }
943                SeqState::Found { csum } => {
944                    let calc_csum = de.name.csum();
945                    if calc_csum == csum {
946                        result = Ok(de.clone());
947                        return ControlFlow::Break(());
948                    } else {
949                        debug!("Bad csum {:02x} != {:02x}", calc_csum, csum);
950                    }
951                }
952            }
953            ControlFlow::Continue(())
954        })?;
955        result
956    }
957
958    /// Delete an entry from the given directory
959    pub(crate) fn delete_directory_entry<D>(
960        &self,
961        block_cache: &mut BlockCache<D>,
962        dir_info: &DirectoryInfo,
963        match_name: &ShortFileName,
964    ) -> Result<(), Error<D::Error>>
965    where
966        D: BlockDevice,
967    {
968        match &self.fat_specific_info {
969            FatSpecificInfo::Fat16(fat16_info) => {
970                // Root directories on FAT16 have a fixed size, because they use
971                // a specially reserved space on disk (see
972                // `first_root_dir_block`). Other directories can have any size
973                // as they are made of regular clusters.
974                let mut current_cluster = Some(dir_info.cluster);
975                let mut first_dir_block_num = match dir_info.cluster {
976                    ClusterId::ROOT_DIR => self.lba_start + fat16_info.first_root_dir_block,
977                    _ => self.cluster_to_block(dir_info.cluster),
978                };
979                let dir_size = match dir_info.cluster {
980                    ClusterId::ROOT_DIR => {
981                        let len_bytes =
982                            u32::from(fat16_info.root_entries_count) * OnDiskDirEntry::LEN_U32;
983                        BlockCount::from_bytes(len_bytes)
984                    }
985                    _ => BlockCount(u32::from(self.blocks_per_cluster)),
986                };
987
988                // Walk the directory
989                while let Some(cluster) = current_cluster {
990                    // Scan the cluster / root dir a block at a time
991                    for block_idx in first_dir_block_num.range(dir_size) {
992                        match self.delete_entry_in_block(block_cache, match_name, block_idx) {
993                            Err(Error::NotFound) => {
994                                // Carry on
995                            }
996                            x => {
997                                // Either we deleted it OK, or there was some
998                                // catastrophic error reading/writing the disk.
999                                return x;
1000                            }
1001                        }
1002                    }
1003                    // if it's not the root dir, find the next cluster so we can keep looking
1004                    if cluster != ClusterId::ROOT_DIR {
1005                        current_cluster = match self.next_cluster(block_cache, cluster) {
1006                            Ok(n) => {
1007                                first_dir_block_num = self.cluster_to_block(n);
1008                                Some(n)
1009                            }
1010                            _ => None,
1011                        };
1012                    } else {
1013                        current_cluster = None;
1014                    }
1015                }
1016                // Ok, give up
1017            }
1018            FatSpecificInfo::Fat32(fat32_info) => {
1019                // Root directories on FAT32 start at a specified cluster, but
1020                // they can have any length.
1021                let mut current_cluster = match dir_info.cluster {
1022                    ClusterId::ROOT_DIR => Some(fat32_info.first_root_dir_cluster),
1023                    _ => Some(dir_info.cluster),
1024                };
1025                // Walk the directory
1026                while let Some(cluster) = current_cluster {
1027                    // Scan the cluster a block at a time
1028                    let start_block_idx = self.cluster_to_block(cluster);
1029                    for block_idx in
1030                        start_block_idx.range(BlockCount(u32::from(self.blocks_per_cluster)))
1031                    {
1032                        match self.delete_entry_in_block(block_cache, match_name, block_idx) {
1033                            Err(Error::NotFound) => {
1034                                // Carry on
1035                                continue;
1036                            }
1037                            x => {
1038                                // Either we deleted it OK, or there was some
1039                                // catastrophic error reading/writing the disk.
1040                                return x;
1041                            }
1042                        }
1043                    }
1044                    // Find the next cluster
1045                    current_cluster = self.next_cluster(block_cache, cluster).ok()
1046                }
1047                // Ok, give up
1048            }
1049        }
1050        // If we get here we never found the right entry in any of the
1051        // blocks that made up the directory
1052        Err(Error::NotFound)
1053    }
1054
1055    /// Deletes a directory entry from a block of directory entries.
1056    ///
1057    /// Entries are marked as deleted by setting the first byte of the file name
1058    /// to a special value.
1059    fn delete_entry_in_block<D>(
1060        &self,
1061        block_cache: &mut BlockCache<D>,
1062        match_name: &ShortFileName,
1063        block_idx: BlockIdx,
1064    ) -> Result<(), Error<D::Error>>
1065    where
1066        D: BlockDevice,
1067    {
1068        trace!("Reading directory");
1069        let block = block_cache
1070            .read_mut(block_idx)
1071            .map_err(Error::DeviceError)?;
1072        for (i, dir_entry_bytes) in block.chunks_exact_mut(OnDiskDirEntry::LEN).enumerate() {
1073            let dir_entry = OnDiskDirEntry::new(dir_entry_bytes);
1074            if dir_entry.is_end() {
1075                // Can quit early
1076                break;
1077            } else if dir_entry.matches(match_name) {
1078                let start = i * OnDiskDirEntry::LEN;
1079                // set first byte to the 'unused' marker
1080                block[start] = 0xE5;
1081                trace!("Updating directory");
1082                return block_cache.write_back().map_err(Error::DeviceError);
1083            }
1084        }
1085        Err(Error::NotFound)
1086    }
1087
1088    /// Finds the next free cluster after the start_cluster and before end_cluster
1089    pub(crate) fn find_next_free_cluster<D>(
1090        &self,
1091        block_cache: &mut BlockCache<D>,
1092        start_cluster: ClusterId,
1093        end_cluster: ClusterId,
1094    ) -> Result<ClusterId, Error<D::Error>>
1095    where
1096        D: BlockDevice,
1097    {
1098        let mut current_cluster = start_cluster;
1099        match &self.fat_specific_info {
1100            FatSpecificInfo::Fat16(_fat16_info) => {
1101                while current_cluster.0 < end_cluster.0 {
1102                    trace!(
1103                        "current_cluster={:?}, end_cluster={:?}",
1104                        current_cluster, end_cluster
1105                    );
1106                    let fat_offset = current_cluster.0 * 2;
1107                    trace!("fat_offset = {:?}", fat_offset);
1108                    let this_fat_block_num =
1109                        self.lba_start + self.fat_start.offset_bytes(fat_offset);
1110                    trace!("this_fat_block_num = {:?}", this_fat_block_num);
1111                    let mut this_fat_ent_offset = usize::try_from(fat_offset % Block::LEN_U32)
1112                        .map_err(|_| Error::ConversionError)?;
1113                    trace!("Reading block {:?}", this_fat_block_num);
1114                    let block = block_cache
1115                        .read(this_fat_block_num)
1116                        .map_err(Error::DeviceError)?;
1117                    while this_fat_ent_offset <= Block::LEN - 2 {
1118                        let fat_entry = LittleEndian::read_u16(
1119                            &block[this_fat_ent_offset..=this_fat_ent_offset + 1],
1120                        );
1121                        if fat_entry == 0 {
1122                            return Ok(current_cluster);
1123                        }
1124                        this_fat_ent_offset += 2;
1125                        current_cluster += 1;
1126                    }
1127                }
1128            }
1129            FatSpecificInfo::Fat32(_fat32_info) => {
1130                while current_cluster.0 < end_cluster.0 {
1131                    trace!(
1132                        "current_cluster={:?}, end_cluster={:?}",
1133                        current_cluster, end_cluster
1134                    );
1135                    let fat_offset = current_cluster.0 * 4;
1136                    trace!("fat_offset = {:?}", fat_offset);
1137                    let this_fat_block_num =
1138                        self.lba_start + self.fat_start.offset_bytes(fat_offset);
1139                    trace!("this_fat_block_num = {:?}", this_fat_block_num);
1140                    let mut this_fat_ent_offset = usize::try_from(fat_offset % Block::LEN_U32)
1141                        .map_err(|_| Error::ConversionError)?;
1142                    trace!("Reading block {:?}", this_fat_block_num);
1143                    let block = block_cache
1144                        .read(this_fat_block_num)
1145                        .map_err(Error::DeviceError)?;
1146                    while this_fat_ent_offset <= Block::LEN - 4 {
1147                        let fat_entry = LittleEndian::read_u32(
1148                            &block[this_fat_ent_offset..=this_fat_ent_offset + 3],
1149                        ) & 0x0FFF_FFFF;
1150                        if fat_entry == 0 {
1151                            return Ok(current_cluster);
1152                        }
1153                        this_fat_ent_offset += 4;
1154                        current_cluster += 1;
1155                    }
1156                }
1157            }
1158        }
1159        warn!("Out of space...");
1160        Err(Error::NotEnoughSpace)
1161    }
1162
1163    /// Tries to allocate a cluster
1164    pub(crate) fn alloc_cluster<D>(
1165        &mut self,
1166        block_cache: &mut BlockCache<D>,
1167        prev_cluster: Option<ClusterId>,
1168        zero: bool,
1169    ) -> Result<ClusterId, Error<D::Error>>
1170    where
1171        D: BlockDevice,
1172    {
1173        debug!("Allocating new cluster, prev_cluster={:?}", prev_cluster);
1174        let end_cluster = ClusterId(self.cluster_count + RESERVED_ENTRIES);
1175        let start_cluster = match self.next_free_cluster {
1176            Some(cluster) if cluster.0 < end_cluster.0 => cluster,
1177            _ => ClusterId(RESERVED_ENTRIES),
1178        };
1179        trace!(
1180            "Finding next free between {:?}..={:?}",
1181            start_cluster, end_cluster
1182        );
1183        let new_cluster = match self.find_next_free_cluster(block_cache, start_cluster, end_cluster)
1184        {
1185            Ok(cluster) => cluster,
1186            Err(_) if start_cluster.0 > RESERVED_ENTRIES => {
1187                debug!(
1188                    "Retrying, finding next free between {:?}..={:?}",
1189                    ClusterId(RESERVED_ENTRIES),
1190                    end_cluster
1191                );
1192                self.find_next_free_cluster(block_cache, ClusterId(RESERVED_ENTRIES), end_cluster)?
1193            }
1194            Err(e) => return Err(e),
1195        };
1196        // This new cluster is the end of the file's chain
1197        self.update_fat(block_cache, new_cluster, ClusterId::END_OF_FILE)?;
1198        // If there's something before this new one, update the FAT to point it at us
1199        if let Some(cluster) = prev_cluster {
1200            trace!(
1201                "Updating old cluster {:?} to {:?} in FAT",
1202                cluster, new_cluster
1203            );
1204            self.update_fat(block_cache, cluster, new_cluster)?;
1205        }
1206        trace!(
1207            "Finding next free between {:?}..={:?}",
1208            new_cluster, end_cluster
1209        );
1210        self.next_free_cluster =
1211            match self.find_next_free_cluster(block_cache, new_cluster, end_cluster) {
1212                Ok(cluster) => Some(cluster),
1213                Err(_) if new_cluster.0 > RESERVED_ENTRIES => {
1214                    match self.find_next_free_cluster(
1215                        block_cache,
1216                        ClusterId(RESERVED_ENTRIES),
1217                        end_cluster,
1218                    ) {
1219                        Ok(cluster) => Some(cluster),
1220                        Err(e) => return Err(e),
1221                    }
1222                }
1223                Err(e) => return Err(e),
1224            };
1225        debug!("Next free cluster is {:?}", self.next_free_cluster);
1226        // Record that we've allocated a cluster
1227        if let Some(ref mut number_free_cluster) = self.free_clusters_count {
1228            *number_free_cluster -= 1;
1229        };
1230        if zero {
1231            let start_block_idx = self.cluster_to_block(new_cluster);
1232            let num_blocks = BlockCount(u32::from(self.blocks_per_cluster));
1233            for block_idx in start_block_idx.range(num_blocks) {
1234                trace!("Zeroing cluster {:?}", block_idx);
1235                let _block = block_cache.blank_mut(block_idx);
1236                block_cache.write_back()?;
1237            }
1238        }
1239        debug!("All done, returning {:?}", new_cluster);
1240        Ok(new_cluster)
1241    }
1242
1243    /// Marks the input cluster as an EOF and all the subsequent clusters in the chain as free
1244    pub(crate) fn truncate_cluster_chain<D>(
1245        &mut self,
1246        block_cache: &mut BlockCache<D>,
1247        cluster: ClusterId,
1248    ) -> Result<(), Error<D::Error>>
1249    where
1250        D: BlockDevice,
1251    {
1252        if cluster.0 < RESERVED_ENTRIES {
1253            // file doesn't have any valid cluster allocated, there is nothing to do
1254            return Ok(());
1255        }
1256        let mut next = {
1257            match self.next_cluster(block_cache, cluster) {
1258                Ok(n) => n,
1259                Err(Error::EndOfFile) => return Ok(()),
1260                Err(e) => return Err(e),
1261            }
1262        };
1263        if let Some(ref mut next_free_cluster) = self.next_free_cluster {
1264            if next_free_cluster.0 > next.0 {
1265                *next_free_cluster = next;
1266            }
1267        } else {
1268            self.next_free_cluster = Some(next);
1269        }
1270        self.update_fat(block_cache, cluster, ClusterId::END_OF_FILE)?;
1271        loop {
1272            match self.next_cluster(block_cache, next) {
1273                Ok(n) => {
1274                    self.update_fat(block_cache, next, ClusterId::EMPTY)?;
1275                    next = n;
1276                }
1277                Err(Error::EndOfFile) => {
1278                    self.update_fat(block_cache, next, ClusterId::EMPTY)?;
1279                    break;
1280                }
1281                Err(e) => return Err(e),
1282            }
1283            if let Some(ref mut number_free_cluster) = self.free_clusters_count {
1284                *number_free_cluster += 1;
1285            };
1286        }
1287        Ok(())
1288    }
1289
1290    /// Writes a Directory Entry to the disk
1291    pub(crate) fn write_entry_to_disk<D>(
1292        &self,
1293        block_cache: &mut BlockCache<D>,
1294        entry: &DirEntry,
1295    ) -> Result<(), Error<D::Error>>
1296    where
1297        D: BlockDevice,
1298    {
1299        let fat_type = match self.fat_specific_info {
1300            FatSpecificInfo::Fat16(_) => FatType::Fat16,
1301            FatSpecificInfo::Fat32(_) => FatType::Fat32,
1302        };
1303        trace!("Reading directory for update");
1304        let block = block_cache
1305            .read_mut(entry.entry_block)
1306            .map_err(Error::DeviceError)?;
1307
1308        let start = usize::try_from(entry.entry_offset).map_err(|_| Error::ConversionError)?;
1309        block[start..start + 32].copy_from_slice(&entry.serialize(fat_type)[..]);
1310
1311        trace!("Updating directory");
1312        block_cache.write_back().map_err(Error::DeviceError)?;
1313        Ok(())
1314    }
1315
1316    /// Create a new directory.
1317    ///
1318    /// 1) Creates the directory entry in the parent
1319    /// 2) Allocates a new cluster to hold the new directory
1320    /// 3) Writes out the `.` and `..` entries in the new directory
1321    pub(crate) fn make_dir<D, T>(
1322        &mut self,
1323        block_cache: &mut BlockCache<D>,
1324        time_source: &T,
1325        parent: ClusterId,
1326        sfn: ShortFileName,
1327        att: Attributes,
1328    ) -> Result<(), Error<D::Error>>
1329    where
1330        D: BlockDevice,
1331        T: TimeSource,
1332    {
1333        let mut new_dir_entry_in_parent =
1334            self.write_new_directory_entry(block_cache, time_source, parent, sfn, att)?;
1335        if new_dir_entry_in_parent.cluster == ClusterId::EMPTY {
1336            new_dir_entry_in_parent.cluster = self.alloc_cluster(block_cache, None, false)?;
1337            // update the parent dir with the cluster of the new dir
1338            self.write_entry_to_disk(block_cache, &new_dir_entry_in_parent)?;
1339        }
1340        let new_dir_start_block = self.cluster_to_block(new_dir_entry_in_parent.cluster);
1341        debug!("Made new dir entry {:?}", new_dir_entry_in_parent);
1342        let now = time_source.get_timestamp();
1343        let fat_type = self.get_fat_type();
1344        // A blank block
1345        let block = block_cache.blank_mut(new_dir_start_block);
1346        // make the "." entry
1347        let dot_entry_in_child = DirEntry {
1348            name: crate::ShortFileName::this_dir(),
1349            mtime: now,
1350            ctime: now,
1351            attributes: att,
1352            // point at ourselves
1353            cluster: new_dir_entry_in_parent.cluster,
1354            size: 0,
1355            entry_block: new_dir_start_block,
1356            entry_offset: 0,
1357        };
1358        debug!("New dir has {:?}", dot_entry_in_child);
1359        let mut offset = 0;
1360        block[offset..offset + OnDiskDirEntry::LEN]
1361            .copy_from_slice(&dot_entry_in_child.serialize(fat_type)[..]);
1362        offset += OnDiskDirEntry::LEN;
1363        // make the ".." entry
1364        let dot_dot_entry_in_child = DirEntry {
1365            name: crate::ShortFileName::parent_dir(),
1366            mtime: now,
1367            ctime: now,
1368            attributes: att,
1369            // point at our parent
1370            cluster: if parent == ClusterId::ROOT_DIR {
1371                // indicate parent is root using Cluster(0)
1372                ClusterId::EMPTY
1373            } else {
1374                parent
1375            },
1376            size: 0,
1377            entry_block: new_dir_start_block,
1378            entry_offset: OnDiskDirEntry::LEN_U32,
1379        };
1380        debug!("New dir has {:?}", dot_dot_entry_in_child);
1381        block[offset..offset + OnDiskDirEntry::LEN]
1382            .copy_from_slice(&dot_dot_entry_in_child.serialize(fat_type)[..]);
1383
1384        block_cache.write_back()?;
1385
1386        for block_idx in new_dir_start_block
1387            .range(BlockCount(u32::from(self.blocks_per_cluster)))
1388            .skip(1)
1389        {
1390            let _block = block_cache.blank_mut(block_idx);
1391            block_cache.write_back()?;
1392        }
1393
1394        Ok(())
1395    }
1396}
1397
1398/// Load the boot parameter block from the start of the given partition and
1399/// determine if the partition contains a valid FAT16 or FAT32 file system.
1400pub fn parse_volume<D>(
1401    block_cache: &mut BlockCache<D>,
1402    lba_start: BlockIdx,
1403    num_blocks: BlockCount,
1404) -> Result<VolumeType, Error<D::Error>>
1405where
1406    D: BlockDevice,
1407    D::Error: core::fmt::Debug,
1408{
1409    trace!("Reading BPB");
1410    let block = block_cache.read(lba_start).map_err(Error::DeviceError)?;
1411    let bpb = Bpb::create_from_bytes(block).map_err(Error::FormatError)?;
1412    let fat_start = BlockCount(u32::from(bpb.reserved_block_count()));
1413    let second_fat_start = if bpb.num_fats() == 2 {
1414        Some(fat_start + BlockCount(bpb.fat_size()))
1415    } else {
1416        None
1417    };
1418    match bpb.fat_type {
1419        FatType::Fat16 => {
1420            if bpb.bytes_per_block() as usize != Block::LEN {
1421                return Err(Error::BadBlockSize(bpb.bytes_per_block()));
1422            }
1423            // FirstDataSector = BPB_ResvdSecCnt + (BPB_NumFATs * FATSz) + RootDirSectors;
1424            let root_dir_blocks = (u32::from(bpb.root_entries_count()) * OnDiskDirEntry::LEN_U32)
1425                .div_ceil(Block::LEN_U32);
1426            let first_root_dir_block =
1427                fat_start + BlockCount(u32::from(bpb.num_fats()) * bpb.fat_size());
1428            let first_data_block = first_root_dir_block + BlockCount(root_dir_blocks);
1429            let volume = FatVolume {
1430                lba_start,
1431                num_blocks,
1432                name: VolumeName {
1433                    contents: bpb.volume_label(),
1434                },
1435                blocks_per_cluster: bpb.blocks_per_cluster(),
1436                first_data_block,
1437                fat_start,
1438                second_fat_start,
1439                free_clusters_count: None,
1440                next_free_cluster: None,
1441                cluster_count: bpb.total_clusters(),
1442                fat_specific_info: FatSpecificInfo::Fat16(Fat16Info {
1443                    root_entries_count: bpb.root_entries_count(),
1444                    first_root_dir_block,
1445                }),
1446            };
1447            Ok(VolumeType::Fat(volume))
1448        }
1449        FatType::Fat32 => {
1450            // FirstDataSector = BPB_ResvdSecCnt + (BPB_NumFATs * FATSz);
1451            let first_data_block =
1452                fat_start + BlockCount(u32::from(bpb.num_fats()) * bpb.fat_size());
1453            // Safe to unwrap since this is a Fat32 Type
1454            let info_location = bpb.fs_info_block().unwrap();
1455            let mut volume = FatVolume {
1456                lba_start,
1457                num_blocks,
1458                name: VolumeName {
1459                    contents: bpb.volume_label(),
1460                },
1461                blocks_per_cluster: bpb.blocks_per_cluster(),
1462                first_data_block,
1463                fat_start,
1464                second_fat_start,
1465                free_clusters_count: None,
1466                next_free_cluster: None,
1467                cluster_count: bpb.total_clusters(),
1468                fat_specific_info: FatSpecificInfo::Fat32(Fat32Info {
1469                    info_location: lba_start + info_location,
1470                    first_root_dir_cluster: ClusterId(bpb.first_root_dir_cluster()),
1471                }),
1472            };
1473
1474            // Now we don't need the BPB, update the volume with data from the info sector
1475            trace!("Reading info block");
1476            let info_block = block_cache
1477                .read(lba_start + info_location)
1478                .map_err(Error::DeviceError)?;
1479            let info_sector =
1480                InfoSector::create_from_bytes(info_block).map_err(Error::FormatError)?;
1481            volume.free_clusters_count = info_sector.free_clusters_count();
1482            volume.next_free_cluster = info_sector.next_free_cluster();
1483
1484            Ok(VolumeType::Fat(volume))
1485        }
1486    }
1487}
1488
1489#[cfg(test)]
1490mod tests {
1491    use super::*;
1492
1493    #[test]
1494    fn volume_name() {
1495        let sfn = VolumeName {
1496            contents: *b"Hello \xA399  ",
1497        };
1498        assert_eq!(sfn, VolumeName::create_from_str("Hello £99").unwrap())
1499    }
1500}
1501
1502// ****************************************************************************
1503//
1504// End Of File
1505//
1506// ****************************************************************************