embedded_sdmmc/fat/
volume.rs

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