Make disk object type generic (breaking change)
This change allows for moving an object ownership to FileSystem object instead of borrowing it. It makes usage of library easier in some cases. Unfortunately it is a breaking change.
This commit is contained in:
parent
b1894a435e
commit
217b6046f1
@ -33,8 +33,8 @@ Put this in your crate root:
|
||||
You can start using library now:
|
||||
|
||||
let img_file = File::open("fat.img")?;
|
||||
let mut buf_stream = fatfs::BufStream::new(img_file);
|
||||
let fs = fatfs::FileSystem::new(&mut buf_stream, fatfs::FsOptions::new())?;
|
||||
let buf_stream = fatfs::BufStream::new(img_file);
|
||||
let fs = fatfs::FileSystem::new(buf_stream, fatfs::FsOptions::new())?;
|
||||
let root_dir = fs.root_dir();
|
||||
let mut file = root_dir.create_file("hello.txt")?;
|
||||
file.write_all(b"Hello World!")?;
|
||||
|
95
src/dir.rs
95
src/dir.rs
@ -6,7 +6,7 @@ use io::prelude::*;
|
||||
use io;
|
||||
use io::{ErrorKind, SeekFrom};
|
||||
|
||||
use fs::{FileSystemRef, DiskSlice};
|
||||
use fs::{FileSystem, DiskSlice, ReadWriteSeek};
|
||||
use file::File;
|
||||
use dir_entry::{DirEntry, DirEntryData, DirFileEntryData, DirLfnEntryData, FileAttributes, ShortName, DIR_ENTRY_SIZE};
|
||||
|
||||
@ -16,13 +16,12 @@ use dir_entry::{LFN_PART_LEN, LFN_ENTRY_LAST_FLAG};
|
||||
#[cfg(all(not(feature = "std"), feature = "alloc"))]
|
||||
use alloc::Vec;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum DirRawStream<'a, 'b: 'a> {
|
||||
File(File<'a, 'b>),
|
||||
Root(DiskSlice<'a, 'b>),
|
||||
pub(crate) enum DirRawStream<'a, T: ReadWriteSeek + 'a> {
|
||||
File(File<'a, T>),
|
||||
Root(DiskSlice<'a, T>),
|
||||
}
|
||||
|
||||
impl <'a, 'b> DirRawStream<'a, 'b> {
|
||||
impl <'a, T: ReadWriteSeek> DirRawStream<'a, T> {
|
||||
fn abs_pos(&self) -> Option<u64> {
|
||||
match self {
|
||||
&DirRawStream::File(ref file) => file.abs_pos(),
|
||||
@ -38,7 +37,17 @@ impl <'a, 'b> DirRawStream<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, 'b> Read for DirRawStream<'a, 'b> {
|
||||
// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925
|
||||
impl <'a, T: ReadWriteSeek> Clone for DirRawStream<'a, T> {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
&DirRawStream::File(ref file) => DirRawStream::File(file.clone()),
|
||||
&DirRawStream::Root(ref raw) => DirRawStream::Root(raw.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, T: ReadWriteSeek> Read for DirRawStream<'a, T> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
match self {
|
||||
&mut DirRawStream::File(ref mut file) => file.read(buf),
|
||||
@ -47,7 +56,7 @@ impl <'a, 'b> Read for DirRawStream<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, 'b> Write for DirRawStream<'a, 'b> {
|
||||
impl <'a, T: ReadWriteSeek> Write for DirRawStream<'a, T> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
match self {
|
||||
&mut DirRawStream::File(ref mut file) => file.write(buf),
|
||||
@ -62,7 +71,7 @@ impl <'a, 'b> Write for DirRawStream<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, 'b> Seek for DirRawStream<'a, 'b> {
|
||||
impl <'a, T: ReadWriteSeek> Seek for DirRawStream<'a, T> {
|
||||
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
||||
match self {
|
||||
&mut DirRawStream::File(ref mut file) => file.seek(pos),
|
||||
@ -80,19 +89,19 @@ fn split_path<'c>(path: &'c str) -> (&'c str, Option<&'c str>) {
|
||||
}
|
||||
|
||||
/// FAT directory
|
||||
#[derive(Clone)]
|
||||
pub struct Dir<'a, 'b: 'a> {
|
||||
stream: DirRawStream<'a, 'b>,
|
||||
fs: FileSystemRef<'a, 'b>,
|
||||
pub struct Dir<'a, T: ReadWriteSeek + 'a> {
|
||||
stream: DirRawStream<'a, T>,
|
||||
fs: &'a FileSystem<T>,
|
||||
}
|
||||
|
||||
impl <'a, 'b> Dir<'a, 'b> {
|
||||
pub(crate) fn new(stream: DirRawStream<'a, 'b>, fs: FileSystemRef<'a, 'b>) -> Self {
|
||||
impl <'a, T: ReadWriteSeek + 'a> Dir<'a, T> {
|
||||
pub(crate) fn new(stream: DirRawStream<'a, T>, fs: &'a FileSystem<T>) -> Self {
|
||||
Dir { stream, fs }
|
||||
}
|
||||
|
||||
/// Creates directory entries iterator
|
||||
pub fn iter(&self) -> DirIter<'a, 'b> {
|
||||
pub fn iter(&self) -> DirIter<'a, T> {
|
||||
self.stream.clone();
|
||||
DirIter {
|
||||
stream: self.stream.clone(),
|
||||
fs: self.fs.clone(),
|
||||
@ -100,7 +109,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
fn find_entry(&self, name: &str, is_dir: Option<bool>, mut short_name_gen: Option<&mut ShortNameGenerator>) -> io::Result<DirEntry<'a, 'b>> {
|
||||
fn find_entry(&self, name: &str, is_dir: Option<bool>, mut short_name_gen: Option<&mut ShortNameGenerator>) -> io::Result<DirEntry<'a, T>> {
|
||||
for r in self.iter() {
|
||||
let e = r?;
|
||||
// compare name ignoring case
|
||||
@ -130,7 +139,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
||||
}
|
||||
|
||||
/// Opens existing file.
|
||||
pub fn open_file(&self, path: &str) -> io::Result<File<'a, 'b>> {
|
||||
pub fn open_file(&self, path: &str) -> io::Result<File<'a, T>> {
|
||||
// traverse path
|
||||
let (name, rest_opt) = split_path(path);
|
||||
if let Some(rest) = rest_opt {
|
||||
@ -143,7 +152,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
||||
}
|
||||
|
||||
/// Creates new file or opens existing without truncating.
|
||||
pub fn create_file(&self, path: &str) -> io::Result<File<'a, 'b>> {
|
||||
pub fn create_file(&self, path: &str) -> io::Result<File<'a, T>> {
|
||||
// traverse path
|
||||
let (name, rest_opt) = split_path(path);
|
||||
if let Some(rest) = rest_opt {
|
||||
@ -255,7 +264,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
||||
/// Destination directory can be cloned source directory in case of rename without moving operation.
|
||||
/// Make sure there is no reference to this file (no File instance) or filesystem corruption
|
||||
/// can happen.
|
||||
pub fn rename(&self, src_path: &str, dst_dir: &Dir, dst_path: &str) -> io::Result<()> {
|
||||
pub fn rename(&self, src_path: &str, dst_dir: &Dir<T>, dst_path: &str) -> io::Result<()> {
|
||||
// traverse source path
|
||||
let (name, rest_opt) = split_path(src_path);
|
||||
if let Some(rest) = rest_opt {
|
||||
@ -272,7 +281,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
||||
self.rename_internal(src_path, dst_dir, dst_path)
|
||||
}
|
||||
|
||||
fn rename_internal(&self, src_name: &str, dst_dir: &Dir, dst_name: &str) -> io::Result<()> {
|
||||
fn rename_internal(&self, src_name: &str, dst_dir: &Dir<T>, dst_name: &str) -> io::Result<()> {
|
||||
trace!("moving {} to {}", src_name, dst_name);
|
||||
// find existing file
|
||||
let e = self.find_entry(src_name, None, None)?;
|
||||
@ -300,7 +309,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn find_free_entries(&self, num_entries: usize) -> io::Result<DirRawStream<'a, 'b>> {
|
||||
fn find_free_entries(&self, num_entries: usize) -> io::Result<DirRawStream<'a, T>> {
|
||||
let mut stream = self.stream.clone();
|
||||
let mut first_free = 0;
|
||||
let mut num_free = 0;
|
||||
@ -334,7 +343,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
fn create_lfn_entries(&self, name: &str, short_name: &[u8]) -> io::Result<(DirRawStream<'a, 'b>, u64)> {
|
||||
fn create_lfn_entries(&self, name: &str, short_name: &[u8]) -> io::Result<(DirRawStream<'a, T>, u64)> {
|
||||
// get short name checksum
|
||||
let lfn_chsum = lfn_checksum(&short_name);
|
||||
// convert long name to UTF-16
|
||||
@ -351,7 +360,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
||||
Ok((stream, start_pos))
|
||||
}
|
||||
#[cfg(not(feature = "alloc"))]
|
||||
fn create_lfn_entries(&self, _name: &str, _short_name: &[u8]) -> io::Result<(DirRawStream<'a, 'b>, u64)> {
|
||||
fn create_lfn_entries(&self, _name: &str, _short_name: &[u8]) -> io::Result<(DirRawStream<'a, T>, u64)> {
|
||||
let mut stream = self.find_free_entries(1)?;
|
||||
let start_pos = stream.seek(io::SeekFrom::Current(0))?;
|
||||
Ok((stream, start_pos))
|
||||
@ -366,7 +375,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
||||
raw_entry
|
||||
}
|
||||
|
||||
fn write_entry(&self, name: &str, raw_entry: DirFileEntryData) -> io::Result<DirEntry<'a, 'b>> {
|
||||
fn write_entry(&self, name: &str, raw_entry: DirFileEntryData) -> io::Result<DirEntry<'a, T>> {
|
||||
trace!("write_entry {}", name);
|
||||
// check if name doesn't contain unsupported characters
|
||||
validate_long_name(name)?;
|
||||
@ -390,16 +399,25 @@ impl <'a, 'b> Dir<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925
|
||||
impl <'a, T: ReadWriteSeek> Clone for Dir<'a, T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
stream: self.stream.clone(),
|
||||
fs: self.fs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Directory entries iterator.
|
||||
#[derive(Clone)]
|
||||
pub struct DirIter<'a, 'b: 'a> {
|
||||
stream: DirRawStream<'a, 'b>,
|
||||
fs: FileSystemRef<'a, 'b>,
|
||||
pub struct DirIter<'a, T: ReadWriteSeek + 'a> {
|
||||
stream: DirRawStream<'a, T>,
|
||||
fs: &'a FileSystem<T>,
|
||||
err: bool,
|
||||
}
|
||||
|
||||
impl <'a, 'b> DirIter<'a, 'b> {
|
||||
fn read_dir_entry(&mut self) -> io::Result<Option<DirEntry<'a, 'b>>> {
|
||||
impl <'a, T: ReadWriteSeek> DirIter<'a, T> {
|
||||
fn read_dir_entry(&mut self) -> io::Result<Option<DirEntry<'a, T>>> {
|
||||
#[cfg(feature = "alloc")]
|
||||
let mut lfn_buf = LongNameBuilder::new();
|
||||
let mut offset = self.stream.seek(SeekFrom::Current(0))?;
|
||||
@ -454,8 +472,19 @@ impl <'a, 'b> DirIter<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, 'b> Iterator for DirIter<'a, 'b> {
|
||||
type Item = io::Result<DirEntry<'a, 'b>>;
|
||||
// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925
|
||||
impl <'a, T: ReadWriteSeek> Clone for DirIter<'a, T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
stream: self.stream.clone(),
|
||||
fs: self.fs,
|
||||
err: self.err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, T: ReadWriteSeek> Iterator for DirIter<'a, T> {
|
||||
type Item = io::Result<DirEntry<'a, T>>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.err {
|
||||
|
@ -13,7 +13,7 @@ use chrono;
|
||||
#[cfg(all(not(feature = "std"), feature = "alloc"))]
|
||||
use alloc::{Vec, String, string::ToString};
|
||||
|
||||
use fs::{FileSystemRef, FatType};
|
||||
use fs::{FileSystem, FatType, ReadWriteSeek};
|
||||
use file::File;
|
||||
use dir::{Dir, DirRawStream};
|
||||
|
||||
@ -589,7 +589,7 @@ impl DirEntryEditor {
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
pub(crate) fn flush(&mut self, fs: FileSystemRef) -> io::Result<()> {
|
||||
pub(crate) fn flush<T: ReadWriteSeek>(&mut self, fs: &FileSystem<T>) -> io::Result<()> {
|
||||
if self.dirty {
|
||||
self.write(fs)?;
|
||||
self.dirty = false;
|
||||
@ -597,7 +597,7 @@ impl DirEntryEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write(&self, fs: FileSystemRef) -> io::Result<()> {
|
||||
fn write<T: ReadWriteSeek>(&self, fs: &FileSystem<T>) -> io::Result<()> {
|
||||
let mut disk = fs.disk.borrow_mut();
|
||||
disk.seek(io::SeekFrom::Start(self.pos))?;
|
||||
self.data.serialize(&mut *disk)
|
||||
@ -608,17 +608,17 @@ impl DirEntryEditor {
|
||||
///
|
||||
/// Returned by DirIter.
|
||||
#[derive(Clone)]
|
||||
pub struct DirEntry<'a, 'b: 'a> {
|
||||
pub struct DirEntry<'a, T: ReadWriteSeek + 'a> {
|
||||
pub(crate) data: DirFileEntryData,
|
||||
pub(crate) short_name: ShortName,
|
||||
#[cfg(feature = "alloc")]
|
||||
pub(crate) lfn: Vec<u16>,
|
||||
pub(crate) entry_pos: u64,
|
||||
pub(crate) offset_range: (u64, u64),
|
||||
pub(crate) fs: FileSystemRef<'a, 'b>,
|
||||
pub(crate) fs: &'a FileSystem<T>,
|
||||
}
|
||||
|
||||
impl <'a, 'b> DirEntry<'a, 'b> {
|
||||
impl <'a, T: ReadWriteSeek> DirEntry<'a, T> {
|
||||
/// Returns short file name
|
||||
#[cfg(feature = "alloc")]
|
||||
pub fn short_file_name(&self) -> String {
|
||||
@ -669,7 +669,7 @@ impl <'a, 'b> DirEntry<'a, 'b> {
|
||||
/// Returns File struct for this entry.
|
||||
///
|
||||
/// Panics if this is not a file.
|
||||
pub fn to_file(&self) -> File<'a, 'b> {
|
||||
pub fn to_file(&self) -> File<'a, T> {
|
||||
assert!(!self.is_dir(), "Not a file entry");
|
||||
File::new(self.first_cluster(), Some(self.editor()), self.fs)
|
||||
}
|
||||
@ -677,7 +677,7 @@ impl <'a, 'b> DirEntry<'a, 'b> {
|
||||
/// Returns Dir struct for this entry.
|
||||
///
|
||||
/// Panics if this is not a directory.
|
||||
pub fn to_dir(&self) -> Dir<'a, 'b> {
|
||||
pub fn to_dir(&self) -> Dir<'a, T> {
|
||||
assert!(self.is_dir(), "Not a directory entry");
|
||||
match self.first_cluster() {
|
||||
Some(n) => {
|
||||
@ -713,7 +713,7 @@ impl <'a, 'b> DirEntry<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, 'b> fmt::Debug for DirEntry<'a, 'b> {
|
||||
impl <'a, T: ReadWriteSeek> fmt::Debug for DirEntry<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
self.data.fmt(f)
|
||||
}
|
||||
|
32
src/file.rs
32
src/file.rs
@ -4,14 +4,13 @@ use io::prelude::*;
|
||||
use io::{SeekFrom, ErrorKind};
|
||||
use io;
|
||||
|
||||
use fs::FileSystemRef;
|
||||
use fs::{FileSystem, ReadWriteSeek};
|
||||
use dir_entry::{DirEntryEditor, DateTime, Date};
|
||||
|
||||
const MAX_FILE_SIZE: u32 = core::u32::MAX;
|
||||
|
||||
/// FAT file used for reading and writing.
|
||||
#[derive(Clone)]
|
||||
pub struct File<'a, 'b: 'a> {
|
||||
pub struct File<'a, T: ReadWriteSeek + 'a> {
|
||||
// Note first_cluster is None if file is empty
|
||||
first_cluster: Option<u32>,
|
||||
// Note: if offset points between clusters current_cluster is the previous cluster
|
||||
@ -21,11 +20,11 @@ pub struct File<'a, 'b: 'a> {
|
||||
// file dir entry editor - None for root dir
|
||||
entry: Option<DirEntryEditor>,
|
||||
// file-system reference
|
||||
fs: FileSystemRef<'a, 'b>,
|
||||
fs: &'a FileSystem<T>,
|
||||
}
|
||||
|
||||
impl <'a, 'b> File<'a, 'b> {
|
||||
pub(crate) fn new(first_cluster: Option<u32>, entry: Option<DirEntryEditor>, fs: FileSystemRef<'a, 'b>) -> Self {
|
||||
impl <'a, T: ReadWriteSeek> File<'a, T> {
|
||||
pub(crate) fn new(first_cluster: Option<u32>, entry: Option<DirEntryEditor>, fs: &'a FileSystem<T>) -> Self {
|
||||
File {
|
||||
first_cluster, entry, fs,
|
||||
current_cluster: None, // cluster before first one
|
||||
@ -132,7 +131,7 @@ impl <'a, 'b> File<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Drop for File<'a, 'b> {
|
||||
impl<'a, T: ReadWriteSeek> Drop for File<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
if let Err(err) = self.flush() {
|
||||
error!("flush failed {}", err);
|
||||
@ -140,7 +139,20 @@ impl<'a, 'b> Drop for File<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Read for File<'a, 'b> {
|
||||
// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925
|
||||
impl <'a, T: ReadWriteSeek> Clone for File<'a, T> {
|
||||
fn clone(&self) -> Self {
|
||||
File {
|
||||
first_cluster: self.first_cluster,
|
||||
current_cluster: self.current_cluster,
|
||||
offset: self.offset,
|
||||
entry: self.entry.clone(),
|
||||
fs: self.fs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ReadWriteSeek> Read for File<'a, T> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let cluster_size = self.fs.cluster_size();
|
||||
let current_cluster_opt = if self.offset % cluster_size == 0 {
|
||||
@ -191,7 +203,7 @@ impl<'a, 'b> Read for File<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Write for File<'a, 'b> {
|
||||
impl<'a, T: ReadWriteSeek> Write for File<'a, T> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
let cluster_size = self.fs.cluster_size();
|
||||
let offset_in_cluster = self.offset % cluster_size;
|
||||
@ -271,7 +283,7 @@ impl<'a, 'b> Write for File<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Seek for File<'a, 'b> {
|
||||
impl<'a, T: ReadWriteSeek> Seek for File<'a, T> {
|
||||
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
||||
let mut new_pos = match pos {
|
||||
SeekFrom::Current(x) => self.offset as i64 + x,
|
||||
|
62
src/fs.rs
62
src/fs.rs
@ -100,7 +100,7 @@ struct BiosParameterBlock {
|
||||
}
|
||||
|
||||
impl BiosParameterBlock {
|
||||
fn deserialize(rdr: &mut Read) -> io::Result<BiosParameterBlock> {
|
||||
fn deserialize<T: Read>(rdr: &mut T) -> io::Result<BiosParameterBlock> {
|
||||
let mut bpb: BiosParameterBlock = Default::default();
|
||||
bpb.bytes_per_sector = rdr.read_u16::<LittleEndian>()?;
|
||||
bpb.sectors_per_cluster = rdr.read_u8()?;
|
||||
@ -188,7 +188,7 @@ struct BootRecord {
|
||||
}
|
||||
|
||||
impl BootRecord {
|
||||
fn deserialize(rdr: &mut Read) -> io::Result<BootRecord> {
|
||||
fn deserialize<T: Read>(rdr: &mut T) -> io::Result<BootRecord> {
|
||||
let mut boot: BootRecord = Default::default();
|
||||
rdr.read_exact(&mut boot.bootjmp)?;
|
||||
rdr.read_exact(&mut boot.oem_name)?;
|
||||
@ -228,7 +228,7 @@ impl FsInfoSector {
|
||||
const STRUC_SIG: u32 = 0x61417272;
|
||||
const TRAIL_SIG: u32 = 0xAA550000;
|
||||
|
||||
fn deserialize(rdr: &mut Read) -> io::Result<FsInfoSector> {
|
||||
fn deserialize<T: Read>(rdr: &mut T) -> io::Result<FsInfoSector> {
|
||||
let lead_sig = rdr.read_u32::<LittleEndian>()?;
|
||||
if lead_sig != Self::LEAD_SIG {
|
||||
return Err(Error::new(ErrorKind::Other, "invalid lead_sig in FsInfo sector"));
|
||||
@ -259,7 +259,7 @@ impl FsInfoSector {
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize(&self, wrt: &mut Write) -> io::Result<()> {
|
||||
fn serialize<T: Write>(&self, wrt: &mut T) -> io::Result<()> {
|
||||
wrt.write_u32::<LittleEndian>(Self::LEAD_SIG)?;
|
||||
let reserved = [0u8; 480];
|
||||
wrt.write(&reserved)?;
|
||||
@ -343,11 +343,9 @@ impl FileSystemStats {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type FileSystemRef<'a, 'b> = &'a FileSystem<'b>;
|
||||
|
||||
/// FAT filesystem main struct.
|
||||
pub struct FileSystem<'a> {
|
||||
pub(crate) disk: RefCell<&'a mut ReadWriteSeek>,
|
||||
pub struct FileSystem<T: ReadWriteSeek> {
|
||||
pub(crate) disk: RefCell<T>,
|
||||
pub(crate) options: FsOptions,
|
||||
fat_type: FatType,
|
||||
bpb: BiosParameterBlock,
|
||||
@ -357,7 +355,7 @@ pub struct FileSystem<'a> {
|
||||
fs_info: RefCell<FsInfoSector>,
|
||||
}
|
||||
|
||||
impl <'a> FileSystem<'a> {
|
||||
impl <T: ReadWriteSeek> FileSystem<T> {
|
||||
/// Creates new filesystem object instance.
|
||||
///
|
||||
/// Supplied disk parameter cannot be seeked. If there is a need to read a fragment of disk image (e.g. partition)
|
||||
@ -365,13 +363,13 @@ impl <'a> FileSystem<'a> {
|
||||
///
|
||||
/// Note: creating multiple filesystem objects with one underlying device/disk image can
|
||||
/// cause filesystem corruption.
|
||||
pub fn new<T: ReadWriteSeek>(disk: &'a mut T, options: FsOptions) -> io::Result<Self> {
|
||||
// make sure given image is not seeked
|
||||
pub fn new(mut disk: T, options: FsOptions) -> io::Result<Self> {
|
||||
// Make sure given image is not seeked
|
||||
debug_assert!(disk.seek(SeekFrom::Current(0))? == 0);
|
||||
|
||||
// read boot sector
|
||||
let bpb = {
|
||||
let boot = BootRecord::deserialize(disk)?;
|
||||
let boot = BootRecord::deserialize(&mut disk)?;
|
||||
if boot.boot_sig != [0x55, 0xAA] {
|
||||
return Err(Error::new(ErrorKind::Other, "invalid signature"));
|
||||
}
|
||||
@ -395,7 +393,7 @@ impl <'a> FileSystem<'a> {
|
||||
// read FSInfo sector if this is FAT32
|
||||
let mut fs_info = if fat_type == FatType::Fat32 {
|
||||
disk.seek(SeekFrom::Start(bpb.fs_info_sector as u64 * 512))?;
|
||||
FsInfoSector::deserialize(disk)?
|
||||
FsInfoSector::deserialize(&mut disk)?
|
||||
} else {
|
||||
FsInfoSector::default()
|
||||
};
|
||||
@ -442,7 +440,7 @@ impl <'a> FileSystem<'a> {
|
||||
}
|
||||
|
||||
/// Returns root directory object allowing futher penetration of filesystem structure.
|
||||
pub fn root_dir<'b>(&'b self) -> Dir<'b, 'a> {
|
||||
pub fn root_dir<'b>(&'b self) -> Dir<'b, T> {
|
||||
let root_rdr = {
|
||||
match self.fat_type {
|
||||
FatType::Fat12 | FatType::Fat16 => DirRawStream::Root(DiskSlice::from_sectors(
|
||||
@ -469,7 +467,7 @@ impl <'a> FileSystem<'a> {
|
||||
self.offset_from_sector(self.sector_from_cluster(cluser))
|
||||
}
|
||||
|
||||
fn fat_slice<'b>(&'b self) -> DiskSlice<'b, 'a> {
|
||||
fn fat_slice<'b>(&'b self) -> DiskSlice<'b, T> {
|
||||
let sectors_per_fat =
|
||||
if self.bpb.sectors_per_fat_16 == 0 { self.bpb.sectors_per_fat_32 }
|
||||
else { self.bpb.sectors_per_fat_16 as u32 };
|
||||
@ -484,7 +482,7 @@ impl <'a> FileSystem<'a> {
|
||||
DiskSlice::from_sectors(fat_first_sector, sectors_per_fat, mirrors, self)
|
||||
}
|
||||
|
||||
pub(crate) fn cluster_iter<'b>(&'b self, cluster: u32) -> ClusterIterator<'b, 'a> {
|
||||
pub(crate) fn cluster_iter<'b>(&'b self, cluster: u32) -> ClusterIterator<DiskSlice<'b, T>> {
|
||||
let disk_slice = self.fat_slice();
|
||||
ClusterIterator::new(disk_slice, self.fat_type, cluster)
|
||||
}
|
||||
@ -574,7 +572,7 @@ impl <'a> FileSystem<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for FileSystem<'a> {
|
||||
impl<T: ReadWriteSeek> Drop for FileSystem<T> {
|
||||
fn drop(&mut self) {
|
||||
if let Err(err) = self.unmount_internal() {
|
||||
error!("unmount failed {}", err);
|
||||
@ -582,21 +580,20 @@ impl<'a> Drop for FileSystem<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct DiskSlice<'a, 'b: 'a> {
|
||||
pub(crate) struct DiskSlice<'a, T: ReadWriteSeek + 'a> {
|
||||
begin: u64,
|
||||
size: u64,
|
||||
offset: u64,
|
||||
mirrors: u8,
|
||||
fs: &'a FileSystem<'b>,
|
||||
fs: &'a FileSystem<T>,
|
||||
}
|
||||
|
||||
impl <'a, 'b> DiskSlice<'a, 'b> {
|
||||
pub(crate) fn new(begin: u64, size: u64, mirrors: u8, fs: FileSystemRef<'a, 'b>) -> Self {
|
||||
impl <'a, T: ReadWriteSeek> DiskSlice<'a, T> {
|
||||
pub(crate) fn new(begin: u64, size: u64, mirrors: u8, fs: &'a FileSystem<T>) -> Self {
|
||||
DiskSlice { begin, size, mirrors, fs, offset: 0 }
|
||||
}
|
||||
|
||||
pub(crate) fn from_sectors(first_sector: u32, sector_count: u32, mirrors: u8, fs: FileSystemRef<'a, 'b>) -> Self {
|
||||
pub(crate) fn from_sectors(first_sector: u32, sector_count: u32, mirrors: u8, fs: &'a FileSystem<T>) -> Self {
|
||||
let bytes_per_sector = fs.bpb.bytes_per_sector as u64;
|
||||
Self::new(first_sector as u64 * bytes_per_sector, sector_count as u64 * bytes_per_sector, mirrors, fs)
|
||||
}
|
||||
@ -606,7 +603,20 @@ impl <'a, 'b> DiskSlice<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, 'b> Read for DiskSlice<'a, 'b> {
|
||||
// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925
|
||||
impl <'a, T: ReadWriteSeek> Clone for DiskSlice<'a, T> {
|
||||
fn clone(&self) -> Self {
|
||||
DiskSlice {
|
||||
begin: self.begin,
|
||||
size: self.size,
|
||||
offset: self.offset,
|
||||
mirrors: self.mirrors,
|
||||
fs: self.fs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, T: ReadWriteSeek> Read for DiskSlice<'a, T> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let offset = self.begin + self.offset;
|
||||
let read_size = cmp::min((self.size - self.offset) as usize, buf.len());
|
||||
@ -618,7 +628,7 @@ impl <'a, 'b> Read for DiskSlice<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, 'b> Write for DiskSlice<'a, 'b> {
|
||||
impl <'a, T: ReadWriteSeek> Write for DiskSlice<'a, T> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
let offset = self.begin + self.offset;
|
||||
let write_size = cmp::min((self.size - self.offset) as usize, buf.len());
|
||||
@ -637,7 +647,7 @@ impl <'a, 'b> Write for DiskSlice<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, 'b> Seek for DiskSlice<'a, 'b> {
|
||||
impl <'a, T: ReadWriteSeek> Seek for DiskSlice<'a, T> {
|
||||
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
||||
let new_offset = match pos {
|
||||
SeekFrom::Current(x) => self.offset as i64 + x,
|
||||
|
67
src/table.rs
67
src/table.rs
@ -1,8 +1,7 @@
|
||||
use io;
|
||||
use io::prelude::*;
|
||||
use byteorder::LittleEndian;
|
||||
use byteorder_ext::{ReadBytesExt, WriteBytesExt};
|
||||
use fs::{FatType, FsStatusFlags, DiskSlice, ReadSeek};
|
||||
use fs::{ReadWriteSeek, ReadSeek, FatType, FsStatusFlags};
|
||||
|
||||
struct Fat<T> {
|
||||
#[allow(dead_code)]
|
||||
@ -24,14 +23,14 @@ enum FatValue {
|
||||
}
|
||||
|
||||
trait FatTrait {
|
||||
fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result<u32>;
|
||||
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue>;
|
||||
fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()>;
|
||||
fn find_free(fat: &mut ReadSeek, start_cluster: u32, end_cluster: u32) -> io::Result<u32>;
|
||||
fn count_free(fat: &mut ReadSeek, end_cluster: u32) -> io::Result<u32>;
|
||||
fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32>;
|
||||
fn get<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<FatValue>;
|
||||
fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()>;
|
||||
fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32>;
|
||||
fn count_free<T: ReadSeek>(fat: &mut T, end_cluster: u32) -> io::Result<u32>;
|
||||
}
|
||||
|
||||
fn read_fat(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result<FatValue> {
|
||||
fn read_fat<T: ReadSeek>(fat: &mut T, fat_type: FatType, cluster: u32) -> io::Result<FatValue> {
|
||||
match fat_type {
|
||||
FatType::Fat12 => Fat12::get(fat, cluster),
|
||||
FatType::Fat16 => Fat16::get(fat, cluster),
|
||||
@ -39,7 +38,7 @@ fn read_fat(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result<F
|
||||
}
|
||||
}
|
||||
|
||||
fn write_fat(fat: &mut DiskSlice, fat_type: FatType, cluster: u32, value: FatValue) -> io::Result<()> {
|
||||
fn write_fat<T: ReadWriteSeek>(fat: &mut T, fat_type: FatType, cluster: u32, value: FatValue) -> io::Result<()> {
|
||||
trace!("write FAT - cluster {} value {:?}", cluster, value);
|
||||
match fat_type {
|
||||
FatType::Fat12 => Fat12::set(fat, cluster, value),
|
||||
@ -48,7 +47,7 @@ fn write_fat(fat: &mut DiskSlice, fat_type: FatType, cluster: u32, value: FatVal
|
||||
}
|
||||
}
|
||||
|
||||
fn get_next_cluster(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::Result<Option<u32>> {
|
||||
fn get_next_cluster<T: ReadSeek>(fat: &mut T, fat_type: FatType, cluster: u32) -> io::Result<Option<u32>> {
|
||||
let val = read_fat(fat, fat_type, cluster)?;
|
||||
match val {
|
||||
FatValue::Data(n) => Ok(Some(n)),
|
||||
@ -56,7 +55,7 @@ fn get_next_cluster(fat: &mut ReadSeek, fat_type: FatType, cluster: u32) -> io::
|
||||
}
|
||||
}
|
||||
|
||||
fn find_free_cluster(fat: &mut ReadSeek, fat_type: FatType, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
|
||||
fn find_free_cluster<T: ReadSeek>(fat: &mut T, fat_type: FatType, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
|
||||
match fat_type {
|
||||
FatType::Fat12 => Fat12::find_free(fat, start_cluster, end_cluster),
|
||||
FatType::Fat16 => Fat16::find_free(fat, start_cluster, end_cluster),
|
||||
@ -64,7 +63,7 @@ fn find_free_cluster(fat: &mut ReadSeek, fat_type: FatType, start_cluster: u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn alloc_cluster(fat: &mut DiskSlice, fat_type: FatType, prev_cluster: Option<u32>, hint: Option<u32>, total_clusters: u32) -> io::Result<u32> {
|
||||
pub(crate) fn alloc_cluster<T: ReadWriteSeek>(fat: &mut T, fat_type: FatType, prev_cluster: Option<u32>, hint: Option<u32>, total_clusters: u32) -> io::Result<u32> {
|
||||
let end_cluster = total_clusters + RESERVED_FAT_ENTRIES;
|
||||
let start_cluster = match hint {
|
||||
Some(n) if n < end_cluster => n,
|
||||
@ -83,7 +82,7 @@ pub(crate) fn alloc_cluster(fat: &mut DiskSlice, fat_type: FatType, prev_cluster
|
||||
Ok(new_cluster)
|
||||
}
|
||||
|
||||
pub(crate) fn read_fat_flags(fat: &mut DiskSlice, fat_type: FatType) -> io::Result<FsStatusFlags> {
|
||||
pub(crate) fn read_fat_flags<T: ReadSeek>(fat: &mut T, fat_type: FatType) -> io::Result<FsStatusFlags> {
|
||||
// check MSB (except in FAT12)
|
||||
let val = match fat_type {
|
||||
FatType::Fat12 => 0xFFF,
|
||||
@ -105,7 +104,7 @@ pub(crate) fn read_fat_flags(fat: &mut DiskSlice, fat_type: FatType) -> io::Resu
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn count_free_clusters(fat: &mut ReadSeek, fat_type: FatType, total_clusters: u32) -> io::Result<u32> {
|
||||
pub(crate) fn count_free_clusters<T: ReadSeek>(fat: &mut T, fat_type: FatType, total_clusters: u32) -> io::Result<u32> {
|
||||
let end_cluster = total_clusters + RESERVED_FAT_ENTRIES;
|
||||
match fat_type {
|
||||
FatType::Fat12 => Fat12::count_free(fat, end_cluster),
|
||||
@ -115,7 +114,7 @@ pub(crate) fn count_free_clusters(fat: &mut ReadSeek, fat_type: FatType, total_c
|
||||
}
|
||||
|
||||
impl FatTrait for Fat12 {
|
||||
fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result<u32> {
|
||||
fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32> {
|
||||
let fat_offset = cluster + (cluster / 2);
|
||||
fat.seek(io::SeekFrom::Start(fat_offset as u64))?;
|
||||
let packed_val = fat.read_u16::<LittleEndian>()?;
|
||||
@ -125,7 +124,7 @@ impl FatTrait for Fat12 {
|
||||
} as u32)
|
||||
}
|
||||
|
||||
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue> {
|
||||
fn get<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<FatValue> {
|
||||
let val = Self::get_raw(fat, cluster)?;
|
||||
Ok(match val {
|
||||
0 => FatValue::Free,
|
||||
@ -135,7 +134,7 @@ impl FatTrait for Fat12 {
|
||||
})
|
||||
}
|
||||
|
||||
fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()> {
|
||||
fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> {
|
||||
let raw_val = match value {
|
||||
FatValue::Free => 0,
|
||||
FatValue::Bad => 0xFF7,
|
||||
@ -154,7 +153,7 @@ impl FatTrait for Fat12 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn find_free(fat: &mut ReadSeek, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
|
||||
fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
|
||||
let mut cluster = start_cluster;
|
||||
let fat_offset = cluster + (cluster / 2);
|
||||
fat.seek(io::SeekFrom::Start(fat_offset as u64))?;
|
||||
@ -181,7 +180,7 @@ impl FatTrait for Fat12 {
|
||||
}
|
||||
}
|
||||
|
||||
fn count_free(fat: &mut ReadSeek, end_cluster: u32) -> io::Result<u32> {
|
||||
fn count_free<T: ReadSeek>(fat: &mut T, end_cluster: u32) -> io::Result<u32> {
|
||||
let mut count = 0;
|
||||
let mut cluster = RESERVED_FAT_ENTRIES;
|
||||
fat.seek(io::SeekFrom::Start((cluster*3/2) as u64))?;
|
||||
@ -211,12 +210,12 @@ impl FatTrait for Fat12 {
|
||||
}
|
||||
|
||||
impl FatTrait for Fat16 {
|
||||
fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result<u32> {
|
||||
fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32> {
|
||||
fat.seek(io::SeekFrom::Start((cluster*2) as u64))?;
|
||||
Ok(fat.read_u16::<LittleEndian>()? as u32)
|
||||
}
|
||||
|
||||
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue> {
|
||||
fn get<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<FatValue> {
|
||||
let val = Self::get_raw(fat, cluster)?;
|
||||
Ok(match val {
|
||||
0 => FatValue::Free,
|
||||
@ -226,7 +225,7 @@ impl FatTrait for Fat16 {
|
||||
})
|
||||
}
|
||||
|
||||
fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()> {
|
||||
fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> {
|
||||
fat.seek(io::SeekFrom::Start((cluster*2) as u64))?;
|
||||
let raw_val = match value {
|
||||
FatValue::Free => 0,
|
||||
@ -238,7 +237,7 @@ impl FatTrait for Fat16 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn find_free(fat: &mut ReadSeek, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
|
||||
fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
|
||||
let mut cluster = start_cluster;
|
||||
fat.seek(io::SeekFrom::Start((cluster*2) as u64))?;
|
||||
while cluster < end_cluster {
|
||||
@ -251,7 +250,7 @@ impl FatTrait for Fat16 {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "end of FAT reached"))
|
||||
}
|
||||
|
||||
fn count_free(fat: &mut ReadSeek, end_cluster: u32) -> io::Result<u32> {
|
||||
fn count_free<T: ReadSeek>(fat: &mut T, end_cluster: u32) -> io::Result<u32> {
|
||||
let mut count = 0;
|
||||
let mut cluster = RESERVED_FAT_ENTRIES;
|
||||
fat.seek(io::SeekFrom::Start((cluster*2) as u64))?;
|
||||
@ -269,12 +268,12 @@ impl FatTrait for Fat16 {
|
||||
}
|
||||
|
||||
impl FatTrait for Fat32 {
|
||||
fn get_raw(fat: &mut ReadSeek, cluster: u32) -> io::Result<u32> {
|
||||
fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32> {
|
||||
fat.seek(io::SeekFrom::Start((cluster*4) as u64))?;
|
||||
Ok(fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF)
|
||||
}
|
||||
|
||||
fn get(fat: &mut ReadSeek, cluster: u32) -> io::Result<FatValue> {
|
||||
fn get<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<FatValue> {
|
||||
let val = Self::get_raw(fat, cluster)?;
|
||||
Ok(match val {
|
||||
0 => FatValue::Free,
|
||||
@ -284,7 +283,7 @@ impl FatTrait for Fat32 {
|
||||
})
|
||||
}
|
||||
|
||||
fn set(fat: &mut DiskSlice, cluster: u32, value: FatValue) -> io::Result<()> {
|
||||
fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> {
|
||||
fat.seek(io::SeekFrom::Start((cluster*4) as u64))?;
|
||||
let raw_val = match value {
|
||||
FatValue::Free => 0,
|
||||
@ -296,7 +295,7 @@ impl FatTrait for Fat32 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn find_free(fat: &mut ReadSeek, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
|
||||
fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
|
||||
let mut cluster = start_cluster;
|
||||
fat.seek(io::SeekFrom::Start((cluster*4) as u64))?;
|
||||
while cluster < end_cluster {
|
||||
@ -309,7 +308,7 @@ impl FatTrait for Fat32 {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "end of FAT reached"))
|
||||
}
|
||||
|
||||
fn count_free(fat: &mut ReadSeek, end_cluster: u32) -> io::Result<u32> {
|
||||
fn count_free<T: ReadSeek>(fat: &mut T, end_cluster: u32) -> io::Result<u32> {
|
||||
let mut count = 0;
|
||||
let mut cluster = RESERVED_FAT_ENTRIES;
|
||||
fat.seek(io::SeekFrom::Start((cluster*4) as u64))?;
|
||||
@ -326,15 +325,15 @@ impl FatTrait for Fat32 {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ClusterIterator<'a, 'b: 'a> {
|
||||
fat: DiskSlice<'a, 'b>,
|
||||
pub(crate) struct ClusterIterator<T: ReadWriteSeek> {
|
||||
fat: T,
|
||||
fat_type: FatType,
|
||||
cluster: Option<u32>,
|
||||
err: bool,
|
||||
}
|
||||
|
||||
impl <'a, 'b> ClusterIterator<'a, 'b> {
|
||||
pub(crate) fn new(fat: DiskSlice<'a, 'b>, fat_type: FatType, cluster: u32) -> Self {
|
||||
impl <T: ReadWriteSeek> ClusterIterator<T> {
|
||||
pub(crate) fn new(fat: T, fat_type: FatType, cluster: u32) -> Self {
|
||||
ClusterIterator {
|
||||
fat,
|
||||
fat_type,
|
||||
@ -368,7 +367,7 @@ impl <'a, 'b> ClusterIterator<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, 'b> Iterator for ClusterIterator<'a, 'b> {
|
||||
impl <T: ReadWriteSeek> Iterator for ClusterIterator<T> {
|
||||
type Item = io::Result<u32>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
|
@ -6,24 +6,26 @@ use std::io::SeekFrom;
|
||||
use std::io::prelude::*;
|
||||
use std::str;
|
||||
|
||||
use fatfs::{FileSystem, FsOptions, FatType, DirEntry, BufStream};
|
||||
use fatfs::{FsOptions, FatType, BufStream};
|
||||
|
||||
const TEST_TEXT: &str = "Rust is cool!\n";
|
||||
const FAT12_IMG: &str = "resources/fat12.img";
|
||||
const FAT16_IMG: &str = "resources/fat16.img";
|
||||
const FAT32_IMG: &str = "resources/fat32.img";
|
||||
|
||||
type FileSystem = fatfs::FileSystem<BufStream<fs::File>>;
|
||||
|
||||
fn call_with_fs(f: &Fn(FileSystem) -> (), filename: &str) {
|
||||
let _ = env_logger::try_init();
|
||||
let file = fs::File::open(filename).unwrap();
|
||||
let mut buf_file = BufStream::new(file);
|
||||
let fs = FileSystem::new(&mut buf_file, FsOptions::new()).unwrap();
|
||||
let buf_file = BufStream::new(file);
|
||||
let fs = FileSystem::new(buf_file, FsOptions::new()).unwrap();
|
||||
f(fs);
|
||||
}
|
||||
|
||||
fn test_root_dir(fs: FileSystem) {
|
||||
let root_dir = fs.root_dir();
|
||||
let entries = root_dir.iter().map(|r| r.unwrap()).collect::<Vec<DirEntry>>();
|
||||
let entries = root_dir.iter().map(|r| r.unwrap()).collect::<Vec<_>>();
|
||||
let short_names = entries.iter().map(|e| e.short_file_name()).collect::<Vec<String>>();
|
||||
assert_eq!(short_names, ["LONG.TXT", "SHORT.TXT", "VERY", "VERY-L~1"]);
|
||||
let names = entries.iter().map(|e| e.file_name()).collect::<Vec<String>>();
|
||||
|
@ -6,7 +6,7 @@ use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::str;
|
||||
|
||||
use fatfs::{FileSystem, FsOptions, BufStream};
|
||||
use fatfs::{FsOptions, BufStream};
|
||||
|
||||
const FAT12_IMG: &str = "fat12.img";
|
||||
const FAT16_IMG: &str = "fat16.img";
|
||||
@ -16,6 +16,8 @@ const TMP_DIR: &str = "tmp";
|
||||
const TEST_STR: &str = "Hi there Rust programmer!\n";
|
||||
const TEST_STR2: &str = "Rust is cool!\n";
|
||||
|
||||
type FileSystem = fatfs::FileSystem<BufStream<fs::File>>;
|
||||
|
||||
fn call_with_fs(f: &Fn(FileSystem) -> (), filename: &str, test_seq: u32) {
|
||||
let _ = env_logger::try_init();
|
||||
let img_path = format!("{}/{}", IMG_DIR, filename);
|
||||
@ -24,9 +26,9 @@ fn call_with_fs(f: &Fn(FileSystem) -> (), filename: &str, test_seq: u32) {
|
||||
fs::copy(&img_path, &tmp_path).unwrap();
|
||||
{
|
||||
let file = fs::OpenOptions::new().read(true).write(true).open(&tmp_path).unwrap();
|
||||
let mut buf_file = BufStream::new(file);
|
||||
let options = FsOptions::new().update_accessed_date(true).update_fs_info(true);
|
||||
let fs = FileSystem::new(&mut buf_file, options).unwrap();
|
||||
let buf_file = BufStream::new(file);
|
||||
let options = FsOptions::new().update_accessed_date(true);
|
||||
let fs = FileSystem::new(buf_file, options).unwrap();
|
||||
f(fs);
|
||||
}
|
||||
fs::remove_file(tmp_path).unwrap();
|
||||
|
Loading…
Reference in New Issue
Block a user