1
1
use crate :: { Dtor , EfiStr , Guid , Owned , Status , Time } ;
2
2
use alloc:: alloc:: { alloc, dealloc, handle_alloc_error} ;
3
- use alloc:: borrow :: ToOwned ;
3
+ use alloc:: boxed :: Box ;
4
4
use bitflags:: bitflags;
5
5
use core:: alloc:: Layout ;
6
- use core:: borrow:: { Borrow , BorrowMut } ;
7
6
use core:: fmt:: { Display , Formatter } ;
8
7
use core:: mem:: zeroed;
9
- use core:: ops:: { Deref , DerefMut } ;
10
- use core:: ptr:: { null_mut, read, slice_from_raw_parts, slice_from_raw_parts_mut} ;
8
+ use core:: ptr:: null_mut;
11
9
12
10
/// Represents an `EFI_SIMPLE_FILE_SYSTEM_PROTOCOL`.
13
11
#[ repr( C ) ]
@@ -141,23 +139,23 @@ impl File {
141
139
}
142
140
}
143
141
144
- pub fn info ( & self ) -> Result < FileInfoBuf , Status > {
142
+ pub fn info ( & self ) -> Result < Box < FileInfo > , Status > {
145
143
// Try until the buffer is enought.
146
- let mut layout = Layout :: from_size_align ( 0x52 , 8 ) . unwrap ( ) ;
147
- let info = loop {
144
+ let mut layout = FileInfo :: memory_layout ( 1 ) ;
145
+ let ( mut info, len ) = loop {
148
146
// Allocate a buffer.
149
- let mut len = layout. size ( ) ;
150
147
let info = unsafe { alloc ( layout) } ;
151
148
152
149
if info. is_null ( ) {
153
150
handle_alloc_error ( layout) ;
154
151
}
155
152
156
153
// Get info.
154
+ let mut len = layout. size ( ) ;
157
155
let status = unsafe { ( self . get_info ) ( self , & FileInfo :: ID , & mut len, info) } ;
158
156
159
157
if status == Status :: SUCCESS {
160
- break info;
158
+ break ( info, len ) ;
161
159
}
162
160
163
161
// Check if we need to try again.
@@ -168,13 +166,37 @@ impl File {
168
166
}
169
167
170
168
// Update memory layout and try again.
171
- layout = Layout :: from_size_align ( len, 8 ) . unwrap ( ) ;
169
+ layout = FileInfo :: memory_layout ( len. checked_sub ( 0x50 ) . unwrap ( ) / 2 ) ;
172
170
} ;
173
171
174
- Ok ( FileInfoBuf {
175
- buf : info,
176
- len : layout. size ( ) ,
177
- } )
172
+ // Check if layout matched.
173
+ let name = len. checked_sub ( 0x50 ) . unwrap ( ) / 2 ;
174
+ let new = FileInfo :: memory_layout ( name) ;
175
+
176
+ if new != layout {
177
+ // Allocate a new buffer to match with final layout.
178
+ let buf = unsafe { alloc ( new) } ;
179
+
180
+ if buf. is_null ( ) {
181
+ handle_alloc_error ( new)
182
+ }
183
+
184
+ // Copy data.
185
+ unsafe { buf. copy_from_nonoverlapping ( info, len) } ;
186
+ unsafe { dealloc ( info, layout) } ;
187
+
188
+ info = buf;
189
+ layout = new;
190
+ }
191
+
192
+ // Cast to FileInfo. Pointer casting here may looks weird but it is how DST works.
193
+ // See https://stackoverflow.com/a/64121094/1829232 for more details.
194
+ let info = core:: ptr:: slice_from_raw_parts_mut :: < u16 > ( info. cast ( ) , name) as * mut FileInfo ;
195
+ let info = unsafe { Box :: from_raw ( info) } ;
196
+
197
+ assert_eq ! ( size_of_val( info. as_ref( ) ) , layout. size( ) ) ;
198
+
199
+ Ok ( info)
178
200
}
179
201
180
202
pub fn set_len ( & mut self , len : u64 ) -> Result < ( ) , FileSetLenError > {
@@ -189,13 +211,15 @@ impl File {
189
211
}
190
212
191
213
// Update the info.
192
- * info. file_size_mut ( ) = len;
193
- * info. create_time_mut ( ) = unsafe { zeroed ( ) } ;
194
- * info. last_accessed_mut ( ) = unsafe { zeroed ( ) } ;
195
- * info. last_modified_mut ( ) = unsafe { zeroed ( ) } ;
214
+ info. set_file_size ( len) ;
215
+ info. set_create_time ( unsafe { zeroed ( ) } ) ;
216
+ info. set_last_accessed ( unsafe { zeroed ( ) } ) ;
217
+ info. set_last_modified ( unsafe { zeroed ( ) } ) ;
196
218
197
219
// Set the info.
198
- let status = unsafe { ( self . set_info ) ( self , & FileInfo :: ID , info. 0 . len ( ) , info. 0 . as_ptr ( ) ) } ;
220
+ let len = 0x50 + info. file_name . len ( ) * 2 ;
221
+ let info = info. as_ref ( ) as * const FileInfo as * const u8 ;
222
+ let status = unsafe { ( self . set_info ) ( self , & FileInfo :: ID , len, info) } ;
199
223
200
224
if status != Status :: SUCCESS {
201
225
Err ( FileSetLenError :: SetInfoFailed ( status) )
@@ -230,6 +254,7 @@ bitflags! {
230
254
bitflags ! {
231
255
/// Attributes of the file to create.
232
256
#[ repr( transparent) ]
257
+ #[ derive( Clone , Copy ) ]
233
258
pub struct FileAttributes : u64 {
234
259
const READ_ONLY = 0x0000000000000001 ;
235
260
const HIDDEN = 0x0000000000000002 ;
@@ -240,12 +265,18 @@ bitflags! {
240
265
}
241
266
}
242
267
243
- /// A borrowed `EFI_FILE_INFO`.
244
- ///
245
- /// Do not depend on a transparent representation as a slice because it will be removed in the
246
- /// future when a Dynamically Sized Type can be safely construct on stable Rust.
247
- #[ repr( transparent) ]
248
- pub struct FileInfo ( [ u8 ] ) ;
268
+ /// Represents an `EFI_FILE_INFO`.
269
+ #[ repr( C ) ]
270
+ pub struct FileInfo {
271
+ size : u64 ,
272
+ file_size : u64 ,
273
+ physical_size : u64 ,
274
+ create_time : Time ,
275
+ last_access_time : Time ,
276
+ modification_time : Time ,
277
+ attribute : FileAttributes ,
278
+ file_name : [ u16 ] ,
279
+ }
249
280
250
281
impl FileInfo {
251
282
pub const ID : Guid = Guid :: new (
@@ -255,112 +286,80 @@ impl FileInfo {
255
286
[ 0x8e , 0x39 , 0x00 , 0xa0 , 0xc9 , 0x69 , 0x72 , 0x3b ] ,
256
287
) ;
257
288
258
- pub fn as_bytes ( & self ) -> & [ u8 ] {
259
- & self . 0
289
+ pub fn file_size ( & self ) -> u64 {
290
+ self . file_size
260
291
}
261
292
262
- pub fn file_size ( & self ) -> u64 {
263
- unsafe { read ( self . 0 . as_ptr ( ) . add ( 0x08 ) as _ ) }
293
+ pub fn set_file_size ( & mut self , v : u64 ) {
294
+ self . file_size = v ;
264
295
}
265
296
266
297
pub fn file_size_mut ( & mut self ) -> & mut u64 {
267
- unsafe { & mut * ( self . 0 . as_mut_ptr ( ) . add ( 0x08 ) as * mut u64 ) }
298
+ & mut self . file_size
268
299
}
269
300
270
301
pub fn physical_size ( & self ) -> u64 {
271
- unsafe { read ( self . 0 . as_ptr ( ) . add ( 0x10 ) as _ ) }
302
+ self . physical_size
272
303
}
273
304
274
305
pub fn create_time ( & self ) -> & Time {
275
- unsafe { & * ( self . 0 . as_ptr ( ) . add ( 0x18 ) as * const Time ) }
276
- }
277
-
278
- pub fn create_time_mut ( & mut self ) -> & mut Time {
279
- unsafe { & mut * ( self . 0 . as_mut_ptr ( ) . add ( 0x18 ) as * mut Time ) }
306
+ & self . create_time
280
307
}
281
308
282
- pub fn last_accessed ( & self ) -> & Time {
283
- unsafe { & * ( self . 0 . as_ptr ( ) . add ( 0x28 ) as * const Time ) }
309
+ pub fn set_create_time ( & mut self , v : Time ) {
310
+ self . create_time = v ;
284
311
}
285
312
286
- pub fn last_accessed_mut ( & mut self ) -> & mut Time {
287
- unsafe { & mut * ( self . 0 . as_mut_ptr ( ) . add ( 0x28 ) as * mut Time ) }
313
+ pub fn create_time_mut ( & mut self ) -> & mut Time {
314
+ & mut self . create_time
288
315
}
289
316
290
- pub fn last_modified ( & self ) -> & Time {
291
- unsafe { & * ( self . 0 . as_ptr ( ) . add ( 0x38 ) as * const Time ) }
317
+ pub fn last_accessed ( & self ) -> & Time {
318
+ & self . last_access_time
292
319
}
293
320
294
- pub fn last_modified_mut ( & mut self ) -> & mut Time {
295
- unsafe { & mut * ( self . 0 . as_mut_ptr ( ) . add ( 0x38 ) as * mut Time ) }
321
+ pub fn set_last_accessed ( & mut self , v : Time ) {
322
+ self . last_access_time = v ;
296
323
}
297
324
298
- pub fn attributes ( & self ) -> FileAttributes {
299
- unsafe { read ( self . 0 . as_ptr ( ) . add ( 0x48 ) as _ ) }
325
+ pub fn last_accessed_mut ( & mut self ) -> & mut Time {
326
+ & mut self . last_access_time
300
327
}
301
328
302
- pub fn attributes_mut ( & mut self ) -> & mut FileAttributes {
303
- unsafe { & mut * ( self . 0 . as_mut_ptr ( ) . add ( 0x48 ) as * mut FileAttributes ) }
329
+ pub fn last_modified ( & self ) -> & Time {
330
+ & self . modification_time
304
331
}
305
332
306
- pub fn file_name ( & self ) -> & EfiStr {
307
- unsafe { EfiStr :: from_ptr ( self . 0 . as_ptr ( ) . add ( 0x50 ) as _ ) }
333
+ pub fn set_last_modified ( & mut self , v : Time ) {
334
+ self . modification_time = v ;
308
335
}
309
- }
310
-
311
- impl ToOwned for FileInfo {
312
- type Owned = FileInfoBuf ;
313
-
314
- fn to_owned ( & self ) -> Self :: Owned {
315
- let len = self . 0 . len ( ) ;
316
- let layout = Layout :: from_size_align ( len, 8 ) . unwrap ( ) ;
317
- let buf = unsafe { alloc ( layout) } ;
318
-
319
- if buf. is_null ( ) {
320
- handle_alloc_error ( layout) ;
321
- }
322
-
323
- unsafe { buf. copy_from_nonoverlapping ( self . 0 . as_ptr ( ) , len) } ;
324
336
325
- FileInfoBuf { buf, len }
337
+ pub fn last_modified_mut ( & mut self ) -> & mut Time {
338
+ & mut self . modification_time
326
339
}
327
- }
328
-
329
- /// An owned version of [`FileInfo`].
330
- pub struct FileInfoBuf {
331
- buf : * mut u8 , // Must be 8 bytes aligment.
332
- len : usize ,
333
- }
334
340
335
- impl Drop for FileInfoBuf {
336
- fn drop ( & mut self ) {
337
- unsafe { dealloc ( self . buf , Layout :: from_size_align ( self . len , 8 ) . unwrap ( ) ) } ;
341
+ pub fn attributes ( & self ) -> FileAttributes {
342
+ self . attribute
338
343
}
339
- }
340
344
341
- impl Deref for FileInfoBuf {
342
- type Target = FileInfo ;
343
-
344
- fn deref ( & self ) -> & Self :: Target {
345
- self . borrow ( )
345
+ pub fn set_attributes ( & mut self , v : FileAttributes ) {
346
+ self . attribute = v;
346
347
}
347
- }
348
348
349
- impl DerefMut for FileInfoBuf {
350
- fn deref_mut ( & mut self ) -> & mut Self :: Target {
351
- self . borrow_mut ( )
349
+ pub fn attributes_mut ( & mut self ) -> & mut FileAttributes {
350
+ & mut self . attribute
352
351
}
353
- }
354
352
355
- impl Borrow < FileInfo > for FileInfoBuf {
356
- fn borrow ( & self ) -> & FileInfo {
357
- unsafe { & * ( slice_from_raw_parts ( self . buf , self . len ) as * const FileInfo ) }
353
+ pub fn file_name ( & self ) -> & EfiStr {
354
+ // SAFETY: UEFI specs guarantee null-terminated.
355
+ unsafe { EfiStr :: new_unchecked ( & self . file_name ) }
358
356
}
359
- }
360
357
361
- impl BorrowMut < FileInfo > for FileInfoBuf {
362
- fn borrow_mut ( & mut self ) -> & mut FileInfo {
363
- unsafe { & mut * ( slice_from_raw_parts_mut ( self . buf , self . len ) as * mut FileInfo ) }
358
+ pub fn memory_layout ( name : usize ) -> Layout {
359
+ Layout :: from_size_align ( 0x50 , 8 )
360
+ . and_then ( move |b| b. extend ( Layout :: array :: < u16 > ( name) . unwrap ( ) ) )
361
+ . map ( |v| v. 0 . pad_to_align ( ) )
362
+ . unwrap ( )
364
363
}
365
364
}
366
365
0 commit comments