20
20
use core:: mem:: MaybeUninit ;
21
21
22
22
use alloc:: boxed:: Box ;
23
+ use alloc:: string:: ToString ;
23
24
use alloc:: sync:: { Arc , Weak } ;
24
25
25
26
use crate :: fs:: cache:: CachedINode ;
@@ -197,10 +198,12 @@ impl DiskINode {
197
198
198
199
const_assert_eq ! ( core:: mem:: size_of:: <DiskINode >( ) , 128 ) ;
199
200
200
- struct INode {
201
+ pub struct INode {
201
202
id : usize ,
202
203
fs : Weak < Ext2 > ,
203
204
inode : Box < DiskINode > ,
205
+
206
+ sref : Weak < INode > ,
204
207
}
205
208
206
209
impl INode {
@@ -238,15 +241,31 @@ impl INode {
238
241
// SAFETY: We have initialized the inode above.
239
242
let inode = unsafe { inode. assume_init ( ) } ;
240
243
241
- log:: debug!( "ino_table_index={ino_table_index:?} inode={inode:?}" ) ;
244
+ Some (
245
+ icache. make_item_cached ( CachedINode :: new ( Arc :: new_cyclic ( |sref| Self {
246
+ inode,
247
+ id,
248
+ fs : ext2,
242
249
243
- Some ( icache. make_item_cached ( CachedINode :: new ( Arc :: new ( Self {
244
- inode,
245
- id,
246
- fs : ext2,
247
- } ) ) ) )
250
+ sref : sref. clone ( ) ,
251
+ } ) ) ) ,
252
+ )
248
253
}
249
254
}
255
+
256
+ pub fn sref ( & self ) -> Arc < INode > {
257
+ self . sref . upgrade ( ) . unwrap ( )
258
+ }
259
+
260
+ pub fn make_dir_entry (
261
+ & self ,
262
+ parent : DirCacheItem ,
263
+ name : & str ,
264
+ entry : & DiskDirEntry ,
265
+ ) -> Option < DirCacheItem > {
266
+ let inode = self . fs . upgrade ( ) ?. find_inode ( entry. inode as usize ) ?;
267
+ Some ( DirEntry :: new ( parent, inode, name. to_string ( ) ) )
268
+ }
250
269
}
251
270
252
271
impl INodeInterface for INode {
@@ -262,6 +281,72 @@ impl INodeInterface for INode {
262
281
children_len : 0 ,
263
282
} )
264
283
}
284
+
285
+ fn dirent ( & self , parent : DirCacheItem , index : usize ) -> super :: Result < Option < DirCacheItem > > {
286
+ Ok ( DirEntryIter :: new ( parent, self . sref ( ) ) . nth ( index) )
287
+ }
288
+ }
289
+
290
+ #[ derive( Debug , Copy , Clone ) ]
291
+ #[ repr( C , packed) ]
292
+ pub struct DiskDirEntry {
293
+ inode : u32 ,
294
+ entry_size : u16 ,
295
+ name_size : u8 ,
296
+ file_type : u8 ,
297
+ }
298
+
299
+ pub struct DirEntryIter {
300
+ parent : DirCacheItem ,
301
+ inode : Arc < INode > ,
302
+ offset : usize ,
303
+ }
304
+
305
+ impl DirEntryIter {
306
+ pub fn new ( parent : DirCacheItem , inode : Arc < INode > ) -> Self {
307
+ Self {
308
+ parent,
309
+ inode,
310
+
311
+ offset : 0 ,
312
+ }
313
+ }
314
+ }
315
+
316
+ impl Iterator for DirEntryIter {
317
+ type Item = DirCacheItem ;
318
+
319
+ fn next ( & mut self ) -> Option < Self :: Item > {
320
+ let filesystem = self . inode . fs . upgrade ( ) ?;
321
+ let file_size = self . inode . inode . size_lower as usize ;
322
+
323
+ if self . offset + core:: mem:: size_of :: < DiskDirEntry > ( ) > file_size {
324
+ return None ;
325
+ }
326
+
327
+ let mut entry = Box :: < DiskDirEntry > :: new_uninit ( ) ;
328
+
329
+ let offset = ( self . inode . inode . data_ptr [ 0 ] as usize * filesystem. superblock . block_size ( ) )
330
+ + self . offset ;
331
+
332
+ filesystem. block . device ( ) . read ( offset, entry. as_bytes_mut ( ) ) ;
333
+
334
+ // SAFETY: We have initialized the entry above.
335
+ let entry = unsafe { entry. assume_init ( ) } ;
336
+
337
+ let mut name = Box :: < [ u8 ] > :: new_uninit_slice ( entry. name_size as usize ) ;
338
+ filesystem. block . device ( ) . read (
339
+ offset + core:: mem:: size_of :: < DiskDirEntry > ( ) ,
340
+ MaybeUninit :: slice_as_bytes_mut ( & mut name) ,
341
+ ) ;
342
+
343
+ // SAFETY: We have initialized the name above.
344
+ let name = unsafe { name. assume_init ( ) } ;
345
+ let name = unsafe { core:: str:: from_utf8_unchecked ( & * name) } ;
346
+
347
+ self . offset += entry. entry_size as usize ;
348
+ self . inode . make_dir_entry ( self . parent . clone ( ) , name, & entry)
349
+ }
265
350
}
266
351
267
352
pub struct Ext2 {
0 commit comments