Speed up allocation by tracking last allocated cluster

This commit is contained in:
Rafał Harabień 2018-05-26 14:36:38 +02:00
parent 1ecc9293a2
commit 9129816893

View File

@ -205,10 +205,11 @@ impl Default for BootRecord {
} }
} }
#[derive(Default, Debug, Clone)]
struct FsInfoSector { struct FsInfoSector {
#[allow(dead_code)] #[allow(dead_code)]
free_cluster_count: u32, free_cluster_count: Option<u32>,
next_free_cluster: u32, next_free_cluster: Option<u32>,
} }
impl FsInfoSector { impl FsInfoSector {
@ -227,8 +228,14 @@ impl FsInfoSector {
if struc_sig != Self::STRUC_SIG { if struc_sig != Self::STRUC_SIG {
return Err(Error::new(ErrorKind::Other, "invalid struc_sig in FsInfo sector")); return Err(Error::new(ErrorKind::Other, "invalid struc_sig in FsInfo sector"));
} }
let free_cluster_count = rdr.read_u32::<LittleEndian>()?; let free_cluster_count = match rdr.read_u32::<LittleEndian>()? {
let next_free_cluster = rdr.read_u32::<LittleEndian>()?; 0xFFFFFFFF => None,
n => Some(n),
};
let next_free_cluster = match rdr.read_u32::<LittleEndian>()? {
0xFFFFFFFF => None,
n => Some(n),
};
let mut reserved2 = [0u8; 12]; let mut reserved2 = [0u8; 12];
rdr.read_exact(&mut reserved2)?; rdr.read_exact(&mut reserved2)?;
let trail_sig = rdr.read_u32::<LittleEndian>()?; let trail_sig = rdr.read_u32::<LittleEndian>()?;
@ -247,8 +254,8 @@ impl FsInfoSector {
let reserved = [0u8; 480]; let reserved = [0u8; 480];
wrt.write(&reserved)?; wrt.write(&reserved)?;
wrt.write_u32::<LittleEndian>(Self::STRUC_SIG)?; wrt.write_u32::<LittleEndian>(Self::STRUC_SIG)?;
wrt.write_u32::<LittleEndian>(self.free_cluster_count)?; wrt.write_u32::<LittleEndian>(self.free_cluster_count.unwrap_or(0xFFFFFFFF))?;
wrt.write_u32::<LittleEndian>(self.next_free_cluster)?; wrt.write_u32::<LittleEndian>(self.next_free_cluster.unwrap_or(0xFFFFFFFF))?;
let reserved2 = [0u8; 12]; let reserved2 = [0u8; 12];
wrt.write(&reserved2)?; wrt.write(&reserved2)?;
wrt.write_u32::<LittleEndian>(Self::TRAIL_SIG)?; wrt.write_u32::<LittleEndian>(Self::TRAIL_SIG)?;
@ -287,7 +294,7 @@ pub struct FileSystem<'a> {
first_data_sector: u32, first_data_sector: u32,
root_dir_sectors: u32, root_dir_sectors: u32,
total_clusters: u32, total_clusters: u32,
fs_info: Option<FsInfoSector>, fs_info: RefCell<FsInfoSector>,
} }
impl <'a> FileSystem<'a> { impl <'a> FileSystem<'a> {
@ -327,9 +334,9 @@ impl <'a> FileSystem<'a> {
let fs_info = if fat_type == FatType::Fat32 { let fs_info = if fat_type == FatType::Fat32 {
disk.seek(SeekFrom::Start(bpb.fs_info_sector as u64 * 512))?; disk.seek(SeekFrom::Start(bpb.fs_info_sector as u64 * 512))?;
Some(FsInfoSector::deserialize(disk)?) FsInfoSector::deserialize(disk)?
} else { } else {
None FsInfoSector::default()
}; };
Ok(FileSystem { Ok(FileSystem {
@ -340,7 +347,7 @@ impl <'a> FileSystem<'a> {
first_data_sector, first_data_sector,
root_dir_sectors, root_dir_sectors,
total_clusters, total_clusters,
fs_info, fs_info: RefCell::new(fs_info),
}) })
} }
@ -416,12 +423,11 @@ impl <'a> FileSystem<'a> {
} }
pub(crate) fn alloc_cluster(&self, prev_cluster: Option<u32>) -> io::Result<u32> { pub(crate) fn alloc_cluster(&self, prev_cluster: Option<u32>) -> io::Result<u32> {
let hint = match self.fs_info { let hint = self.fs_info.borrow().next_free_cluster;
Some(ref info) => Some(info.next_free_cluster),
None => None,
};
let mut fat = self.fat_slice(); let mut fat = self.fat_slice();
alloc_cluster(&mut fat, self.fat_type, prev_cluster, hint, self.total_clusters) let cluster = alloc_cluster(&mut fat, self.fat_type, prev_cluster, hint, self.total_clusters)?;
self.fs_info.borrow_mut().next_free_cluster = Some(cluster + 1);
Ok(cluster)
} }
pub fn read_status_flags(&self) -> io::Result<FsStatusFlags> { pub fn read_status_flags(&self) -> io::Result<FsStatusFlags> {