summaryrefslogtreecommitdiff
path: root/src/memory/dir_entry.rs
diff options
context:
space:
mode:
authorChuyan Zhang <me@zcy.moe>2023-11-27 00:11:55 -0800
committerChuyan Zhang <me@zcy.moe>2023-11-27 00:11:55 -0800
commitec2f349a648e4d87fba12d20e338b1cd6d8ef29a (patch)
tree867221cfc9d46b10fee508de5b63996f12704051 /src/memory/dir_entry.rs
parent9d1368b0ea380a9446b4697af668d1685464b6c7 (diff)
downloadmyfs-ec2f349a648e4d87fba12d20e338b1cd6d8ef29a.tar.gz
myfs-ec2f349a648e4d87fba12d20e338b1cd6d8ef29a.zip
Fix directory stuff
Diffstat (limited to 'src/memory/dir_entry.rs')
-rw-r--r--src/memory/dir_entry.rs304
1 files changed, 231 insertions, 73 deletions
diff --git a/src/memory/dir_entry.rs b/src/memory/dir_entry.rs
index 2d961db..08a82c5 100644
--- a/src/memory/dir_entry.rs
+++ b/src/memory/dir_entry.rs
@@ -1,117 +1,275 @@
use crate::disk::block::{DirectoryBlock, DirectoryEntry};
use crate::disk::inode::Inode;
use crate::AyaFS;
+use indexmap::IndexMap;
use libc::{c_int, ENOENT, ENOSPC};
-use std::ffi::OsStr;
+use log::debug;
+use std::ffi::{OsStr, OsString};
use std::os::unix::ffi::OsStrExt;
impl AyaFS {
- /// 删除所有的 dir entry, 递归
- pub(crate) fn clear_direntry(&mut self, parent_inode: &mut Inode) -> Result<(), c_int> {
- todo!()
+ pub(crate) fn init_direntry_map(&mut self, index: usize) {
+ let direntry_map: IndexMap<OsString, DirectoryEntry> = IndexMap::new();
+ if let Some((old_inode_index, old_dir_entry_map)) =
+ self.dir_entry_map.push(index, direntry_map)
+ {
+ if let Some(old_inode) = self.get_inode(old_inode_index) {
+ let mut old_inode = old_inode.clone();
+ self.write_back_direntry(old_inode_index, &mut old_inode, old_dir_entry_map)
+ .unwrap();
+ self.update_inode(old_inode_index, old_inode);
+ }
+ }
+ }
+
+ pub(crate) fn load_direntry_map(&mut self, index: usize, inode: &Inode) -> Result<(), c_int> {
+ if self.dir_entry_map.contains(&index) {
+ debug!("load_direntry_map(ino: {}) already in cache", index);
+ return Ok(());
+ }
+
+ debug!("load_direntry_map(ino: {}) loading", index);
+ let mut dir_entry_map: IndexMap<OsString, DirectoryEntry> = IndexMap::new();
+ let mut entry_index: usize = 0;
+ loop {
+ let block_index_within_inode = entry_index / 15;
+ let entry_index_within_block = entry_index % 15;
+
+ match self.access_block::<DirectoryBlock>(inode, block_index_within_inode) {
+ Some(directory_block) => {
+ if directory_block.block.query(entry_index_within_block) {
+ let dir_entry = &directory_block.block.entries[entry_index_within_block];
+ let name = dir_entry.name();
+ dir_entry_map.insert(name, dir_entry.clone());
+ } else {
+ break;
+ }
+ }
+ None => break,
+ }
+ entry_index += 1;
+ }
+
+ if let Some((old_inode_index, old_dir_entry_map)) =
+ self.dir_entry_map.push(index, dir_entry_map)
+ {
+ if let Some(old_inode) = self.get_inode(old_inode_index) {
+ let mut old_inode = old_inode.clone();
+ self.write_back_direntry(old_inode_index, &mut old_inode, old_dir_entry_map)?;
+ self.update_inode(old_inode_index, old_inode);
+ }
+ }
+
+ Ok(())
+ }
+
+ pub(crate) fn write_back_direntry(
+ &mut self,
+ _parent_index: usize,
+ parent_inode: &mut Inode,
+ dir_entry_map: IndexMap<OsString, DirectoryEntry>,
+ ) -> Result<(), c_int> {
+ for (entry_index, (_, dir_entry)) in dir_entry_map.into_iter().enumerate() {
+ let block_index_within_inode = entry_index / 15;
+ let entry_index_within_block = entry_index % 15;
+ // 不够就新分配
+ if self
+ .get_block_index(parent_inode, block_index_within_inode)
+ .is_none()
+ {
+ match self.allocate_block_for(parent_inode) {
+ Some((_, block_index_within)) => {
+ assert_eq!(block_index_within, block_index_within_inode);
+ }
+ None => {
+ return Err(ENOSPC);
+ }
+ }
+ }
+ match self.access_block_mut::<DirectoryBlock>(parent_inode, block_index_within_inode) {
+ Some(directory_block) => {
+ directory_block.block.entries[entry_index_within_block] = dir_entry;
+ }
+ None => {
+ return Err(ENOENT);
+ }
+ }
+ }
+ Ok(())
}
/// 删除第 entry_index 个 dir entry
pub(crate) fn remove_direntry(
&mut self,
+ parent_index: usize,
parent_inode: &mut Inode,
+ name: &OsStr,
entry_index: u32,
) -> Result<(), c_int> {
- let block_index_within_inode = (entry_index / 15) as usize;
- let entry_index_within_block = (entry_index % 15) as usize;
-
- match self.access_block_mut::<DirectoryBlock>(parent_inode, block_index_within_inode) {
- Some(directory_block) => {
- if directory_block.block.query(entry_index_within_block) {
- directory_block.block.deallocate(entry_index_within_block);
- directory_block.block.entries[entry_index_within_block] =
- DirectoryEntry::default();
- Ok(())
- } else {
- Err(ENOENT)
- }
+ self.load_direntry_map(parent_index, parent_inode)?;
+ if let Some(dir_entry_map) = self.dir_entry_map.get_mut(&parent_index) {
+ debug!(" remove_direntry(ino: {}) using hashmap", parent_index);
+ if dir_entry_map.shift_remove(name).is_some() {
+ Ok(())
+ } else {
+ Err(ENOENT)
}
- None => Err(ENOENT),
+ } else {
+ Err(ENOENT)
+ // let block_index_within_inode = (entry_index / 15) as usize;
+ // let entry_index_within_block = (entry_index % 15) as usize;
+ //
+ // match self.access_block_mut::<DirectoryBlock>(parent_inode, block_index_within_inode) {
+ // Some(directory_block) => {
+ // if directory_block.block.query(entry_index_within_block) {
+ // directory_block.block.deallocate(entry_index_within_block);
+ // // directory_block.block.entries[entry_index_within_block] =
+ // // DirectoryEntry::default();
+ // Ok(())
+ // } else {
+ // Err(ENOENT)
+ // }
+ // }
+ // None => Err(ENOENT),
+ // }
}
}
- pub(crate) fn add_direntry(
+ pub(crate) fn add_direntry<T: AsRef<OsStr>>(
&mut self,
+ parent_index: usize,
parent_inode: &mut Inode,
child_inode_index: usize,
- child_inode_name: &OsStr,
- child_inode: &Inode,
+ child_inode_name: T,
+ file_type: u8,
) -> Result<u32, c_int> {
- // 找到第一个有空闲 DirEntry 的块, 从中分配一个 entry
- let mut block_index_within_inode: usize = 0;
- loop {
- // 所有已经分配的块都用完, 需要额外分配一个块了
- if block_index_within_inode as u32 == parent_inode.n_blocks {
- if self.allocate_block_for(parent_inode).is_none() {
- return Err(ENOSPC);
- }
- }
- // 寻找当前块里有没有空闲空间
- if let Some(directory_block) =
- self.access_block_mut::<DirectoryBlock>(parent_inode, block_index_within_inode)
- {
- if let Some(entry_index_within_block) = directory_block.block.allocate() {
- // 如果有空闲空间, 可以分配一个块
- let name_len = child_inode_name.len() as u8;
- let file_type = child_inode.mode.into();
- let mut name = [0u8; 256];
- name.copy_from_slice(child_inode_name.as_bytes());
+ let child_inode_name = child_inode_name.as_ref();
+ self.load_direntry_map(parent_index, parent_inode)?;
+ if let Some(dir_entry_map) = self.dir_entry_map.get_mut(&parent_index) {
+ let name_len = child_inode_name.len() as u8;
+ let mut name = [0u8; 256];
+ (&mut name[0..child_inode_name.len()]).copy_from_slice(child_inode_name.as_bytes());
- let dir_entry = DirectoryEntry {
- inode: child_inode_index as u32,
- record_len: 264,
- name_len,
- file_type,
- name,
- };
- directory_block.block.entries[entry_index_within_block] = dir_entry;
- let entry_index = block_index_within_inode * 15 + entry_index_within_block;
- return Ok(entry_index as u32);
- }
- }
- block_index_within_inode += 1;
+ let dir_entry = DirectoryEntry {
+ inode: child_inode_index as u32,
+ record_len: 264,
+ name_len,
+ file_type,
+ name,
+ };
+
+ let (entry_index, _) =
+ dir_entry_map.insert_full(child_inode_name.to_os_string(), dir_entry);
+ debug!(
+ " add_direntry(ino: {}) using hashmap, entry {}",
+ parent_index, entry_index
+ );
+ parent_inode.size += 1;
+ Ok(entry_index as u32)
+ } else {
+ Err(ENOENT)
}
+ // // 找到第一个有空闲 DirEntry 的块, 从中分配一个 entry
+ // let mut block_index_within_inode: usize = 0;
+ // loop {
+ // // 所有已经分配的块都用完, 需要额外分配一个块了
+ // if block_index_within_inode as u32 == parent_inode.n_blocks {
+ // if self.allocate_block_for(parent_inode).is_none() {
+ // return Err(ENOSPC);
+ // }
+ // }
+ // // 寻找当前块里有没有空闲空间
+ // if let Some(directory_block) =
+ // self.access_block_mut::<DirectoryBlock>(parent_inode, block_index_within_inode)
+ // {
+ // if let Some(entry_index_within_block) = directory_block.block.allocate() {
+ // // 如果有空闲空间, 可以分配一个块
+ // let name_len = child_inode_name.len() as u8;
+ // let mut name = [0u8; 256];
+ // (&mut name[0..name_len as usize])
+ // .copy_from_slice(child_inode_name.as_bytes());
+ //
+ // let dir_entry = DirectoryEntry {
+ // inode: child_inode_index as u32,
+ // record_len: 264,
+ // name_len,
+ // file_type,
+ // name,
+ // };
+ // directory_block.block.entries[entry_index_within_block] = dir_entry;
+ // let entry_index = block_index_within_inode * 15 + entry_index_within_block;
+ // parent_inode.size += 1;
+ // return Ok(entry_index as u32);
+ // }
+ // }
+ // block_index_within_inode += 1;
+ // }
}
pub(crate) fn get_direntry(
&mut self,
+ parent_index: usize,
parent_inode: &Inode,
entry_index: u32,
- ) -> Option<DirectoryEntry> {
- let block_index_within_inode = (entry_index / 15) as usize;
- let entry_index_within_block = (entry_index % 15) as usize;
-
- self.access_block::<DirectoryBlock>(parent_inode, block_index_within_inode)
- .and_then(|directory_block| {
- if directory_block.block.query(entry_index_within_block) {
- Some(directory_block.block.entries[entry_index_within_block].clone())
- } else {
- None
- }
- })
+ ) -> Result<DirectoryEntry, c_int> {
+ self.load_direntry_map(parent_index, parent_inode)?;
+ if let Some(dir_entry_map) = self.dir_entry_map.get(&parent_index) {
+ debug!(
+ " get_direntry(ino: {}, entry_index: {}) using hashmap",
+ parent_index, entry_index
+ );
+ dir_entry_map
+ .iter()
+ .skip(entry_index as usize)
+ .next()
+ .map(|entry| entry.1.clone())
+ .ok_or(ENOENT)
+ } else {
+ Err(ENOENT)
+ // let block_index_within_inode = (entry_index / 15) as usize;
+ // let entry_index_within_block = (entry_index % 15) as usize;
+ //
+ // match self.access_block::<DirectoryBlock>(parent_inode, block_index_within_inode) {
+ // Some(directory_block) => {
+ // if directory_block.block.query(entry_index_within_block) {
+ // Ok(directory_block.block.entries[entry_index_within_block].clone())
+ // } else {
+ // Err(ENOENT)
+ // }
+ // }
+ // None => Err(ENOENT),
+ // }
+ }
}
// TODO 实现一个带 cache 的版本
/// 返回 inode_index, inode 在 parent 里的 index, inode 本身
pub fn lookup_name(
&mut self,
+ parent_index: usize,
parent_inode: &Inode,
name: &OsStr,
) -> Result<(u32, u32, Inode), c_int> {
- let mut entry_index = 0;
- while entry_index < parent_inode.size {
- if let Some(entry) = self.get_direntry(parent_inode, entry_index) {
- if entry.name() == name {
- let inode = self.get_inode(entry.inode as usize).unwrap().clone();
- return Ok((entry.inode, entry_index, inode));
+ self.load_direntry_map(parent_index, parent_inode)?;
+ if let Some(dir_entry_map) = self.dir_entry_map.get(&parent_index) {
+ if let Some((entry_index, _, dir_entry)) = dir_entry_map.get_full(name) {
+ let inode_index = dir_entry.inode;
+ let inode = self.get_inode(inode_index as usize).unwrap().clone();
+ Ok((inode_index, entry_index as u32, inode))
+ } else {
+ Err(ENOENT)
+ }
+ } else {
+ let mut entry_index = 0;
+ while entry_index < parent_inode.size {
+ if let Ok(entry) = self.get_direntry(parent_index, parent_inode, entry_index) {
+ if entry.name() == name {
+ let inode = self.get_inode(entry.inode as usize).unwrap().clone();
+ return Ok((entry.inode, entry_index, inode));
+ }
}
+ entry_index += 1;
}
- entry_index += 1;
+ Err(ENOENT)
}
- Err(ENOENT)
}
}