Move BufStream to fscommon crate (BREAKING CHANGE)

BufStream is universal and can be used with any filesystem so its place is
in different crate. Also moved Partition struct from examples to
fscommon::StreamSlice struct (please note constructor arguments has changed).
This commit is contained in:
Rafał Harabień 2018-06-16 17:57:29 +02:00
parent 5f7fb04084
commit 892c3974d3
9 changed files with 21 additions and 207 deletions

View File

@ -34,3 +34,4 @@ core_io = { version = "0.1", optional = true }
[dev-dependencies]
env_logger = "0.5"
fscommon = "0.1"

View File

@ -1,10 +1,12 @@
extern crate fatfs;
extern crate fscommon;
use std::env;
use std::fs::File;
use std::io::{self, prelude::*};
use fatfs::{FileSystem, FsOptions, BufStream};
use fatfs::{FileSystem, FsOptions};
use fscommon::BufStream;
fn main() -> io::Result<()> {
let file = File::open("resources/fat32.img")?;

View File

@ -1,4 +1,5 @@
extern crate fatfs;
extern crate fscommon;
extern crate chrono;
use std::env;
@ -6,7 +7,8 @@ use std::fs::File;
use std::io;
use chrono::{DateTime, Local};
use fatfs::{FileSystem, FsOptions, BufStream};
use fatfs::{FileSystem, FsOptions};
use fscommon::BufStream;
fn format_file_size(size: u64) -> String {
const KB: u64 = 1024;

View File

@ -1,69 +1,9 @@
extern crate fatfs;
extern crate fscommon;
use std::{cmp, fs, io};
use std::io::{prelude::*, SeekFrom, ErrorKind};
use fatfs::{FileSystem, FsOptions, BufStream};
trait ReadWriteSeek: Read + Write + Seek {}
impl<T> ReadWriteSeek for T where T: Read + Write + Seek {}
// File wrapper for accessing part of file
#[derive(Clone)]
pub(crate) struct Partition<T: ReadWriteSeek> {
inner: T,
start_offset: u64,
current_offset: u64,
size: u64,
}
impl <T: ReadWriteSeek> Partition<T> {
pub(crate) fn new(mut inner: T, start_offset: u64, size: u64) -> io::Result<Self> {
inner.seek(SeekFrom::Start(start_offset))?;
Ok(Self {
start_offset, size, inner,
current_offset: 0,
})
}
}
impl <T: ReadWriteSeek> Read for Partition<T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let max_read_size = cmp::min((self.size - self.current_offset) as usize, buf.len());
let bytes_read = self.inner.read(&mut buf[..max_read_size])?;
self.current_offset += bytes_read as u64;
Ok(bytes_read)
}
}
impl <T: ReadWriteSeek> Write for Partition<T> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let max_write_size = cmp::min((self.size - self.current_offset) as usize, buf.len());
let bytes_written = self.inner.write(&buf[..max_write_size])?;
self.current_offset += bytes_written as u64;
Ok(bytes_written)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
impl <T: ReadWriteSeek> Seek for Partition<T> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let new_offset = match pos {
SeekFrom::Current(x) => self.current_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.inner.seek(SeekFrom::Start(self.start_offset + new_offset as u64))?;
self.current_offset = new_offset as u64;
Ok(self.current_offset)
}
}
}
use std::{fs, io};
use fatfs::{FileSystem, FsOptions};
use fscommon::{BufStream, StreamSlice};
fn main() -> io::Result<()> {
// Open disk image
@ -72,7 +12,7 @@ fn main() -> io::Result<()> {
let first_lba = 0;
let last_lba = 10000;
// Create partition using provided start address and size in bytes
let partition = Partition::<fs::File>::new(file, first_lba, last_lba - first_lba + 1)?;
let partition = StreamSlice::new(file, first_lba, last_lba + 1)?;
// Create buffered stream to optimize file access
let buf_rdr = BufStream::new(partition);
// Finally initialize filesystem struct using provided partition

View File

@ -1,9 +1,11 @@
extern crate fatfs;
extern crate fscommon;
use std::fs::OpenOptions;
use std::io::{self, prelude::*};
use fatfs::{FileSystem, FsOptions, BufStream};
use fatfs::{FileSystem, FsOptions};
use fscommon::BufStream;
fn main() -> io::Result<()> {
let img_file = match OpenOptions::new().read(true).write(true).open("fat.img") {

View File

@ -30,9 +30,6 @@ mod dir_entry;
mod file;
mod table;
#[cfg(all(feature = "alloc"))]
mod utils;
#[cfg(not(feature = "std"))]
mod byteorder_core_io;
@ -52,6 +49,3 @@ pub use fs::*;
pub use dir::*;
pub use dir_entry::*;
pub use file::*;
#[cfg(all(feature = "alloc"))]
pub use utils::*;

View File

@ -1,131 +0,0 @@
use io::prelude::*;
use io;
use core::cmp;
const BUF_SIZE: usize = 512;
pub struct BufStream<T: Read+Write+Seek> {
inner: T,
buf: [u8; BUF_SIZE],
len: usize,
pos: usize,
write: bool,
}
/// The BufStream struct adds buffering to underlying file or device.
///
/// It's basically composition of BufReader and BufWritter.
impl<T: Read+Write+Seek> BufStream<T> {
/// Creates new BufStream object for given stream.
pub fn new(inner: T) -> Self {
BufStream::<T> {
inner,
buf: [0; BUF_SIZE],
pos: 0,
len: 0,
write: false,
}
}
fn flush_buf(&mut self) -> io::Result<()> {
if self.write {
self.inner.write_all(&self.buf[..self.pos])?;
self.pos = 0;
}
Ok(())
}
fn make_reader(&mut self) -> io::Result<()> {
if self.write {
self.flush_buf()?;
self.write = false;
self.len = 0;
self.pos = 0;
}
Ok(())
}
fn make_writter(&mut self) -> io::Result<()> {
if !self.write {
self.inner.seek(io::SeekFrom::Current(-(self.len as i64 - self.pos as i64)))?;
self.write = true;
self.len = 0;
self.pos = 0;
}
Ok(())
}
}
impl<T: Read+Write+Seek> BufRead for BufStream<T> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.make_reader()?;
if self.pos >= self.len {
self.len = self.inner.read(&mut self.buf)?;
self.pos = 0;
}
Ok(&self.buf[self.pos..self.len])
}
fn consume(&mut self, amt: usize) {
self.pos = cmp::min(self.pos + amt, self.len);
}
}
impl<T: Read+Write+Seek> Read for BufStream<T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
// Make sure we are in read mode
self.make_reader()?;
// Check if this read is bigger than buffer size
if self.pos == self.len && buf.len() >= BUF_SIZE {
return self.inner.read(buf);
}
let nread = {
let mut rem = self.fill_buf()?;
rem.read(buf)?
};
self.consume(nread);
Ok(nread)
}
}
impl<T: Read+Write+Seek> Write for BufStream<T> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
// Make sure we are in write mode
self.make_writter()?;
if self.pos + buf.len() > BUF_SIZE {
self.flush_buf()?;
if buf.len() >= BUF_SIZE {
return self.inner.write(buf);
}
}
let written = (&mut self.buf[self.pos..]).write(buf)?;
self.pos += written;
Ok(written)
}
fn flush(&mut self) -> io::Result<()> {
self.flush_buf()?;
self.inner.flush()
}
}
impl<T: Read+Write+Seek> Seek for BufStream<T> {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
self.flush_buf()?;
let new_pos = match pos {
io::SeekFrom::Current(x) => io::SeekFrom::Current(x - (self.len as i64 - self.pos as i64)),
_ => pos,
};
self.pos = 0;
self.len = 0;
self.inner.seek(new_pos)
}
}
impl<T: Read+Write+Seek> Drop for BufStream<T> {
fn drop(&mut self) {
if let Err(err) = self.flush() {
error!("flush failed {}", err);
}
}
}

View File

@ -1,4 +1,5 @@
extern crate fatfs;
extern crate fscommon;
extern crate env_logger;
use std::fs;
@ -6,7 +7,8 @@ use std::io::SeekFrom;
use std::io::prelude::*;
use std::str;
use fatfs::{FsOptions, FatType, BufStream};
use fatfs::{FsOptions, FatType};
use fscommon::BufStream;
const TEST_TEXT: &str = "Rust is cool!\n";
const FAT12_IMG: &str = "resources/fat12.img";

View File

@ -1,4 +1,5 @@
extern crate fatfs;
extern crate fscommon;
extern crate env_logger;
use std::fs;
@ -6,7 +7,8 @@ use std::io::prelude::*;
use std::io;
use std::str;
use fatfs::{FsOptions, BufStream};
use fatfs::FsOptions;
use fscommon::BufStream;
const FAT12_IMG: &str = "fat12.img";
const FAT16_IMG: &str = "fat16.img";