Fix possible panics if cluster chain ends before EOF.

This commit is contained in:
Rafał Harabień 2017-10-07 02:37:29 +02:00
parent 3e08c80fb0
commit beb463ba3f
3 changed files with 20 additions and 17 deletions

View File

@ -180,8 +180,9 @@ impl <'a, 'b> FatDirEntry<'a, 'b> {
!self.is_dir() !self.is_dir()
} }
pub(crate) fn first_cluster(&self) -> u32 { pub(crate) fn first_cluster(&self) -> Option<u32> {
((self.data.first_cluster_hi as u32) << 16) | self.data.first_cluster_lo as u32 let n = ((self.data.first_cluster_hi as u32) << 16) | self.data.first_cluster_lo as u32;
if n == 0 { None } else { Some(n) }
} }
pub fn to_file(&self) -> FatFile<'a, 'b> { pub fn to_file(&self) -> FatFile<'a, 'b> {

View File

@ -7,7 +7,7 @@ use fs::FatFileSystemRef;
#[derive(Clone)] #[derive(Clone)]
pub struct FatFile<'a, 'b: 'a> { pub struct FatFile<'a, 'b: 'a> {
first_cluster: u32, first_cluster: Option<u32>,
size: Option<u32>, size: Option<u32>,
offset: u32, offset: u32,
current_cluster: Option<u32>, current_cluster: Option<u32>,
@ -15,10 +15,10 @@ pub struct FatFile<'a, 'b: 'a> {
} }
impl <'a, 'b> FatFile<'a, 'b> { impl <'a, 'b> FatFile<'a, 'b> {
pub(crate) fn new(first_cluster: u32, size: Option<u32>, fs: FatFileSystemRef<'a, 'b>) -> Self { pub(crate) fn new(first_cluster: Option<u32>, size: Option<u32>, fs: FatFileSystemRef<'a, 'b>) -> Self {
FatFile { FatFile {
first_cluster, size, fs, first_cluster, size, fs,
current_cluster: Some(first_cluster), current_cluster: first_cluster,
offset: 0, offset: 0,
} }
} }
@ -34,7 +34,7 @@ impl <'a, 'b> Read for FatFile<'a, 'b> {
let bytes_left_in_file = self.size.map(|size| (size - self.offset) as usize).unwrap_or(bytes_left_in_cluster); let bytes_left_in_file = self.size.map(|size| (size - self.offset) as usize).unwrap_or(bytes_left_in_cluster);
let bytes_left_in_buf = buf.len() - buf_offset; let bytes_left_in_buf = buf.len() - buf_offset;
let read_size = cmp::min(cmp::min(bytes_left_in_buf, bytes_left_in_cluster), bytes_left_in_file); let read_size = cmp::min(cmp::min(bytes_left_in_buf, bytes_left_in_cluster), bytes_left_in_file);
if read_size == 0 { if read_size == 0 || self.current_cluster.is_none() {
break; break;
} }
let current_cluster = self.current_cluster.unwrap(); let current_cluster = self.current_cluster.unwrap();
@ -50,11 +50,12 @@ impl <'a, 'b> Read for FatFile<'a, 'b> {
self.offset += read_bytes as u32; self.offset += read_bytes as u32;
buf_offset += read_bytes; buf_offset += read_bytes;
if self.offset % cluster_size == 0 { if self.offset % cluster_size == 0 {
match self.fs.cluster_iter(current_cluster).skip(1).next() { let r = self.fs.cluster_iter(current_cluster).skip(1).next();
self.current_cluster = match r {
Some(Err(err)) => return Err(err), Some(Err(err)) => return Err(err),
Some(Ok(n)) => self.current_cluster = Some(n), Some(Ok(n)) => Some(n),
None => self.current_cluster = None, None => None,
} };
} }
} }
Ok(buf_offset) Ok(buf_offset)
@ -73,14 +74,15 @@ impl <'a, 'b> Seek for FatFile<'a, 'b> {
} }
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) as usize;
let mut new_cluster = Some(self.first_cluster); let new_cluster = if cluster_count > 0 {
if cluster_count > 0 { match self.fs.cluster_iter(self.first_cluster.unwrap()).skip(cluster_count).next() {
match self.fs.cluster_iter(new_cluster.unwrap()).skip(cluster_count).next() {
Some(Err(err)) => return Err(err), Some(Err(err)) => return Err(err),
Some(Ok(n)) => new_cluster = Some(n), Some(Ok(n)) => Some(n),
None => new_cluster = 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;
Ok(self.offset as u64) Ok(self.offset as u64)

View File

@ -127,7 +127,7 @@ impl <'a> FatFileSystem<'a> {
match self.fat_type { match self.fat_type {
FatType::Fat12 | FatType::Fat16 => FatDirReader::Root(FatSlice::from_sectors( FatType::Fat12 | FatType::Fat16 => FatDirReader::Root(FatSlice::from_sectors(
self.first_data_sector - self.root_dir_sectors, self.root_dir_sectors, self)), self.first_data_sector - self.root_dir_sectors, self.root_dir_sectors, self)),
_ => FatDirReader::File(FatFile::new(self.boot.bpb.root_dir_first_cluster, None, self)), _ => FatDirReader::File(FatFile::new(Some(self.boot.bpb.root_dir_first_cluster), None, self)),
} }
}; };
FatDir::new(root_rdr, self) FatDir::new(root_rdr, self)