@@ -3,6 +3,16 @@ use crate::data_types::Align;
3
3
use crate :: Result ;
4
4
use core:: ffi:: c_void;
5
5
6
+ #[ cfg( feature = "exts" ) ]
7
+ use {
8
+ crate :: { ResultExt , Status } ,
9
+ alloc_api:: alloc,
10
+ alloc_api:: boxed:: Box ,
11
+ core:: alloc:: Layout ,
12
+ core:: ptr:: NonNull ,
13
+ core:: slice,
14
+ } ;
15
+
6
16
/// A `FileHandle` that is also a directory.
7
17
///
8
18
/// Use `File::into_type` or `Directory::new` to create a `Directory`. In
@@ -20,7 +30,7 @@ impl Directory {
20
30
Self ( RegularFile :: new ( handle) )
21
31
}
22
32
23
- /// Read the next directory entry
33
+ /// Read the next directory entry.
24
34
///
25
35
/// Try to read the next directory entry into `buffer`. If the buffer is too small, report the
26
36
/// required buffer size as part of the error. If there are no more directory entries, return
@@ -56,6 +66,64 @@ impl Directory {
56
66
} )
57
67
}
58
68
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 = "exts" ) ]
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
+
59
127
/// Start over the process of enumerating directory entries
60
128
pub fn reset_entry_readout ( & mut self ) -> Result {
61
129
self . 0 . set_position ( 0 )
0 commit comments