Support checking entire FAT table when hint points in the middle of it

This commit is contained in:
Rafał Harabień 2018-05-12 23:38:56 +02:00
parent 4793d20977
commit d094fd5d1d
2 changed files with 33 additions and 14 deletions

View File

@ -286,6 +286,7 @@ pub struct FileSystem<'a> {
bpb: BiosParameterBlock, bpb: BiosParameterBlock,
first_data_sector: u32, first_data_sector: u32,
root_dir_sectors: u32, root_dir_sectors: u32,
total_clusters: u32,
fs_info: Option<FsInfoSector>, fs_info: Option<FsInfoSector>,
} }
@ -338,6 +339,7 @@ impl <'a> FileSystem<'a> {
bpb: bpb, bpb: bpb,
first_data_sector, first_data_sector,
root_dir_sectors, root_dir_sectors,
total_clusters,
fs_info, fs_info,
}) })
} }
@ -419,7 +421,7 @@ impl <'a> FileSystem<'a> {
None => None, None => None,
}; };
let mut fat = self.fat_slice(); let mut fat = self.fat_slice();
alloc_cluster(&mut fat, self.fat_type, prev_cluster, hint) alloc_cluster(&mut fat, self.fat_type, prev_cluster, hint, self.total_clusters)
} }
pub fn read_status_flags(&self) -> io::Result<FsStatusFlags> { pub fn read_status_flags(&self) -> io::Result<FsStatusFlags> {

View File

@ -24,7 +24,7 @@ enum FatValue {
trait FatTrait { trait FatTrait {
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue>; fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue>;
fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()>; fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()>;
fn find_free(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result<u32>; fn find_free(fat: &mut ReadSeek, start_cluster: u32, end_cluster: u32) -> io::Result<u32>;
fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result<u32>; fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result<u32>;
} }
@ -53,16 +53,24 @@ fn get_next_cluster(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::
} }
} }
fn find_free_cluster(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result<u32> { fn find_free_cluster(fat: &mut ReadSeek, fat_type: FatType, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
match fat_type { match fat_type {
FatType::Fat12 => Fat12::find_free(fat, cluster), FatType::Fat12 => Fat12::find_free(fat, start_cluster, end_cluster),
FatType::Fat16 => Fat16::find_free(fat, cluster), FatType::Fat16 => Fat16::find_free(fat, start_cluster, end_cluster),
FatType::Fat32 => Fat32::find_free(fat, cluster), FatType::Fat32 => Fat32::find_free(fat, start_cluster, end_cluster),
} }
} }
pub(crate) fn alloc_cluster(fat: &mut DiskSlice, fat_type: FatType, prev_cluster: Option<u32>, hint: Option<u32>) -> io::Result<u32> { pub(crate) fn alloc_cluster(fat: &mut DiskSlice, fat_type: FatType, prev_cluster: Option<u32>, hint: Option<u32>, total_clusters: u32) -> io::Result<u32> {
let new_cluster = find_free_cluster(fat, fat_type, hint.unwrap_or(2))?; let start_cluster = match hint {
Some(n) if n < total_clusters => n,
_ => 2,
};
let new_cluster = match find_free_cluster(fat, fat_type, start_cluster, total_clusters) {
Ok(n) => n,
Err(_) if start_cluster > 2 => find_free_cluster(fat, fat_type, 2, start_cluster)?,
Err(e) => return Err(e),
};
write_fat(fat, fat_type, new_cluster, FatValue::EndOfChain)?; write_fat(fat, fat_type, new_cluster, FatValue::EndOfChain)?;
match prev_cluster { match prev_cluster {
Some(n) => write_fat(fat, fat_type, n, FatValue::Data(new_cluster))?, Some(n) => write_fat(fat, fat_type, n, FatValue::Data(new_cluster))?,
@ -136,8 +144,8 @@ impl FatTrait for Fat12 {
Ok(()) Ok(())
} }
fn find_free(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result<u32> { fn find_free(fat: &mut ReadSeek, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
let mut cluster = hint_cluster; let mut cluster = start_cluster;
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 mut packed_val = fat.read_u16::<LittleEndian>()?; let mut packed_val = fat.read_u16::<LittleEndian>()?;
@ -150,6 +158,9 @@ impl FatTrait for Fat12 {
return Ok(cluster); return Ok(cluster);
} }
cluster += 1; cluster += 1;
if cluster == end_cluster {
return Err(io::Error::new(io::ErrorKind::Other, "end of FAT reached"));
}
packed_val = match cluster & 1 { packed_val = match cluster & 1 {
0 => fat.read_u16::<LittleEndian>()?, 0 => fat.read_u16::<LittleEndian>()?,
_ => { _ => {
@ -189,8 +200,8 @@ impl FatTrait for Fat16 {
Ok(()) Ok(())
} }
fn find_free(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result<u32> { fn find_free(fat: &mut ReadSeek, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
let mut cluster = hint_cluster; let mut cluster = start_cluster;
fat.seek(io::SeekFrom::Start((cluster*2) as u64))?; fat.seek(io::SeekFrom::Start((cluster*2) as u64))?;
loop { loop {
let val = fat.read_u16::<LittleEndian>()?; let val = fat.read_u16::<LittleEndian>()?;
@ -198,6 +209,9 @@ impl FatTrait for Fat16 {
return Ok(cluster); return Ok(cluster);
} }
cluster += 1; cluster += 1;
if cluster == end_cluster {
return Err(io::Error::new(io::ErrorKind::Other, "end of FAT reached"));
}
} }
} }
} }
@ -230,8 +244,8 @@ impl FatTrait for Fat32 {
Ok(()) Ok(())
} }
fn find_free(fat: &mut ReadSeek, hint_cluster: u32) -> io::Result<u32> { fn find_free(fat: &mut ReadSeek, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
let mut cluster = hint_cluster; let mut cluster = start_cluster;
fat.seek(io::SeekFrom::Start((cluster*4) as u64))?; fat.seek(io::SeekFrom::Start((cluster*4) as u64))?;
loop { loop {
let val = fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF; let val = fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF;
@ -239,6 +253,9 @@ impl FatTrait for Fat32 {
return Ok(cluster); return Ok(cluster);
} }
cluster += 1; cluster += 1;
if cluster == end_cluster {
return Err(io::Error::new(io::ErrorKind::Other, "end of FAT reached"));
}
} }
} }
} }