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

View File

@ -1,6 +1,6 @@
use std::cmp;
use std::io::prelude::*;
use std::io::SeekFrom;
use std::io::{SeekFrom, ErrorKind};
use std::io;
use fs::FatSharedStateRef;
@ -54,3 +54,26 @@ impl Read for FatFile {
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 {
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(
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
@ -280,3 +280,19 @@ impl Read for FatSlice {
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;
use std::fs::File;
use std::io::BufReader;
use std::io::{BufReader, SeekFrom};
use std::io::prelude::*;
use std::str;
@ -15,16 +15,23 @@ fn test_img(name: &str) {
let mut fs = FatFileSystem::new(Box::new(buf_rdr)).unwrap();
let mut root_dir = fs.root_dir();
let entries = root_dir.list().unwrap();
assert_eq!(entries.len(), 3);
assert_eq!(entries[0].get_name(), "LONG.TXT");
assert_eq!(entries[1].get_name(), "SHORT.TXT");
assert_eq!(entries[2].get_name(), "VERY");
let names = entries.iter().map(|e| e.get_name()).collect::<Vec<String>>();
assert_eq!(names, ["LONG.TXT", "SHORT.TXT", "VERY"]);
// Try read again
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 buf = Vec::new();
short_file.read_to_end(&mut buf).unwrap();
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..]);
}
{