rust-fatfs/src/table.rs
Henry Gabryjelski 2a4c01082a Preserve 4 MSB in FAT32 entries and add more sanity checks (#13)
* Update compatibility maximum cluster size when sector size is larger than 512 bytes.

* Additional validation of values in FsInfo sector.
* next_free_cluster cannot be 0 or 1, as these are reserved clusters
* next_free_cluster must be a valid cluster (using BPB to validate)
* free_cluster_count must be possible value (using BPB to validate)

* Avoid data-loss edge-case on volumes over 138GB in size.

Specifically, if the volume has more
than 0x0FFF_FFF4 clusters, then the FAT
will include an entry for clusters that
are reserved values.  Specifically, cluster
number 0x0FFF_FFF7 is defined to mean
BAD_SECTOR, while numbers 0x0FFF_FFF8 ..
0x0FFF_FFFF are defined to mean end-of-chain.

This prevents these clusters from being part
of any valid cluster chain.  Therefore:
1. prevent setting these clusters to point to
   a valid next cluster
2. prevent reading these clusters as pointing
   to a valid next cluster

Instead, always read/write these FAT entries
to have next cluster value of BAD_SECTOR.

* Reduce noisy warnings on FAT32.

* The reserved bits in FAT entry must be preserved on update.

* Change the set() implementation for FAT32 entries to return an actual Err(),
when attempting to set values for cluster numbers that have special meaning.
2018-10-06 16:42:31 +02:00

509 lines
20 KiB
Rust

use io;
use io::{Error, ErrorKind};
use byteorder::LittleEndian;
use byteorder_ext::{ReadBytesExt, WriteBytesExt};
use fs::{FatType, FsStatusFlags, ReadSeek, ReadWriteSeek};
struct Fat<T> {
#[allow(dead_code)]
dummy: [T; 0],
}
type Fat12 = Fat<u8>;
type Fat16 = Fat<u16>;
type Fat32 = Fat<u32>;
pub const RESERVED_FAT_ENTRIES: u32 = 2;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
enum FatValue {
Free,
Data(u32),
Bad,
EndOfChain,
}
trait FatTrait {
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 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 count_free<T: ReadSeek>(fat: &mut T, end_cluster: u32) -> io::Result<u32>;
}
fn read_fat<T: ReadSeek>(fat: &mut T, fat_type: FatType, cluster: u32) -> io::Result<FatValue> {
match fat_type {
FatType::Fat12 => Fat12::get(fat, cluster),
FatType::Fat16 => Fat16::get(fat, cluster),
FatType::Fat32 => Fat32::get(fat, cluster),
}
}
fn write_fat<T: ReadWriteSeek>(fat: &mut T, fat_type: FatType, cluster: u32, value: FatValue) -> io::Result<()> {
trace!("write FAT - cluster {} value {:?}", cluster, value);
match fat_type {
FatType::Fat12 => Fat12::set(fat, cluster, value),
FatType::Fat16 => Fat16::set(fat, cluster, value),
FatType::Fat32 => Fat32::set(fat, cluster, value),
}
}
fn get_next_cluster<T: ReadSeek>(fat: &mut T, fat_type: FatType, cluster: u32) -> io::Result<Option<u32>> {
let val = read_fat(fat, fat_type, cluster)?;
match val {
FatValue::Data(n) => Ok(Some(n)),
_ => Ok(None),
}
}
fn find_free_cluster<T: ReadSeek>(fat: &mut T, fat_type: FatType, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
match fat_type {
FatType::Fat12 => Fat12::find_free(fat, start_cluster, end_cluster),
FatType::Fat16 => Fat16::find_free(fat, start_cluster, end_cluster),
FatType::Fat32 => Fat32::find_free(fat, start_cluster, end_cluster),
}
}
pub(crate) fn alloc_cluster<T: ReadWriteSeek>(
fat: &mut T,
fat_type: FatType,
prev_cluster: Option<u32>,
hint: Option<u32>,
total_clusters: u32,
) -> io::Result<u32> {
let end_cluster = total_clusters + RESERVED_FAT_ENTRIES;
let start_cluster = match hint {
Some(n) if n < end_cluster => n,
_ => RESERVED_FAT_ENTRIES,
};
let new_cluster = match find_free_cluster(fat, fat_type, start_cluster, end_cluster) {
Ok(n) => n,
Err(_) if start_cluster > RESERVED_FAT_ENTRIES => find_free_cluster(fat, fat_type, RESERVED_FAT_ENTRIES, start_cluster)?,
Err(e) => return Err(e),
};
write_fat(fat, fat_type, new_cluster, FatValue::EndOfChain)?;
if let Some(n) = prev_cluster {
write_fat(fat, fat_type, n, FatValue::Data(new_cluster))?;
}
trace!("allocated cluster {}", new_cluster);
Ok(new_cluster)
}
pub(crate) fn read_fat_flags<T: ReadSeek>(fat: &mut T, fat_type: FatType) -> io::Result<FsStatusFlags> {
// check MSB (except in FAT12)
let val = match fat_type {
FatType::Fat12 => 0xFFF,
FatType::Fat16 => Fat16::get_raw(fat, 1)?,
FatType::Fat32 => Fat32::get_raw(fat, 1)?,
};
let dirty = match fat_type {
FatType::Fat12 => false,
FatType::Fat16 => val & (1 << 15) == 0,
FatType::Fat32 => val & (1 << 27) == 0,
};
let io_error = match fat_type {
FatType::Fat12 => false,
FatType::Fat16 => val & (1 << 14) == 0,
FatType::Fat32 => val & (1 << 26) == 0,
};
Ok(FsStatusFlags { dirty, io_error })
}
pub(crate) fn count_free_clusters<T: ReadSeek>(fat: &mut T, fat_type: FatType, total_clusters: u32) -> io::Result<u32> {
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),
}
}
impl FatTrait for Fat12 {
fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32> {
let fat_offset = cluster + (cluster / 2);
fat.seek(io::SeekFrom::Start(fat_offset as u64))?;
let packed_val = fat.read_u16::<LittleEndian>()?;
Ok(match cluster & 1 {
0 => packed_val & 0x0FFF,
_ => packed_val >> 4,
} as u32)
}
fn get<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<FatValue> {
let val = Self::get_raw(fat, cluster)?;
Ok(match val {
0 => FatValue::Free,
0xFF7 => FatValue::Bad,
0xFF8...0xFFF => FatValue::EndOfChain,
n => FatValue::Data(n as u32),
})
}
fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> {
let raw_val = match value {
FatValue::Free => 0,
FatValue::Bad => 0xFF7,
FatValue::EndOfChain => 0xFFF,
FatValue::Data(n) => n as u16,
};
let fat_offset = cluster + (cluster / 2);
fat.seek(io::SeekFrom::Start(fat_offset as u64))?;
let old_packed = fat.read_u16::<LittleEndian>()?;
fat.seek(io::SeekFrom::Start(fat_offset as u64))?;
let new_packed = match cluster & 1 {
0 => (old_packed & 0xF000) | raw_val,
_ => (old_packed & 0x000F) | (raw_val << 4),
};
fat.write_u16::<LittleEndian>(new_packed)?;
Ok(())
}
fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
let mut cluster = start_cluster;
let fat_offset = cluster + (cluster / 2);
fat.seek(io::SeekFrom::Start(fat_offset as u64))?;
let mut packed_val = fat.read_u16::<LittleEndian>()?;
loop {
let val = match cluster & 1 {
0 => packed_val & 0x0FFF,
_ => packed_val >> 4,
};
if val == 0 {
return Ok(cluster);
}
cluster += 1;
if cluster == end_cluster {
return Err(io::Error::new(io::ErrorKind::Other, "No space left on device"));
}
packed_val = match cluster & 1 {
0 => fat.read_u16::<LittleEndian>()?,
_ => {
let next_byte = fat.read_u8()? as u16;
(packed_val >> 8) | (next_byte << 8)
},
};
}
}
fn count_free<T: ReadSeek>(fat: &mut T, end_cluster: u32) -> io::Result<u32> {
let mut count = 0;
let mut cluster = RESERVED_FAT_ENTRIES;
fat.seek(io::SeekFrom::Start((cluster * 3 / 2) as u64))?;
let mut prev_packed_val = 0u16;
while cluster < end_cluster {
let res = match cluster & 1 {
0 => fat.read_u16::<LittleEndian>(),
_ => fat.read_u8().map(|n| n as u16),
};
let packed_val = match res {
Err(err) => return Err(err),
Ok(n) => n,
};
let val = match cluster & 1 {
0 => packed_val & 0x0FFF,
_ => (packed_val << 8) | (prev_packed_val >> 12),
};
prev_packed_val = packed_val;
if val == 0 {
count += 1;
}
cluster += 1;
}
Ok(count)
}
}
impl FatTrait for Fat16 {
fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32> {
fat.seek(io::SeekFrom::Start((cluster * 2) as u64))?;
Ok(fat.read_u16::<LittleEndian>()? as u32)
}
fn get<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<FatValue> {
let val = Self::get_raw(fat, cluster)?;
Ok(match val {
0 => FatValue::Free,
0xFFF7 => FatValue::Bad,
0xFFF8...0xFFFF => FatValue::EndOfChain,
n => FatValue::Data(n as u32),
})
}
fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> {
fat.seek(io::SeekFrom::Start((cluster * 2) as u64))?;
let raw_val = match value {
FatValue::Free => 0,
FatValue::Bad => 0xFFF7,
FatValue::EndOfChain => 0xFFFF,
FatValue::Data(n) => n as u16,
};
fat.write_u16::<LittleEndian>(raw_val)?;
Ok(())
}
fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
let mut cluster = start_cluster;
fat.seek(io::SeekFrom::Start((cluster * 2) as u64))?;
while cluster < end_cluster {
let val = fat.read_u16::<LittleEndian>()?;
if val == 0 {
return Ok(cluster);
}
cluster += 1;
}
Err(io::Error::new(io::ErrorKind::Other, "No space left on device"))
}
fn count_free<T: ReadSeek>(fat: &mut T, end_cluster: u32) -> io::Result<u32> {
let mut count = 0;
let mut cluster = RESERVED_FAT_ENTRIES;
fat.seek(io::SeekFrom::Start((cluster * 2) as u64))?;
while cluster < end_cluster {
let val = fat.read_u16::<LittleEndian>()?;
if val == 0 {
count += 1;
}
cluster += 1;
}
Ok(count)
}
}
impl FatTrait for Fat32 {
fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32> {
fat.seek(io::SeekFrom::Start((cluster * 4) as u64))?;
Ok(fat.read_u32::<LittleEndian>()?)
}
fn get<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<FatValue> {
let val = Self::get_raw(fat, cluster)? & 0x0FFFFFFF;
Ok(match val {
0 if cluster >= 0x0FFFFFF7 && cluster <= 0x0FFFFFFF => {
let tmp = if cluster == 0x0FFFFFF7 { "BAD_CLUSTER" } else { "end-of-chain" };
warn!("cluster number {} is a special value in FAT to indicate {}; it should never be seen as free", cluster, tmp);
FatValue::Bad // avoid accidental use or allocation into a FAT chain
},
0 => FatValue::Free,
0x0FFFFFF7 => FatValue::Bad,
0x0FFFFFF8...0x0FFFFFFF => FatValue::EndOfChain,
n if cluster >= 0x0FFFFFF7 && cluster <= 0x0FFFFFFF => {
let tmp = if cluster == 0x0FFFFFF7 { "BAD_CLUSTER" } else { "end-of-chain" };
warn!("cluster number {} is a special value in FAT to indicate {}; hiding potential FAT chain value {} and instead reporting as a bad sector", cluster, tmp, n);
FatValue::Bad // avoid accidental use or allocation into a FAT chain
},
n => FatValue::Data(n as u32),
})
}
fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> {
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 {
// NOTE: it is technically allowed for them to store FAT chain loops,
// or even have them all store value '4' as their next cluster.
// Some believe only FatValue::Bad should be allowed for this edge case.
let tmp = if cluster == 0x0FFFFFF7 { "BAD_CLUSTER" } else { "end-of-chain" };
let msg = format!("cluster number {} is a special value in FAT to indicate {}; it should never be set as free", cluster, tmp);
let custom_error = Error::new(ErrorKind::Other, msg);
return Err(custom_error);
};
let raw_val = match value {
FatValue::Free => 0,
FatValue::Bad => 0x0FFFFFF7,
FatValue::EndOfChain => 0x0FFFFFFF,
FatValue::Data(n) => n,
};
let raw_val = raw_val | old_reserved_bits; // must preserve original reserved values
fat.write_u32::<LittleEndian>(raw_val)?;
Ok(())
}
fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
let mut cluster = start_cluster;
fat.seek(io::SeekFrom::Start((cluster * 4) as u64))?;
while cluster < end_cluster {
let val = fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF;
if val == 0 {
return Ok(cluster);
}
cluster += 1;
}
Err(io::Error::new(io::ErrorKind::Other, "No space left on device"))
}
fn count_free<T: ReadSeek>(fat: &mut T, end_cluster: u32) -> io::Result<u32> {
let mut count = 0;
let mut cluster = RESERVED_FAT_ENTRIES;
fat.seek(io::SeekFrom::Start((cluster * 4) as u64))?;
while cluster < end_cluster {
let val = fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF;
if val == 0 {
count += 1;
}
cluster += 1;
}
Ok(count)
}
}
pub(crate) struct ClusterIterator<T: ReadWriteSeek> {
fat: T,
fat_type: FatType,
cluster: Option<u32>,
err: bool,
}
impl<T: ReadWriteSeek> ClusterIterator<T> {
pub(crate) fn new(fat: T, fat_type: FatType, cluster: u32) -> Self {
ClusterIterator {
fat,
fat_type,
cluster: Some(cluster),
err: false,
}
}
pub(crate) fn truncate(&mut self) -> io::Result<u32> {
match self.cluster {
Some(n) => {
// Move to the next cluster
self.next();
// Mark previous cluster as end of chain
write_fat(&mut self.fat, self.fat_type, n, FatValue::EndOfChain)?;
// Free rest of chain
self.free()
},
None => Ok(0),
}
}
pub(crate) fn free(&mut self) -> io::Result<u32> {
let mut num_free = 0;
while let Some(n) = self.cluster {
self.next();
write_fat(&mut self.fat, self.fat_type, n, FatValue::Free)?;
num_free += 1;
}
Ok(num_free)
}
}
impl<T: ReadWriteSeek> Iterator for ClusterIterator<T> {
type Item = io::Result<u32>;
fn next(&mut self) -> Option<Self::Item> {
if self.err {
return None;
}
if let Some(current_cluster) = self.cluster {
self.cluster = match get_next_cluster(&mut self.fat, self.fat_type, current_cluster) {
Ok(next_cluster) => next_cluster,
Err(err) => {
self.err = true;
return Some(Err(err));
},
}
}
self.cluster.map(|n| Ok(n))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_fat<T: ReadWriteSeek>(fat_type: FatType, mut cur: T) {
// based on cluster maps from Wikipedia:
// https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#Cluster_map
assert_eq!(read_fat(&mut cur, fat_type, 1).unwrap(), FatValue::EndOfChain);
assert_eq!(read_fat(&mut cur, fat_type, 4).unwrap(), FatValue::Data(5));
assert_eq!(read_fat(&mut cur, fat_type, 5).unwrap(), FatValue::Data(6));
assert_eq!(read_fat(&mut cur, fat_type, 8).unwrap(), FatValue::EndOfChain);
assert_eq!(read_fat(&mut cur, fat_type, 9).unwrap(), FatValue::Data(0xA));
assert_eq!(read_fat(&mut cur, fat_type, 0xA).unwrap(), FatValue::Data(0x14));
assert_eq!(read_fat(&mut cur, fat_type, 0x12).unwrap(), FatValue::Free);
assert_eq!(read_fat(&mut cur, fat_type, 0x17).unwrap(), FatValue::Bad);
assert_eq!(read_fat(&mut cur, fat_type, 0x18).unwrap(), FatValue::Bad);
assert_eq!(read_fat(&mut cur, fat_type, 0x1B).unwrap(), FatValue::Free);
assert_eq!(find_free_cluster(&mut cur, fat_type, 2, 0x20).unwrap(), 0x12);
assert_eq!(find_free_cluster(&mut cur, fat_type, 0x12, 0x20).unwrap(), 0x12);
assert_eq!(find_free_cluster(&mut cur, fat_type, 0x13, 0x20).unwrap(), 0x1B);
assert!(find_free_cluster(&mut cur, fat_type, 0x13, 0x14).is_err());
assert_eq!(count_free_clusters(&mut cur, fat_type, 0x1E).unwrap(), 5);
// test allocation
assert_eq!(alloc_cluster(&mut cur, fat_type, None, Some(0x13), 0x1E).unwrap(), 0x1B);
assert_eq!(read_fat(&mut cur, fat_type, 0x1B).unwrap(), FatValue::EndOfChain);
assert_eq!(alloc_cluster(&mut cur, fat_type, Some(0x1B), None, 0x1E).unwrap(), 0x12);
assert_eq!(read_fat(&mut cur, fat_type, 0x1B).unwrap(), FatValue::Data(0x12));
assert_eq!(read_fat(&mut cur, fat_type, 0x12).unwrap(), FatValue::EndOfChain);
assert_eq!(count_free_clusters(&mut cur, fat_type, 0x1E).unwrap(), 3);
// test reading from iterator
{
let iter = ClusterIterator::new(&mut cur, fat_type, 0x9);
assert_eq!(
iter.map(|r| r.unwrap()).collect::<Vec<_>>(),
vec![0xA, 0x14, 0x15, 0x16, 0x19, 0x1A]
);
}
// test truncating a chain
{
let mut iter = ClusterIterator::new(&mut cur, fat_type, 0x9);
assert_eq!(iter.nth(3).unwrap().unwrap(), 0x16);
iter.truncate().unwrap();
}
assert_eq!(read_fat(&mut cur, fat_type, 0x16).unwrap(), FatValue::EndOfChain);
assert_eq!(read_fat(&mut cur, fat_type, 0x19).unwrap(), FatValue::Free);
assert_eq!(read_fat(&mut cur, fat_type, 0x1A).unwrap(), FatValue::Free);
// test freeing a chain
{
let mut iter = ClusterIterator::new(&mut cur, fat_type, 0x9);
iter.free().unwrap();
}
assert_eq!(read_fat(&mut cur, fat_type, 0x9).unwrap(), FatValue::Free);
assert_eq!(read_fat(&mut cur, fat_type, 0xA).unwrap(), FatValue::Free);
assert_eq!(read_fat(&mut cur, fat_type, 0x14).unwrap(), FatValue::Free);
assert_eq!(read_fat(&mut cur, fat_type, 0x15).unwrap(), FatValue::Free);
assert_eq!(read_fat(&mut cur, fat_type, 0x16).unwrap(), FatValue::Free);
}
#[test]
fn test_fat12() {
let mut fat: Vec<u8> = vec![
0xF0, 0xFF, 0xFF, 0x03, 0x40, 0x00, 0x05, 0x60, 0x00, 0x07, 0x80, 0x00, 0xFF, 0xAF, 0x00, 0x14, 0xC0, 0x00, 0x0D, 0xE0, 0x00,
0x0F, 0x00, 0x01, 0x11, 0xF0, 0xFF, 0x00, 0xF0, 0xFF, 0x15, 0x60, 0x01, 0x19, 0x70, 0xFF, 0xF7, 0xAF, 0x01, 0xFF, 0x0F, 0x00,
0x00, 0x70, 0xFF, 0x00, 0x00, 0x00,
];
test_fat(FatType::Fat12, io::Cursor::new(&mut fat));
}
#[test]
fn test_fat16() {
let mut fat: Vec<u8> = vec![
0xF0, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0xFF, 0xFF, 0x0A, 0x00, 0x14,
0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x10, 0x00, 0x11, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x15, 0x00,
0x16, 0x00, 0x19, 0x00, 0xF7, 0xFF, 0xF7, 0xFF, 0x1A, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0x00, 0x00, 0x00,
0x00,
];
test_fat(FatType::Fat16, io::Cursor::new(&mut fat));
}
#[test]
fn test_fat32() {
let mut fat: Vec<u8> = vec![
0xF0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06,
0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00,
0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x11, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x15, 0x00, 0x00, 0x00,
0x16, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0xFF, 0x0F, 0xF7, 0xFF, 0xFF, 0x0F, 0x1A, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
];
test_fat(FatType::Fat32, io::Cursor::new(&mut fat));
}
}