use io; use io::prelude::*; use byteorder::LittleEndian; use byteorder_ext::{ReadBytesExt, WriteBytesExt}; use fs::{FatType, FsStatusFlags, DiskSlice, ReadSeek}; struct Fat { #[allow(dead_code)] dummy: [T; 0], } type Fat12 = Fat; type Fat16 = Fat; type Fat32 = Fat; #[derive(Debug, Clone, Copy)] enum FatValue { Free, Data(u32), Bad, EndOfChain, } trait FatTrait { fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result; fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()>; fn find_free(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result; fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result; } fn read_fat(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result { 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> { 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 { 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) -> io::Result { 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 { // 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 { let fat_offset = cluster + (cluster / 2); fat.seek(io::SeekFrom::Start(fat_offset as u64))?; let packed_val = fat.read_u16::()?; Ok(match cluster & 1 { 0 => packed_val & 0x0FFF, _ => packed_val >> 4, } as u32) } fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result { 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::()?; 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::(new_packed)?; Ok(()) } fn find_free(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result { 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::()?; 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::()?, _ => { 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 { fat.seek(io::SeekFrom::Start((cluster*2) as u64))?; Ok(fat.read_u16::()? as u32) } fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result { 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::(raw_val)?; Ok(()) } fn find_free(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result { let mut cluster = hint_cluster; fat.seek(io::SeekFrom::Start((cluster*2) as u64))?; loop { let val = fat.read_u16::()?; if val == 0 { return Ok(cluster); } cluster += 1; } } } impl FatTrait for Fat32 { fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result { fat.seek(io::SeekFrom::Start((cluster*4) as u64))?; Ok(fat.read_u32::()? & 0x0FFFFFFF) } fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result { 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::(raw_val)?; Ok(()) } fn find_free(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result { let mut cluster = hint_cluster; fat.seek(io::SeekFrom::Start((cluster*4) as u64))?; loop { let val = fat.read_u32::()? & 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, 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; fn next(&mut self) -> Option { 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, } } }