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
|
match_block_trailing_comma = true
|
||||||
use_field_init_shorthand = true
|
use_field_init_shorthand = true
|
||||||
ignore = [
|
ignore = [
|
||||||
"src/byteorder_core_io.rs",
|
"src/byteorder_core_io.rs",
|
||||||
]
|
]
|
||||||
unstable_features = true
|
unstable_features = true
|
||||||
|
use_small_heuristics = "Max"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use core::cmp;
|
use core::cmp;
|
||||||
use core::u8;
|
|
||||||
use core::u16;
|
use core::u16;
|
||||||
|
use core::u8;
|
||||||
use io;
|
use io;
|
||||||
use io::prelude::*;
|
use io::prelude::*;
|
||||||
use io::{Error, ErrorKind};
|
use io::{Error, ErrorKind};
|
||||||
@ -140,10 +140,7 @@ impl BiosParameterBlock {
|
|||||||
fn validate(&self) -> io::Result<()> {
|
fn validate(&self) -> io::Result<()> {
|
||||||
// sanity checks
|
// sanity checks
|
||||||
if self.bytes_per_sector.count_ones() != 1 {
|
if self.bytes_per_sector.count_ones() != 1 {
|
||||||
return Err(Error::new(
|
return Err(Error::new(ErrorKind::Other, "invalid bytes_per_sector value in BPB (not power of two)"));
|
||||||
ErrorKind::Other,
|
|
||||||
"invalid bytes_per_sector value in BPB (not power of two)",
|
|
||||||
));
|
|
||||||
} else if self.bytes_per_sector < 512 {
|
} else if self.bytes_per_sector < 512 {
|
||||||
return Err(Error::new(ErrorKind::Other, "invalid bytes_per_sector value in BPB (value < 512)"));
|
return Err(Error::new(ErrorKind::Other, "invalid bytes_per_sector value in BPB (value < 512)"));
|
||||||
} else if self.bytes_per_sector > 4096 {
|
} else if self.bytes_per_sector > 4096 {
|
||||||
@ -151,17 +148,11 @@ impl BiosParameterBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.sectors_per_cluster.count_ones() != 1 {
|
if self.sectors_per_cluster.count_ones() != 1 {
|
||||||
return Err(Error::new(
|
return Err(Error::new(ErrorKind::Other, "invalid sectors_per_cluster value in BPB (not power of two)"));
|
||||||
ErrorKind::Other,
|
|
||||||
"invalid sectors_per_cluster value in BPB (not power of two)",
|
|
||||||
));
|
|
||||||
} else if self.sectors_per_cluster < 1 {
|
} else if self.sectors_per_cluster < 1 {
|
||||||
return Err(Error::new(ErrorKind::Other, "invalid sectors_per_cluster value in BPB (value < 1)"));
|
return Err(Error::new(ErrorKind::Other, "invalid sectors_per_cluster value in BPB (value < 1)"));
|
||||||
} else if self.sectors_per_cluster > 128 {
|
} else if self.sectors_per_cluster > 128 {
|
||||||
return Err(Error::new(
|
return Err(Error::new(ErrorKind::Other, "invalid sectors_per_cluster value in BPB (value > 128)"));
|
||||||
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
|
// 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 {
|
if is_fat32 && self.root_entries != 0 {
|
||||||
return Err(Error::new(
|
return Err(Error::new(ErrorKind::Other, "Invalid root_entries value in BPB (should be zero for FAT32)"));
|
||||||
ErrorKind::Other,
|
|
||||||
"Invalid root_entries value in BPB (should be zero for FAT32)",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !is_fat32 && self.root_entries == 0 {
|
if !is_fat32 && self.root_entries == 0 {
|
||||||
return Err(Error::new(
|
return Err(Error::new(ErrorKind::Other, "Empty root directory region defined in FAT12/FAT16 BPB"));
|
||||||
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 {
|
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
|
sectors_per_fat as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fs_geometry(total_sectors: u32, bytes_per_sector: u16, sectors_per_cluster: u8, fat_type: FatType,
|
fn try_fs_geometry(
|
||||||
root_dir_sectors: u32, fats: u8) -> io::Result<(u16, u32)> {
|
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
|
// 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
|
// 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.
|
// 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,
|
fats,
|
||||||
);
|
);
|
||||||
|
|
||||||
let data_sectors = total_sectors - u32::from(reserved_sectors) - u32::from(root_dir_sectors)
|
let data_sectors =
|
||||||
- sectors_per_fat * u32::from(fats);
|
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);
|
let total_clusters = data_sectors / u32::from(sectors_per_cluster);
|
||||||
if fat_type != FatType::from_clusters(total_clusters) {
|
if fat_type != FatType::from_clusters(total_clusters) {
|
||||||
return Err(Error::new(ErrorKind::Other, "Invalid FAT type"));
|
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,
|
fn determine_fs_geometry(
|
||||||
root_dir_entries: u16, fats: u8
|
total_sectors: u32,
|
||||||
|
bytes_per_sector: u16,
|
||||||
|
sectors_per_cluster: u8,
|
||||||
|
root_dir_entries: u16,
|
||||||
|
fats: u8,
|
||||||
) -> io::Result<(FatType, u16, u32)> {
|
) -> io::Result<(FatType, u16, u32)> {
|
||||||
|
|
||||||
for &fat_type in &[FatType::Fat32, FatType::Fat16, FatType::Fat12] {
|
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 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() {
|
if result.is_ok() {
|
||||||
let (reserved_sectors, sectors_per_fat) = result.unwrap(); // SAFE: used is_ok() before
|
let (reserved_sectors, sectors_per_fat) = result.unwrap(); // SAFE: used is_ok() before
|
||||||
return Ok((fat_type, reserved_sectors, sectors_per_fat));
|
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"));
|
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)> {
|
fn format_bpb(
|
||||||
let bytes_per_cluster = options
|
options: &FormatVolumeOptions,
|
||||||
.bytes_per_cluster
|
total_sectors: u32,
|
||||||
.unwrap_or_else(|| {
|
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);
|
let total_bytes = u64::from(total_sectors) * u64::from(bytes_per_sector);
|
||||||
determine_bytes_per_cluster(total_bytes, bytes_per_sector, options.fat_type)
|
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)?;
|
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
|
// drive_num should be 0 for floppy disks and 0x80 for hard disks - determine it using FAT type
|
||||||
let drive_num = options
|
let drive_num = options.drive_num.unwrap_or_else(|| if fat_type == FatType::Fat12 { 0 } else { 0x80 });
|
||||||
.drive_num
|
|
||||||
.unwrap_or_else(|| if fat_type == FatType::Fat12 { 0 } else { 0x80 });
|
|
||||||
|
|
||||||
// reserved_0 is always zero
|
// reserved_0 is always zero
|
||||||
let reserved_0 = [0u8; 12];
|
let reserved_0 = [0u8; 12];
|
||||||
@ -679,7 +674,11 @@ fn format_bpb(options: &FormatVolumeOptions, total_sectors: u32, bytes_per_secto
|
|||||||
Ok((bpb, fat_type))
|
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 mut boot: BootSector = Default::default();
|
||||||
let (bpb, fat_type) = format_bpb(options, total_sectors, bytes_per_sector)?;
|
let (bpb, fat_type) = format_bpb(options, total_sectors, bytes_per_sector)?;
|
||||||
boot.bpb = bpb;
|
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 code copied from FAT32 boot sector initialized by mkfs.fat
|
||||||
boot.bootjmp = [0xEB, 0x58, 0x90];
|
boot.bootjmp = [0xEB, 0x58, 0x90];
|
||||||
let boot_code: [u8; 129] = [
|
let boot_code: [u8; 129] = [
|
||||||
0x0E, 0x1F, 0xBE, 0x77, 0x7C, 0xAC, 0x22, 0xC0, 0x74, 0x0B, 0x56, 0xB4, 0x0E, 0xBB, 0x07, 0x00,
|
0x0E, 0x1F, 0xBE, 0x77, 0x7C, 0xAC, 0x22, 0xC0, 0x74, 0x0B, 0x56, 0xB4, 0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10,
|
||||||
0xCD, 0x10, 0x5E, 0xEB, 0xF0, 0x32, 0xE4, 0xCD, 0x16, 0xCD, 0x19, 0xEB, 0xFE, 0x54, 0x68, 0x69,
|
0x5E, 0xEB, 0xF0, 0x32, 0xE4, 0xCD, 0x16, 0xCD, 0x19, 0xEB, 0xFE, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
|
||||||
0x73, 0x20, 0x69, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x61,
|
0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x69,
|
||||||
0x62, 0x6C, 0x65, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x2E, 0x20, 0x20, 0x50, 0x6C, 0x65, 0x61, 0x73,
|
0x73, 0x6B, 0x2E, 0x20, 0x20, 0x50, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x69, 0x6E, 0x73, 0x65, 0x72, 0x74,
|
||||||
0x65, 0x20, 0x69, 0x6E, 0x73, 0x65, 0x72, 0x74, 0x20, 0x61, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x61,
|
0x20, 0x61, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x66, 0x6C, 0x6F, 0x70, 0x70, 0x79,
|
||||||
0x62, 0x6C, 0x65, 0x20, 0x66, 0x6C, 0x6F, 0x70, 0x70, 0x79, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A,
|
0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65,
|
||||||
0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x74, 0x6F,
|
0x79, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x2E, 0x2E, 0x2E,
|
||||||
0x20, 0x74, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x2E, 0x2E, 0x2E, 0x20, 0x0D,
|
0x20, 0x0D, 0x0A,
|
||||||
0x0A];
|
];
|
||||||
boot.boot_code[..boot_code.len()].copy_from_slice(&boot_code);
|
boot.boot_code[..boot_code.len()].copy_from_slice(&boot_code);
|
||||||
boot.boot_sig = [0x55, 0xAA];
|
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());
|
let sfn_entry = self.create_sfn_entry(dot_sfn, FileAttributes::DIRECTORY, entry.first_cluster());
|
||||||
dir.write_entry(".", sfn_entry)?;
|
dir.write_entry(".", sfn_entry)?;
|
||||||
let dotdot_sfn = ShortNameGenerator::new("..").generate().unwrap();
|
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)?;
|
dir.write_entry("..", sfn_entry)?;
|
||||||
Ok(dir)
|
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);
|
let mut raw_entry = DirFileEntryData::new(short_name, attrs);
|
||||||
raw_entry.set_first_cluster(first_cluster, self.fs.fat_type());
|
raw_entry.set_first_cluster(first_cluster, self.fs.fat_type());
|
||||||
let now = self.fs.options.time_provider.get_current_date_time();
|
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
|
// get short name checksum
|
||||||
let lfn_chsum = lfn_checksum(short_name);
|
let lfn_chsum = lfn_checksum(short_name);
|
||||||
// create LFN entries generator
|
// 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
|
// 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(), fs: self.fs }
|
||||||
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> {
|
impl<'a, T: ReadWriteSeek> DirIter<'a, T> {
|
||||||
fn new(stream: DirRawStream<'a, T>, fs: &'a FileSystem<T>, skip_volume: bool) -> Self {
|
fn new(stream: DirRawStream<'a, T>, fs: &'a FileSystem<T>, skip_volume: bool) -> Self {
|
||||||
DirIter {
|
DirIter { stream, fs, skip_volume, err: false }
|
||||||
stream,
|
|
||||||
fs,
|
|
||||||
skip_volume,
|
|
||||||
err: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_ship_entry(&self, raw_entry: &DirEntryData) -> bool {
|
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
|
// 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(), fs: self.fs, err: self.err, skip_volume: self.skip_volume }
|
||||||
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 {
|
match c {
|
||||||
'a'...'z' | 'A'...'Z' | '0'...'9' => {},
|
'a'...'z' | 'A'...'Z' | '0'...'9' => {},
|
||||||
'\u{80}'...'\u{FFFF}' => {},
|
'\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")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -613,11 +610,7 @@ struct LongNameBuilder {
|
|||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
impl LongNameBuilder {
|
impl LongNameBuilder {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
LongNameBuilder {
|
LongNameBuilder { buf: Vec::<u16>::new(), chksum: 0, index: 0 }
|
||||||
buf: Vec::<u16>::new(),
|
|
||||||
chksum: 0,
|
|
||||||
index: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
@ -670,13 +663,7 @@ 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!(
|
warn!("currupted lfn entry! {:x} {:x} {:x} {:x}", data.order(), self.index, data.checksum(), self.chksum);
|
||||||
"currupted lfn entry! {:x} {:x} {:x} {:x}",
|
|
||||||
data.order(),
|
|
||||||
self.index,
|
|
||||||
data.checksum(),
|
|
||||||
self.chksum
|
|
||||||
);
|
|
||||||
self.clear();
|
self.clear();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -833,25 +820,20 @@ impl ShortNameGenerator {
|
|||||||
let (basename_len, name_fits, lossy_conv) = match name.rfind('.') {
|
let (basename_len, name_fits, lossy_conv) = match name.rfind('.') {
|
||||||
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, basename_len: basename_len as u8, ..Default::default() }
|
||||||
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) {
|
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)
|
// 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] == b'~' {
|
let num_suffix =
|
||||||
(short_name[prefix_len + 1] as char).to_digit(10)
|
if short_name[prefix_len] == b'~' { (short_name[prefix_len + 1] as char).to_digit(10) } else { None };
|
||||||
} 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
|
||||||
@ -911,7 +890,8 @@ impl ShortNameGenerator {
|
|||||||
None
|
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;
|
||||||
@ -1013,9 +993,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lfn_checksum_overflow() {
|
fn test_lfn_checksum_overflow() {
|
||||||
lfn_checksum(&[
|
lfn_checksum(&[0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8]);
|
||||||
0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -56,11 +56,7 @@ 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]
|
let ext_len = raw_name[8..11].iter().rposition(|x| *x != Self::PADDING).map(|p| p + 1).unwrap_or(0);
|
||||||
.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 {
|
||||||
@ -77,10 +73,7 @@ impl ShortName {
|
|||||||
name[0] = 0xE5;
|
name[0] = 0xE5;
|
||||||
}
|
}
|
||||||
// Short names in FAT filesystem are encoded in OEM code-page
|
// Short names in FAT filesystem are encoded in OEM code-page
|
||||||
ShortName {
|
ShortName { name, len: total_len as u8 }
|
||||||
name,
|
|
||||||
len: total_len as u8,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_bytes(&self) -> &[u8] {
|
fn as_bytes(&self) -> &[u8] {
|
||||||
@ -124,11 +117,7 @@ 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, ..Default::default() }
|
||||||
name,
|
|
||||||
attrs,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn renamed(&self, new_name: [u8; 11]) -> Self {
|
pub(crate) fn renamed(&self, new_name: [u8; 11]) -> Self {
|
||||||
@ -279,12 +268,7 @@ 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, attrs: FileAttributes::LFN, ..Default::default() }
|
||||||
order,
|
|
||||||
checksum,
|
|
||||||
attrs: FileAttributes::LFN,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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]) {
|
||||||
@ -369,10 +353,7 @@ impl DirEntryData {
|
|||||||
let attrs = FileAttributes::from_bits_truncate(rdr.read_u8()?);
|
let attrs = FileAttributes::from_bits_truncate(rdr.read_u8()?);
|
||||||
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);
|
||||||
data.order = cur.read_u8()?;
|
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");
|
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!(
|
assert_eq!(ShortName::new(&raw_short_name).to_string(&LOSSY_OEM_CP_CONVERTER), "\u{FFFD}OOK AT.M \u{FFFD}");
|
||||||
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),
|
ShortName::new(&raw_short_name).eq_ignore_case("\u{FFFD}OOK AT.M \u{FFFD}", &LOSSY_OEM_CP_CONVERTER),
|
||||||
true
|
true
|
||||||
@ -696,11 +674,8 @@ mod tests {
|
|||||||
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(b"FOO RS ");
|
raw_short_name.copy_from_slice(b"FOO RS ");
|
||||||
let mut raw_entry = DirFileEntryData {
|
let mut raw_entry =
|
||||||
name: raw_short_name,
|
DirFileEntryData { name: raw_short_name, reserved_0: (1 << 3) | (1 << 4), ..Default::default() };
|
||||||
reserved_0: (1 << 3) | (1 << 4),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
assert_eq!(raw_entry.lowercase_name().to_string(&LOSSY_OEM_CP_CONVERTER), "foo.rs");
|
assert_eq!(raw_entry.lowercase_name().to_string(&LOSSY_OEM_CP_CONVERTER), "foo.rs");
|
||||||
raw_entry.reserved_0 = 1 << 3;
|
raw_entry.reserved_0 = 1 << 3;
|
||||||
assert_eq!(raw_entry.lowercase_name().to_string(&LOSSY_OEM_CP_CONVERTER), "foo.RS");
|
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::cell::{Cell, RefCell};
|
||||||
use core::char;
|
use core::char;
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use core::u32;
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use core::iter::FromIterator;
|
use core::iter::FromIterator;
|
||||||
|
use core::u32;
|
||||||
use io;
|
use io;
|
||||||
use io::prelude::*;
|
use io::prelude::*;
|
||||||
use io::{Error, ErrorKind, SeekFrom};
|
use io::{Error, ErrorKind, SeekFrom};
|
||||||
@ -108,10 +108,7 @@ impl FsStatusFlags {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn decode(flags: u8) -> Self {
|
pub(crate) fn decode(flags: u8) -> Self {
|
||||||
FsStatusFlags {
|
FsStatusFlags { dirty: flags & 1 != 0, io_error: flags & 2 != 0 }
|
||||||
dirty: flags & 1 != 0,
|
|
||||||
io_error: flags & 2 != 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,11 +163,7 @@ impl FsInfoSector {
|
|||||||
if trail_sig != Self::TRAIL_SIG {
|
if trail_sig != Self::TRAIL_SIG {
|
||||||
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, dirty: false })
|
||||||
free_cluster_count,
|
|
||||||
next_free_cluster,
|
|
||||||
dirty: false,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize<T: Write>(&self, wrt: &mut T) -> io::Result<()> {
|
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;
|
let max_valid_cluster_number = total_clusters + RESERVED_FAT_ENTRIES;
|
||||||
if let Some(n) = self.free_cluster_count {
|
if let Some(n) = self.free_cluster_count {
|
||||||
if n > total_clusters {
|
if n > total_clusters {
|
||||||
warn!(
|
warn!("invalid free_cluster_count ({}) in fs_info exceeds total cluster count ({})", n, total_clusters);
|
||||||
"invalid free_cluster_count ({}) in fs_info exceeds total cluster count ({})",
|
|
||||||
n, total_clusters
|
|
||||||
);
|
|
||||||
self.free_cluster_count = None;
|
self.free_cluster_count = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -537,11 +527,7 @@ impl<T: ReadWriteSeek> FileSystem<T> {
|
|||||||
Some(n) => n,
|
Some(n) => n,
|
||||||
_ => self.recalc_free_clusters()?,
|
_ => self.recalc_free_clusters()?,
|
||||||
};
|
};
|
||||||
Ok(FileSystemStats {
|
Ok(FileSystemStats { cluster_size: self.cluster_size(), total_clusters: self.total_clusters, free_clusters })
|
||||||
cluster_size: self.cluster_size(),
|
|
||||||
total_clusters: self.total_clusters,
|
|
||||||
free_clusters,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Forces free clusters recalculation.
|
/// Forces free clusters recalculation.
|
||||||
@ -667,22 +653,11 @@ pub(crate) struct DiskSlice<T> {
|
|||||||
|
|
||||||
impl<T> DiskSlice<T> {
|
impl<T> DiskSlice<T> {
|
||||||
pub(crate) fn new(begin: u64, size: u64, mirrors: u8, inner: T) -> Self {
|
pub(crate) fn new(begin: u64, size: u64, mirrors: u8, inner: T) -> Self {
|
||||||
DiskSlice {
|
DiskSlice { begin, size, mirrors, inner, offset: 0 }
|
||||||
begin,
|
|
||||||
size,
|
|
||||||
mirrors,
|
|
||||||
inner,
|
|
||||||
offset: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_sectors(first_sector: u32, sector_count: u32, mirrors: u8, bpb: &BiosParameterBlock, inner: T) -> Self {
|
fn from_sectors(first_sector: u32, sector_count: u32, mirrors: u8, bpb: &BiosParameterBlock, inner: T) -> Self {
|
||||||
Self::new(
|
Self::new(bpb.bytes_from_sectors(first_sector), bpb.bytes_from_sectors(sector_count), mirrors, inner)
|
||||||
bpb.bytes_from_sectors(first_sector),
|
|
||||||
bpb.bytes_from_sectors(sector_count),
|
|
||||||
mirrors,
|
|
||||||
inner,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn abs_pos(&self) -> u64 {
|
pub(crate) fn abs_pos(&self) -> u64 {
|
||||||
@ -830,9 +805,7 @@ impl FormatVolumeOptions {
|
|||||||
/// Allows to overwrite many filesystem parameters.
|
/// Allows to overwrite many filesystem parameters.
|
||||||
/// In normal use-case defaults should suffice.
|
/// In normal use-case defaults should suffice.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
FormatVolumeOptions {
|
FormatVolumeOptions { ..Default::default() }
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set size of cluster in bytes (must be dividable by sector size)
|
/// 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() {
|
if boot.bpb.is_fat32() {
|
||||||
// FSInfo sector
|
// FSInfo sector
|
||||||
let fs_info_sector = FsInfoSector {
|
let fs_info_sector = FsInfoSector { free_cluster_count: None, next_free_cluster: None, dirty: false };
|
||||||
free_cluster_count: None,
|
|
||||||
next_free_cluster: None,
|
|
||||||
dirty: false,
|
|
||||||
};
|
|
||||||
disk.seek(SeekFrom::Start(boot.bpb.bytes_from_sectors(boot.bpb.fs_info_sector())))?;
|
disk.seek(SeekFrom::Start(boot.bpb.bytes_from_sectors(boot.bpb.fs_info_sector())))?;
|
||||||
fs_info_sector.serialize(&mut disk)?;
|
fs_info_sector.serialize(&mut disk)?;
|
||||||
write_zeros_until_end_of_sector(&mut disk, bytes_per_sector)?;
|
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);
|
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 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);
|
let root_dir_pos = boot.bpb.bytes_from_sectors(root_dir_first_sector);
|
||||||
disk.seek(SeekFrom::Start(root_dir_pos))?;
|
disk.seek(SeekFrom::Start(root_dir_pos))?;
|
||||||
write_zeros(&mut disk, boot.bpb.cluster_size() as u64)?;
|
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 {
|
match fat_type {
|
||||||
FatType::Fat12 => Fat12::find_free(fat, start_cluster, end_cluster),
|
FatType::Fat12 => Fat12::find_free(fat, start_cluster, end_cluster),
|
||||||
FatType::Fat16 => Fat16::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) {
|
let new_cluster = match find_free_cluster(fat, fat_type, start_cluster, end_cluster) {
|
||||||
Ok(n) => n,
|
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),
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
write_fat(fat, fat_type, new_cluster, FatValue::EndOfChain)?;
|
write_fat(fat, fat_type, new_cluster, FatValue::EndOfChain)?;
|
||||||
@ -413,12 +420,7 @@ pub(crate) struct ClusterIterator<T: ReadWriteSeek> {
|
|||||||
|
|
||||||
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_type, cluster: Some(cluster), err: false }
|
||||||
fat,
|
|
||||||
fat_type,
|
|
||||||
cluster: Some(cluster),
|
|
||||||
err: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn truncate(&mut self) -> io::Result<u32> {
|
pub(crate) fn truncate(&mut self) -> io::Result<u32> {
|
||||||
@ -501,10 +503,7 @@ 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!(
|
assert_eq!(iter.map(|r| r.unwrap()).collect::<Vec<_>>(), vec![0xA, 0x14, 0x15, 0x16, 0x19, 0x1A]);
|
||||||
iter.map(|r| r.unwrap()).collect::<Vec<_>>(),
|
|
||||||
vec![0xA, 0x14, 0x15, 0x16, 0x19, 0x1A]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// test truncating a chain
|
// test truncating a chain
|
||||||
{
|
{
|
||||||
@ -530,9 +529,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fat12() {
|
fn test_fat12() {
|
||||||
let fat: Vec<u8> = vec![
|
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,
|
0xF0, 0xFF, 0xFF, 0x03, 0x40, 0x00, 0x05, 0x60, 0x00, 0x07, 0x80, 0x00, 0xFF, 0xAF, 0x00, 0x14, 0xC0, 0x00,
|
||||||
0x0F, 0x00, 0x01, 0x11, 0xF0, 0xFF, 0x00, 0xF0, 0xFF, 0x15, 0x60, 0x01, 0x19, 0x70, 0xFF, 0xF7, 0xAF, 0x01, 0xFF, 0x0F, 0x00,
|
0x0D, 0xE0, 0x00, 0x0F, 0x00, 0x01, 0x11, 0xF0, 0xFF, 0x00, 0xF0, 0xFF, 0x15, 0x60, 0x01, 0x19, 0x70, 0xFF,
|
||||||
0x00, 0x70, 0xFF, 0x00, 0x00, 0x00,
|
0xF7, 0xAF, 0x01, 0xFF, 0x0F, 0x00, 0x00, 0x70, 0xFF, 0x00, 0x00, 0x00,
|
||||||
];
|
];
|
||||||
test_fat(FatType::Fat12, io::Cursor::new(fat));
|
test_fat(FatType::Fat12, io::Cursor::new(fat));
|
||||||
}
|
}
|
||||||
@ -540,10 +539,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fat16() {
|
fn test_fat16() {
|
||||||
let fat: Vec<u8> = vec![
|
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,
|
0xF0, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0xFF, 0xFF,
|
||||||
0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x10, 0x00, 0x11, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x15, 0x00,
|
0x0A, 0x00, 0x14, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x10, 0x00, 0x11, 0x00, 0xFF, 0xFF,
|
||||||
0x16, 0x00, 0x19, 0x00, 0xF7, 0xFF, 0xF7, 0xFF, 0x1A, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0xFF, 0xFF, 0x15, 0x00, 0x16, 0x00, 0x19, 0x00, 0xF7, 0xFF, 0xF7, 0xFF, 0x1A, 0x00, 0xFF, 0xFF,
|
||||||
0x00,
|
0x00, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||||
];
|
];
|
||||||
test_fat(FatType::Fat16, io::Cursor::new(fat));
|
test_fat(FatType::Fat16, io::Cursor::new(fat));
|
||||||
}
|
}
|
||||||
@ -551,12 +550,13 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fat32() {
|
fn test_fat32() {
|
||||||
let fat: Vec<u8> = vec![
|
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,
|
0xF0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x0F, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00,
|
0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F,
|
||||||
0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
|
0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x0E, 0x00,
|
||||||
0x00, 0x11, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x15, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 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,
|
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x19, 0x00,
|
||||||
0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 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,
|
0x00, 0x00,
|
||||||
];
|
];
|
||||||
test_fat(FatType::Fat32, io::Cursor::new(fat));
|
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 {
|
impl DateTime {
|
||||||
pub(crate) fn decode(dos_date: u16, dos_time: u16, dos_time_hi_res: u8) -> Self {
|
pub(crate) fn decode(dos_date: u16, dos_time: u16, dos_time_hi_res: u8) -> Self {
|
||||||
DateTime {
|
DateTime { date: Date::decode(dos_date), time: Time::decode(dos_time, dos_time_hi_res) }
|
||||||
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")]
|
#[cfg(feature = "chrono")]
|
||||||
impl From<chrono::Date<Local>> for Date {
|
impl From<chrono::Date<Local>> for Date {
|
||||||
fn from(date: chrono::Date<Local>) -> Self {
|
fn from(date: chrono::Date<Local>) -> Self {
|
||||||
Date {
|
Date { year: date.year() as u16, month: date.month() as u16, day: date.day() as u16 }
|
||||||
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>>();
|
let filenames = subdir2.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
||||||
assert_eq!(filenames, [".", "..", "test file name.txt"]);
|
assert_eq!(filenames, [".", "..", "test file name.txt"]);
|
||||||
|
|
||||||
subdir1
|
subdir1.rename("subdir2 with long name/test file name.txt", &root_dir, "new-name.txt").expect("rename");
|
||||||
.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>>();
|
let filenames = subdir2.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
||||||
assert_eq!(filenames, [".", ".."]);
|
assert_eq!(filenames, [".", ".."]);
|
||||||
|
Loading…
Reference in New Issue
Block a user