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