Lots of breakage! Mkdir refactored for arena allocator.

This commit is contained in:
Bas Wiel, van de 2024-05-09 16:33:47 +02:00
parent d33324da1a
commit 6fc4b6bcf6
2 changed files with 133 additions and 46 deletions

View File

@ -1,14 +1,15 @@
use std::fmt;
use std::os::unix::process::parent_id;
use self::allocationtable::AllocationTable;
use self::direntry::{DirEntry, DirEntryType};
use self::direntry::{Arena, DirEntry, DirEntryType, NodeId};
use crate::disk::partition::{Partition, PartitionType};
use crate::disk::vhd::VhdDisktype;
use crate::fat::direntry::Node;
use crate::os::OperatingSystem;
use crate::Disk;
pub mod allocationtable;
pub mod arena;
pub mod attributes;
pub mod cluster;
pub mod direntry;
@ -24,7 +25,8 @@ pub struct Fat {
/// Holds the allocation table, which manages cluster allocation and deallocation.
pub allocation_table: AllocationTable,
/// Holds the root directory entries.
pub root_directory: DirEntry,
pub arena: Arena<DirEntry>,
pub root_directory: NodeId,
/// Stores the OEM name of the filesystem.
oem_name: String,
/// Indicates the number of bytes per sector in the filesystem.
@ -168,6 +170,8 @@ impl Fat {
None => [0u8; 446],
};
let mut arena = Arena::new();
let root_directory = arena.insert_node(Node::new_directory("root", 0));
Ok(Fat {
fat_type,
allocation_table: AllocationTable::new(
@ -384,51 +388,34 @@ impl Fat {
/// Equivalent of the MS-DOS "MKDIR" command. Provide a name, the system will do the rest.
pub fn mkdir(
&mut self,
parent: Option<&mut DirEntry>,
parent: Option<NodeId>,
dir_name: &str,
) -> Result<(), std::io::Error> {
) -> Result<NodeId, std::io::Error> {
// Set the parent to the root dir if none is given
let new_start_cluster = self.allocate_cluster()?;
self.allocation_table.mark_end_of_chain(new_start_cluster)?;
let allocated_clusters: Vec<u32> = vec![new_start_cluster];
let parent_entry = parent.unwrap_or(&mut self.root_directory);
let parent_clusters = vec![parent_entry.get_start_cluster()];
let parent_entry = parent.unwrap_or(self.root_directory);
let parent_clusters = if let Some(parent_node) = self.arena.get_node(parent_id) {
parent_node.value.get_allocated_clusters().clone()
} else {
vec![2] // Default to empty if parent isn't found, though this should be handled more robustly
};
// Instantiate the new entry.
let mut new_entry = DirEntry::new(
dir_name,
DirEntryType::Directory,
None,
&allocated_clusters,
0,
None,
)?;
let new_dir_node = Node::new_directory(dir_name, allocated_clusters);
let new_dir_id = self.arena.insert_node(new_dir_node);
self.arena.add_child(parent_entry, new_dir_id);
// Create the "." entry as a child.
new_entry.add_child(DirEntry::new(
".",
DirEntryType::Directory,
None,
&allocated_clusters,
0,
None,
)?);
let self_dot_node = Node::new_directory(".", allocated_clusters);
let self_dot_id = self.arena.insert_node(self_dot_node);
let parent_dot_node = Node::new_directory("..", parent_clusters);
let parent_dot_id = self.arena.insert_node(parent_dot_node);
self.arena.add_child(new_dir_id, self_dot_id);
self.arena.add_child(new_dir_id, parent_dot_id);
// Create the ".." entry as a child.
new_entry.add_child(DirEntry::new(
"..",
DirEntryType::Directory,
None,
&parent_clusters,
0,
None,
)?);
// Add the complete new entry to its parent
parent_entry.add_child(new_entry);
Ok(())
Ok(new_dir_id)
}
/// Generate a BIOS Parameter Block (BPB) compatible with DOS 2.00.
@ -664,6 +651,28 @@ impl Fat {
+ rootdir_sector_count;
first_data_sector as u32
}
// Gets children of a directory entry by NodeId and returns references to their DirEntry
pub fn get_directory_entries(&self, directory_id: NodeId) -> Vec<&DirEntry> {
self.arena
.get_node(directory_id)
.map_or(vec![], |dir_entry| {
dir_entry
.children
.iter()
.filter_map(|&child_id| self.arena.get_node(child_id))
.collect()
})
}
/// Retrieves the allocated clusters for a directory entry identified by `node_id`.
pub fn get_allocated_clusters(&self, node_id: NodeId) -> Option<&Vec<u32>> {
// Access the node from the arena using the node ID
self.arena
.get_node(node_id)
// If the node exists, retrieve the allocated clusters
.map(|node| node.value.get_allocated_clusters())
}
}
/// Enum representing different types of FAT (File Allocation Table) file systems.

View File

@ -8,11 +8,82 @@ pub struct DirEntry {
create_timedate: TimeDate,
pub file_size: u32,
pub entry_type: DirEntryType,
pub children: Vec<DirEntry>,
pub children: Vec<NodeId>,
pub allocated_clusters: Vec<u32>,
data: Vec<u8>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Node<T> {
pub value: T,
pub parent: Option<NodeId>, // Optionally keep track of the parent
}
impl Node<DirEntry> {
pub fn new_directory(dir_name: &str, allocated_clusters: Vec<u32>) -> Self {
Node {
value: DirEntry::new(
dir_name,
DirEntryType::Directory,
None,
&allocated_clusters,
0,
None,
)
.expect("Boom!"),
parent: None,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Arena<T> {
nodes: Vec<Node<T>>,
}
impl Arena<DirEntry> {
pub fn new_node(&mut self, entry: DirEntry) -> NodeId {
let node_id = NodeId(self.nodes.len());
self.nodes.push(Node {
value: entry,
parent: None,
});
node_id
}
pub fn add_child(&mut self, parent_id: NodeId, child_id: NodeId) {
if let Some(node) = self.nodes.get_mut(parent_id.0) {
node.value.children.push(child_id);
}
if let Some(node) = self.nodes.get_mut(child_id.0) {
node.parent = Some(parent_id);
}
}
/// Inserts a new node into the arena and returns a NodeId that can be used to reference it.
pub fn insert_node(&mut self, node: Node<T>) -> NodeId {
let node_id = NodeId(self.nodes.len());
self.nodes.push(node);
node_id
}
/// Retrieves an immutable reference to the node specified by `node_id`.
/// Returns `None` if no node exists at that index.
pub fn get_node(&self, node_id: NodeId) -> Option<&Node<T>> {
self.nodes.get(node_id.0)
}
/// Retrieves a mutable reference to the node specified by `node_id`.
/// Returns `None` if no node exists at that index.
pub fn get_node_mut(&mut self, node_id: NodeId) -> Option<&mut Node<T>> {
self.nodes.get_mut(node_id.0)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct NodeId(usize);
/// Enum to differentiate between different types of DirEntry. These types streamline
/// the definition of default values.
#[derive(Clone, Copy, Debug, PartialEq)]
@ -66,9 +137,13 @@ impl DirEntry {
file_size,
data.unwrap().to_vec(),
),
DirEntryType::SysFile => {
Self::create_sysfile(filename, create_timedate, file_size, allocated_clusters, data)
}
DirEntryType::SysFile => Self::create_sysfile(
filename,
create_timedate,
file_size,
allocated_clusters,
data,
),
DirEntryType::Directory => {
Self::create_directory(filename, create_timedate, allocated_clusters)
}
@ -341,8 +416,12 @@ impl DirEntry {
}
}
pub fn get_children(&mut self) -> &Vec<DirEntry> {
&mut self.children
pub fn get_allocated_clusters(&self) -> &Vec<u32> {
&self.allocated_clusters
}
pub fn get_children(&mut self) -> &Vec<NodeId> {
&self.children
}
pub fn add_child(&mut self, child: DirEntry) {
@ -381,7 +460,6 @@ impl DirEntry {
}
Ok(bytes)
}
}
#[cfg(test)]
@ -405,7 +483,7 @@ mod tests {
file_size: 4608,
entry_type: DirEntryType::File, // Dummy placeholder
children: Vec::new(),
allocated_clusters: vec![2,3,4],
allocated_clusters: vec![2, 3, 4],
data: Vec::new(),
};
// Semi-representative entry that reflects IBMBIO.COM on April 4 1983.