forked from M-Labs/rust-fatfs
Improve code style using rustfmt
This commit is contained in:
parent
98c0fa528c
commit
30f3f96537
@ -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 {
|
||||
|
@ -2,6 +2,7 @@ extern crate fatfs;
|
||||
extern crate fscommon;
|
||||
|
||||
use std::{fs, io};
|
||||
|
||||
use fatfs::{FileSystem, FsOptions};
|
||||
use fscommon::{BufStream, StreamSlice};
|
||||
|
||||
|
@ -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
7
rustfmt.toml
Normal 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
|
@ -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])
|
||||
|
124
src/dir.rs
124
src/dir.rs
@ -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]
|
||||
|
114
src/dir_entry.rs
114
src/dir_entry.rs
@ -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,
|
||||
|
26
src/file.rs
26
src/file.rs
@ -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"));
|
||||
|
84
src/fs.rs
84
src/fs.rs
@ -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,
|
||||
|
22
src/lib.rs
22
src/lib.rs
@ -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::*;
|
||||
|
72
src/table.rs
72
src/table.rs
@ -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));
|
||||
}
|
||||
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user