1use crate::blockdevice::BlockCount;
6use crate::{
7 Attributes, Block, BlockDevice, BlockIdx, Cluster, Controller, DirEntry, Directory, Error,
8 ShortFileName, TimeSource, Timestamp, VolumeType,
9};
10use byteorder::{ByteOrder, LittleEndian};
11use core::convert::TryFrom;
12use log::{debug, trace, warn};
13
14pub(crate) const RESERVED_ENTRIES: u32 = 2;
15
16#[derive(Debug, Copy, Clone, PartialEq, Eq)]
18pub(crate) enum FatType {
19 Fat16,
21 Fat32,
23}
24
25#[derive(Debug, Eq, PartialEq)]
27pub(crate) enum FatSpecificInfo {
28 Fat16(Fat16Info),
30 Fat32(Fat32Info),
32}
33
34#[derive(Debug, Eq, PartialEq)]
36pub(crate) struct Fat32Info {
37 pub(crate) first_root_dir_cluster: Cluster,
40 pub(crate) info_location: BlockIdx,
42}
43
44#[derive(Debug, Eq, PartialEq)]
46pub(crate) struct Fat16Info {
47 pub(crate) first_root_dir_block: BlockCount,
49 pub(crate) root_entries_count: u16,
51}
52
53#[derive(PartialEq, Eq)]
54pub(crate) struct VolumeName {
55 pub(crate) data: [u8; 11],
56}
57
58#[derive(PartialEq, Eq, Debug)]
60pub struct FatVolume {
61 pub(crate) lba_start: BlockIdx,
63 pub(crate) num_blocks: BlockCount,
65 pub(crate) name: VolumeName,
67 pub(crate) blocks_per_cluster: u8,
69 pub(crate) first_data_block: BlockCount,
71 pub(crate) fat_start: BlockCount,
73 pub(crate) free_clusters_count: Option<u32>,
75 pub(crate) next_free_cluster: Option<Cluster>,
77 pub(crate) cluster_count: u32,
79 pub(crate) fat_specific_info: FatSpecificInfo,
81}
82
83impl core::fmt::Debug for VolumeName {
84 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
85 match core::str::from_utf8(&self.data) {
86 Ok(s) => write!(fmt, "{:?}", s),
87 Err(_e) => write!(fmt, "{:?}", &self.data),
88 }
89 }
90}
91
92struct Bpb<'a> {
93 data: &'a [u8; 512],
94 fat_type: FatType,
95 cluster_count: u32,
96}
97
98impl<'a> Bpb<'a> {
99 const FOOTER_VALUE: u16 = 0xAA55;
100
101 pub fn create_from_bytes(data: &[u8; 512]) -> Result<Bpb, &'static str> {
102 let mut bpb = Bpb {
103 data,
104 fat_type: FatType::Fat16,
105 cluster_count: 0,
106 };
107 if bpb.footer() != Self::FOOTER_VALUE {
108 return Err("Bad BPB footer");
109 }
110
111 let root_dir_blocks = ((u32::from(bpb.root_entries_count()) * OnDiskDirEntry::LEN_U32)
112 + (Block::LEN_U32 - 1))
113 / Block::LEN_U32;
114 let data_blocks = bpb.total_blocks()
115 - (u32::from(bpb.reserved_block_count())
116 + (u32::from(bpb.num_fats()) * bpb.fat_size())
117 + root_dir_blocks);
118 bpb.cluster_count = data_blocks / u32::from(bpb.blocks_per_cluster());
119 if bpb.cluster_count < 4085 {
120 return Err("FAT12 is unsupported");
121 } else if bpb.cluster_count < 65525 {
122 bpb.fat_type = FatType::Fat16;
123 } else {
124 bpb.fat_type = FatType::Fat32;
125 }
126
127 match bpb.fat_type {
128 FatType::Fat16 => Ok(bpb),
129 FatType::Fat32 if bpb.fs_ver() == 0 => {
130 Ok(bpb)
132 }
133 _ => Err("Invalid FAT format"),
134 }
135 }
136
137 define_field!(bytes_per_block, u16, 11);
139 define_field!(blocks_per_cluster, u8, 13);
140 define_field!(reserved_block_count, u16, 14);
141 define_field!(num_fats, u8, 16);
142 define_field!(root_entries_count, u16, 17);
143 define_field!(total_blocks16, u16, 19);
144 define_field!(media, u8, 21);
145 define_field!(fat_size16, u16, 22);
146 define_field!(blocks_per_track, u16, 24);
147 define_field!(num_heads, u16, 26);
148 define_field!(hidden_blocks, u32, 28);
149 define_field!(total_blocks32, u32, 32);
150 define_field!(footer, u16, 510);
151
152 define_field!(fat_size32, u32, 36);
154 define_field!(fs_ver, u16, 42);
155 define_field!(first_root_dir_cluster, u32, 44);
156 define_field!(fs_info, u16, 48);
157 define_field!(backup_boot_block, u16, 50);
158
159 pub fn oem_name(&self) -> &[u8] {
160 &self.data[3..11]
161 }
162
163 pub fn drive_number(&self) -> u8 {
166 if self.fat_type != FatType::Fat32 {
167 self.data[36]
168 } else {
169 self.data[64]
170 }
171 }
172
173 pub fn boot_signature(&self) -> u8 {
174 if self.fat_type != FatType::Fat32 {
175 self.data[38]
176 } else {
177 self.data[66]
178 }
179 }
180
181 pub fn volume_id(&self) -> u32 {
182 if self.fat_type != FatType::Fat32 {
183 LittleEndian::read_u32(&self.data[39..=42])
184 } else {
185 LittleEndian::read_u32(&self.data[67..=70])
186 }
187 }
188
189 pub fn volume_label(&self) -> &[u8] {
190 if self.fat_type != FatType::Fat32 {
191 &self.data[43..=53]
192 } else {
193 &self.data[71..=81]
194 }
195 }
196
197 pub fn fs_type(&self) -> &[u8] {
198 if self.fat_type != FatType::Fat32 {
199 &self.data[54..=61]
200 } else {
201 &self.data[82..=89]
202 }
203 }
204
205 pub fn current_fat(&self) -> u8 {
208 self.data[40] & 0x0F
209 }
210
211 pub fn use_specific_fat(&self) -> bool {
212 (self.data[40] & 0x80) != 0x00
213 }
214
215 pub fn root_cluster(&self) -> Cluster {
216 Cluster(LittleEndian::read_u32(&self.data[44..=47]))
217 }
218
219 pub fn fs_info_block(&self) -> Option<BlockCount> {
220 if self.fat_type != FatType::Fat32 {
221 None
222 } else {
223 Some(BlockCount(u32::from(self.fs_info())))
224 }
225 }
226
227 pub fn fat_size(&self) -> u32 {
230 let result = u32::from(self.fat_size16());
231 if result != 0 {
232 result
233 } else {
234 self.fat_size32()
235 }
236 }
237
238 pub fn total_blocks(&self) -> u32 {
239 let result = u32::from(self.total_blocks16());
240 if result != 0 {
241 result
242 } else {
243 self.total_blocks32()
244 }
245 }
246
247 pub fn total_clusters(&self) -> u32 {
248 self.cluster_count
249 }
250}
251
252struct InfoSector<'a> {
258 data: &'a [u8; 512],
259}
260
261impl<'a> InfoSector<'a> {
262 const LEAD_SIG: u32 = 0x4161_5252;
263 const STRUC_SIG: u32 = 0x6141_7272;
264 const TRAIL_SIG: u32 = 0xAA55_0000;
265
266 fn create_from_bytes(data: &[u8; 512]) -> Result<InfoSector, &'static str> {
267 let info = InfoSector { data };
268 if info.lead_sig() != Self::LEAD_SIG {
269 return Err("Bad lead signature on InfoSector");
270 }
271 if info.struc_sig() != Self::STRUC_SIG {
272 return Err("Bad struc signature on InfoSector");
273 }
274 if info.trail_sig() != Self::TRAIL_SIG {
275 return Err("Bad trail signature on InfoSector");
276 }
277 Ok(info)
278 }
279
280 define_field!(lead_sig, u32, 0);
281 define_field!(struc_sig, u32, 484);
282 define_field!(free_count, u32, 488);
283 define_field!(next_free, u32, 492);
284 define_field!(trail_sig, u32, 508);
285
286 pub fn free_clusters_count(&self) -> Option<u32> {
287 match self.free_count() {
288 0xFFFF_FFFF => None,
289 n => Some(n),
290 }
291 }
292
293 pub fn next_free_cluster(&self) -> Option<Cluster> {
294 match self.next_free() {
295 0xFFFF_FFFF | 0 | 1 => None,
297 n => Some(Cluster(n)),
298 }
299 }
300}
301
302pub(crate) struct OnDiskDirEntry<'a> {
303 data: &'a [u8],
304}
305
306impl<'a> core::fmt::Debug for OnDiskDirEntry<'a> {
307 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
308 write!(f, "OnDiskDirEntry<")?;
309 write!(f, "raw_attr = {}", self.raw_attr())?;
310 write!(f, ", create_time = {}", self.create_time())?;
311 write!(f, ", create_date = {}", self.create_date())?;
312 write!(f, ", last_access_data = {}", self.last_access_data())?;
313 write!(f, ", first_cluster_hi = {}", self.first_cluster_hi())?;
314 write!(f, ", write_time = {}", self.write_time())?;
315 write!(f, ", write_date = {}", self.write_date())?;
316 write!(f, ", first_cluster_lo = {}", self.first_cluster_lo())?;
317 write!(f, ", file_size = {}", self.file_size())?;
318 write!(f, ", is_end = {}", self.is_end())?;
319 write!(f, ", is_valid = {}", self.is_valid())?;
320 write!(f, ", is_lfn = {}", self.is_lfn())?;
321 write!(
322 f,
323 ", first_cluster_fat32 = {:?}",
324 self.first_cluster_fat32()
325 )?;
326 write!(
327 f,
328 ", first_cluster_fat16 = {:?}",
329 self.first_cluster_fat16()
330 )?;
331 write!(f, ">")?;
332 Ok(())
333 }
334}
335
336impl<'a> OnDiskDirEntry<'a> {
339 pub(crate) const LEN: usize = 32;
340 pub(crate) const LEN_U32: u32 = 32;
341 const LFN_FRAGMENT_LEN: usize = 13;
342
343 define_field!(raw_attr, u8, 11);
344 define_field!(create_time, u16, 14);
345 define_field!(create_date, u16, 16);
346 define_field!(last_access_data, u16, 18);
347 define_field!(first_cluster_hi, u16, 20);
348 define_field!(write_time, u16, 22);
349 define_field!(write_date, u16, 24);
350 define_field!(first_cluster_lo, u16, 26);
351 define_field!(file_size, u32, 28);
352
353 fn new(data: &[u8]) -> OnDiskDirEntry {
354 OnDiskDirEntry { data }
355 }
356
357 fn is_end(&self) -> bool {
358 self.data[0] == 0x00
359 }
360
361 fn is_valid(&self) -> bool {
362 !self.is_end() && (self.data[0] != 0xE5)
363 }
364
365 fn is_lfn(&self) -> bool {
366 let attributes = Attributes::create_from_fat(self.raw_attr());
367 attributes.is_lfn()
368 }
369
370 fn lfn_contents(&self) -> Option<(bool, u8, [char; 13])> {
371 if self.is_lfn() {
372 let mut buffer = [' '; 13];
373 let is_start = (self.data[0] & 0x40) != 0;
374 let sequence = self.data[0] & 0x1F;
375 buffer[0] =
376 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[1..=2]))).unwrap();
377 buffer[1] =
378 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[3..=4]))).unwrap();
379 buffer[2] =
380 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[5..=6]))).unwrap();
381 buffer[3] =
382 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[7..=8]))).unwrap();
383 buffer[4] = core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[9..=10])))
384 .unwrap();
385 buffer[5] =
386 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[14..=15])))
387 .unwrap();
388 buffer[6] =
389 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[16..=17])))
390 .unwrap();
391 buffer[7] =
392 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[18..=19])))
393 .unwrap();
394 buffer[8] =
395 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[20..=21])))
396 .unwrap();
397 buffer[9] =
398 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[22..=23])))
399 .unwrap();
400 buffer[10] =
401 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[24..=25])))
402 .unwrap();
403 buffer[11] =
404 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[28..=29])))
405 .unwrap();
406 buffer[12] =
407 core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[30..=31])))
408 .unwrap();
409 Some((is_start, sequence, buffer))
410 } else {
411 None
412 }
413 }
414
415 fn matches(&self, sfn: &ShortFileName) -> bool {
416 self.data[0..11] == sfn.contents
417 }
418
419 fn first_cluster_fat32(&self) -> Cluster {
420 let cluster_no =
421 (u32::from(self.first_cluster_hi()) << 16) | u32::from(self.first_cluster_lo());
422 Cluster(cluster_no)
423 }
424
425 fn first_cluster_fat16(&self) -> Cluster {
426 let cluster_no = u32::from(self.first_cluster_lo());
427 Cluster(cluster_no)
428 }
429
430 fn get_entry(&self, fat_type: FatType, entry_block: BlockIdx, entry_offset: u32) -> DirEntry {
431 let mut result = DirEntry {
432 name: ShortFileName {
433 contents: [0u8; 11],
434 },
435 mtime: Timestamp::from_fat(self.write_date(), self.write_time()),
436 ctime: Timestamp::from_fat(self.create_date(), self.create_time()),
437 attributes: Attributes::create_from_fat(self.raw_attr()),
438 cluster: if fat_type == FatType::Fat32 {
439 self.first_cluster_fat32()
440 } else {
441 self.first_cluster_fat16()
442 },
443 size: self.file_size(),
444 entry_block,
445 entry_offset,
446 };
447 result.name.contents.copy_from_slice(&self.data[0..11]);
448 result
449 }
450}
451
452impl FatVolume {
453 pub fn update_info_sector<D, T>(
455 &mut self,
456 controller: &mut Controller<D, T>,
457 ) -> Result<(), Error<D::Error>>
458 where
459 D: BlockDevice,
460 T: TimeSource,
461 {
462 match &self.fat_specific_info {
463 FatSpecificInfo::Fat16(_) => {}
464 FatSpecificInfo::Fat32(fat32_info) => {
465 if self.free_clusters_count.is_none() && self.next_free_cluster.is_none() {
466 return Ok(());
467 }
468 let mut blocks = [Block::new()];
469 controller
470 .block_device
471 .read(&mut blocks, fat32_info.info_location, "read_info_sector")
472 .map_err(Error::DeviceError)?;
473 let block = &mut blocks[0];
474 if let Some(count) = self.free_clusters_count {
475 block[488..492].copy_from_slice(&count.to_le_bytes());
476 }
477 if let Some(next_free_cluster) = self.next_free_cluster {
478 block[492..496].copy_from_slice(&next_free_cluster.0.to_le_bytes());
479 }
480 controller
481 .block_device
482 .write(&blocks, fat32_info.info_location)
483 .map_err(Error::DeviceError)?;
484 }
485 }
486 Ok(())
487 }
488
489 pub(crate) fn get_fat_type(&self) -> FatType {
491 match &self.fat_specific_info {
492 FatSpecificInfo::Fat16(_) => FatType::Fat16,
493 FatSpecificInfo::Fat32(_) => FatType::Fat32,
494 }
495 }
496
497 fn get_fat<D, T>(
499 &self,
500 controller: &mut Controller<D, T>,
501 cluster: Cluster,
502 ) -> Result<Cluster, Error<D::Error>>
503 where
504 D: BlockDevice,
505 T: TimeSource,
506 {
507 let mut blocks = [Block::new()];
508 let entry = match &self.fat_specific_info {
509 FatSpecificInfo::Fat16(_fat16_info) => {
510 let fat_offset = cluster.0 * 2;
511 let this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
512 let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
513 controller
514 .block_device
515 .read(&mut blocks, this_fat_block_num, "read_fat")
516 .map_err(Error::DeviceError)?;
517 u32::from(LittleEndian::read_u16(
518 &blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 1],
519 ))
520 }
521 FatSpecificInfo::Fat32(_fat32_info) => {
522 let fat_offset = cluster.0 as u32 * 4;
524 let this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
525 let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
526 controller
527 .block_device
528 .read(&mut blocks, this_fat_block_num, "read_fat")
529 .map_err(Error::DeviceError)?;
530 LittleEndian::read_u32(&blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 3])
531 & 0x0FFF_FFFF
532 }
533 };
534 Ok(Cluster(entry))
535 }
536
537 fn update_fat<D, T>(
539 &mut self,
540 controller: &mut Controller<D, T>,
541 cluster: Cluster,
542 new_value: Cluster,
543 ) -> Result<(), Error<D::Error>>
544 where
545 D: BlockDevice,
546 T: TimeSource,
547 {
548 let mut blocks = [Block::new()];
549 let this_fat_block_num;
550 match &self.fat_specific_info {
551 FatSpecificInfo::Fat16(_fat16_info) => {
552 let fat_offset = cluster.0 * 2;
553 this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
554 let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
555 controller
556 .block_device
557 .read(&mut blocks, this_fat_block_num, "read_fat")
558 .map_err(Error::DeviceError)?;
559 let entry = match new_value {
560 Cluster::INVALID => 0xFFF6,
561 Cluster::BAD => 0xFFF7,
562 Cluster::EMPTY => 0x0000,
563 Cluster::END_OF_FILE => 0xFFFF,
564 _ => new_value.0 as u16,
565 };
566 LittleEndian::write_u16(
567 &mut blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 1],
568 entry,
569 );
570 }
571 FatSpecificInfo::Fat32(_fat32_info) => {
572 let fat_offset = cluster.0 as u32 * 4;
574 this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
575 let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
576 controller
577 .block_device
578 .read(&mut blocks, this_fat_block_num, "read_fat")
579 .map_err(Error::DeviceError)?;
580 let entry = match new_value {
581 Cluster::INVALID => 0x0FFF_FFF6,
582 Cluster::BAD => 0x0FFF_FFF7,
583 Cluster::EMPTY => 0x0000_0000,
584 _ => new_value.0,
585 };
586 let existing = LittleEndian::read_u32(
587 &blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 3],
588 );
589 let new = (existing & 0xF000_0000) | (entry & 0x0FFF_FFFF);
590 LittleEndian::write_u32(
591 &mut blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 3],
592 new,
593 );
594 }
595 }
596 controller
597 .block_device
598 .write(&blocks, this_fat_block_num)
599 .map_err(Error::DeviceError)?;
600 Ok(())
601 }
602
603 pub(crate) fn next_cluster<D, T>(
605 &self,
606 controller: &Controller<D, T>,
607 cluster: Cluster,
608 ) -> Result<Cluster, Error<D::Error>>
609 where
610 D: BlockDevice,
611 T: TimeSource,
612 {
613 let mut blocks = [Block::new()];
614 match &self.fat_specific_info {
615 FatSpecificInfo::Fat16(_fat16_info) => {
616 let fat_offset = cluster.0 * 2;
617 let this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
618 let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
619 controller
620 .block_device
621 .read(&mut blocks, this_fat_block_num, "next_cluster")
622 .map_err(Error::DeviceError)?;
623 let fat_entry = LittleEndian::read_u16(
624 &blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 1],
625 );
626 match fat_entry {
627 0xFFF7 => {
628 Err(Error::BadCluster)
630 }
631 0xFFF8..=0xFFFF => {
632 Err(Error::EndOfFile)
634 }
635 f => {
636 Ok(Cluster(u32::from(f)))
638 }
639 }
640 }
641 FatSpecificInfo::Fat32(_fat32_info) => {
642 let fat_offset = cluster.0 * 4;
643 let this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
644 let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
645 controller
646 .block_device
647 .read(&mut blocks, this_fat_block_num, "next_cluster")
648 .map_err(Error::DeviceError)?;
649 let fat_entry = LittleEndian::read_u32(
650 &blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 3],
651 ) & 0x0FFF_FFFF;
652 match fat_entry {
653 0x0000_0000 => {
654 Err(Error::JumpedFree)
656 }
657 0x0FFF_FFF7 => {
658 Err(Error::BadCluster)
660 }
661 0x0000_0001 | 0x0FFF_FFF8..=0x0FFF_FFFF => {
662 Err(Error::EndOfFile)
664 }
665 f => {
666 Ok(Cluster(f))
668 }
669 }
670 }
671 }
672 }
673
674 pub(crate) fn bytes_per_cluster(&self) -> u32 {
676 u32::from(self.blocks_per_cluster) * Block::LEN_U32
677 }
678
679 pub(crate) fn cluster_to_block(&self, cluster: Cluster) -> BlockIdx {
683 match &self.fat_specific_info {
684 FatSpecificInfo::Fat16(fat16_info) => {
685 let block_num = match cluster {
686 Cluster::ROOT_DIR => fat16_info.first_root_dir_block,
687 Cluster(c) => {
688 let first_block_of_cluster =
690 BlockCount((c - 2) * u32::from(self.blocks_per_cluster));
691 self.first_data_block + first_block_of_cluster
692 }
693 };
694 self.lba_start + block_num
695 }
696 FatSpecificInfo::Fat32(fat32_info) => {
697 let cluster_num = match cluster {
698 Cluster::ROOT_DIR => fat32_info.first_root_dir_cluster.0,
699 c => c.0,
700 };
701 let first_block_of_cluster =
703 BlockCount((cluster_num - 2) * u32::from(self.blocks_per_cluster));
704 self.lba_start + self.first_data_block + first_block_of_cluster
705 }
706 }
707 }
708
709 pub(crate) fn write_new_directory_entry<D, T>(
712 &mut self,
713 controller: &mut Controller<D, T>,
714 dir: &Directory,
715 name: ShortFileName,
716 attributes: Attributes,
717 ) -> Result<(DirEntry), Error<D::Error>>
718 where
719 D: BlockDevice,
720 T: TimeSource,
721 {
722 match &self.fat_specific_info {
723 FatSpecificInfo::Fat16(fat16_info) => {
724 let mut first_dir_block_num = match dir.cluster {
725 Cluster::ROOT_DIR => self.lba_start + fat16_info.first_root_dir_block,
726 _ => self.cluster_to_block(dir.cluster),
727 };
728 let mut current_cluster = Some(dir.cluster);
729 let mut blocks = [Block::new()];
730
731 let dir_size = match dir.cluster {
732 Cluster::ROOT_DIR => BlockCount(
733 ((u32::from(fat16_info.root_entries_count) * 32) + (Block::LEN as u32 - 1))
734 / Block::LEN as u32,
735 ),
736 _ => BlockCount(u32::from(self.blocks_per_cluster)),
737 };
738 while let Some(cluster) = current_cluster {
739 for block in first_dir_block_num.range(dir_size) {
740 controller
741 .block_device
742 .read(&mut blocks, block, "read_dir")
743 .map_err(Error::DeviceError)?;
744 for entry in 0..Block::LEN / OnDiskDirEntry::LEN {
745 let start = entry * OnDiskDirEntry::LEN;
746 let end = (entry + 1) * OnDiskDirEntry::LEN;
747 let dir_entry = OnDiskDirEntry::new(&blocks[0][start..end]);
748 if !dir_entry.is_valid() {
750 let ctime = controller.timesource.get_timestamp();
751 let entry = DirEntry::new(
752 name,
753 attributes,
754 Cluster(0),
755 ctime,
756 block,
757 start as u32,
758 );
759 blocks[0][start..start + 32]
760 .copy_from_slice(&entry.serialize(FatType::Fat16)[..]);
761 controller
762 .block_device
763 .write(&blocks, block)
764 .map_err(Error::DeviceError)?;
765 return Ok(entry);
766 }
767 }
768 }
769 if cluster != Cluster::ROOT_DIR {
770 current_cluster = match self.next_cluster(controller, cluster) {
771 Ok(n) => {
772 first_dir_block_num = self.cluster_to_block(n);
773 Some(n)
774 }
775 Err(Error::EndOfFile) => {
776 let c = self.alloc_cluster(controller, Some(cluster), true)?;
777 first_dir_block_num = self.cluster_to_block(c);
778 Some(c)
779 }
780 _ => None,
781 };
782 } else {
783 current_cluster = None;
784 }
785 }
786 Err(Error::NotEnoughSpace)
787 }
788 FatSpecificInfo::Fat32(fat32_info) => {
789 let mut first_dir_block_num = match dir.cluster {
790 Cluster::ROOT_DIR => self.cluster_to_block(fat32_info.first_root_dir_cluster),
791 _ => self.cluster_to_block(dir.cluster),
792 };
793 let mut current_cluster = Some(dir.cluster);
794 let mut blocks = [Block::new()];
795
796 let dir_size = BlockCount(u32::from(self.blocks_per_cluster));
797 while let Some(cluster) = current_cluster {
798 for block in first_dir_block_num.range(dir_size) {
799 controller
800 .block_device
801 .read(&mut blocks, block, "read_dir")
802 .map_err(Error::DeviceError)?;
803 for entry in 0..Block::LEN / OnDiskDirEntry::LEN {
804 let start = entry * OnDiskDirEntry::LEN;
805 let end = (entry + 1) * OnDiskDirEntry::LEN;
806 let dir_entry = OnDiskDirEntry::new(&blocks[0][start..end]);
807 if !dir_entry.is_valid() {
809 let ctime = controller.timesource.get_timestamp();
810 let entry = DirEntry::new(
811 name,
812 attributes,
813 Cluster(0),
814 ctime,
815 block,
816 start as u32,
817 );
818 blocks[0][start..start + 32]
819 .copy_from_slice(&entry.serialize(FatType::Fat32)[..]);
820 controller
821 .block_device
822 .write(&blocks, block)
823 .map_err(Error::DeviceError)?;
824 return Ok(entry);
825 }
826 }
827 }
828 current_cluster = match self.next_cluster(controller, cluster) {
829 Ok(n) => {
830 first_dir_block_num = self.cluster_to_block(n);
831 Some(n)
832 }
833 Err(Error::EndOfFile) => {
834 let c = self.alloc_cluster(controller, Some(cluster), true)?;
835 first_dir_block_num = self.cluster_to_block(c);
836 Some(c)
837 }
838 _ => None,
839 };
840 }
841 Err(Error::NotEnoughSpace)
842 }
843 }
844 }
845
846 pub(crate) fn iterate_dir<D, T, F>(
849 &self,
850 controller: &Controller<D, T>,
851 dir: &Directory,
852 mut func: F,
853 ) -> Result<(), Error<D::Error>>
854 where
855 F: FnMut(&DirEntry),
856 D: BlockDevice,
857 T: TimeSource,
858 {
859 match &self.fat_specific_info {
860 FatSpecificInfo::Fat16(fat16_info) => {
861 let mut first_dir_block_num = match dir.cluster {
862 Cluster::ROOT_DIR => self.lba_start + fat16_info.first_root_dir_block,
863 _ => self.cluster_to_block(dir.cluster),
864 };
865 let mut current_cluster = Some(dir.cluster);
866 let dir_size = match dir.cluster {
867 Cluster::ROOT_DIR => BlockCount(
868 ((u32::from(fat16_info.root_entries_count) * 32) + (Block::LEN as u32 - 1))
869 / Block::LEN as u32,
870 ),
871 _ => BlockCount(u32::from(self.blocks_per_cluster)),
872 };
873 let mut blocks = [Block::new()];
874 while let Some(cluster) = current_cluster {
875 for block in first_dir_block_num.range(dir_size) {
876 controller
877 .block_device
878 .read(&mut blocks, block, "read_dir")
879 .map_err(Error::DeviceError)?;
880 for entry in 0..Block::LEN / OnDiskDirEntry::LEN {
881 let start = entry * OnDiskDirEntry::LEN;
882 let end = (entry + 1) * OnDiskDirEntry::LEN;
883 let dir_entry = OnDiskDirEntry::new(&blocks[0][start..end]);
884 if dir_entry.is_end() {
885 return Ok(());
887 } else if dir_entry.is_valid() && !dir_entry.is_lfn() {
888 let start = u32::try_from(start).unwrap();
890 let entry = dir_entry.get_entry(FatType::Fat16, block, start);
891 func(&entry);
892 }
893 }
894 }
895 if cluster != Cluster::ROOT_DIR {
896 current_cluster = match self.next_cluster(controller, cluster) {
897 Ok(n) => {
898 first_dir_block_num = self.cluster_to_block(n);
899 Some(n)
900 }
901 _ => None,
902 };
903 } else {
904 current_cluster = None;
905 }
906 }
907 Ok(())
908 }
909 FatSpecificInfo::Fat32(fat32_info) => {
910 let mut current_cluster = match dir.cluster {
911 Cluster::ROOT_DIR => Some(fat32_info.first_root_dir_cluster),
912 _ => Some(dir.cluster),
913 };
914 let mut blocks = [Block::new()];
915 while let Some(cluster) = current_cluster {
916 let block_idx = self.cluster_to_block(cluster);
917 for block in block_idx.range(BlockCount(u32::from(self.blocks_per_cluster))) {
918 controller
919 .block_device
920 .read(&mut blocks, block, "read_dir")
921 .map_err(Error::DeviceError)?;
922 for entry in 0..Block::LEN / OnDiskDirEntry::LEN {
923 let start = entry * OnDiskDirEntry::LEN;
924 let end = (entry + 1) * OnDiskDirEntry::LEN;
925 let dir_entry = OnDiskDirEntry::new(&blocks[0][start..end]);
926 if dir_entry.is_end() {
927 return Ok(());
929 } else if dir_entry.is_valid() && !dir_entry.is_lfn() {
930 let start = u32::try_from(start).unwrap();
932 let entry = dir_entry.get_entry(FatType::Fat16, block, start);
933 func(&entry);
934 }
935 }
936 }
937 current_cluster = match self.next_cluster(controller, cluster) {
938 Ok(n) => Some(n),
939 _ => None,
940 };
941 }
942 Ok(())
943 }
944 }
945 }
946
947 pub(crate) fn find_directory_entry<D, T>(
949 &self,
950 controller: &mut Controller<D, T>,
951 dir: &Directory,
952 name: &str,
953 ) -> Result<DirEntry, Error<D::Error>>
954 where
955 D: BlockDevice,
956 T: TimeSource,
957 {
958 let match_name = ShortFileName::create_from_str(name).map_err(Error::FilenameError)?;
959 let mut blocks = [Block::new()];
960 match &self.fat_specific_info {
961 FatSpecificInfo::Fat16(fat16_info) => {
962 let mut current_cluster = Some(dir.cluster);
963 let mut first_dir_block_num = match dir.cluster {
964 Cluster::ROOT_DIR => self.lba_start + fat16_info.first_root_dir_block,
965 _ => self.cluster_to_block(dir.cluster),
966 };
967 let dir_size = match dir.cluster {
968 Cluster::ROOT_DIR => BlockCount(
969 ((u32::from(fat16_info.root_entries_count) * 32) + (Block::LEN as u32 - 1))
970 / Block::LEN as u32,
971 ),
972 _ => BlockCount(u32::from(self.blocks_per_cluster)),
973 };
974
975 while let Some(cluster) = current_cluster {
976 for block in first_dir_block_num.range(dir_size) {
977 controller
978 .block_device
979 .read(&mut blocks, block, "read_dir")
980 .map_err(Error::DeviceError)?;
981 for entry in 0..Block::LEN / OnDiskDirEntry::LEN {
982 let start = entry * OnDiskDirEntry::LEN;
983 let end = (entry + 1) * OnDiskDirEntry::LEN;
984 let dir_entry = OnDiskDirEntry::new(&blocks[0][start..end]);
985 if dir_entry.is_end() {
986 return Err(Error::FileNotFound);
988 } else if dir_entry.matches(&match_name) {
989 let start = u32::try_from(start).unwrap();
992 return Ok(dir_entry.get_entry(FatType::Fat16, block, start));
993 }
994 }
995 }
996 if cluster != Cluster::ROOT_DIR {
997 current_cluster = match self.next_cluster(controller, cluster) {
998 Ok(n) => {
999 first_dir_block_num = self.cluster_to_block(n);
1000 Some(n)
1001 }
1002 _ => None,
1003 };
1004 } else {
1005 current_cluster = None;
1006 }
1007 }
1008 Err(Error::FileNotFound)
1009 }
1010 FatSpecificInfo::Fat32(fat32_info) => {
1011 let match_name =
1012 ShortFileName::create_from_str(name).map_err(Error::FilenameError)?;
1013 let mut current_cluster = match dir.cluster {
1014 Cluster::ROOT_DIR => Some(fat32_info.first_root_dir_cluster),
1015 _ => Some(dir.cluster),
1016 };
1017 let mut blocks = [Block::new()];
1018 while let Some(cluster) = current_cluster {
1019 let block_idx = self.cluster_to_block(cluster);
1020 for block in block_idx.range(BlockCount(u32::from(self.blocks_per_cluster))) {
1021 controller
1022 .block_device
1023 .read(&mut blocks, block, "read_dir")
1024 .map_err(Error::DeviceError)?;
1025 for entry in 0..Block::LEN / OnDiskDirEntry::LEN {
1026 let start = entry * OnDiskDirEntry::LEN;
1027 let end = (entry + 1) * OnDiskDirEntry::LEN;
1028 let dir_entry = OnDiskDirEntry::new(&blocks[0][start..end]);
1029 if dir_entry.is_end() {
1030 return Err(Error::FileNotFound);
1032 } else if dir_entry.matches(&match_name) {
1033 let start = u32::try_from(start).unwrap();
1036 return Ok(dir_entry.get_entry(FatType::Fat16, block, start));
1037 }
1038 }
1039 }
1040 current_cluster = match self.next_cluster(controller, cluster) {
1041 Ok(n) => Some(n),
1042 _ => None,
1043 }
1044 }
1045 Err(Error::FileNotFound)
1046 }
1047 }
1048 }
1049
1050 pub(crate) fn find_next_free_cluster<D, T>(
1052 &self,
1053 controller: &mut Controller<D, T>,
1054 start_cluster: Cluster,
1055 end_cluster: Cluster,
1056 ) -> Result<Cluster, Error<D::Error>>
1057 where
1058 D: BlockDevice,
1059 T: TimeSource,
1060 {
1061 let mut blocks = [Block::new()];
1062 let mut current_cluster = start_cluster;
1063 match &self.fat_specific_info {
1064 FatSpecificInfo::Fat16(_fat16_info) => {
1065 while current_cluster.0 < end_cluster.0 {
1066 trace!(
1067 "current_cluster={:?}, end_cluster={:?}",
1068 current_cluster,
1069 end_cluster
1070 );
1071 let fat_offset = current_cluster.0 * 2;
1072 trace!("fat_offset = {:?}", fat_offset);
1073 let this_fat_block_num =
1074 self.lba_start + self.fat_start.offset_bytes(fat_offset);
1075 trace!("this_fat_block_num = {:?}", this_fat_block_num);
1076 let mut this_fat_ent_offset = usize::try_from(fat_offset % Block::LEN_U32)
1077 .map_err(|_| Error::ConversionError)?;
1078 trace!("Reading block {:?}", this_fat_block_num);
1079 controller
1080 .block_device
1081 .read(&mut blocks, this_fat_block_num, "next_cluster")
1082 .map_err(Error::DeviceError)?;
1083
1084 while this_fat_ent_offset <= Block::LEN - 2 {
1085 let fat_entry = LittleEndian::read_u16(
1086 &blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 1],
1087 );
1088 if fat_entry == 0 {
1089 return Ok(current_cluster);
1090 }
1091 this_fat_ent_offset += 2;
1092 current_cluster += 1;
1093 }
1094 }
1095 }
1096 FatSpecificInfo::Fat32(_fat32_info) => {
1097 while current_cluster.0 < end_cluster.0 {
1098 trace!(
1099 "current_cluster={:?}, end_cluster={:?}",
1100 current_cluster,
1101 end_cluster
1102 );
1103 let fat_offset = current_cluster.0 * 4;
1104 trace!("fat_offset = {:?}", fat_offset);
1105 let this_fat_block_num =
1106 self.lba_start + self.fat_start.offset_bytes(fat_offset);
1107 trace!("this_fat_block_num = {:?}", this_fat_block_num);
1108 let mut this_fat_ent_offset = usize::try_from(fat_offset % Block::LEN_U32)
1109 .map_err(|_| Error::ConversionError)?;
1110 trace!("Reading block {:?}", this_fat_block_num);
1111 controller
1112 .block_device
1113 .read(&mut blocks, this_fat_block_num, "next_cluster")
1114 .map_err(Error::DeviceError)?;
1115
1116 while this_fat_ent_offset <= Block::LEN - 4 {
1117 let fat_entry = LittleEndian::read_u32(
1118 &blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 3],
1119 ) & 0x0FFF_FFFF;
1120 if fat_entry == 0 {
1121 return Ok(current_cluster);
1122 }
1123 this_fat_ent_offset += 4;
1124 current_cluster += 1;
1125 }
1126 }
1127 }
1128 }
1129 warn!("Out of space...");
1130 Err(Error::NotEnoughSpace)
1131 }
1132
1133 pub(crate) fn alloc_cluster<D, T>(
1135 &mut self,
1136 controller: &mut Controller<D, T>,
1137 prev_cluster: Option<Cluster>,
1138 zero: bool,
1139 ) -> Result<Cluster, Error<D::Error>>
1140 where
1141 D: BlockDevice,
1142 T: TimeSource,
1143 {
1144 debug!("Allocating new cluster, prev_cluster={:?}", prev_cluster);
1145 let end_cluster = Cluster(self.cluster_count + RESERVED_ENTRIES);
1146 let start_cluster = match self.next_free_cluster {
1147 Some(cluster) if cluster.0 < end_cluster.0 => cluster,
1148 _ => Cluster(RESERVED_ENTRIES),
1149 };
1150 trace!(
1151 "Finding next free between {:?}..={:?}",
1152 start_cluster,
1153 end_cluster
1154 );
1155 let new_cluster = match self.find_next_free_cluster(controller, start_cluster, end_cluster)
1156 {
1157 Ok(cluster) => cluster,
1158 Err(_) if start_cluster.0 > RESERVED_ENTRIES => {
1159 debug!(
1160 "Retrying, finding next free between {:?}..={:?}",
1161 Cluster(RESERVED_ENTRIES),
1162 end_cluster
1163 );
1164 self.find_next_free_cluster(controller, Cluster(RESERVED_ENTRIES), end_cluster)?
1165 }
1166 Err(e) => return Err(e),
1167 };
1168 self.update_fat(controller, new_cluster, Cluster::END_OF_FILE)?;
1169 if let Some(cluster) = prev_cluster {
1170 trace!(
1171 "Updating old cluster {:?} to {:?} in FAT",
1172 cluster,
1173 new_cluster
1174 );
1175 self.update_fat(controller, cluster, new_cluster)?;
1176 }
1177 trace!(
1178 "Finding next free between {:?}..={:?}",
1179 new_cluster,
1180 end_cluster
1181 );
1182 self.next_free_cluster =
1183 match self.find_next_free_cluster(controller, new_cluster, end_cluster) {
1184 Ok(cluster) => Some(cluster),
1185 Err(_) if new_cluster.0 > RESERVED_ENTRIES => {
1186 match self.find_next_free_cluster(
1187 controller,
1188 Cluster(RESERVED_ENTRIES),
1189 end_cluster,
1190 ) {
1191 Ok(cluster) => Some(cluster),
1192 Err(e) => return Err(e),
1193 }
1194 }
1195 Err(e) => return Err(e),
1196 };
1197 debug!("Next free cluster is {:?}", self.next_free_cluster);
1198 if let Some(ref mut number_free_cluster) = self.free_clusters_count {
1199 *number_free_cluster -= 1;
1200 };
1201 if zero {
1202 let blocks = [Block::new()];
1203 let first_block = self.cluster_to_block(new_cluster);
1204 let num_blocks = BlockCount(u32::from(self.blocks_per_cluster));
1205 for block in first_block.range(num_blocks) {
1206 controller
1207 .block_device
1208 .write(&blocks, block)
1209 .map_err(Error::DeviceError)?;
1210 }
1211 }
1212 debug!("All done, returning {:?}", new_cluster);
1213 Ok(new_cluster)
1214 }
1215
1216 pub(crate) fn alloc_clusters<D, T>(
1218 &mut self,
1219 controller: &mut Controller<D, T>,
1220 mut prev_cluster: Option<Cluster>,
1221 mut clusters_to_alloc: u32,
1222 zero: bool,
1223 ) -> Result<(), Error<D::Error>>
1224 where
1225 D: BlockDevice,
1226 T: TimeSource,
1227 {
1228 while clusters_to_alloc > 0 {
1229 debug!("Allocating clusters, left={:?}", clusters_to_alloc);
1230 let new_cluster = self.alloc_cluster(controller, prev_cluster, zero)?;
1231 prev_cluster = Some(new_cluster);
1232 clusters_to_alloc -= 1;
1233 }
1234 Ok(())
1235 }
1236
1237 pub(crate) fn truncate_cluster_chain<D, T>(
1239 &mut self,
1240 controller: &mut Controller<D, T>,
1241 cluster: Cluster,
1242 ) -> Result<(), Error<D::Error>>
1243 where
1244 D: BlockDevice,
1245 T: TimeSource,
1246 {
1247 if cluster.0 < RESERVED_ENTRIES {
1248 return Ok(());
1250 }
1251 let mut next = match self.next_cluster(controller, cluster) {
1252 Ok(n) => n,
1253 Err(Error::EndOfFile) => return Ok(()),
1254 Err(e) => return Err(e),
1255 };
1256 if let Some(ref mut next_free_cluster) = self.next_free_cluster {
1257 if next_free_cluster.0 > next.0 {
1258 *next_free_cluster = next;
1259 }
1260 } else {
1261 self.next_free_cluster = Some(next);
1262 }
1263 self.update_fat(controller, cluster, Cluster::END_OF_FILE)?;
1264 loop {
1265 match self.next_cluster(controller, next) {
1266 Ok(n) => {
1267 self.update_fat(controller, next, Cluster::EMPTY)?;
1268 next = n;
1269 }
1270 Err(Error::EndOfFile) => {
1271 self.update_fat(controller, next, Cluster::EMPTY)?;
1272 break;
1273 }
1274 Err(e) => return Err(e),
1275 }
1276 if let Some(ref mut number_free_cluster) = self.free_clusters_count {
1277 *number_free_cluster += 1;
1278 };
1279 }
1280 Ok(())
1281 }
1282}
1283
1284pub fn parse_volume<D, T>(
1287 controller: &mut Controller<D, T>,
1288 lba_start: BlockIdx,
1289 num_blocks: BlockCount,
1290) -> Result<VolumeType, Error<D::Error>>
1291where
1292 D: BlockDevice,
1293 T: TimeSource,
1294 D::Error: core::fmt::Debug,
1295{
1296 let mut blocks = [Block::new()];
1297 controller
1298 .block_device
1299 .read(&mut blocks, lba_start, "read_bpb")
1300 .map_err(Error::DeviceError)?;
1301 let block = &blocks[0];
1302 let bpb = Bpb::create_from_bytes(&block).map_err(Error::FormatError)?;
1303 match bpb.fat_type {
1304 FatType::Fat16 => {
1305 let root_dir_blocks = ((u32::from(bpb.root_entries_count()) * OnDiskDirEntry::LEN_U32)
1307 + (Block::LEN_U32 - 1))
1308 / Block::LEN_U32;
1309 let fat_start = BlockCount(u32::from(bpb.reserved_block_count()));
1310 let first_root_dir_block =
1311 fat_start + BlockCount(u32::from(bpb.num_fats()) * bpb.fat_size());
1312 let first_data_block = first_root_dir_block + BlockCount(root_dir_blocks);
1313 let mut volume = FatVolume {
1314 lba_start,
1315 num_blocks,
1316 name: VolumeName { data: [0u8; 11] },
1317 blocks_per_cluster: bpb.blocks_per_cluster(),
1318 first_data_block: (first_data_block),
1319 fat_start: BlockCount(u32::from(bpb.reserved_block_count())),
1320 free_clusters_count: None,
1321 next_free_cluster: None,
1322 cluster_count: bpb.total_clusters(),
1323 fat_specific_info: FatSpecificInfo::Fat16(Fat16Info {
1324 root_entries_count: bpb.root_entries_count(),
1325 first_root_dir_block,
1326 }),
1327 };
1328 volume.name.data[..].copy_from_slice(bpb.volume_label());
1329 Ok(VolumeType::Fat(volume))
1330 }
1331 FatType::Fat32 => {
1332 let first_data_block = u32::from(bpb.reserved_block_count())
1334 + (u32::from(bpb.num_fats()) * bpb.fat_size());
1335
1336 let info_location = bpb.fs_info_block().unwrap();
1338 let mut info_blocks = [Block::new()];
1339 controller
1340 .block_device
1341 .read(
1342 &mut info_blocks,
1343 lba_start + info_location,
1344 "read_info_sector",
1345 )
1346 .map_err(Error::DeviceError)?;
1347 let info_block = &info_blocks[0];
1348 let info_sector =
1349 InfoSector::create_from_bytes(&info_block).map_err(Error::FormatError)?;
1350
1351 let mut volume = FatVolume {
1352 lba_start,
1353 num_blocks,
1354 name: VolumeName { data: [0u8; 11] },
1355 blocks_per_cluster: bpb.blocks_per_cluster(),
1356 first_data_block: BlockCount(first_data_block),
1357 fat_start: BlockCount(u32::from(bpb.reserved_block_count())),
1358 free_clusters_count: info_sector.free_clusters_count(),
1359 next_free_cluster: info_sector.next_free_cluster(),
1360 cluster_count: bpb.total_clusters(),
1361 fat_specific_info: FatSpecificInfo::Fat32(Fat32Info {
1362 info_location: lba_start + info_location,
1363 first_root_dir_cluster: Cluster(bpb.first_root_dir_cluster()),
1364 }),
1365 };
1366 volume.name.data[..].copy_from_slice(bpb.volume_label());
1367 Ok(VolumeType::Fat(volume))
1368 }
1369 }
1370}
1371
1372#[cfg(test)]
1373mod test {
1374 use super::*;
1375
1376 fn parse(input: &str) -> Vec<u8> {
1377 let mut output = Vec::new();
1378 for line in input.lines() {
1379 let line = line.trim();
1380 if !line.is_empty() {
1381 for index in 0..32 {
1383 let start = index * 2;
1384 let end = start + 1;
1385 let piece = &line[start..=end];
1386 let value = u8::from_str_radix(piece, 16).unwrap();
1387 output.push(value);
1388 }
1389 }
1390 }
1391 output
1392 }
1393
1394 #[test]
1421 fn test_dir_entries() {
1422 #[derive(Debug)]
1423 enum Expected {
1424 Lfn(bool, u8, [char; 13]),
1425 Short(DirEntry),
1426 }
1427 let raw_data = r#"
1428 626f6f7420202020202020080000699c754775470000699c7547000000000000 boot ...i.uGuG..i.uG......
1429 416f007600650072006c000f00476100790073000000ffffffff0000ffffffff Ao.v.e.r.l...Ga.y.s.............
1430 4f5645524c4159532020201000001b9f6148614800001b9f6148030000000000 OVERLAYS .....aHaH....aH......
1431 422d0070006c00750073000f00792e006400740062000000ffff0000ffffffff B-.p.l.u.s...y..d.t.b...........
1432 01620063006d00320037000f0079300038002d0072007000690000002d006200 .b.c.m.2.7...y0.8.-.r.p.i...-.b.
1433 42434d3237307e31445442200064119f614861480000119f61480900702b0000 BCM270~1DTB .d..aHaH....aH..p+..
1434 4143004f005000590049000f00124e0047002e006c0069006e00000075007800 AC.O.P.Y.I....N.G...l.i.n...u.x.
1435 434f5059494e7e314c494e2000000f9f6148614800000f9f6148050005490000 COPYIN~1LIN ....aHaH....aH...I..
1436 4263006f006d000000ffff0f0067ffffffffffffffffffffffff0000ffffffff Bc.o.m.......g..................
1437 014c004900430045004e000f0067430045002e00620072006f00000061006400 .L.I.C.E.N...gC.E...b.r.o...a.d.
1438 4c4943454e437e3142524f200000119f614861480000119f61480800d6050000 LICENC~1BRO ....aHaH....aH......
1439 422d0062002e00640074000f001962000000ffffffffffffffff0000ffffffff B-.b...d.t....b.................
1440 01620063006d00320037000f0019300039002d0072007000690000002d003200 .b.c.m.2.7....0.9.-.r.p.i...-.2.
1441 42434d3237307e34445442200064129f614861480000129f61480f004c2f0000 BCM270~4DTB .d..aHaH....aH..L/..
1442 422e0064007400620000000f0059ffffffffffffffffffffffff0000ffffffff B..d.t.b.....Y..................
1443 01620063006d00320037000f0059300038002d0072007000690000002d006200 .b.c.m.2.7...Y0.8.-.r.p.i...-.b.
1444 "#;
1445 let results = [
1446 Expected::Short(DirEntry {
1447 name: ShortFileName::create_from_str_mixed_case("boot").unwrap(),
1448 mtime: Timestamp::from_calendar(2015, 11, 21, 19, 35, 18).unwrap(),
1449 ctime: Timestamp::from_calendar(2015, 11, 21, 19, 35, 18).unwrap(),
1450 attributes: Attributes::create_from_fat(Attributes::VOLUME),
1451 cluster: Cluster(0),
1452 size: 0,
1453 entry_block: BlockIdx(0),
1454 entry_offset: 0,
1455 }),
1456 Expected::Lfn(
1457 true,
1458 1,
1459 [
1460 'o', 'v', 'e', 'r', 'l', 'a', 'y', 's', '\u{0000}', '\u{ffff}', '\u{ffff}',
1461 '\u{ffff}', '\u{ffff}',
1462 ],
1463 ),
1464 Expected::Short(DirEntry {
1465 name: ShortFileName::create_from_str("OVERLAYS").unwrap(),
1466 mtime: Timestamp::from_calendar(2016, 3, 1, 19, 56, 54).unwrap(),
1467 ctime: Timestamp::from_calendar(2016, 3, 1, 19, 56, 54).unwrap(),
1468 attributes: Attributes::create_from_fat(Attributes::DIRECTORY),
1469 cluster: Cluster(3),
1470 size: 0,
1471 entry_block: BlockIdx(0),
1472 entry_offset: 0,
1473 }),
1474 Expected::Lfn(
1475 true,
1476 2,
1477 [
1478 '-', 'p', 'l', 'u', 's', '.', 'd', 't', 'b', '\u{0000}', '\u{ffff}',
1479 '\u{ffff}', '\u{ffff}',
1480 ],
1481 ),
1482 Expected::Lfn(
1483 false,
1484 1,
1485 [
1486 'b', 'c', 'm', '2', '7', '0', '8', '-', 'r', 'p', 'i', '-', 'b',
1487 ],
1488 ),
1489 Expected::Short(DirEntry {
1490 name: ShortFileName::create_from_str("BCM270~1.DTB").unwrap(),
1491 mtime: Timestamp::from_calendar(2016, 3, 1, 19, 56, 34).unwrap(),
1492 ctime: Timestamp::from_calendar(2016, 3, 1, 19, 56, 34).unwrap(),
1493 attributes: Attributes::create_from_fat(Attributes::ARCHIVE),
1494 cluster: Cluster(9),
1495 size: 11120,
1496 entry_block: BlockIdx(0),
1497 entry_offset: 0,
1498 }),
1499 Expected::Lfn(
1500 true,
1501 1,
1502 [
1503 'C', 'O', 'P', 'Y', 'I', 'N', 'G', '.', 'l', 'i', 'n', 'u', 'x',
1504 ],
1505 ),
1506 Expected::Short(DirEntry {
1507 name: ShortFileName::create_from_str("COPYIN~1.LIN").unwrap(),
1508 mtime: Timestamp::from_calendar(2016, 3, 1, 19, 56, 30).unwrap(),
1509 ctime: Timestamp::from_calendar(2016, 3, 1, 19, 56, 30).unwrap(),
1510 attributes: Attributes::create_from_fat(Attributes::ARCHIVE),
1511 cluster: Cluster(5),
1512 size: 18693,
1513 entry_block: BlockIdx(0),
1514 entry_offset: 0,
1515 }),
1516 Expected::Lfn(
1517 true,
1518 2,
1519 [
1520 'c', 'o', 'm', '\u{0}', '\u{ffff}', '\u{ffff}', '\u{ffff}', '\u{ffff}',
1521 '\u{ffff}', '\u{ffff}', '\u{ffff}', '\u{ffff}', '\u{ffff}',
1522 ],
1523 ),
1524 Expected::Lfn(
1525 false,
1526 1,
1527 [
1528 'L', 'I', 'C', 'E', 'N', 'C', 'E', '.', 'b', 'r', 'o', 'a', 'd',
1529 ],
1530 ),
1531 Expected::Short(DirEntry {
1532 name: ShortFileName::create_from_str("LICENC~1.BRO").unwrap(),
1533 mtime: Timestamp::from_calendar(2016, 3, 1, 19, 56, 34).unwrap(),
1534 ctime: Timestamp::from_calendar(2016, 3, 1, 19, 56, 34).unwrap(),
1535 attributes: Attributes::create_from_fat(Attributes::ARCHIVE),
1536 cluster: Cluster(8),
1537 size: 1494,
1538 entry_block: BlockIdx(0),
1539 entry_offset: 0,
1540 }),
1541 Expected::Lfn(
1542 true,
1543 2,
1544 [
1545 '-', 'b', '.', 'd', 't', 'b', '\u{0000}', '\u{ffff}', '\u{ffff}', '\u{ffff}',
1546 '\u{ffff}', '\u{ffff}', '\u{ffff}',
1547 ],
1548 ),
1549 Expected::Lfn(
1550 false,
1551 1,
1552 [
1553 'b', 'c', 'm', '2', '7', '0', '9', '-', 'r', 'p', 'i', '-', '2',
1554 ],
1555 ),
1556 Expected::Short(DirEntry {
1557 name: ShortFileName::create_from_str("BCM270~4.DTB").unwrap(),
1558 mtime: Timestamp::from_calendar(2016, 3, 1, 19, 56, 36).unwrap(),
1559 ctime: Timestamp::from_calendar(2016, 3, 1, 19, 56, 36).unwrap(),
1560 attributes: Attributes::create_from_fat(Attributes::ARCHIVE),
1561 cluster: Cluster(15),
1562 size: 12108,
1563 entry_block: BlockIdx(0),
1564 entry_offset: 0,
1565 }),
1566 Expected::Lfn(
1567 true,
1568 2,
1569 [
1570 '.', 'd', 't', 'b', '\u{0000}', '\u{ffff}', '\u{ffff}', '\u{ffff}', '\u{ffff}',
1571 '\u{ffff}', '\u{ffff}', '\u{ffff}', '\u{ffff}',
1572 ],
1573 ),
1574 Expected::Lfn(
1575 false,
1576 1,
1577 [
1578 'b', 'c', 'm', '2', '7', '0', '8', '-', 'r', 'p', 'i', '-', 'b',
1579 ],
1580 ),
1581 ];
1582
1583 let data = parse(raw_data);
1584 for (part, expected) in data.chunks(OnDiskDirEntry::LEN).zip(results.iter()) {
1585 let on_disk_entry = OnDiskDirEntry::new(part);
1586 match expected {
1587 Expected::Lfn(start, index, contents) if on_disk_entry.is_lfn() => {
1588 let (calc_start, calc_index, calc_contents) =
1589 on_disk_entry.lfn_contents().unwrap();
1590 assert_eq!(*start, calc_start);
1591 assert_eq!(*index, calc_index);
1592 assert_eq!(*contents, calc_contents);
1593 }
1594 Expected::Short(expected_entry) if !on_disk_entry.is_lfn() => {
1595 let parsed_entry = on_disk_entry.get_entry(FatType::Fat32, BlockIdx(0), 0);
1596 assert_eq!(*expected_entry, parsed_entry);
1597 }
1598 _ => {
1599 panic!(
1600 "Bad dir entry, expected:\n{:#?}\nhad\n{:#?}",
1601 expected, on_disk_entry
1602 );
1603 }
1604 }
1605 }
1606 }
1607
1608 #[test]
1609 fn test_bpb() {
1610 const BPB_EXAMPLE: [u8; 512] = [
1612 0xeb, 0x3c, 0x90, 0x6d, 0x6b, 0x66, 0x73, 0x2e, 0x66, 0x61, 0x74, 0x00, 0x02, 0x10,
1613 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0xf8, 0x20, 0x00, 0x3f, 0x00, 0xff, 0x00,
1614 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x80, 0x01, 0x29, 0xbb, 0xb0, 0x71,
1615 0x77, 0x62, 0x6f, 0x6f, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x41,
1616 0x54, 0x31, 0x36, 0x20, 0x20, 0x20, 0x0e, 0x1f, 0xbe, 0x5b, 0x7c, 0xac, 0x22, 0xc0,
1617 0x74, 0x0b, 0x56, 0xb4, 0x0e, 0xbb, 0x07, 0x00, 0xcd, 0x10, 0x5e, 0xeb, 0xf0, 0x32,
1618 0xe4, 0xcd, 0x16, 0xcd, 0x19, 0xeb, 0xfe, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
1619 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c,
1620 0x65, 0x20, 0x64, 0x69, 0x73, 0x6b, 0x2e, 0x20, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73,
1621 0x65, 0x20, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f,
1622 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x70, 0x70, 0x79, 0x20, 0x61,
1623 0x6e, 0x64, 0x0d, 0x0a, 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x79, 0x20,
1624 0x6b, 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61,
1625 0x69, 0x6e, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x0d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
1626 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1627 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1628 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1629 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1630 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1631 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1632 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1633 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1634 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1635 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1636 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1637 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1638 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1639 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1640 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1641 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1642 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1643 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1644 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1645 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1646 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1647 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1648 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa,
1649 ];
1650 let bpb = Bpb::create_from_bytes(&BPB_EXAMPLE).unwrap();
1651 assert_eq!(bpb.footer(), Bpb::FOOTER_VALUE);
1652 assert_eq!(bpb.oem_name(), b"mkfs.fat");
1653 assert_eq!(bpb.bytes_per_block(), 512);
1654 assert_eq!(bpb.blocks_per_cluster(), 16);
1655 assert_eq!(bpb.reserved_block_count(), 1);
1656 assert_eq!(bpb.num_fats(), 2);
1657 assert_eq!(bpb.root_entries_count(), 512);
1658 assert_eq!(bpb.total_blocks16(), 0);
1659 assert!((bpb.media() & 0xF0) == 0xF0);
1660 assert_eq!(bpb.fat_size16(), 32);
1661 assert_eq!(bpb.blocks_per_track(), 63);
1662 assert_eq!(bpb.num_heads(), 255);
1663 assert_eq!(bpb.hidden_blocks(), 0);
1664 assert_eq!(bpb.total_blocks32(), 122_880);
1665 assert_eq!(bpb.footer(), 0xAA55);
1666 assert_eq!(bpb.drive_number(), 0x80);
1667 assert_eq!(bpb.boot_signature(), 0x29);
1668 assert_eq!(bpb.volume_id(), 0x7771_B0BB);
1669 assert_eq!(bpb.volume_label(), b"boot ");
1670 assert_eq!(bpb.fs_type(), b"FAT16 ");
1671 assert_eq!(bpb.fat_size(), 32);
1672 assert_eq!(bpb.total_blocks(), 122_880);
1673 assert_eq!(bpb.fat_type, FatType::Fat16);
1674 }
1675}
1676
1677