Implement Seek trait for File and rewind method in Dir.

This commit is contained in:
Rafał Harabień 2017-09-24 02:10:59 +02:00
parent 8d974a6ee4
commit daa51e3540
4 changed files with 62 additions and 12 deletions

View File

@ -1,12 +1,12 @@
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::io::prelude::*; use std::io::prelude::*;
use std::io; use std::io;
use std::io::ErrorKind; use std::io::{ErrorKind, SeekFrom};
use std::str; use std::str;
use byteorder::{LittleEndian, ReadBytesExt}; use byteorder::{LittleEndian, ReadBytesExt};
use chrono::{DateTime, Date, TimeZone, Local}; use chrono::{DateTime, Date, TimeZone, Local};
use fs::FatSharedStateRef; use fs::{FatSharedStateRef, ReadSeek};
use file::FatFile; use file::FatFile;
bitflags! { bitflags! {
@ -103,17 +103,18 @@ impl FatDirEntry {
} }
pub struct FatDir { pub struct FatDir {
rdr: Box<Read>, rdr: Box<ReadSeek>,
state: FatSharedStateRef, state: FatSharedStateRef,
} }
impl FatDir { impl FatDir {
pub(crate) fn new(rdr: Box<Read>, state: FatSharedStateRef) -> FatDir { pub(crate) fn new(rdr: Box<ReadSeek>, state: FatSharedStateRef) -> FatDir {
FatDir { rdr, state } FatDir { rdr, state }
} }
pub fn list(&mut self) -> io::Result<Vec<FatDirEntry>> { pub fn list(&mut self) -> io::Result<Vec<FatDirEntry>> {
self.rewind();
let mut entries = Vec::new(); let mut entries = Vec::new();
loop { loop {
let entry = self.read_dir_entry()?; let entry = self.read_dir_entry()?;
@ -132,6 +133,10 @@ impl FatDir {
Ok(entries) Ok(entries)
} }
pub fn rewind(&mut self) {
self.rdr.seek(SeekFrom::Start(0)).unwrap();
}
fn read_dir_entry(&mut self) -> io::Result<FatDirEntry> { fn read_dir_entry(&mut self) -> io::Result<FatDirEntry> {
let mut name = [0; 11]; let mut name = [0; 11];
self.rdr.read(&mut name)?; self.rdr.read(&mut name)?;
@ -161,7 +166,6 @@ impl FatDir {
} }
fn find_entry(&mut self, name: &str) -> io::Result<FatDirEntry> { fn find_entry(&mut self, name: &str) -> io::Result<FatDirEntry> {
// FIXME: we should seek to beggining here
let entries: Vec<FatDirEntry> = self.list()?; let entries: Vec<FatDirEntry> = self.list()?;
for e in entries { for e in entries {
if e.get_name().eq_ignore_ascii_case(name) { if e.get_name().eq_ignore_ascii_case(name) {

View File

@ -1,6 +1,6 @@
use std::cmp; use std::cmp;
use std::io::prelude::*; use std::io::prelude::*;
use std::io::SeekFrom; use std::io::{SeekFrom, ErrorKind};
use std::io; use std::io;
use fs::FatSharedStateRef; use fs::FatSharedStateRef;
@ -54,3 +54,26 @@ impl Read for FatFile {
Ok(buf_offset) Ok(buf_offset)
} }
} }
impl Seek for FatFile {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
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,
};
if new_offset < 0 || (self.size.is_some() && new_offset as u64 > self.size.unwrap() as u64) {
return Err(io::Error::new(ErrorKind::InvalidInput, "invalid seek"));
}
let cluster_size = self.state.borrow().get_cluster_size();
let cluster_count = (new_offset / cluster_size as i64) as usize;
let mut new_cluster = Some(self.first_cluster);
let state = self.state.borrow_mut();
for _ in 0..cluster_count {
new_cluster = state.table.get_next_cluster(new_cluster.unwrap());
}
self.offset = new_offset as u32;
self.current_cluster = new_cluster;
Ok(self.offset as u64)
}
}

View File

@ -242,7 +242,7 @@ impl FatFileSystem {
pub fn root_dir(&mut self) -> FatDir { pub fn root_dir(&mut self) -> FatDir {
let state = self.state.borrow(); let state = self.state.borrow();
let root_rdr: Box<Read> = match state.fat_type { let root_rdr: Box<ReadSeek> = match state.fat_type {
FatType::Fat12 | FatType::Fat16 => Box::new(FatSlice::from_sectors( FatType::Fat12 | FatType::Fat16 => Box::new(FatSlice::from_sectors(
state.first_data_sector - state.root_dir_sectors, state.root_dir_sectors, self.state.clone())), state.first_data_sector - state.root_dir_sectors, state.root_dir_sectors, self.state.clone())),
_ => Box::new(FatFile::new(state.boot.bpb.root_cluster, None, self.state.clone())) // FIXME _ => Box::new(FatFile::new(state.boot.bpb.root_cluster, None, self.state.clone())) // FIXME
@ -280,3 +280,19 @@ impl Read for FatSlice {
Ok(size) Ok(size)
} }
} }
impl Seek for FatSlice {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let new_offset = match pos {
SeekFrom::Current(x) => self.offset as i64 + x,
SeekFrom::Start(x) => x as i64,
SeekFrom::End(x) => self.size as i64 + x,
};
if new_offset < 0 || new_offset as u64 > self.size {
Err(io::Error::new(ErrorKind::InvalidInput, "invalid seek"))
} else {
self.offset = new_offset as u64;
Ok(self.offset)
}
}
}

View File

@ -1,7 +1,7 @@
extern crate rustfat; extern crate rustfat;
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::{BufReader, SeekFrom};
use std::io::prelude::*; use std::io::prelude::*;
use std::str; use std::str;
@ -15,16 +15,23 @@ fn test_img(name: &str) {
let mut fs = FatFileSystem::new(Box::new(buf_rdr)).unwrap(); let mut fs = FatFileSystem::new(Box::new(buf_rdr)).unwrap();
let mut root_dir = fs.root_dir(); let mut root_dir = fs.root_dir();
let entries = root_dir.list().unwrap(); let entries = root_dir.list().unwrap();
assert_eq!(entries.len(), 3); let names = entries.iter().map(|e| e.get_name()).collect::<Vec<String>>();
assert_eq!(entries[0].get_name(), "LONG.TXT"); assert_eq!(names, ["LONG.TXT", "SHORT.TXT", "VERY"]);
assert_eq!(entries[1].get_name(), "SHORT.TXT"); // Try read again
assert_eq!(entries[2].get_name(), "VERY"); let entries = root_dir.list().unwrap();
let names2 = entries.iter().map(|e| e.get_name()).collect::<Vec<String>>();
assert_eq!(names2, names);
{ {
let mut short_file = entries[1].get_file(); let mut short_file = entries[1].get_file();
let mut buf = Vec::new(); let mut buf = Vec::new();
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();
buf.clear();
short_file.read_to_end(&mut buf).unwrap();
assert_eq!(str::from_utf8(&buf).unwrap(), &TEST_TEXT[5..]);
} }
{ {