@@ -3,6 +3,16 @@ use crate::data_types::Align;
33use crate :: Result ;
44use core:: ffi:: c_void;
55
6+ #[ cfg( feature = "alloc" ) ]
7+ use {
8+ crate :: { ResultExt , Status } ,
9+ :: alloc:: boxed:: Box ,
10+ alloc:: alloc,
11+ core:: alloc:: Layout ,
12+ core:: ptr:: NonNull ,
13+ core:: slice,
14+ } ;
15+
616/// A `FileHandle` that is also a directory.
717///
818/// Use `File::into_type` or `Directory::new` to create a `Directory`. In
@@ -20,7 +30,7 @@ impl Directory {
2030 Self ( RegularFile :: new ( handle) )
2131 }
2232
23- /// Read the next directory entry
33+ /// Read the next directory entry.
2434 ///
2535 /// Try to read the next directory entry into `buffer`. If the buffer is too small, report the
2636 /// required buffer size as part of the error. If there are no more directory entries, return
@@ -56,6 +66,64 @@ impl Directory {
5666 } )
5767 }
5868
69+ /// Wrapper around [`Self::read_entry`] that returns an owned copy of the data. It has the same
70+ /// implications and requirements. On failure, the payload of `Err` is `()´.
71+ #[ cfg( feature = "alloc" ) ]
72+ pub fn read_entry_boxed ( & mut self ) -> Result < Option < Box < FileInfo > > > {
73+ let read_entry_res = self . read_entry ( & mut [ ] ) ;
74+
75+ // If no more entries are available, return early.
76+ if let Ok ( None ) = read_entry_res {
77+ return Ok ( None ) ;
78+ }
79+
80+ let required_size = match read_entry_res
81+ . expect_err ( "zero sized read unexpectedly succeeded" )
82+ . split ( )
83+ {
84+ // Early return if something has failed.
85+ ( s, None ) => return Err ( s. into ( ) ) ,
86+ ( _, Some ( required_size) ) => required_size,
87+ } ;
88+
89+ // We add trailing padding because the size of a rust structure must
90+ // always be a multiple of alignment.
91+ let layout = Layout :: from_size_align ( required_size, FileInfo :: alignment ( ) )
92+ . unwrap ( )
93+ . pad_to_align ( ) ;
94+
95+ // Allocate the buffer.
96+ let heap_buf: NonNull < u8 > = unsafe {
97+ let ptr = alloc:: alloc ( layout) ;
98+ match NonNull :: new ( ptr) {
99+ None => return Err ( Status :: OUT_OF_RESOURCES . into ( ) ) ,
100+ Some ( ptr) => ptr,
101+ }
102+ } ;
103+
104+ // Get the file info using the allocated buffer for storage.
105+ let info = {
106+ let buffer = unsafe { slice:: from_raw_parts_mut ( heap_buf. as_ptr ( ) , layout. size ( ) ) } ;
107+ self . read_entry ( buffer) . discard_errdata ( )
108+ } ;
109+
110+ // If an error occurred, deallocate the memory before returning.
111+ let info = match info {
112+ Ok ( info) => info,
113+ Err ( err) => {
114+ unsafe { alloc:: dealloc ( heap_buf. as_ptr ( ) , layout) } ;
115+ return Err ( err) ;
116+ }
117+ } ;
118+
119+ // Wrap the file info in a box so that it will be deallocated on
120+ // drop. This is valid because the memory was allocated with the
121+ // global allocator.
122+ let info = info. map ( |info| unsafe { Box :: from_raw ( info) } ) ;
123+
124+ Ok ( info)
125+ }
126+
59127 /// Start over the process of enumerating directory entries
60128 pub fn reset_entry_readout ( & mut self ) -> Result {
61129 self . 0 . set_position ( 0 )
0 commit comments