1use super::{
2 block_cache_sync_all, get_block_cache, BlockDevice, DirEntry, DiskInode, DiskInodeType,
3 EasyFileSystem, DIRENT_SZ,
4};
5use alloc::string::String;
6use alloc::sync::Arc;
7use alloc::vec::Vec;
8use spin::{Mutex, MutexGuard};
9pub struct Inode {
11 block_id: usize,
12 block_offset: usize,
13 fs: Arc<Mutex<EasyFileSystem>>,
14 block_device: Arc<dyn BlockDevice>,
15}
16
17impl Inode {
18 pub fn new(
20 block_id: u32,
21 block_offset: usize,
22 fs: Arc<Mutex<EasyFileSystem>>,
23 block_device: Arc<dyn BlockDevice>,
24 ) -> Self {
25 Self {
26 block_id: block_id as usize,
27 block_offset,
28 fs,
29 block_device,
30 }
31 }
32
33 fn read_disk_inode<V>(&self, f: impl FnOnce(&DiskInode) -> V) -> V {
35 get_block_cache(self.block_id, Arc::clone(&self.block_device))
36 .lock()
37 .read(self.block_offset, f)
38 }
39
40 fn modify_disk_inode<V>(&self, f: impl FnOnce(&mut DiskInode) -> V) -> V {
42 get_block_cache(self.block_id, Arc::clone(&self.block_device))
43 .lock()
44 .modify(self.block_offset, f)
45 }
46
47 fn find_inode_id(&self, name: &str, disk_inode: &DiskInode) -> Option<u32> {
49 assert!(disk_inode.is_dir());
51 let file_count = (disk_inode.size as usize) / DIRENT_SZ;
52 let mut dirent = DirEntry::empty();
53 for i in 0..file_count {
54 assert_eq!(
55 disk_inode.read_at(DIRENT_SZ * i, dirent.as_bytes_mut(), &self.block_device,),
56 DIRENT_SZ,
57 );
58 if dirent.name() == name {
59 return Some(dirent.inode_number());
60 }
61 }
62 None
63 }
64
65 pub fn find(&self, name: &str) -> Option<Arc<Inode>> {
67 let fs = self.fs.lock();
69 self.read_disk_inode(|disk_inode| {
70 self.find_inode_id(name, disk_inode).map(|inode_id| {
71 let (block_id, block_offset) = fs.get_disk_inode_pos(inode_id);
72 Arc::new(Self::new(
73 block_id,
74 block_offset,
75 self.fs.clone(),
76 self.block_device.clone(),
77 ))
78 })
79 })
80 }
81
82 fn increase_size(
84 &self,
85 new_size: u32,
86 disk_inode: &mut DiskInode,
87 fs: &mut MutexGuard<EasyFileSystem>,
88 ) {
89 if new_size < disk_inode.size {
90 return;
91 }
92 let blocks_needed = disk_inode.blocks_num_needed(new_size);
94 let mut v: Vec<u32> = Vec::new();
95 for _ in 0..blocks_needed {
96 v.push(fs.alloc_data());
97 }
98 disk_inode.increase_size(new_size, v, &self.block_device);
99 }
100
101 pub fn create(&self, name: &str) -> Option<Arc<Inode>> {
104 let mut fs = self.fs.lock();
105 let new_inode_id = fs.alloc_inode();
107 let (new_inode_block_id, new_inode_block_offset) = fs.get_disk_inode_pos(new_inode_id);
109 get_block_cache(new_inode_block_id as usize, Arc::clone(&self.block_device))
110 .lock()
111 .modify(new_inode_block_offset, |new_inode: &mut DiskInode| {
112 new_inode.initialize(DiskInodeType::File);
113 });
114 self.modify_disk_inode(|root_inode| {
116 let file_count = (root_inode.size as usize) / DIRENT_SZ;
118 let new_size = (file_count + 1) * DIRENT_SZ;
119 self.increase_size(new_size as u32, root_inode, &mut fs);
121 let dirent = DirEntry::new(name, new_inode_id);
123 root_inode.write_at(
124 file_count * DIRENT_SZ,
125 dirent.as_bytes(),
126 &self.block_device,
127 );
128 });
129
130 let (block_id, block_offset) = fs.get_disk_inode_pos(new_inode_id);
131 block_cache_sync_all();
132 Some(Arc::new(Self::new(
134 block_id,
135 block_offset,
136 self.fs.clone(),
137 self.block_device.clone(),
138 )))
139 }
141
142 pub fn readdir(&self) -> Vec<String> {
144 let _fs = self.fs.lock();
145 self.read_disk_inode(|disk_inode| {
146 let file_count = (disk_inode.size as usize) / DIRENT_SZ;
147 let mut v: Vec<String> = Vec::new();
148 for i in 0..file_count {
149 let mut dirent = DirEntry::empty();
150 assert_eq!(
151 disk_inode.read_at(i * DIRENT_SZ, dirent.as_bytes_mut(), &self.block_device,),
152 DIRENT_SZ,
153 );
154 v.push(String::from(dirent.name()));
155 }
156 v
157 })
158 }
159
160 pub fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize {
162 let _fs = self.fs.lock();
163 self.read_disk_inode(|disk_inode| disk_inode.read_at(offset, buf, &self.block_device))
164 }
165
166 pub fn write_at(&self, offset: usize, buf: &[u8]) -> usize {
168 let mut fs = self.fs.lock();
169 let size = self.modify_disk_inode(|disk_inode| {
170 self.increase_size((offset + buf.len()) as u32, disk_inode, &mut fs);
171 disk_inode.write_at(offset, buf, &self.block_device)
172 });
173 block_cache_sync_all();
174 size
175 }
176
177 pub fn clear(&self) {
179 let mut fs = self.fs.lock();
180 self.modify_disk_inode(|disk_inode| {
181 let size = disk_inode.size;
182 let data_blocks_dealloc = disk_inode.clear_size(&self.block_device);
183 assert!(data_blocks_dealloc.len() == DiskInode::total_blocks(size) as usize);
184 for data_block in data_blocks_dealloc.into_iter() {
185 fs.dealloc_data(data_block);
186 }
187 });
188 block_cache_sync_all();
189 }
190}