Properly initialize file allocation table when formatting a volume

This commit is contained in:
Rafał Harabień 2018-12-04 00:06:41 +01:00 committed by Rafał
parent 447c9dda35
commit b9753248f7
4 changed files with 189 additions and 79 deletions

View File

@ -11,7 +11,7 @@ use dir_entry::{DirEntry, DirEntryData, DirFileEntryData, DirLfnEntryData, FileA
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use dir_entry::{LFN_ENTRY_LAST_FLAG, LFN_PART_LEN}; use dir_entry::{LFN_ENTRY_LAST_FLAG, LFN_PART_LEN};
use file::File; use file::File;
use fs::{DiskSlice, FileSystem, ReadWriteSeek}; use fs::{DiskSlice, FsIoAdapter, FileSystem, ReadWriteSeek};
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
type LfnUtf16 = Vec<u16>; type LfnUtf16 = Vec<u16>;
@ -20,7 +20,7 @@ type LfnUtf16 = ();
pub(crate) enum DirRawStream<'a, T: ReadWriteSeek + 'a> { pub(crate) enum DirRawStream<'a, T: ReadWriteSeek + 'a> {
File(File<'a, T>), File(File<'a, T>),
Root(DiskSlice<'a, T>), Root(DiskSlice<FsIoAdapter<'a, T>>),
} }
impl<'a, T: ReadWriteSeek> DirRawStream<'a, T> { impl<'a, T: ReadWriteSeek> DirRawStream<'a, T> {

135
src/fs.rs
View File

@ -788,7 +788,8 @@ impl<T: ReadWriteSeek> FileSystem<T> {
self.first_data_sector - self.root_dir_sectors, self.first_data_sector - self.root_dir_sectors,
self.root_dir_sectors, self.root_dir_sectors,
1, 1,
self, &self.bpb,
FsIoAdapter { fs: self },
)), )),
_ => DirRawStream::File(File::new(Some(self.bpb.root_dir_first_cluster), None, self)), _ => DirRawStream::File(File::new(Some(self.bpb.root_dir_first_cluster), None, self)),
} }
@ -812,20 +813,14 @@ impl<T: ReadWriteSeek> FileSystem<T> {
self.offset_from_sector(self.sector_from_cluster(cluser)) self.offset_from_sector(self.sector_from_cluster(cluser))
} }
fn fat_slice<'b>(&'b self) -> DiskSlice<'b, T> { fn fat_slice<'b>(&'b self) -> DiskSlice<FsIoAdapter<'b, T>> {
let sectors_per_fat = self.bpb.sectors_per_fat(); let io = FsIoAdapter {
let mirroring_enabled = self.bpb.mirroring_enabled(); fs: self,
let (fat_first_sector, mirrors) = if mirroring_enabled {
(self.bpb.reserved_sectors as u32, self.bpb.fats)
} else {
let active_fat = self.bpb.active_fat() as u32;
let fat_first_sector = (self.bpb.reserved_sectors as u32) + active_fat * sectors_per_fat;
(fat_first_sector, 1)
}; };
DiskSlice::from_sectors(fat_first_sector, sectors_per_fat, mirrors, self) fat_slice(io, &self.bpb)
} }
pub(crate) fn cluster_iter<'b>(&'b self, cluster: u32) -> ClusterIterator<DiskSlice<'b, T>> { pub(crate) fn cluster_iter<'b>(&'b self, cluster: u32) -> ClusterIterator<DiskSlice<FsIoAdapter<'b, T>>> {
let disk_slice = self.fat_slice(); let disk_slice = self.fat_slice();
ClusterIterator::new(disk_slice, self.fat_type, cluster) ClusterIterator::new(disk_slice, self.fat_type, cluster)
} }
@ -946,32 +941,84 @@ impl<T: ReadWriteSeek> Drop for FileSystem<T> {
} }
} }
pub(crate) struct DiskSlice<'a, T: ReadWriteSeek + 'a> { pub(crate) struct FsIoAdapter<'a, T: ReadWriteSeek + 'a> {
fs: &'a FileSystem<T>,
}
impl<'a, T: ReadWriteSeek> Read for FsIoAdapter<'a, T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.fs.disk.borrow_mut().read(buf)
}
}
impl<'a, T: ReadWriteSeek> Write for FsIoAdapter<'a, T> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let size = self.fs.disk.borrow_mut().write(buf)?;
if size > 0 {
self.fs.set_dirty_flag(true)?;
}
Ok(size)
}
fn flush(&mut self) -> io::Result<()> {
self.fs.disk.borrow_mut().flush()
}
}
impl<'a, T: ReadWriteSeek> Seek for FsIoAdapter<'a, T> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
self.fs.disk.borrow_mut().seek(pos)
}
}
// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925
impl<'a, T: ReadWriteSeek> Clone for FsIoAdapter<'a, T> {
fn clone(&self) -> Self {
FsIoAdapter {
fs: self.fs,
}
}
}
fn fat_slice<T: ReadWriteSeek>(io: T, bpb: &BiosParameterBlock) -> DiskSlice<T> {
let sectors_per_fat = bpb.sectors_per_fat();
let mirroring_enabled = bpb.mirroring_enabled();
let (fat_first_sector, mirrors) = if mirroring_enabled {
(bpb.reserved_sectors as u32, bpb.fats)
} else {
let active_fat = bpb.active_fat() as u32;
let fat_first_sector = (bpb.reserved_sectors as u32) + active_fat * sectors_per_fat;
(fat_first_sector, 1)
};
DiskSlice::from_sectors(fat_first_sector, sectors_per_fat, mirrors, bpb, io)
}
pub(crate) struct DiskSlice<T> {
begin: u64, begin: u64,
size: u64, size: u64,
offset: u64, offset: u64,
mirrors: u8, mirrors: u8,
fs: &'a FileSystem<T>, inner: T,
} }
impl<'a, T: ReadWriteSeek> DiskSlice<'a, T> { impl<T> DiskSlice<T> {
pub(crate) fn new(begin: u64, size: u64, mirrors: u8, fs: &'a FileSystem<T>) -> Self { pub(crate) fn new(begin: u64, size: u64, mirrors: u8, inner: T) -> Self {
DiskSlice { DiskSlice {
begin, begin,
size, size,
mirrors, mirrors,
fs, inner,
offset: 0, offset: 0,
} }
} }
pub(crate) fn from_sectors(first_sector: u32, sector_count: u32, mirrors: u8, fs: &'a FileSystem<T>) -> Self { fn from_sectors(first_sector: u32, sector_count: u32, mirrors: u8, bpb: &BiosParameterBlock, inner: T) -> Self {
let bytes_per_sector = fs.bpb.bytes_per_sector as u64; let bytes_per_sector = bpb.bytes_per_sector as u64;
Self::new( Self::new(
first_sector as u64 * bytes_per_sector, first_sector as u64 * bytes_per_sector,
sector_count as u64 * bytes_per_sector, sector_count as u64 * bytes_per_sector,
mirrors, mirrors,
fs, inner,
) )
} }
@ -981,56 +1028,51 @@ impl<'a, T: ReadWriteSeek> DiskSlice<'a, T> {
} }
// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925 // Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925
impl<'a, T: ReadWriteSeek> Clone for DiskSlice<'a, T> { impl<T: Clone> Clone for DiskSlice<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
DiskSlice { DiskSlice {
begin: self.begin, begin: self.begin,
size: self.size, size: self.size,
offset: self.offset, offset: self.offset,
mirrors: self.mirrors, mirrors: self.mirrors,
fs: self.fs, inner: self.inner.clone(),
} }
} }
} }
impl<'a, T: ReadWriteSeek> Read for DiskSlice<'a, T> { impl<'a, T: Read + Seek> Read for DiskSlice<T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let offset = self.begin + self.offset; let offset = self.begin + self.offset;
let read_size = cmp::min((self.size - self.offset) as usize, buf.len()); let read_size = cmp::min((self.size - self.offset) as usize, buf.len());
let mut disk = self.fs.disk.borrow_mut(); self.inner.seek(SeekFrom::Start(offset))?;
disk.seek(SeekFrom::Start(offset))?; let size = self.inner.read(&mut buf[..read_size])?;
let size = disk.read(&mut buf[..read_size])?;
self.offset += size as u64; self.offset += size as u64;
Ok(size) Ok(size)
} }
} }
impl<'a, T: ReadWriteSeek> Write for DiskSlice<'a, T> { impl<'a, T: Write + Seek> Write for DiskSlice<T> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let offset = self.begin + self.offset; let offset = self.begin + self.offset;
let write_size = cmp::min((self.size - self.offset) as usize, buf.len()); let write_size = cmp::min((self.size - self.offset) as usize, buf.len());
if write_size == 0 { if write_size == 0 {
return Ok(0); return Ok(0);
} }
// Mark the volume 'dirty'
self.fs.set_dirty_flag(true)?;
// Write data // Write data
let mut disk = self.fs.disk.borrow_mut();
for i in 0..self.mirrors { for i in 0..self.mirrors {
disk.seek(SeekFrom::Start(offset + i as u64 * self.size))?; self.inner.seek(SeekFrom::Start(offset + i as u64 * self.size))?;
disk.write_all(&buf[..write_size])?; self.inner.write_all(&buf[..write_size])?;
} }
self.offset += write_size as u64; self.offset += write_size as u64;
Ok(write_size) Ok(write_size)
} }
fn flush(&mut self) -> io::Result<()> { fn flush(&mut self) -> io::Result<()> {
let mut disk = self.fs.disk.borrow_mut(); self.inner.flush()
disk.flush()
} }
} }
impl<'a, T: ReadWriteSeek> Seek for DiskSlice<'a, T> { impl<'a, T> Seek for DiskSlice<T> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let new_offset = match pos { let new_offset = match pos {
SeekFrom::Current(x) => self.offset as i64 + x, SeekFrom::Current(x) => self.offset as i64 + x,
@ -1325,25 +1367,24 @@ pub fn format_volume<T: ReadWriteSeek>(mut disk: T, options: FormatOptions) -> i
let sectors_per_fat: u32 = boot.bpb.sectors_per_fat(); let sectors_per_fat: u32 = boot.bpb.sectors_per_fat();
let bytes_per_fat: u32 = sectors_per_fat * bytes_per_sector as u32; let bytes_per_fat: u32 = sectors_per_fat * bytes_per_sector as u32;
let reserved_sectors = boot.bpb.reserved_sectors; let reserved_sectors = boot.bpb.reserved_sectors;
let mut fat_pos = reserved_sectors as u64 * bytes_per_sector as u64; let fat_pos = reserved_sectors as u64 * bytes_per_sector as u64;
for _ in 0..boot.bpb.fats { disk.seek(SeekFrom::Start(fat_pos))?;
disk.seek(SeekFrom::Start(fat_pos))?; write_zeros(&mut disk, bytes_per_fat as usize * boot.bpb.fats as usize)?;
write_zeros(&mut disk, bytes_per_fat as usize)?; {
disk.seek(SeekFrom::Start(fat_pos))?; let mut fat_slice = fat_slice(&mut disk, &boot.bpb);
format_fat(&mut disk, fat_type, boot.bpb.media)?; format_fat(&mut fat_slice, fat_type, boot.bpb.media, bytes_per_fat, boot.bpb.total_clusters())?;
fat_pos += bytes_per_fat as u64;
// TODO: mark entries at the end of FAT as used (after FAT but before sector end)
// TODO: mark special entries 0x0FFFFFF0 - 0x0FFFFFFF as BAD if they exists on FAT32 volume
} }
// Root directory // Root directory
let root_dir_pos = fat_pos; let root_dir_pos = fat_pos + bytes_per_fat as u64 * boot.bpb.fats as u64;
disk.seek(SeekFrom::Start(root_dir_pos))?; disk.seek(SeekFrom::Start(root_dir_pos))?;
let root_dir_sectors: u32 = boot.bpb.root_dir_sectors(); let root_dir_sectors: u32 = boot.bpb.root_dir_sectors();
write_zeros(&mut disk, root_dir_sectors as usize * bytes_per_sector as usize)?; write_zeros(&mut disk, root_dir_sectors as usize * bytes_per_sector as usize)?;
if fat_type == FatType::Fat32 { if fat_type == FatType::Fat32 {
// FIXME: alloc_cluster needs FAT stream, not entire disk let root_dir_first_cluster = {
let root_dir_first_cluster = alloc_cluster(&mut disk, fat_type, None, None, 1)?; let mut fat_slice = fat_slice(&mut disk, &boot.bpb);
alloc_cluster(&mut fat_slice, fat_type, None, None, 1)?
};
assert!(root_dir_first_cluster == boot.bpb.root_dir_first_cluster); assert!(root_dir_first_cluster == boot.bpb.root_dir_first_cluster);
let first_data_sector = reserved_sectors as u32 + sectors_per_fat + root_dir_sectors; let first_data_sector = reserved_sectors as u32 + sectors_per_fat + root_dir_sectors;
let sectors_per_cluster = boot.bpb.sectors_per_cluster; let sectors_per_cluster = boot.bpb.sectors_per_cluster;

View File

@ -1,5 +1,6 @@
use byteorder::LittleEndian; use byteorder::LittleEndian;
use byteorder_ext::{ReadBytesExt, WriteBytesExt}; use byteorder_ext::{ReadBytesExt, WriteBytesExt};
use core::cmp;
use io; use io;
use fs::{FatType, FsStatusFlags, ReadSeek, ReadWriteSeek}; use fs::{FatType, FsStatusFlags, ReadSeek, ReadWriteSeek};
@ -26,6 +27,7 @@ enum FatValue {
trait FatTrait { trait FatTrait {
fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32>; fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32>;
fn get<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<FatValue>; fn get<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<FatValue>;
fn set_raw<T: ReadWriteSeek>(fat: &mut T, cluster: u32, raw_value: u32) -> io::Result<()>;
fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()>; fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()>;
fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32>; fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32>;
fn count_free<T: ReadSeek>(fat: &mut T, end_cluster: u32) -> io::Result<u32>; fn count_free<T: ReadSeek>(fat: &mut T, end_cluster: u32) -> io::Result<u32>;
@ -109,8 +111,17 @@ pub(crate) fn read_fat_flags<T: ReadSeek>(fat: &mut T, fat_type: FatType) -> io:
Ok(FsStatusFlags { dirty, io_error }) Ok(FsStatusFlags { dirty, io_error })
} }
pub(crate) fn format_fat<T: ReadWriteSeek>(fat: &mut T, fat_type: FatType, media: u8) -> io::Result<()> { pub(crate) fn count_free_clusters<T: ReadSeek>(fat: &mut T, fat_type: FatType, total_clusters: u32) -> io::Result<u32> {
// Note: cannot use any seeking function here because fat parameter is not a disk slice let end_cluster = total_clusters + RESERVED_FAT_ENTRIES;
match fat_type {
FatType::Fat12 => Fat12::count_free(fat, end_cluster),
FatType::Fat16 => Fat16::count_free(fat, end_cluster),
FatType::Fat32 => Fat32::count_free(fat, end_cluster),
}
}
pub(crate) fn format_fat<T: ReadWriteSeek>(fat: &mut T, fat_type: FatType, media: u8, bytes_per_fat: u32, total_clusters: u32) -> io::Result<()> {
// init first two reserved entries to FAT ID
match fat_type { match fat_type {
FatType::Fat12 => { FatType::Fat12 => {
fat.write_u8(media)?; fat.write_u8(media)?;
@ -125,16 +136,21 @@ pub(crate) fn format_fat<T: ReadWriteSeek>(fat: &mut T, fat_type: FatType, media
fat.write_u32::<LittleEndian>(0xFFFFFFFF)?; fat.write_u32::<LittleEndian>(0xFFFFFFFF)?;
}, },
}; };
Ok(()) // mark entries at the end of FAT as used (after FAT but before sector end)
} const BITS_PER_BYTE: u32 = 8;
let start_cluster = total_clusters + RESERVED_FAT_ENTRIES;
pub(crate) fn count_free_clusters<T: ReadSeek>(fat: &mut T, fat_type: FatType, total_clusters: u32) -> io::Result<u32> { let end_cluster = bytes_per_fat * BITS_PER_BYTE / fat_type.bits_per_fat_entry();
let end_cluster = total_clusters + RESERVED_FAT_ENTRIES; for cluster in start_cluster..end_cluster {
match fat_type { write_fat(fat, fat_type, cluster, FatValue::EndOfChain)?;
FatType::Fat12 => Fat12::count_free(fat, end_cluster),
FatType::Fat16 => Fat16::count_free(fat, end_cluster),
FatType::Fat32 => Fat32::count_free(fat, end_cluster),
} }
// mark special entries 0x0FFFFFF0 - 0x0FFFFFFF as BAD if they exists on FAT32 volume
if end_cluster > 0x0FFFFFF0 {
let end_bad_cluster = cmp::min(0x0FFFFFFF + 1, end_cluster);
for cluster in 0x0FFFFFF0..end_bad_cluster {
write_fat(fat, fat_type, cluster, FatValue::Bad)?;
}
}
Ok(())
} }
impl FatTrait for Fat12 { impl FatTrait for Fat12 {
@ -165,13 +181,17 @@ impl FatTrait for Fat12 {
FatValue::EndOfChain => 0xFFF, FatValue::EndOfChain => 0xFFF,
FatValue::Data(n) => n as u16, FatValue::Data(n) => n as u16,
}; };
Self::set_raw(fat, cluster, raw_val as u32)
}
fn set_raw<T: ReadWriteSeek>(fat: &mut T, cluster: u32, raw_val: u32) -> io::Result<()> {
let fat_offset = cluster + (cluster / 2); let fat_offset = cluster + (cluster / 2);
fat.seek(io::SeekFrom::Start(fat_offset as u64))?; fat.seek(io::SeekFrom::Start(fat_offset as u64))?;
let old_packed = fat.read_u16::<LittleEndian>()?; let old_packed = fat.read_u16::<LittleEndian>()?;
fat.seek(io::SeekFrom::Start(fat_offset as u64))?; fat.seek(io::SeekFrom::Start(fat_offset as u64))?;
let new_packed = match cluster & 1 { let new_packed = match cluster & 1 {
0 => (old_packed & 0xF000) | raw_val, 0 => (old_packed & 0xF000) | raw_val as u16,
_ => (old_packed & 0x000F) | (raw_val << 4), _ => (old_packed & 0x000F) | ((raw_val as u16) << 4),
}; };
fat.write_u16::<LittleEndian>(new_packed)?; fat.write_u16::<LittleEndian>(new_packed)?;
Ok(()) Ok(())
@ -248,16 +268,20 @@ impl FatTrait for Fat16 {
}) })
} }
fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> { fn set_raw<T: ReadWriteSeek>(fat: &mut T, cluster: u32, raw_value: u32) -> io::Result<()> {
fat.seek(io::SeekFrom::Start((cluster * 2) as u64))?; fat.seek(io::SeekFrom::Start((cluster * 2) as u64))?;
let raw_val = match value { fat.write_u16::<LittleEndian>(raw_value as u16)?;
Ok(())
}
fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> {
let raw_value = match value {
FatValue::Free => 0, FatValue::Free => 0,
FatValue::Bad => 0xFFF7, FatValue::Bad => 0xFFF7,
FatValue::EndOfChain => 0xFFFF, FatValue::EndOfChain => 0xFFFF,
FatValue::Data(n) => n as u16, FatValue::Data(n) => n as u16,
}; };
fat.write_u16::<LittleEndian>(raw_val)?; Self::set_raw(fat, cluster, raw_value as u32)
Ok(())
} }
fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32> { fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
@ -317,9 +341,14 @@ impl FatTrait for Fat32 {
}) })
} }
fn set_raw<T: ReadWriteSeek>(fat: &mut T, cluster: u32, raw_value: u32) -> io::Result<()> {
fat.seek(io::SeekFrom::Start((cluster * 4) as u64))?;
fat.write_u32::<LittleEndian>(raw_value)?;
Ok(())
}
fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> { fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> {
let old_reserved_bits = Self::get_raw(fat, cluster)? & 0xF0000000; let old_reserved_bits = Self::get_raw(fat, cluster)? & 0xF0000000;
fat.seek(io::SeekFrom::Start((cluster * 4) as u64))?;
if value == FatValue::Free && cluster >= 0x0FFFFFF7 && cluster <= 0x0FFFFFFF { if value == FatValue::Free && cluster >= 0x0FFFFFF7 && cluster <= 0x0FFFFFFF {
// NOTE: it is technically allowed for them to store FAT chain loops, // NOTE: it is technically allowed for them to store FAT chain loops,
@ -338,8 +367,7 @@ impl FatTrait for Fat32 {
FatValue::Data(n) => n, FatValue::Data(n) => n,
}; };
let raw_val = raw_val | old_reserved_bits; // must preserve original reserved values let raw_val = raw_val | old_reserved_bits; // must preserve original reserved values
fat.write_u32::<LittleEndian>(raw_val)?; Self::set_raw(fat, cluster, raw_val)
Ok(())
} }
fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32> { fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {

View File

@ -11,17 +11,9 @@ const KB: u32 = 1024;
const MB: u32 = KB * 1024; const MB: u32 = KB * 1024;
const TEST_STR: &str = "Hi there Rust programmer!\n"; const TEST_STR: &str = "Hi there Rust programmer!\n";
#[test] type FileSystem = fatfs::FileSystem<BufStream<io::Cursor<Vec<u8>>>>;
fn test_format() {
let _ = env_logger::try_init();
let storage_vec: Vec<u8> = Vec::with_capacity((8 * MB) as usize);
let storage_cur = io::Cursor::new(storage_vec);
let mut buffered_stream = BufStream::new(storage_cur);
let mut opts: fatfs::FormatOptions = Default::default();
opts.total_sectors = 8 * MB / 512;
fatfs::format_volume(&mut buffered_stream, opts).expect("format volume");
let fs = fatfs::FileSystem::new(buffered_stream, fatfs::FsOptions::new()).expect("open fs"); fn basic_fs_test(fs: &FileSystem) {
let root_dir = fs.root_dir(); let root_dir = fs.root_dir();
let entries = root_dir.iter().map(|r| r.unwrap()).collect::<Vec<_>>(); let entries = root_dir.iter().map(|r| r.unwrap()).collect::<Vec<_>>();
assert_eq!(entries.len(), 0); assert_eq!(entries.len(), 0);
@ -33,3 +25,52 @@ fn test_format() {
let entries = root_dir.iter().map(|r| r.unwrap()).collect::<Vec<_>>(); let entries = root_dir.iter().map(|r| r.unwrap()).collect::<Vec<_>>();
assert_eq!(entries.len(), 1); assert_eq!(entries.len(), 1);
} }
fn test_format_fs(opts: fatfs::FormatOptions, total_bytes: u64) -> FileSystem {
let _ = env_logger::try_init();
let storage_vec: Vec<u8> = Vec::with_capacity(total_bytes as usize);
let storage_cur = io::Cursor::new(storage_vec);
let mut buffered_stream = BufStream::new(storage_cur);
fatfs::format_volume(&mut buffered_stream, opts).expect("format volume");
let fs = fatfs::FileSystem::new(buffered_stream, fatfs::FsOptions::new()).expect("open fs");
basic_fs_test(&fs);
fs
}
#[test]
fn test_format_1mb() {
let total_bytes = 1 * MB as u64;
let mut opts: fatfs::FormatOptions = Default::default();
opts.total_sectors = (total_bytes / 512) as u32;
let fs = test_format_fs(opts, total_bytes);
assert_eq!(fs.fat_type(), fatfs::FatType::Fat12);
}
#[test]
fn test_format_8mb() {
let total_bytes = 8 * MB as u64;
let mut opts: fatfs::FormatOptions = Default::default();
opts.total_sectors = (total_bytes / 512) as u32;
let fs = test_format_fs(opts, total_bytes);
assert_eq!(fs.fat_type(), fatfs::FatType::Fat16);
}
#[test]
fn test_format_50mb() {
let total_bytes = 50 * MB as u64;
let mut opts: fatfs::FormatOptions = Default::default();
opts.total_sectors = (total_bytes / 512) as u32;
let fs = test_format_fs(opts, total_bytes);
assert_eq!(fs.fat_type(), fatfs::FatType::Fat16);
}
#[test]
fn test_format_512mb() {
let total_bytes = 2 * 1024 * MB as u64;
let mut opts: fatfs::FormatOptions = Default::default();
opts.total_sectors = (total_bytes / 512) as u32;
let fs = test_format_fs(opts, total_bytes);
assert_eq!(fs.fat_type(), fatfs::FatType::Fat32);
}