1use 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#[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 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 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 '\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 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 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 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#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
147#[derive(Debug, PartialEq, Eq)]
148pub struct FatVolume {
149 pub(crate) lba_start: BlockIdx,
151 pub(crate) num_blocks: BlockCount,
153 pub(crate) name: VolumeName,
155 pub(crate) blocks_per_cluster: u8,
157 pub(crate) first_data_block: BlockCount,
160 pub(crate) fat_start: BlockCount,
163 pub(crate) second_fat_start: Option<BlockCount>,
166 pub(crate) free_clusters_count: Option<u32>,
168 pub(crate) next_free_cluster: Option<ClusterId>,
170 pub(crate) cluster_count: u32,
172 pub(crate) fat_specific_info: FatSpecificInfo,
174}
175
176impl FatVolume {
177 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 }
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 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 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 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 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 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 Err(Error::BadCluster)
317 }
318 0xFFF8..=0xFFFF => {
319 Err(Error::EndOfFile)
321 }
322 f => {
323 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 Err(Error::UnterminatedFatChain)
341 }
342 0x0FFF_FFF7 => {
343 Err(Error::BadCluster)
345 }
346 0x0000_0001 | 0x0FFF_FFF8..=0x0FFF_FFFF => {
347 Err(Error::EndOfFile)
349 }
350 f => {
351 Ok(ClusterId(f))
353 }
354 }
355 }
356 }
357 }
358
359 pub(crate) fn bytes_per_cluster(&self) -> u32 {
361 u32::from(self.blocks_per_cluster) * Block::LEN_U32
362 }
363
364 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 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 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 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 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 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 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 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 while let Some(cluster) = current_cluster {
489 for block_idx in first_dir_block_num.range(dir_size) {
491 trace!("Reading directory");
493 let block = block_cache
494 .read_mut(block_idx)
495 .map_err(Error::DeviceError)?;
496 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 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 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 Err(Error::NotEnoughSpace)
539 }
540 }
541 }
542
543 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 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 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 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 func(de, Some(lfn_buffer.as_str()))
669 } else {
670 func(de, None)
672 }
673 } else {
674 func(de, None)
675 }
676 })
677 }
678
679 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 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 break 'outer;
719 } else if dir_entry.is_valid() {
720 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 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 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 break 'outer;
774 } else if dir_entry.is_valid() {
775 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 break 'outer;
781 }
782 }
783 }
784 }
785 current_cluster = self.next_cluster(block_cache, cluster).ok();
786 }
787 Ok(())
788 }
789
790 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 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 Waiting,
826 Scanning {
828 remaining: &'a str,
829 sequence: u8,
830 csum: u8,
831 },
832 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 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 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 if remaining.is_empty() {
870 state = SeqState::Found { csum }
872 } else {
873 state = SeqState::Waiting
875 }
876 } else {
877 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 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 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 if remaining.is_empty() {
927 state = SeqState::Found { csum }
929 } else {
930 state = SeqState::Waiting
932 }
933 } else {
934 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 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 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 while let Some(cluster) = current_cluster {
990 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 }
996 x => {
997 return x;
1000 }
1001 }
1002 }
1003 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 }
1018 FatSpecificInfo::Fat32(fat32_info) => {
1019 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 while let Some(cluster) = current_cluster {
1027 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 continue;
1036 }
1037 x => {
1038 return x;
1041 }
1042 }
1043 }
1044 current_cluster = self.next_cluster(block_cache, cluster).ok()
1046 }
1047 }
1049 }
1050 Err(Error::NotFound)
1053 }
1054
1055 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 break;
1077 } else if dir_entry.matches(match_name) {
1078 let start = i * OnDiskDirEntry::LEN;
1079 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 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 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 self.update_fat(block_cache, new_cluster, ClusterId::END_OF_FILE)?;
1198 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 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 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 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 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 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 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 let block = block_cache.blank_mut(new_dir_start_block);
1346 let dot_entry_in_child = DirEntry {
1348 name: crate::ShortFileName::this_dir(),
1349 mtime: now,
1350 ctime: now,
1351 attributes: att,
1352 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 let dot_dot_entry_in_child = DirEntry {
1365 name: crate::ShortFileName::parent_dir(),
1366 mtime: now,
1367 ctime: now,
1368 attributes: att,
1369 cluster: if parent == ClusterId::ROOT_DIR {
1371 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
1398pub 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 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 let first_data_block =
1452 fat_start + BlockCount(u32::from(bpb.num_fats()) * bpb.fat_size());
1453 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 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