Change rustfmt options and reformat code
Option 'use_small_heuristics' is too abstract for me. Smaller lines and disabled heuristics should work better.
This commit is contained in:
parent
8ddd1de5fc
commit
812f61e393
@ -1,7 +1,8 @@
|
||||
max_width = 140
|
||||
max_width = 120
|
||||
match_block_trailing_comma = true
|
||||
use_field_init_shorthand = true
|
||||
ignore = [
|
||||
"src/byteorder_core_io.rs",
|
||||
]
|
||||
unstable_features = true
|
||||
use_small_heuristics = "Max"
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::cmp;
|
||||
use core::u8;
|
||||
use core::u16;
|
||||
use core::u8;
|
||||
use io;
|
||||
use io::prelude::*;
|
||||
use io::{Error, ErrorKind};
|
||||
@ -140,10 +140,7 @@ impl BiosParameterBlock {
|
||||
fn validate(&self) -> io::Result<()> {
|
||||
// sanity checks
|
||||
if self.bytes_per_sector.count_ones() != 1 {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"invalid bytes_per_sector value in BPB (not power of two)",
|
||||
));
|
||||
return Err(Error::new(ErrorKind::Other, "invalid bytes_per_sector value in BPB (not power of two)"));
|
||||
} else if self.bytes_per_sector < 512 {
|
||||
return Err(Error::new(ErrorKind::Other, "invalid bytes_per_sector value in BPB (value < 512)"));
|
||||
} else if self.bytes_per_sector > 4096 {
|
||||
@ -151,17 +148,11 @@ impl BiosParameterBlock {
|
||||
}
|
||||
|
||||
if self.sectors_per_cluster.count_ones() != 1 {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"invalid sectors_per_cluster value in BPB (not power of two)",
|
||||
));
|
||||
return Err(Error::new(ErrorKind::Other, "invalid sectors_per_cluster value in BPB (not power of two)"));
|
||||
} else if self.sectors_per_cluster < 1 {
|
||||
return Err(Error::new(ErrorKind::Other, "invalid sectors_per_cluster value in BPB (value < 1)"));
|
||||
} else if self.sectors_per_cluster > 128 {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"invalid sectors_per_cluster value in BPB (value > 128)",
|
||||
));
|
||||
return Err(Error::new(ErrorKind::Other, "invalid sectors_per_cluster value in BPB (value > 128)"));
|
||||
}
|
||||
|
||||
// bytes per sector is u16, sectors per cluster is u8, so guaranteed no overflow in multiplication
|
||||
@ -198,17 +189,11 @@ impl BiosParameterBlock {
|
||||
}
|
||||
|
||||
if is_fat32 && self.root_entries != 0 {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"Invalid root_entries value in BPB (should be zero for FAT32)",
|
||||
));
|
||||
return Err(Error::new(ErrorKind::Other, "Invalid root_entries value in BPB (should be zero for FAT32)"));
|
||||
}
|
||||
|
||||
if !is_fat32 && self.root_entries == 0 {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"Empty root directory region defined in FAT12/FAT16 BPB",
|
||||
));
|
||||
return Err(Error::new(ErrorKind::Other, "Empty root directory region defined in FAT12/FAT16 BPB"));
|
||||
}
|
||||
|
||||
if (u32::from(self.root_entries) * DIR_ENTRY_SIZE as u32) % u32::from(self.bytes_per_sector) != 0 {
|
||||
@ -524,8 +509,14 @@ fn determine_sectors_per_fat(
|
||||
sectors_per_fat as u32
|
||||
}
|
||||
|
||||
fn try_fs_geometry(total_sectors: u32, bytes_per_sector: u16, sectors_per_cluster: u8, fat_type: FatType,
|
||||
root_dir_sectors: u32, fats: u8) -> io::Result<(u16, u32)> {
|
||||
fn try_fs_geometry(
|
||||
total_sectors: u32,
|
||||
bytes_per_sector: u16,
|
||||
sectors_per_cluster: u8,
|
||||
fat_type: FatType,
|
||||
root_dir_sectors: u32,
|
||||
fats: u8,
|
||||
) -> io::Result<(u16, u32)> {
|
||||
// Note: most of implementations use 32 reserved sectors for FAT32 but it's wasting of space
|
||||
// This implementation uses only 8. This is enough to fit in two boot sectors (main and backup) with additional
|
||||
// bootstrap code and one FSInfo sector. It also makes FAT alligned to 4096 which is a nice number.
|
||||
@ -548,8 +539,8 @@ fn try_fs_geometry(total_sectors: u32, bytes_per_sector: u16, sectors_per_cluste
|
||||
fats,
|
||||
);
|
||||
|
||||
let data_sectors = total_sectors - u32::from(reserved_sectors) - u32::from(root_dir_sectors)
|
||||
- sectors_per_fat * u32::from(fats);
|
||||
let data_sectors =
|
||||
total_sectors - u32::from(reserved_sectors) - u32::from(root_dir_sectors) - sectors_per_fat * u32::from(fats);
|
||||
let total_clusters = data_sectors / u32::from(sectors_per_cluster);
|
||||
if fat_type != FatType::from_clusters(total_clusters) {
|
||||
return Err(Error::new(ErrorKind::Other, "Invalid FAT type"));
|
||||
@ -572,13 +563,17 @@ fn determine_root_dir_sectors(root_dir_entries: u16, bytes_per_sector: u16, fat_
|
||||
}
|
||||
}
|
||||
|
||||
fn determine_fs_geometry(total_sectors: u32, bytes_per_sector: u16, sectors_per_cluster: u8,
|
||||
root_dir_entries: u16, fats: u8
|
||||
fn determine_fs_geometry(
|
||||
total_sectors: u32,
|
||||
bytes_per_sector: u16,
|
||||
sectors_per_cluster: u8,
|
||||
root_dir_entries: u16,
|
||||
fats: u8,
|
||||
) -> io::Result<(FatType, u16, u32)> {
|
||||
|
||||
for &fat_type in &[FatType::Fat32, FatType::Fat16, FatType::Fat12] {
|
||||
let root_dir_sectors = determine_root_dir_sectors(root_dir_entries, bytes_per_sector, fat_type);
|
||||
let result = try_fs_geometry(total_sectors, bytes_per_sector, sectors_per_cluster, fat_type, root_dir_sectors, fats);
|
||||
let result =
|
||||
try_fs_geometry(total_sectors, bytes_per_sector, sectors_per_cluster, fat_type, root_dir_sectors, fats);
|
||||
if result.is_ok() {
|
||||
let (reserved_sectors, sectors_per_fat) = result.unwrap(); // SAFE: used is_ok() before
|
||||
return Ok((fat_type, reserved_sectors, sectors_per_fat));
|
||||
@ -588,10 +583,12 @@ fn determine_fs_geometry(total_sectors: u32, bytes_per_sector: u16, sectors_per_
|
||||
return Err(Error::new(ErrorKind::Other, "Cannot select FAT type - unfortunate disk size"));
|
||||
}
|
||||
|
||||
fn format_bpb(options: &FormatVolumeOptions, total_sectors: u32, bytes_per_sector: u16) -> io::Result<(BiosParameterBlock, FatType)> {
|
||||
let bytes_per_cluster = options
|
||||
.bytes_per_cluster
|
||||
.unwrap_or_else(|| {
|
||||
fn format_bpb(
|
||||
options: &FormatVolumeOptions,
|
||||
total_sectors: u32,
|
||||
bytes_per_sector: u16,
|
||||
) -> io::Result<(BiosParameterBlock, FatType)> {
|
||||
let bytes_per_cluster = options.bytes_per_cluster.unwrap_or_else(|| {
|
||||
let total_bytes = u64::from(total_sectors) * u64::from(bytes_per_sector);
|
||||
determine_bytes_per_cluster(total_bytes, bytes_per_sector, options.fat_type)
|
||||
});
|
||||
@ -606,9 +603,7 @@ fn format_bpb(options: &FormatVolumeOptions, total_sectors: u32, bytes_per_secto
|
||||
determine_fs_geometry(total_sectors, bytes_per_sector, sectors_per_cluster, root_dir_entries, fats)?;
|
||||
|
||||
// drive_num should be 0 for floppy disks and 0x80 for hard disks - determine it using FAT type
|
||||
let drive_num = options
|
||||
.drive_num
|
||||
.unwrap_or_else(|| if fat_type == FatType::Fat12 { 0 } else { 0x80 });
|
||||
let drive_num = options.drive_num.unwrap_or_else(|| if fat_type == FatType::Fat12 { 0 } else { 0x80 });
|
||||
|
||||
// reserved_0 is always zero
|
||||
let reserved_0 = [0u8; 12];
|
||||
@ -679,7 +674,11 @@ fn format_bpb(options: &FormatVolumeOptions, total_sectors: u32, bytes_per_secto
|
||||
Ok((bpb, fat_type))
|
||||
}
|
||||
|
||||
pub(crate) fn format_boot_sector(options: &FormatVolumeOptions, total_sectors: u32, bytes_per_sector: u16) -> io::Result<(BootSector, FatType)> {
|
||||
pub(crate) fn format_boot_sector(
|
||||
options: &FormatVolumeOptions,
|
||||
total_sectors: u32,
|
||||
bytes_per_sector: u16,
|
||||
) -> io::Result<(BootSector, FatType)> {
|
||||
let mut boot: BootSector = Default::default();
|
||||
let (bpb, fat_type) = format_bpb(options, total_sectors, bytes_per_sector)?;
|
||||
boot.bpb = bpb;
|
||||
@ -687,15 +686,15 @@ pub(crate) fn format_boot_sector(options: &FormatVolumeOptions, total_sectors: u
|
||||
// Boot code copied from FAT32 boot sector initialized by mkfs.fat
|
||||
boot.bootjmp = [0xEB, 0x58, 0x90];
|
||||
let boot_code: [u8; 129] = [
|
||||
0x0E, 0x1F, 0xBE, 0x77, 0x7C, 0xAC, 0x22, 0xC0, 0x74, 0x0B, 0x56, 0xB4, 0x0E, 0xBB, 0x07, 0x00,
|
||||
0xCD, 0x10, 0x5E, 0xEB, 0xF0, 0x32, 0xE4, 0xCD, 0x16, 0xCD, 0x19, 0xEB, 0xFE, 0x54, 0x68, 0x69,
|
||||
0x73, 0x20, 0x69, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x61,
|
||||
0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x2E, 0x20, 0x20, 0x50, 0x6C, 0x65, 0x61, 0x73,
|
||||
0x65, 0x20, 0x69, 0x6E, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x61,
|
||||
0x62, 0x6C, 0x65, 0x20, 0x66, 0x6C, 0x6F, 0x70, 0x70, 0x79, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A,
|
||||
0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x74, 0x6F,
|
||||
0x20, 0x74, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x2E, 0x2E, 0x2E, 0x20, 0x0D,
|
||||
0x0A];
|
||||
0x0E, 0x1F, 0xBE, 0x77, 0x7C, 0xAC, 0x22, 0xC0, 0x74, 0x0B, 0x56, 0xB4, 0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10,
|
||||
0x5E, 0xEB, 0xF0, 0x32, 0xE4, 0xCD, 0x16, 0xCD, 0x19, 0xEB, 0xFE, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
|
||||
0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x69,
|
||||
0x73, 0x6B, 0x2E, 0x20, 0x20, 0x50, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x69, 0x6E, 0x73, 0x65, 0x72, 0x74,
|
||||
0x20, 0x61, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x66, 0x6C, 0x6F, 0x70, 0x70, 0x79,
|
||||
0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65,
|
||||
0x79, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x2E, 0x2E, 0x2E,
|
||||
0x20, 0x0D, 0x0A,
|
||||
];
|
||||
boot.boot_code[..boot_code.len()].copy_from_slice(&boot_code);
|
||||
boot.boot_sig = [0x55, 0xAA];
|
||||
|
||||
|
82
src/dir.rs
82
src/dir.rs
@ -246,7 +246,8 @@ impl<'a, T: ReadWriteSeek + 'a> Dir<'a, T> {
|
||||
let sfn_entry = self.create_sfn_entry(dot_sfn, FileAttributes::DIRECTORY, entry.first_cluster());
|
||||
dir.write_entry(".", sfn_entry)?;
|
||||
let dotdot_sfn = ShortNameGenerator::new("..").generate().unwrap();
|
||||
let sfn_entry = self.create_sfn_entry(dotdot_sfn, FileAttributes::DIRECTORY, self.stream.first_cluster());
|
||||
let sfn_entry =
|
||||
self.create_sfn_entry(dotdot_sfn, FileAttributes::DIRECTORY, self.stream.first_cluster());
|
||||
dir.write_entry("..", sfn_entry)?;
|
||||
Ok(dir)
|
||||
},
|
||||
@ -396,7 +397,12 @@ impl<'a, T: ReadWriteSeek + 'a> Dir<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn create_sfn_entry(&self, short_name: [u8; 11], attrs: FileAttributes, first_cluster: Option<u32>) -> DirFileEntryData {
|
||||
fn create_sfn_entry(
|
||||
&self,
|
||||
short_name: [u8; 11],
|
||||
attrs: FileAttributes,
|
||||
first_cluster: Option<u32>,
|
||||
) -> DirFileEntryData {
|
||||
let mut raw_entry = DirFileEntryData::new(short_name, attrs);
|
||||
raw_entry.set_first_cluster(first_cluster, self.fs.fat_type());
|
||||
let now = self.fs.options.time_provider.get_current_date_time();
|
||||
@ -415,7 +421,11 @@ impl<'a, T: ReadWriteSeek + 'a> Dir<'a, T> {
|
||||
()
|
||||
}
|
||||
|
||||
fn alloc_and_write_lfn_entries(&self, lfn_utf16: &LfnUtf16, short_name: &[u8; 11]) -> io::Result<(DirRawStream<'a, T>, u64)> {
|
||||
fn alloc_and_write_lfn_entries(
|
||||
&self,
|
||||
lfn_utf16: &LfnUtf16,
|
||||
short_name: &[u8; 11],
|
||||
) -> io::Result<(DirRawStream<'a, T>, u64)> {
|
||||
// get short name checksum
|
||||
let lfn_chsum = lfn_checksum(short_name);
|
||||
// create LFN entries generator
|
||||
@ -459,10 +469,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> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
stream: self.stream.clone(),
|
||||
fs: self.fs,
|
||||
}
|
||||
Self { stream: self.stream.clone(), fs: self.fs }
|
||||
}
|
||||
}
|
||||
|
||||
@ -478,12 +485,7 @@ pub struct DirIter<'a, T: ReadWriteSeek + 'a> {
|
||||
|
||||
impl<'a, T: ReadWriteSeek> DirIter<'a, T> {
|
||||
fn new(stream: DirRawStream<'a, T>, fs: &'a FileSystem<T>, skip_volume: bool) -> Self {
|
||||
DirIter {
|
||||
stream,
|
||||
fs,
|
||||
skip_volume,
|
||||
err: false,
|
||||
}
|
||||
DirIter { stream, fs, skip_volume, err: false }
|
||||
}
|
||||
|
||||
fn should_ship_entry(&self, raw_entry: &DirEntryData) -> bool {
|
||||
@ -546,12 +548,7 @@ impl<'a, T: ReadWriteSeek> DirIter<'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 DirIter<'a, T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
stream: self.stream.clone(),
|
||||
fs: self.fs,
|
||||
err: self.err,
|
||||
skip_volume: self.skip_volume,
|
||||
}
|
||||
Self { stream: self.stream.clone(), fs: self.fs, err: self.err, skip_volume: self.skip_volume }
|
||||
}
|
||||
}
|
||||
|
||||
@ -587,8 +584,8 @@ fn validate_long_name(name: &str) -> io::Result<()> {
|
||||
match c {
|
||||
'a'...'z' | 'A'...'Z' | '0'...'9' => {},
|
||||
'\u{80}'...'\u{FFFF}' => {},
|
||||
'$' | '%' | '\'' | '-' | '_' | '@' | '~' | '`' | '!' | '(' | ')' | '{' | '}' | '.' | ' ' | '+' | ',' | ';' | '=' | '['
|
||||
| ']' => {},
|
||||
'$' | '%' | '\'' | '-' | '_' | '@' | '~' | '`' | '!' | '(' | ')' | '{' | '}' | '.' | ' ' | '+' | ','
|
||||
| ';' | '=' | '[' | ']' => {},
|
||||
_ => return Err(io::Error::new(ErrorKind::Other, "File name contains unsupported characters")),
|
||||
}
|
||||
}
|
||||
@ -613,11 +610,7 @@ struct LongNameBuilder {
|
||||
#[cfg(feature = "alloc")]
|
||||
impl LongNameBuilder {
|
||||
fn new() -> Self {
|
||||
LongNameBuilder {
|
||||
buf: Vec::<u16>::new(),
|
||||
chksum: 0,
|
||||
index: 0,
|
||||
}
|
||||
LongNameBuilder { buf: Vec::<u16>::new(), chksum: 0, index: 0 }
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
@ -670,13 +663,7 @@ 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 {
|
||||
@ -833,25 +820,20 @@ impl ShortNameGenerator {
|
||||
let (basename_len, name_fits, lossy_conv) = match name.rfind('.') {
|
||||
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 (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..]);
|
||||
(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);
|
||||
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,
|
||||
basename_len: basename_len as u8,
|
||||
..Default::default()
|
||||
}
|
||||
Self { short_name, chksum, name_fits, lossy_conv, basename_len: basename_len as u8, ..Default::default() }
|
||||
}
|
||||
|
||||
fn copy_short_name_part(dst: &mut [u8], src: &str) -> (usize, bool, bool) {
|
||||
@ -892,11 +874,8 @@ 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] == b'~' {
|
||||
(short_name[prefix_len + 1] as char).to_digit(10)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let num_suffix =
|
||||
if short_name[prefix_len] == b'~' { (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
|
||||
@ -911,7 +890,8 @@ impl ShortNameGenerator {
|
||||
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;
|
||||
@ -1013,9 +993,7 @@ 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]
|
||||
|
@ -56,11 +56,7 @@ 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 {
|
||||
@ -77,10 +73,7 @@ impl ShortName {
|
||||
name[0] = 0xE5;
|
||||
}
|
||||
// Short names in FAT filesystem are encoded in OEM code-page
|
||||
ShortName {
|
||||
name,
|
||||
len: total_len as u8,
|
||||
}
|
||||
ShortName { name, len: total_len as u8 }
|
||||
}
|
||||
|
||||
fn as_bytes(&self) -> &[u8] {
|
||||
@ -124,11 +117,7 @@ pub(crate) struct DirFileEntryData {
|
||||
|
||||
impl DirFileEntryData {
|
||||
pub(crate) fn new(name: [u8; 11], attrs: FileAttributes) -> Self {
|
||||
DirFileEntryData {
|
||||
name,
|
||||
attrs,
|
||||
..Default::default()
|
||||
}
|
||||
DirFileEntryData { name, attrs, ..Default::default() }
|
||||
}
|
||||
|
||||
pub(crate) fn renamed(&self, new_name: [u8; 11]) -> Self {
|
||||
@ -279,12 +268,7 @@ pub(crate) struct DirLfnEntryData {
|
||||
|
||||
impl DirLfnEntryData {
|
||||
pub(crate) fn new(order: u8, checksum: u8) -> Self {
|
||||
DirLfnEntryData {
|
||||
order,
|
||||
checksum,
|
||||
attrs: FileAttributes::LFN,
|
||||
..Default::default()
|
||||
}
|
||||
DirLfnEntryData { order, checksum, attrs: FileAttributes::LFN, ..Default::default() }
|
||||
}
|
||||
|
||||
pub(crate) fn copy_name_from_slice(&mut self, lfn_part: &[u16; LFN_PART_LEN]) {
|
||||
@ -369,10 +353,7 @@ impl DirEntryData {
|
||||
let attrs = FileAttributes::from_bits_truncate(rdr.read_u8()?);
|
||||
if attrs & FileAttributes::LFN == FileAttributes::LFN {
|
||||
// read long name entry
|
||||
let mut data = DirLfnEntryData {
|
||||
attrs,
|
||||
..Default::default()
|
||||
};
|
||||
let mut data = DirLfnEntryData { attrs, ..Default::default() };
|
||||
// use cursor to divide name into order and LFN name_0
|
||||
let mut cur = Cursor::new(&name);
|
||||
data.order = cur.read_u8()?;
|
||||
@ -648,10 +629,7 @@ mod tests {
|
||||
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).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
|
||||
@ -696,11 +674,8 @@ mod tests {
|
||||
fn lowercase_short_name() {
|
||||
let mut raw_short_name = [0u8; 11];
|
||||
raw_short_name.copy_from_slice(b"FOO RS ");
|
||||
let mut raw_entry = DirFileEntryData {
|
||||
name: raw_short_name,
|
||||
reserved_0: (1 << 3) | (1 << 4),
|
||||
..Default::default()
|
||||
};
|
||||
let mut raw_entry =
|
||||
DirFileEntryData { name: raw_short_name, reserved_0: (1 << 3) | (1 << 4), ..Default::default() };
|
||||
assert_eq!(raw_entry.lowercase_name().to_string(&LOSSY_OEM_CP_CONVERTER), "foo.rs");
|
||||
raw_entry.reserved_0 = 1 << 3;
|
||||
assert_eq!(raw_entry.lowercase_name().to_string(&LOSSY_OEM_CP_CONVERTER), "foo.RS");
|
||||
|
52
src/fs.rs
52
src/fs.rs
@ -3,9 +3,9 @@ use alloc::String;
|
||||
use core::cell::{Cell, RefCell};
|
||||
use core::char;
|
||||
use core::cmp;
|
||||
use core::u32;
|
||||
use core::fmt::Debug;
|
||||
use core::iter::FromIterator;
|
||||
use core::u32;
|
||||
use io;
|
||||
use io::prelude::*;
|
||||
use io::{Error, ErrorKind, SeekFrom};
|
||||
@ -108,10 +108,7 @@ impl FsStatusFlags {
|
||||
}
|
||||
|
||||
pub(crate) fn decode(flags: u8) -> Self {
|
||||
FsStatusFlags {
|
||||
dirty: flags & 1 != 0,
|
||||
io_error: flags & 2 != 0,
|
||||
}
|
||||
FsStatusFlags { dirty: flags & 1 != 0, io_error: flags & 2 != 0 }
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,11 +163,7 @@ impl FsInfoSector {
|
||||
if trail_sig != Self::TRAIL_SIG {
|
||||
return Err(Error::new(ErrorKind::Other, "invalid trail_sig in FsInfo sector"));
|
||||
}
|
||||
Ok(FsInfoSector {
|
||||
free_cluster_count,
|
||||
next_free_cluster,
|
||||
dirty: false,
|
||||
})
|
||||
Ok(FsInfoSector { free_cluster_count, next_free_cluster, dirty: false })
|
||||
}
|
||||
|
||||
fn serialize<T: Write>(&self, wrt: &mut T) -> io::Result<()> {
|
||||
@ -190,10 +183,7 @@ impl FsInfoSector {
|
||||
let max_valid_cluster_number = total_clusters + RESERVED_FAT_ENTRIES;
|
||||
if let Some(n) = self.free_cluster_count {
|
||||
if n > total_clusters {
|
||||
warn!(
|
||||
"invalid free_cluster_count ({}) in fs_info exceeds total cluster count ({})",
|
||||
n, total_clusters
|
||||
);
|
||||
warn!("invalid free_cluster_count ({}) in fs_info exceeds total cluster count ({})", n, total_clusters);
|
||||
self.free_cluster_count = None;
|
||||
}
|
||||
}
|
||||
@ -537,11 +527,7 @@ impl<T: ReadWriteSeek> FileSystem<T> {
|
||||
Some(n) => n,
|
||||
_ => self.recalc_free_clusters()?,
|
||||
};
|
||||
Ok(FileSystemStats {
|
||||
cluster_size: self.cluster_size(),
|
||||
total_clusters: self.total_clusters,
|
||||
free_clusters,
|
||||
})
|
||||
Ok(FileSystemStats { cluster_size: self.cluster_size(), total_clusters: self.total_clusters, free_clusters })
|
||||
}
|
||||
|
||||
/// Forces free clusters recalculation.
|
||||
@ -667,22 +653,11 @@ pub(crate) struct DiskSlice<T> {
|
||||
|
||||
impl<T> DiskSlice<T> {
|
||||
pub(crate) fn new(begin: u64, size: u64, mirrors: u8, inner: T) -> Self {
|
||||
DiskSlice {
|
||||
begin,
|
||||
size,
|
||||
mirrors,
|
||||
inner,
|
||||
offset: 0,
|
||||
}
|
||||
DiskSlice { begin, size, mirrors, inner, offset: 0 }
|
||||
}
|
||||
|
||||
fn from_sectors(first_sector: u32, sector_count: u32, mirrors: u8, bpb: &BiosParameterBlock, inner: T) -> Self {
|
||||
Self::new(
|
||||
bpb.bytes_from_sectors(first_sector),
|
||||
bpb.bytes_from_sectors(sector_count),
|
||||
mirrors,
|
||||
inner,
|
||||
)
|
||||
Self::new(bpb.bytes_from_sectors(first_sector), bpb.bytes_from_sectors(sector_count), mirrors, inner)
|
||||
}
|
||||
|
||||
pub(crate) fn abs_pos(&self) -> u64 {
|
||||
@ -830,9 +805,7 @@ impl FormatVolumeOptions {
|
||||
/// Allows to overwrite many filesystem parameters.
|
||||
/// In normal use-case defaults should suffice.
|
||||
pub fn new() -> Self {
|
||||
FormatVolumeOptions {
|
||||
..Default::default()
|
||||
}
|
||||
FormatVolumeOptions { ..Default::default() }
|
||||
}
|
||||
|
||||
/// Set size of cluster in bytes (must be dividable by sector size)
|
||||
@ -980,11 +953,7 @@ pub fn format_volume<T: ReadWriteSeek>(mut disk: T, options: FormatVolumeOptions
|
||||
|
||||
if boot.bpb.is_fat32() {
|
||||
// FSInfo sector
|
||||
let fs_info_sector = FsInfoSector {
|
||||
free_cluster_count: None,
|
||||
next_free_cluster: None,
|
||||
dirty: false,
|
||||
};
|
||||
let fs_info_sector = FsInfoSector { free_cluster_count: None, next_free_cluster: None, dirty: false };
|
||||
disk.seek(SeekFrom::Start(boot.bpb.bytes_from_sectors(boot.bpb.fs_info_sector())))?;
|
||||
fs_info_sector.serialize(&mut disk)?;
|
||||
write_zeros_until_end_of_sector(&mut disk, bytes_per_sector)?;
|
||||
@ -1021,7 +990,8 @@ pub fn format_volume<T: ReadWriteSeek>(mut disk: T, options: FormatVolumeOptions
|
||||
};
|
||||
assert!(root_dir_first_cluster == boot.bpb.root_dir_first_cluster);
|
||||
let first_data_sector = reserved_sectors + sectors_per_all_fats + root_dir_sectors;
|
||||
let root_dir_first_sector = first_data_sector + boot.bpb.sectors_from_clusters(root_dir_first_cluster - RESERVED_FAT_ENTRIES);
|
||||
let root_dir_first_sector =
|
||||
first_data_sector + boot.bpb.sectors_from_clusters(root_dir_first_cluster - RESERVED_FAT_ENTRIES);
|
||||
let root_dir_pos = boot.bpb.bytes_from_sectors(root_dir_first_sector);
|
||||
disk.seek(SeekFrom::Start(root_dir_pos))?;
|
||||
write_zeros(&mut disk, boot.bpb.cluster_size() as u64)?;
|
||||
|
50
src/table.rs
50
src/table.rs
@ -58,7 +58,12 @@ fn get_next_cluster<T: ReadSeek>(fat: &mut T, fat_type: FatType, cluster: u32) -
|
||||
}
|
||||
}
|
||||
|
||||
fn find_free_cluster<T: ReadSeek>(fat: &mut T, fat_type: FatType, start_cluster: u32, end_cluster: u32) -> io::Result<u32> {
|
||||
fn find_free_cluster<T: ReadSeek>(
|
||||
fat: &mut T,
|
||||
fat_type: FatType,
|
||||
start_cluster: u32,
|
||||
end_cluster: u32,
|
||||
) -> io::Result<u32> {
|
||||
match fat_type {
|
||||
FatType::Fat12 => Fat12::find_free(fat, start_cluster, end_cluster),
|
||||
FatType::Fat16 => Fat16::find_free(fat, start_cluster, end_cluster),
|
||||
@ -80,7 +85,9 @@ pub(crate) fn alloc_cluster<T: ReadWriteSeek>(
|
||||
};
|
||||
let new_cluster = match find_free_cluster(fat, fat_type, start_cluster, end_cluster) {
|
||||
Ok(n) => n,
|
||||
Err(_) if start_cluster > RESERVED_FAT_ENTRIES => find_free_cluster(fat, fat_type, RESERVED_FAT_ENTRIES, start_cluster)?,
|
||||
Err(_) if start_cluster > RESERVED_FAT_ENTRIES => {
|
||||
find_free_cluster(fat, fat_type, RESERVED_FAT_ENTRIES, start_cluster)?
|
||||
},
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
write_fat(fat, fat_type, new_cluster, FatValue::EndOfChain)?;
|
||||
@ -413,12 +420,7 @@ pub(crate) struct ClusterIterator<T: ReadWriteSeek> {
|
||||
|
||||
impl<T: ReadWriteSeek> ClusterIterator<T> {
|
||||
pub(crate) fn new(fat: T, fat_type: FatType, cluster: u32) -> Self {
|
||||
ClusterIterator {
|
||||
fat,
|
||||
fat_type,
|
||||
cluster: Some(cluster),
|
||||
err: false,
|
||||
}
|
||||
ClusterIterator { fat, fat_type, cluster: Some(cluster), err: false }
|
||||
}
|
||||
|
||||
pub(crate) fn truncate(&mut self) -> io::Result<u32> {
|
||||
@ -501,10 +503,7 @@ 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
|
||||
{
|
||||
@ -530,9 +529,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_fat12() {
|
||||
let 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(fat));
|
||||
}
|
||||
@ -540,10 +539,10 @@ mod tests {
|
||||
#[test]
|
||||
fn test_fat16() {
|
||||
let 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(fat));
|
||||
}
|
||||
@ -551,12 +550,13 @@ mod tests {
|
||||
#[test]
|
||||
fn test_fat32() {
|
||||
let 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,
|
||||
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(fat));
|
||||
|
11
src/time.rs
11
src/time.rs
@ -73,10 +73,7 @@ pub struct DateTime {
|
||||
|
||||
impl DateTime {
|
||||
pub(crate) fn decode(dos_date: u16, dos_time: u16, dos_time_hi_res: u8) -> Self {
|
||||
DateTime {
|
||||
date: Date::decode(dos_date),
|
||||
time: Time::decode(dos_time, dos_time_hi_res),
|
||||
}
|
||||
DateTime { date: Date::decode(dos_date), time: Time::decode(dos_time, dos_time_hi_res) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,11 +99,7 @@ impl From<DateTime> for chrono::DateTime<Local> {
|
||||
#[cfg(feature = "chrono")]
|
||||
impl From<chrono::Date<Local>> for Date {
|
||||
fn from(date: chrono::Date<Local>) -> Self {
|
||||
Date {
|
||||
year: date.year() as u16,
|
||||
month: date.month() as u16,
|
||||
day: date.day() as u16,
|
||||
}
|
||||
Date { year: date.year() as u16, month: date.month() as u16, day: date.day() as u16 }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,9 +47,7 @@ fn basic_fs_test(fs: &FileSystem) {
|
||||
let filenames = subdir2.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
||||
assert_eq!(filenames, [".", "..", "test file name.txt"]);
|
||||
|
||||
subdir1
|
||||
.rename("subdir2 with long name/test file name.txt", &root_dir, "new-name.txt")
|
||||
.expect("rename");
|
||||
subdir1.rename("subdir2 with long name/test file name.txt", &root_dir, "new-name.txt").expect("rename");
|
||||
|
||||
let filenames = subdir2.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
||||
assert_eq!(filenames, [".", ".."]);
|
||||
|
Loading…
Reference in New Issue
Block a user