2020use core:: mem:: MaybeUninit ;
2121
2222use alloc:: boxed:: Box ;
23+ use alloc:: string:: ToString ;
2324use alloc:: sync:: { Arc , Weak } ;
2425
2526use crate :: fs:: cache:: CachedINode ;
@@ -197,10 +198,12 @@ impl DiskINode {
197198
198199const_assert_eq ! ( core:: mem:: size_of:: <DiskINode >( ) , 128 ) ;
199200
200- struct INode {
201+ pub struct INode {
201202 id : usize ,
202203 fs : Weak < Ext2 > ,
203204 inode : Box < DiskINode > ,
205+
206+ sref : Weak < INode > ,
204207}
205208
206209impl INode {
@@ -238,15 +241,31 @@ impl INode {
238241 // SAFETY: We have initialized the inode above.
239242 let inode = unsafe { inode. assume_init ( ) } ;
240243
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,
242249
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+ )
248253 }
249254 }
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+ }
250269}
251270
252271impl INodeInterface for INode {
@@ -262,6 +281,72 @@ impl INodeInterface for INode {
262281 children_len : 0 ,
263282 } )
264283 }
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+ }
265350}
266351
267352pub struct Ext2 {
0 commit comments