Improve code style using rustfmt

This commit is contained in:
Rafał Harabień 2018-06-28 18:13:07 +02:00
parent 98c0fa528c
commit 30f3f96537
13 changed files with 332 additions and 263 deletions

View File

@ -1,19 +1,19 @@
extern crate chrono;
extern crate fatfs;
extern crate fscommon;
extern crate chrono;
use std::env;
use std::fs::File;
use std::io;
use chrono::{DateTime, Local};
use chrono::{DateTime, Local};
use fatfs::{FileSystem, FsOptions};
use fscommon::BufStream;
fn format_file_size(size: u64) -> String {
const KB: u64 = 1024;
const MB: u64 = 1024*KB;
const GB: u64 = 1024*MB;
const MB: u64 = 1024 * KB;
const GB: u64 = 1024 * MB;
if size < 1024 {
format!("{}B", size)
} else if size < MB {

View File

@ -2,6 +2,7 @@ extern crate fatfs;
extern crate fscommon;
use std::{fs, io};
use fatfs::{FileSystem, FsOptions};
use fscommon::{BufStream, StreamSlice};

View File

@ -13,7 +13,7 @@ fn main() -> io::Result<()> {
Err(err) => {
println!("Failed to open image!");
return Err(err);
}
},
};
let buf_stream = BufStream::new(img_file);
let options = FsOptions::new().update_accessed_date(true);

7
rustfmt.toml Normal file
View File

@ -0,0 +1,7 @@
max_width = 140
match_block_trailing_comma = true
use_field_init_shorthand = true
ignore = [
"src/byteorder_core_io.rs",
]
unstable_features = true

View File

@ -1,5 +1,5 @@
use io::{self, Result};
use core::slice;
use io::{self, Result};
use byteorder::ByteOrder;
@ -618,10 +618,7 @@ pub trait ReadBytesExt: io::Read {
/// ```
#[cfg(feature = "i128")]
#[inline]
fn read_u128_into<T: ByteOrder>(
&mut self,
dst: &mut [u128],
) -> Result<()> {
fn read_u128_into<T: ByteOrder>(&mut self, dst: &mut [u128]) -> Result<()> {
{
let mut buf = unsafe { slice_to_u8_mut(dst) };
try!(self.read_exact(buf));
@ -768,10 +765,7 @@ pub trait ReadBytesExt: io::Read {
/// ```
#[cfg(feature = "i128")]
#[inline]
fn read_i128_into<T: ByteOrder>(
&mut self,
dst: &mut [i128],
) -> Result<()> {
fn read_i128_into<T: ByteOrder>(&mut self, dst: &mut [i128]) -> Result<()> {
{
let mut buf = unsafe { slice_to_u8_mut(dst) };
try!(self.read_exact(buf));
@ -812,10 +806,7 @@ pub trait ReadBytesExt: io::Read {
/// assert_eq!([f32::consts::PI, 1.0], dst);
/// ```
#[inline]
fn read_f32_into<T: ByteOrder>(
&mut self,
dst: &mut [f32],
) -> Result<()> {
fn read_f32_into<T: ByteOrder>(&mut self, dst: &mut [f32]) -> Result<()> {
{
let buf = unsafe { slice_to_u8_mut(dst) };
try!(self.read_exact(buf));
@ -860,11 +851,8 @@ pub trait ReadBytesExt: io::Read {
/// assert_eq!([f32::consts::PI, 1.0], dst);
/// ```
#[inline]
#[deprecated(since="1.2.0", note="please use `read_f32_into` instead")]
fn read_f32_into_unchecked<T: ByteOrder>(
&mut self,
dst: &mut [f32],
) -> Result<()> {
#[deprecated(since = "1.2.0", note = "please use `read_f32_into` instead")]
fn read_f32_into_unchecked<T: ByteOrder>(&mut self, dst: &mut [f32]) -> Result<()> {
self.read_f32_into::<T>(dst)
}
@ -900,10 +888,7 @@ pub trait ReadBytesExt: io::Read {
/// assert_eq!([f64::consts::PI, 1.0], dst);
/// ```
#[inline]
fn read_f64_into<T: ByteOrder>(
&mut self,
dst: &mut [f64],
) -> Result<()> {
fn read_f64_into<T: ByteOrder>(&mut self, dst: &mut [f64]) -> Result<()> {
{
let buf = unsafe { slice_to_u8_mut(dst) };
try!(self.read_exact(buf));
@ -954,11 +939,8 @@ pub trait ReadBytesExt: io::Read {
/// assert_eq!([f64::consts::PI, 1.0], dst);
/// ```
#[inline]
#[deprecated(since="1.2.0", note="please use `read_f64_into` instead")]
fn read_f64_into_unchecked<T: ByteOrder>(
&mut self,
dst: &mut [f64],
) -> Result<()> {
#[deprecated(since = "1.2.0", note = "please use `read_f64_into` instead")]
fn read_f64_into_unchecked<T: ByteOrder>(&mut self, dst: &mut [f64]) -> Result<()> {
self.read_f64_into::<T>(dst)
}
}
@ -1159,11 +1141,7 @@ pub trait WriteBytesExt: io::Write {
/// If the given integer is not representable in the given number of bytes,
/// this method panics. If `nbytes > 8`, this method panics.
#[inline]
fn write_uint<T: ByteOrder>(
&mut self,
n: u64,
nbytes: usize,
) -> Result<()> {
fn write_uint<T: ByteOrder>(&mut self, n: u64, nbytes: usize) -> Result<()> {
let mut buf = [0; 8];
T::write_uint(&mut buf, n, nbytes);
self.write_all(&buf[0..nbytes])
@ -1182,11 +1160,7 @@ pub trait WriteBytesExt: io::Write {
/// If the given integer is not representable in the given number of bytes,
/// this method panics. If `nbytes > 8`, this method panics.
#[inline]
fn write_int<T: ByteOrder>(
&mut self,
n: i64,
nbytes: usize,
) -> Result<()> {
fn write_int<T: ByteOrder>(&mut self, n: i64, nbytes: usize) -> Result<()> {
let mut buf = [0; 8];
T::write_int(&mut buf, n, nbytes);
self.write_all(&buf[0..nbytes])
@ -1198,11 +1172,7 @@ pub trait WriteBytesExt: io::Write {
/// this method panics. If `nbytes > 16`, this method panics.
#[cfg(feature = "i128")]
#[inline]
fn write_uint128<T: ByteOrder>(
&mut self,
n: u128,
nbytes: usize,
) -> Result<()> {
fn write_uint128<T: ByteOrder>(&mut self, n: u128, nbytes: usize) -> Result<()> {
let mut buf = [0; 16];
T::write_uint128(&mut buf, n, nbytes);
self.write_all(&buf[0..nbytes])
@ -1214,11 +1184,7 @@ pub trait WriteBytesExt: io::Write {
/// this method panics. If `nbytes > 16`, this method panics.
#[cfg(feature = "i128")]
#[inline]
fn write_int128<T: ByteOrder>(
&mut self,
n: i128,
nbytes: usize,
) -> Result<()> {
fn write_int128<T: ByteOrder>(&mut self, n: i128, nbytes: usize) -> Result<()> {
let mut buf = [0; 16];
T::write_int128(&mut buf, n, nbytes);
self.write_all(&buf[0..nbytes])

View File

@ -1,27 +1,24 @@
#[cfg(feature = "alloc")]
use core::{slice, iter};
use core::{str, char, cmp, num};
use io::prelude::*;
use io;
use io::{ErrorKind, SeekFrom};
use fs::{FileSystem, DiskSlice, ReadWriteSeek};
use file::File;
use dir_entry::{DirEntry, DirEntryData, DirFileEntryData, DirLfnEntryData, FileAttributes, ShortName, DIR_ENTRY_SIZE};
#[cfg(feature = "alloc")]
use dir_entry::{LFN_PART_LEN, LFN_ENTRY_LAST_FLAG};
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::Vec;
use core::{char, cmp, num, str};
#[cfg(feature = "alloc")]
use core::{iter, slice};
use io;
use io::prelude::*;
use io::{ErrorKind, SeekFrom};
use dir_entry::{DirEntry, DirEntryData, DirFileEntryData, DirLfnEntryData, FileAttributes, ShortName, DIR_ENTRY_SIZE};
#[cfg(feature = "alloc")]
use dir_entry::{LFN_ENTRY_LAST_FLAG, LFN_PART_LEN};
use file::File;
use fs::{DiskSlice, FileSystem, ReadWriteSeek};
pub(crate) enum DirRawStream<'a, T: ReadWriteSeek + 'a> {
File(File<'a, T>),
Root(DiskSlice<'a, T>),
}
impl <'a, T: ReadWriteSeek> DirRawStream<'a, T> {
impl<'a, T: ReadWriteSeek> DirRawStream<'a, T> {
fn abs_pos(&self) -> Option<u64> {
match self {
&DirRawStream::File(ref file) => file.abs_pos(),
@ -38,7 +35,7 @@ impl <'a, T: ReadWriteSeek> DirRawStream<'a, T> {
}
// 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> {
impl<'a, T: ReadWriteSeek> Clone for DirRawStream<'a, T> {
fn clone(&self) -> Self {
match self {
&DirRawStream::File(ref file) => DirRawStream::File(file.clone()),
@ -47,7 +44,7 @@ impl <'a, T: ReadWriteSeek> Clone for DirRawStream<'a, T> {
}
}
impl <'a, T: ReadWriteSeek> Read for DirRawStream<'a, T> {
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),
@ -56,7 +53,7 @@ impl <'a, T: ReadWriteSeek> Read for DirRawStream<'a, T> {
}
}
impl <'a, T: ReadWriteSeek> Write for DirRawStream<'a, T> {
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),
@ -71,7 +68,7 @@ impl <'a, T: ReadWriteSeek> Write for DirRawStream<'a, T> {
}
}
impl <'a, T: ReadWriteSeek> Seek for DirRawStream<'a, T> {
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),
@ -102,7 +99,7 @@ pub struct Dir<'a, T: ReadWriteSeek + 'a> {
fs: &'a FileSystem<T>,
}
impl <'a, T: ReadWriteSeek + 'a> Dir<'a, T> {
impl<'a, T: ReadWriteSeek + 'a> Dir<'a, T> {
pub(crate) fn new(stream: DirRawStream<'a, T>, fs: &'a FileSystem<T>) -> Self {
Dir { stream, fs }
}
@ -116,7 +113,12 @@ impl <'a, T: ReadWriteSeek + 'a> Dir<'a, T> {
}
}
fn find_entry(&self, name: &str, is_dir: Option<bool>, mut short_name_gen: Option<&mut ShortNameGenerator>) -> io::Result<DirEntry<'a, T>> {
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
@ -311,7 +313,6 @@ impl <'a, T: ReadWriteSeek + 'a> Dir<'a, T> {
self.rename_internal(src_path, dst_dir, dst_path)
}
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
@ -436,7 +437,7 @@ impl <'a, T: ReadWriteSeek + 'a> Dir<'a, T> {
}
// 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> {
impl<'a, T: ReadWriteSeek> Clone for Dir<'a, T> {
fn clone(&self) -> Self {
Self {
stream: self.stream.clone(),
@ -454,7 +455,7 @@ pub struct DirIter<'a, T: ReadWriteSeek + 'a> {
err: bool,
}
impl <'a, T: ReadWriteSeek> DirIter<'a, T> {
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();
@ -504,14 +505,14 @@ impl <'a, T: ReadWriteSeek> DirIter<'a, T> {
// Append to LFN buffer
#[cfg(feature = "alloc")]
lfn_buf.process(&data);
}
},
}
}
}
}
// 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> {
impl<'a, T: ReadWriteSeek> Clone for DirIter<'a, T> {
fn clone(&self) -> Self {
Self {
stream: self.stream.clone(),
@ -521,7 +522,7 @@ impl <'a, T: ReadWriteSeek> Clone for DirIter<'a, T> {
}
}
impl <'a, T: ReadWriteSeek> Iterator for DirIter<'a, T> {
impl<'a, T: ReadWriteSeek> Iterator for DirIter<'a, T> {
type Item = io::Result<DirEntry<'a, T>>;
fn next(&mut self) -> Option<Self::Item> {
@ -551,9 +552,10 @@ fn validate_long_name(name: &str) -> io::Result<()> {
// check if there are only valid characters
for c in name.chars() {
match c {
'a'...'z' | 'A'...'Z' | '0'...'9' | '\u{80}'...'\u{FFFF}' |
'$' | '%' | '\'' | '-' | '_' | '@' | '~' | '`' | '!' | '(' | ')' | '{' | '}' |
'.' | ' ' | '+' | ',' | ';' | '=' | '[' | ']' => {},
'a'...'z' | 'A'...'Z' | '0'...'9' => {},
'\u{80}'...'\u{FFFF}' => {},
'$' | '%' | '\'' | '-' | '_' | '@' | '~' | '`' | '!' | '(' | ')' | '{' | '}' | '.' | ' ' | '+' | ',' | ';' | '=' | '['
| ']' => {},
_ => return Err(io::Error::new(ErrorKind::Other, "File name contains unsupported characters")),
}
}
@ -605,7 +607,7 @@ impl LongNameBuilder {
// Truncate 0 and 0xFFFF characters from LFN buffer
let mut lfn_len = self.buf.len();
while lfn_len > 0 {
match self.buf[lfn_len-1] {
match self.buf[lfn_len - 1] {
0xFFFF | 0 => lfn_len -= 1,
_ => break,
}
@ -629,7 +631,13 @@ impl LongNameBuilder {
self.buf.resize(index as usize * LFN_PART_LEN, 0);
} else if self.index == 0 || index != self.index - 1 || data.checksum() != self.chksum {
// Corrupted entry
warn!("currupted lfn entry! {:x} {:x} {:x} {:x}", data.order(), self.index, data.checksum(), self.chksum);
warn!(
"currupted lfn entry! {:x} {:x} {:x} {:x}",
data.order(),
self.index,
data.checksum(),
self.chksum
);
self.clear();
return;
} else {
@ -638,7 +646,7 @@ impl LongNameBuilder {
}
let pos = LFN_PART_LEN * (index - 1) as usize;
// copy name parts into LFN buffer
data.copy_name_to_slice(&mut self.buf[pos..pos+13]);
data.copy_name_to_slice(&mut self.buf[pos..pos + 13]);
}
fn validate_chksum(&mut self, short_name: &[u8]) {
@ -710,7 +718,7 @@ impl<'a> Iterator for LfnEntriesGenerator<'a> {
// end of name
self.ended = true;
None
}
},
}
}
@ -744,18 +752,21 @@ impl ShortNameGenerator {
Some(index) => {
// extension found - copy parts before and after dot
let (basename_len, basename_fits, basename_lossy) = Self::copy_short_name_part(&mut short_name[0..8], &name[..index]);
let (_, ext_fits, ext_lossy) = Self::copy_short_name_part(&mut short_name[8..11], &name[index+1..]);
let (_, ext_fits, ext_lossy) = Self::copy_short_name_part(&mut short_name[8..11], &name[index + 1..]);
(basename_len, basename_fits && ext_fits, basename_lossy || ext_lossy)
},
None => {
// no extension - copy name and leave extension empty
let (basename_len, basename_fits, basename_lossy) = Self::copy_short_name_part(&mut short_name[0..8], &name);
(basename_len, basename_fits, basename_lossy)
}
},
};
let chksum = Self::checksum(name);
Self {
short_name, chksum, name_fits, lossy_conv,
short_name,
chksum,
name_fits,
lossy_conv,
basename_len: basename_len as u8,
..Default::default()
}
@ -777,9 +788,8 @@ impl ShortNameGenerator {
continue;
},
// copy allowed characters
'A'...'Z' | 'a'...'z' | '0'...'9' |
'!' | '#' | '$' | '%' | '&' | '\'' | '(' | ')' |
'-' | '@' | '^' | '_' | '`' | '{' | '}' | '~' => c,
'A'...'Z' | 'a'...'z' | '0'...'9' => c,
'!' | '#' | '$' | '%' | '&' | '\'' | '(' | ')' | '-' | '@' | '^' | '_' | '`' | '{' | '}' | '~' => c,
// replace disallowed characters by underscore
_ => '_',
};
@ -800,7 +810,11 @@ impl ShortNameGenerator {
}
// check for long prefix form collision (TEXTFI~1.TXT)
let prefix_len = cmp::min(self.basename_len, 6) as usize;
let num_suffix = if short_name[prefix_len] as char == '~' { (short_name[prefix_len+1] as char).to_digit(10) } else { None };
let num_suffix = if short_name[prefix_len] as char == '~' {
(short_name[prefix_len + 1] as char).to_digit(10)
} else {
None
};
let ext_matches = short_name[8..] == self.short_name[8..];
if short_name[..prefix_len] == self.short_name[..prefix_len] && num_suffix.is_some() && ext_matches {
let num = num_suffix.unwrap(); // SAFE
@ -809,9 +823,13 @@ impl ShortNameGenerator {
// check for short prefix + checksum form collision (TE021F~1.TXT)
let prefix_len = cmp::min(self.basename_len, 2) as usize;
let num_suffix = if short_name[prefix_len+4] as char == '~' { (short_name[prefix_len+4+1] as char).to_digit(10) } else { None };
let num_suffix = if short_name[prefix_len + 4] as char == '~' {
(short_name[prefix_len + 4 + 1] as char).to_digit(10)
} else {
None
};
if short_name[..prefix_len] == self.short_name[..prefix_len] && num_suffix.is_some() && ext_matches {
let chksum_res = str::from_utf8(&short_name[prefix_len..prefix_len+4]).map(|s| u16::from_str_radix(s, 16));
let chksum_res = str::from_utf8(&short_name[prefix_len..prefix_len + 4]).map(|s| u16::from_str_radix(s, 16));
if chksum_res == Ok(Ok(self.chksum)) {
let num = num_suffix.unwrap(); // SAFE
self.prefix_chksum_bitmap |= 1 << num;
@ -876,12 +894,12 @@ impl ShortNameGenerator {
buf
}
fn u16_to_u8_array(x: u16) -> [u8;4] {
fn u16_to_u8_array(x: u16) -> [u8; 4] {
let c1 = char::from_digit((x as u32 >> 12) & 0xF, 16).unwrap().to_ascii_uppercase() as u8;
let c2 = char::from_digit((x as u32 >> 8) & 0xF, 16).unwrap().to_ascii_uppercase() as u8;
let c3 = char::from_digit((x as u32 >> 4) & 0xF, 16).unwrap().to_ascii_uppercase() as u8;
let c4 = char::from_digit((x as u32 >> 0) & 0xF, 16).unwrap().to_ascii_uppercase() as u8;
return [c1, c2, c3, c4]
return [c1, c2, c3, c4];
}
}
@ -902,8 +920,14 @@ mod tests {
assert_eq!(&ShortNameGenerator::new("Foo.b").generate().unwrap(), "FOO B ".as_bytes());
assert_eq!(&ShortNameGenerator::new("Foo.baR").generate().unwrap(), "FOO BAR".as_bytes());
assert_eq!(&ShortNameGenerator::new("Foo+1.baR").generate().unwrap(), "FOO_1~1 BAR".as_bytes());
assert_eq!(&ShortNameGenerator::new("ver +1.2.text").generate().unwrap(), "VER_12~1TEX".as_bytes());
assert_eq!(&ShortNameGenerator::new(".bashrc.swp").generate().unwrap(), "BASHRC~1SWP".as_bytes());
assert_eq!(
&ShortNameGenerator::new("ver +1.2.text").generate().unwrap(),
"VER_12~1TEX".as_bytes()
);
assert_eq!(
&ShortNameGenerator::new(".bashrc.swp").generate().unwrap(),
"BASHRC~1SWP".as_bytes()
);
}
#[test]
@ -913,7 +937,9 @@ mod tests {
#[test]
fn test_lfn_checksum_overflow() {
lfn_checksum(&[0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8]);
lfn_checksum(&[
0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8,
]);
}
#[test]

View File

@ -1,23 +1,22 @@
use core::{fmt, str};
use core::iter::FromIterator;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::{String, Vec};
use core::char;
use io::prelude::*;
use core::iter::FromIterator;
use core::{fmt, str};
use io;
use io::prelude::*;
use io::Cursor;
use byteorder::{LittleEndian};
use byteorder_ext::{ReadBytesExt, WriteBytesExt};
#[cfg(feature = "chrono")]
use chrono::{TimeZone, Local, Datelike, Timelike};
use byteorder::LittleEndian;
use byteorder_ext::{ReadBytesExt, WriteBytesExt};
#[cfg(feature = "chrono")]
use chrono;
#[cfg(feature = "chrono")]
use chrono::{Datelike, Local, TimeZone, Timelike};
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::{Vec, String};
use fs::{FileSystem, FatType, ReadWriteSeek, OemCpConverter};
use file::File;
use dir::{Dir, DirRawStream};
use file::File;
use fs::{FatType, FileSystem, OemCpConverter, ReadWriteSeek};
bitflags! {
/// A FAT file attributes.
@ -60,14 +59,18 @@ impl ShortName {
pub(crate) fn new(raw_name: &[u8; 11]) -> Self {
// get name components length by looking for space character
let name_len = raw_name[0..8].iter().rposition(|x| *x != Self::PADDING).map(|p| p + 1).unwrap_or(0);
let ext_len = raw_name[8..11].iter().rposition(|x| *x != Self::PADDING).map(|p| p + 1).unwrap_or(0);
let ext_len = raw_name[8..11]
.iter()
.rposition(|x| *x != Self::PADDING)
.map(|p| p + 1)
.unwrap_or(0);
let mut name = [Self::PADDING; 12];
name[..name_len].copy_from_slice(&raw_name[..name_len]);
let total_len = if ext_len > 0 {
name[name_len] = '.' as u8;
name[name_len+1..name_len+1+ext_len].copy_from_slice(&raw_name[8..8+ext_len]);
name[name_len + 1..name_len + 1 + ext_len].copy_from_slice(&raw_name[8..8 + ext_len]);
// Return total name length
name_len+1+ext_len
name_len + 1 + ext_len
} else {
// No extension - return length of name part
name_len
@ -125,7 +128,8 @@ pub(crate) struct DirFileEntryData {
impl DirFileEntryData {
pub(crate) fn new(name: [u8; 11], attrs: FileAttributes) -> Self {
DirFileEntryData {
name, attrs,
name,
attrs,
..Default::default()
}
}
@ -157,9 +161,14 @@ impl DirFileEntryData {
}
pub(crate) fn first_cluster(&self, fat_type: FatType) -> Option<u32> {
let first_cluster_hi = if fat_type == FatType::Fat32 { self.first_cluster_hi } else { 0 };
let first_cluster_hi =
if fat_type == FatType::Fat32 { self.first_cluster_hi } else { 0 };
let n = ((first_cluster_hi as u32) << 16) | self.first_cluster_lo as u32;
if n == 0 { None } else { Some(n) }
if n == 0 {
None
} else {
Some(n)
}
}
pub(crate) fn set_first_cluster(&mut self, cluster: Option<u32>, fat_type: FatType) {
@ -314,7 +323,8 @@ pub(crate) struct DirLfnEntryData {
impl DirLfnEntryData {
pub(crate) fn new(order: u8, checksum: u8) -> Self {
DirLfnEntryData {
order, checksum,
order,
checksum,
attrs: FileAttributes::LFN,
..Default::default()
}
@ -322,8 +332,8 @@ impl DirLfnEntryData {
pub(crate) fn copy_name_from_slice(&mut self, lfn_part: &[u16; LFN_PART_LEN]) {
self.name_0.copy_from_slice(&lfn_part[0..5]);
self.name_1.copy_from_slice(&lfn_part[5..5+6]);
self.name_2.copy_from_slice(&lfn_part[11..11+2]);
self.name_1.copy_from_slice(&lfn_part[5..5 + 6]);
self.name_2.copy_from_slice(&lfn_part[11..11 + 2]);
}
pub(crate) fn copy_name_to_slice(&self, lfn_part: &mut [u16]) {
@ -394,10 +404,8 @@ impl DirEntryData {
Err(ref err) if err.kind() == io::ErrorKind::UnexpectedEof => {
// entries can occupy all clusters of directory so there is no zero entry at the end
// handle it here by returning non-existing empty entry
return Ok(DirEntryData::File(DirFileEntryData {
..Default::default()
}));
}
return Ok(DirEntryData::File(DirFileEntryData { ..Default::default() }));
},
Err(err) => return Err(err),
_ => {},
}
@ -405,7 +413,8 @@ impl DirEntryData {
if attrs & FileAttributes::LFN == FileAttributes::LFN {
// read long name entry
let mut data = DirLfnEntryData {
attrs, ..Default::default()
attrs,
..Default::default()
};
// use cursor to divide name into order and LFN name_0
let mut cur = Cursor::new(&name);
@ -544,9 +553,12 @@ impl From<Date> for chrono::Date<Local> {
#[cfg(feature = "chrono")]
impl From<DateTime> for chrono::DateTime<Local> {
fn from(date_time: DateTime) -> Self {
chrono::Date::<Local>::from(date_time.date)
.and_hms_milli(date_time.time.hour as u32, date_time.time.min as u32,
date_time.time.sec as u32, date_time.time.millis as u32)
chrono::Date::<Local>::from(date_time.date).and_hms_milli(
date_time.time.hour as u32,
date_time.time.min as u32,
date_time.time.sec as u32,
date_time.time.millis as u32,
)
}
}
@ -585,10 +597,7 @@ pub(crate) struct DirEntryEditor {
impl DirEntryEditor {
fn new(data: DirFileEntryData, pos: u64) -> Self {
DirEntryEditor {
data, pos,
dirty: false,
}
DirEntryEditor { data, pos, dirty: false }
}
pub(crate) fn inner(&self) -> &DirFileEntryData {
@ -671,7 +680,7 @@ pub struct DirEntry<'a, T: ReadWriteSeek + 'a> {
pub(crate) fs: &'a FileSystem<T>,
}
impl <'a, T: ReadWriteSeek> DirEntry<'a, T> {
impl<'a, T: ReadWriteSeek> DirEntry<'a, T> {
/// Returns short file name.
///
/// Non-ASCII characters are replaced by the replacement character (U+FFFD).
@ -789,7 +798,7 @@ impl <'a, T: ReadWriteSeek> DirEntry<'a, T> {
}
}
impl <'a, T: ReadWriteSeek> fmt::Debug for DirEntry<'a, T> {
impl<'a, T: ReadWriteSeek> fmt::Debug for DirEntry<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
self.data.fmt(f)
}
@ -802,20 +811,26 @@ mod tests {
#[test]
fn short_name_with_ext() {
let mut raw_short_name = [0u8;11];
let mut raw_short_name = [0u8; 11];
raw_short_name.copy_from_slice("FOO BAR".as_bytes());
assert_eq!(ShortName::new(&raw_short_name).to_string(&LOSSY_OEM_CP_CONVERTER), "FOO.BAR");
raw_short_name.copy_from_slice("LOOK AT M E".as_bytes());
assert_eq!(ShortName::new(&raw_short_name).to_string(&LOSSY_OEM_CP_CONVERTER), "LOOK AT.M E");
raw_short_name[0] = 0x99;
raw_short_name[10] = 0x99;
assert_eq!(ShortName::new(&raw_short_name).to_string(&LOSSY_OEM_CP_CONVERTER), "\u{FFFD}OOK AT.M \u{FFFD}");
assert_eq!(ShortName::new(&raw_short_name).eq_ignore_case("\u{FFFD}OOK AT.M \u{FFFD}", &LOSSY_OEM_CP_CONVERTER), true);
assert_eq!(
ShortName::new(&raw_short_name).to_string(&LOSSY_OEM_CP_CONVERTER),
"\u{FFFD}OOK AT.M \u{FFFD}"
);
assert_eq!(
ShortName::new(&raw_short_name).eq_ignore_case("\u{FFFD}OOK AT.M \u{FFFD}", &LOSSY_OEM_CP_CONVERTER),
true
);
}
#[test]
fn short_name_without_ext() {
let mut raw_short_name = [0u8;11];
let mut raw_short_name = [0u8; 11];
raw_short_name.copy_from_slice("FOO ".as_bytes());
assert_eq!(ShortName::new(&raw_short_name).to_string(&LOSSY_OEM_CP_CONVERTER), "FOO");
raw_short_name.copy_from_slice("LOOK AT ".as_bytes());
@ -824,23 +839,32 @@ mod tests {
#[test]
fn short_name_eq_ignore_case() {
let mut raw_short_name = [0u8;11];
let mut raw_short_name = [0u8; 11];
raw_short_name.copy_from_slice("LOOK AT M E".as_bytes());
raw_short_name[0] = 0x99;
raw_short_name[10] = 0x99;
assert_eq!(ShortName::new(&raw_short_name).eq_ignore_case("\u{FFFD}OOK AT.M \u{FFFD}", &LOSSY_OEM_CP_CONVERTER), true);
assert_eq!(ShortName::new(&raw_short_name).eq_ignore_case("\u{FFFD}ook AT.m \u{FFFD}", &LOSSY_OEM_CP_CONVERTER), true);
assert_eq!(
ShortName::new(&raw_short_name).eq_ignore_case("\u{FFFD}OOK AT.M \u{FFFD}", &LOSSY_OEM_CP_CONVERTER),
true
);
assert_eq!(
ShortName::new(&raw_short_name).eq_ignore_case("\u{FFFD}ook AT.m \u{FFFD}", &LOSSY_OEM_CP_CONVERTER),
true
);
}
#[test]
fn short_name_05_changed_to_e5() {
let raw_short_name = [0x05;11];
assert_eq!(ShortName::new(&raw_short_name).as_bytes(), [0xE5, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, '.' as u8, 0x05, 0x05, 0x05]);
let raw_short_name = [0x05; 11];
assert_eq!(
ShortName::new(&raw_short_name).as_bytes(),
[0xE5, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, '.' as u8, 0x05, 0x05, 0x05]
);
}
#[test]
fn lowercase_short_name() {
let mut raw_short_name = [0u8;11];
let mut raw_short_name = [0u8; 11];
raw_short_name.copy_from_slice("FOO RS ".as_bytes());
let mut raw_entry = DirFileEntryData {
name: raw_short_name,

View File

@ -1,11 +1,11 @@
use core::cmp;
use core;
use io::prelude::*;
use io::{SeekFrom, ErrorKind};
use core::cmp;
use io;
use io::prelude::*;
use io::{ErrorKind, SeekFrom};
use dir_entry::{Date, DateTime, DirEntryEditor};
use fs::{FileSystem, ReadWriteSeek};
use dir_entry::{DirEntryEditor, DateTime, Date};
const MAX_FILE_SIZE: u32 = core::u32::MAX;
@ -25,10 +25,12 @@ pub struct File<'a, T: ReadWriteSeek + 'a> {
fs: &'a FileSystem<T>,
}
impl <'a, T: ReadWriteSeek> File<'a, T> {
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,
first_cluster,
entry,
fs,
current_cluster: None, // cluster before first one
offset: 0,
}
@ -142,7 +144,7 @@ impl<'a, T: ReadWriteSeek> Drop for File<'a, T> {
}
// 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> {
impl<'a, T: ReadWriteSeek> Clone for File<'a, T> {
fn clone(&self) -> Self {
File {
first_cluster: self.first_cluster,
@ -246,7 +248,7 @@ impl<'a, T: ReadWriteSeek> Write for File<'a, T> {
let abs_pos = self.fs.offset_from_cluster(new_cluster);
let mut disk = self.fs.disk.borrow_mut();
disk.seek(SeekFrom::Start(abs_pos))?;
for _ in 0..cluster_size/32 {
for _ in 0..cluster_size / 32 {
let zero = [0u8; 32];
disk.write(&zero)?;
}
@ -290,7 +292,13 @@ impl<'a, T: ReadWriteSeek> Seek for File<'a, T> {
let mut new_pos = match pos {
SeekFrom::Current(x) => self.offset as i64 + x,
SeekFrom::Start(x) => x as i64,
SeekFrom::End(x) => self.entry.iter().next().map_or(None, |e| e.inner().size()).expect("cannot seek from end if size is unknown") as i64 + x,
SeekFrom::End(x) => {
self.entry
.iter()
.next()
.map_or(None, |e| e.inner().size())
.expect("cannot seek from end if size is unknown") as i64 + x
},
};
if new_pos < 0 {
return Err(io::Error::new(ErrorKind::InvalidInput, "Seek to a negative offset"));

View File

@ -1,20 +1,20 @@
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::String;
use core::cell::RefCell;
use core::cmp;
use core::char;
use core::cmp;
use core::iter::FromIterator;
use io;
use io::prelude::*;
use io::{Error, ErrorKind, SeekFrom};
use io;
use byteorder::LittleEndian;
use byteorder_ext::{ReadBytesExt, WriteBytesExt};
use file::File;
use dir::{DirRawStream, Dir};
use dir::{Dir, DirRawStream};
use dir_entry::DIR_ENTRY_SIZE;
use table::{ClusterIterator, alloc_cluster, read_fat_flags, count_free_clusters};
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::String;
use file::File;
use table::{alloc_cluster, count_free_clusters, read_fat_flags, ClusterIterator};
// FAT implementation based on:
// http://wiki.osdev.org/FAT
@ -68,11 +68,11 @@ impl FsStatusFlags {
/// A sum of `Read` and `Seek` traits.
pub trait ReadSeek: Read + Seek {}
impl<T> ReadSeek for T where T: Read + Seek {}
impl<T: Read + Seek> ReadSeek for T {}
/// A sum of `Read`, `Write` and `Seek` traits.
pub trait ReadWriteSeek: Read + Write + Seek {}
impl<T> ReadWriteSeek for T where T: Read + Write + Seek {}
impl<T: Read + Write + Seek> ReadWriteSeek for T {}
#[allow(dead_code)]
#[derive(Default, Debug, Clone)]
@ -113,7 +113,7 @@ impl BiosParameterBlock {
bpb.sectors_per_cluster = rdr.read_u8()?;
bpb.reserved_sectors = rdr.read_u16::<LittleEndian>()?;
bpb.fats = rdr.read_u8()?;
bpb.root_entries = rdr.read_u16::<LittleEndian>()? ;
bpb.root_entries = rdr.read_u16::<LittleEndian>()?;
bpb.total_sectors_16 = rdr.read_u16::<LittleEndian>()?;
bpb.media = rdr.read_u8()?;
bpb.sectors_per_fat_16 = rdr.read_u16::<LittleEndian>()?;
@ -259,7 +259,8 @@ impl FsInfoSector {
return Err(Error::new(ErrorKind::Other, "invalid trail_sig in FsInfo sector"));
}
Ok(FsInfoSector {
free_cluster_count, next_free_cluster,
free_cluster_count,
next_free_cluster,
dirty: false,
})
}
@ -365,7 +366,7 @@ pub struct FileSystem<T: ReadWriteSeek> {
fs_info: RefCell<FsInfoSector>,
}
impl <T: ReadWriteSeek> FileSystem<T> {
impl<T: ReadWriteSeek> FileSystem<T> {
/// Creates a new filesystem object instance.
///
/// Supplied `disk` parameter cannot be seeked. If there is a need to read a fragment of disk
@ -391,12 +392,16 @@ impl <T: ReadWriteSeek> FileSystem<T> {
return Err(Error::new(ErrorKind::Other, "Unknown FS version"));
}
let total_sectors =
if bpb.total_sectors_16 == 0 { bpb.total_sectors_32 }
else { bpb.total_sectors_16 as u32 };
let sectors_per_fat =
if bpb.sectors_per_fat_16 == 0 { bpb.sectors_per_fat_32 }
else { bpb.sectors_per_fat_16 as u32 };
let total_sectors = if bpb.total_sectors_16 == 0 {
bpb.total_sectors_32
} else {
bpb.total_sectors_16 as u32
};
let sectors_per_fat = if bpb.sectors_per_fat_16 == 0 {
bpb.sectors_per_fat_32
} else {
bpb.sectors_per_fat_16 as u32
};
let root_dir_bytes = bpb.root_entries as u32 * DIR_ENTRY_SIZE as u32;
let root_dir_sectors = (root_dir_bytes + (bpb.bytes_per_sector as u32 - 1)) / bpb.bytes_per_sector as u32;
let first_data_sector = bpb.reserved_sectors as u32 + (bpb.fats as u32 * sectors_per_fat) + root_dir_sectors;
@ -423,7 +428,7 @@ impl <T: ReadWriteSeek> FileSystem<T> {
disk: RefCell::new(disk),
options,
fat_type,
bpb: bpb,
bpb,
first_data_sector,
root_dir_sectors,
total_clusters,
@ -471,7 +476,11 @@ impl <T: ReadWriteSeek> FileSystem<T> {
let root_rdr = {
match self.fat_type {
FatType::Fat12 | FatType::Fat16 => DirRawStream::Root(DiskSlice::from_sectors(
self.first_data_sector - self.root_dir_sectors, self.root_dir_sectors, 1, self)),
self.first_data_sector - self.root_dir_sectors,
self.root_dir_sectors,
1,
self,
)),
_ => DirRawStream::File(File::new(Some(self.bpb.root_dir_first_cluster), None, self)),
}
};
@ -495,9 +504,11 @@ impl <T: ReadWriteSeek> FileSystem<T> {
}
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 };
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
};
let mirroring_enabled = self.bpb.mirroring_enabled();
let (fat_first_sector, mirrors) = if mirroring_enabled {
(self.bpb.reserved_sectors as u32, self.bpb.fats)
@ -616,14 +627,25 @@ pub(crate) struct DiskSlice<'a, T: ReadWriteSeek + 'a> {
fs: &'a FileSystem<T>,
}
impl <'a, T: ReadWriteSeek> DiskSlice<'a, T> {
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 }
DiskSlice {
begin,
size,
mirrors,
fs,
offset: 0,
}
}
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)
Self::new(
first_sector as u64 * bytes_per_sector,
sector_count as u64 * bytes_per_sector,
mirrors,
fs,
)
}
pub(crate) fn abs_pos(&self) -> u64 {
@ -632,7 +654,7 @@ impl <'a, T: ReadWriteSeek> DiskSlice<'a, T> {
}
// 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> {
impl<'a, T: ReadWriteSeek> Clone for DiskSlice<'a, T> {
fn clone(&self) -> Self {
DiskSlice {
begin: self.begin,
@ -644,7 +666,7 @@ impl <'a, T: ReadWriteSeek> Clone for DiskSlice<'a, T> {
}
}
impl <'a, T: ReadWriteSeek> Read for DiskSlice<'a, T> {
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());
@ -656,7 +678,7 @@ impl <'a, T: ReadWriteSeek> Read for DiskSlice<'a, T> {
}
}
impl <'a, T: ReadWriteSeek> Write for DiskSlice<'a, T> {
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());
@ -675,7 +697,7 @@ impl <'a, T: ReadWriteSeek> Write for DiskSlice<'a, T> {
}
}
impl <'a, T: ReadWriteSeek> Seek for DiskSlice<'a, T> {
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,

View File

@ -54,12 +54,10 @@
#![crate_type = "lib"]
#![crate_name = "fatfs"]
#![cfg_attr(not(feature="std"), no_std)]
#![cfg_attr(not(feature="std"), feature(alloc))]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))]
// Disable warnings to not clutter code with cfg too much
#![cfg_attr(not(feature="alloc"), allow(dead_code, unused_imports))]
#![cfg_attr(not(feature = "alloc"), allow(dead_code, unused_imports))]
extern crate byteorder;
@ -78,28 +76,28 @@ extern crate core_io;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
extern crate alloc;
mod fs;
mod dir;
mod dir_entry;
mod file;
mod fs;
mod table;
#[cfg(not(feature = "std"))]
mod byteorder_core_io;
#[cfg(not(feature = "std"))]
use byteorder_core_io as byteorder_ext;
#[cfg(feature = "std")]
use byteorder as byteorder_ext;
#[cfg(feature = "std")]
use std as core;
#[cfg(not(feature = "std"))]
use byteorder_core_io as byteorder_ext;
#[cfg(not(feature = "std"))]
use core_io as io;
#[cfg(feature = "std")]
use std as core;
#[cfg(feature = "std")]
use std::io as io;
use std::io;
pub use fs::*;
pub use dir::*;
pub use dir_entry::*;
pub use file::*;
pub use fs::*;

View File

@ -1,7 +1,9 @@
use io;
use byteorder::LittleEndian;
use byteorder_ext::{ReadBytesExt, WriteBytesExt};
use fs::{ReadWriteSeek, ReadSeek, FatType, FsStatusFlags};
use fs::{FatType, FsStatusFlags, ReadSeek, ReadWriteSeek};
struct Fat<T> {
#[allow(dead_code)]
@ -63,7 +65,13 @@ fn find_free_cluster<T: ReadSeek>(fat: &mut T, fat_type: FatType, start_cluster:
}
}
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> {
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,
@ -99,9 +107,7 @@ pub(crate) fn read_fat_flags<T: ReadSeek>(fat: &mut T, fat_type: FatType) -> io:
FatType::Fat16 => val & (1 << 14) == 0,
FatType::Fat32 => val & (1 << 26) == 0,
};
Ok(FsStatusFlags {
dirty, io_error,
})
Ok(FsStatusFlags { dirty, io_error })
}
pub(crate) fn count_free_clusters<T: ReadSeek>(fat: &mut T, fat_type: FatType, total_clusters: u32) -> io::Result<u32> {
@ -183,7 +189,7 @@ impl FatTrait for Fat12 {
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))?;
fat.seek(io::SeekFrom::Start((cluster * 3 / 2) as u64))?;
let mut prev_packed_val = 0u16;
while cluster < end_cluster {
let res = match cluster & 1 {
@ -210,7 +216,7 @@ impl FatTrait for Fat12 {
impl FatTrait for Fat16 {
fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32> {
fat.seek(io::SeekFrom::Start((cluster*2) as u64))?;
fat.seek(io::SeekFrom::Start((cluster * 2) as u64))?;
Ok(fat.read_u16::<LittleEndian>()? as u32)
}
@ -225,7 +231,7 @@ impl FatTrait for Fat16 {
}
fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> {
fat.seek(io::SeekFrom::Start((cluster*2) as u64))?;
fat.seek(io::SeekFrom::Start((cluster * 2) as u64))?;
let raw_val = match value {
FatValue::Free => 0,
FatValue::Bad => 0xFFF7,
@ -238,7 +244,7 @@ impl FatTrait for Fat16 {
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))?;
fat.seek(io::SeekFrom::Start((cluster * 2) as u64))?;
while cluster < end_cluster {
let val = fat.read_u16::<LittleEndian>()?;
if val == 0 {
@ -252,7 +258,7 @@ impl FatTrait for Fat16 {
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))?;
fat.seek(io::SeekFrom::Start((cluster * 2) as u64))?;
while cluster < end_cluster {
let val = fat.read_u16::<LittleEndian>()?;
if val == 0 {
@ -266,7 +272,7 @@ impl FatTrait for Fat16 {
impl FatTrait for Fat32 {
fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32> {
fat.seek(io::SeekFrom::Start((cluster*4) as u64))?;
fat.seek(io::SeekFrom::Start((cluster * 4) as u64))?;
Ok(fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF)
}
@ -281,7 +287,7 @@ impl FatTrait for Fat32 {
}
fn set<T: ReadWriteSeek>(fat: &mut T, cluster: u32, value: FatValue) -> io::Result<()> {
fat.seek(io::SeekFrom::Start((cluster*4) as u64))?;
fat.seek(io::SeekFrom::Start((cluster * 4) as u64))?;
let raw_val = match value {
FatValue::Free => 0,
FatValue::Bad => 0x0FFFFFF7,
@ -294,7 +300,7 @@ impl FatTrait for Fat32 {
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))?;
fat.seek(io::SeekFrom::Start((cluster * 4) as u64))?;
while cluster < end_cluster {
let val = fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF;
if val == 0 {
@ -308,7 +314,7 @@ impl FatTrait for Fat32 {
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))?;
fat.seek(io::SeekFrom::Start((cluster * 4) as u64))?;
while cluster < end_cluster {
let val = fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF;
if val == 0 {
@ -327,7 +333,7 @@ pub(crate) struct ClusterIterator<T: ReadWriteSeek> {
err: bool,
}
impl <T: ReadWriteSeek> ClusterIterator<T> {
impl<T: ReadWriteSeek> ClusterIterator<T> {
pub(crate) fn new(fat: T, fat_type: FatType, cluster: u32) -> Self {
ClusterIterator {
fat,
@ -362,7 +368,7 @@ impl <T: ReadWriteSeek> ClusterIterator<T> {
}
}
impl <T: ReadWriteSeek> Iterator for ClusterIterator<T> {
impl<T: ReadWriteSeek> Iterator for ClusterIterator<T> {
type Item = io::Result<u32>;
fn next(&mut self) -> Option<Self::Item> {
@ -417,7 +423,10 @@ mod tests {
// test reading from iterator
{
let iter = ClusterIterator::new(&mut cur, fat_type, 0x9);
assert_eq!(iter.map(|r| r.unwrap()).collect::<Vec<_>>(), vec![0xA, 0x14, 0x15, 0x16, 0x19, 0x1A]);
assert_eq!(
iter.map(|r| r.unwrap()).collect::<Vec<_>>(),
vec![0xA, 0x14, 0x15, 0x16, 0x19, 0x1A]
);
}
// test truncating a chain
{
@ -443,9 +452,9 @@ mod tests {
#[test]
fn test_fat12() {
let mut fat: Vec<u8> = vec![
0xF0, 0xFF, 0xFF, 0x03, 0x40, 0x00, 0x05, 0x60, 0x00, 0x07, 0x80, 0x00, 0xFF, 0xAF, 0x00, 0x14,
0xC0, 0x00, 0x0D, 0xE0, 0x00, 0x0F, 0x00, 0x01, 0x11, 0xF0, 0xFF, 0x00, 0xF0, 0xFF, 0x15, 0x60,
0x01, 0x19, 0x70, 0xFF, 0xF7, 0xAF, 0x01, 0xFF, 0x0F, 0x00, 0x00, 0x70, 0xFF, 0x00, 0x00, 0x00,
0xF0, 0xFF, 0xFF, 0x03, 0x40, 0x00, 0x05, 0x60, 0x00, 0x07, 0x80, 0x00, 0xFF, 0xAF, 0x00, 0x14, 0xC0, 0x00, 0x0D, 0xE0, 0x00,
0x0F, 0x00, 0x01, 0x11, 0xF0, 0xFF, 0x00, 0xF0, 0xFF, 0x15, 0x60, 0x01, 0x19, 0x70, 0xFF, 0xF7, 0xAF, 0x01, 0xFF, 0x0F, 0x00,
0x00, 0x70, 0xFF, 0x00, 0x00, 0x00,
];
test_fat(FatType::Fat12, io::Cursor::new(&mut fat));
}
@ -453,10 +462,10 @@ mod tests {
#[test]
fn test_fat16() {
let mut fat: Vec<u8> = vec![
0xF0, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00,
0xFF, 0xFF, 0x0A, 0x00, 0x14, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x10, 0x00,
0x11, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x15, 0x00, 0x16, 0x00, 0x19, 0x00, 0xF7, 0xFF,
0xF7, 0xFF, 0x1A, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xF0, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0xFF, 0xFF, 0x0A, 0x00, 0x14,
0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x10, 0x00, 0x11, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x15, 0x00,
0x16, 0x00, 0x19, 0x00, 0xF7, 0xFF, 0xF7, 0xFF, 0x1A, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0x00, 0x00, 0x00,
0x00,
];
test_fat(FatType::Fat16, io::Cursor::new(&mut fat));
}
@ -464,14 +473,13 @@ mod tests {
#[test]
fn test_fat32() {
let mut fat: Vec<u8> = vec![
0xF0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0x04, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x0F, 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F,
0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0xFF, 0x0F,
0xF7, 0xFF, 0xFF, 0x0F, 0x1A, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06,
0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00,
0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x00, 0x11, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x15, 0x00, 0x00, 0x00,
0x16, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0xFF, 0x0F, 0xF7, 0xFF, 0xFF, 0x0F, 0x1A, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
];
test_fat(FatType::Fat32, io::Cursor::new(&mut fat));
}

View File

@ -1,13 +1,13 @@
extern crate env_logger;
extern crate fatfs;
extern crate fscommon;
extern crate env_logger;
use std::fs;
use std::io::SeekFrom;
use std::io::prelude::*;
use std::io::SeekFrom;
use std::str;
use fatfs::{FsOptions, FatType};
use fatfs::{FatType, FsOptions};
use fscommon::BufStream;
const TEST_TEXT: &str = "Rust is cool!\n";
@ -228,30 +228,39 @@ fn test_status_flags_fat32() {
#[test]
fn test_stats_fat12() {
call_with_fs(&|fs| {
call_with_fs(
&|fs| {
let stats = fs.stats().unwrap();
assert_eq!(stats.cluster_size(), 512);
assert_eq!(stats.total_clusters(), 1955); // 1000 * 1024 / 512 = 2000
assert_eq!(stats.free_clusters(), 1920);
}, FAT12_IMG)
},
FAT12_IMG,
)
}
#[test]
fn test_stats_fat16() {
call_with_fs(&|fs| {
call_with_fs(
&|fs| {
let stats = fs.stats().unwrap();
assert_eq!(stats.cluster_size(), 512);
assert_eq!(stats.total_clusters(), 4927); // 2500 * 1024 / 512 = 5000
assert_eq!(stats.free_clusters(), 4892);
}, FAT16_IMG)
},
FAT16_IMG,
)
}
#[test]
fn test_stats_fat32() {
call_with_fs(&|fs| {
call_with_fs(
&|fs| {
let stats = fs.stats().unwrap();
assert_eq!(stats.cluster_size(), 512);
assert_eq!(stats.total_clusters(), 66922); // 34000 * 1024 / 512 = 68000
assert_eq!(stats.free_clusters(), 66886);
}, FAT32_IMG)
},
FAT32_IMG,
)
}

View File

@ -1,10 +1,10 @@
extern crate env_logger;
extern crate fatfs;
extern crate fscommon;
extern crate env_logger;
use std::fs;
use std::io::prelude::*;
use std::io;
use std::io::prelude::*;
use std::str;
use fatfs::FsOptions;
@ -154,12 +154,12 @@ fn test_create_file(fs: FileSystem) {
assert_eq!(&content, &TEST_STR);
}
// Create enough entries to allocate next cluster
for i in 0..512/32 {
for i in 0..512 / 32 {
let name = format!("test{}", i);
dir.create_file(&name).unwrap();
}
names = dir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
assert_eq!(names.len(), 4 + 512/32);
assert_eq!(names.len(), 4 + 512 / 32);
// check creating existing file opens it
{
let mut file = root_dir.create_file("very/long/path/new-file-with-long-name.txt").unwrap();