1use byteorder::{ByteOrder, LittleEndian};
6use core::convert::TryFrom;
7
8use crate::fat::{self, BlockCache, OnDiskDirEntry, RESERVED_ENTRIES};
9
10use crate::filesystem::{
11    Attributes, ClusterId, DirEntry, DirectoryInfo, FileInfo, Mode, RawDirectory, RawFile,
12    SearchIdGenerator, TimeSource, ToShortFileName, MAX_FILE_SIZE,
13};
14use crate::{
15    debug, Block, BlockCount, BlockDevice, BlockIdx, Error, RawVolume, ShortFileName, Volume,
16    VolumeIdx, VolumeInfo, VolumeType, PARTITION_ID_FAT16, PARTITION_ID_FAT16_LBA,
17    PARTITION_ID_FAT32_CHS_LBA, PARTITION_ID_FAT32_LBA,
18};
19use heapless::Vec;
20
21#[derive(Debug)]
27pub struct VolumeManager<
28    D,
29    T,
30    const MAX_DIRS: usize = 4,
31    const MAX_FILES: usize = 4,
32    const MAX_VOLUMES: usize = 1,
33> where
34    D: BlockDevice,
35    T: TimeSource,
36    <D as BlockDevice>::Error: core::fmt::Debug,
37{
38    pub(crate) block_device: D,
39    pub(crate) time_source: T,
40    id_generator: SearchIdGenerator,
41    open_volumes: Vec<VolumeInfo, MAX_VOLUMES>,
42    open_dirs: Vec<DirectoryInfo, MAX_DIRS>,
43    open_files: Vec<FileInfo, MAX_FILES>,
44}
45
46impl<D, T> VolumeManager<D, T, 4, 4>
47where
48    D: BlockDevice,
49    T: TimeSource,
50    <D as BlockDevice>::Error: core::fmt::Debug,
51{
52    pub fn new(block_device: D, time_source: T) -> VolumeManager<D, T, 4, 4, 1> {
60        Self::new_with_limits(block_device, time_source, 5000)
63    }
64}
65
66impl<D, T, const MAX_DIRS: usize, const MAX_FILES: usize, const MAX_VOLUMES: usize>
67    VolumeManager<D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>
68where
69    D: BlockDevice,
70    T: TimeSource,
71    <D as BlockDevice>::Error: core::fmt::Debug,
72{
73    pub fn new_with_limits(
81        block_device: D,
82        time_source: T,
83        id_offset: u32,
84    ) -> VolumeManager<D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES> {
85        debug!("Creating new embedded-sdmmc::VolumeManager");
86        VolumeManager {
87            block_device,
88            time_source,
89            id_generator: SearchIdGenerator::new(id_offset),
90            open_volumes: Vec::new(),
91            open_dirs: Vec::new(),
92            open_files: Vec::new(),
93        }
94    }
95
96    pub fn device(&mut self) -> &mut D {
98        &mut self.block_device
99    }
100
101    pub fn open_volume(
106        &mut self,
107        volume_idx: VolumeIdx,
108    ) -> Result<Volume<D, T, MAX_DIRS, MAX_FILES, MAX_VOLUMES>, Error<D::Error>> {
109        let v = self.open_raw_volume(volume_idx)?;
110        Ok(v.to_volume(self))
111    }
112
113    pub fn open_raw_volume(&mut self, volume_idx: VolumeIdx) -> Result<RawVolume, Error<D::Error>> {
121        const PARTITION1_START: usize = 446;
122        const PARTITION2_START: usize = PARTITION1_START + PARTITION_INFO_LENGTH;
123        const PARTITION3_START: usize = PARTITION2_START + PARTITION_INFO_LENGTH;
124        const PARTITION4_START: usize = PARTITION3_START + PARTITION_INFO_LENGTH;
125        const FOOTER_START: usize = 510;
126        const FOOTER_VALUE: u16 = 0xAA55;
127        const PARTITION_INFO_LENGTH: usize = 16;
128        const PARTITION_INFO_STATUS_INDEX: usize = 0;
129        const PARTITION_INFO_TYPE_INDEX: usize = 4;
130        const PARTITION_INFO_LBA_START_INDEX: usize = 8;
131        const PARTITION_INFO_NUM_BLOCKS_INDEX: usize = 12;
132
133        if self.open_volumes.is_full() {
134            return Err(Error::TooManyOpenVolumes);
135        }
136
137        for v in self.open_volumes.iter() {
138            if v.idx == volume_idx {
139                return Err(Error::VolumeAlreadyOpen);
140            }
141        }
142
143        let (part_type, lba_start, num_blocks) = {
144            let mut blocks = [Block::new()];
145            self.block_device
146                .read(&mut blocks, BlockIdx(0), "read_mbr")
147                .map_err(Error::DeviceError)?;
148            let block = &blocks[0];
149            if LittleEndian::read_u16(&block[FOOTER_START..FOOTER_START + 2]) != FOOTER_VALUE {
152                return Err(Error::FormatError("Invalid MBR signature"));
153            }
154            let partition = match volume_idx {
155                VolumeIdx(0) => {
156                    &block[PARTITION1_START..(PARTITION1_START + PARTITION_INFO_LENGTH)]
157                }
158                VolumeIdx(1) => {
159                    &block[PARTITION2_START..(PARTITION2_START + PARTITION_INFO_LENGTH)]
160                }
161                VolumeIdx(2) => {
162                    &block[PARTITION3_START..(PARTITION3_START + PARTITION_INFO_LENGTH)]
163                }
164                VolumeIdx(3) => {
165                    &block[PARTITION4_START..(PARTITION4_START + PARTITION_INFO_LENGTH)]
166                }
167                _ => {
168                    return Err(Error::NoSuchVolume);
169                }
170            };
171            if (partition[PARTITION_INFO_STATUS_INDEX] & 0x7F) != 0x00 {
173                return Err(Error::FormatError("Invalid partition status"));
174            }
175            let lba_start = LittleEndian::read_u32(
176                &partition[PARTITION_INFO_LBA_START_INDEX..(PARTITION_INFO_LBA_START_INDEX + 4)],
177            );
178            let num_blocks = LittleEndian::read_u32(
179                &partition[PARTITION_INFO_NUM_BLOCKS_INDEX..(PARTITION_INFO_NUM_BLOCKS_INDEX + 4)],
180            );
181            (
182                partition[PARTITION_INFO_TYPE_INDEX],
183                BlockIdx(lba_start),
184                BlockCount(num_blocks),
185            )
186        };
187        match part_type {
188            PARTITION_ID_FAT32_CHS_LBA
189            | PARTITION_ID_FAT32_LBA
190            | PARTITION_ID_FAT16_LBA
191            | PARTITION_ID_FAT16 => {
192                let volume = fat::parse_volume(&self.block_device, lba_start, num_blocks)?;
193                let id = RawVolume(self.id_generator.get());
194                let info = VolumeInfo {
195                    volume_id: id,
196                    idx: volume_idx,
197                    volume_type: volume,
198                };
199                self.open_volumes.push(info).unwrap();
201                Ok(id)
202            }
203            _ => Err(Error::FormatError("Partition type not supported")),
204        }
205    }
206
207    pub fn open_root_dir(&mut self, volume: RawVolume) -> Result<RawDirectory, Error<D::Error>> {
212        let directory_id = RawDirectory(self.id_generator.get());
215        let dir_info = DirectoryInfo {
216            volume_id: volume,
217            cluster: ClusterId::ROOT_DIR,
218            directory_id,
219        };
220
221        self.open_dirs
222            .push(dir_info)
223            .map_err(|_| Error::TooManyOpenDirs)?;
224
225        Ok(directory_id)
226    }
227
228    pub fn open_dir<N>(
234        &mut self,
235        parent_dir: RawDirectory,
236        name: N,
237    ) -> Result<RawDirectory, Error<D::Error>>
238    where
239        N: ToShortFileName,
240    {
241        if self.open_dirs.is_full() {
242            return Err(Error::TooManyOpenDirs);
243        }
244
245        let parent_dir_idx = self.get_dir_by_id(parent_dir)?;
247        let volume_idx = self.get_volume_by_id(self.open_dirs[parent_dir_idx].volume_id)?;
248        let short_file_name = name.to_short_filename().map_err(Error::FilenameError)?;
249        let parent_dir_info = &self.open_dirs[parent_dir_idx];
250
251        if short_file_name == ShortFileName::this_dir() {
253            let directory_id = RawDirectory(self.id_generator.get());
255            let dir_info = DirectoryInfo {
256                directory_id,
257                volume_id: self.open_volumes[volume_idx].volume_id,
258                cluster: parent_dir_info.cluster,
259            };
260
261            self.open_dirs
262                .push(dir_info)
263                .map_err(|_| Error::TooManyOpenDirs)?;
264
265            return Ok(directory_id);
266        }
267
268        let dir_entry = match &self.open_volumes[volume_idx].volume_type {
269            VolumeType::Fat(fat) => {
270                fat.find_directory_entry(&self.block_device, parent_dir_info, &short_file_name)?
271            }
272        };
273
274        debug!("Found dir entry: {:?}", dir_entry);
275
276        if !dir_entry.attributes.is_directory() {
277            return Err(Error::OpenedFileAsDir);
278        }
279
280        let directory_id = RawDirectory(self.id_generator.get());
285        let dir_info = DirectoryInfo {
286            directory_id,
287            volume_id: self.open_volumes[volume_idx].volume_id,
288            cluster: dir_entry.cluster,
289        };
290
291        self.open_dirs
292            .push(dir_info)
293            .map_err(|_| Error::TooManyOpenDirs)?;
294
295        Ok(directory_id)
296    }
297
298    pub fn close_dir(&mut self, directory: RawDirectory) -> Result<(), Error<D::Error>> {
301        for (idx, info) in self.open_dirs.iter().enumerate() {
302            if directory == info.directory_id {
303                self.open_dirs.swap_remove(idx);
304                return Ok(());
305            }
306        }
307        Err(Error::BadHandle)
308    }
309
310    pub fn close_volume(&mut self, volume: RawVolume) -> Result<(), Error<D::Error>> {
314        for f in self.open_files.iter() {
315            if f.volume_id == volume {
316                return Err(Error::VolumeStillInUse);
317            }
318        }
319
320        for d in self.open_dirs.iter() {
321            if d.volume_id == volume {
322                return Err(Error::VolumeStillInUse);
323            }
324        }
325
326        let volume_idx = self.get_volume_by_id(volume)?;
327
328        match &mut self.open_volumes[volume_idx].volume_type {
329            VolumeType::Fat(fat_volume) => {
330                fat_volume.update_info_sector(&self.block_device)?;
331            }
332        }
333
334        self.open_volumes.swap_remove(volume_idx);
335
336        Ok(())
337    }
338
339    pub fn find_directory_entry<N>(
341        &mut self,
342        directory: RawDirectory,
343        name: N,
344    ) -> Result<DirEntry, Error<D::Error>>
345    where
346        N: ToShortFileName,
347    {
348        let directory_idx = self.get_dir_by_id(directory)?;
349        let volume_idx = self.get_volume_by_id(self.open_dirs[directory_idx].volume_id)?;
350        match &self.open_volumes[volume_idx].volume_type {
351            VolumeType::Fat(fat) => {
352                let sfn = name.to_short_filename().map_err(Error::FilenameError)?;
353                fat.find_directory_entry(&self.block_device, &self.open_dirs[directory_idx], &sfn)
354            }
355        }
356    }
357
358    pub fn iterate_dir<F>(
360        &mut self,
361        directory: RawDirectory,
362        func: F,
363    ) -> Result<(), Error<D::Error>>
364    where
365        F: FnMut(&DirEntry),
366    {
367        let directory_idx = self.get_dir_by_id(directory)?;
368        let volume_idx = self.get_volume_by_id(self.open_dirs[directory_idx].volume_id)?;
369        match &self.open_volumes[volume_idx].volume_type {
370            VolumeType::Fat(fat) => {
371                fat.iterate_dir(&self.block_device, &self.open_dirs[directory_idx], func)
372            }
373        }
374    }
375
376    unsafe fn open_dir_entry(
383        &mut self,
384        volume: RawVolume,
385        dir_entry: DirEntry,
386        mode: Mode,
387    ) -> Result<RawFile, Error<D::Error>> {
388        if self.open_files.is_full() {
390            return Err(Error::TooManyOpenFiles);
391        }
392
393        if dir_entry.attributes.is_read_only() && mode != Mode::ReadOnly {
394            return Err(Error::ReadOnly);
395        }
396
397        if dir_entry.attributes.is_directory() {
398            return Err(Error::OpenedDirAsFile);
399        }
400
401        if self.file_is_open(volume, &dir_entry) {
403            return Err(Error::FileAlreadyOpen);
404        }
405
406        let mode = solve_mode_variant(mode, true);
407        let file_id = RawFile(self.id_generator.get());
408
409        let file = match mode {
410            Mode::ReadOnly => FileInfo {
411                file_id,
412                volume_id: volume,
413                current_cluster: (0, dir_entry.cluster),
414                current_offset: 0,
415                mode,
416                entry: dir_entry,
417                dirty: false,
418            },
419            Mode::ReadWriteAppend => {
420                let mut file = FileInfo {
421                    file_id,
422                    volume_id: volume,
423                    current_cluster: (0, dir_entry.cluster),
424                    current_offset: 0,
425                    mode,
426                    entry: dir_entry,
427                    dirty: false,
428                };
429                file.seek_from_end(0).ok();
431                file
432            }
433            Mode::ReadWriteTruncate => {
434                let mut file = FileInfo {
435                    file_id,
436                    volume_id: volume,
437                    current_cluster: (0, dir_entry.cluster),
438                    current_offset: 0,
439                    mode,
440                    entry: dir_entry,
441                    dirty: false,
442                };
443                let volume_idx = self.get_volume_by_id(volume)?;
444                match &mut self.open_volumes[volume_idx].volume_type {
445                    VolumeType::Fat(fat) => {
446                        fat.truncate_cluster_chain(&self.block_device, file.entry.cluster)?
447                    }
448                };
449                file.update_length(0);
450                match &self.open_volumes[volume_idx].volume_type {
451                    VolumeType::Fat(fat) => {
452                        file.entry.mtime = self.time_source.get_timestamp();
453                        fat.write_entry_to_disk(&self.block_device, &file.entry)?;
454                    }
455                };
456
457                file
458            }
459            _ => return Err(Error::Unsupported),
460        };
461
462        unsafe {
464            self.open_files.push_unchecked(file);
465        }
466
467        Ok(file_id)
468    }
469
470    pub fn open_file_in_dir<N>(
472        &mut self,
473        directory: RawDirectory,
474        name: N,
475        mode: Mode,
476    ) -> Result<RawFile, Error<D::Error>>
477    where
478        N: ToShortFileName,
479    {
480        if self.open_files.is_full() {
482            return Err(Error::TooManyOpenFiles);
483        }
484
485        let directory_idx = self.get_dir_by_id(directory)?;
486        let directory_info = &self.open_dirs[directory_idx];
487        let volume_id = self.open_dirs[directory_idx].volume_id;
488        let volume_idx = self.get_volume_by_id(volume_id)?;
489        let volume_info = &self.open_volumes[volume_idx];
490        let sfn = name.to_short_filename().map_err(Error::FilenameError)?;
491
492        let dir_entry = match &volume_info.volume_type {
493            VolumeType::Fat(fat) => {
494                fat.find_directory_entry(&self.block_device, directory_info, &sfn)
495            }
496        };
497
498        let dir_entry = match dir_entry {
499            Ok(entry) => {
500                Some(entry)
502            }
503            Err(_)
504                if (mode == Mode::ReadWriteCreate)
505                    | (mode == Mode::ReadWriteCreateOrTruncate)
506                    | (mode == Mode::ReadWriteCreateOrAppend) =>
507            {
508                None
511            }
512            _ => {
513                return Err(Error::NotFound);
515            }
516        };
517
518        if let Some(dir_entry) = &dir_entry {
520            if self.file_is_open(volume_info.volume_id, dir_entry) {
521                return Err(Error::FileAlreadyOpen);
522            }
523        }
524
525        let mode = solve_mode_variant(mode, dir_entry.is_some());
526
527        match mode {
528            Mode::ReadWriteCreate => {
529                if dir_entry.is_some() {
530                    return Err(Error::FileAlreadyExists);
531                }
532                let att = Attributes::create_from_fat(0);
533                let volume_idx = self.get_volume_by_id(volume_id)?;
534                let entry = match &mut self.open_volumes[volume_idx].volume_type {
535                    VolumeType::Fat(fat) => fat.write_new_directory_entry(
536                        &self.block_device,
537                        &self.time_source,
538                        directory_info.cluster,
539                        sfn,
540                        att,
541                    )?,
542                };
543
544                let file_id = RawFile(self.id_generator.get());
545
546                let file = FileInfo {
547                    file_id,
548                    volume_id,
549                    current_cluster: (0, entry.cluster),
550                    current_offset: 0,
551                    mode,
552                    entry,
553                    dirty: false,
554                };
555
556                unsafe {
558                    self.open_files.push_unchecked(file);
559                }
560
561                Ok(file_id)
562            }
563            _ => {
564                let dir_entry = dir_entry.unwrap();
566                unsafe { self.open_dir_entry(volume_id, dir_entry, mode) }
568            }
569        }
570    }
571
572    pub fn delete_file_in_dir<N>(
574        &mut self,
575        directory: RawDirectory,
576        name: N,
577    ) -> Result<(), Error<D::Error>>
578    where
579        N: ToShortFileName,
580    {
581        let dir_idx = self.get_dir_by_id(directory)?;
582        let dir_info = &self.open_dirs[dir_idx];
583        let volume_idx = self.get_volume_by_id(dir_info.volume_id)?;
584        let sfn = name.to_short_filename().map_err(Error::FilenameError)?;
585
586        let dir_entry = match &self.open_volumes[volume_idx].volume_type {
587            VolumeType::Fat(fat) => fat.find_directory_entry(&self.block_device, dir_info, &sfn),
588        }?;
589
590        if dir_entry.attributes.is_directory() {
591            return Err(Error::DeleteDirAsFile);
592        }
593
594        if self.file_is_open(dir_info.volume_id, &dir_entry) {
595            return Err(Error::FileAlreadyOpen);
596        }
597
598        let volume_idx = self.get_volume_by_id(dir_info.volume_id)?;
599        match &self.open_volumes[volume_idx].volume_type {
600            VolumeType::Fat(fat) => {
601                fat.delete_directory_entry(&self.block_device, dir_info, &sfn)?
602            }
603        }
604
605        Ok(())
606    }
607
608    fn file_is_open(&self, volume: RawVolume, dir_entry: &DirEntry) -> bool {
612        for f in self.open_files.iter() {
613            if f.volume_id == volume
614                && f.entry.entry_block == dir_entry.entry_block
615                && f.entry.entry_offset == dir_entry.entry_offset
616            {
617                return true;
618            }
619        }
620        false
621    }
622
623    pub fn read(&mut self, file: RawFile, buffer: &mut [u8]) -> Result<usize, Error<D::Error>> {
625        let file_idx = self.get_file_by_id(file)?;
626        let volume_idx = self.get_volume_by_id(self.open_files[file_idx].volume_id)?;
627        let mut space = buffer.len();
631        let mut read = 0;
632        while space > 0 && !self.open_files[file_idx].eof() {
633            let mut current_cluster = self.open_files[file_idx].current_cluster;
634            let (block_idx, block_offset, block_avail) = self.find_data_on_disk(
635                volume_idx,
636                &mut current_cluster,
637                self.open_files[file_idx].entry.cluster,
638                self.open_files[file_idx].current_offset,
639            )?;
640            self.open_files[file_idx].current_cluster = current_cluster;
641            let mut blocks = [Block::new()];
642            self.block_device
643                .read(&mut blocks, block_idx, "read")
644                .map_err(Error::DeviceError)?;
645            let block = &blocks[0];
646            let to_copy = block_avail
647                .min(space)
648                .min(self.open_files[file_idx].left() as usize);
649            assert!(to_copy != 0);
650            buffer[read..read + to_copy]
651                .copy_from_slice(&block[block_offset..block_offset + to_copy]);
652            read += to_copy;
653            space -= to_copy;
654            self.open_files[file_idx]
655                .seek_from_current(to_copy as i32)
656                .unwrap();
657        }
658        Ok(read)
659    }
660
661    pub fn write(&mut self, file: RawFile, buffer: &[u8]) -> Result<(), Error<D::Error>> {
663        #[cfg(feature = "defmt-log")]
664        debug!("write(file={:?}, buffer={:x}", file, buffer);
665
666        #[cfg(feature = "log")]
667        debug!("write(file={:?}, buffer={:x?}", file, buffer);
668
669        let file_idx = self.get_file_by_id(file)?;
672        let volume_idx = self.get_volume_by_id(self.open_files[file_idx].volume_id)?;
673
674        if self.open_files[file_idx].mode == Mode::ReadOnly {
675            return Err(Error::ReadOnly);
676        }
677
678        self.open_files[file_idx].dirty = true;
679
680        if self.open_files[file_idx].entry.cluster.0 < RESERVED_ENTRIES {
681            self.open_files[file_idx].entry.cluster =
683                match self.open_volumes[volume_idx].volume_type {
684                    VolumeType::Fat(ref mut fat) => {
685                        fat.alloc_cluster(&self.block_device, None, false)?
686                    }
687                };
688            debug!(
689                "Alloc first cluster {:?}",
690                self.open_files[file_idx].entry.cluster
691            );
692        }
693
694        let volume_idx = self.get_volume_by_id(self.open_files[file_idx].volume_id)?;
696
697        if (self.open_files[file_idx].current_cluster.1) < self.open_files[file_idx].entry.cluster {
698            debug!("Rewinding to start");
699            self.open_files[file_idx].current_cluster =
700                (0, self.open_files[file_idx].entry.cluster);
701        }
702        let bytes_until_max =
703            usize::try_from(MAX_FILE_SIZE - self.open_files[file_idx].current_offset)
704                .map_err(|_| Error::ConversionError)?;
705        let bytes_to_write = core::cmp::min(buffer.len(), bytes_until_max);
706        let mut written = 0;
707
708        while written < bytes_to_write {
709            let mut current_cluster = self.open_files[file_idx].current_cluster;
710            debug!(
711                "Have written bytes {}/{}, finding cluster {:?}",
712                written, bytes_to_write, current_cluster
713            );
714            let current_offset = self.open_files[file_idx].current_offset;
715            let (block_idx, block_offset, block_avail) = match self.find_data_on_disk(
716                volume_idx,
717                &mut current_cluster,
718                self.open_files[file_idx].entry.cluster,
719                current_offset,
720            ) {
721                Ok(vars) => {
722                    debug!(
723                        "Found block_idx={:?}, block_offset={:?}, block_avail={}",
724                        vars.0, vars.1, vars.2
725                    );
726                    vars
727                }
728                Err(Error::EndOfFile) => {
729                    debug!("Extending file");
730                    match self.open_volumes[volume_idx].volume_type {
731                        VolumeType::Fat(ref mut fat) => {
732                            if fat
733                                .alloc_cluster(&self.block_device, Some(current_cluster.1), false)
734                                .is_err()
735                            {
736                                return Err(Error::DiskFull);
737                            }
738                            debug!("Allocated new FAT cluster, finding offsets...");
739                            let new_offset = self
740                                .find_data_on_disk(
741                                    volume_idx,
742                                    &mut current_cluster,
743                                    self.open_files[file_idx].entry.cluster,
744                                    self.open_files[file_idx].current_offset,
745                                )
746                                .map_err(|_| Error::AllocationError)?;
747                            debug!("New offset {:?}", new_offset);
748                            new_offset
749                        }
750                    }
751                }
752                Err(e) => return Err(e),
753            };
754            let mut blocks = [Block::new()];
755            let to_copy = core::cmp::min(block_avail, bytes_to_write - written);
756            if block_offset != 0 || to_copy != block_avail {
757                debug!("Partial block read/modify/write");
758                self.block_device
759                    .read(&mut blocks, block_idx, "read")
760                    .map_err(Error::DeviceError)?;
761            }
762            let block = &mut blocks[0];
763            block[block_offset..block_offset + to_copy]
764                .copy_from_slice(&buffer[written..written + to_copy]);
765            debug!("Writing block {:?}", block_idx);
766            self.block_device
767                .write(&blocks, block_idx)
768                .map_err(Error::DeviceError)?;
769            written += to_copy;
770            self.open_files[file_idx].current_cluster = current_cluster;
771
772            let to_copy = to_copy as u32;
773            let new_offset = self.open_files[file_idx].current_offset + to_copy;
774            if new_offset > self.open_files[file_idx].entry.size {
775                self.open_files[file_idx].update_length(new_offset);
777            }
778            self.open_files[file_idx]
779                .seek_from_start(new_offset)
780                .unwrap();
781            }
783        self.open_files[file_idx].entry.attributes.set_archive(true);
784        self.open_files[file_idx].entry.mtime = self.time_source.get_timestamp();
785        Ok(())
786    }
787
788    pub fn close_file(&mut self, file: RawFile) -> Result<(), Error<D::Error>> {
790        let flush_result = self.flush_file(file);
791        let file_idx = self.get_file_by_id(file)?;
792        self.open_files.swap_remove(file_idx);
793        flush_result
794    }
795
796    pub fn flush_file(&mut self, file: RawFile) -> Result<(), Error<D::Error>> {
798        let file_info = self
799            .open_files
800            .iter()
801            .find(|info| info.file_id == file)
802            .ok_or(Error::BadHandle)?;
803
804        if file_info.dirty {
805            let volume_idx = self.get_volume_by_id(file_info.volume_id)?;
806            match self.open_volumes[volume_idx].volume_type {
807                VolumeType::Fat(ref mut fat) => {
808                    debug!("Updating FAT info sector");
809                    fat.update_info_sector(&self.block_device)?;
810                    debug!("Updating dir entry {:?}", file_info.entry);
811                    if file_info.entry.size != 0 {
812                        assert!(file_info.entry.cluster.0 != 0);
814                    }
815                    fat.write_entry_to_disk(&self.block_device, &file_info.entry)?;
816                }
817            };
818        }
819        Ok(())
820    }
821
822    pub fn has_open_handles(&self) -> bool {
824        !(self.open_dirs.is_empty() || self.open_files.is_empty())
825    }
826
827    pub fn free(self) -> (D, T) {
829        (self.block_device, self.time_source)
830    }
831
832    pub fn file_eof(&self, file: RawFile) -> Result<bool, Error<D::Error>> {
834        let file_idx = self.get_file_by_id(file)?;
835        Ok(self.open_files[file_idx].eof())
836    }
837
838    pub fn file_seek_from_start(
840        &mut self,
841        file: RawFile,
842        offset: u32,
843    ) -> Result<(), Error<D::Error>> {
844        let file_idx = self.get_file_by_id(file)?;
845        self.open_files[file_idx]
846            .seek_from_start(offset)
847            .map_err(|_| Error::InvalidOffset)?;
848        Ok(())
849    }
850
851    pub fn file_seek_from_current(
853        &mut self,
854        file: RawFile,
855        offset: i32,
856    ) -> Result<(), Error<D::Error>> {
857        let file_idx = self.get_file_by_id(file)?;
858        self.open_files[file_idx]
859            .seek_from_current(offset)
860            .map_err(|_| Error::InvalidOffset)?;
861        Ok(())
862    }
863
864    pub fn file_seek_from_end(
866        &mut self,
867        file: RawFile,
868        offset: u32,
869    ) -> Result<(), Error<D::Error>> {
870        let file_idx = self.get_file_by_id(file)?;
871        self.open_files[file_idx]
872            .seek_from_end(offset)
873            .map_err(|_| Error::InvalidOffset)?;
874        Ok(())
875    }
876
877    pub fn file_length(&self, file: RawFile) -> Result<u32, Error<D::Error>> {
879        let file_idx = self.get_file_by_id(file)?;
880        Ok(self.open_files[file_idx].length())
881    }
882
883    pub fn file_offset(&self, file: RawFile) -> Result<u32, Error<D::Error>> {
885        let file_idx = self.get_file_by_id(file)?;
886        Ok(self.open_files[file_idx].current_offset)
887    }
888
889    pub fn make_dir_in_dir<N>(
891        &mut self,
892        directory: RawDirectory,
893        name: N,
894    ) -> Result<(), Error<D::Error>>
895    where
896        N: ToShortFileName,
897    {
898        if self.open_dirs.is_full() {
900            return Err(Error::TooManyOpenDirs);
901        }
902
903        let parent_directory_idx = self.get_dir_by_id(directory)?;
904        let parent_directory_info = &self.open_dirs[parent_directory_idx];
905        let volume_id = self.open_dirs[parent_directory_idx].volume_id;
906        let volume_idx = self.get_volume_by_id(volume_id)?;
907        let volume_info = &self.open_volumes[volume_idx];
908        let sfn = name.to_short_filename().map_err(Error::FilenameError)?;
909
910        debug!("Creating directory '{}'", sfn);
911        debug!(
912            "Parent dir is in cluster {:?}",
913            parent_directory_info.cluster
914        );
915
916        let maybe_dir_entry = match &volume_info.volume_type {
918            VolumeType::Fat(fat) => {
919                fat.find_directory_entry(&self.block_device, parent_directory_info, &sfn)
920            }
921        };
922
923        match maybe_dir_entry {
924            Ok(entry) if entry.attributes.is_directory() => {
925                return Err(Error::DirAlreadyExists);
926            }
927            Ok(_entry) => {
928                return Err(Error::FileAlreadyExists);
929            }
930            Err(Error::NotFound) => {
931                }
933            Err(e) => {
934                return Err(e);
936            }
937        };
938
939        let att = Attributes::create_from_fat(Attributes::DIRECTORY);
940
941        match &mut self.open_volumes[volume_idx].volume_type {
943            VolumeType::Fat(fat) => {
944                debug!("Making dir entry");
945                let mut new_dir_entry_in_parent = fat.write_new_directory_entry(
946                    &self.block_device,
947                    &self.time_source,
948                    parent_directory_info.cluster,
949                    sfn,
950                    att,
951                )?;
952                if new_dir_entry_in_parent.cluster == ClusterId::EMPTY {
953                    new_dir_entry_in_parent.cluster =
954                        fat.alloc_cluster(&self.block_device, None, false)?;
955                    fat.write_entry_to_disk(&self.block_device, &new_dir_entry_in_parent)?;
957                }
958                let new_dir_start_block = fat.cluster_to_block(new_dir_entry_in_parent.cluster);
959                debug!("Made new dir entry {:?}", new_dir_entry_in_parent);
960                let now = self.time_source.get_timestamp();
961                let fat_type = fat.get_fat_type();
962                let mut blocks = [Block::new()];
964                let dot_entry_in_child = DirEntry {
966                    name: crate::ShortFileName::this_dir(),
967                    mtime: now,
968                    ctime: now,
969                    attributes: att,
970                    cluster: new_dir_entry_in_parent.cluster,
972                    size: 0,
973                    entry_block: new_dir_start_block,
974                    entry_offset: 0,
975                };
976                debug!("New dir has {:?}", dot_entry_in_child);
977                let mut offset = 0;
978                blocks[0][offset..offset + OnDiskDirEntry::LEN]
979                    .copy_from_slice(&dot_entry_in_child.serialize(fat_type)[..]);
980                offset += OnDiskDirEntry::LEN;
981                let dot_dot_entry_in_child = DirEntry {
983                    name: crate::ShortFileName::parent_dir(),
984                    mtime: now,
985                    ctime: now,
986                    attributes: att,
987                    cluster: {
989                        if parent_directory_info.cluster == ClusterId::ROOT_DIR {
991                            ClusterId::EMPTY
992                        } else {
993                            parent_directory_info.cluster
994                        }
995                    },
996                    size: 0,
997                    entry_block: new_dir_start_block,
998                    entry_offset: OnDiskDirEntry::LEN_U32,
999                };
1000                debug!("New dir has {:?}", dot_dot_entry_in_child);
1001                blocks[0][offset..offset + OnDiskDirEntry::LEN]
1002                    .copy_from_slice(&dot_dot_entry_in_child.serialize(fat_type)[..]);
1003
1004                self.block_device
1005                    .write(&blocks, new_dir_start_block)
1006                    .map_err(Error::DeviceError)?;
1007
1008                for b in blocks[0].iter_mut() {
1010                    *b = 0;
1011                }
1012                for block in new_dir_start_block
1013                    .range(BlockCount(u32::from(fat.blocks_per_cluster)))
1014                    .skip(1)
1015                {
1016                    self.block_device
1017                        .write(&blocks, block)
1018                        .map_err(Error::DeviceError)?;
1019                }
1020            }
1021        };
1022
1023        Ok(())
1024    }
1025
1026    fn get_volume_by_id(&self, volume: RawVolume) -> Result<usize, Error<D::Error>> {
1027        for (idx, v) in self.open_volumes.iter().enumerate() {
1028            if v.volume_id == volume {
1029                return Ok(idx);
1030            }
1031        }
1032        Err(Error::BadHandle)
1033    }
1034
1035    fn get_dir_by_id(&self, directory: RawDirectory) -> Result<usize, Error<D::Error>> {
1036        for (idx, d) in self.open_dirs.iter().enumerate() {
1037            if d.directory_id == directory {
1038                return Ok(idx);
1039            }
1040        }
1041        Err(Error::BadHandle)
1042    }
1043
1044    fn get_file_by_id(&self, file: RawFile) -> Result<usize, Error<D::Error>> {
1045        for (idx, f) in self.open_files.iter().enumerate() {
1046            if f.file_id == file {
1047                return Ok(idx);
1048            }
1049        }
1050        Err(Error::BadHandle)
1051    }
1052
1053    fn find_data_on_disk(
1063        &self,
1064        volume_idx: usize,
1065        start: &mut (u32, ClusterId),
1066        file_start: ClusterId,
1067        desired_offset: u32,
1068    ) -> Result<(BlockIdx, usize, usize), Error<D::Error>> {
1069        let bytes_per_cluster = match &self.open_volumes[volume_idx].volume_type {
1070            VolumeType::Fat(fat) => fat.bytes_per_cluster(),
1071        };
1072        if desired_offset < start.0 {
1074            start.0 = 0;
1077            start.1 = file_start;
1078        }
1079        let offset_from_cluster = desired_offset - start.0;
1081        let num_clusters = offset_from_cluster / bytes_per_cluster;
1083        let mut block_cache = BlockCache::empty();
1084        for _ in 0..num_clusters {
1085            start.1 = match &self.open_volumes[volume_idx].volume_type {
1086                VolumeType::Fat(fat) => {
1087                    fat.next_cluster(&self.block_device, start.1, &mut block_cache)?
1088                }
1089            };
1090            start.0 += bytes_per_cluster;
1091        }
1092        let offset_from_cluster = desired_offset - start.0;
1094        assert!(offset_from_cluster < bytes_per_cluster);
1095        let num_blocks = BlockCount(offset_from_cluster / Block::LEN_U32);
1096        let block_idx = match &self.open_volumes[volume_idx].volume_type {
1097            VolumeType::Fat(fat) => fat.cluster_to_block(start.1),
1098        } + num_blocks;
1099        let block_offset = (desired_offset % Block::LEN_U32) as usize;
1100        let available = Block::LEN - block_offset;
1101        Ok((block_idx, block_offset, available))
1102    }
1103}
1104
1105fn solve_mode_variant(mode: Mode, dir_entry_is_some: bool) -> Mode {
1108    let mut mode = mode;
1109    if mode == Mode::ReadWriteCreateOrAppend {
1110        if dir_entry_is_some {
1111            mode = Mode::ReadWriteAppend;
1112        } else {
1113            mode = Mode::ReadWriteCreate;
1114        }
1115    } else if mode == Mode::ReadWriteCreateOrTruncate {
1116        if dir_entry_is_some {
1117            mode = Mode::ReadWriteTruncate;
1118        } else {
1119            mode = Mode::ReadWriteCreate;
1120        }
1121    }
1122    mode
1123}
1124
1125#[cfg(test)]
1132mod tests {
1133    use super::*;
1134    use crate::filesystem::SearchId;
1135    use crate::Timestamp;
1136
1137    struct DummyBlockDevice;
1138
1139    struct Clock;
1140
1141    #[derive(Debug)]
1142    enum Error {
1143        Unknown,
1144    }
1145
1146    impl TimeSource for Clock {
1147        fn get_timestamp(&self) -> Timestamp {
1148            Timestamp {
1150                year_since_1970: 0,
1151                zero_indexed_month: 0,
1152                zero_indexed_day: 0,
1153                hours: 0,
1154                minutes: 0,
1155                seconds: 0,
1156            }
1157        }
1158    }
1159
1160    impl BlockDevice for DummyBlockDevice {
1161        type Error = Error;
1162
1163        fn read(
1165            &self,
1166            blocks: &mut [Block],
1167            start_block_idx: BlockIdx,
1168            _reason: &str,
1169        ) -> Result<(), Self::Error> {
1170            static BLOCKS: [Block; 3] = [
1172                Block {
1173                    contents: [
1174                        0xfa, 0xb8, 0x00, 0x10, 0x8e, 0xd0, 0xbc, 0x00, 0xb0, 0xb8, 0x00, 0x00,
1175                        0x8e, 0xd8, 0x8e, 0xc0, 0xfb, 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x06, 0xb9, 0x00, 0x02, 0xf3, 0xa4,
1177                        0xea, 0x21, 0x06, 0x00, 0x00, 0xbe, 0xbe, 0x07, 0x38, 0x04, 0x75, 0x0b, 0x83, 0xc6, 0x10, 0x81,
1179                        0xfe, 0xfe, 0x07, 0x75, 0xf3, 0xeb, 0x16, 0xb4, 0x02, 0xb0, 0x01, 0xbb, 0x00, 0x7c, 0xb2, 0x80,
1181                        0x8a, 0x74, 0x01, 0x8b, 0x4c, 0x02, 0xcd, 0x13, 0xea, 0x00, 0x7c, 0x00, 0x00, 0xeb, 0xfe, 0x00,
1183                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1185                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1187                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1189                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1191                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1193                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1195                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1197                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1199                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1201                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1203                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1205                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1207                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1209                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1211                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1213                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1215                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1217                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1219                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1221                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1223                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1225                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1227                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0xca, 0xde, 0x06,
1229                        0x00, 0x00, 0x00, 0x04, 0x01, 0x04, 0x0c, 0xfe, 0xc2, 0xff, 0x01, 0x00, 0x00, 0x00, 0x33, 0x22,
1231                        0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1233                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1235                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1237                        0x00, 0x00, 0x55, 0xaa, ],
1239                },
1240                Block {
1241                    contents: [
1242                        0xeb, 0x58, 0x90, 0x6d, 0x6b, 0x66, 0x73, 0x2e, 0x66, 0x61, 0x74, 0x00,
1243                        0x02, 0x08, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x10, 0x00, 0x04, 0x00,
1245                        0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x76, 0x00, 0x80, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1247                        0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1249                        0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x29, 0x0b, 0xa8, 0x89, 0x27, 0x50, 0x69, 0x63, 0x74, 0x75,
1251                        0x72, 0x65, 0x73, 0x20, 0x20, 0x20, 0x46, 0x41, 0x54, 0x33, 0x32, 0x20, 0x20, 0x20, 0x0e, 0x1f,
1253                        0xbe, 0x77, 0x7c, 0xac, 0x22, 0xc0, 0x74, 0x0b, 0x56, 0xb4, 0x0e, 0xbb, 0x07, 0x00, 0xcd, 0x10,
1255                        0x5e, 0xeb, 0xf0, 0x32, 0xe4, 0xcd, 0x16, 0xcd, 0x19, 0xeb, 0xfe, 0x54, 0x68, 0x69, 0x73, 0x20,
1257                        0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c,
1259                        0x65, 0x20, 0x64, 0x69, 0x73, 0x6b, 0x2e, 0x20, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20,
1261                        0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x61, 0x62, 0x6c,
1263                        0x65, 0x20, 0x66, 0x6c, 0x6f, 0x70, 0x70, 0x79, 0x20, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x70, 0x72,
1265                        0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74,
1267                        0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6e, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x0d, 0x0a, 0x00,
1269                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1271                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1273                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1275                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1277                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1279                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1281                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1283                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1285                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1287                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1289                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1291                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1293                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1295                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1297                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1299                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1301                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1303                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1305                        0x00, 0x00, 0x55, 0xaa, ],
1307                },
1308                Block {
1309                    contents: hex!(
1310                        "52 52 61 41 00 00 00 00 00 00 00 00 00 00 00 00
1311                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1312                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1313                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1314                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1315                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1316                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1317                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1318                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1319                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1320                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1321                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1322                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1323                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1324                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1325                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1326                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1327                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1328                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1329                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1330                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1331                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1332                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1333                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1334                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1335                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1336                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1337                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1338                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1339                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1340                         00 00 00 00 72 72 41 61 FF FF FF FF FF FF FF FF
1341                         00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA"
1342                    ),
1343                },
1344            ];
1345            println!(
1346                "Reading block {} to {}",
1347                start_block_idx.0,
1348                start_block_idx.0 as usize + blocks.len()
1349            );
1350            for (idx, block) in blocks.iter_mut().enumerate() {
1351                let block_idx = start_block_idx.0 as usize + idx;
1352                if block_idx < BLOCKS.len() {
1353                    *block = BLOCKS[block_idx].clone();
1354                } else {
1355                    return Err(Error::Unknown);
1356                }
1357            }
1358            Ok(())
1359        }
1360
1361        fn write(&self, _blocks: &[Block], _start_block_idx: BlockIdx) -> Result<(), Self::Error> {
1363            unimplemented!();
1364        }
1365
1366        fn num_blocks(&self) -> Result<BlockCount, Self::Error> {
1368            Ok(BlockCount(2))
1369        }
1370    }
1371
1372    #[test]
1373    fn partition0() {
1374        let mut c: VolumeManager<DummyBlockDevice, Clock, 2, 2> =
1375            VolumeManager::new_with_limits(DummyBlockDevice, Clock, 0xAA00_0000);
1376
1377        let v = c.open_raw_volume(VolumeIdx(0)).unwrap();
1378        let expected_id = RawVolume(SearchId(0xAA00_0000));
1379        assert_eq!(v, expected_id);
1380        assert_eq!(
1381            &c.open_volumes[0],
1382            &VolumeInfo {
1383                volume_id: expected_id,
1384                idx: VolumeIdx(0),
1385                volume_type: VolumeType::Fat(crate::FatVolume {
1386                    lba_start: BlockIdx(1),
1387                    num_blocks: BlockCount(0x0011_2233),
1388                    blocks_per_cluster: 8,
1389                    first_data_block: BlockCount(15136),
1390                    fat_start: BlockCount(32),
1391                    second_fat_start: Some(BlockCount(32 + 0x0000_1D80)),
1392                    name: fat::VolumeName::new(*b"Pictures   "),
1393                    free_clusters_count: None,
1394                    next_free_cluster: None,
1395                    cluster_count: 965_788,
1396                    fat_specific_info: fat::FatSpecificInfo::Fat32(fat::Fat32Info {
1397                        first_root_dir_cluster: ClusterId(2),
1398                        info_location: BlockIdx(1) + BlockCount(1),
1399                    })
1400                })
1401            }
1402        );
1403    }
1404}
1405
1406