1#[cfg(all(not(feature = "std"), feature = "alloc"))]
2use alloc::string::String;
3use core::borrow::BorrowMut;
4use core::cell::{Cell, RefCell};
5use core::convert::TryFrom;
6use core::fmt::Debug;
7use core::marker::PhantomData;
8
9use crate::boot_sector::{format_boot_sector, BiosParameterBlock, BootSector};
10use crate::dir::{Dir, DirRawStream};
11use crate::dir_entry::{DirFileEntryData, FileAttributes, SFN_PADDING, SFN_SIZE};
12use crate::error::Error;
13use crate::file::File;
14use crate::io::{self, IoBase, Read, ReadLeExt, Seek, SeekFrom, Write, WriteLeExt};
15use crate::table::{
16 alloc_cluster, count_free_clusters, format_fat, read_fat_flags, ClusterIterator, RESERVED_FAT_ENTRIES,
17};
18use crate::time::{DefaultTimeProvider, TimeProvider};
19
20#[derive(Copy, Clone, Eq, PartialEq, Debug)]
28pub enum FatType {
29 Fat12,
31 Fat16,
33 Fat32,
35}
36
37impl FatType {
38 const FAT16_MIN_CLUSTERS: u32 = 4085;
39 const FAT32_MIN_CLUSTERS: u32 = 65525;
40 const FAT32_MAX_CLUSTERS: u32 = 0x0FFF_FFF4;
41
42 pub(crate) fn from_clusters(total_clusters: u32) -> Self {
43 if total_clusters < Self::FAT16_MIN_CLUSTERS {
44 FatType::Fat12
45 } else if total_clusters < Self::FAT32_MIN_CLUSTERS {
46 FatType::Fat16
47 } else {
48 FatType::Fat32
49 }
50 }
51
52 pub(crate) fn bits_per_fat_entry(self) -> u32 {
53 match self {
54 FatType::Fat12 => 12,
55 FatType::Fat16 => 16,
56 FatType::Fat32 => 32,
57 }
58 }
59
60 pub(crate) fn min_clusters(self) -> u32 {
61 match self {
62 FatType::Fat12 => 0,
63 FatType::Fat16 => Self::FAT16_MIN_CLUSTERS,
64 FatType::Fat32 => Self::FAT32_MIN_CLUSTERS,
65 }
66 }
67
68 pub(crate) fn max_clusters(self) -> u32 {
69 match self {
70 FatType::Fat12 => Self::FAT16_MIN_CLUSTERS - 1,
71 FatType::Fat16 => Self::FAT32_MIN_CLUSTERS - 1,
72 FatType::Fat32 => Self::FAT32_MAX_CLUSTERS,
73 }
74 }
75}
76
77#[derive(Copy, Clone, Eq, PartialEq, Debug)]
79pub struct FsStatusFlags {
80 pub(crate) dirty: bool,
81 pub(crate) io_error: bool,
82}
83
84impl FsStatusFlags {
85 #[must_use]
89 pub fn dirty(&self) -> bool {
90 self.dirty
91 }
92
93 #[must_use]
95 pub fn io_error(&self) -> bool {
96 self.io_error
97 }
98
99 fn encode(self) -> u8 {
100 let mut res = 0_u8;
101 if self.dirty {
102 res |= 1;
103 }
104 if self.io_error {
105 res |= 2;
106 }
107 res
108 }
109
110 pub(crate) fn decode(flags: u8) -> Self {
111 Self {
112 dirty: flags & 1 != 0,
113 io_error: flags & 2 != 0,
114 }
115 }
116}
117
118pub trait ReadSeek: Read + Seek {}
120impl<T: Read + Seek> ReadSeek for T {}
121
122pub trait ReadWriteSeek: Read + Write + Seek {}
124impl<T: Read + Write + Seek> ReadWriteSeek for T {}
125
126#[derive(Clone, Default, Debug)]
127struct FsInfoSector {
128 free_cluster_count: Option<u32>,
129 next_free_cluster: Option<u32>,
130 dirty: bool,
131}
132
133impl FsInfoSector {
134 const LEAD_SIG: u32 = 0x4161_5252;
135 const STRUC_SIG: u32 = 0x6141_7272;
136 const TRAIL_SIG: u32 = 0xAA55_0000;
137
138 fn deserialize<R: Read>(rdr: &mut R) -> Result<Self, Error<R::Error>> {
139 let lead_sig = rdr.read_u32_le()?;
140 if lead_sig != Self::LEAD_SIG {
141 error!("invalid lead_sig in FsInfo sector: {}", lead_sig);
142 return Err(Error::CorruptedFileSystem);
143 }
144 let mut reserved = [0_u8; 480];
145 rdr.read_exact(&mut reserved)?;
146 let struc_sig = rdr.read_u32_le()?;
147 if struc_sig != Self::STRUC_SIG {
148 error!("invalid struc_sig in FsInfo sector: {}", struc_sig);
149 return Err(Error::CorruptedFileSystem);
150 }
151 let free_cluster_count = match rdr.read_u32_le()? {
152 0xFFFF_FFFF => None,
153 n => Some(n),
155 };
156 let next_free_cluster = match rdr.read_u32_le()? {
157 0xFFFF_FFFF => None,
158 0 | 1 => {
159 warn!("invalid next_free_cluster in FsInfo sector (values 0 and 1 are reserved)");
160 None
161 }
162 n => Some(n),
164 };
165 let mut reserved2 = [0_u8; 12];
166 rdr.read_exact(&mut reserved2)?;
167 let trail_sig = rdr.read_u32_le()?;
168 if trail_sig != Self::TRAIL_SIG {
169 error!("invalid trail_sig in FsInfo sector: {}", trail_sig);
170 return Err(Error::CorruptedFileSystem);
171 }
172 Ok(Self {
173 free_cluster_count,
174 next_free_cluster,
175 dirty: false,
176 })
177 }
178
179 fn serialize<W: Write>(&self, wrt: &mut W) -> Result<(), Error<W::Error>> {
180 wrt.write_u32_le(Self::LEAD_SIG)?;
181 let reserved = [0_u8; 480];
182 wrt.write_all(&reserved)?;
183 wrt.write_u32_le(Self::STRUC_SIG)?;
184 wrt.write_u32_le(self.free_cluster_count.unwrap_or(0xFFFF_FFFF))?;
185 wrt.write_u32_le(self.next_free_cluster.unwrap_or(0xFFFF_FFFF))?;
186 let reserved2 = [0_u8; 12];
187 wrt.write_all(&reserved2)?;
188 wrt.write_u32_le(Self::TRAIL_SIG)?;
189 Ok(())
190 }
191
192 fn validate_and_fix(&mut self, total_clusters: u32) {
193 let max_valid_cluster_number = total_clusters + RESERVED_FAT_ENTRIES;
194 if let Some(n) = self.free_cluster_count {
195 if n > total_clusters {
196 warn!(
197 "invalid free_cluster_count ({}) in fs_info exceeds total cluster count ({})",
198 n, total_clusters
199 );
200 self.free_cluster_count = None;
201 }
202 }
203 if let Some(n) = self.next_free_cluster {
204 if n > max_valid_cluster_number {
205 warn!(
206 "invalid free_cluster_count ({}) in fs_info exceeds maximum cluster number ({})",
207 n, max_valid_cluster_number
208 );
209 self.next_free_cluster = None;
210 }
211 }
212 }
213
214 fn map_free_clusters(&mut self, map_fn: impl Fn(u32) -> u32) {
215 if let Some(n) = self.free_cluster_count {
216 self.free_cluster_count = Some(map_fn(n));
217 self.dirty = true;
218 }
219 }
220
221 fn set_next_free_cluster(&mut self, cluster: u32) {
222 self.next_free_cluster = Some(cluster);
223 self.dirty = true;
224 }
225
226 fn set_free_cluster_count(&mut self, free_cluster_count: u32) {
227 self.free_cluster_count = Some(free_cluster_count);
228 self.dirty = true;
229 }
230}
231
232#[derive(Copy, Clone, Debug, Default)]
236pub struct FsOptions<TP, OCC> {
237 pub(crate) update_accessed_date: bool,
238 pub(crate) oem_cp_converter: OCC,
239 pub(crate) time_provider: TP,
240 pub(crate) strict: bool,
241}
242
243impl FsOptions<DefaultTimeProvider, LossyOemCpConverter> {
244 #[must_use]
246 pub fn new() -> Self {
247 Self {
248 update_accessed_date: false,
249 oem_cp_converter: LossyOemCpConverter::new(),
250 time_provider: DefaultTimeProvider::new(),
251 strict: true,
252 }
253 }
254}
255
256impl<TP: TimeProvider, OCC: OemCpConverter> FsOptions<TP, OCC> {
257 #[must_use]
259 pub fn update_accessed_date(mut self, enabled: bool) -> Self {
260 self.update_accessed_date = enabled;
261 self
262 }
263
264 pub fn oem_cp_converter<OCC2: OemCpConverter>(self, oem_cp_converter: OCC2) -> FsOptions<TP, OCC2> {
266 FsOptions::<TP, OCC2> {
267 update_accessed_date: self.update_accessed_date,
268 oem_cp_converter,
269 time_provider: self.time_provider,
270 strict: self.strict,
271 }
272 }
273
274 pub fn time_provider<TP2: TimeProvider>(self, time_provider: TP2) -> FsOptions<TP2, OCC> {
276 FsOptions::<TP2, OCC> {
277 update_accessed_date: self.update_accessed_date,
278 oem_cp_converter: self.oem_cp_converter,
279 time_provider,
280 strict: self.strict,
281 }
282 }
283
284 pub fn strict(self, strict: bool) -> Self {
286 Self {
287 update_accessed_date: self.update_accessed_date,
288 oem_cp_converter: self.oem_cp_converter,
289 time_provider: self.time_provider,
290 strict,
291 }
292 }
293}
294
295#[derive(Copy, Clone, Eq, PartialEq, Debug)]
297pub struct FileSystemStats {
298 cluster_size: u32,
299 total_clusters: u32,
300 free_clusters: u32,
301}
302
303impl FileSystemStats {
304 #[must_use]
306 pub fn cluster_size(&self) -> u32 {
307 self.cluster_size
308 }
309
310 #[must_use]
312 pub fn total_clusters(&self) -> u32 {
313 self.total_clusters
314 }
315
316 #[must_use]
318 pub fn free_clusters(&self) -> u32 {
319 self.free_clusters
320 }
321}
322
323pub struct FileSystem<IO: ReadWriteSeek, TP = DefaultTimeProvider, OCC = LossyOemCpConverter> {
327 pub(crate) disk: RefCell<IO>,
328 pub(crate) options: FsOptions<TP, OCC>,
329 fat_type: FatType,
330 bpb: BiosParameterBlock,
331 first_data_sector: u32,
332 root_dir_sectors: u32,
333 total_clusters: u32,
334 fs_info: RefCell<FsInfoSector>,
335 current_status_flags: Cell<FsStatusFlags>,
336}
337
338pub trait IntoStorage<T: Read + Write + Seek> {
339 fn into_storage(self) -> T;
340}
341
342impl<T: Read + Write + Seek> IntoStorage<T> for T {
343 fn into_storage(self) -> Self {
344 self
345 }
346}
347
348#[cfg(feature = "std")]
349impl<T: std::io::Read + std::io::Write + std::io::Seek> IntoStorage<io::StdIoWrapper<T>> for T {
350 fn into_storage(self) -> io::StdIoWrapper<Self> {
351 io::StdIoWrapper::new(self)
352 }
353}
354
355impl<IO: Read + Write + Seek, TP, OCC> FileSystem<IO, TP, OCC> {
356 pub fn new<T: IntoStorage<IO>>(storage: T, options: FsOptions<TP, OCC>) -> Result<Self, Error<IO::Error>> {
377 let mut disk = storage.into_storage();
379 trace!("FileSystem::new");
380 debug_assert!(disk.seek(SeekFrom::Current(0))? == 0);
381
382 let bpb = {
384 let boot = BootSector::deserialize(&mut disk)?;
385 boot.validate(options.strict)?;
386 boot.bpb
387 };
388
389 let root_dir_sectors = bpb.root_dir_sectors();
390 let first_data_sector = bpb.first_data_sector();
391 let total_clusters = bpb.total_clusters();
392 let fat_type = FatType::from_clusters(total_clusters);
393
394 let mut fs_info = if fat_type == FatType::Fat32 {
396 disk.seek(SeekFrom::Start(bpb.bytes_from_sectors(bpb.fs_info_sector())))?;
397 FsInfoSector::deserialize(&mut disk)?
398 } else {
399 FsInfoSector::default()
400 };
401
402 if bpb.status_flags().dirty {
404 fs_info.free_cluster_count = None;
405 }
406
407 fs_info.validate_and_fix(total_clusters);
409
410 let status_flags = bpb.status_flags();
412 trace!("FileSystem::new end");
413 Ok(Self {
414 disk: RefCell::new(disk),
415 options,
416 fat_type,
417 bpb,
418 first_data_sector,
419 root_dir_sectors,
420 total_clusters,
421 fs_info: RefCell::new(fs_info),
422 current_status_flags: Cell::new(status_flags),
423 })
424 }
425
426 pub fn fat_type(&self) -> FatType {
428 self.fat_type
429 }
430
431 pub fn volume_id(&self) -> u32 {
433 self.bpb.volume_id
434 }
435
436 pub fn bytes_per_sector(&self) -> u16 {
438 self.bpb.bytes_per_sector
439 }
440
441 pub fn volume_label_as_bytes(&self) -> &[u8] {
447 let full_label_slice = &self.bpb.volume_label;
448 let len = full_label_slice
449 .iter()
450 .rposition(|b| *b != SFN_PADDING)
451 .map_or(0, |p| p + 1);
452 &full_label_slice[..len]
453 }
454
455 fn offset_from_sector(&self, sector: u32) -> u64 {
456 self.bpb.bytes_from_sectors(sector)
457 }
458
459 fn sector_from_cluster(&self, cluster: u32) -> u32 {
460 self.first_data_sector + self.bpb.sectors_from_clusters(cluster - RESERVED_FAT_ENTRIES)
461 }
462
463 pub fn cluster_size(&self) -> u32 {
464 self.bpb.cluster_size()
465 }
466
467 pub(crate) fn offset_from_cluster(&self, cluster: u32) -> u64 {
468 self.offset_from_sector(self.sector_from_cluster(cluster))
469 }
470
471 pub(crate) fn bytes_from_clusters(&self, clusters: u32) -> u64 {
472 self.bpb.bytes_from_sectors(self.bpb.sectors_from_clusters(clusters))
473 }
474
475 pub(crate) fn clusters_from_bytes(&self, bytes: u64) -> u32 {
476 self.bpb.clusters_from_bytes(bytes)
477 }
478
479 fn fat_slice(&self) -> impl ReadWriteSeek<Error = Error<IO::Error>> + '_ {
480 let io = FsIoAdapter { fs: self };
481 fat_slice(io, &self.bpb)
482 }
483
484 pub(crate) fn cluster_iter(
485 &self,
486 cluster: u32,
487 ) -> ClusterIterator<impl ReadWriteSeek<Error = Error<IO::Error>> + '_, IO::Error> {
488 let disk_slice = self.fat_slice();
489 ClusterIterator::new(disk_slice, self.fat_type, cluster)
490 }
491
492 pub(crate) fn truncate_cluster_chain(&self, cluster: u32) -> Result<(), Error<IO::Error>> {
493 let mut iter = self.cluster_iter(cluster);
494 let num_free = iter.truncate()?;
495 let mut fs_info = self.fs_info.borrow_mut();
496 fs_info.map_free_clusters(|n| n + num_free);
497 Ok(())
498 }
499
500 pub(crate) fn free_cluster_chain(&self, cluster: u32) -> Result<(), Error<IO::Error>> {
501 let mut iter = self.cluster_iter(cluster);
502 let num_free = iter.free()?;
503 let mut fs_info = self.fs_info.borrow_mut();
504 fs_info.map_free_clusters(|n| n + num_free);
505 Ok(())
506 }
507
508 pub(crate) fn alloc_cluster(&self, prev_cluster: Option<u32>, zero: bool) -> Result<u32, Error<IO::Error>> {
509 trace!("alloc_cluster");
510 let hint = self.fs_info.borrow().next_free_cluster;
511 let cluster = {
512 let mut fat = self.fat_slice();
513 alloc_cluster(&mut fat, self.fat_type, prev_cluster, hint, self.total_clusters)?
514 };
515 if zero {
516 let mut disk = self.disk.borrow_mut();
517 disk.seek(SeekFrom::Start(self.offset_from_cluster(cluster)))?;
518 write_zeros(&mut *disk, u64::from(self.cluster_size()))?;
519 }
520 let mut fs_info = self.fs_info.borrow_mut();
521 fs_info.set_next_free_cluster(cluster + 1);
522 fs_info.map_free_clusters(|n| n - 1);
523 Ok(cluster)
524 }
525
526 pub fn read_status_flags(&self) -> Result<FsStatusFlags, Error<IO::Error>> {
532 let bpb_status = self.bpb.status_flags();
533 let fat_status = read_fat_flags(&mut self.fat_slice(), self.fat_type)?;
534 Ok(FsStatusFlags {
535 dirty: bpb_status.dirty || fat_status.dirty,
536 io_error: bpb_status.io_error || fat_status.io_error,
537 })
538 }
539
540 pub fn stats(&self) -> Result<FileSystemStats, Error<IO::Error>> {
549 let free_clusters_option = self.fs_info.borrow().free_cluster_count;
550 let free_clusters = if let Some(n) = free_clusters_option {
551 n
552 } else {
553 self.recalc_free_clusters()?
554 };
555 Ok(FileSystemStats {
556 cluster_size: self.cluster_size(),
557 total_clusters: self.total_clusters,
558 free_clusters,
559 })
560 }
561
562 fn recalc_free_clusters(&self) -> Result<u32, Error<IO::Error>> {
564 let mut fat = self.fat_slice();
565 let free_cluster_count = count_free_clusters(&mut fat, self.fat_type, self.total_clusters)?;
566 self.fs_info.borrow_mut().set_free_cluster_count(free_cluster_count);
567 Ok(free_cluster_count)
568 }
569
570 pub fn unmount(self) -> Result<(), Error<IO::Error>> {
578 self.unmount_internal()
579 }
580
581 fn unmount_internal(&self) -> Result<(), Error<IO::Error>> {
582 self.flush_fs_info()?;
583 self.set_dirty_flag(false)?;
584 Ok(())
585 }
586
587 fn flush_fs_info(&self) -> Result<(), Error<IO::Error>> {
588 let mut fs_info = self.fs_info.borrow_mut();
589 if self.fat_type == FatType::Fat32 && fs_info.dirty {
590 let mut disk = self.disk.borrow_mut();
591 let fs_info_sector_offset = self.offset_from_sector(u32::from(self.bpb.fs_info_sector));
592 disk.seek(SeekFrom::Start(fs_info_sector_offset))?;
593 fs_info.serialize(&mut *disk)?;
594 fs_info.dirty = false;
595 }
596 Ok(())
597 }
598
599 pub(crate) fn set_dirty_flag(&self, dirty: bool) -> Result<(), IO::Error> {
600 let mut flags = self.bpb.status_flags();
602 flags.dirty |= dirty;
603 let current_flags = self.current_status_flags.get();
605 if flags == current_flags {
606 return Ok(());
608 }
609 let encoded = flags.encode();
610 let offset = if self.fat_type() == FatType::Fat32 {
613 0x041
614 } else {
615 0x025
616 };
617 let mut disk = self.disk.borrow_mut();
618 disk.seek(io::SeekFrom::Start(offset))?;
619 disk.write_u8(encoded)?;
620 self.current_status_flags.set(flags);
621 Ok(())
622 }
623
624 pub fn root_dir(&self) -> Dir<'_, IO, TP, OCC> {
626 trace!("root_dir");
627 let root_rdr = {
628 match self.fat_type {
629 FatType::Fat12 | FatType::Fat16 => DirRawStream::Root(DiskSlice::from_sectors(
630 self.first_data_sector - self.root_dir_sectors,
631 self.root_dir_sectors,
632 1,
633 &self.bpb,
634 FsIoAdapter { fs: self },
635 )),
636 FatType::Fat32 => DirRawStream::File(File::new(Some(self.bpb.root_dir_first_cluster), None, self)),
637 }
638 };
639 Dir::new(root_rdr, self)
640 }
641}
642
643impl<IO: ReadWriteSeek, TP, OCC: OemCpConverter> FileSystem<IO, TP, OCC> {
644 #[cfg(feature = "alloc")]
650 pub fn volume_label(&self) -> String {
651 let volume_label_iter = self.volume_label_as_bytes().iter().copied();
653 let char_iter = volume_label_iter.map(|c| self.options.oem_cp_converter.decode(c));
654 char_iter.collect()
656 }
657}
658
659impl<IO: ReadWriteSeek, TP: TimeProvider, OCC: OemCpConverter> FileSystem<IO, TP, OCC> {
660 #[cfg(feature = "alloc")]
668 pub fn read_volume_label_from_root_dir(&self) -> Result<Option<String>, Error<IO::Error>> {
669 let volume_label_opt = self.read_volume_label_from_root_dir_as_bytes()?;
672 volume_label_opt.map_or(Ok(None), |volume_label| {
673 let len = volume_label
675 .iter()
676 .rposition(|b| *b != SFN_PADDING)
677 .map_or(0, |p| p + 1);
678 let label_slice = &volume_label[..len];
679 let volume_label_iter = label_slice.iter().copied();
681 let char_iter = volume_label_iter.map(|c| self.options.oem_cp_converter.decode(c));
682 Ok(Some(char_iter.collect::<String>()))
684 })
685 }
686
687 pub fn read_volume_label_from_root_dir_as_bytes(&self) -> Result<Option<[u8; SFN_SIZE]>, Error<IO::Error>> {
696 let entry_opt = self.root_dir().find_volume_entry()?;
697 Ok(entry_opt.map(|e| *e.raw_short_name()))
698 }
699}
700
701impl<IO: ReadWriteSeek, TP, OCC> Drop for FileSystem<IO, TP, OCC> {
703 fn drop(&mut self) {
704 if let Err(err) = self.unmount_internal() {
705 error!("unmount failed {:?}", err);
706 }
707 }
708}
709
710pub(crate) struct FsIoAdapter<'a, IO: ReadWriteSeek, TP, OCC> {
711 fs: &'a FileSystem<IO, TP, OCC>,
712}
713
714impl<IO: ReadWriteSeek, TP, OCC> IoBase for FsIoAdapter<'_, IO, TP, OCC> {
715 type Error = IO::Error;
716}
717
718impl<IO: ReadWriteSeek, TP, OCC> Read for FsIoAdapter<'_, IO, TP, OCC> {
719 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
720 self.fs.disk.borrow_mut().read(buf)
721 }
722}
723
724impl<IO: ReadWriteSeek, TP, OCC> Write for FsIoAdapter<'_, IO, TP, OCC> {
725 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
726 let size = self.fs.disk.borrow_mut().write(buf)?;
727 if size > 0 {
728 self.fs.set_dirty_flag(true)?;
729 }
730 Ok(size)
731 }
732
733 fn flush(&mut self) -> Result<(), Self::Error> {
734 self.fs.disk.borrow_mut().flush()
735 }
736}
737
738impl<IO: ReadWriteSeek, TP, OCC> Seek for FsIoAdapter<'_, IO, TP, OCC> {
739 fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error> {
740 self.fs.disk.borrow_mut().seek(pos)
741 }
742}
743
744impl<IO: ReadWriteSeek, TP, OCC> Clone for FsIoAdapter<'_, IO, TP, OCC> {
746 fn clone(&self) -> Self {
747 FsIoAdapter { fs: self.fs }
748 }
749}
750
751fn fat_slice<S: ReadWriteSeek, B: BorrowMut<S>>(
752 io: B,
753 bpb: &BiosParameterBlock,
754) -> impl ReadWriteSeek<Error = Error<S::Error>> {
755 let sectors_per_fat = bpb.sectors_per_fat();
756 let mirroring_enabled = bpb.mirroring_enabled();
757 let (fat_first_sector, mirrors) = if mirroring_enabled {
758 (bpb.reserved_sectors(), bpb.fats)
759 } else {
760 let active_fat = u32::from(bpb.active_fat());
761 let fat_first_sector = (bpb.reserved_sectors()) + active_fat * sectors_per_fat;
762 (fat_first_sector, 1)
763 };
764 DiskSlice::from_sectors(fat_first_sector, sectors_per_fat, mirrors, bpb, io)
765}
766
767pub(crate) struct DiskSlice<B, S = B> {
768 begin: u64,
769 size: u64,
770 offset: u64,
771 mirrors: u8,
772 inner: B,
773 phantom: PhantomData<S>,
774}
775
776impl<B: BorrowMut<S>, S: ReadWriteSeek> DiskSlice<B, S> {
777 pub(crate) fn new(begin: u64, size: u64, mirrors: u8, inner: B) -> Self {
778 Self {
779 begin,
780 size,
781 mirrors,
782 inner,
783 offset: 0,
784 phantom: PhantomData,
785 }
786 }
787
788 fn from_sectors(first_sector: u32, sector_count: u32, mirrors: u8, bpb: &BiosParameterBlock, inner: B) -> Self {
789 Self::new(
790 bpb.bytes_from_sectors(first_sector),
791 bpb.bytes_from_sectors(sector_count),
792 mirrors,
793 inner,
794 )
795 }
796
797 pub(crate) fn abs_pos(&self) -> u64 {
798 self.begin + self.offset
799 }
800}
801
802impl<B: Clone, S> Clone for DiskSlice<B, S> {
804 fn clone(&self) -> Self {
805 Self {
806 begin: self.begin,
807 size: self.size,
808 offset: self.offset,
809 mirrors: self.mirrors,
810 inner: self.inner.clone(),
811 phantom: PhantomData,
813 }
814 }
815}
816
817impl<B, S: IoBase> IoBase for DiskSlice<B, S> {
818 type Error = Error<S::Error>;
819}
820
821impl<B: BorrowMut<S>, S: Read + Seek> Read for DiskSlice<B, S> {
822 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
823 let offset = self.begin + self.offset;
824 let read_size = (buf.len() as u64).min(self.size - self.offset) as usize;
825 self.inner.borrow_mut().seek(SeekFrom::Start(offset))?;
826 let size = self.inner.borrow_mut().read(&mut buf[..read_size])?;
827 self.offset += size as u64;
828 Ok(size)
829 }
830}
831
832impl<B: BorrowMut<S>, S: Write + Seek> Write for DiskSlice<B, S> {
833 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
834 let offset = self.begin + self.offset;
835 let write_size = (buf.len() as u64).min(self.size - self.offset) as usize;
836 if write_size == 0 {
837 return Ok(0);
838 }
839 let storage = self.inner.borrow_mut();
841 for i in 0..self.mirrors {
842 storage.seek(SeekFrom::Start(offset + u64::from(i) * self.size))?;
843 storage.write_all(&buf[..write_size])?;
844 }
845 self.offset += write_size as u64;
846 Ok(write_size)
847 }
848
849 fn flush(&mut self) -> Result<(), Self::Error> {
850 Ok(self.inner.borrow_mut().flush()?)
851 }
852}
853
854impl<B, S: IoBase> Seek for DiskSlice<B, S> {
855 fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error> {
856 let new_offset_opt: Option<u64> = match pos {
857 SeekFrom::Current(x) => i64::try_from(self.offset)
858 .ok()
859 .and_then(|n| n.checked_add(x))
860 .and_then(|n| u64::try_from(n).ok()),
861 SeekFrom::Start(x) => Some(x),
862 SeekFrom::End(o) => i64::try_from(self.size)
863 .ok()
864 .and_then(|size| size.checked_add(o))
865 .and_then(|n| u64::try_from(n).ok()),
866 };
867 if let Some(new_offset) = new_offset_opt {
868 if new_offset > self.size {
869 error!("Seek beyond the end of the file");
870 Err(Error::InvalidInput)
871 } else {
872 self.offset = new_offset;
873 Ok(self.offset)
874 }
875 } else {
876 error!("Invalid seek offset");
877 Err(Error::InvalidInput)
878 }
879 }
880}
881
882pub trait OemCpConverter: Debug {
887 fn decode(&self, oem_char: u8) -> char;
888 fn encode(&self, uni_char: char) -> Option<u8>;
889}
890
891#[derive(Debug, Clone, Copy, Default)]
893pub struct LossyOemCpConverter {
894 _dummy: (),
895}
896
897impl LossyOemCpConverter {
898 #[must_use]
899 pub fn new() -> Self {
900 Self { _dummy: () }
901 }
902}
903
904impl OemCpConverter for LossyOemCpConverter {
905 fn decode(&self, oem_char: u8) -> char {
906 if oem_char <= 0x7F {
907 char::from(oem_char)
908 } else {
909 '\u{FFFD}'
910 }
911 }
912 fn encode(&self, uni_char: char) -> Option<u8> {
913 if uni_char <= '\x7F' {
914 Some(uni_char as u8) } else {
916 None
917 }
918 }
919}
920
921pub(crate) fn write_zeros<IO: ReadWriteSeek>(disk: &mut IO, mut len: u64) -> Result<(), IO::Error> {
922 const ZEROS: [u8; 512] = [0_u8; 512];
923 while len > 0 {
924 let write_size = len.min(ZEROS.len() as u64) as usize;
925 disk.write_all(&ZEROS[..write_size])?;
926 len -= write_size as u64;
927 }
928 Ok(())
929}
930
931fn write_zeros_until_end_of_sector<IO: ReadWriteSeek>(disk: &mut IO, bytes_per_sector: u16) -> Result<(), IO::Error> {
932 let pos = disk.seek(SeekFrom::Current(0))?;
933 let total_bytes_to_write = u64::from(bytes_per_sector) - (pos % u64::from(bytes_per_sector));
934 if total_bytes_to_write != u64::from(bytes_per_sector) {
935 write_zeros(disk, total_bytes_to_write)?;
936 }
937 Ok(())
938}
939
940#[derive(Debug, Clone)]
945pub struct FormatVolumeOptions {
946 pub(crate) bytes_per_sector: u16,
947 pub(crate) total_sectors: Option<u32>,
948 pub(crate) bytes_per_cluster: Option<u32>,
949 pub(crate) fat_type: Option<FatType>,
950 pub(crate) max_root_dir_entries: u16,
951 pub(crate) fats: u8,
952 pub(crate) media: u8,
953 pub(crate) sectors_per_track: u16,
954 pub(crate) heads: u16,
955 pub(crate) drive_num: Option<u8>,
956 pub(crate) volume_id: u32,
957 pub(crate) volume_label: Option<[u8; SFN_SIZE]>,
958}
959
960impl Default for FormatVolumeOptions {
961 fn default() -> Self {
962 Self {
963 bytes_per_sector: 512,
964 total_sectors: None,
965 bytes_per_cluster: None,
966 fat_type: None,
967 max_root_dir_entries: 512,
968 fats: 2,
969 media: 0xF8,
970 sectors_per_track: 0x20,
971 heads: 0x40,
972 drive_num: None,
973 volume_id: 0x1234_5678,
974 volume_label: None,
975 }
976 }
977}
978
979impl FormatVolumeOptions {
980 #[must_use]
985 pub fn new() -> Self {
986 Self::default()
987 }
988
989 #[must_use]
999 pub fn bytes_per_cluster(mut self, bytes_per_cluster: u32) -> Self {
1000 assert!(
1001 bytes_per_cluster.is_power_of_two() && bytes_per_cluster >= 512,
1002 "Invalid bytes_per_cluster"
1003 );
1004 self.bytes_per_cluster = Some(bytes_per_cluster);
1005 self
1006 }
1007
1008 #[must_use]
1015 pub fn fat_type(mut self, fat_type: FatType) -> Self {
1016 self.fat_type = Some(fat_type);
1017 self
1018 }
1019
1020 #[must_use]
1029 pub fn bytes_per_sector(mut self, bytes_per_sector: u16) -> Self {
1030 assert!(
1031 bytes_per_sector.is_power_of_two() && bytes_per_sector >= 512,
1032 "Invalid bytes_per_sector"
1033 );
1034 self.bytes_per_sector = bytes_per_sector;
1035 self
1036 }
1037
1038 #[must_use]
1042 pub fn total_sectors(mut self, total_sectors: u32) -> Self {
1043 self.total_sectors = Some(total_sectors);
1044 self
1045 }
1046
1047 #[must_use]
1054 pub fn max_root_dir_entries(mut self, max_root_dir_entries: u16) -> Self {
1055 self.max_root_dir_entries = max_root_dir_entries;
1056 self
1057 }
1058
1059 #[must_use]
1068 pub fn fats(mut self, fats: u8) -> Self {
1069 assert!((1..=2).contains(&fats), "Invalid number of FATs");
1070 self.fats = fats;
1071 self
1072 }
1073
1074 #[must_use]
1078 pub fn media(mut self, media: u8) -> Self {
1079 self.media = media;
1080 self
1081 }
1082
1083 #[must_use]
1087 pub fn sectors_per_track(mut self, sectors_per_track: u16) -> Self {
1088 self.sectors_per_track = sectors_per_track;
1089 self
1090 }
1091
1092 #[must_use]
1096 pub fn heads(mut self, heads: u16) -> Self {
1097 self.heads = heads;
1098 self
1099 }
1100
1101 #[must_use]
1105 pub fn drive_num(mut self, drive_num: u8) -> Self {
1106 self.drive_num = Some(drive_num);
1107 self
1108 }
1109
1110 #[must_use]
1114 pub fn volume_id(mut self, volume_id: u32) -> Self {
1115 self.volume_id = volume_id;
1116 self
1117 }
1118
1119 #[must_use]
1123 pub fn volume_label(mut self, volume_label: [u8; SFN_SIZE]) -> Self {
1124 self.volume_label = Some(volume_label);
1125 self
1126 }
1127}
1128
1129#[allow(clippy::needless_pass_by_value)]
1152pub fn format_volume<S: ReadWriteSeek>(storage: &mut S, options: FormatVolumeOptions) -> Result<(), Error<S::Error>> {
1153 trace!("format_volume");
1154 debug_assert!(storage.seek(SeekFrom::Current(0))? == 0);
1155
1156 let total_sectors = if let Some(total_sectors) = options.total_sectors {
1157 total_sectors
1158 } else {
1159 let total_bytes: u64 = storage.seek(SeekFrom::End(0))?;
1160 let total_sectors_64 = total_bytes / u64::from(options.bytes_per_sector);
1161 storage.seek(SeekFrom::Start(0))?;
1162 if total_sectors_64 > u64::from(u32::MAX) {
1163 error!("Volume has too many sectors: {}", total_sectors_64);
1164 return Err(Error::InvalidInput);
1165 }
1166 total_sectors_64 as u32 };
1168
1169 let (boot, fat_type) = format_boot_sector(&options, total_sectors)?;
1171 if boot.validate::<S::Error>(true).is_err() {
1172 return Err(Error::InvalidInput);
1173 }
1174 boot.serialize(storage)?;
1175 let bytes_per_sector = boot.bpb.bytes_per_sector;
1177 write_zeros_until_end_of_sector(storage, bytes_per_sector)?;
1178
1179 let bpb = &boot.bpb;
1180 if bpb.is_fat32() {
1181 let fs_info_sector = FsInfoSector {
1183 free_cluster_count: None,
1184 next_free_cluster: None,
1185 dirty: false,
1186 };
1187 storage.seek(SeekFrom::Start(bpb.bytes_from_sectors(bpb.fs_info_sector())))?;
1188 fs_info_sector.serialize(storage)?;
1189 write_zeros_until_end_of_sector(storage, bytes_per_sector)?;
1190
1191 storage.seek(SeekFrom::Start(bpb.bytes_from_sectors(bpb.backup_boot_sector())))?;
1193 boot.serialize(storage)?;
1194 write_zeros_until_end_of_sector(storage, bytes_per_sector)?;
1195 }
1196
1197 let reserved_sectors = bpb.reserved_sectors();
1199 let fat_pos = bpb.bytes_from_sectors(reserved_sectors);
1200 let sectors_per_all_fats = bpb.sectors_per_all_fats();
1201 storage.seek(SeekFrom::Start(fat_pos))?;
1202 write_zeros(storage, bpb.bytes_from_sectors(sectors_per_all_fats))?;
1203 {
1204 let mut fat_slice = fat_slice::<S, &mut S>(storage, bpb);
1205 let sectors_per_fat = bpb.sectors_per_fat();
1206 let bytes_per_fat = bpb.bytes_from_sectors(sectors_per_fat);
1207 format_fat(&mut fat_slice, fat_type, bpb.media, bytes_per_fat, bpb.total_clusters())?;
1208 }
1209
1210 let root_dir_first_sector = reserved_sectors + sectors_per_all_fats;
1212 let root_dir_sectors = bpb.root_dir_sectors();
1213 let root_dir_pos = bpb.bytes_from_sectors(root_dir_first_sector);
1214 storage.seek(SeekFrom::Start(root_dir_pos))?;
1215 write_zeros(storage, bpb.bytes_from_sectors(root_dir_sectors))?;
1216 if fat_type == FatType::Fat32 {
1217 let root_dir_first_cluster = {
1218 let mut fat_slice = fat_slice::<S, &mut S>(storage, bpb);
1219 alloc_cluster(&mut fat_slice, fat_type, None, None, 1)?
1220 };
1221 assert!(root_dir_first_cluster == bpb.root_dir_first_cluster);
1222 let first_data_sector = reserved_sectors + sectors_per_all_fats + root_dir_sectors;
1223 let data_sectors_before_root_dir = bpb.sectors_from_clusters(root_dir_first_cluster - RESERVED_FAT_ENTRIES);
1224 let fat32_root_dir_first_sector = first_data_sector + data_sectors_before_root_dir;
1225 let fat32_root_dir_pos = bpb.bytes_from_sectors(fat32_root_dir_first_sector);
1226 storage.seek(SeekFrom::Start(fat32_root_dir_pos))?;
1227 write_zeros(storage, u64::from(bpb.cluster_size()))?;
1228 }
1229
1230 if let Some(volume_label) = options.volume_label {
1232 storage.seek(SeekFrom::Start(root_dir_pos))?;
1233 let volume_entry = DirFileEntryData::new(volume_label, FileAttributes::VOLUME_ID);
1234 volume_entry.serialize(storage)?;
1235 }
1236
1237 storage.seek(SeekFrom::Start(0))?;
1238 trace!("format_volume end");
1239 Ok(())
1240}