kernel/fs/
fat.rs

1use core::{cell::Cell, fmt, mem, ops::Range};
2
3use alloc::{
4    boxed::Box,
5    collections::BTreeMap,
6    format,
7    string::{String, ToString},
8    sync::Arc,
9    vec,
10    vec::Vec,
11};
12
13use crate::{
14    devices::ide::IdeDevice,
15    io::NoDebug,
16    memory_management::memory_layout::{align_down, align_up},
17    sync::spin::mutex::Mutex,
18};
19
20use super::{
21    AccessHelper, BaseNode, DirTraverse, DirectoryNode, FileAttributes, FileNode, FileSystem,
22    FileSystemError, Node,
23};
24
25const DIRECTORY_ENTRY_SIZE: u32 = 32;
26
27fn file_attribute_from_fat(attributes: u8) -> FileAttributes {
28    let mut file_attributes = FileAttributes::EMPTY;
29    if attributes & attrs::READ_ONLY == attrs::READ_ONLY {
30        file_attributes |= FileAttributes::READ_ONLY;
31    }
32    if attributes & attrs::HIDDEN == attrs::HIDDEN {
33        file_attributes |= FileAttributes::HIDDEN;
34    }
35    if attributes & attrs::SYSTEM == attrs::SYSTEM {
36        file_attributes |= FileAttributes::SYSTEM;
37    }
38    if attributes & attrs::VOLUME_ID == attrs::VOLUME_ID {
39        file_attributes |= FileAttributes::VOLUME_LABEL;
40    }
41    if attributes & attrs::DIRECTORY == attrs::DIRECTORY {
42        file_attributes |= FileAttributes::DIRECTORY;
43    }
44    if attributes & attrs::ARCHIVE == attrs::ARCHIVE {
45        file_attributes |= FileAttributes::ARCHIVE;
46    }
47    file_attributes
48}
49
50fn file_attribute_to_fat(attributes: FileAttributes) -> u8 {
51    let mut fat_attributes = 0;
52    if attributes.contains(FileAttributes::READ_ONLY) {
53        fat_attributes |= attrs::READ_ONLY;
54    }
55    if attributes.contains(FileAttributes::HIDDEN) {
56        fat_attributes |= attrs::HIDDEN;
57    }
58    if attributes.contains(FileAttributes::SYSTEM) {
59        fat_attributes |= attrs::SYSTEM;
60    }
61    if attributes.contains(FileAttributes::VOLUME_LABEL) {
62        fat_attributes |= attrs::VOLUME_ID;
63    }
64    if attributes.contains(FileAttributes::DIRECTORY) {
65        fat_attributes |= attrs::DIRECTORY;
66    }
67    if attributes.contains(FileAttributes::ARCHIVE) {
68        fat_attributes |= attrs::ARCHIVE;
69    }
70    fat_attributes
71}
72
73fn long_entries_name_merge(entries: impl DoubleEndedIterator<Item = String>) -> String {
74    let mut name = String::new();
75    entries.rev().for_each(|s| name.push_str(&s));
76    name
77}
78
79fn create_dir_entries(
80    name: &str,
81    attributes: FileAttributes,
82) -> (DirectoryEntryNormal, Vec<DirectoryEntryLong>) {
83    // create short name entry
84    let mut short_name = [0; 11];
85
86    let (mut filename, extension) = match name.find('.') {
87        Some(i) => {
88            let (filename, extension) = name.split_at(i);
89            (filename, &extension[1..])
90        }
91        None => (name, ""),
92    };
93
94    let mut more_than_8 = false;
95
96    if filename.len() > 8 {
97        filename = &filename[..6];
98        more_than_8 = true;
99    } else {
100        let len = filename.len().min(8);
101        filename = &filename[..len];
102    }
103    assert!(filename.len() <= 8);
104
105    for (i, c) in short_name.iter_mut().enumerate().take(8) {
106        *c = if i < filename.len() {
107            filename.as_bytes()[i].to_ascii_uppercase()
108        } else {
109            b' '
110        };
111    }
112    if more_than_8 {
113        short_name[6] = b'~';
114        short_name[7] = b'1';
115    }
116
117    for i in 0..3 {
118        short_name[8 + i] = if i < extension.len() {
119            extension.as_bytes()[i].to_ascii_uppercase()
120        } else {
121            b' '
122        };
123    }
124
125    // TODO: add support for time and date
126    let normal_entry = DirectoryEntryNormal {
127        short_name,
128        attributes: file_attribute_to_fat(attributes),
129        _nt_reserved: 0,
130        creation_time_tenths_of_seconds: 0,
131        creation_time: 0,
132        creation_date: 0,
133        last_access_date: 0,
134        first_cluster_hi: 0,
135        last_modification_time: 0,
136        last_modification_date: 0,
137        first_cluster_lo: 0,
138        file_size: 0,
139    };
140
141    let short_name_checksum = normal_entry.name_checksum();
142
143    // create long name entries
144    let mut long_name_entries = Vec::new();
145    let mut sequence_number = 1;
146    let mut long_name = name;
147    loop {
148        if long_name.is_empty() {
149            break;
150        }
151
152        let len = long_name.len().min(13);
153        let mut name_part = long_name[..len].chars();
154
155        long_name = &long_name[len..];
156
157        let mut name1 = [0; 5];
158        let mut name2 = [0; 6];
159        let mut name3 = [0; 2];
160
161        for c in &mut name1 {
162            *c = name_part.next().unwrap_or('\0') as u16;
163        }
164        for c in &mut name2 {
165            *c = name_part.next().unwrap_or('\0') as u16;
166        }
167        for c in &mut name3 {
168            *c = name_part.next().unwrap_or('\0') as u16;
169        }
170
171        let mut entry = DirectoryEntryLong {
172            sequence_number,
173            name1,
174            attributes: attrs::LONG_NAME,
175            long_name_type: 0,
176            checksum: short_name_checksum,
177            name2,
178            _zero: 0,
179            name3,
180        };
181
182        sequence_number += 1;
183
184        // mark the last entry
185        if long_name.is_empty() {
186            entry.sequence_number |= 0x40;
187        }
188
189        long_name_entries.push(entry);
190    }
191
192    (normal_entry, long_name_entries)
193}
194
195fn increment_short_name(short_name: &mut [u8; 11]) {
196    let base_name = &mut short_name[..8];
197
198    let mut telda_pos = base_name
199        .iter()
200        .position(|c| *c == b'~')
201        .expect("Telda position be present");
202
203    assert!(telda_pos <= 6);
204    let current_num_size = 8 - telda_pos - 1;
205    let current_num = base_name[telda_pos + 1..].iter().fold(0u32, |acc, x| {
206        assert!(*x >= b'0' && *x <= b'9');
207        acc * 10 + (x - b'0') as u32
208    });
209
210    let new_num = current_num + 1;
211    if new_num > 999999 {
212        panic!("Short name exceeded limit 999999");
213    }
214
215    let new_num_str = format!("{new_num}");
216    if new_num_str.len() > current_num_size {
217        telda_pos -= 1;
218    }
219
220    assert_eq!(base_name[telda_pos + 1..].len(), new_num_str.len());
221    base_name[telda_pos + 1..].copy_from_slice(new_num_str.as_bytes());
222}
223
224#[derive(Debug)]
225pub enum FatError {
226    InvalidBootSector,
227    UnexpectedFatEntry,
228    NotEnoughSpace,
229}
230
231impl From<FatError> for FileSystemError {
232    fn from(e: FatError) -> Self {
233        FileSystemError::FatError(e)
234    }
235}
236
237pub fn load_fat_filesystem(
238    device: Arc<IdeDevice>,
239    start_lba: u32,
240    size_in_sectors: u32,
241) -> Result<FatFilesystem, FileSystemError> {
242    let size = align_up(
243        mem::size_of::<FatBootSectorRaw>(),
244        device.sector_size() as usize,
245    );
246    let mut sectors = vec![0; size];
247
248    device
249        .read_sync(start_lba as u64, &mut sectors)
250        .map_err(|e| FileSystemError::DiskReadError {
251            sector: start_lba as u64,
252            error: e,
253        })?;
254
255    // SAFETY: This is a valid, allocated memory
256    let boot_sector = unsafe { sectors.as_ptr().cast::<FatBootSectorRaw>().read() };
257    let boot_sector = FatBootSector::new(boot_sector, size_in_sectors)?;
258
259    FatFilesystem::new(start_lba, size_in_sectors, boot_sector, device)
260}
261
262#[repr(C, packed)]
263#[derive(Debug, Copy, Clone)]
264struct Fat12_16ExtendedBootSector {
265    drive_number: u8,
266    reserved: u8,
267    boot_signature: u8,
268    volume_id: u32,
269    volume_label: [u8; 11],
270    file_system_type: [u8; 8],
271    boot_code: NoDebug<[u8; 448]>,
272    boot_signature_2: u16,
273}
274
275#[repr(C, packed)]
276#[derive(Debug, Copy, Clone)]
277struct Fat32ExtendedBootSector {
278    fat_size_32: u32,
279    ext_flags: u16,
280    fs_version: u16,
281    root_cluster: u32,
282    fs_info: u16,
283    backup_boot_sector: u16,
284    reserved: [u8; 12],
285    drive_number: u8,
286    reserved_2: u8,
287    boot_signature: u8,
288    volume_id: u32,
289    volume_label: [u8; 11],
290    file_system_type: [u8; 8],
291    boot_code: NoDebug<[u8; 420]>,
292    boot_signature_2: u16,
293}
294
295#[repr(C, packed)]
296#[derive(Copy, Clone)]
297union FatExtendedBootSector {
298    fat12_16: Fat12_16ExtendedBootSector,
299    fat32: Fat32ExtendedBootSector,
300}
301
302#[repr(C, packed)]
303#[derive(Copy, Clone)]
304struct FatBootSectorRaw {
305    jmp_boot: [u8; 3],
306    oem_name: [u8; 8],
307    bytes_per_sector: u16,
308    sectors_per_cluster: u8,
309    reserved_sectors_count: u16,
310    number_of_fats: u8,
311    root_entry_count: u16,
312    total_sectors_16: u16,
313    media_type: u8,
314    fat_size_16: u16,
315    sectors_per_track: u16,
316    number_of_heads: u16,
317    hidden_sectors: u32,
318    total_sectors_32: u32,
319    extended: FatExtendedBootSector,
320}
321
322impl fmt::Debug for FatBootSectorRaw {
323    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324        let bytes_per_sector = self.bytes_per_sector;
325        let reserved_sectors_count = self.reserved_sectors_count;
326        let root_entry_count = self.root_entry_count;
327        let total_sectors_16 = self.total_sectors_16;
328        let fat_size_16 = self.fat_size_16;
329        let sectors_per_track = self.sectors_per_track;
330        let number_of_heads = self.number_of_heads;
331        let hidden_sectors = self.hidden_sectors;
332        let total_sectors_32 = self.total_sectors_32;
333
334        let is_fat32 = self.fat_size_16 == 0;
335
336        let mut s = f.debug_struct("FatBootSector");
337
338        s.field("jmp_boot", &self.jmp_boot)
339            .field("oem_name", &self.oem_name)
340            .field("bytes_per_sector", &bytes_per_sector)
341            .field("sectors_per_cluster", &self.sectors_per_cluster)
342            .field("reserved_sectors_count", &reserved_sectors_count)
343            .field("number_of_fats", &self.number_of_fats)
344            .field("root_entry_count", &root_entry_count)
345            .field("total_sectors_16", &total_sectors_16)
346            .field("media_type", &self.media_type)
347            .field("fat_size_16", &fat_size_16)
348            .field("sectors_per_track", &sectors_per_track)
349            .field("number_of_heads", &number_of_heads)
350            .field("hidden_sectors", &hidden_sectors)
351            .field("total_sectors_32", &total_sectors_32);
352
353        if is_fat32 {
354            s.field("extended_fat32", unsafe { &self.extended.fat32 })
355                .finish()
356        } else {
357            s.field("extended_fat12_16", unsafe { &self.extended.fat12_16 })
358                .finish()
359        }
360    }
361}
362
363#[derive(Debug, Clone, Copy, PartialEq, Eq)]
364pub enum FatType {
365    Fat12,
366    Fat16,
367    Fat32,
368}
369
370#[derive(Debug, Clone, Copy, PartialEq, Eq)]
371enum FatEntry {
372    Free,
373    // In use, and point to the next cluster
374    Next(u32),
375    // In use, and this is the last cluster
376    EndOfChain,
377    Bad,
378    Reserved,
379}
380
381impl FatEntry {
382    pub fn from_u32(ty: FatType, entry: u32) -> FatEntry {
383        match ty {
384            FatType::Fat12 => {
385                if entry == 0 {
386                    FatEntry::Free
387                } else if entry >= 0xFF8 {
388                    FatEntry::EndOfChain
389                } else if entry == 0xFF7 {
390                    FatEntry::Bad
391                } else if (0x002..=0xFF6).contains(&entry) {
392                    FatEntry::Next(entry)
393                } else {
394                    FatEntry::Reserved
395                }
396            }
397            FatType::Fat16 => {
398                if entry == 0 {
399                    FatEntry::Free
400                } else if entry >= 0xFFF8 {
401                    FatEntry::EndOfChain
402                } else if entry == 0xFFF7 {
403                    FatEntry::Bad
404                } else if (0x002..=0xFFF6).contains(&entry) {
405                    FatEntry::Next(entry)
406                } else {
407                    FatEntry::Reserved
408                }
409            }
410            FatType::Fat32 => {
411                if entry == 0 {
412                    FatEntry::Free
413                } else if entry >= 0x0FFF_FFF8 {
414                    FatEntry::EndOfChain
415                } else if entry == 0x0FFF_FFF7 {
416                    FatEntry::Bad
417                } else if (0x002..=0x0FFF_FFF6).contains(&entry) {
418                    FatEntry::Next(entry)
419                } else {
420                    FatEntry::Reserved
421                }
422            }
423        }
424    }
425
426    pub fn to_u32(self, ty: FatType) -> Option<u32> {
427        match self {
428            FatEntry::Free => Some(0),
429            FatEntry::EndOfChain => match ty {
430                FatType::Fat12 => Some(0xFF8),
431                FatType::Fat16 => Some(0xFFF8),
432                FatType::Fat32 => Some(0x0FFF_FFF8),
433            },
434            FatEntry::Bad => match ty {
435                FatType::Fat12 => Some(0xFF7),
436                FatType::Fat16 => Some(0xFFF7),
437                FatType::Fat32 => Some(0x0FFF_FFF7),
438            },
439            FatEntry::Next(entry) => match (ty, entry) {
440                (FatType::Fat12, 0x002..=0xFF6) => Some(entry),
441                (FatType::Fat16, 0x002..=0xFFF6) => Some(entry),
442                (FatType::Fat32, 0x002..=0x0FFF_FFF6) => Some(entry),
443                _ => None,
444            },
445            FatEntry::Reserved => None,
446        }
447    }
448}
449
450#[derive(Debug)]
451struct FatBootSector {
452    ty: FatType,
453    boot_sector: FatBootSectorRaw,
454}
455
456#[allow(dead_code)]
457impl FatBootSector {
458    fn new(boot_sector: FatBootSectorRaw, size_in_sectors: u32) -> Result<FatBootSector, FatError> {
459        if unsafe { boot_sector.extended.fat32.boot_signature_2 } != 0xAA55 {
460            return Err(FatError::InvalidBootSector);
461        }
462
463        let count_of_clusters = size_in_sectors / boot_sector.sectors_per_cluster as u32;
464
465        let fat_type = match count_of_clusters {
466            _ if boot_sector.fat_size_16 == 0 => FatType::Fat32,
467            0..=4084 => FatType::Fat12,
468            4085..=65524 => FatType::Fat16,
469            _ => FatType::Fat32,
470        };
471
472        Ok(FatBootSector {
473            ty: fat_type,
474            boot_sector,
475        })
476    }
477
478    pub fn bytes_per_sector(&self) -> u16 {
479        self.boot_sector.bytes_per_sector
480    }
481
482    pub fn sectors_per_cluster(&self) -> u8 {
483        self.boot_sector.sectors_per_cluster
484    }
485
486    pub fn bytes_per_cluster(&self) -> u32 {
487        self.boot_sector.sectors_per_cluster as u32 * self.boot_sector.bytes_per_sector as u32
488    }
489
490    pub fn reserved_sectors_count(&self) -> u16 {
491        self.boot_sector.reserved_sectors_count
492    }
493
494    pub fn total_sectors(&self) -> u32 {
495        if self.boot_sector.total_sectors_16 != 0 {
496            self.boot_sector.total_sectors_16 as u32
497        } else {
498            self.boot_sector.total_sectors_32
499        }
500    }
501
502    pub fn fat_size_in_sectors(&self) -> u32 {
503        if self.ty == FatType::Fat32 {
504            unsafe { self.boot_sector.extended.fat32.fat_size_32 }
505        } else {
506            self.boot_sector.fat_size_16 as u32
507        }
508    }
509
510    pub fn number_of_fats(&self) -> u8 {
511        self.boot_sector.number_of_fats
512    }
513
514    pub fn fat_start_sector(&self) -> u32 {
515        self.boot_sector.reserved_sectors_count as u32
516    }
517
518    pub fn root_dir_sectors(&self) -> u32 {
519        (self.boot_sector.root_entry_count as u32 * DIRECTORY_ENTRY_SIZE)
520            .div_ceil(self.boot_sector.bytes_per_sector as u32)
521    }
522
523    pub fn root_dir_start_sector(&self) -> u32 {
524        self.fat_start_sector() + self.number_of_fats() as u32 * self.fat_size_in_sectors()
525    }
526
527    pub fn data_start_sector(&self) -> u32 {
528        self.root_dir_start_sector() + self.root_dir_sectors()
529    }
530
531    pub fn data_sectors(&self) -> u32 {
532        self.total_sectors() - self.data_start_sector()
533    }
534
535    pub fn volume_label(&self) -> &[u8; 11] {
536        match self.ty {
537            FatType::Fat12 | FatType::Fat16 => unsafe {
538                &self.boot_sector.extended.fat12_16.volume_label
539            },
540            FatType::Fat32 => unsafe { &self.boot_sector.extended.fat32.volume_label },
541        }
542    }
543}
544
545#[allow(dead_code)]
546mod attrs {
547    pub const READ_ONLY: u8 = 0x01;
548    pub const HIDDEN: u8 = 0x02;
549    pub const SYSTEM: u8 = 0x04;
550    pub const VOLUME_ID: u8 = 0x08;
551    pub const DIRECTORY: u8 = 0x10;
552    pub const ARCHIVE: u8 = 0x20;
553    pub const LONG_NAME: u8 = READ_ONLY | HIDDEN | SYSTEM | VOLUME_ID;
554}
555
556#[derive(Debug, Clone, Copy, PartialEq, Eq)]
557enum DirectoryEntryState {
558    Free,
559    FreeAndLast,
560    Used,
561}
562
563#[derive(Debug, Clone, PartialEq, Eq)]
564#[repr(C, packed)]
565struct DirectoryEntryNormal {
566    short_name: [u8; 11],
567    attributes: u8,
568    _nt_reserved: u8,
569    creation_time_tenths_of_seconds: u8,
570    creation_time: u16,
571    creation_date: u16,
572    last_access_date: u16,
573    first_cluster_hi: u16,
574    last_modification_time: u16,
575    last_modification_date: u16,
576    first_cluster_lo: u16,
577    file_size: u32,
578}
579
580impl DirectoryEntryNormal {
581    pub fn name(&self) -> String {
582        let base_name = &self.short_name[..8];
583        let base_name_end = 8 - base_name.iter().rev().position(|&c| c != 0x20).unwrap();
584        let extension = &self.short_name[8..11];
585
586        let mut name = String::with_capacity(13);
587        let mut i = 0;
588        while i < base_name_end {
589            name.push(base_name[i] as char);
590            i += 1;
591        }
592        let extension_present = extension[0] != 0x20;
593        if extension_present {
594            name.push('.');
595            i = 0;
596            while i < extension.len() && extension[i] != 0x20 {
597                name.push(extension[i] as char);
598                i += 1;
599            }
600        }
601        name
602    }
603
604    pub fn first_cluster(&self) -> u32 {
605        ((self.first_cluster_hi as u32) << 16) | self.first_cluster_lo as u32
606    }
607
608    pub fn name_checksum(&self) -> u8 {
609        let mut checksum = 0u8;
610        for &c in self.short_name.iter() {
611            checksum = ((checksum & 1) << 7)
612                .wrapping_add(checksum >> 1)
613                .wrapping_add(c);
614        }
615        checksum
616    }
617}
618
619#[derive(Debug, Clone)]
620#[repr(C, packed)]
621struct DirectoryEntryLong {
622    sequence_number: u8,
623    name1: [u16; 5],
624    attributes: u8,
625    long_name_type: u8,
626    checksum: u8,
627    name2: [u16; 6],
628    _zero: u16,
629    name3: [u16; 2],
630}
631
632impl DirectoryEntryLong {
633    pub fn name(&self) -> String {
634        let name1 = unsafe { &core::ptr::addr_of!(self.name1).read_unaligned() };
635        let name2 = unsafe { &core::ptr::addr_of!(self.name2).read_unaligned() };
636        let name3 = unsafe { &core::ptr::addr_of!(self.name3).read_unaligned() };
637
638        // construct an iterator and fill the string part
639        let name_iter = name1
640            .iter()
641            .chain(name2)
642            .chain(name3)
643            .cloned()
644            .take_while(|c| c != &0);
645
646        let mut name_part = String::with_capacity(13);
647        char::decode_utf16(name_iter)
648            .map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER))
649            .for_each(|c| name_part.push(c));
650
651        name_part
652    }
653}
654
655enum DirectoryEntry<'a> {
656    Normal(&'a mut DirectoryEntryNormal),
657    Long(&'a mut DirectoryEntryLong),
658}
659
660impl<'a> DirectoryEntry<'a> {
661    pub fn from_raw(raw: &mut [u8]) -> DirectoryEntry<'_> {
662        assert_eq!(raw.len(), DIRECTORY_ENTRY_SIZE as usize);
663        let normal = unsafe {
664            raw.as_mut_ptr()
665                .cast::<DirectoryEntryNormal>()
666                .as_mut()
667                .unwrap()
668        };
669        let attributes = normal.attributes;
670        if attributes & attrs::LONG_NAME == attrs::LONG_NAME {
671            DirectoryEntry::Long(unsafe {
672                raw.as_mut_ptr()
673                    .cast::<DirectoryEntryLong>()
674                    .as_mut()
675                    .unwrap()
676            })
677        } else {
678            DirectoryEntry::Normal(normal)
679        }
680    }
681
682    pub fn state(&self) -> DirectoryEntryState {
683        let first_byte = match self {
684            DirectoryEntry::Normal(entry) => entry.short_name[0],
685            DirectoryEntry::Long(entry) => entry.sequence_number,
686        };
687        match first_byte {
688            0x00 => DirectoryEntryState::FreeAndLast,
689            0xE5 => DirectoryEntryState::Free,
690            _ => DirectoryEntryState::Used,
691        }
692    }
693
694    pub fn as_normal(&self) -> &DirectoryEntryNormal {
695        match self {
696            DirectoryEntry::Normal(entry) => entry,
697            _ => panic!("expected normal entry"),
698        }
699    }
700
701    pub fn as_normal_mut(&mut self) -> &mut DirectoryEntryNormal {
702        match self {
703            DirectoryEntry::Normal(entry) => entry,
704            _ => panic!("expected normal entry"),
705        }
706    }
707
708    pub fn is_long(&self) -> bool {
709        matches!(self, DirectoryEntry::Long(_))
710    }
711
712    pub fn as_long(&self) -> &DirectoryEntryLong {
713        match self {
714            DirectoryEntry::Long(entry) => entry,
715            _ => panic!("expected long entry"),
716        }
717    }
718
719    fn write_long(&mut self, new_entry: DirectoryEntryLong) {
720        assert_eq!(new_entry.attributes & attrs::LONG_NAME, attrs::LONG_NAME);
721        match self {
722            DirectoryEntry::Long(entry) => {
723                **entry = new_entry;
724            }
725            DirectoryEntry::Normal(entry) => {
726                // convert to long entry
727                // Safety: we know that these share the same memory layout
728                unsafe {
729                    let long_entry = core::ptr::from_mut(*entry)
730                        .cast::<DirectoryEntryLong>()
731                        .as_mut()
732                        .unwrap();
733                    *long_entry = new_entry;
734                    *self = DirectoryEntry::Long(long_entry);
735                }
736            }
737        }
738    }
739
740    fn write_normal(&mut self, new_entry: DirectoryEntryNormal) {
741        assert_ne!(new_entry.attributes & attrs::LONG_NAME, attrs::LONG_NAME);
742        match self {
743            DirectoryEntry::Normal(entry) => {
744                **entry = new_entry;
745            }
746            DirectoryEntry::Long(entry) => {
747                // convert to normal entry
748                // Safety: we know that these share the same memory layout
749                unsafe {
750                    let normal_entry = core::ptr::from_mut(entry)
751                        .cast::<DirectoryEntryNormal>()
752                        .as_mut()
753                        .unwrap();
754                    *normal_entry = new_entry;
755                    *self = DirectoryEntry::Normal(normal_entry);
756                }
757            }
758        }
759    }
760}
761
762/// A custom version of `fs::Node` for fat systems
763pub struct FatNode {
764    normal_entry: DirectoryEntryNormal,
765    long_name: Option<String>,
766
767    parent_dir_sector: u64,
768    parent_dir_index: u16,
769}
770
771impl FatNode {
772    pub fn matches(&self, matcher: &str) -> bool {
773        // First, check if we have a long name and if it matches
774        if let Some(long_name) = &self.long_name {
775            if long_name.eq_ignore_ascii_case(matcher) {
776                return true;
777            }
778        }
779
780        // If no long name match, check the short name
781        let short_name = self.normal_entry.name();
782        short_name.eq_ignore_ascii_case(matcher)
783    }
784}
785
786impl From<FatNode> for Node {
787    fn from(value: FatNode) -> Self {
788        Node::new(
789            value.long_name.unwrap_or(value.normal_entry.name()),
790            file_attribute_from_fat(value.normal_entry.attributes),
791            value.normal_entry.first_cluster().into(),
792            value.normal_entry.file_size.into(),
793            value.parent_dir_sector,
794            value.parent_dir_index,
795        )
796    }
797}
798
799#[derive(Debug, Clone, Copy)]
800struct DirectoryIterSavedPosition {
801    cluster: u32,
802    sector: u32,
803    entry: u16,
804}
805
806#[derive(Debug, Clone)]
807enum Directory {
808    RootFat12_16 {
809        start_sector: u32,
810        size_in_sectors: u32,
811    },
812    Normal {
813        inode: DirectoryNode,
814    },
815}
816
817pub struct DirectoryIterator<'a> {
818    dir: Directory,
819    filesystem: &'a FatFilesystem,
820    // only hold one sector
821    current_sector: Vec<u8>,
822    current_sector_index: u32,
823    current_cluster: u32,
824    current_sector_dirty: bool,
825    entry_index_in_sector: u16,
826}
827
828impl DirectoryIterator<'_> {
829    fn new(
830        filesystem: &FatFilesystem,
831        dir: Directory,
832    ) -> Result<DirectoryIterator<'_>, FileSystemError> {
833        let (sector_index, current_cluster, current_sector) = match dir {
834            Directory::RootFat12_16 { start_sector, .. } => (
835                start_sector,
836                0,
837                filesystem.read_sectors_no_cache(start_sector, 1)?,
838            ),
839            Directory::Normal { ref inode } => {
840                if matches!(filesystem.fat_type(), FatType::Fat12 | FatType::Fat16)
841                    && inode.start_cluster() == 0
842                {
843                    // looks like we got back using `..` to the root, thus, we should use the root directly
844                    return Self::new(filesystem, filesystem.open_root_dir()?);
845                }
846
847                let start_sector = filesystem.first_sector_of_cluster(inode.start_cluster() as u32);
848
849                (
850                    start_sector,
851                    inode.start_cluster() as u32,
852                    filesystem.read_sectors_no_cache(start_sector, 1)?,
853                )
854            }
855        };
856        Ok(DirectoryIterator {
857            dir,
858            filesystem,
859            current_sector,
860            current_cluster,
861            current_sector_dirty: false,
862            current_sector_index: sector_index,
863            entry_index_in_sector: 0,
864        })
865    }
866
867    // return true if we got more sectors and we can continue
868    fn next_sector(&mut self) -> Result<bool, FileSystemError> {
869        self.flush_current_sector();
870
871        // are we done?
872        let mut next_sector_index = self.current_sector_index + 1;
873        match self.dir {
874            Directory::RootFat12_16 {
875                start_sector,
876                size_in_sectors,
877            } => {
878                if next_sector_index >= start_sector + size_in_sectors {
879                    return Ok(false);
880                }
881            }
882            Directory::Normal { .. } => {
883                // did we exceed cluster boundary?
884                if next_sector_index
885                    .is_multiple_of(self.filesystem.boot_sector.sectors_per_cluster() as u32)
886                {
887                    // get next cluster
888                    let next_cluster = self.filesystem.fat.next_cluster(self.current_cluster);
889                    match next_cluster {
890                        Ok(Some(cluster)) => {
891                            self.current_cluster = cluster;
892                            next_sector_index =
893                                cluster * self.filesystem.boot_sector.sectors_per_cluster() as u32;
894                        }
895                        Ok(None) => {
896                            return Ok(false);
897                        }
898                        Err(_e) => {
899                            return Err(FileSystemError::FileNotFound);
900                        }
901                    }
902                }
903            }
904        }
905
906        self.current_sector = self
907            .filesystem
908            .read_sectors_no_cache(next_sector_index, 1)?;
909        self.current_sector_index = next_sector_index;
910        self.entry_index_in_sector = 0;
911        Ok(true)
912    }
913
914    fn get_next_entry(&mut self) -> Result<DirectoryEntry<'_>, FileSystemError> {
915        let entry_start = self.entry_index_in_sector as usize * DIRECTORY_ENTRY_SIZE as usize;
916        let entry_end = entry_start + DIRECTORY_ENTRY_SIZE as usize;
917        if entry_end > self.current_sector.len() {
918            // we need to read the next sector
919            return if self.next_sector()? {
920                self.get_next_entry()
921            } else {
922                Err(FileSystemError::FileNotFound)
923            };
924        }
925        let entry = &mut self.current_sector[entry_start..entry_end];
926        self.entry_index_in_sector += 1;
927
928        assert_eq!(entry.len(), DIRECTORY_ENTRY_SIZE as usize);
929        Ok(DirectoryEntry::from_raw(entry))
930    }
931
932    fn mark_sector_dirty(&mut self) {
933        self.current_sector_dirty = true;
934    }
935
936    fn flush_current_sector(&mut self) {
937        if self.current_sector_dirty {
938            let start_sector = self.current_sector_index;
939            self.filesystem
940                .write_sectors(start_sector, &self.current_sector)
941                .unwrap();
942            self.current_sector_dirty = false;
943        }
944    }
945
946    fn restore_at(&mut self, saved_pos: DirectoryIterSavedPosition) -> Result<(), FileSystemError> {
947        self.current_cluster = saved_pos.cluster;
948        self.entry_index_in_sector = saved_pos.entry;
949        if self.current_sector_index != saved_pos.sector {
950            self.flush_current_sector();
951
952            // we need to read the current sector
953            self.current_sector_index = saved_pos.sector;
954            self.current_sector = self
955                .filesystem
956                .read_sectors_no_cache(self.current_sector_index, 1)?;
957        }
958        Ok(())
959    }
960
961    fn save_current(&self) -> DirectoryIterSavedPosition {
962        DirectoryIterSavedPosition {
963            cluster: self.current_cluster,
964            sector: self.current_sector_index,
965            // if this is the first entry, keep it zero, otherwise it will always be at least 1
966            entry: self.entry_index_in_sector.saturating_sub(1),
967        }
968    }
969
970    fn add_entry(
971        &mut self,
972        mut entry: DirectoryEntryNormal,
973        long_entries: Vec<DirectoryEntryLong>,
974    ) -> Result<Node, FileSystemError> {
975        // used to check if the entry is already in the directory
976        let mut new_entry_short_name = entry.short_name;
977        let new_entry_long_name =
978            long_entries_name_merge(long_entries.iter().map(DirectoryEntryLong::name));
979
980        let needed_entries = long_entries.len() + 1;
981
982        let mut is_last = false;
983
984        let mut first_free = None;
985        let mut running_free = 0;
986        let mut current_long_entries_name = Vec::new();
987        let long_entries_require_free = Cell::new(false);
988
989        let mut is_already_exists = |entry: DirectoryEntry| -> bool {
990            if entry.is_long() {
991                if long_entries_require_free.get() {
992                    long_entries_require_free.set(false);
993                    current_long_entries_name.clear();
994                }
995                current_long_entries_name.push(entry.as_long().name());
996            } else {
997                let long_name = long_entries_name_merge(current_long_entries_name.drain(..));
998
999                if long_name.eq_ignore_ascii_case(&new_entry_long_name) {
1000                    return true;
1001                }
1002                // long name doesn't match, but short one matches, meaning the short name got clipped
1003                if entry.as_normal().short_name == new_entry_short_name {
1004                    increment_short_name(&mut new_entry_short_name);
1005                }
1006            }
1007
1008            false
1009        };
1010
1011        loop {
1012            let entry = self.get_next_entry()?;
1013            match entry.state() {
1014                DirectoryEntryState::FreeAndLast => {
1015                    long_entries_require_free.set(true);
1016
1017                    is_last = true;
1018                    // this is the first and last entry
1019                    if first_free.is_none() {
1020                        first_free = Some(self.save_current());
1021                    }
1022                    break;
1023                }
1024                DirectoryEntryState::Free => {
1025                    long_entries_require_free.set(true);
1026
1027                    // make sure we have enough free entries
1028                    if first_free.is_none() {
1029                        first_free = Some(self.save_current());
1030                    }
1031                    running_free += 1;
1032                    if running_free == needed_entries {
1033                        break;
1034                    }
1035                }
1036                DirectoryEntryState::Used => {
1037                    // reset the running free
1038                    running_free = 0;
1039                    first_free = None;
1040                    if is_already_exists(entry) {
1041                        return Err(FileSystemError::AlreadyExists);
1042                    }
1043                }
1044            }
1045        }
1046
1047        if !is_last {
1048            // keep looking through all Used
1049            loop {
1050                let entry = self.get_next_entry()?;
1051                match entry.state() {
1052                    DirectoryEntryState::FreeAndLast => break,
1053                    DirectoryEntryState::Used => {
1054                        if is_already_exists(entry) {
1055                            return Err(FileSystemError::AlreadyExists);
1056                        }
1057                    }
1058                    _ => {}
1059                }
1060            }
1061        }
1062
1063        // update the short_name if it changed/incremented
1064        entry.short_name = new_entry_short_name;
1065
1066        assert!(first_free.is_some());
1067        let first_free = first_free.unwrap();
1068
1069        self.restore_at(first_free)?;
1070
1071        // write the long entries
1072        let mut current_entry = self.get_next_entry()?;
1073
1074        for long_entry in long_entries.into_iter().rev() {
1075            current_entry.write_long(long_entry);
1076            self.mark_sector_dirty();
1077            current_entry = self.get_next_entry()?;
1078        }
1079
1080        // write the normal entry
1081        current_entry.write_normal(entry);
1082        self.mark_sector_dirty();
1083
1084        // go back
1085        self.restore_at(first_free)?;
1086        let node = self.next();
1087
1088        if is_last {
1089            let pos = self.save_current();
1090            // that was the last entry, make sure the new last is valid
1091            current_entry = self.get_next_entry()?;
1092            current_entry.as_normal_mut().short_name[0] = 0x00;
1093            self.mark_sector_dirty();
1094            // restore, so that next calls to `add_entry` can continue without missing an entry
1095            self.restore_at(pos)?;
1096        }
1097
1098        Ok(node.expect("node should be created").into())
1099    }
1100}
1101
1102impl Iterator for DirectoryIterator<'_> {
1103    type Item = FatNode;
1104
1105    fn next(&mut self) -> Option<Self::Item> {
1106        let mut entry = self.get_next_entry().ok()?;
1107
1108        loop {
1109            match entry.state() {
1110                DirectoryEntryState::FreeAndLast => {
1111                    return None;
1112                }
1113                DirectoryEntryState::Free => {
1114                    entry = self.get_next_entry().ok()?;
1115                }
1116                _ => break,
1117            }
1118        }
1119
1120        let long_name = if entry.is_long() {
1121            let mut long_entry = entry.as_long().clone();
1122            // long file name
1123            // this should be the last
1124            assert_eq!(long_entry.sequence_number & 0x40, 0x40);
1125            let number_of_entries = long_entry.sequence_number & 0x3F;
1126            let mut long_name_entries = Vec::with_capacity(number_of_entries as usize);
1127            // skip all long file name entries
1128            for i in 0..number_of_entries {
1129                let name_part = long_entry.name();
1130
1131                // add to the entries
1132                long_name_entries.push(name_part);
1133
1134                // next entry
1135                entry = self.get_next_entry().ok()?;
1136                if i + 1 < number_of_entries {
1137                    long_entry = entry.as_long().clone();
1138                }
1139            }
1140
1141            Some(long_entries_name_merge(long_name_entries.into_iter()))
1142        } else {
1143            None
1144        };
1145
1146        let normal_entry = entry.as_normal().clone();
1147        assert!(self.entry_index_in_sector > 0);
1148
1149        Some(FatNode {
1150            normal_entry,
1151            long_name,
1152            parent_dir_sector: self.current_sector_index.into(),
1153            parent_dir_index: self.entry_index_in_sector - 1,
1154        })
1155    }
1156}
1157
1158impl Drop for DirectoryIterator<'_> {
1159    fn drop(&mut self) {
1160        self.flush_current_sector();
1161    }
1162}
1163
1164#[derive(Debug)]
1165struct ClusterCacheEntry {
1166    #[allow(dead_code)]
1167    cluster: u32,
1168    /// Number of active users of this cluster
1169    reference_count: u32,
1170    dirty_range: Option<Range<usize>>,
1171    data: NoDebug<Vec<u8>>,
1172}
1173
1174#[derive(Default, Debug)]
1175struct ClusterCache {
1176    entries: BTreeMap<u32, ClusterCacheEntry>,
1177}
1178
1179impl ClusterCache {
1180    pub fn try_get_cluster_mut(&mut self, cluster: u32) -> Option<&mut ClusterCacheEntry> {
1181        self.entries.get_mut(&cluster)
1182    }
1183
1184    pub fn try_get_cluster_locked(&mut self, cluster: u32) -> Option<&mut ClusterCacheEntry> {
1185        if let Some(entry) = self.entries.get_mut(&cluster) {
1186            entry.reference_count += 1;
1187            return Some(entry);
1188        }
1189        None
1190    }
1191
1192    pub fn insert_cluster(&mut self, cluster: u32, data: Vec<u8>) -> &mut ClusterCacheEntry {
1193        let entry = ClusterCacheEntry {
1194            cluster,
1195            reference_count: 1,
1196            data: NoDebug(data),
1197            dirty_range: None,
1198        };
1199        self.entries.entry(cluster).or_insert(entry)
1200    }
1201
1202    pub fn release_cluster(&mut self, cluster: u32) -> Option<ClusterCacheEntry> {
1203        match self.entries.entry(cluster) {
1204            alloc::collections::btree_map::Entry::Vacant(_) => None,
1205            alloc::collections::btree_map::Entry::Occupied(mut entry) => {
1206                let cluster = entry.get_mut();
1207                cluster.reference_count -= 1;
1208                if cluster.reference_count == 0 {
1209                    return Some(entry.remove());
1210                }
1211                None
1212            }
1213        }
1214    }
1215
1216    pub fn release_all(&mut self) -> BTreeMap<u32, ClusterCacheEntry> {
1217        core::mem::take(&mut self.entries)
1218    }
1219}
1220
1221/// Buffer for reading or writing file data
1222enum FileAccessBuffer<'a> {
1223    Read(&'a mut [u8]),
1224    Write(&'a [u8]),
1225}
1226
1227impl FileAccessBuffer<'_> {
1228    pub fn len(&self) -> usize {
1229        match self {
1230            FileAccessBuffer::Read(data) => data.len(),
1231            FileAccessBuffer::Write(data) => data.len(),
1232        }
1233    }
1234}
1235
1236/// File Allocation Table buffer
1237#[derive(Debug)]
1238struct Fat {
1239    buffer: NoDebug<Vec<u8>>,
1240    sector_size: u16,
1241    fat_type: FatType,
1242    dirty: bool,
1243    /// One bit for each sector in the FAT
1244    dirty_bitmap: Vec<u64>,
1245}
1246
1247impl Fat {
1248    /// A temporary initializer for the FAT, will be replaced with [`Fat::load`]
1249    fn new() -> Self {
1250        Self {
1251            buffer: NoDebug(Vec::new()),
1252            sector_size: 0,
1253            fat_type: FatType::Fat12,
1254            dirty: false,
1255            dirty_bitmap: Vec::new(),
1256        }
1257    }
1258
1259    fn load(filesystem: &FatFilesystem) -> Result<Self, FileSystemError> {
1260        let fats_size_in_sectors = filesystem.boot_sector.fat_size_in_sectors()
1261            * filesystem.boot_sector.number_of_fats() as u32;
1262        let fat_start_sector = filesystem.boot_sector.fat_start_sector();
1263
1264        let buffer = filesystem.read_sectors_no_cache(fat_start_sector, fats_size_in_sectors)?;
1265        let fat_type = filesystem.fat_type();
1266
1267        Ok(Self {
1268            buffer: NoDebug(buffer),
1269            sector_size: filesystem.boot_sector.bytes_per_sector(),
1270            fat_type,
1271            dirty: false,
1272            dirty_bitmap: vec![0; (fats_size_in_sectors as usize).div_ceil(64)],
1273        })
1274    }
1275
1276    // return an iterator of (sector_index, sector_data) for all dirty sectors
1277    fn dirty_sectors(&self) -> Option<impl Iterator<Item = (u32, &[u8])>> {
1278        if !self.dirty {
1279            return None;
1280        }
1281
1282        Some(
1283            self.dirty_bitmap
1284                .iter()
1285                .enumerate()
1286                .filter_map(move |(i, dirty)| {
1287                    if *dirty == 0 {
1288                        return None;
1289                    }
1290
1291                    let mut dirty = *dirty;
1292                    let mut bit = 0;
1293
1294                    Some(core::iter::from_fn(move || {
1295                        while dirty != 0 {
1296                            if dirty & 1 != 0 {
1297                                let sector = (i * 64 + bit) as u32;
1298                                let sector_start = sector * self.sector_size as u32;
1299                                let sector_end = sector_start + self.sector_size as u32;
1300                                let data = &self.buffer[sector_start as usize..sector_end as usize];
1301                                dirty >>= 1;
1302                                bit += 1;
1303                                return Some((sector, data));
1304                            }
1305                            dirty >>= 1;
1306                            bit += 1;
1307                        }
1308                        None
1309                    }))
1310                })
1311                .flatten(),
1312        )
1313    }
1314
1315    fn clear_dirty(&mut self) {
1316        if self.dirty {
1317            self.dirty = false;
1318            self.dirty_bitmap.iter_mut().for_each(|d| *d = 0);
1319        }
1320    }
1321
1322    fn read_fat_entry(&self, entry: u32) -> FatEntry {
1323        let fat_offset = match self.fat_type {
1324            FatType::Fat12 => entry * 3 / 2,
1325            FatType::Fat16 => entry * 2,
1326            FatType::Fat32 => entry * 4,
1327        } as usize;
1328        assert!(fat_offset < self.buffer.0.len(), "FAT entry out of bounds");
1329        let ptr = unsafe { self.buffer.0.as_ptr().add(fat_offset) };
1330
1331        let entry = match self.fat_type {
1332            FatType::Fat12 => {
1333                let byte1 = self.buffer.0[fat_offset];
1334                let byte2 = self.buffer.0[fat_offset + 1];
1335                if entry & 1 == 1 {
1336                    ((byte2 as u32) << 4) | ((byte1 as u32) >> 4)
1337                } else {
1338                    (((byte2 as u32) & 0xF) << 8) | (byte1 as u32)
1339                }
1340            }
1341            FatType::Fat16 => unsafe { (*(ptr as *const u16)) as u32 },
1342            FatType::Fat32 => unsafe { (*(ptr as *const u32)) & 0x0FFF_FFFF },
1343        };
1344
1345        FatEntry::from_u32(self.fat_type, entry)
1346    }
1347
1348    fn mark_sector_dirty(&mut self, sector: usize) {
1349        let index = sector / 64;
1350        let bit = sector % 64;
1351        self.dirty_bitmap[index] |= 1 << bit;
1352    }
1353
1354    fn write_fat_entry(&mut self, entry: u32, fat_entry: FatEntry) {
1355        let fat_offset = match self.fat_type {
1356            FatType::Fat12 => entry * 3 / 2,
1357            FatType::Fat16 => entry * 2,
1358            FatType::Fat32 => entry * 4,
1359        } as usize;
1360        assert!(fat_offset < self.buffer.0.len(), "FAT entry out of bounds");
1361        let ptr = unsafe { self.buffer.0.as_mut_ptr().add(fat_offset) };
1362
1363        let new_entry = fat_entry.to_u32(self.fat_type).expect("invalid FAT entry");
1364
1365        match self.fat_type {
1366            FatType::Fat12 => {
1367                if entry & 1 == 1 {
1368                    self.buffer.0[fat_offset] =
1369                        (self.buffer.0[fat_offset] & 0x0F) | (new_entry << 4) as u8;
1370                    self.buffer.0[fat_offset + 1] = (new_entry >> 4) as u8;
1371                } else {
1372                    self.buffer.0[fat_offset] = new_entry as u8;
1373                    self.buffer.0[fat_offset + 1] =
1374                        (self.buffer.0[fat_offset + 1] & 0xF0) | ((new_entry >> 8) as u8);
1375                }
1376            }
1377            FatType::Fat16 => unsafe { *(ptr as *mut u16) = new_entry as u16 },
1378            FatType::Fat32 => unsafe { *(ptr as *mut u32) = new_entry },
1379        }
1380
1381        self.mark_sector_dirty(fat_offset / self.sector_size as usize);
1382
1383        // can cross sector boundary sometimes
1384        if self.fat_type == FatType::Fat12 {
1385            self.mark_sector_dirty((fat_offset + 1) / self.sector_size as usize);
1386        }
1387
1388        self.dirty = true;
1389    }
1390
1391    fn find_free_cluster(&self) -> Option<u32> {
1392        let fat_size = self.buffer.0.len();
1393
1394        let number_of_fat_entries = match self.fat_type {
1395            FatType::Fat12 => fat_size * 2 / 3,
1396            FatType::Fat16 => fat_size / 2,
1397            FatType::Fat32 => fat_size / 4,
1398        } as u32;
1399
1400        (2..number_of_fat_entries).find(|&i| self.read_fat_entry(i) == FatEntry::Free)
1401    }
1402
1403    fn next_cluster(&self, cluster: u32) -> Result<Option<u32>, FileSystemError> {
1404        match self.read_fat_entry(cluster) {
1405            FatEntry::Next(next_cluster) => Ok(Some(next_cluster)),
1406            FatEntry::EndOfChain => Ok(None),
1407            FatEntry::Bad => Err(FatError::UnexpectedFatEntry.into()),
1408            FatEntry::Reserved => Err(FatError::UnexpectedFatEntry.into()),
1409            FatEntry::Free => Err(FatError::UnexpectedFatEntry.into()),
1410        }
1411    }
1412}
1413
1414#[derive(Debug)]
1415pub struct FatFilesystem {
1416    start_lba: u32,
1417    #[allow(dead_code)]
1418    size_in_sectors: u32,
1419    boot_sector: Box<FatBootSector>,
1420    fat: Fat,
1421    device: NoDebug<Arc<IdeDevice>>,
1422    cluster_cache: ClusterCache,
1423}
1424
1425impl FatFilesystem {
1426    fn new(
1427        start_lba: u32,
1428        size_in_sectors: u32,
1429        boot_sector: FatBootSector,
1430        device: Arc<IdeDevice>,
1431    ) -> Result<Self, FileSystemError> {
1432        let mut s = FatFilesystem {
1433            start_lba,
1434            size_in_sectors,
1435            boot_sector: Box::new(boot_sector),
1436            fat: Fat::new(),
1437            device: NoDebug(device),
1438            cluster_cache: ClusterCache::default(),
1439        };
1440
1441        // TODO: replace by lazily reading FAT when needed
1442        s.fat = Fat::load(&s)?;
1443
1444        Ok(s)
1445    }
1446
1447    pub fn volume_label(&self) -> String {
1448        let label = self.boot_sector.volume_label();
1449        let mut label = String::from_utf8_lossy(label).to_string();
1450        label.retain(|c| c != '\0');
1451        label
1452    }
1453
1454    pub fn fat_type(&self) -> FatType {
1455        self.boot_sector.ty
1456    }
1457
1458    fn first_sector_of_cluster(&self, cluster: u32) -> u32 {
1459        self.boot_sector.data_start_sector()
1460            + (cluster - 2) * self.boot_sector.sectors_per_cluster() as u32
1461    }
1462
1463    fn read_sectors_no_cache(
1464        &self,
1465        start_sector: u32,
1466        count: u32,
1467    ) -> Result<Vec<u8>, FileSystemError> {
1468        if count == 0 {
1469            return Ok(Vec::new());
1470        }
1471
1472        let sector_size = self.boot_sector.bytes_per_sector() as usize;
1473        let mut sectors = vec![0; sector_size * count as usize];
1474
1475        let start_lba = (self.start_lba + start_sector) as u64;
1476        self.device
1477            .read_sync(start_lba, &mut sectors)
1478            .map_err(|e| FileSystemError::DiskReadError {
1479                sector: start_lba,
1480                error: e,
1481            })?;
1482
1483        Ok(sectors)
1484    }
1485
1486    fn write_sectors(&self, start_sector: u32, data: &[u8]) -> Result<(), FileSystemError> {
1487        if data.is_empty() {
1488            return Ok(());
1489        }
1490        assert_eq!(data.len() % self.boot_sector.bytes_per_sector() as usize, 0);
1491        let start_lba = (self.start_lba + start_sector) as u64;
1492        self.device
1493            .write_sync(start_lba, data)
1494            .map_err(|e| FileSystemError::DiskReadError {
1495                sector: start_lba,
1496                error: e,
1497            })?;
1498        Ok(())
1499    }
1500
1501    fn get_cluster(&mut self, cluster: u32) -> Option<&mut ClusterCacheEntry> {
1502        self.cluster_cache.try_get_cluster_mut(cluster)
1503    }
1504
1505    fn lock_cluster(&mut self, cluster: u32) -> Result<&mut ClusterCacheEntry, FileSystemError> {
1506        // TODO: fix this borrow checker issue when the language fixes it
1507        //       without borrow checker error we won't need to call `try_get_cluster_locked` twice
1508        if self.cluster_cache.try_get_cluster_mut(cluster).is_none() {
1509            let data = self.read_sectors_no_cache(
1510                self.first_sector_of_cluster(cluster),
1511                self.boot_sector.sectors_per_cluster().into(),
1512            )?;
1513            return Ok(self.cluster_cache.insert_cluster(cluster, data));
1514        }
1515
1516        Ok(self.cluster_cache.try_get_cluster_locked(cluster).unwrap())
1517    }
1518
1519    /// Helper method to write the dirty parts of a cluster into disk
1520    fn flush_cluster_dirty_range_file(
1521        &mut self,
1522        inode: &FileNode,
1523        cluster_data: &[u8],
1524        cluster_num: u32,
1525        dirty_range: Range<usize>,
1526    ) -> Result<(), FileSystemError> {
1527        self.flush_fat()?;
1528        self.update_directory_entry(inode, |entry| {
1529            entry.file_size = inode.size() as u32;
1530        })?;
1531
1532        self.flush_cluster_dirty_range(cluster_data, cluster_num, dirty_range)
1533    }
1534
1535    fn flush_cluster_dirty_range(
1536        &mut self,
1537        cluster_data: &[u8],
1538        cluster_num: u32,
1539        dirty_range: Range<usize>,
1540    ) -> Result<(), FileSystemError> {
1541        let start_byte_offset = align_down(
1542            dirty_range.start,
1543            self.boot_sector.bytes_per_sector() as usize,
1544        );
1545        let end_byte_offset = align_up(
1546            dirty_range.end,
1547            self.boot_sector.bytes_per_sector() as usize,
1548        );
1549        assert!(
1550            start_byte_offset < self.boot_sector.bytes_per_cluster() as usize,
1551            "start_byte_offset: {start_byte_offset} < {}",
1552            self.boot_sector.bytes_per_cluster()
1553        );
1554        assert!(
1555            end_byte_offset <= self.boot_sector.bytes_per_cluster() as usize,
1556            "end_byte_offset: {end_byte_offset} < {}",
1557            self.boot_sector.bytes_per_cluster()
1558        );
1559        assert!(
1560            start_byte_offset < end_byte_offset,
1561            "start_byte_offset, end_byte_offset {start_byte_offset} < {end_byte_offset}"
1562        );
1563
1564        // write back
1565        let start_sector = self.first_sector_of_cluster(cluster_num)
1566            + (start_byte_offset as u32 / self.boot_sector.bytes_per_sector() as u32);
1567        self.write_sectors(
1568            start_sector,
1569            &cluster_data[start_byte_offset..end_byte_offset],
1570        )?;
1571
1572        Ok(())
1573    }
1574
1575    fn release_cluster(&mut self, inode: &FileNode, cluster: u32) -> Result<(), FileSystemError> {
1576        if let Some(cluster) = self.cluster_cache.release_cluster(cluster) {
1577            if let Some(dirty_range) = cluster.dirty_range {
1578                self.flush_cluster_dirty_range_file(
1579                    inode,
1580                    &cluster.data,
1581                    cluster.cluster,
1582                    dirty_range,
1583                )?;
1584            }
1585        }
1586        Ok(())
1587    }
1588
1589    /// Same as `release_cluster`, but doesn't release it, i.e. the cluster will
1590    /// still be used, but the `dirty` flag is removed
1591    fn flush_cluster(&mut self, inode: &FileNode, cluster: u32) -> Result<(), FileSystemError> {
1592        let mut cluster_data: Option<NoDebug<Vec<u8>>> = None;
1593
1594        if let Some(cluster) = self.cluster_cache.try_get_cluster_mut(cluster) {
1595            if let Some(dirty_range) = cluster.dirty_range.take() {
1596                let cluster_num = cluster.cluster;
1597                cluster_data = Some(NoDebug(Vec::new()));
1598                core::mem::swap(&mut cluster.data, cluster_data.as_mut().unwrap());
1599                self.flush_cluster_dirty_range_file(
1600                    inode,
1601                    cluster_data.as_ref().unwrap(),
1602                    cluster_num,
1603                    dirty_range,
1604                )?;
1605            }
1606        }
1607        // swap back
1608        // This is annoying, and its only used to get around the borrow checker
1609        // probably there is a way to better achieve this
1610        // FIXME: find better solution
1611        if let Some(cluster) = self.cluster_cache.try_get_cluster_mut(cluster) {
1612            if let Some(cluster_data) = cluster_data.as_mut() {
1613                core::mem::swap(&mut cluster.data, cluster_data);
1614            }
1615        }
1616
1617        Ok(())
1618    }
1619
1620    fn flush_fat(&mut self) -> Result<(), FileSystemError> {
1621        if let Some(dirt_iter) = self.fat.dirty_sectors() {
1622            for (sector, data) in dirt_iter {
1623                self.write_sectors(self.boot_sector.fat_start_sector() + sector, data)?;
1624            }
1625        }
1626        self.fat.clear_dirty();
1627
1628        Ok(())
1629    }
1630
1631    fn open_root_dir(&self) -> Result<Directory, FileSystemError> {
1632        match self.fat_type() {
1633            FatType::Fat12 | FatType::Fat16 => Ok(Directory::RootFat12_16 {
1634                start_sector: self.boot_sector.root_dir_start_sector(),
1635                size_in_sectors: self.boot_sector.root_dir_sectors(),
1636            }),
1637            FatType::Fat32 => {
1638                let root_cluster =
1639                    unsafe { self.boot_sector.boot_sector.extended.fat32.root_cluster };
1640                let inode = DirectoryNode::without_parent(
1641                    String::from("/"),
1642                    file_attribute_from_fat(attrs::DIRECTORY),
1643                    root_cluster as u64,
1644                );
1645                Ok(Directory::Normal { inode })
1646            }
1647        }
1648    }
1649
1650    fn open_root_dir_inode(&self) -> Result<DirectoryNode, FileSystemError> {
1651        match self.fat_type() {
1652            FatType::Fat12 | FatType::Fat16 => {
1653                // use a special inode for root
1654                let inode = DirectoryNode::without_parent(
1655                    String::from("/"),
1656                    file_attribute_from_fat(attrs::DIRECTORY),
1657                    0,
1658                );
1659
1660                Ok(inode)
1661            }
1662            FatType::Fat32 => {
1663                let root_cluster =
1664                    unsafe { self.boot_sector.boot_sector.extended.fat32.root_cluster };
1665                let inode = DirectoryNode::without_parent(
1666                    String::from("/"),
1667                    file_attribute_from_fat(attrs::DIRECTORY),
1668                    root_cluster as u64,
1669                );
1670                Ok(inode)
1671            }
1672        }
1673    }
1674
1675    pub fn open_dir_inode(
1676        &self,
1677        inode: &DirectoryNode,
1678    ) -> Result<DirectoryIterator<'_>, FileSystemError> {
1679        let dir = match self.fat_type() {
1680            FatType::Fat12 | FatType::Fat16 => {
1681                // try to see if this is the root
1682                // this could be 0 if we are back from using `..` to the root
1683                if inode.start_cluster() == 0 {
1684                    self.open_root_dir()?
1685                } else {
1686                    Directory::Normal {
1687                        inode: inode.clone(),
1688                    }
1689                }
1690            }
1691            FatType::Fat32 => Directory::Normal {
1692                inode: inode.clone(),
1693            },
1694        };
1695
1696        DirectoryIterator::new(self, dir)
1697    }
1698
1699    fn read_write_file(
1700        &mut self,
1701        inode: &FileNode,
1702        position: u32,
1703        mut buf: FileAccessBuffer,
1704        access_helper: &mut AccessHelper,
1705    ) -> Result<u64, FileSystemError> {
1706        if position >= inode.size() as u32 {
1707            return Ok(0);
1708        }
1709        let remaining_file = inode.size() as u32 - position;
1710        let max_to_access = (buf.len() as u32).min(remaining_file);
1711        let bytes_per_cluster = self.boot_sector.bytes_per_cluster();
1712        let mut position_in_cluster = position % bytes_per_cluster;
1713        let cluster_index = position / bytes_per_cluster;
1714
1715        // seek happened or switch exactly to next cluster after last call
1716        if access_helper.cluster_index != cluster_index as u64 {
1717            if access_helper.current_cluster != 0 {
1718                self.release_cluster(inode, access_helper.current_cluster as u32)?;
1719            }
1720            access_helper.current_cluster = 0;
1721        }
1722
1723        // starting out
1724        let mut cluster_entry = if access_helper.current_cluster == 0 {
1725            let mut cluster = inode.start_cluster() as u32;
1726
1727            // cannot be empty, or be the root
1728            assert_ne!(cluster, 0);
1729
1730            for _ in 0..cluster_index {
1731                cluster = self
1732                    .fat
1733                    .next_cluster(cluster)?
1734                    .ok_or(FatError::UnexpectedFatEntry)?;
1735            }
1736
1737            access_helper.current_cluster = cluster as u64;
1738            access_helper.cluster_index = cluster_index as u64;
1739            self.lock_cluster(access_helper.current_cluster as u32)?
1740        } else {
1741            self.get_cluster(access_helper.current_cluster as u32)
1742                .expect("This should be cached")
1743        };
1744        let mut cluster = access_helper.current_cluster as u32;
1745
1746        // read/write
1747        let mut accessed = 0;
1748        while accessed < max_to_access as usize {
1749            let remaining_in_cluster = &mut cluster_entry.data[position_in_cluster as usize..];
1750
1751            let to_access = core::cmp::min(
1752                remaining_in_cluster.len() as u32,
1753                max_to_access - accessed as u32,
1754            ) as usize;
1755            match buf {
1756                FileAccessBuffer::Read(ref mut buf) => {
1757                    buf[accessed..accessed + to_access]
1758                        .copy_from_slice(&remaining_in_cluster[..to_access]);
1759                }
1760                FileAccessBuffer::Write(buf) => {
1761                    let range_start = position_in_cluster as usize;
1762                    let range_end = range_start + to_access;
1763
1764                    if let Some(dirty_range) = cluster_entry.dirty_range.as_mut() {
1765                        dirty_range.start = dirty_range.start.min(range_start);
1766                        dirty_range.end = dirty_range.end.max(range_end);
1767                    } else {
1768                        cluster_entry.dirty_range = Some(range_start..range_end);
1769                    }
1770                    remaining_in_cluster[..to_access]
1771                        .copy_from_slice(&buf[accessed..accessed + to_access]);
1772                }
1773            }
1774
1775            accessed += to_access;
1776            position_in_cluster += to_access as u32;
1777            if position_in_cluster >= bytes_per_cluster {
1778                assert_eq!(position_in_cluster, bytes_per_cluster);
1779                position_in_cluster = 0;
1780                match self.fat.next_cluster(cluster)? {
1781                    Some(next_cluster) => {
1782                        self.release_cluster(inode, cluster)?;
1783                        cluster = next_cluster;
1784                        cluster_entry = self.lock_cluster(cluster)?;
1785                        access_helper.current_cluster = cluster as u64;
1786                        access_helper.cluster_index += 1;
1787                    }
1788                    None => {
1789                        break;
1790                    }
1791                };
1792            }
1793        }
1794
1795        Ok(accessed as u64)
1796    }
1797
1798    fn update_directory_entry(
1799        &mut self,
1800        inode: &BaseNode,
1801        mut update: impl FnMut(&mut DirectoryEntryNormal),
1802    ) -> Result<(), FileSystemError> {
1803        let mut sector = self.read_sectors_no_cache(inode.parent_dir_sector() as u32, 1)?;
1804        let entry_index = inode.parent_dir_index();
1805        let start = entry_index as usize * DIRECTORY_ENTRY_SIZE as usize;
1806        let end = start + DIRECTORY_ENTRY_SIZE as usize;
1807
1808        let mut entry = DirectoryEntry::from_raw(&mut sector[start..end]);
1809        assert_eq!(entry.state(), DirectoryEntryState::Used);
1810
1811        let entry = entry.as_normal_mut();
1812        let current = entry.clone();
1813        update(entry);
1814
1815        if current != *entry {
1816            // write back
1817            self.write_sectors(inode.parent_dir_sector() as u32, &sector)?;
1818        }
1819
1820        Ok(())
1821    }
1822
1823    fn add_directory_entry(
1824        &mut self,
1825        parent_inode: &DirectoryNode,
1826        name: &str,
1827        attributes: FileAttributes,
1828    ) -> Result<Node, FileSystemError> {
1829        let (mut normal_entry, long_name_entries) = create_dir_entries(name, attributes);
1830
1831        // NOTE: here, we perform the following (for dirs)
1832        // - allocate cluster
1833        // - create the directory (this may fail, if so, rollback)
1834        // - create the . and .. entries
1835        // We could have done it more efficiently, by starting with cluster=0
1836        // and then allocating and creating directories if its not existent
1837        // but the issue is that qemu vvfat driver will complain and print some debug messages that
1838        // cluster 0 is used multiple times, so we are here, making sure the cluster is always
1839        // valid
1840        //
1841        // TODO: probably we don't need this for normal disks, but for now, lets keep it as its
1842        // easier to use vvfat
1843        // create the . and .. entries if this is a directory
1844
1845        let cluster = self
1846            .fat
1847            .find_free_cluster()
1848            .ok_or(FatError::NotEnoughSpace)?;
1849        self.fat.write_fat_entry(cluster, FatEntry::EndOfChain);
1850        self.flush_fat()?;
1851        // let's empty out the first sector only
1852        // if it's a file, the size is 0 anyway
1853        // if it's a directory, it will exit since the
1854        // first direntry will be zero
1855        self.write_sectors(
1856            self.first_sector_of_cluster(cluster),
1857            &vec![0; self.boot_sector.bytes_per_sector() as usize],
1858        )?;
1859
1860        normal_entry.first_cluster_lo = (cluster & 0xFFFF) as u16;
1861        normal_entry.first_cluster_hi = (cluster >> 16) as u16;
1862
1863        let node = self
1864            .open_dir_inode(parent_inode)
1865            .and_then(|mut dir| dir.add_entry(normal_entry.clone(), long_name_entries));
1866
1867        let node = match node {
1868            Ok(node) => node,
1869            e @ Err(_) => {
1870                // revert fat changes
1871                self.fat.write_fat_entry(cluster, FatEntry::Free);
1872                self.flush_fat()?;
1873                return e;
1874            }
1875        };
1876
1877        assert_eq!(node.name(), name, "node name: {:?}", node.name());
1878
1879        // create the . and .. entries if this is a directory
1880        if attributes.directory() {
1881            assert_eq!(node.start_cluster(), cluster as u64);
1882            let mut dot_entry = DirectoryEntryNormal {
1883                short_name: [0x20; 11],
1884                _nt_reserved: 0,
1885                ..normal_entry
1886            };
1887            dot_entry.short_name[0] = b'.';
1888            let parent_cluster = parent_inode.start_cluster() as u32;
1889            let mut dot_dot_entry = DirectoryEntryNormal {
1890                short_name: [0x20; 11],
1891                _nt_reserved: 0,
1892                attributes: file_attribute_to_fat(parent_inode.attributes()),
1893                creation_time_tenths_of_seconds: 0,
1894                creation_time: 0,
1895                creation_date: 0,
1896                last_access_date: 0,
1897                first_cluster_lo: (parent_cluster & 0xFFFF) as u16,
1898                first_cluster_hi: (parent_cluster >> 16) as u16,
1899                last_modification_time: 0,
1900                last_modification_date: 0,
1901                file_size: 0,
1902            };
1903            dot_dot_entry.short_name[0] = b'.';
1904            dot_dot_entry.short_name[1] = b'.';
1905
1906            let dir_node = match node {
1907                Node::Directory(ref dir) => dir,
1908                _ => unreachable!(),
1909            };
1910
1911            let mut dir_iter = self.open_dir_inode(dir_node)?;
1912            let dot_node = dir_iter.add_entry(dot_entry, Vec::new())?;
1913            let dot_dot_node = dir_iter.add_entry(dot_dot_entry, Vec::new())?;
1914
1915            assert_eq!(dot_node.name(), ".", "dot node name: {:?}", dot_node.name());
1916            assert_eq!(
1917                dot_dot_node.name(),
1918                "..",
1919                "dot dot node name: {:?}",
1920                dot_dot_node.name()
1921            );
1922        }
1923
1924        Ok(node)
1925    }
1926
1927    fn set_file_size(&mut self, inode: &mut FileNode, size: u64) -> Result<(), FileSystemError> {
1928        let bytes_per_cluster = self.boot_sector.bytes_per_cluster() as u64;
1929        let current_size_in_clusters = inode.size().div_ceil(bytes_per_cluster);
1930        let new_size_in_clusters = size.div_ceil(bytes_per_cluster);
1931
1932        // at least 1 cluster at any point
1933        let current_size_in_clusters = current_size_in_clusters.max(1);
1934        let new_size_in_clusters = new_size_in_clusters.max(1);
1935
1936        if new_size_in_clusters != current_size_in_clusters {
1937            // update fat references
1938            let to_keep = new_size_in_clusters.min(current_size_in_clusters);
1939
1940            let mut current_cluster = inode.start_cluster() as u32;
1941
1942            // if we won't keep anything, then don't loop
1943            for _ in 0..to_keep.saturating_sub(1) {
1944                let next_cluster = self
1945                    .fat
1946                    .next_cluster(current_cluster)?
1947                    .expect("next cluster");
1948                current_cluster = next_cluster;
1949            }
1950
1951            let mut last_cluster = current_cluster;
1952
1953            if current_size_in_clusters > new_size_in_clusters {
1954                // deleting old clusters
1955                let to_delete = current_size_in_clusters - new_size_in_clusters;
1956                let mut clusters = Vec::with_capacity(to_delete as usize);
1957
1958                for _ in 0..to_delete {
1959                    let next_cluster = self
1960                        .fat
1961                        .next_cluster(current_cluster)?
1962                        .expect("next cluster");
1963                    clusters.push(next_cluster);
1964                    current_cluster = next_cluster;
1965                }
1966
1967                // move backwards
1968                for cluster in clusters.into_iter().rev() {
1969                    self.fat.write_fat_entry(cluster, FatEntry::Free);
1970                }
1971
1972                // mark the current cluster as last
1973                self.fat.write_fat_entry(last_cluster, FatEntry::EndOfChain);
1974            } else {
1975                // adding new clusters
1976
1977                let to_add = new_size_in_clusters - current_size_in_clusters;
1978
1979                for _ in 0..to_add {
1980                    let new_cluster = self
1981                        .fat
1982                        .find_free_cluster()
1983                        .ok_or(FatError::NotEnoughSpace)?;
1984
1985                    self.fat
1986                        .write_fat_entry(last_cluster, FatEntry::Next(new_cluster));
1987                    // reserve
1988                    self.fat.write_fat_entry(new_cluster, FatEntry::EndOfChain);
1989
1990                    last_cluster = new_cluster;
1991                }
1992            }
1993        }
1994
1995        inode.set_size(size);
1996
1997        Ok(())
1998    }
1999}
2000
2001impl FileSystem for Mutex<FatFilesystem> {
2002    fn open_root(&self) -> Result<DirectoryNode, FileSystemError> {
2003        self.lock().open_root_dir_inode()
2004    }
2005
2006    fn read_dir(
2007        &self,
2008        inode: &DirectoryNode,
2009        handler: &mut dyn FnMut(Node) -> DirTraverse,
2010    ) -> Result<(), FileSystemError> {
2011        for node in self.lock().open_dir_inode(inode)? {
2012            if let DirTraverse::Stop = handler(node.into()) {
2013                break;
2014            }
2015        }
2016
2017        Ok(())
2018    }
2019
2020    fn traverse_dir(&self, inode: &DirectoryNode, matcher: &str) -> Result<Node, FileSystemError> {
2021        for node in self.lock().open_dir_inode(inode)? {
2022            if node.matches(matcher) {
2023                return Ok(node.into());
2024            }
2025        }
2026
2027        Err(FileSystemError::FileNotFound)
2028    }
2029
2030    fn create_node(
2031        &self,
2032        parent: &DirectoryNode,
2033        name: &str,
2034        attributes: FileAttributes,
2035    ) -> Result<Node, FileSystemError> {
2036        self.lock().add_directory_entry(parent, name, attributes)
2037    }
2038
2039    fn read_file(
2040        &self,
2041        inode: &FileNode,
2042        position: u64,
2043        buf: &mut [u8],
2044        access_helper: &mut AccessHelper,
2045    ) -> Result<u64, FileSystemError> {
2046        assert!(position <= u32::MAX as u64);
2047        self.lock().read_write_file(
2048            inode,
2049            position as u32,
2050            FileAccessBuffer::Read(buf),
2051            access_helper,
2052        )
2053    }
2054
2055    fn write_file(
2056        &self,
2057        inode: &mut FileNode,
2058        position: u64,
2059        buf: &[u8],
2060        access_helper: &mut AccessHelper,
2061    ) -> Result<u64, FileSystemError> {
2062        assert!(position <= u32::MAX as u64);
2063
2064        let mut s = self.lock();
2065
2066        let current_size = inode.size();
2067        let new_size = position + buf.len() as u64;
2068
2069        if new_size > current_size {
2070            s.set_file_size(inode, new_size)
2071                .map_err(|_| FileSystemError::CouldNotSetFileLength)?;
2072        }
2073
2074        // we seeked past the end of the file
2075        // extend to the position with zeros
2076        if position > current_size {
2077            let extend_size = position - current_size;
2078
2079            let zeros = vec![0; s.boot_sector.bytes_per_sector() as usize];
2080
2081            let mut written = 0;
2082            while written < extend_size {
2083                let to_write = zeros.len().min((extend_size - written) as usize);
2084                s.read_write_file(
2085                    inode,
2086                    (current_size + written) as u32,
2087                    FileAccessBuffer::Write(&zeros[..to_write]),
2088                    access_helper,
2089                )?;
2090                written += to_write as u64;
2091            }
2092        }
2093
2094        s.read_write_file(
2095            inode,
2096            position as u32,
2097            FileAccessBuffer::Write(buf),
2098            access_helper,
2099        )
2100    }
2101
2102    fn flush_file(
2103        &self,
2104        inode: &mut FileNode,
2105        access_helper: &mut AccessHelper,
2106    ) -> Result<(), FileSystemError> {
2107        self.lock()
2108            .flush_cluster(inode, access_helper.current_cluster as u32)
2109    }
2110
2111    fn close_file(
2112        &self,
2113        inode: &FileNode,
2114        access_helper: AccessHelper,
2115    ) -> Result<(), FileSystemError> {
2116        self.lock()
2117            .release_cluster(inode, access_helper.current_cluster as u32)
2118    }
2119
2120    fn set_file_size(&self, inode: &mut FileNode, size: u64) -> Result<(), FileSystemError> {
2121        let mut s = self.lock();
2122
2123        s.set_file_size(inode, size)?;
2124        s.flush_fat()?;
2125        s.update_directory_entry(inode, |entry| {
2126            entry.file_size = inode.size() as u32;
2127        })?;
2128
2129        Ok(())
2130    }
2131
2132    fn unmount(self: Arc<Self>) {
2133        let mut s = self.lock();
2134        s.flush_fat().expect("flush fat");
2135
2136        for cluster in s.cluster_cache.release_all().into_values() {
2137            if let Some(dirty_range) = cluster.dirty_range {
2138                s.flush_cluster_dirty_range(&cluster.data, cluster.cluster, dirty_range)
2139                    .expect("flush cluster dirty range");
2140            }
2141        }
2142    }
2143}