Write correct allocation tables for files.

This commit is contained in:
Bas Wiel, van de 2024-05-03 13:27:09 +02:00
parent b8aac70371
commit fa2d258298
2 changed files with 62 additions and 67 deletions

View File

@ -184,6 +184,44 @@ impl DiskBuilder {
Ok(())
}
/// Writes the allocation tables to the disk for the specified partition.
pub fn write_allocation_tables(&mut self) -> Result<(), std::io::Error> {
let allocation_table_bytes = self.filesystem.allocation_table.as_bytes(self.filesystem.fat_type)?;
let mut sectors: Vec<[u8; 512]> = Vec::new();
let mut current_chunk: [u8; 512] = [0; 512];
let mut current_index = 0;
for &byte in allocation_table_bytes.iter() {
current_chunk[current_index] = byte;
current_index += 1;
// If the current sector is full, push it to the sectors vector and reset
if current_index == 512 {
sectors.push(current_chunk);
current_chunk = [0; 512];
current_index = 0;
}
}
// If there are remaining bytes in the last chunk, fill the rest with zeros and push it
if current_index > 0 {
sectors.push(current_chunk);
}
let mut sector_offset = self.filesystem.reserved_sector_count;
let mut counter = 0;
while counter < self.filesystem.fat_copies {
for (index, sector) in sectors.iter().enumerate() {
self.partition.write_sector(&mut self.disk, sector_offset as u32 + index as u32, *sector)?;
}
counter += 1;
sector_offset = sector_offset + self.filesystem.sectors_per_fat;
}
Ok(())
}
/// The builder is the struct that does all manner of validation before trying to
/// create a Disk so that what we create will make sense.
pub fn build(&mut self) -> Result<(), std::io::Error> {
@ -230,8 +268,7 @@ impl DiskBuilder {
// filesystem.mkdir(None, "DOS")?;
//filesystem.mkdir(None,"GAME")?;
// Last action: write the allocation table copies to the disk
self.filesystem
.write_allocation_tables(&self.partition, &mut self.disk)?;
self.write_allocation_tables()?;
for file in self.filesystem.root_directory.children.clone() {
self.write_file_to_storage(&file)?;

View File

@ -19,7 +19,7 @@ pub mod vbr;
/// Represents the overall structure of a FAT filesystem.
pub struct Fat {
/// Represents the type of the FAT filesystem (FAT12, FAT16, FAT32).
fat_type: FatType,
pub fat_type: FatType,
/// Holds the allocation table, which manages cluster allocation and deallocation.
pub allocation_table: AllocationTable,
/// Holds the root directory entries.
@ -31,9 +31,9 @@ pub struct Fat {
/// Specifies the number of sectors per cluster.
sectors_per_cluster: u8,
/// Indicates the count of reserved sectors at the beginning of the filesystem.
reserved_sector_count: u16,
pub reserved_sector_count: u16,
/// Specifies the number of copies of the FAT table.
fat_copies: u8,
pub fat_copies: u8,
/// Indicates the number of entries in the root directory (only applicable for FAT12 and FAT16).
root_dir_entries: u16,
/// Represents the total count of sectors in the filesystem.
@ -41,7 +41,7 @@ pub struct Fat {
/// Stores the media descriptor byte, indicating the type of storage media.
media_descriptor: MediaDescriptor,
/// Specifies the count of sectors per FAT table.
sectors_per_fat: u16,
pub sectors_per_fat: u16,
/// Indicates the count of sectors per track.
sectors_per_track: u16,
/// Specifies the count of heads (surfaces) on the storage device.
@ -348,6 +348,19 @@ impl Fat {
// Attempt to allocate clusters and handle errors appropriately
let allocated_clusters = self.allocate_clusters(data)?;
// Write the proper values to the allocation table
if let Some((last, elements)) = allocated_clusters.split_last() {
// Iterate over all but the last element with their indices
for (i, &current_cluster) in elements.iter().enumerate() {
let next_cluster = allocated_clusters[i + 1];
self.allocation_table
.allocate_cluster(current_cluster, next_cluster)?;
}
// Handle the last cluster, which points to the end of the chain
self.allocation_table.mark_end_of_chain(*last)?;
}
// Create a new directory entry
let file_entry = DirEntry::new(
filename,
@ -416,61 +429,6 @@ impl Fat {
Ok(())
}
/// Writes the allocation tables to the disk for the specified partition.
///
/// This method takes a mutable reference to self, representing the file system, and
/// references to a `Partition` and a mutable `Disk` where the allocation tables will be written.
/// It returns a `Result<(), std::io::Error>` indicating whether the operation was successful or not.
///
/// # Arguments
///
/// * `partition` - A reference to the partition where the allocation tables will be written.
/// * `disk` - A mutable reference to the disk where the allocation tables will be written.
///
/// # Errors
///
/// Returns an `std::io::Error` if any I/O operation fails during writing.
pub fn write_allocation_tables(
&mut self,
partition: &Partition,
disk: &mut Disk,
) -> Result<(), std::io::Error> {
let allocation_table_bytes = self.allocation_table.as_bytes(self.fat_type)?;
let mut sectors: Vec<[u8; 512]> = Vec::new();
let mut current_chunk: [u8; 512] = [0; 512];
let mut current_index = 0;
for &byte in allocation_table_bytes.iter() {
current_chunk[current_index] = byte;
current_index += 1;
// If the current sector is full, push it to the sectors vector and reset
if current_index == 512 {
sectors.push(current_chunk);
current_chunk = [0; 512];
current_index = 0;
}
}
// If there are remaining bytes in the last chunk, fill the rest with zeros and push it
if current_index > 0 {
sectors.push(current_chunk);
}
let mut sector_offset = self.reserved_sector_count;
let mut counter = 0;
while counter < self.fat_copies {
for (index, sector) in sectors.iter().enumerate() {
partition.write_sector(disk, sector_offset as u32 + index as u32, *sector)?;
}
counter += 1;
sector_offset = sector_offset + self.sectors_per_fat;
}
Ok(())
}
/// Generate a BIOS Parameter Block (BPB) compatible with DOS 2.00.
///
/// Constructs a BPB suitable for DOS 2.00 based on the filesystem parameters.
@ -697,12 +655,12 @@ impl Fat {
/// Return the sector address of the first data sector
pub fn get_first_data_sector(&self) -> u32 {
// Iterate over data in chunks and write sectors
let rootdir_sector_count = ((self.root_dir_entries * 32) / 512) & !512;
let first_data_sector = self.reserved_sector_count
+ (self.fat_copies as u16 * self.sectors_per_fat)
+ rootdir_sector_count;
first_data_sector as u32
// Iterate over data in chunks and write sectors
let rootdir_sector_count = ((self.root_dir_entries * 32) / 512) & !512;
let first_data_sector = self.reserved_sector_count
+ (self.fat_copies as u16 * self.sectors_per_fat)
+ rootdir_sector_count;
first_data_sector as u32
}
}