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 cluster_size = self.fs.get_cluster_size();
loop {
let current_cluster = match self.current_cluster {
Some(n) => n,
None => break,
};
let offset_in_cluster = self.offset % cluster_size;
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_buf = buf.len() - buf_offset;
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;
}
let current_cluster = self.current_cluster.unwrap();
let offset_in_fs = self.fs.offset_from_cluster(current_cluster) + (offset_in_cluster as u64);
let read_bytes = {
let mut rdr = self.fs.rdr.borrow_mut();
@ -67,17 +70,22 @@ impl <'a, 'b> Seek for File<'a, 'b> {
let new_offset = match pos {
SeekFrom::Current(x) => self.offset as i64 + x,
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"));
}
let cluster_size = self.fs.get_cluster_size();
let cluster_count = (new_offset / cluster_size as i64) as usize;
let new_cluster = if cluster_count > 0 {
match self.fs.cluster_iter(self.first_cluster.unwrap()).skip(cluster_count).next() {
Some(Err(err)) => return Err(err),
Some(Ok(n)) => Some(n),
match self.first_cluster {
Some(n) => {
match self.fs.cluster_iter(n).skip(cluster_count).next() {
Some(Err(err)) => return Err(err),
Some(Ok(n)) => Some(n),
None => None,
}
},
None => None,
}
} else {

View File

@ -53,10 +53,14 @@ fn test_read_seek_short_file(fs: FileSystem) {
short_file.read_to_end(&mut buf).unwrap();
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];
short_file.read_exact(&mut buf2).unwrap();
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]
@ -81,7 +85,7 @@ fn test_read_long_file(fs: FileSystem) {
long_file.read_to_end(&mut buf).unwrap();
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();
let mut buf2 = [0; 10];
long_file.read_exact(&mut buf2).unwrap();