summaryrefslogtreecommitdiff
path: root/src/memory/dir_entry.rs
blob: 0ade23fb31e6d9ce66c8a8616008027189868659 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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)
    }
}