From daa51e3540e26cc7c04d4ae45d218b21afaa5992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Harabie=C5=84?= Date: Sun, 24 Sep 2017 02:10:59 +0200 Subject: [PATCH] Implement Seek trait for File and rewind method in Dir. --- src/dir.rs | 14 +++++++++----- src/file.rs | 25 ++++++++++++++++++++++++- src/fs.rs | 18 +++++++++++++++++- tests/integration-test.rs | 17 ++++++++++++----- 4 files changed, 62 insertions(+), 12 deletions(-) diff --git a/src/dir.rs b/src/dir.rs index 4f2e58b..bed2740 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -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, + rdr: Box, state: FatSharedStateRef, } impl FatDir { - pub(crate) fn new(rdr: Box, state: FatSharedStateRef) -> FatDir { + pub(crate) fn new(rdr: Box, state: FatSharedStateRef) -> FatDir { FatDir { rdr, state } } pub fn list(&mut self) -> io::Result> { + 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 { 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 { - // FIXME: we should seek to beggining here let entries: Vec = self.list()?; for e in entries { if e.get_name().eq_ignore_ascii_case(name) { diff --git a/src/file.rs b/src/file.rs index 5e13d1f..d3d267c 100644 --- a/src/file.rs +++ b/src/file.rs @@ -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 { + 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) + } +} diff --git a/src/fs.rs b/src/fs.rs index 7734a53..8ebc178 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -242,7 +242,7 @@ impl FatFileSystem { pub fn root_dir(&mut self) -> FatDir { let state = self.state.borrow(); - let root_rdr: Box = match state.fat_type { + let root_rdr: Box = 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 { + 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) + } + } +} diff --git a/tests/integration-test.rs b/tests/integration-test.rs index 0c0f5bd..e54c280 100644 --- a/tests/integration-test.rs +++ b/tests/integration-test.rs @@ -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::>(); + 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::>(); + 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..]); } {