summaryrefslogtreecommitdiff
path: root/src/memory/dir_entry.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/memory/dir_entry.rs')
-rw-r--r--src/memory/dir_entry.rs103
1 files changed, 103 insertions, 0 deletions
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::<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(
+ &mut self,
+ parent_inode: &mut Inode,
+ child_inode_index: u32,
+ child_inode_name: &OsStr,
+ child_inode: &Inode,
+ ) -> 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 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<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
+ }
+ })
+ }
+
+ // 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)
+ }
+}