@@ -70,28 +70,75 @@ impl Inode {
7070 None
7171 }
7272
73- /// Find inode under current inode by name (1 level only)
74- pub fn find ( & self , name : & str ) -> Option < Arc < Inode > > {
75- let fs = self . fs . lock ( ) ;
73+ /// Find direntry under a disk inode by pred
74+ fn get_dirent (
75+ & self ,
76+ disk_inode : & DiskInode ,
77+ pred : impl Fn ( & DirEntry ) -> bool ,
78+ ) -> Option < DirEntry > {
79+ assert ! ( disk_inode. is_dir( ) ) ;
80+ let file_count = ( disk_inode. size as usize ) / DIRENT_SZ ;
81+ let mut dirent = DirEntry :: new_empty ( ) ;
82+ for i in 0 ..file_count {
83+ assert_eq ! (
84+ disk_inode. read_at( i * DIRENT_SZ , dirent. as_bytes_mut( ) , & self . block_device) ,
85+ DIRENT_SZ
86+ ) ;
87+ if pred ( & dirent) {
88+ return Some ( dirent) ;
89+ }
90+ }
91+ None
92+ }
93+
94+ /// Read child direnty by inode_id
95+ pub fn read_dirent < V > ( & self , inode_id : u32 , f : impl FnOnce ( DirEntry ) -> V ) -> Option < V > {
7696 self . read_disk_inode ( |disk_inode| {
77- self . find_inode_id ( name, disk_inode) . map ( |inode_id| {
78- let ( block_id, block_offset) = fs. get_disk_inode_pos ( inode_id) ;
79- Arc :: new ( Inode :: new (
80- inode_id,
81- block_id,
82- block_offset,
83- self . fs . clone ( ) ,
84- self . block_device . clone ( ) ,
85- ) )
86- } )
97+ self . get_dirent ( disk_inode, |d| d. inode_number ( ) == inode_id)
8798 } )
99+ . map ( f)
100+ }
101+
102+ /// Find inode under current inode(recursively) by name
103+ pub fn find ( & self , path : & str ) -> Option < Arc < Inode > > {
104+ let fs = self . fs . lock ( ) ;
105+ let mut inode_id = self . inode_id ;
106+ let mut block_id = self . block_id as u32 ;
107+ let mut block_offset = self . block_offset ;
108+
109+ for name in path. split ( '/' ) . filter ( |s| !s. is_empty ( ) ) {
110+ let opt_inode_id = get_block_cache ( block_id as usize , self . block_device . clone ( ) )
111+ . lock ( )
112+ . read ( block_offset, |disk_inode : & DiskInode | {
113+ if disk_inode. is_file ( ) {
114+ return None ;
115+ }
116+ self . find_inode_id ( name, disk_inode)
117+ } ) ;
118+ match opt_inode_id {
119+ Some ( v) => {
120+ inode_id = v;
121+ ( block_id, block_offset) = fs. get_disk_inode_pos ( v) ;
122+ }
123+ _ => return None ,
124+ }
125+ }
126+ Some ( Arc :: new ( Self :: new (
127+ inode_id,
128+ block_id,
129+ block_offset,
130+ self . fs . clone ( ) ,
131+ self . block_device . clone ( ) ,
132+ ) ) )
88133 }
89134
90135 /// List inodes under current inode
91136 pub fn ls ( & self ) -> Vec < String > {
92137 let _fs = self . fs . lock ( ) ;
93138 self . read_disk_inode ( |disk_inode| {
94- assert ! ( disk_inode. is_dir( ) ) ;
139+ if disk_inode. is_file ( ) {
140+ return Vec :: new ( ) ;
141+ }
95142 let file_count = ( disk_inode. size as usize ) / DIRENT_SZ ;
96143 let mut v = Vec :: with_capacity ( file_count) ;
97144 let mut dirent = DirEntry :: new_empty ( ) ;
@@ -126,7 +173,7 @@ impl Inode {
126173 }
127174
128175 /// Create inode under current inode by name
129- pub fn create ( & self , name : & str ) -> Option < Arc < Inode > > {
176+ fn create_inode ( & self , name : & str , inode_type : DiskInodeType ) -> Option < Arc < Inode > > {
130177 let mut fs = self . fs . lock ( ) ;
131178 let op = |root_inode : & DiskInode | {
132179 assert ! ( root_inode. is_dir( ) ) ;
@@ -145,9 +192,9 @@ impl Inode {
145192 get_block_cache ( new_inode_block_id as usize , self . block_device . clone ( ) )
146193 . lock ( )
147194 . modify ( new_inode_block_offset, |new_inode : & mut DiskInode | {
148- new_inode. initialize ( DiskInodeType :: File )
195+ new_inode. initialize ( inode_type )
149196 } ) ;
150- // 3. modify current inode(root inode) : add one more dirent
197+ // 3. modify current inode: add one more dirent
151198 self . modify_disk_inode ( |root_inode| {
152199 // append file in dirent
153200 let file_count = ( root_inode. size as usize ) / DIRENT_SZ ;
@@ -162,22 +209,45 @@ impl Inode {
162209 & self . block_device ,
163210 ) ;
164211 } ) ;
165- // 4. return inode
166- block_cache_sync_all ( ) ;
167- Some ( Arc :: new ( Self :: new (
212+ let inode = Self :: new (
168213 new_inode_id,
169214 new_inode_block_id,
170215 new_inode_block_offset,
171216 self . fs . clone ( ) ,
172217 self . block_device . clone ( ) ,
173- ) ) )
218+ ) ;
219+ if inode_type == DiskInodeType :: Directory {
220+ let curr_inode_id = self . inode_id ;
221+ inode. modify_disk_inode ( |curr_inode| {
222+ curr_inode. initialize_dir (
223+ new_inode_id,
224+ curr_inode_id,
225+ || fs. alloc_data ( ) ,
226+ & self . block_device ,
227+ ) ;
228+ } ) ;
229+ }
230+ // 4. return inode
231+ block_cache_sync_all ( ) ;
232+ Some ( Arc :: new ( inode) )
174233 // release efs lock
175234 }
176235
236+ /// Create regular file under current inode
237+ pub fn create ( & self , name : & str ) -> Option < Arc < Inode > > {
238+ self . create_inode ( name, DiskInodeType :: File )
239+ }
240+
241+ /// Create directory under current inode
242+ pub fn create_dir ( & self , name : & str ) -> Option < Arc < Inode > > {
243+ self . create_inode ( name, DiskInodeType :: Directory )
244+ }
245+
177246 /// Clear the data in current inode
178247 pub fn clear ( & self ) {
179248 let mut fs = self . fs . lock ( ) ;
180249 self . modify_disk_inode ( |disk_inode| {
250+ assert ! ( disk_inode. is_file( ) ) ;
181251 let size = disk_inode. size ;
182252 let data_blocks_dealloc = disk_inode. clear_size ( & self . block_device ) ;
183253 assert_eq ! (
@@ -200,6 +270,7 @@ impl Inode {
200270 pub fn write_at ( & self , offset : usize , buf : & [ u8 ] ) -> usize {
201271 let mut fs = self . fs . lock ( ) ;
202272 self . modify_disk_inode ( |disk_inode| {
273+ assert ! ( disk_inode. is_file( ) ) ;
203274 // extend first
204275 self . increase_size ( ( offset + buf. len ( ) ) as u32 , disk_inode, & mut fs) ;
205276 disk_inode. write_at ( offset, buf, & self . block_device )
@@ -215,4 +286,14 @@ impl Inode {
215286 pub fn get_size ( & self ) -> usize {
216287 self . read_disk_inode ( |disk_inode| disk_inode. size as usize )
217288 }
289+
290+ /// Is dir?
291+ pub fn is_dir ( & self ) -> bool {
292+ self . read_disk_inode ( |disk_inode| disk_inode. is_dir ( ) )
293+ }
294+
295+ /// Is file?
296+ pub fn is_file ( & self ) -> bool {
297+ self . read_disk_inode ( |disk_inode| disk_inode. is_file ( ) )
298+ }
218299}
0 commit comments