From 777d5e01a34b8ebe6f1a5751b593266f93e88499 Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Sat, 25 Nov 2023 19:36:31 -0800 Subject: Add dir entry operations --- src/memory/dir_entry.rs | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/memory/dir_entry.rs (limited to 'src/memory/dir_entry.rs') diff --git a/src/memory/dir_entry.rs b/src/memory/dir_entry.rs new file mode 100644 index 0000000..0ade23f --- /dev/null +++ b/src/memory/dir_entry.rs @@ -0,0 +1,103 @@ +use std::ffi::OsStr; +use std::os::unix::ffi::OsStrExt; +use libc::{c_int, ENOENT, ENOSPC}; +use crate::disk::block::{DirectoryBlock, DirectoryEntry}; +use crate::disk::inode::{Inode}; +use crate::AyaFS; + +impl AyaFS { + pub(crate) fn remove_direntry( + &mut self, + parent_inode: &mut Inode, + 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::(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( + &mut self, + parent_inode: &mut Inode, + child_inode_index: u32, + child_inode_name: &OsStr, + child_inode: &Inode, + ) -> Result { + // 找到第一个有空闲 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::(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 dir_entry = DirectoryEntry { + inode: child_inode_index, + 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; + }; + } + pub(crate) fn get_direntry( + &mut self, + parent_inode: &Inode, + entry_index: u32 + ) -> Option { + let block_index_within_inode = (entry_index / 15) as usize; + let entry_index_within_block = (entry_index % 15) as usize; + + self.access_block::(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 + } + }) + } + + // TODO 实现一个带 cache 的版本 + pub fn lookup_name(&mut self, 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)) + } + } + entry_index += 1; + } + Err(ENOENT) + } +} -- cgit v1.2.3-70-g09d2