rust-fatfs/src/table.rs
2018-05-10 01:00:24 +02:00

313 lines
9.6 KiB
Rust

use io;
use io::prelude::*;
use byteorder::LittleEndian;
use byteorder_ext::{ReadBytesExt, WriteBytesExt};
use fs::{FatType, FsStatusFlags, DiskSlice, ReadSeek};
struct Fat<T> {
#[allow(dead_code)]
dummy: [T; 0],
}
type Fat12 = Fat<u8>;
type Fat16 = Fat<u16>;
type Fat32 = Fat<u32>;
#[derive(Debug, Clone, Copy)]
enum FatValue {
Free,
Data(u32),
Bad,
EndOfChain,
}
trait FatTrait {
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue>;
fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()>;
fn find_free(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result<u32>;
fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result<u32>;
}
fn read_fat(fat: &mut ReadSeek, 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(fat: &mut DiskSlice, 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(fat: &mut ReadSeek, 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(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result<u32> {
match fat_type {
FatType::Fat12 => Fat12::find_free(fat, cluster),
FatType::Fat16 => Fat16::find_free(fat, cluster),
FatType::Fat32 => Fat32::find_free(fat, cluster),
}
}
pub(crate) fn alloc_cluster(fat: &mut DiskSlice, fat_type: FatType, prev_cluster: Option<u32>) -> io::Result<u32> {
let new_cluster = find_free_cluster(fat, fat_type, 2)?;
write_fat(fat, fat_type, new_cluster, FatValue::EndOfChain)?;
match prev_cluster {
Some(n) => write_fat(fat, fat_type, n, FatValue::Data(new_cluster))?,
None => {},
}
trace!("allocated cluster {}", new_cluster);
Ok(new_cluster)
}
pub(crate) fn read_fat_flags(fat: &mut DiskSlice, 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,
})
}
impl FatTrait for Fat12 {
fn get_raw(fat: &mut ReadSeek, 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(fat: &mut ReadSeek, 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(fat: &mut DiskSlice, 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(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result<u32> {
let mut cluster = hint_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;
packed_val = match cluster & 1 {
0 => fat.read_u16::<LittleEndian>()?,
_ => {
let next_byte = fat.read_u8()? as u16;
(packed_val >> 8) | (next_byte << 8)
},
};
}
}
}
impl FatTrait for Fat16 {
fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result<u32> {
fat.seek(io::SeekFrom::Start((cluster*2) as u64))?;
Ok(fat.read_u16::<LittleEndian>()? as u32)
}
fn get(fat: &mut ReadSeek, 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(fat: &mut DiskSlice, 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(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result<u32> {
let mut cluster = hint_cluster;
fat.seek(io::SeekFrom::Start((cluster*2) as u64))?;
loop {
let val = fat.read_u16::<LittleEndian>()?;
if val == 0 {
return Ok(cluster);
}
cluster += 1;
}
}
}
impl FatTrait for Fat32 {
fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result<u32> {
fat.seek(io::SeekFrom::Start((cluster*4) as u64))?;
Ok(fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF)
}
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue> {
let val = Self::get_raw(fat, cluster)?;
Ok(match val {
0 => FatValue::Free,
0x0FFFFFF7 => FatValue::Bad,
0x0FFFFFF8...0x0FFFFFFF => FatValue::EndOfChain,
n => FatValue::Data(n as u32),
})
}
fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()> {
fat.seek(io::SeekFrom::Start((cluster*4) as u64))?;
let raw_val = match value {
FatValue::Free => 0,
FatValue::Bad => 0x0FFFFFF7,
FatValue::EndOfChain => 0x0FFFFFFF,
FatValue::Data(n) => n,
};
fat.write_u32::<LittleEndian>(raw_val)?;
Ok(())
}
fn find_free(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result<u32> {
let mut cluster = hint_cluster;
fat.seek(io::SeekFrom::Start((cluster*4) as u64))?;
loop {
let val = fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF;
if val == 0 {
return Ok(cluster);
}
cluster += 1;
}
}
}
pub(crate) struct ClusterIterator<'a, 'b: 'a> {
fat: DiskSlice<'a, 'b>,
fat_type: FatType,
cluster: Option<u32>,
err: bool,
}
impl <'a, 'b> ClusterIterator<'a, 'b> {
pub(crate) fn new(fat: DiskSlice<'a, 'b>, fat_type: FatType, cluster: u32)
-> ClusterIterator<'a, 'b> {
ClusterIterator {
fat: fat,
fat_type: fat_type,
cluster: Some(cluster),
err: false,
}
}
pub(crate) fn truncate(&mut self) -> io::Result<()> {
match self.cluster {
Some(n) => {
write_fat(&mut self.fat, self.fat_type, n, FatValue::EndOfChain)?;
self.next();
self.free()
},
None => Ok(()),
}
}
pub(crate) fn free(&mut self) -> io::Result<()> {
loop {
let prev = self.cluster;
self.next();
match prev {
Some(n) => write_fat(&mut self.fat, self.fat_type, n, FatValue::Free)?,
None => break,
};
}
Ok(())
}
}
impl <'a, 'b> Iterator for ClusterIterator<'a, 'b> {
type Item = io::Result<u32>;
fn next(&mut self) -> Option<Self::Item> {
if self.err {
return None;
}
match self.cluster {
Some(current_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));
},
}
},
None => {},
};
match self.cluster {
Some(n) => Some(Ok(n)),
None => None,
}
}
}