forked from M-Labs/rust-fatfs
Refactor FAT type determination, rename and add option for format_volume
* FAT type should be properly selected even if custom cluster size is used. * root_entries has been renamed to max_root_dir_entries in FormatVolumeOptions * added option FormatVolumeOptions::fats
This commit is contained in:
parent
131f047c91
commit
dc128b7308
@ -1,4 +1,6 @@
|
|||||||
use core::cmp;
|
use core::cmp;
|
||||||
|
use core::u8;
|
||||||
|
use core::u16;
|
||||||
use io;
|
use io;
|
||||||
use io::prelude::*;
|
use io::prelude::*;
|
||||||
use io::{Error, ErrorKind};
|
use io::{Error, ErrorKind};
|
||||||
@ -427,7 +429,8 @@ impl Default for BootSector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn determine_fat_type(total_bytes: u64) -> FatType {
|
pub(crate) fn estimate_fat_type(total_bytes: u64) -> FatType {
|
||||||
|
// Used only to select cluster size if FAT type has not been overriden in options
|
||||||
if total_bytes < 4 * MB {
|
if total_bytes < 4 * MB {
|
||||||
FatType::Fat12
|
FatType::Fat12
|
||||||
} else if total_bytes < 512 * MB {
|
} else if total_bytes < 512 * MB {
|
||||||
@ -437,7 +440,8 @@ pub(crate) fn determine_fat_type(total_bytes: u64) -> FatType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn determine_bytes_per_cluster(total_bytes: u64, fat_type: FatType, bytes_per_sector: u16) -> u32 {
|
fn determine_bytes_per_cluster(total_bytes: u64, bytes_per_sector: u16, fat_type: Option<FatType>) -> u32 {
|
||||||
|
let fat_type = fat_type.unwrap_or_else(|| estimate_fat_type(total_bytes));
|
||||||
let bytes_per_cluster = match fat_type {
|
let bytes_per_cluster = match fat_type {
|
||||||
FatType::Fat12 => (total_bytes.next_power_of_two() / MB * 512) as u32,
|
FatType::Fat12 => (total_bytes.next_power_of_two() / MB * 512) as u32,
|
||||||
FatType::Fat16 => {
|
FatType::Fat16 => {
|
||||||
@ -520,29 +524,16 @@ fn determine_sectors_per_fat(
|
|||||||
sectors_per_fat as u32
|
sectors_per_fat as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_bpb(options: &FormatVolumeOptions, total_sectors: u32, bytes_per_sector: u16) -> io::Result<(BiosParameterBlock, FatType)> {
|
fn try_fs_geometry(total_sectors: u32, bytes_per_sector: u16, sectors_per_cluster: u8, fat_type: FatType,
|
||||||
let total_bytes = u64::from(total_sectors) * u64::from(bytes_per_sector);
|
root_dir_sectors: u32, fats: u8) -> io::Result<(u16, u32)> {
|
||||||
// FIXME: determine FAT type from cluster size because it can be modified by user
|
|
||||||
let fat_type = options.fat_type.unwrap_or_else(|| determine_fat_type(total_bytes));
|
|
||||||
let bytes_per_cluster = options
|
|
||||||
.bytes_per_cluster
|
|
||||||
.unwrap_or_else(|| determine_bytes_per_cluster(total_bytes, fat_type, bytes_per_sector));
|
|
||||||
let sectors_per_cluster = (bytes_per_cluster / bytes_per_sector as u32) as u8;
|
|
||||||
|
|
||||||
// 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.
|
||||||
let reserved_sectors: u16 = if fat_type == FatType::Fat32 { 8 } else { 1 };
|
let reserved_sectors: u16 = if fat_type == FatType::Fat32 { 8 } else { 1 };
|
||||||
|
|
||||||
let fats = 2u8;
|
|
||||||
let is_fat32 = fat_type == FatType::Fat32;
|
|
||||||
let root_entries = if is_fat32 { 0 } else { options.root_entries.unwrap_or(512) };
|
|
||||||
let root_dir_bytes = root_entries as u32 * DIR_ENTRY_SIZE as u32;
|
|
||||||
let root_dir_sectors = (root_dir_bytes + bytes_per_sector as u32 - 1) / bytes_per_sector as u32;
|
|
||||||
|
|
||||||
// Check if volume has enough space to accomodate reserved sectors, FAT, root directory and some data space
|
// Check if volume has enough space to accomodate reserved sectors, FAT, root directory and some data space
|
||||||
// Having less than 8 sectors for FAT and data would make a little sense
|
// Having less than 8 sectors for FAT and data would make a little sense
|
||||||
if total_sectors <= reserved_sectors as u32 + root_dir_sectors as u32 + 8 {
|
if total_sectors <= u32::from(reserved_sectors) + u32::from(root_dir_sectors) + 8 {
|
||||||
return Err(Error::new(ErrorKind::Other, "Volume is too small"));
|
return Err(Error::new(ErrorKind::Other, "Volume is too small"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,6 +548,63 @@ fn format_bpb(options: &FormatVolumeOptions, total_sectors: u32, bytes_per_secto
|
|||||||
fats,
|
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"));
|
||||||
|
}
|
||||||
|
debug_assert!(total_clusters >= fat_type.min_clusters());
|
||||||
|
if total_clusters > fat_type.max_clusters() {
|
||||||
|
// Note: it can happen for FAT32
|
||||||
|
return Err(Error::new(ErrorKind::Other, "Too many clusters"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok((reserved_sectors, sectors_per_fat));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn determine_root_dir_sectors(root_dir_entries: u16, bytes_per_sector: u16, fat_type: FatType) -> u32 {
|
||||||
|
if fat_type == FatType::Fat32 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
let root_dir_bytes = u32::from(root_dir_entries) * DIR_ENTRY_SIZE as u32;
|
||||||
|
(root_dir_bytes + u32::from(bytes_per_sector) - 1) / u32::from(bytes_per_sector)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(|| {
|
||||||
|
let total_bytes = u64::from(total_sectors) * u64::from(bytes_per_sector);
|
||||||
|
determine_bytes_per_cluster(total_bytes, bytes_per_sector, options.fat_type)
|
||||||
|
});
|
||||||
|
|
||||||
|
let sectors_per_cluster = bytes_per_cluster / u32::from(bytes_per_sector);
|
||||||
|
assert!(sectors_per_cluster <= u32::from(u8::MAX));
|
||||||
|
let sectors_per_cluster = sectors_per_cluster as u8;
|
||||||
|
|
||||||
|
let fats = options.fats.unwrap_or(2u8);
|
||||||
|
let root_dir_entries = options.max_root_dir_entries.unwrap_or(512);
|
||||||
|
let (fat_type, reserved_sectors, sectors_per_fat) =
|
||||||
|
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
|
.drive_num
|
||||||
@ -583,15 +631,22 @@ fn format_bpb(options: &FormatVolumeOptions, total_sectors: u32, bytes_per_secto
|
|||||||
fs_type_label.copy_from_slice(fs_type_label_str);
|
fs_type_label.copy_from_slice(fs_type_label_str);
|
||||||
|
|
||||||
// create Bios Parameter Block struct
|
// create Bios Parameter Block struct
|
||||||
|
let is_fat32 = fat_type == FatType::Fat32;
|
||||||
|
let sectors_per_fat_16 = if is_fat32 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
debug_assert!(sectors_per_fat <= u32::from(u16::MAX));
|
||||||
|
sectors_per_fat as u16
|
||||||
|
};
|
||||||
let bpb = BiosParameterBlock {
|
let bpb = BiosParameterBlock {
|
||||||
bytes_per_sector,
|
bytes_per_sector,
|
||||||
sectors_per_cluster,
|
sectors_per_cluster,
|
||||||
reserved_sectors,
|
reserved_sectors,
|
||||||
fats,
|
fats,
|
||||||
root_entries,
|
root_entries: if is_fat32 { 0 } else { root_dir_entries },
|
||||||
total_sectors_16: if total_sectors < 0x10000 { total_sectors as u16 } else { 0 },
|
total_sectors_16: if total_sectors < 0x10000 { total_sectors as u16 } else { 0 },
|
||||||
media: options.media.unwrap_or(0xF8),
|
media: options.media.unwrap_or(0xF8),
|
||||||
sectors_per_fat_16: if is_fat32 { 0 } else { sectors_per_fat as u16 },
|
sectors_per_fat_16,
|
||||||
sectors_per_track: options.sectors_per_track.unwrap_or(0x20),
|
sectors_per_track: options.sectors_per_track.unwrap_or(0x20),
|
||||||
heads: options.heads.unwrap_or(0x40),
|
heads: options.heads.unwrap_or(0x40),
|
||||||
hidden_sectors: 0,
|
hidden_sectors: 0,
|
||||||
@ -647,11 +702,11 @@ pub(crate) fn format_boot_sector(options: &FormatVolumeOptions, total_sectors: u
|
|||||||
// fix offsets in bootjmp and boot code for non-FAT32 filesystems (bootcode is on a different offset)
|
// fix offsets in bootjmp and boot code for non-FAT32 filesystems (bootcode is on a different offset)
|
||||||
if fat_type != FatType::Fat32 {
|
if fat_type != FatType::Fat32 {
|
||||||
// offset of boot code
|
// offset of boot code
|
||||||
let boot_code_offset = 0x36 + 8;
|
let boot_code_offset: u8 = 0x36 + 8;
|
||||||
boot.bootjmp[1] = (boot_code_offset - 2) as u8;
|
boot.bootjmp[1] = boot_code_offset - 2;
|
||||||
// offset of message
|
// offset of message
|
||||||
const MESSAGE_OFFSET: u32 = 29;
|
const MESSAGE_OFFSET: u16 = 29;
|
||||||
let message_offset_in_sector = boot_code_offset + MESSAGE_OFFSET + 0x7c00;
|
let message_offset_in_sector = u16::from(boot_code_offset) + MESSAGE_OFFSET + 0x7c00;
|
||||||
boot.boot_code[3] = (message_offset_in_sector & 0xff) as u8;
|
boot.boot_code[3] = (message_offset_in_sector & 0xff) as u8;
|
||||||
boot.boot_code[4] = (message_offset_in_sector >> 8) as u8;
|
boot.boot_code[4] = (message_offset_in_sector >> 8) as u8;
|
||||||
}
|
}
|
||||||
@ -664,49 +719,49 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_determine_fat_type() {
|
fn test_estimate_fat_type() {
|
||||||
assert_eq!(determine_fat_type(3 * MB), FatType::Fat12);
|
assert_eq!(estimate_fat_type(3 * MB), FatType::Fat12);
|
||||||
assert_eq!(determine_fat_type(4 * MB), FatType::Fat16);
|
assert_eq!(estimate_fat_type(4 * MB), FatType::Fat16);
|
||||||
assert_eq!(determine_fat_type(511 * MB), FatType::Fat16);
|
assert_eq!(estimate_fat_type(511 * MB), FatType::Fat16);
|
||||||
assert_eq!(determine_fat_type(512 * MB), FatType::Fat32);
|
assert_eq!(estimate_fat_type(512 * MB), FatType::Fat32);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_determine_bytes_per_cluster_fat12() {
|
fn test_determine_bytes_per_cluster_fat12() {
|
||||||
assert_eq!(determine_bytes_per_cluster(1 * MB + 0, FatType::Fat12, 512), 512);
|
assert_eq!(determine_bytes_per_cluster(1 * MB + 0, 512, Some(FatType::Fat12)), 512);
|
||||||
assert_eq!(determine_bytes_per_cluster(1 * MB + 1, FatType::Fat12, 512), 1024);
|
assert_eq!(determine_bytes_per_cluster(1 * MB + 1, 512, Some(FatType::Fat12)), 1024);
|
||||||
assert_eq!(determine_bytes_per_cluster(1 * MB, FatType::Fat12, 4096), 4096);
|
assert_eq!(determine_bytes_per_cluster(1 * MB, 4096, Some(FatType::Fat12)), 4096);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_determine_bytes_per_cluster_fat16() {
|
fn test_determine_bytes_per_cluster_fat16() {
|
||||||
assert_eq!(determine_bytes_per_cluster(1 * MB, FatType::Fat16, 512), 1 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(1 * MB, 512, Some(FatType::Fat16)), 1 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(1 * MB, FatType::Fat16, 4 * KB as u16), 4 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(1 * MB, 4 * KB as u16, Some(FatType::Fat16)), 4 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(16 * MB + 0, FatType::Fat16, 512), 1 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(16 * MB + 0, 512, Some(FatType::Fat16)), 1 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(16 * MB + 1, FatType::Fat16, 512), 2 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(16 * MB + 1, 512, Some(FatType::Fat16)), 2 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(128 * MB + 0, FatType::Fat16, 512), 2 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(128 * MB + 0, 512, Some(FatType::Fat16)), 2 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(128 * MB + 1, FatType::Fat16, 512), 4 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(128 * MB + 1, 512, Some(FatType::Fat16)), 4 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(256 * MB + 0, FatType::Fat16, 512), 4 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(256 * MB + 0, 512, Some(FatType::Fat16)), 4 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(256 * MB + 1, FatType::Fat16, 512), 8 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(256 * MB + 1, 512, Some(FatType::Fat16)), 8 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(512 * MB + 0, FatType::Fat16, 512), 8 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(512 * MB + 0, 512, Some(FatType::Fat16)), 8 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(512 * MB + 1, FatType::Fat16, 512), 16 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(512 * MB + 1, 512, Some(FatType::Fat16)), 16 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(1024 * MB + 0, FatType::Fat16, 512), 16 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(1024 * MB + 0, 512, Some(FatType::Fat16)), 16 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(1024 * MB + 1, FatType::Fat16, 512), 32 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(1024 * MB + 1, 512, Some(FatType::Fat16)), 32 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(99999 * MB, FatType::Fat16, 512), 32 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(99999 * MB, 512, Some(FatType::Fat16)), 32 * KB as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_determine_bytes_per_cluster_fat32() {
|
fn test_determine_bytes_per_cluster_fat32() {
|
||||||
assert_eq!(determine_bytes_per_cluster(260 * MB as u64, FatType::Fat32, 512), 512);
|
assert_eq!(determine_bytes_per_cluster(260 * MB as u64, 512, Some(FatType::Fat32)), 512);
|
||||||
assert_eq!(determine_bytes_per_cluster(260 * MB as u64, FatType::Fat32, 4 * KB as u16), 4 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(260 * MB as u64, 4 * KB as u16, Some(FatType::Fat32)), 4 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(260 * MB as u64 + 1, FatType::Fat32, 512), 4 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(260 * MB as u64 + 1, 512, Some(FatType::Fat32)), 4 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(8 * GB as u64, FatType::Fat32, 512), 4 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(8 * GB as u64, 512, Some(FatType::Fat32)), 4 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(8 * GB as u64 + 1, FatType::Fat32, 512), 8 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(8 * GB as u64 + 1, 512, Some(FatType::Fat32)), 8 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(16 * GB as u64 + 0, FatType::Fat32, 512), 8 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(16 * GB as u64 + 0, 512, Some(FatType::Fat32)), 8 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(16 * GB as u64 + 1, FatType::Fat32, 512), 16 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(16 * GB as u64 + 1, 512, Some(FatType::Fat32)), 16 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(32 * GB as u64, FatType::Fat32, 512), 16 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(32 * GB as u64, 512, Some(FatType::Fat32)), 16 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(32 * GB as u64 + 1, FatType::Fat32, 512), 32 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(32 * GB as u64 + 1, 512, Some(FatType::Fat32)), 32 * KB as u32);
|
||||||
assert_eq!(determine_bytes_per_cluster(999 * GB as u64, FatType::Fat32, 512), 32 * KB as u32);
|
assert_eq!(determine_bytes_per_cluster(999 * GB as u64, 512, Some(FatType::Fat32)), 32 * KB as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_determine_sectors_per_fat_single(
|
fn test_determine_sectors_per_fat_single(
|
||||||
@ -810,16 +865,21 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_format_boot_sector_large_partition() {
|
fn test_format_boot_sector() {
|
||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
let bytes_per_sector = 512;
|
let bytes_per_sector = 512u16;
|
||||||
let bytes_per_cluster = 4 * 4096;
|
// test all partition sizes from 1MB to 2TB (u32::MAX sectors is 2TB - 1 for 512 byte sectors)
|
||||||
let total_sectors = core::u32::MAX;
|
let mut total_sectors_vec = Vec::new();
|
||||||
let (boot, _) = format_boot_sector(&FormatVolumeOptions::new()
|
let mut size = 1 * MB;
|
||||||
.total_sectors(total_sectors)
|
while size < 2048 * GB {
|
||||||
.bytes_per_sector(bytes_per_sector)
|
total_sectors_vec.push((size / u64::from(bytes_per_sector)) as u32);
|
||||||
.bytes_per_cluster(bytes_per_cluster), total_sectors, bytes_per_sector)
|
size = size + size / 7;
|
||||||
.expect("format_boot_sector");
|
}
|
||||||
boot.validate().expect("validate");
|
total_sectors_vec.push(core::u32::MAX);
|
||||||
|
for total_sectors in total_sectors_vec {
|
||||||
|
let (boot, _) = format_boot_sector(&FormatVolumeOptions::new(), total_sectors, bytes_per_sector)
|
||||||
|
.expect("format_boot_sector");
|
||||||
|
boot.validate().expect("validate");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
41
src/fs.rs
41
src/fs.rs
@ -37,10 +37,14 @@ pub enum FatType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FatType {
|
impl FatType {
|
||||||
|
const FAT16_MIN_CLUSTERS: u32 = 4085;
|
||||||
|
const FAT32_MIN_CLUSTERS: u32 = 65525;
|
||||||
|
const FAT32_MAX_CLUSTERS: u32 = 0x0FFF_FFF4;
|
||||||
|
|
||||||
pub(crate) fn from_clusters(total_clusters: u32) -> FatType {
|
pub(crate) fn from_clusters(total_clusters: u32) -> FatType {
|
||||||
if total_clusters < 4085 {
|
if total_clusters < Self::FAT16_MIN_CLUSTERS {
|
||||||
FatType::Fat12
|
FatType::Fat12
|
||||||
} else if total_clusters < 65525 {
|
} else if total_clusters < Self::FAT32_MIN_CLUSTERS {
|
||||||
FatType::Fat16
|
FatType::Fat16
|
||||||
} else {
|
} else {
|
||||||
FatType::Fat32
|
FatType::Fat32
|
||||||
@ -54,6 +58,22 @@ impl FatType {
|
|||||||
&FatType::Fat32 => 32,
|
&FatType::Fat32 => 32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn min_clusters(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
&FatType::Fat12 => 0,
|
||||||
|
&FatType::Fat16 => Self::FAT16_MIN_CLUSTERS,
|
||||||
|
&FatType::Fat32 => Self::FAT32_MIN_CLUSTERS,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn max_clusters(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
&FatType::Fat12 => Self::FAT16_MIN_CLUSTERS - 1,
|
||||||
|
&FatType::Fat16 => Self::FAT32_MIN_CLUSTERS - 1,
|
||||||
|
&FatType::Fat32 => Self::FAT32_MAX_CLUSTERS,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A FAT volume status flags retrived from the Boot Sector and the allocation table second entry.
|
/// A FAT volume status flags retrived from the Boot Sector and the allocation table second entry.
|
||||||
@ -794,7 +814,8 @@ pub struct FormatVolumeOptions {
|
|||||||
pub(crate) total_sectors: Option<u32>,
|
pub(crate) total_sectors: Option<u32>,
|
||||||
pub(crate) bytes_per_cluster: Option<u32>,
|
pub(crate) bytes_per_cluster: Option<u32>,
|
||||||
pub(crate) fat_type: Option<FatType>,
|
pub(crate) fat_type: Option<FatType>,
|
||||||
pub(crate) root_entries: Option<u16>,
|
pub(crate) max_root_dir_entries: Option<u16>,
|
||||||
|
pub(crate) fats: Option<u8>,
|
||||||
pub(crate) media: Option<u8>,
|
pub(crate) media: Option<u8>,
|
||||||
pub(crate) sectors_per_track: Option<u16>,
|
pub(crate) sectors_per_track: Option<u16>,
|
||||||
pub(crate) heads: Option<u16>,
|
pub(crate) heads: Option<u16>,
|
||||||
@ -857,8 +878,18 @@ impl FormatVolumeOptions {
|
|||||||
/// Total root directory size should be dividable by sectors size so keep it a multiple of 16 (for default sector
|
/// Total root directory size should be dividable by sectors size so keep it a multiple of 16 (for default sector
|
||||||
/// size).
|
/// size).
|
||||||
/// Default is `512`.
|
/// Default is `512`.
|
||||||
pub fn root_entries(mut self, root_entries: u16) -> Self {
|
pub fn max_root_dir_entries(mut self, max_root_dir_entries: u16) -> Self {
|
||||||
self.root_entries = Some(root_entries);
|
self.max_root_dir_entries = Some(max_root_dir_entries);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set number of File Allocation Tables
|
||||||
|
///
|
||||||
|
/// The only allowed values are `1` and `2`. If `2` is used FAT is mirrored.
|
||||||
|
/// Default is `2`.
|
||||||
|
pub fn fats(mut self, fats: u8) -> Self {
|
||||||
|
assert!(fats >= 1 && fats <= 2);
|
||||||
|
self.fats = Some(fats);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,9 +80,9 @@ fn test_format_1mb() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_format_8mb() {
|
fn test_format_8mb_1fat() {
|
||||||
let total_bytes = 8 * MB;
|
let total_bytes = 8 * MB;
|
||||||
let opts = fatfs::FormatVolumeOptions::new();
|
let opts = fatfs::FormatVolumeOptions::new().fats(1);
|
||||||
let fs = test_format_fs(opts, total_bytes);
|
let fs = test_format_fs(opts, total_bytes);
|
||||||
assert_eq!(fs.fat_type(), fatfs::FatType::Fat16);
|
assert_eq!(fs.fat_type(), fatfs::FatType::Fat16);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user