@@ -286,8 +286,13 @@ pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
286
286
unsupported ( )
287
287
}
288
288
289
- pub fn exists ( _path : & Path ) -> io:: Result < bool > {
290
- unsupported ( )
289
+ pub fn exists ( path : & Path ) -> io:: Result < bool > {
290
+ let f = uefi_fs:: File :: from_path ( path, r_efi:: protocols:: file:: MODE_READ , 0 ) ;
291
+ match f {
292
+ Ok ( _) => Ok ( true ) ,
293
+ Err ( e) if e. kind ( ) == io:: ErrorKind :: NotFound => Ok ( false ) ,
294
+ Err ( e) => Err ( e) ,
295
+ }
291
296
}
292
297
293
298
pub fn readlink ( _p : & Path ) -> io:: Result < PathBuf > {
@@ -317,3 +322,122 @@ pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
317
322
pub fn copy ( _from : & Path , _to : & Path ) -> io:: Result < u64 > {
318
323
unsupported ( )
319
324
}
325
+
326
+ mod uefi_fs {
327
+ use r_efi:: protocols:: { device_path, file, simple_file_system} ;
328
+
329
+ use crate :: boxed:: Box ;
330
+ use crate :: io;
331
+ use crate :: mem:: MaybeUninit ;
332
+ use crate :: path:: Path ;
333
+ use crate :: ptr:: NonNull ;
334
+ use crate :: sys:: helpers;
335
+
336
+ pub ( crate ) struct File ( NonNull < file:: Protocol > ) ;
337
+
338
+ impl File {
339
+ pub ( crate ) fn from_path ( path : & Path , open_mode : u64 , attr : u64 ) -> io:: Result < Self > {
340
+ let absoulte = crate :: path:: absolute ( path) ?;
341
+
342
+ let p = helpers:: OwnedDevicePath :: from_text ( absoulte. as_os_str ( ) ) ?;
343
+ let ( vol, mut path_remaining) = Self :: open_volume_from_device_path ( p. borrow ( ) ) ?;
344
+
345
+ vol. open ( & mut path_remaining, open_mode, attr)
346
+ }
347
+
348
+ fn open_volume_from_device_path (
349
+ path : helpers:: BorrowedDevicePath < ' _ > ,
350
+ ) -> io:: Result < ( Self , Box < [ u16 ] > ) > {
351
+ let handles = match helpers:: locate_handles ( simple_file_system:: PROTOCOL_GUID ) {
352
+ Ok ( x) => x,
353
+ Err ( e) => return Err ( e) ,
354
+ } ;
355
+ for handle in handles {
356
+ let volume_device_path: NonNull < device_path:: Protocol > =
357
+ match helpers:: open_protocol ( handle, device_path:: PROTOCOL_GUID ) {
358
+ Ok ( x) => x,
359
+ Err ( _) => continue ,
360
+ } ;
361
+ let volume_device_path = helpers:: BorrowedDevicePath :: new ( volume_device_path) ;
362
+
363
+ if let Some ( left_path) = path_best_match ( & volume_device_path, & path) {
364
+ return Ok ( ( Self :: open_volume ( handle) ?, left_path) ) ;
365
+ }
366
+ }
367
+
368
+ Err ( io:: const_error!( io:: ErrorKind :: NotFound , "Volume Not Found" ) )
369
+ }
370
+
371
+ // Open volume on device_handle using SIMPLE_FILE_SYSTEM_PROTOCOL
372
+ fn open_volume ( device_handle : NonNull < crate :: ffi:: c_void > ) -> io:: Result < Self > {
373
+ let simple_file_system_protocol = helpers:: open_protocol :: < simple_file_system:: Protocol > (
374
+ device_handle,
375
+ simple_file_system:: PROTOCOL_GUID ,
376
+ ) ?;
377
+
378
+ let mut file_protocol: MaybeUninit < * mut file:: Protocol > = MaybeUninit :: uninit ( ) ;
379
+ let r = unsafe {
380
+ ( ( * simple_file_system_protocol. as_ptr ( ) ) . open_volume ) (
381
+ simple_file_system_protocol. as_ptr ( ) ,
382
+ file_protocol. as_mut_ptr ( ) ,
383
+ )
384
+ } ;
385
+ if r. is_error ( ) {
386
+ return Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) ;
387
+ }
388
+
389
+ // Since no error was returned, file protocol should be non-NULL.
390
+ let p = NonNull :: new ( unsafe { file_protocol. assume_init ( ) } ) . unwrap ( ) ;
391
+ Ok ( Self ( p) )
392
+ }
393
+
394
+ fn open ( & self , path : & mut [ u16 ] , open_mode : u64 , attr : u64 ) -> io:: Result < Self > {
395
+ let file_ptr = self . 0 . as_ptr ( ) ;
396
+ let mut file_opened: MaybeUninit < * mut file:: Protocol > = MaybeUninit :: uninit ( ) ;
397
+
398
+ let r = unsafe {
399
+ ( ( * file_ptr) . open ) (
400
+ file_ptr,
401
+ file_opened. as_mut_ptr ( ) ,
402
+ path. as_mut_ptr ( ) ,
403
+ open_mode,
404
+ attr,
405
+ )
406
+ } ;
407
+
408
+ if r. is_error ( ) {
409
+ return Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) ;
410
+ }
411
+
412
+ // Since no error was returned, file protocol should be non-NULL.
413
+ let p = NonNull :: new ( unsafe { file_opened. assume_init ( ) } ) . unwrap ( ) ;
414
+ Ok ( File ( p) )
415
+ }
416
+ }
417
+
418
+ impl Drop for File {
419
+ fn drop ( & mut self ) {
420
+ let file_ptr = self . 0 . as_ptr ( ) ;
421
+ let _ = unsafe { ( ( * self . 0 . as_ptr ( ) ) . close ) ( file_ptr) } ;
422
+ }
423
+ }
424
+
425
+ fn path_best_match < ' a > (
426
+ source : & helpers:: BorrowedDevicePath < ' a > ,
427
+ target : & helpers:: BorrowedDevicePath < ' a > ,
428
+ ) -> Option < Box < [ u16 ] > > {
429
+ let mut source_iter = source. iter ( ) . take_while ( |x| !x. is_end_instance ( ) ) ;
430
+ let mut target_iter = target. iter ( ) . take_while ( |x| !x. is_end_instance ( ) ) ;
431
+
432
+ loop {
433
+ match ( source_iter. next ( ) , target_iter. next ( ) ) {
434
+ ( Some ( x) , Some ( y) ) if x == y => continue ,
435
+ ( None , Some ( y) ) => {
436
+ let p = y. to_path ( ) . to_text ( ) . ok ( ) ?;
437
+ return helpers:: os_string_to_raw ( & p) ;
438
+ }
439
+ _ => return None ,
440
+ }
441
+ }
442
+ }
443
+ }
0 commit comments