1use 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#[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 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 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 '\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 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 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 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#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
144#[derive(Debug, PartialEq, Eq)]
145pub struct FatVolume {
146 pub(crate) lba_start: BlockIdx,
148 pub(crate) num_blocks: BlockCount,
150 pub(crate) name: VolumeName,
152 pub(crate) blocks_per_cluster: u8,
154 pub(crate) first_data_block: BlockCount,
157 pub(crate) fat_start: BlockCount,
160 pub(crate) second_fat_start: Option<BlockCount>,
163 pub(crate) free_clusters_count: Option<u32>,
165 pub(crate) next_free_cluster: Option<ClusterId>,
167 pub(crate) cluster_count: u32,
169 pub(crate) fat_specific_info: FatSpecificInfo,
171}
172
173impl FatVolume {
174 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 }
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 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 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 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 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 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 Err(Error::BadCluster)
314 }
315 0xFFF8..=0xFFFF => {
316 Err(Error::EndOfFile)
318 }
319 f => {
320 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 Err(Error::UnterminatedFatChain)
338 }
339 0x0FFF_FFF7 => {
340 Err(Error::BadCluster)
342 }
343 0x0000_0001 | 0x0FFF_FFF8..=0x0FFF_FFFF => {
344 Err(Error::EndOfFile)
346 }
347 f => {
348 Ok(ClusterId(f))
350 }
351 }
352 }
353 }
354 }
355
356 pub(crate) fn bytes_per_cluster(&self) -> u32 {
358 u32::from(self.blocks_per_cluster) * Block::LEN_U32
359 }
360
361 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 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 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 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 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 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 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 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 while let Some(cluster) = current_cluster {
486 for block_idx in first_dir_block_num.range(dir_size) {
488 trace!("Reading directory");
490 let block = block_cache
491 .read_mut(block_idx)
492 .map_err(Error::DeviceError)?;
493 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 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 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 Err(Error::NotEnoughSpace)
536 }
537 }
538 }
539
540 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 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 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 func(de, Some(lfn_buffer.as_str()))
646 } else {
647 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 func(de, Some(lfn_buffer.as_str()))
663 } else {
664 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 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 return Ok(());
712 } else if dir_entry.is_valid() {
713 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 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 return Ok(());
762 } else if dir_entry.is_valid() {
763 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 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 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 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 break;
880 } else if dir_entry.matches(match_name) {
881 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 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 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 while let Some(cluster) = current_cluster {
922 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 }
928 x => {
929 return x;
932 }
933 }
934 }
935 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 }
950 FatSpecificInfo::Fat32(fat32_info) => {
951 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 while let Some(cluster) = current_cluster {
959 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 continue;
968 }
969 x => {
970 return x;
973 }
974 }
975 }
976 current_cluster = match self.next_cluster(block_cache, cluster) {
978 Ok(n) => Some(n),
979 _ => None,
980 }
981 }
982 }
984 }
985 Err(Error::NotFound)
988 }
989
990 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 break;
1012 } else if dir_entry.matches(match_name) {
1013 let start = i * OnDiskDirEntry::LEN;
1014 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 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 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 self.update_fat(block_cache, new_cluster, ClusterId::END_OF_FILE)?;
1136 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 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 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 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 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 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 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 let block = block_cache.blank_mut(new_dir_start_block);
1286 let dot_entry_in_child = DirEntry {
1288 name: crate::ShortFileName::this_dir(),
1289 mtime: now,
1290 ctime: now,
1291 attributes: att,
1292 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 let dot_dot_entry_in_child = DirEntry {
1305 name: crate::ShortFileName::parent_dir(),
1306 mtime: now,
1307 ctime: now,
1308 attributes: att,
1309 cluster: if parent == ClusterId::ROOT_DIR {
1311 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
1338pub 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 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 let first_data_block =
1393 fat_start + BlockCount(u32::from(bpb.num_fats()) * bpb.fat_size());
1394 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 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