Fix seek for directory backed file.

This commit is contained in:
Rafał Harabień 2017-10-15 15:56:01 +02:00
parent da76625759
commit e2374c08cc
2 changed files with 40 additions and 14 deletions

View File

@ -37,6 +37,21 @@ impl <'a, 'b> Read for DirRawStream<'a, 'b> {
} }
} }
impl <'a, 'b> Write for DirRawStream<'a, 'b> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self {
&mut DirRawStream::File(ref mut file) => file.write(buf),
&mut DirRawStream::Root(ref mut raw) => raw.write(buf),
}
}
fn flush(&mut self) -> io::Result<()> {
match self {
&mut DirRawStream::File(ref mut file) => file.flush(),
&mut DirRawStream::Root(ref mut raw) => raw.flush(),
}
}
}
impl <'a, 'b> Seek for DirRawStream<'a, 'b> { impl <'a, 'b> Seek for DirRawStream<'a, 'b> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
match self { match self {
@ -89,8 +104,12 @@ impl DirFileEntryData {
self.first_cluster_lo = (n & 0xFFFF) as u16; self.first_cluster_lo = (n & 0xFFFF) as u16;
} }
pub(crate) fn size(&self) -> u32 { pub(crate) fn size(&self) -> Option<u32> {
self.size if self.is_file() {
Some(self.size)
} else {
None
}
} }
pub(crate) fn set_size(&mut self, size: u32) { pub(crate) fn set_size(&mut self, size: u32) {

View File

@ -32,10 +32,11 @@ impl <'a, 'b> File<'a, 'b> {
} }
fn update_size(&mut self) { fn update_size(&mut self) {
let offset = self.offset;
match self.entry { match self.entry {
Some(ref mut e) => { Some(ref mut e) => {
if self.offset > e.data.size() { if e.data.size().map_or(false, |s| offset > s) {
e.data.set_size(self.offset); e.data.set_size(offset);
self.entry_dirty = true; self.entry_dirty = true;
} }
}, },
@ -44,9 +45,10 @@ impl <'a, 'b> File<'a, 'b> {
} }
pub fn truncate(&mut self) -> io::Result<()> { pub fn truncate(&mut self) -> io::Result<()> {
let offset = self.offset;
match self.entry { match self.entry {
Some(ref mut e) => { Some(ref mut e) => {
if e.data.size() == self.offset { if e.data.size().map_or(false, |s| offset == s) {
return Ok(()); return Ok(());
} }
@ -108,13 +110,7 @@ impl <'a, 'b> File<'a, 'b> {
fn bytes_left_in_file(&self) -> Option<usize> { fn bytes_left_in_file(&self) -> Option<usize> {
match self.entry { match self.entry {
Some(ref e) => { Some(ref e) => e.data.size().map(|s| (s - self.offset) as usize),
if e.data.is_file() {
Some((e.data.size() - self.offset) as usize)
} else {
None
}
},
None => None, None => None,
} }
} }
@ -253,15 +249,26 @@ impl<'a, 'b> Seek for File<'a, 'b> {
let mut new_pos = match pos { let mut new_pos = 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.entry.iter().next().expect("cannot seek from end if size is unknown").data.size() as i64 + x, SeekFrom::End(x) => self.entry.iter().next().map_or(None, |e| e.data.size()).expect("cannot seek from end if size is unknown") as i64 + x,
}; };
if new_pos < 0 { if new_pos < 0 {
return Err(io::Error::new(ErrorKind::InvalidInput, "invalid seek")); return Err(io::Error::new(ErrorKind::InvalidInput, "invalid seek"));
} }
new_pos = match self.entry { new_pos = match self.entry {
Some(ref e) => cmp::min(new_pos, e.data.size() as i64), Some(ref e) => {
if e.data.size().map_or(false, |s| new_pos > s as i64) {
info!("seek beyond end of file");
e.data.size().unwrap() as i64 // safe
} else {
new_pos
}
},
_ => new_pos, _ => new_pos,
}; };
trace!("file seek {} -> {} - entry {:?}", self.offset, new_pos, self.entry);
if new_pos == self.offset as i64 {
return Ok(self.offset as u64);
}
let cluster_size = self.fs.get_cluster_size(); let cluster_size = self.fs.get_cluster_size();
let new_cluster = if new_pos == 0 { let new_cluster = if new_pos == 0 {
None None