Allow seeking beyond end of file as documented in Seek trait.

Also fix possible panic when seeking in file without clusters.
This commit is contained in:
Rafał Harabień 2017-10-07 16:07:33 +02:00
parent 120c9b035c
commit d32ae0eef9
2 changed files with 21 additions and 9 deletions

View File

@ -29,15 +29,18 @@ 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 {
Some(n) => n,
None => break,
};
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_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 || self.current_cluster.is_none() { if read_size == 0 {
break; break;
} }
let current_cluster = self.current_cluster.unwrap();
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 rdr = self.fs.rdr.borrow_mut(); let mut rdr = self.fs.rdr.borrow_mut();
@ -67,19 +70,24 @@ impl <'a, 'b> Seek for File<'a, 'b> {
let new_offset = match pos { let new_offset = match pos {
SeekFrom::Current(x) => self.offset as i64 + x, SeekFrom::Current(x) => self.offset as i64 + x,
SeekFrom::Start(x) => x as i64, SeekFrom::Start(x) => x as i64,
SeekFrom::End(x) => self.size.unwrap() as i64 + x, SeekFrom::End(x) => self.size.expect("cannot seek from end if size is unknown") as i64 + x,
}; };
if new_offset < 0 || (self.size.is_some() && new_offset as u64 > self.size.unwrap() as u64) { if new_offset < 0 {
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) as usize;
let new_cluster = if cluster_count > 0 { let new_cluster = if cluster_count > 0 {
match self.fs.cluster_iter(self.first_cluster.unwrap()).skip(cluster_count).next() { match self.first_cluster {
Some(n) => {
match self.fs.cluster_iter(n).skip(cluster_count).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,
} }
},
None => None,
}
} else { } else {
self.first_cluster self.first_cluster
}; };

View File

@ -53,10 +53,14 @@ fn test_read_seek_short_file(fs: FileSystem) {
short_file.read_to_end(&mut buf).unwrap(); short_file.read_to_end(&mut buf).unwrap();
assert_eq!(str::from_utf8(&buf).unwrap(), TEST_TEXT); assert_eq!(str::from_utf8(&buf).unwrap(), TEST_TEXT);
short_file.seek(SeekFrom::Start(5)).unwrap(); assert_eq!(short_file.seek(SeekFrom::Start(5)).unwrap(), 5);
let mut buf2 = [0; 5]; let mut buf2 = [0; 5];
short_file.read_exact(&mut buf2).unwrap(); short_file.read_exact(&mut buf2).unwrap();
assert_eq!(str::from_utf8(&buf2).unwrap(), &TEST_TEXT[5..10]); assert_eq!(str::from_utf8(&buf2).unwrap(), &TEST_TEXT[5..10]);
assert_eq!(short_file.seek(SeekFrom::Start(1000)).unwrap(), 1000);
let mut buf2 = [0; 5];
assert_eq!(short_file.read(&mut buf2).unwrap(), 0);
} }
#[test] #[test]
@ -81,7 +85,7 @@ fn test_read_long_file(fs: FileSystem) {
long_file.read_to_end(&mut buf).unwrap(); long_file.read_to_end(&mut buf).unwrap();
assert_eq!(str::from_utf8(&buf).unwrap(), TEST_TEXT.repeat(1000)); assert_eq!(str::from_utf8(&buf).unwrap(), TEST_TEXT.repeat(1000));
long_file.seek(SeekFrom::Start(2017)).unwrap(); assert_eq!(long_file.seek(SeekFrom::Start(2017)).unwrap(), 2017);
buf.clear(); buf.clear();
let mut buf2 = [0; 10]; let mut buf2 = [0; 10];
long_file.read_exact(&mut buf2).unwrap(); long_file.read_exact(&mut buf2).unwrap();