use crate::disk::block::{DirectoryBlock, DirectoryEntry}; use crate::disk::inode::Inode; use crate::AyaFS; use libc::{c_int, ENOENT, ENOSPC}; use std::ffi::OsStr; 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!() } /// 删除第 entry_index 个 dir entry 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: usize, 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 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; } } 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 的版本 /// 返回 inode_index, inode 在 parent 里的 index, inode 本身 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) } }