@@ -286,8 +286,13 @@ pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
286286    unsupported ( ) 
287287} 
288288
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+     } 
291296} 
292297
293298pub  fn  readlink ( _p :  & Path )  -> io:: Result < PathBuf >  { 
@@ -317,3 +322,134 @@ pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
317322pub  fn  copy ( _from :  & Path ,  _to :  & Path )  -> io:: Result < u64 >  { 
318323    unsupported ( ) 
319324} 
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 :: path:: Path ; 
332+     use  crate :: ptr:: NonNull ; 
333+     use  crate :: sys:: helpers; 
334+ 
335+     pub ( crate )  struct  File ( NonNull < file:: Protocol > ) ; 
336+ 
337+     impl  File  { 
338+         pub ( crate )  fn  from_path ( path :  & Path ,  open_mode :  u64 ,  attr :  u64 )  -> io:: Result < Self >  { 
339+             let  absolute = crate :: path:: absolute ( path) ?; 
340+ 
341+             let  p = helpers:: OwnedDevicePath :: from_text ( absolute. as_os_str ( ) ) ?; 
342+             let  ( vol,  mut  path_remaining)  = Self :: open_volume_from_device_path ( p. borrow ( ) ) ?; 
343+ 
344+             vol. open ( & mut  path_remaining,  open_mode,  attr) 
345+         } 
346+ 
347+         /// Open Filesystem volume given a devicepath to the volume, or a file/directory in the 
348+          /// volume. The path provided should be absolute UEFI device path, without any UEFI shell 
349+          /// mappings. 
350+          /// 
351+          /// Returns 
352+          /// 1. The volume as a UEFI File 
353+          /// 2. Path relative to the volume. 
354+          /// 
355+          /// For example, given "PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Slave,0x0)/\abc\run.efi", 
356+          /// this will open the volume "PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Slave,0x0)" 
357+          /// and return the remaining file path "\abc\run.efi". 
358+          fn  open_volume_from_device_path ( 
359+             path :  helpers:: BorrowedDevicePath < ' _ > , 
360+         )  -> io:: Result < ( Self ,  Box < [ u16 ] > ) >  { 
361+             let  handles = match  helpers:: locate_handles ( simple_file_system:: PROTOCOL_GUID )  { 
362+                 Ok ( x)  => x, 
363+                 Err ( e)  => return  Err ( e) , 
364+             } ; 
365+             for  handle in  handles { 
366+                 let  volume_device_path:  NonNull < device_path:: Protocol >  =
367+                     match  helpers:: open_protocol ( handle,  device_path:: PROTOCOL_GUID )  { 
368+                         Ok ( x)  => x, 
369+                         Err ( _)  => continue , 
370+                     } ; 
371+                 let  volume_device_path = helpers:: BorrowedDevicePath :: new ( volume_device_path) ; 
372+ 
373+                 if  let  Some ( left_path)  = path_best_match ( & volume_device_path,  & path)  { 
374+                     return  Ok ( ( Self :: open_volume ( handle) ?,  left_path) ) ; 
375+                 } 
376+             } 
377+ 
378+             Err ( io:: const_error!( io:: ErrorKind :: NotFound ,  "Volume Not Found" ) ) 
379+         } 
380+ 
381+         // Open volume on device_handle using SIMPLE_FILE_SYSTEM_PROTOCOL 
382+         fn  open_volume ( device_handle :  NonNull < crate :: ffi:: c_void > )  -> io:: Result < Self >  { 
383+             let  simple_file_system_protocol = helpers:: open_protocol :: < simple_file_system:: Protocol > ( 
384+                 device_handle, 
385+                 simple_file_system:: PROTOCOL_GUID , 
386+             ) ?; 
387+ 
388+             let  mut  file_protocol = crate :: ptr:: null_mut ( ) ; 
389+             let  r = unsafe  { 
390+                 ( ( * simple_file_system_protocol. as_ptr ( ) ) . open_volume ) ( 
391+                     simple_file_system_protocol. as_ptr ( ) , 
392+                     & mut  file_protocol, 
393+                 ) 
394+             } ; 
395+             if  r. is_error ( )  { 
396+                 return  Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) ; 
397+             } 
398+ 
399+             // Since no error was returned, file protocol should be non-NULL. 
400+             let  p = NonNull :: new ( file_protocol) . unwrap ( ) ; 
401+             Ok ( Self ( p) ) 
402+         } 
403+ 
404+         fn  open ( & self ,  path :  & mut  [ u16 ] ,  open_mode :  u64 ,  attr :  u64 )  -> io:: Result < Self >  { 
405+             let  file_ptr = self . 0 . as_ptr ( ) ; 
406+             let  mut  file_opened = crate :: ptr:: null_mut ( ) ; 
407+ 
408+             let  r = unsafe  { 
409+                 ( ( * file_ptr) . open ) ( file_ptr,  & mut  file_opened,  path. as_mut_ptr ( ) ,  open_mode,  attr) 
410+             } ; 
411+ 
412+             if  r. is_error ( )  { 
413+                 return  Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) ; 
414+             } 
415+ 
416+             // Since no error was returned, file protocol should be non-NULL. 
417+             let  p = NonNull :: new ( file_opened) . unwrap ( ) ; 
418+             Ok ( File ( p) ) 
419+         } 
420+     } 
421+ 
422+     impl  Drop  for  File  { 
423+         fn  drop ( & mut  self )  { 
424+             let  file_ptr = self . 0 . as_ptr ( ) ; 
425+             let  _ = unsafe  {  ( ( * self . 0 . as_ptr ( ) ) . close ) ( file_ptr)  } ; 
426+         } 
427+     } 
428+ 
429+     /// A helper to check that target path is a descendent of source. It is expected to be used with 
430+      /// absolute UEFI device paths without any UEFI shell mappings. 
431+      /// 
432+      /// Returns the path relative to source 
433+      /// 
434+      /// For example, given "PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Slave,0x0)/" and 
435+      /// "PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Slave,0x0)/\abc\run.efi", this will return 
436+      /// "\abc\run.efi" 
437+      fn  path_best_match ( 
438+         source :  & helpers:: BorrowedDevicePath < ' _ > , 
439+         target :  & helpers:: BorrowedDevicePath < ' _ > , 
440+     )  -> Option < Box < [ u16 ] > >  { 
441+         let  mut  source_iter = source. iter ( ) . take_while ( |x| !x. is_end_instance ( ) ) ; 
442+         let  mut  target_iter = target. iter ( ) . take_while ( |x| !x. is_end_instance ( ) ) ; 
443+ 
444+         loop  { 
445+             match  ( source_iter. next ( ) ,  target_iter. next ( ) )  { 
446+                 ( Some ( x) ,  Some ( y) )  if  x == y => continue , 
447+                 ( None ,  Some ( y) )  => { 
448+                     let  p = y. to_path ( ) . to_text ( ) . ok ( ) ?; 
449+                     return  helpers:: os_string_to_raw ( & p) ; 
450+                 } 
451+                 _ => return  None , 
452+             } 
453+         } 
454+     } 
455+ } 
0 commit comments