Alloc and free clusters for file data.

This commit is contained in:
Rafał Harabień 2017-10-09 21:14:28 +02:00
parent f32f1c7279
commit d8eba51b88
6 changed files with 390 additions and 105 deletions

View File

@ -6,16 +6,20 @@ Rust FAT
Introduction Introduction
------------ ------------
FAT filesystem read-only library implemented in Rust. FAT filesystem library implemented in Rust.
Features: Features:
* FAT12, FAT16, FAT32 filesystem versions, * FAT12, FAT16, FAT32 supported,
* read directory, * read directory entries,
* read file, * read file contents,
* LFN (Long File Names). * LFN (Long File Names),
* basic write support (write and truncate existing file).
Planned features: Missing features (yet):
* write support, * create new file/directory,
* remove file/directory,
Other planned features (Nice to Have):
* no_std environment support. * no_std environment support.
License License

View File

@ -83,6 +83,12 @@ impl DirFileEntryData {
if n == 0 { None } else { Some(n) } if n == 0 { None } else { Some(n) }
} }
pub(crate) fn set_first_cluster(&mut self, cluster: Option<u32>) {
let n = cluster.unwrap_or(0);
self.first_cluster_hi = (n >> 16) as u16;
self.first_cluster_lo = (n & 0xFFFF) as u16;
}
pub(crate) fn size(&self) -> u32 { pub(crate) fn size(&self) -> u32 {
self.size self.size
} }
@ -372,10 +378,8 @@ pub struct DirIter<'a, 'b: 'a> {
impl <'a, 'b> DirIter<'a, 'b> { impl <'a, 'b> DirIter<'a, 'b> {
fn read_dir_entry_data(&mut self) -> io::Result<DirEntryData> { fn read_dir_entry_data(&mut self) -> io::Result<DirEntryData> {
println!("read_dir_entry_data");
let mut name = [0; 11]; let mut name = [0; 11];
self.rdr.read_exact(&mut name)?; self.rdr.read_exact(&mut name)?;
println!("read_dir_entry_data {:?}", &name);
let attrs = FileAttributes::from_bits_truncate(self.rdr.read_u8()?); let attrs = FileAttributes::from_bits_truncate(self.rdr.read_u8()?);
if attrs == FileAttributes::LFN { if attrs == FileAttributes::LFN {
let mut data = DirLfnEntryData { let mut data = DirLfnEntryData {
@ -389,7 +393,6 @@ impl <'a, 'b> DirIter<'a, 'b> {
self.rdr.read_u16_into::<LittleEndian>(&mut data.name_1)?; self.rdr.read_u16_into::<LittleEndian>(&mut data.name_1)?;
data.reserved_0 = self.rdr.read_u16::<LittleEndian>()?; data.reserved_0 = self.rdr.read_u16::<LittleEndian>()?;
self.rdr.read_u16_into::<LittleEndian>(&mut data.name_2)?; self.rdr.read_u16_into::<LittleEndian>(&mut data.name_2)?;
println!("read_dir_entry_data end");
Ok(DirEntryData::Lfn(data)) Ok(DirEntryData::Lfn(data))
} else { } else {
let data = DirFileEntryData { let data = DirFileEntryData {
@ -406,12 +409,13 @@ impl <'a, 'b> DirIter<'a, 'b> {
first_cluster_lo: self.rdr.read_u16::<LittleEndian>()?, first_cluster_lo: self.rdr.read_u16::<LittleEndian>()?,
size: self.rdr.read_u32::<LittleEndian>()?, size: self.rdr.read_u32::<LittleEndian>()?,
}; };
println!("read_dir_entry_data end");
Ok(DirEntryData::File(data)) Ok(DirEntryData::File(data))
} }
} }
} }
const DIR_ENTRY_SIZE: u64 = 32;
impl <'a, 'b> Iterator for DirIter<'a, 'b> { impl <'a, 'b> Iterator for DirIter<'a, 'b> {
type Item = io::Result<DirEntry<'a, 'b>>; type Item = io::Result<DirEntry<'a, 'b>>;
@ -421,8 +425,8 @@ impl <'a, 'b> Iterator for DirIter<'a, 'b> {
} }
let mut lfn_buf = Vec::<u16>::new(); let mut lfn_buf = Vec::<u16>::new();
loop { loop {
let entry_pos = self.rdr.global_pos();
let res = self.read_dir_entry_data(); let res = self.read_dir_entry_data();
let entry_pos = self.rdr.global_pos().map(|p| p - DIR_ENTRY_SIZE);
let data = match res { let data = match res {
Ok(data) => data, Ok(data) => data,
Err(err) => { Err(err) => {

View File

@ -9,6 +9,7 @@ use dir::{FileEntryInfo, DateTime};
#[derive(Clone)] #[derive(Clone)]
pub struct File<'a, 'b: 'a> { pub struct File<'a, 'b: 'a> {
first_cluster: Option<u32>, first_cluster: Option<u32>,
// Note: if offset points between clusters current_cluster is the previous cluster
current_cluster: Option<u32>, current_cluster: Option<u32>,
offset: u32, offset: u32,
entry: Option<FileEntryInfo>, entry: Option<FileEntryInfo>,
@ -20,7 +21,7 @@ impl <'a, 'b> File<'a, 'b> {
pub(crate) fn new(first_cluster: Option<u32>, entry: Option<FileEntryInfo>, fs: FileSystemRef<'a, 'b>) -> Self { pub(crate) fn new(first_cluster: Option<u32>, entry: Option<FileEntryInfo>, fs: FileSystemRef<'a, 'b>) -> Self {
File { File {
first_cluster, entry, fs, first_cluster, entry, fs,
current_cluster: first_cluster, current_cluster: None, // cluster before first one
offset: 0, offset: 0,
entry_dirty: false, entry_dirty: false,
} }
@ -38,20 +39,32 @@ impl <'a, 'b> File<'a, 'b> {
} }
} }
pub fn truncate(&mut self) { pub fn truncate(&mut self) -> io::Result<()> {
// FIXME: free clusters?
match self.entry { match self.entry {
Some(ref mut e) => { Some(ref mut e) => {
if e.data.size != self.offset { if e.data.size == self.offset {
e.data.size = self.offset; return Ok(());
self.entry_dirty = true;
} }
e.data.size = self.offset;
if self.offset == 0 {
e.data.set_first_cluster(None);
}
self.entry_dirty = true;
}, },
_ => {}, _ => {},
} }
if self.offset > 0 {
self.fs.cluster_iter(self.current_cluster.unwrap()).truncate()
} else {
self.fs.cluster_iter(self.first_cluster.unwrap()).free()?;
self.first_cluster = None;
Ok(())
}
} }
pub(crate) fn global_pos(&self) -> Option<u64> { pub(crate) fn global_pos(&self) -> Option<u64> {
// Note: when between clusters it returns position after previous cluster
match self.current_cluster { match self.current_cluster {
Some(n) => { Some(n) => {
let cluster_size = self.fs.get_cluster_size(); let cluster_size = self.fs.get_cluster_size();
@ -93,6 +106,17 @@ impl <'a, 'b> File<'a, 'b> {
None => None, None => None,
} }
} }
fn set_first_cluster(&mut self, cluster: u32) {
self.first_cluster = Some(cluster);
match self.entry {
Some(ref mut e) => {
e.data.set_first_cluster(self.first_cluster);
},
None => {},
}
self.entry_dirty = true;
}
} }
impl<'a, 'b> Drop for File<'a, 'b> { impl<'a, 'b> Drop for File<'a, 'b> {
@ -106,7 +130,23 @@ impl<'a, 'b> Read for File<'a, 'b> {
let mut buf_offset: usize = 0; let mut buf_offset: usize = 0;
let cluster_size = self.fs.get_cluster_size(); let cluster_size = self.fs.get_cluster_size();
loop { loop {
let current_cluster = match self.current_cluster { let current_cluster_opt = if self.offset % cluster_size == 0 {
// next cluster
match self.current_cluster {
None => self.first_cluster,
Some(n) => {
let r = self.fs.cluster_iter(n).next();
match r {
Some(Err(err)) => return Err(err),
Some(Ok(n)) => Some(n),
None => None,
}
},
}
} else {
self.current_cluster
};
let current_cluster = match current_cluster_opt {
Some(n) => n, Some(n) => n,
None => break, None => break,
}; };
@ -118,6 +158,7 @@ impl<'a, 'b> Read for File<'a, 'b> {
if read_size == 0 { if read_size == 0 {
break; break;
} }
//println!("read c {} n {}", current_cluster, read_size);
let offset_in_fs = self.fs.offset_from_cluster(current_cluster) + (offset_in_cluster as u64); let offset_in_fs = self.fs.offset_from_cluster(current_cluster) + (offset_in_cluster as u64);
let read_bytes = { let read_bytes = {
let mut disk = self.fs.disk.borrow_mut(); let mut disk = self.fs.disk.borrow_mut();
@ -128,15 +169,8 @@ impl<'a, 'b> Read for File<'a, 'b> {
break; break;
} }
self.offset += read_bytes as u32; self.offset += read_bytes as u32;
self.current_cluster = Some(current_cluster);
buf_offset += read_bytes; buf_offset += read_bytes;
if self.offset % cluster_size == 0 {
let r = self.fs.cluster_iter(current_cluster).skip(1).next();
self.current_cluster = match r {
Some(Err(err)) => return Err(err),
Some(Ok(n)) => Some(n),
None => None,
};
}
} }
Ok(buf_offset) Ok(buf_offset)
} }
@ -147,17 +181,45 @@ impl<'a, 'b> Write for File<'a, 'b> {
let mut buf_offset: usize = 0; let mut buf_offset: usize = 0;
let cluster_size = self.fs.get_cluster_size(); let cluster_size = self.fs.get_cluster_size();
loop { loop {
let current_cluster = match self.current_cluster {
Some(n) => n,
None => unimplemented!(), // FIXME: allocate cluster
};
let offset_in_cluster = self.offset % cluster_size; let offset_in_cluster = self.offset % cluster_size;
let bytes_left_in_cluster = (cluster_size - offset_in_cluster) as usize; let bytes_left_in_cluster = (cluster_size - offset_in_cluster) as usize;
let bytes_left_in_buf = buf.len() - buf_offset; let bytes_left_in_buf = buf.len() - buf_offset;
let write_size = cmp::min(bytes_left_in_buf, bytes_left_in_cluster); let write_size = cmp::min(bytes_left_in_buf, bytes_left_in_cluster);
//println!("write {:?}", write_size);
if write_size == 0 { if write_size == 0 {
break; break;
} }
let current_cluster_opt = if self.offset % cluster_size == 0 {
// next cluster
let next_cluster = match self.current_cluster {
None => self.first_cluster,
Some(n) => {
let r = self.fs.cluster_iter(n).next();
match r {
Some(Err(err)) => return Err(err),
Some(Ok(n)) => Some(n),
None => None,
}
},
};
match next_cluster {
Some(_) => next_cluster,
None => {
let new_cluster = self.fs.alloc_cluster(self.current_cluster)?;
if self.first_cluster.is_none() {
self.set_first_cluster(new_cluster);
}
Some(new_cluster)
},
}
} else {
self.current_cluster
};
let current_cluster = match current_cluster_opt {
Some(n) => n,
None => panic!("Offset inside cluster but no cluster allocated"), // FIXME
};
let offset_in_fs = self.fs.offset_from_cluster(current_cluster) + (offset_in_cluster as u64); let offset_in_fs = self.fs.offset_from_cluster(current_cluster) + (offset_in_cluster as u64);
let written_bytes = { let written_bytes = {
let mut disk = self.fs.disk.borrow_mut(); let mut disk = self.fs.disk.borrow_mut();
@ -168,15 +230,8 @@ impl<'a, 'b> Write for File<'a, 'b> {
break; break;
} }
self.offset += written_bytes as u32; self.offset += written_bytes as u32;
self.current_cluster = Some(current_cluster);
buf_offset += written_bytes; buf_offset += written_bytes;
if self.offset % cluster_size == 0 {
let r = self.fs.cluster_iter(current_cluster).skip(1).next();
self.current_cluster = match r {
Some(Err(err)) => return Err(err),
Some(Ok(n)) => Some(n),
None => None,
};
}
} }
self.update_size(); self.update_size();
Ok(buf_offset) Ok(buf_offset)
@ -200,11 +255,15 @@ impl<'a, 'b> Seek for File<'a, 'b> {
return Err(io::Error::new(ErrorKind::InvalidInput, "invalid seek")); return Err(io::Error::new(ErrorKind::InvalidInput, "invalid seek"));
} }
let cluster_size = self.fs.get_cluster_size(); let cluster_size = self.fs.get_cluster_size();
let cluster_count = (new_offset / cluster_size as i64) as usize; let cluster_count = ((new_offset + cluster_size as i64 - 1) / cluster_size as i64 - 1) as isize;
let new_cluster = if cluster_count > 0 { let new_cluster = if cluster_count == -1 {
None
} else if cluster_count == 0 {
self.first_cluster
} else {
match self.first_cluster { match self.first_cluster {
Some(n) => { Some(n) => {
match self.fs.cluster_iter(n).skip(cluster_count).next() { match self.fs.cluster_iter(n).skip(cluster_count as usize - 1).next() {
Some(Err(err)) => return Err(err), Some(Err(err)) => return Err(err),
Some(Ok(n)) => Some(n), Some(Ok(n)) => Some(n),
None => None, None => None,
@ -212,8 +271,6 @@ impl<'a, 'b> Seek for File<'a, 'b> {
}, },
None => None, None => None,
} }
} else {
self.first_cluster
}; };
self.offset = new_offset as u32; self.offset = new_offset as u32;
self.current_cluster = new_cluster; self.current_cluster = new_cluster;

View File

@ -1,6 +1,5 @@
use core::cell::RefCell; use core::cell::RefCell;
use core::cmp; use core::cmp;
use core::iter;
use std::io::prelude::*; use std::io::prelude::*;
use std::io::{Error, ErrorKind, SeekFrom}; use std::io::{Error, ErrorKind, SeekFrom};
use std::io; use std::io;
@ -8,7 +7,7 @@ use byteorder::{LittleEndian, ReadBytesExt};
use file::File; use file::File;
use dir::{DirRawStream, Dir}; use dir::{DirRawStream, Dir};
use table::ClusterIterator; use table::{ClusterIterator, alloc_cluster};
// FAT implementation based on: // FAT implementation based on:
// http://wiki.osdev.org/FAT // http://wiki.osdev.org/FAT
@ -92,7 +91,6 @@ impl <'a> FileSystem<'a> {
pub fn new<T: ReadWriteSeek>(disk: &'a mut T) -> io::Result<FileSystem<'a>> { pub fn new<T: ReadWriteSeek>(disk: &'a mut T) -> io::Result<FileSystem<'a>> {
let boot = Self::read_boot_record(disk)?; let boot = Self::read_boot_record(disk)?;
println!("sig {:?}", boot.boot_sig);
if boot.boot_sig != [0x55, 0xAA] { if boot.boot_sig != [0x55, 0xAA] {
return Err(Error::new(ErrorKind::Other, "invalid signature")); return Err(Error::new(ErrorKind::Other, "invalid signature"));
} }
@ -218,16 +216,25 @@ impl <'a> FileSystem<'a> {
self.offset_from_sector(self.sector_from_cluster(cluser)) self.offset_from_sector(self.sector_from_cluster(cluser))
} }
pub(crate) fn cluster_iter<'b>(&'b self, cluster: u32) -> iter::Chain<iter::Once<io::Result<u32>>, ClusterIterator<'b, 'a>> { fn fat_slice<'b>(&'b self) -> DiskSlice<'b, 'a> {
let bytes_per_sector = self.boot.bpb.bytes_per_sector as u64; let bytes_per_sector = self.boot.bpb.bytes_per_sector as u64;
let fat_offset = self.boot.bpb.reserved_sectors as u64 * bytes_per_sector; let fat_offset = self.boot.bpb.reserved_sectors as u64 * bytes_per_sector;
let sectors_per_fat = let sectors_per_fat =
if self.boot.bpb.sectors_per_fat_16 == 0 { self.boot.bpb.sectors_per_fat_32 } if self.boot.bpb.sectors_per_fat_16 == 0 { self.boot.bpb.sectors_per_fat_32 }
else { self.boot.bpb.sectors_per_fat_16 as u32 }; else { self.boot.bpb.sectors_per_fat_16 as u32 };
let fat_size = sectors_per_fat as u64 * bytes_per_sector; let fat_size = sectors_per_fat as u64 * bytes_per_sector;
let disk_slice = DiskSlice::new(fat_offset, fat_size, self); DiskSlice::new(fat_offset, fat_size, self)
}
pub(crate) fn cluster_iter<'b>(&'b self, cluster: u32) -> ClusterIterator<'b, 'a> {
let disk_slice = self.fat_slice();
ClusterIterator::new(disk_slice, self.fat_type, cluster) ClusterIterator::new(disk_slice, self.fat_type, cluster)
} }
pub(crate) fn alloc_cluster(&self, prev_cluster: Option<u32>) -> io::Result<u32> {
let mut disk_slice = self.fat_slice();
alloc_cluster(&mut disk_slice, self.fat_type, prev_cluster)
}
} }
#[derive(Clone)] #[derive(Clone)]

View File

@ -1,72 +1,248 @@
use std::io; use std::io;
use byteorder::{LittleEndian, ReadBytesExt}; use std::io::prelude::*;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use fs::{FatType, DiskSlice, ReadSeek}; use fs::{FatType, DiskSlice, ReadSeek};
use core::iter;
fn get_next_cluster(rdr: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result<Option<u32>> { 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 read_fat(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result<FatValue> {
match fat_type { match fat_type {
FatType::Fat12 => get_next_cluster_12(rdr, cluster), FatType::Fat12 => Fat12::get(fat, cluster),
FatType::Fat16 => get_next_cluster_16(rdr, cluster), FatType::Fat16 => Fat16::get(fat, cluster),
FatType::Fat32 => get_next_cluster_32(rdr, cluster), FatType::Fat32 => Fat32::get(fat, cluster),
} }
} }
fn get_next_cluster_12(rdr: &mut ReadSeek, cluster: u32) -> io::Result<Option<u32>> { fn write_fat(fat: &mut DiskSlice, fat_type: FatType, cluster: u32, value: FatValue) -> io::Result<()> {
let fat_offset = cluster + (cluster / 2); //println!("write_fat {} {:?}", cluster, value);
let mut bytes = [0;2]; match fat_type {
rdr.seek(io::SeekFrom::Start(fat_offset as u64))?; FatType::Fat12 => Fat12::set(fat, cluster, value),
rdr.read(&mut bytes)?; FatType::Fat16 => Fat16::set(fat, cluster, value),
let (val1, val2) = (bytes[0] as u16, bytes[1] as u16); FatType::Fat32 => Fat32::set(fat, cluster, value),
let val = if cluster & 1 == 1 {
(val1 >> 4) | (val2 << 4)
} else {
val1 | (val2 & 0x0F)
};
if val <= 1 || val >= 0xFF7 {
Ok(None)
} else {
Ok(Some(val as u32))
} }
} }
fn get_next_cluster_16(rdr: &mut ReadSeek, cluster: u32) -> io::Result<Option<u32>> { fn get_next_cluster(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result<Option<u32>> {
rdr.seek(io::SeekFrom::Start((cluster*2) as u64))?; let val = read_fat(fat, fat_type, cluster)?;
let val = rdr.read_u16::<LittleEndian>()?; match val {
if val <= 1 || val >= 0xFFF7 { FatValue::Data(n) => Ok(Some(n)),
Ok(None) _ => Ok(None),
} else {
Ok(Some(val as u32))
} }
} }
fn get_next_cluster_32(rdr: &mut ReadSeek, cluster: u32) -> io::Result<Option<u32>> { fn find_free_cluster(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result<u32> {
rdr.seek(io::SeekFrom::Start((cluster*4) as u64))?; match fat_type {
let val = rdr.read_u32::<LittleEndian>()? & 0x0FFFFFFF; FatType::Fat12 => Fat12::find_free(fat, cluster),
if val <= 1 || val >= 0x0FFFFFF7 { FatType::Fat16 => Fat16::find_free(fat, cluster),
Ok(None) FatType::Fat32 => Fat32::find_free(fat, cluster),
} else { }
Ok(Some(val)) }
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)?;
if prev_cluster.is_some() {
write_fat(fat, fat_type, prev_cluster.unwrap(), FatValue::Data(new_cluster))?; // safe
}
//println!("alloc_cluster {}", new_cluster);
Ok(new_cluster)
}
impl FatTrait for Fat12 {
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue> {
let fat_offset = cluster + (cluster / 2);
fat.seek(io::SeekFrom::Start(fat_offset as u64))?;
let packed_val = fat.read_u16::<LittleEndian>()?;
let val = match cluster & 1 {
0 => packed_val & 0x0FFF,
_ => packed_val >> 4,
};
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(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue> {
fat.seek(io::SeekFrom::Start((cluster*2) as u64))?;
let val = fat.read_u16::<LittleEndian>()?;
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(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue> {
fat.seek(io::SeekFrom::Start((cluster*4) as u64))?;
let val = fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF;
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> { pub(crate) struct ClusterIterator<'a, 'b: 'a> {
rdr: DiskSlice<'a, 'b>, fat: DiskSlice<'a, 'b>,
fat_type: FatType, fat_type: FatType,
cluster: Option<u32>, cluster: Option<u32>,
err: bool, err: bool,
} }
impl <'a, 'b> ClusterIterator<'a, 'b> { impl <'a, 'b> ClusterIterator<'a, 'b> {
pub(crate) fn new(rdr: DiskSlice<'a, 'b>, fat_type: FatType, cluster: u32) pub(crate) fn new(fat: DiskSlice<'a, 'b>, fat_type: FatType, cluster: u32)
-> iter::Chain<iter::Once<io::Result<u32>>, ClusterIterator<'a, 'b>> { -> ClusterIterator<'a, 'b> {
let iter = ClusterIterator { ClusterIterator {
rdr: rdr, fat: fat,
fat_type: fat_type, fat_type: fat_type,
cluster: Some(cluster), cluster: Some(cluster),
err: false, err: false,
}; }
iter::once(Ok(cluster)).chain(iter) }
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(())
} }
} }
@ -79,7 +255,7 @@ impl <'a, 'b> Iterator for ClusterIterator<'a, 'b> {
} }
match self.cluster { match self.cluster {
Some(current_cluster) => { Some(current_cluster) => {
self.cluster = match get_next_cluster(&mut self.rdr, self.fat_type, current_cluster) { self.cluster = match get_next_cluster(&mut self.fat, self.fat_type, current_cluster) {
Ok(next_cluster) => next_cluster, Ok(next_cluster) => next_cluster,
Err(err) => { Err(err) => {
self.err = true; self.err = true;

View File

@ -15,23 +15,27 @@ const IMG_DIR: &str = "resources";
const TMP_DIR: &str = "tmp"; const TMP_DIR: &str = "tmp";
const TEST_STR: &str = "Hi there Rust programmer!\n"; const TEST_STR: &str = "Hi there Rust programmer!\n";
fn call_with_fs(f: &Fn(FileSystem) -> (), filename: &str) { fn call_with_fs(f: &Fn(FileSystem) -> (), filename: &str, test_seq: u32) {
let img_path = format!("{}/{}", IMG_DIR, filename); let img_path = format!("{}/{}", IMG_DIR, filename);
let tmp_path = format!("{}/{}", TMP_DIR, filename); let tmp_path = format!("{}/{}-{}", TMP_DIR, test_seq, filename);
fs::create_dir(TMP_DIR).ok(); fs::create_dir(TMP_DIR).ok();
fs::copy(&img_path, &tmp_path).unwrap(); fs::copy(&img_path, &tmp_path).unwrap();
// let file = fs::OpenOptions::new().read(true).write(true).open(&tmp_path).unwrap(); {
// let mut buf_file = BufStream::new(file); // TODO: fix BufStream
// let fs = FileSystem::new(&mut buf_file).unwrap(); // let file = fs::OpenOptions::new().read(true).write(true).open(&tmp_path).unwrap();
let mut file = fs::OpenOptions::new().read(true).write(true).open(&tmp_path).unwrap(); // let mut buf_file = BufStream::new(file);
let fs = FileSystem::new(&mut file).unwrap(); // let fs = FileSystem::new(&mut buf_file).unwrap();
f(fs); let mut file = fs::OpenOptions::new().read(true).write(true).open(&tmp_path).unwrap();
let fs = FileSystem::new(&mut file).unwrap();
f(fs);
}
fs::remove_file(tmp_path).unwrap();
} }
fn test_write_file(fs: FileSystem) { fn test_write_short_file(fs: FileSystem) {
let mut root_dir = fs.root_dir(); let mut root_dir = fs.root_dir();
let mut file = root_dir.open_file("short.txt").expect("open file"); let mut file = root_dir.open_file("short.txt").expect("open file");
file.truncate(); file.truncate().unwrap();
assert_eq!(TEST_STR.len(), file.write(&TEST_STR.as_bytes()).unwrap()); assert_eq!(TEST_STR.len(), file.write(&TEST_STR.as_bytes()).unwrap());
file.seek(io::SeekFrom::Start(0)).unwrap(); file.seek(io::SeekFrom::Start(0)).unwrap();
let mut buf = Vec::new(); let mut buf = Vec::new();
@ -41,15 +45,48 @@ fn test_write_file(fs: FileSystem) {
#[test] #[test]
fn test_write_file_fat12() { fn test_write_file_fat12() {
call_with_fs(&test_write_file, FAT12_IMG) call_with_fs(&test_write_short_file, FAT12_IMG, 1)
} }
#[test] #[test]
fn test_write_file_fat16() { fn test_write_file_fat16() {
call_with_fs(&test_write_file, FAT16_IMG) call_with_fs(&test_write_short_file, FAT16_IMG, 1)
} }
#[test] #[test]
fn test_write_file_fat32() { fn test_write_file_fat32() {
call_with_fs(&test_write_file, FAT32_IMG) call_with_fs(&test_write_short_file, FAT32_IMG, 1)
}
fn test_write_long_file(fs: FileSystem) {
let mut root_dir = fs.root_dir();
let mut file = root_dir.open_file("long.txt").expect("open file");
file.truncate().unwrap();
let test_str = TEST_STR.repeat(100);
assert_eq!(test_str.len(), file.write(&test_str.as_bytes()).unwrap());
file.seek(io::SeekFrom::Start(0)).unwrap();
let mut buf = Vec::new();
file.read_to_end(&mut buf).unwrap();
assert_eq!(test_str, str::from_utf8(&buf).unwrap());
file.seek(io::SeekFrom::Start(1234)).unwrap();
file.truncate().unwrap();
file.seek(io::SeekFrom::Start(0)).unwrap();
buf.clear();
file.read_to_end(&mut buf).unwrap();
assert_eq!(&test_str[..1234], str::from_utf8(&buf).unwrap());
}
#[test]
fn test_write_long_file_fat12() {
call_with_fs(&test_write_long_file, FAT12_IMG, 2)
}
#[test]
fn test_write_long_file_fat16() {
call_with_fs(&test_write_long_file, FAT16_IMG, 2)
}
#[test]
fn test_write_long_file_fat32() {
call_with_fs(&test_write_long_file, FAT32_IMG, 2)
} }