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 fatfs;
|
||||||
extern crate fscommon;
|
extern crate fscommon;
|
||||||
extern crate chrono;
|
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use chrono::{DateTime, Local};
|
|
||||||
|
|
||||||
|
use chrono::{DateTime, Local};
|
||||||
use fatfs::{FileSystem, FsOptions};
|
use fatfs::{FileSystem, FsOptions};
|
||||||
use fscommon::BufStream;
|
use fscommon::BufStream;
|
||||||
|
|
||||||
fn format_file_size(size: u64) -> String {
|
fn format_file_size(size: u64) -> String {
|
||||||
const KB: u64 = 1024;
|
const KB: u64 = 1024;
|
||||||
const MB: u64 = 1024*KB;
|
const MB: u64 = 1024 * KB;
|
||||||
const GB: u64 = 1024*MB;
|
const GB: u64 = 1024 * MB;
|
||||||
if size < 1024 {
|
if size < 1024 {
|
||||||
format!("{}B", size)
|
format!("{}B", size)
|
||||||
} else if size < MB {
|
} else if size < MB {
|
||||||
|
@ -2,6 +2,7 @@ extern crate fatfs;
|
|||||||
extern crate fscommon;
|
extern crate fscommon;
|
||||||
|
|
||||||
use std::{fs, io};
|
use std::{fs, io};
|
||||||
|
|
||||||
use fatfs::{FileSystem, FsOptions};
|
use fatfs::{FileSystem, FsOptions};
|
||||||
use fscommon::{BufStream, StreamSlice};
|
use fscommon::{BufStream, StreamSlice};
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ fn main() -> io::Result<()> {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("Failed to open image!");
|
println!("Failed to open image!");
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
let buf_stream = BufStream::new(img_file);
|
let buf_stream = BufStream::new(img_file);
|
||||||
let options = FsOptions::new().update_accessed_date(true);
|
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 core::slice;
|
||||||
|
use io::{self, Result};
|
||||||
|
|
||||||
use byteorder::ByteOrder;
|
use byteorder::ByteOrder;
|
||||||
|
|
||||||
@ -618,10 +618,7 @@ pub trait ReadBytesExt: io::Read {
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "i128")]
|
#[cfg(feature = "i128")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_u128_into<T: ByteOrder>(
|
fn read_u128_into<T: ByteOrder>(&mut self, dst: &mut [u128]) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
dst: &mut [u128],
|
|
||||||
) -> Result<()> {
|
|
||||||
{
|
{
|
||||||
let mut buf = unsafe { slice_to_u8_mut(dst) };
|
let mut buf = unsafe { slice_to_u8_mut(dst) };
|
||||||
try!(self.read_exact(buf));
|
try!(self.read_exact(buf));
|
||||||
@ -768,10 +765,7 @@ pub trait ReadBytesExt: io::Read {
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "i128")]
|
#[cfg(feature = "i128")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_i128_into<T: ByteOrder>(
|
fn read_i128_into<T: ByteOrder>(&mut self, dst: &mut [i128]) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
dst: &mut [i128],
|
|
||||||
) -> Result<()> {
|
|
||||||
{
|
{
|
||||||
let mut buf = unsafe { slice_to_u8_mut(dst) };
|
let mut buf = unsafe { slice_to_u8_mut(dst) };
|
||||||
try!(self.read_exact(buf));
|
try!(self.read_exact(buf));
|
||||||
@ -812,10 +806,7 @@ pub trait ReadBytesExt: io::Read {
|
|||||||
/// assert_eq!([f32::consts::PI, 1.0], dst);
|
/// assert_eq!([f32::consts::PI, 1.0], dst);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_f32_into<T: ByteOrder>(
|
fn read_f32_into<T: ByteOrder>(&mut self, dst: &mut [f32]) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
dst: &mut [f32],
|
|
||||||
) -> Result<()> {
|
|
||||||
{
|
{
|
||||||
let buf = unsafe { slice_to_u8_mut(dst) };
|
let buf = unsafe { slice_to_u8_mut(dst) };
|
||||||
try!(self.read_exact(buf));
|
try!(self.read_exact(buf));
|
||||||
@ -860,11 +851,8 @@ pub trait ReadBytesExt: io::Read {
|
|||||||
/// assert_eq!([f32::consts::PI, 1.0], dst);
|
/// assert_eq!([f32::consts::PI, 1.0], dst);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[deprecated(since="1.2.0", note="please use `read_f32_into` instead")]
|
#[deprecated(since = "1.2.0", note = "please use `read_f32_into` instead")]
|
||||||
fn read_f32_into_unchecked<T: ByteOrder>(
|
fn read_f32_into_unchecked<T: ByteOrder>(&mut self, dst: &mut [f32]) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
dst: &mut [f32],
|
|
||||||
) -> Result<()> {
|
|
||||||
self.read_f32_into::<T>(dst)
|
self.read_f32_into::<T>(dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -900,10 +888,7 @@ pub trait ReadBytesExt: io::Read {
|
|||||||
/// assert_eq!([f64::consts::PI, 1.0], dst);
|
/// assert_eq!([f64::consts::PI, 1.0], dst);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_f64_into<T: ByteOrder>(
|
fn read_f64_into<T: ByteOrder>(&mut self, dst: &mut [f64]) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
dst: &mut [f64],
|
|
||||||
) -> Result<()> {
|
|
||||||
{
|
{
|
||||||
let buf = unsafe { slice_to_u8_mut(dst) };
|
let buf = unsafe { slice_to_u8_mut(dst) };
|
||||||
try!(self.read_exact(buf));
|
try!(self.read_exact(buf));
|
||||||
@ -954,11 +939,8 @@ pub trait ReadBytesExt: io::Read {
|
|||||||
/// assert_eq!([f64::consts::PI, 1.0], dst);
|
/// assert_eq!([f64::consts::PI, 1.0], dst);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[deprecated(since="1.2.0", note="please use `read_f64_into` instead")]
|
#[deprecated(since = "1.2.0", note = "please use `read_f64_into` instead")]
|
||||||
fn read_f64_into_unchecked<T: ByteOrder>(
|
fn read_f64_into_unchecked<T: ByteOrder>(&mut self, dst: &mut [f64]) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
dst: &mut [f64],
|
|
||||||
) -> Result<()> {
|
|
||||||
self.read_f64_into::<T>(dst)
|
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,
|
/// If the given integer is not representable in the given number of bytes,
|
||||||
/// this method panics. If `nbytes > 8`, this method panics.
|
/// this method panics. If `nbytes > 8`, this method panics.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_uint<T: ByteOrder>(
|
fn write_uint<T: ByteOrder>(&mut self, n: u64, nbytes: usize) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
n: u64,
|
|
||||||
nbytes: usize,
|
|
||||||
) -> Result<()> {
|
|
||||||
let mut buf = [0; 8];
|
let mut buf = [0; 8];
|
||||||
T::write_uint(&mut buf, n, nbytes);
|
T::write_uint(&mut buf, n, nbytes);
|
||||||
self.write_all(&buf[0..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,
|
/// If the given integer is not representable in the given number of bytes,
|
||||||
/// this method panics. If `nbytes > 8`, this method panics.
|
/// this method panics. If `nbytes > 8`, this method panics.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_int<T: ByteOrder>(
|
fn write_int<T: ByteOrder>(&mut self, n: i64, nbytes: usize) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
n: i64,
|
|
||||||
nbytes: usize,
|
|
||||||
) -> Result<()> {
|
|
||||||
let mut buf = [0; 8];
|
let mut buf = [0; 8];
|
||||||
T::write_int(&mut buf, n, nbytes);
|
T::write_int(&mut buf, n, nbytes);
|
||||||
self.write_all(&buf[0..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.
|
/// this method panics. If `nbytes > 16`, this method panics.
|
||||||
#[cfg(feature = "i128")]
|
#[cfg(feature = "i128")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_uint128<T: ByteOrder>(
|
fn write_uint128<T: ByteOrder>(&mut self, n: u128, nbytes: usize) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
n: u128,
|
|
||||||
nbytes: usize,
|
|
||||||
) -> Result<()> {
|
|
||||||
let mut buf = [0; 16];
|
let mut buf = [0; 16];
|
||||||
T::write_uint128(&mut buf, n, nbytes);
|
T::write_uint128(&mut buf, n, nbytes);
|
||||||
self.write_all(&buf[0..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.
|
/// this method panics. If `nbytes > 16`, this method panics.
|
||||||
#[cfg(feature = "i128")]
|
#[cfg(feature = "i128")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_int128<T: ByteOrder>(
|
fn write_int128<T: ByteOrder>(&mut self, n: i128, nbytes: usize) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
n: i128,
|
|
||||||
nbytes: usize,
|
|
||||||
) -> Result<()> {
|
|
||||||
let mut buf = [0; 16];
|
let mut buf = [0; 16];
|
||||||
T::write_int128(&mut buf, n, nbytes);
|
T::write_int128(&mut buf, n, nbytes);
|
||||||
self.write_all(&buf[0..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"))]
|
#[cfg(all(not(feature = "std"), feature = "alloc"))]
|
||||||
use alloc::Vec;
|
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> {
|
pub(crate) enum DirRawStream<'a, T: ReadWriteSeek + 'a> {
|
||||||
File(File<'a, T>),
|
File(File<'a, T>),
|
||||||
Root(DiskSlice<'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> {
|
fn abs_pos(&self) -> Option<u64> {
|
||||||
match self {
|
match self {
|
||||||
&DirRawStream::File(ref file) => file.abs_pos(),
|
&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
|
// 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 {
|
fn clone(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
&DirRawStream::File(ref file) => DirRawStream::File(file.clone()),
|
&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> {
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
match self {
|
match self {
|
||||||
&mut DirRawStream::File(ref mut file) => file.read(buf),
|
&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> {
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
match self {
|
match self {
|
||||||
&mut DirRawStream::File(ref mut file) => file.write(buf),
|
&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> {
|
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
||||||
match self {
|
match self {
|
||||||
&mut DirRawStream::File(ref mut file) => file.seek(pos),
|
&mut DirRawStream::File(ref mut file) => file.seek(pos),
|
||||||
@ -102,7 +99,7 @@ pub struct Dir<'a, T: ReadWriteSeek + 'a> {
|
|||||||
fs: &'a FileSystem<T>,
|
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 {
|
pub(crate) fn new(stream: DirRawStream<'a, T>, fs: &'a FileSystem<T>) -> Self {
|
||||||
Dir { stream, fs }
|
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() {
|
for r in self.iter() {
|
||||||
let e = r?;
|
let e = r?;
|
||||||
// compare name ignoring case
|
// 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)
|
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<()> {
|
fn rename_internal(&self, src_name: &str, dst_dir: &Dir<T>, dst_name: &str) -> io::Result<()> {
|
||||||
trace!("moving {} to {}", src_name, dst_name);
|
trace!("moving {} to {}", src_name, dst_name);
|
||||||
// find existing file
|
// 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
|
// 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 {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stream: self.stream.clone(),
|
stream: self.stream.clone(),
|
||||||
@ -454,7 +455,7 @@ pub struct DirIter<'a, T: ReadWriteSeek + 'a> {
|
|||||||
err: bool,
|
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>>> {
|
fn read_dir_entry(&mut self) -> io::Result<Option<DirEntry<'a, T>>> {
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
let mut lfn_buf = LongNameBuilder::new();
|
let mut lfn_buf = LongNameBuilder::new();
|
||||||
@ -504,14 +505,14 @@ impl <'a, T: ReadWriteSeek> DirIter<'a, T> {
|
|||||||
// Append to LFN buffer
|
// Append to LFN buffer
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
lfn_buf.process(&data);
|
lfn_buf.process(&data);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: derive cannot be used because of invalid bounds. See: https://github.com/rust-lang/rust/issues/26925
|
// 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 {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stream: self.stream.clone(),
|
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>>;
|
type Item = io::Result<DirEntry<'a, T>>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
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
|
// check if there are only valid characters
|
||||||
for c in name.chars() {
|
for c in name.chars() {
|
||||||
match c {
|
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")),
|
_ => 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
|
// Truncate 0 and 0xFFFF characters from LFN buffer
|
||||||
let mut lfn_len = self.buf.len();
|
let mut lfn_len = self.buf.len();
|
||||||
while lfn_len > 0 {
|
while lfn_len > 0 {
|
||||||
match self.buf[lfn_len-1] {
|
match self.buf[lfn_len - 1] {
|
||||||
0xFFFF | 0 => lfn_len -= 1,
|
0xFFFF | 0 => lfn_len -= 1,
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
@ -629,7 +631,13 @@ impl LongNameBuilder {
|
|||||||
self.buf.resize(index as usize * LFN_PART_LEN, 0);
|
self.buf.resize(index as usize * LFN_PART_LEN, 0);
|
||||||
} else if self.index == 0 || index != self.index - 1 || data.checksum() != self.chksum {
|
} else if self.index == 0 || index != self.index - 1 || data.checksum() != self.chksum {
|
||||||
// Corrupted entry
|
// 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();
|
self.clear();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -638,7 +646,7 @@ impl LongNameBuilder {
|
|||||||
}
|
}
|
||||||
let pos = LFN_PART_LEN * (index - 1) as usize;
|
let pos = LFN_PART_LEN * (index - 1) as usize;
|
||||||
// copy name parts into LFN buffer
|
// 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]) {
|
fn validate_chksum(&mut self, short_name: &[u8]) {
|
||||||
@ -710,7 +718,7 @@ impl<'a> Iterator for LfnEntriesGenerator<'a> {
|
|||||||
// end of name
|
// end of name
|
||||||
self.ended = true;
|
self.ended = true;
|
||||||
None
|
None
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -744,18 +752,21 @@ impl ShortNameGenerator {
|
|||||||
Some(index) => {
|
Some(index) => {
|
||||||
// extension found - copy parts before and after dot
|
// 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 (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)
|
(basename_len, basename_fits && ext_fits, basename_lossy || ext_lossy)
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
// no extension - copy name and leave extension empty
|
// 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);
|
let (basename_len, basename_fits, basename_lossy) = Self::copy_short_name_part(&mut short_name[0..8], &name);
|
||||||
(basename_len, basename_fits, basename_lossy)
|
(basename_len, basename_fits, basename_lossy)
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
let chksum = Self::checksum(name);
|
let chksum = Self::checksum(name);
|
||||||
Self {
|
Self {
|
||||||
short_name, chksum, name_fits, lossy_conv,
|
short_name,
|
||||||
|
chksum,
|
||||||
|
name_fits,
|
||||||
|
lossy_conv,
|
||||||
basename_len: basename_len as u8,
|
basename_len: basename_len as u8,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
@ -777,9 +788,8 @@ impl ShortNameGenerator {
|
|||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
// copy allowed characters
|
// copy allowed characters
|
||||||
'A'...'Z' | 'a'...'z' | '0'...'9' |
|
'A'...'Z' | 'a'...'z' | '0'...'9' => c,
|
||||||
'!' | '#' | '$' | '%' | '&' | '\'' | '(' | ')' |
|
'!' | '#' | '$' | '%' | '&' | '\'' | '(' | ')' | '-' | '@' | '^' | '_' | '`' | '{' | '}' | '~' => c,
|
||||||
'-' | '@' | '^' | '_' | '`' | '{' | '}' | '~' => c,
|
|
||||||
// replace disallowed characters by underscore
|
// replace disallowed characters by underscore
|
||||||
_ => '_',
|
_ => '_',
|
||||||
};
|
};
|
||||||
@ -800,7 +810,11 @@ impl ShortNameGenerator {
|
|||||||
}
|
}
|
||||||
// check for long prefix form collision (TEXTFI~1.TXT)
|
// check for long prefix form collision (TEXTFI~1.TXT)
|
||||||
let prefix_len = cmp::min(self.basename_len, 6) as usize;
|
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..];
|
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 {
|
if short_name[..prefix_len] == self.short_name[..prefix_len] && num_suffix.is_some() && ext_matches {
|
||||||
let num = num_suffix.unwrap(); // SAFE
|
let num = num_suffix.unwrap(); // SAFE
|
||||||
@ -809,9 +823,13 @@ impl ShortNameGenerator {
|
|||||||
|
|
||||||
// check for short prefix + checksum form collision (TE021F~1.TXT)
|
// check for short prefix + checksum form collision (TE021F~1.TXT)
|
||||||
let prefix_len = cmp::min(self.basename_len, 2) as usize;
|
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 {
|
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)) {
|
if chksum_res == Ok(Ok(self.chksum)) {
|
||||||
let num = num_suffix.unwrap(); // SAFE
|
let num = num_suffix.unwrap(); // SAFE
|
||||||
self.prefix_chksum_bitmap |= 1 << num;
|
self.prefix_chksum_bitmap |= 1 << num;
|
||||||
@ -876,12 +894,12 @@ impl ShortNameGenerator {
|
|||||||
buf
|
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 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 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 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;
|
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.b").generate().unwrap(), "FOO B ".as_bytes());
|
||||||
assert_eq!(&ShortNameGenerator::new("Foo.baR").generate().unwrap(), "FOO BAR".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("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!(
|
||||||
assert_eq!(&ShortNameGenerator::new(".bashrc.swp").generate().unwrap(), "BASHRC~1SWP".as_bytes());
|
&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]
|
#[test]
|
||||||
@ -913,7 +937,9 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lfn_checksum_overflow() {
|
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]
|
#[test]
|
||||||
|
130
src/dir_entry.rs
130
src/dir_entry.rs
@ -1,23 +1,22 @@
|
|||||||
use core::{fmt, str};
|
#[cfg(all(not(feature = "std"), feature = "alloc"))]
|
||||||
use core::iter::FromIterator;
|
use alloc::{String, Vec};
|
||||||
use core::char;
|
use core::char;
|
||||||
use io::prelude::*;
|
use core::iter::FromIterator;
|
||||||
|
use core::{fmt, str};
|
||||||
use io;
|
use io;
|
||||||
|
use io::prelude::*;
|
||||||
use io::Cursor;
|
use io::Cursor;
|
||||||
use byteorder::{LittleEndian};
|
|
||||||
use byteorder_ext::{ReadBytesExt, WriteBytesExt};
|
|
||||||
|
|
||||||
#[cfg(feature = "chrono")]
|
use byteorder::LittleEndian;
|
||||||
use chrono::{TimeZone, Local, Datelike, Timelike};
|
use byteorder_ext::{ReadBytesExt, WriteBytesExt};
|
||||||
#[cfg(feature = "chrono")]
|
#[cfg(feature = "chrono")]
|
||||||
use 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 dir::{Dir, DirRawStream};
|
||||||
|
use file::File;
|
||||||
|
use fs::{FatType, FileSystem, OemCpConverter, ReadWriteSeek};
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// A FAT file attributes.
|
/// A FAT file attributes.
|
||||||
@ -60,14 +59,18 @@ impl ShortName {
|
|||||||
pub(crate) fn new(raw_name: &[u8; 11]) -> Self {
|
pub(crate) fn new(raw_name: &[u8; 11]) -> Self {
|
||||||
// get name components length by looking for space character
|
// 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 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];
|
let mut name = [Self::PADDING; 12];
|
||||||
name[..name_len].copy_from_slice(&raw_name[..name_len]);
|
name[..name_len].copy_from_slice(&raw_name[..name_len]);
|
||||||
let total_len = if ext_len > 0 {
|
let total_len = if ext_len > 0 {
|
||||||
name[name_len] = '.' as u8;
|
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
|
// Return total name length
|
||||||
name_len+1+ext_len
|
name_len + 1 + ext_len
|
||||||
} else {
|
} else {
|
||||||
// No extension - return length of name part
|
// No extension - return length of name part
|
||||||
name_len
|
name_len
|
||||||
@ -125,7 +128,8 @@ pub(crate) struct DirFileEntryData {
|
|||||||
impl DirFileEntryData {
|
impl DirFileEntryData {
|
||||||
pub(crate) fn new(name: [u8; 11], attrs: FileAttributes) -> Self {
|
pub(crate) fn new(name: [u8; 11], attrs: FileAttributes) -> Self {
|
||||||
DirFileEntryData {
|
DirFileEntryData {
|
||||||
name, attrs,
|
name,
|
||||||
|
attrs,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,9 +161,14 @@ impl DirFileEntryData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn first_cluster(&self, fat_type: FatType) -> Option<u32> {
|
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;
|
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) {
|
pub(crate) fn set_first_cluster(&mut self, cluster: Option<u32>, fat_type: FatType) {
|
||||||
@ -314,7 +323,8 @@ pub(crate) struct DirLfnEntryData {
|
|||||||
impl DirLfnEntryData {
|
impl DirLfnEntryData {
|
||||||
pub(crate) fn new(order: u8, checksum: u8) -> Self {
|
pub(crate) fn new(order: u8, checksum: u8) -> Self {
|
||||||
DirLfnEntryData {
|
DirLfnEntryData {
|
||||||
order, checksum,
|
order,
|
||||||
|
checksum,
|
||||||
attrs: FileAttributes::LFN,
|
attrs: FileAttributes::LFN,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
@ -322,8 +332,8 @@ impl DirLfnEntryData {
|
|||||||
|
|
||||||
pub(crate) fn copy_name_from_slice(&mut self, lfn_part: &[u16; LFN_PART_LEN]) {
|
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_0.copy_from_slice(&lfn_part[0..5]);
|
||||||
self.name_1.copy_from_slice(&lfn_part[5..5+6]);
|
self.name_1.copy_from_slice(&lfn_part[5..5 + 6]);
|
||||||
self.name_2.copy_from_slice(&lfn_part[11..11+2]);
|
self.name_2.copy_from_slice(&lfn_part[11..11 + 2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn copy_name_to_slice(&self, lfn_part: &mut [u16]) {
|
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 => {
|
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
|
// 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
|
// handle it here by returning non-existing empty entry
|
||||||
return Ok(DirEntryData::File(DirFileEntryData {
|
return Ok(DirEntryData::File(DirFileEntryData { ..Default::default() }));
|
||||||
..Default::default()
|
},
|
||||||
}));
|
|
||||||
}
|
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
@ -405,7 +413,8 @@ impl DirEntryData {
|
|||||||
if attrs & FileAttributes::LFN == FileAttributes::LFN {
|
if attrs & FileAttributes::LFN == FileAttributes::LFN {
|
||||||
// read long name entry
|
// read long name entry
|
||||||
let mut data = DirLfnEntryData {
|
let mut data = DirLfnEntryData {
|
||||||
attrs, ..Default::default()
|
attrs,
|
||||||
|
..Default::default()
|
||||||
};
|
};
|
||||||
// use cursor to divide name into order and LFN name_0
|
// use cursor to divide name into order and LFN name_0
|
||||||
let mut cur = Cursor::new(&name);
|
let mut cur = Cursor::new(&name);
|
||||||
@ -422,16 +431,16 @@ impl DirEntryData {
|
|||||||
let data = DirFileEntryData {
|
let data = DirFileEntryData {
|
||||||
name,
|
name,
|
||||||
attrs,
|
attrs,
|
||||||
reserved_0: rdr.read_u8()?,
|
reserved_0: rdr.read_u8()?,
|
||||||
create_time_0: rdr.read_u8()?,
|
create_time_0: rdr.read_u8()?,
|
||||||
create_time_1: rdr.read_u16::<LittleEndian>()?,
|
create_time_1: rdr.read_u16::<LittleEndian>()?,
|
||||||
create_date: rdr.read_u16::<LittleEndian>()?,
|
create_date: rdr.read_u16::<LittleEndian>()?,
|
||||||
access_date: rdr.read_u16::<LittleEndian>()?,
|
access_date: rdr.read_u16::<LittleEndian>()?,
|
||||||
first_cluster_hi: rdr.read_u16::<LittleEndian>()?,
|
first_cluster_hi: rdr.read_u16::<LittleEndian>()?,
|
||||||
modify_time: rdr.read_u16::<LittleEndian>()?,
|
modify_time: rdr.read_u16::<LittleEndian>()?,
|
||||||
modify_date: rdr.read_u16::<LittleEndian>()?,
|
modify_date: rdr.read_u16::<LittleEndian>()?,
|
||||||
first_cluster_lo: rdr.read_u16::<LittleEndian>()?,
|
first_cluster_lo: rdr.read_u16::<LittleEndian>()?,
|
||||||
size: rdr.read_u32::<LittleEndian>()?,
|
size: rdr.read_u32::<LittleEndian>()?,
|
||||||
};
|
};
|
||||||
Ok(DirEntryData::File(data))
|
Ok(DirEntryData::File(data))
|
||||||
}
|
}
|
||||||
@ -544,9 +553,12 @@ impl From<Date> for chrono::Date<Local> {
|
|||||||
#[cfg(feature = "chrono")]
|
#[cfg(feature = "chrono")]
|
||||||
impl From<DateTime> for chrono::DateTime<Local> {
|
impl From<DateTime> for chrono::DateTime<Local> {
|
||||||
fn from(date_time: DateTime) -> Self {
|
fn from(date_time: DateTime) -> Self {
|
||||||
chrono::Date::<Local>::from(date_time.date)
|
chrono::Date::<Local>::from(date_time.date).and_hms_milli(
|
||||||
.and_hms_milli(date_time.time.hour as u32, date_time.time.min as u32,
|
date_time.time.hour as u32,
|
||||||
date_time.time.sec as u32, date_time.time.millis 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 {
|
impl DirEntryEditor {
|
||||||
fn new(data: DirFileEntryData, pos: u64) -> Self {
|
fn new(data: DirFileEntryData, pos: u64) -> Self {
|
||||||
DirEntryEditor {
|
DirEntryEditor { data, pos, dirty: false }
|
||||||
data, pos,
|
|
||||||
dirty: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn inner(&self) -> &DirFileEntryData {
|
pub(crate) fn inner(&self) -> &DirFileEntryData {
|
||||||
@ -671,7 +680,7 @@ pub struct DirEntry<'a, T: ReadWriteSeek + 'a> {
|
|||||||
pub(crate) fs: &'a FileSystem<T>,
|
pub(crate) fs: &'a FileSystem<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a, T: ReadWriteSeek> DirEntry<'a, T> {
|
impl<'a, T: ReadWriteSeek> DirEntry<'a, T> {
|
||||||
/// Returns short file name.
|
/// Returns short file name.
|
||||||
///
|
///
|
||||||
/// Non-ASCII characters are replaced by the replacement character (U+FFFD).
|
/// 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> {
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
self.data.fmt(f)
|
self.data.fmt(f)
|
||||||
}
|
}
|
||||||
@ -802,20 +811,26 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn short_name_with_ext() {
|
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());
|
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");
|
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());
|
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");
|
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[0] = 0x99;
|
||||||
raw_short_name[10] = 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!(
|
||||||
assert_eq!(ShortName::new(&raw_short_name).eq_ignore_case("\u{FFFD}OOK AT.M \u{FFFD}", &LOSSY_OEM_CP_CONVERTER), true);
|
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]
|
#[test]
|
||||||
fn short_name_without_ext() {
|
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());
|
raw_short_name.copy_from_slice("FOO ".as_bytes());
|
||||||
assert_eq!(ShortName::new(&raw_short_name).to_string(&LOSSY_OEM_CP_CONVERTER), "FOO");
|
assert_eq!(ShortName::new(&raw_short_name).to_string(&LOSSY_OEM_CP_CONVERTER), "FOO");
|
||||||
raw_short_name.copy_from_slice("LOOK AT ".as_bytes());
|
raw_short_name.copy_from_slice("LOOK AT ".as_bytes());
|
||||||
@ -824,23 +839,32 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn short_name_eq_ignore_case() {
|
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.copy_from_slice("LOOK AT M E".as_bytes());
|
||||||
raw_short_name[0] = 0x99;
|
raw_short_name[0] = 0x99;
|
||||||
raw_short_name[10] = 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!(
|
||||||
assert_eq!(ShortName::new(&raw_short_name).eq_ignore_case("\u{FFFD}ook AT.m \u{FFFD}", &LOSSY_OEM_CP_CONVERTER), true);
|
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]
|
#[test]
|
||||||
fn short_name_05_changed_to_e5() {
|
fn short_name_05_changed_to_e5() {
|
||||||
let raw_short_name = [0x05;11];
|
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]);
|
assert_eq!(
|
||||||
|
ShortName::new(&raw_short_name).as_bytes(),
|
||||||
|
[0xE5, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, '.' as u8, 0x05, 0x05, 0x05]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lowercase_short_name() {
|
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());
|
raw_short_name.copy_from_slice("FOO RS ".as_bytes());
|
||||||
let mut raw_entry = DirFileEntryData {
|
let mut raw_entry = DirFileEntryData {
|
||||||
name: raw_short_name,
|
name: raw_short_name,
|
||||||
|
26
src/file.rs
26
src/file.rs
@ -1,11 +1,11 @@
|
|||||||
use core::cmp;
|
|
||||||
use core;
|
use core;
|
||||||
use io::prelude::*;
|
use core::cmp;
|
||||||
use io::{SeekFrom, ErrorKind};
|
|
||||||
use io;
|
use io;
|
||||||
|
use io::prelude::*;
|
||||||
|
use io::{ErrorKind, SeekFrom};
|
||||||
|
|
||||||
|
use dir_entry::{Date, DateTime, DirEntryEditor};
|
||||||
use fs::{FileSystem, ReadWriteSeek};
|
use fs::{FileSystem, ReadWriteSeek};
|
||||||
use dir_entry::{DirEntryEditor, DateTime, Date};
|
|
||||||
|
|
||||||
const MAX_FILE_SIZE: u32 = core::u32::MAX;
|
const MAX_FILE_SIZE: u32 = core::u32::MAX;
|
||||||
|
|
||||||
@ -25,10 +25,12 @@ pub struct File<'a, T: ReadWriteSeek + 'a> {
|
|||||||
fs: &'a FileSystem<T>,
|
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 {
|
pub(crate) fn new(first_cluster: Option<u32>, entry: Option<DirEntryEditor>, fs: &'a FileSystem<T>) -> Self {
|
||||||
File {
|
File {
|
||||||
first_cluster, entry, fs,
|
first_cluster,
|
||||||
|
entry,
|
||||||
|
fs,
|
||||||
current_cluster: None, // cluster before first one
|
current_cluster: None, // cluster before first one
|
||||||
offset: 0,
|
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
|
// 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 {
|
fn clone(&self) -> Self {
|
||||||
File {
|
File {
|
||||||
first_cluster: self.first_cluster,
|
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 abs_pos = self.fs.offset_from_cluster(new_cluster);
|
||||||
let mut disk = self.fs.disk.borrow_mut();
|
let mut disk = self.fs.disk.borrow_mut();
|
||||||
disk.seek(SeekFrom::Start(abs_pos))?;
|
disk.seek(SeekFrom::Start(abs_pos))?;
|
||||||
for _ in 0..cluster_size/32 {
|
for _ in 0..cluster_size / 32 {
|
||||||
let zero = [0u8; 32];
|
let zero = [0u8; 32];
|
||||||
disk.write(&zero)?;
|
disk.write(&zero)?;
|
||||||
}
|
}
|
||||||
@ -290,7 +292,13 @@ impl<'a, T: ReadWriteSeek> Seek for File<'a, T> {
|
|||||||
let mut new_pos = match pos {
|
let mut new_pos = match pos {
|
||||||
SeekFrom::Current(x) => self.offset as i64 + x,
|
SeekFrom::Current(x) => self.offset as i64 + x,
|
||||||
SeekFrom::Start(x) => x as i64,
|
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 {
|
if new_pos < 0 {
|
||||||
return Err(io::Error::new(ErrorKind::InvalidInput, "Seek to a negative offset"));
|
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::cell::RefCell;
|
||||||
use core::cmp;
|
|
||||||
use core::char;
|
use core::char;
|
||||||
|
use core::cmp;
|
||||||
use core::iter::FromIterator;
|
use core::iter::FromIterator;
|
||||||
|
use io;
|
||||||
use io::prelude::*;
|
use io::prelude::*;
|
||||||
use io::{Error, ErrorKind, SeekFrom};
|
use io::{Error, ErrorKind, SeekFrom};
|
||||||
use io;
|
|
||||||
use byteorder::LittleEndian;
|
use byteorder::LittleEndian;
|
||||||
use byteorder_ext::{ReadBytesExt, WriteBytesExt};
|
use byteorder_ext::{ReadBytesExt, WriteBytesExt};
|
||||||
|
|
||||||
use file::File;
|
use dir::{Dir, DirRawStream};
|
||||||
use dir::{DirRawStream, Dir};
|
|
||||||
use dir_entry::DIR_ENTRY_SIZE;
|
use dir_entry::DIR_ENTRY_SIZE;
|
||||||
use table::{ClusterIterator, alloc_cluster, read_fat_flags, count_free_clusters};
|
use file::File;
|
||||||
|
use table::{alloc_cluster, count_free_clusters, read_fat_flags, ClusterIterator};
|
||||||
#[cfg(all(not(feature = "std"), feature = "alloc"))]
|
|
||||||
use alloc::String;
|
|
||||||
|
|
||||||
// FAT implementation based on:
|
// FAT implementation based on:
|
||||||
// http://wiki.osdev.org/FAT
|
// http://wiki.osdev.org/FAT
|
||||||
@ -68,11 +68,11 @@ impl FsStatusFlags {
|
|||||||
|
|
||||||
/// A sum of `Read` and `Seek` traits.
|
/// A sum of `Read` and `Seek` traits.
|
||||||
pub trait ReadSeek: Read + Seek {}
|
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.
|
/// A sum of `Read`, `Write` and `Seek` traits.
|
||||||
pub trait ReadWriteSeek: Read + Write + Seek {}
|
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)]
|
#[allow(dead_code)]
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
@ -113,7 +113,7 @@ impl BiosParameterBlock {
|
|||||||
bpb.sectors_per_cluster = rdr.read_u8()?;
|
bpb.sectors_per_cluster = rdr.read_u8()?;
|
||||||
bpb.reserved_sectors = rdr.read_u16::<LittleEndian>()?;
|
bpb.reserved_sectors = rdr.read_u16::<LittleEndian>()?;
|
||||||
bpb.fats = rdr.read_u8()?;
|
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.total_sectors_16 = rdr.read_u16::<LittleEndian>()?;
|
||||||
bpb.media = rdr.read_u8()?;
|
bpb.media = rdr.read_u8()?;
|
||||||
bpb.sectors_per_fat_16 = rdr.read_u16::<LittleEndian>()?;
|
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"));
|
return Err(Error::new(ErrorKind::Other, "invalid trail_sig in FsInfo sector"));
|
||||||
}
|
}
|
||||||
Ok(FsInfoSector {
|
Ok(FsInfoSector {
|
||||||
free_cluster_count, next_free_cluster,
|
free_cluster_count,
|
||||||
|
next_free_cluster,
|
||||||
dirty: false,
|
dirty: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -365,7 +366,7 @@ pub struct FileSystem<T: ReadWriteSeek> {
|
|||||||
fs_info: RefCell<FsInfoSector>,
|
fs_info: RefCell<FsInfoSector>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T: ReadWriteSeek> FileSystem<T> {
|
impl<T: ReadWriteSeek> FileSystem<T> {
|
||||||
/// Creates a new filesystem object instance.
|
/// Creates a new filesystem object instance.
|
||||||
///
|
///
|
||||||
/// Supplied `disk` parameter cannot be seeked. If there is a need to read a fragment of disk
|
/// 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"));
|
return Err(Error::new(ErrorKind::Other, "Unknown FS version"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let total_sectors =
|
let total_sectors = if bpb.total_sectors_16 == 0 {
|
||||||
if bpb.total_sectors_16 == 0 { bpb.total_sectors_32 }
|
bpb.total_sectors_32
|
||||||
else { bpb.total_sectors_16 as u32 };
|
} else {
|
||||||
let sectors_per_fat =
|
bpb.total_sectors_16 as u32
|
||||||
if bpb.sectors_per_fat_16 == 0 { bpb.sectors_per_fat_32 }
|
};
|
||||||
else { bpb.sectors_per_fat_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_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 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;
|
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),
|
disk: RefCell::new(disk),
|
||||||
options,
|
options,
|
||||||
fat_type,
|
fat_type,
|
||||||
bpb: bpb,
|
bpb,
|
||||||
first_data_sector,
|
first_data_sector,
|
||||||
root_dir_sectors,
|
root_dir_sectors,
|
||||||
total_clusters,
|
total_clusters,
|
||||||
@ -471,7 +476,11 @@ impl <T: ReadWriteSeek> FileSystem<T> {
|
|||||||
let root_rdr = {
|
let root_rdr = {
|
||||||
match self.fat_type {
|
match self.fat_type {
|
||||||
FatType::Fat12 | FatType::Fat16 => DirRawStream::Root(DiskSlice::from_sectors(
|
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)),
|
_ => 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> {
|
fn fat_slice<'b>(&'b self) -> DiskSlice<'b, T> {
|
||||||
let sectors_per_fat =
|
let sectors_per_fat = if self.bpb.sectors_per_fat_16 == 0 {
|
||||||
if self.bpb.sectors_per_fat_16 == 0 { self.bpb.sectors_per_fat_32 }
|
self.bpb.sectors_per_fat_32
|
||||||
else { self.bpb.sectors_per_fat_16 as u32 };
|
} else {
|
||||||
|
self.bpb.sectors_per_fat_16 as u32
|
||||||
|
};
|
||||||
let mirroring_enabled = self.bpb.mirroring_enabled();
|
let mirroring_enabled = self.bpb.mirroring_enabled();
|
||||||
let (fat_first_sector, mirrors) = if mirroring_enabled {
|
let (fat_first_sector, mirrors) = if mirroring_enabled {
|
||||||
(self.bpb.reserved_sectors as u32, self.bpb.fats)
|
(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>,
|
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 {
|
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 {
|
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;
|
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 {
|
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
|
// 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 {
|
fn clone(&self) -> Self {
|
||||||
DiskSlice {
|
DiskSlice {
|
||||||
begin: self.begin,
|
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> {
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
let offset = self.begin + self.offset;
|
let offset = self.begin + self.offset;
|
||||||
let read_size = cmp::min((self.size - self.offset) as usize, buf.len());
|
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> {
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
let offset = self.begin + self.offset;
|
let offset = self.begin + self.offset;
|
||||||
let write_size = cmp::min((self.size - self.offset) as usize, buf.len());
|
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> {
|
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
||||||
let new_offset = match pos {
|
let new_offset = match pos {
|
||||||
SeekFrom::Current(x) => self.offset as i64 + x,
|
SeekFrom::Current(x) => self.offset as i64 + x,
|
||||||
|
22
src/lib.rs
22
src/lib.rs
@ -54,12 +54,10 @@
|
|||||||
|
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
#![crate_name = "fatfs"]
|
#![crate_name = "fatfs"]
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![cfg_attr(not(feature="std"), no_std)]
|
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
||||||
#![cfg_attr(not(feature="std"), feature(alloc))]
|
|
||||||
|
|
||||||
// Disable warnings to not clutter code with cfg too much
|
// 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;
|
extern crate byteorder;
|
||||||
|
|
||||||
@ -78,28 +76,28 @@ extern crate core_io;
|
|||||||
#[cfg(all(not(feature = "std"), feature = "alloc"))]
|
#[cfg(all(not(feature = "std"), feature = "alloc"))]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
mod fs;
|
|
||||||
mod dir;
|
mod dir;
|
||||||
mod dir_entry;
|
mod dir_entry;
|
||||||
mod file;
|
mod file;
|
||||||
|
mod fs;
|
||||||
mod table;
|
mod table;
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
mod byteorder_core_io;
|
mod byteorder_core_io;
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
use byteorder_core_io as byteorder_ext;
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use byteorder as byteorder_ext;
|
use byteorder as byteorder_ext;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(not(feature = "std"))]
|
||||||
use std as core;
|
use byteorder_core_io as byteorder_ext;
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
use core_io as io;
|
use core_io as io;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
use std as core;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::io as io;
|
use std::io;
|
||||||
|
|
||||||
pub use fs::*;
|
|
||||||
pub use dir::*;
|
pub use dir::*;
|
||||||
pub use dir_entry::*;
|
pub use dir_entry::*;
|
||||||
pub use file::*;
|
pub use file::*;
|
||||||
|
pub use fs::*;
|
||||||
|
72
src/table.rs
72
src/table.rs
@ -1,7 +1,9 @@
|
|||||||
use io;
|
use io;
|
||||||
|
|
||||||
use byteorder::LittleEndian;
|
use byteorder::LittleEndian;
|
||||||
use byteorder_ext::{ReadBytesExt, WriteBytesExt};
|
use byteorder_ext::{ReadBytesExt, WriteBytesExt};
|
||||||
use fs::{ReadWriteSeek, ReadSeek, FatType, FsStatusFlags};
|
|
||||||
|
use fs::{FatType, FsStatusFlags, ReadSeek, ReadWriteSeek};
|
||||||
|
|
||||||
struct Fat<T> {
|
struct Fat<T> {
|
||||||
#[allow(dead_code)]
|
#[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 end_cluster = total_clusters + RESERVED_FAT_ENTRIES;
|
||||||
let start_cluster = match hint {
|
let start_cluster = match hint {
|
||||||
Some(n) if n < end_cluster => n,
|
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::Fat16 => val & (1 << 14) == 0,
|
||||||
FatType::Fat32 => val & (1 << 26) == 0,
|
FatType::Fat32 => val & (1 << 26) == 0,
|
||||||
};
|
};
|
||||||
Ok(FsStatusFlags {
|
Ok(FsStatusFlags { dirty, io_error })
|
||||||
dirty, io_error,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn count_free_clusters<T: ReadSeek>(fat: &mut T, fat_type: FatType, total_clusters: u32) -> io::Result<u32> {
|
pub(crate) fn count_free_clusters<T: ReadSeek>(fat: &mut T, fat_type: FatType, total_clusters: u32) -> io::Result<u32> {
|
||||||
@ -183,7 +189,7 @@ impl FatTrait for Fat12 {
|
|||||||
fn count_free<T: ReadSeek>(fat: &mut T, end_cluster: u32) -> io::Result<u32> {
|
fn count_free<T: ReadSeek>(fat: &mut T, end_cluster: u32) -> io::Result<u32> {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
let mut cluster = RESERVED_FAT_ENTRIES;
|
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;
|
let mut prev_packed_val = 0u16;
|
||||||
while cluster < end_cluster {
|
while cluster < end_cluster {
|
||||||
let res = match cluster & 1 {
|
let res = match cluster & 1 {
|
||||||
@ -210,7 +216,7 @@ impl FatTrait for Fat12 {
|
|||||||
|
|
||||||
impl FatTrait for Fat16 {
|
impl FatTrait for Fat16 {
|
||||||
fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32> {
|
fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32> {
|
||||||
fat.seek(io::SeekFrom::Start((cluster*2) as u64))?;
|
fat.seek(io::SeekFrom::Start((cluster * 2) as u64))?;
|
||||||
Ok(fat.read_u16::<LittleEndian>()? as u32)
|
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<()> {
|
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 {
|
let raw_val = match value {
|
||||||
FatValue::Free => 0,
|
FatValue::Free => 0,
|
||||||
FatValue::Bad => 0xFFF7,
|
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> {
|
fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
|
||||||
let mut cluster = start_cluster;
|
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 {
|
while cluster < end_cluster {
|
||||||
let val = fat.read_u16::<LittleEndian>()?;
|
let val = fat.read_u16::<LittleEndian>()?;
|
||||||
if val == 0 {
|
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> {
|
fn count_free<T: ReadSeek>(fat: &mut T, end_cluster: u32) -> io::Result<u32> {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
let mut cluster = RESERVED_FAT_ENTRIES;
|
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 {
|
while cluster < end_cluster {
|
||||||
let val = fat.read_u16::<LittleEndian>()?;
|
let val = fat.read_u16::<LittleEndian>()?;
|
||||||
if val == 0 {
|
if val == 0 {
|
||||||
@ -266,7 +272,7 @@ impl FatTrait for Fat16 {
|
|||||||
|
|
||||||
impl FatTrait for Fat32 {
|
impl FatTrait for Fat32 {
|
||||||
fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32> {
|
fn get_raw<T: ReadSeek>(fat: &mut T, cluster: u32) -> io::Result<u32> {
|
||||||
fat.seek(io::SeekFrom::Start((cluster*4) as u64))?;
|
fat.seek(io::SeekFrom::Start((cluster * 4) as u64))?;
|
||||||
Ok(fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF)
|
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<()> {
|
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 {
|
let raw_val = match value {
|
||||||
FatValue::Free => 0,
|
FatValue::Free => 0,
|
||||||
FatValue::Bad => 0x0FFFFFF7,
|
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> {
|
fn find_free<T: ReadSeek>(fat: &mut T, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
|
||||||
let mut cluster = start_cluster;
|
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 {
|
while cluster < end_cluster {
|
||||||
let val = fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF;
|
let val = fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF;
|
||||||
if val == 0 {
|
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> {
|
fn count_free<T: ReadSeek>(fat: &mut T, end_cluster: u32) -> io::Result<u32> {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
let mut cluster = RESERVED_FAT_ENTRIES;
|
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 {
|
while cluster < end_cluster {
|
||||||
let val = fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF;
|
let val = fat.read_u32::<LittleEndian>()? & 0x0FFFFFFF;
|
||||||
if val == 0 {
|
if val == 0 {
|
||||||
@ -327,7 +333,7 @@ pub(crate) struct ClusterIterator<T: ReadWriteSeek> {
|
|||||||
err: bool,
|
err: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T: ReadWriteSeek> ClusterIterator<T> {
|
impl<T: ReadWriteSeek> ClusterIterator<T> {
|
||||||
pub(crate) fn new(fat: T, fat_type: FatType, cluster: u32) -> Self {
|
pub(crate) fn new(fat: T, fat_type: FatType, cluster: u32) -> Self {
|
||||||
ClusterIterator {
|
ClusterIterator {
|
||||||
fat,
|
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>;
|
type Item = io::Result<u32>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@ -417,7 +423,10 @@ mod tests {
|
|||||||
// test reading from iterator
|
// test reading from iterator
|
||||||
{
|
{
|
||||||
let iter = ClusterIterator::new(&mut cur, fat_type, 0x9);
|
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
|
// test truncating a chain
|
||||||
{
|
{
|
||||||
@ -443,9 +452,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fat12() {
|
fn test_fat12() {
|
||||||
let mut fat: Vec<u8> = vec![
|
let mut fat: Vec<u8> = vec![
|
||||||
0xF0, 0xFF, 0xFF, 0x03, 0x40, 0x00, 0x05, 0x60, 0x00, 0x07, 0x80, 0x00, 0xFF, 0xAF, 0x00, 0x14,
|
0xF0, 0xFF, 0xFF, 0x03, 0x40, 0x00, 0x05, 0x60, 0x00, 0x07, 0x80, 0x00, 0xFF, 0xAF, 0x00, 0x14, 0xC0, 0x00, 0x0D, 0xE0, 0x00,
|
||||||
0xC0, 0x00, 0x0D, 0xE0, 0x00, 0x0F, 0x00, 0x01, 0x11, 0xF0, 0xFF, 0x00, 0xF0, 0xFF, 0x15, 0x60,
|
0x0F, 0x00, 0x01, 0x11, 0xF0, 0xFF, 0x00, 0xF0, 0xFF, 0x15, 0x60, 0x01, 0x19, 0x70, 0xFF, 0xF7, 0xAF, 0x01, 0xFF, 0x0F, 0x00,
|
||||||
0x01, 0x19, 0x70, 0xFF, 0xF7, 0xAF, 0x01, 0xFF, 0x0F, 0x00, 0x00, 0x70, 0xFF, 0x00, 0x00, 0x00,
|
0x00, 0x70, 0xFF, 0x00, 0x00, 0x00,
|
||||||
];
|
];
|
||||||
test_fat(FatType::Fat12, io::Cursor::new(&mut fat));
|
test_fat(FatType::Fat12, io::Cursor::new(&mut fat));
|
||||||
}
|
}
|
||||||
@ -453,10 +462,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fat16() {
|
fn test_fat16() {
|
||||||
let mut fat: Vec<u8> = vec![
|
let mut fat: Vec<u8> = vec![
|
||||||
0xF0, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00,
|
0xF0, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0xFF, 0xFF, 0x0A, 0x00, 0x14,
|
||||||
0xFF, 0xFF, 0x0A, 0x00, 0x14, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x10, 0x00,
|
0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x10, 0x00, 0x11, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x15, 0x00,
|
||||||
0x11, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x15, 0x00, 0x16, 0x00, 0x19, 0x00, 0xF7, 0xFF,
|
0x16, 0x00, 0x19, 0x00, 0xF7, 0xFF, 0xF7, 0xFF, 0x1A, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0x00, 0x00, 0x00,
|
||||||
0xF7, 0xFF, 0x1A, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
];
|
];
|
||||||
test_fat(FatType::Fat16, io::Cursor::new(&mut fat));
|
test_fat(FatType::Fat16, io::Cursor::new(&mut fat));
|
||||||
}
|
}
|
||||||
@ -464,14 +473,13 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fat32() {
|
fn test_fat32() {
|
||||||
let mut fat: Vec<u8> = vec![
|
let mut fat: Vec<u8> = vec![
|
||||||
0xF0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0x04, 0x00, 0x00, 0x00,
|
0xF0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06,
|
||||||
0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00,
|
||||||
0xFF, 0xFF, 0xFF, 0x0F, 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
|
||||||
0x0D, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
0x00, 0x11, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x15, 0x00, 0x00, 0x00,
|
||||||
0x11, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F,
|
0x16, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0xFF, 0x0F, 0xF7, 0xFF, 0xFF, 0x0F, 0x1A, 0x00, 0x00, 0x00, 0xFF,
|
||||||
0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0xFF, 0x0F,
|
0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0xF7, 0xFF, 0xFF, 0x0F, 0x1A, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 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));
|
test_fat(FatType::Fat32, io::Cursor::new(&mut fat));
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
|
extern crate env_logger;
|
||||||
extern crate fatfs;
|
extern crate fatfs;
|
||||||
extern crate fscommon;
|
extern crate fscommon;
|
||||||
extern crate env_logger;
|
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::SeekFrom;
|
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
use std::io::SeekFrom;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use fatfs::{FsOptions, FatType};
|
use fatfs::{FatType, FsOptions};
|
||||||
use fscommon::BufStream;
|
use fscommon::BufStream;
|
||||||
|
|
||||||
const TEST_TEXT: &str = "Rust is cool!\n";
|
const TEST_TEXT: &str = "Rust is cool!\n";
|
||||||
@ -228,30 +228,39 @@ fn test_status_flags_fat32() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_stats_fat12() {
|
fn test_stats_fat12() {
|
||||||
call_with_fs(&|fs| {
|
call_with_fs(
|
||||||
let stats = fs.stats().unwrap();
|
&|fs| {
|
||||||
assert_eq!(stats.cluster_size(), 512);
|
let stats = fs.stats().unwrap();
|
||||||
assert_eq!(stats.total_clusters(), 1955); // 1000 * 1024 / 512 = 2000
|
assert_eq!(stats.cluster_size(), 512);
|
||||||
assert_eq!(stats.free_clusters(), 1920);
|
assert_eq!(stats.total_clusters(), 1955); // 1000 * 1024 / 512 = 2000
|
||||||
}, FAT12_IMG)
|
assert_eq!(stats.free_clusters(), 1920);
|
||||||
|
},
|
||||||
|
FAT12_IMG,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_stats_fat16() {
|
fn test_stats_fat16() {
|
||||||
call_with_fs(&|fs| {
|
call_with_fs(
|
||||||
let stats = fs.stats().unwrap();
|
&|fs| {
|
||||||
assert_eq!(stats.cluster_size(), 512);
|
let stats = fs.stats().unwrap();
|
||||||
assert_eq!(stats.total_clusters(), 4927); // 2500 * 1024 / 512 = 5000
|
assert_eq!(stats.cluster_size(), 512);
|
||||||
assert_eq!(stats.free_clusters(), 4892);
|
assert_eq!(stats.total_clusters(), 4927); // 2500 * 1024 / 512 = 5000
|
||||||
}, FAT16_IMG)
|
assert_eq!(stats.free_clusters(), 4892);
|
||||||
|
},
|
||||||
|
FAT16_IMG,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_stats_fat32() {
|
fn test_stats_fat32() {
|
||||||
call_with_fs(&|fs| {
|
call_with_fs(
|
||||||
let stats = fs.stats().unwrap();
|
&|fs| {
|
||||||
assert_eq!(stats.cluster_size(), 512);
|
let stats = fs.stats().unwrap();
|
||||||
assert_eq!(stats.total_clusters(), 66922); // 34000 * 1024 / 512 = 68000
|
assert_eq!(stats.cluster_size(), 512);
|
||||||
assert_eq!(stats.free_clusters(), 66886);
|
assert_eq!(stats.total_clusters(), 66922); // 34000 * 1024 / 512 = 68000
|
||||||
}, FAT32_IMG)
|
assert_eq!(stats.free_clusters(), 66886);
|
||||||
|
},
|
||||||
|
FAT32_IMG,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
|
extern crate env_logger;
|
||||||
extern crate fatfs;
|
extern crate fatfs;
|
||||||
extern crate fscommon;
|
extern crate fscommon;
|
||||||
extern crate env_logger;
|
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::prelude::*;
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::io::prelude::*;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use fatfs::FsOptions;
|
use fatfs::FsOptions;
|
||||||
@ -154,12 +154,12 @@ fn test_create_file(fs: FileSystem) {
|
|||||||
assert_eq!(&content, &TEST_STR);
|
assert_eq!(&content, &TEST_STR);
|
||||||
}
|
}
|
||||||
// Create enough entries to allocate next cluster
|
// Create enough entries to allocate next cluster
|
||||||
for i in 0..512/32 {
|
for i in 0..512 / 32 {
|
||||||
let name = format!("test{}", i);
|
let name = format!("test{}", i);
|
||||||
dir.create_file(&name).unwrap();
|
dir.create_file(&name).unwrap();
|
||||||
}
|
}
|
||||||
names = dir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
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
|
// check creating existing file opens it
|
||||||
{
|
{
|
||||||
let mut file = root_dir.create_file("very/long/path/new-file-with-long-name.txt").unwrap();
|
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