@@ -216,6 +216,60 @@ pub(crate) fn device_path_to_text(path: NonNull<device_path::Protocol>) -> io::R
216216    Err ( io:: const_error!( io:: ErrorKind :: NotFound ,  "no device path to text protocol found" ) ) 
217217} 
218218
219+ fn  device_node_to_text ( path :  NonNull < device_path:: Protocol > )  -> io:: Result < OsString >  { 
220+     fn  node_to_text ( 
221+         protocol :  NonNull < device_path_to_text:: Protocol > , 
222+         path :  NonNull < device_path:: Protocol > , 
223+     )  -> io:: Result < OsString >  { 
224+         let  path_ptr:  * mut  r_efi:: efi:: Char16  = unsafe  { 
225+             ( ( * protocol. as_ptr ( ) ) . convert_device_node_to_text ) ( 
226+                 path. as_ptr ( ) , 
227+                 // DisplayOnly 
228+                 r_efi:: efi:: Boolean :: FALSE , 
229+                 // AllowShortcuts 
230+                 r_efi:: efi:: Boolean :: FALSE , 
231+             ) 
232+         } ; 
233+ 
234+         let  path = os_string_from_raw ( path_ptr) 
235+             . ok_or ( io:: const_error!( io:: ErrorKind :: InvalidData ,  "Invalid path" ) ) ?; 
236+ 
237+         if  let  Some ( boot_services)  = crate :: os:: uefi:: env:: boot_services ( )  { 
238+             let  boot_services:  NonNull < r_efi:: efi:: BootServices >  = boot_services. cast ( ) ; 
239+             unsafe  { 
240+                 ( ( * boot_services. as_ptr ( ) ) . free_pool ) ( path_ptr. cast ( ) ) ; 
241+             } 
242+         } 
243+ 
244+         Ok ( path) 
245+     } 
246+ 
247+     static  LAST_VALID_HANDLE :  AtomicPtr < crate :: ffi:: c_void >  =
248+         AtomicPtr :: new ( crate :: ptr:: null_mut ( ) ) ; 
249+ 
250+     if  let  Some ( handle)  = NonNull :: new ( LAST_VALID_HANDLE . load ( Ordering :: Acquire ) )  { 
251+         if  let  Ok ( protocol)  = open_protocol :: < device_path_to_text:: Protocol > ( 
252+             handle, 
253+             device_path_to_text:: PROTOCOL_GUID , 
254+         )  { 
255+             return  node_to_text ( protocol,  path) ; 
256+         } 
257+     } 
258+ 
259+     let  device_path_to_text_handles = locate_handles ( device_path_to_text:: PROTOCOL_GUID ) ?; 
260+     for  handle in  device_path_to_text_handles { 
261+         if  let  Ok ( protocol)  = open_protocol :: < device_path_to_text:: Protocol > ( 
262+             handle, 
263+             device_path_to_text:: PROTOCOL_GUID , 
264+         )  { 
265+             LAST_VALID_HANDLE . store ( handle. as_ptr ( ) ,  Ordering :: Release ) ; 
266+             return  node_to_text ( protocol,  path) ; 
267+         } 
268+     } 
269+ 
270+     Err ( io:: const_error!( io:: ErrorKind :: NotFound ,  "No device path to text protocol found" ) ) 
271+ } 
272+ 
219273/// Gets RuntimeServices. 
220274pub ( crate )  fn  runtime_services ( )  -> Option < NonNull < r_efi:: efi:: RuntimeServices > >  { 
221275    let  system_table:  NonNull < r_efi:: efi:: SystemTable >  =
@@ -319,6 +373,11 @@ impl<'a> BorrowedDevicePath<'a> {
319373    pub ( crate )  fn  to_text ( & self )  -> io:: Result < OsString >  { 
320374        device_path_to_text ( self . protocol ) 
321375    } 
376+ 
377+     #[ expect( dead_code) ]  
378+     pub ( crate )  const  fn  iter ( & ' a  self )  -> DevicePathIterator < ' a >  { 
379+         DevicePathIterator :: new ( DevicePathNode :: new ( self . protocol ) ) 
380+     } 
322381} 
323382
324383impl < ' a >  crate :: fmt:: Debug  for  BorrowedDevicePath < ' a >  { 
@@ -330,6 +389,126 @@ impl<'a> crate::fmt::Debug for BorrowedDevicePath<'a> {
330389    } 
331390} 
332391
392+ pub ( crate )  struct  DevicePathIterator < ' a > ( Option < DevicePathNode < ' a > > ) ; 
393+ 
394+ impl < ' a >  DevicePathIterator < ' a >  { 
395+     const  fn  new ( node :  DevicePathNode < ' a > )  -> Self  { 
396+         if  node. is_end ( )  {  Self ( None )  }  else  {  Self ( Some ( node) )  } 
397+     } 
398+ } 
399+ 
400+ impl < ' a >  Iterator  for  DevicePathIterator < ' a >  { 
401+     type  Item  = DevicePathNode < ' a > ; 
402+ 
403+     fn  next ( & mut  self )  -> Option < Self :: Item >  { 
404+         let  cur_node = self . 0 ?; 
405+ 
406+         let  next_node = unsafe  {  cur_node. next_node ( )  } ; 
407+         self . 0  = if  next_node. is_end ( )  {  None  }  else  {  Some ( next_node)  } ; 
408+ 
409+         Some ( cur_node) 
410+     } 
411+ } 
412+ 
413+ #[ derive( Copy ,  Clone ) ]  
414+ pub ( crate )  struct  DevicePathNode < ' a >  { 
415+     protocol :  NonNull < r_efi:: protocols:: device_path:: Protocol > , 
416+     phantom :  PhantomData < & ' a  r_efi:: protocols:: device_path:: Protocol > , 
417+ } 
418+ 
419+ impl < ' a >  DevicePathNode < ' a >  { 
420+     pub ( crate )  const  fn  new ( protocol :  NonNull < r_efi:: protocols:: device_path:: Protocol > )  -> Self  { 
421+         Self  {  protocol,  phantom :  PhantomData  } 
422+     } 
423+ 
424+     pub ( crate )  const  fn  length ( & self )  -> u16  { 
425+         let  len = unsafe  {  ( * self . protocol . as_ptr ( ) ) . length  } ; 
426+         u16:: from_le_bytes ( len) 
427+     } 
428+ 
429+     pub ( crate )  const  fn  node_type ( & self )  -> u8  { 
430+         unsafe  {  ( * self . protocol . as_ptr ( ) ) . r#type  } 
431+     } 
432+ 
433+     pub ( crate )  const  fn  sub_type ( & self )  -> u8  { 
434+         unsafe  {  ( * self . protocol . as_ptr ( ) ) . sub_type  } 
435+     } 
436+ 
437+     pub ( crate )  fn  data ( & self )  -> & [ u8 ]  { 
438+         let  length:  usize  = self . length ( ) . into ( ) ; 
439+ 
440+         // Some nodes do not have any special data 
441+         if  length > 4  { 
442+             let  raw_ptr:  * const  u8  = self . protocol . as_ptr ( ) . cast ( ) ; 
443+             let  data = unsafe  {  raw_ptr. add ( 4 )  } ; 
444+             unsafe  {  crate :: slice:: from_raw_parts ( data,  length - 4 )  } 
445+         }  else  { 
446+             & [ ] 
447+         } 
448+     } 
449+ 
450+     pub ( crate )  const  fn  is_end ( & self )  -> bool  { 
451+         self . node_type ( )  == r_efi:: protocols:: device_path:: TYPE_END 
452+             && self . sub_type ( )  == r_efi:: protocols:: device_path:: End :: SUBTYPE_ENTIRE 
453+     } 
454+ 
455+     #[ expect( dead_code) ]  
456+     pub ( crate )  const  fn  is_end_instance ( & self )  -> bool  { 
457+         self . node_type ( )  == r_efi:: protocols:: device_path:: TYPE_END 
458+             && self . sub_type ( )  == r_efi:: protocols:: device_path:: End :: SUBTYPE_INSTANCE 
459+     } 
460+ 
461+     pub ( crate )  unsafe  fn  next_node ( & self )  -> Self  { 
462+         let  node = unsafe  { 
463+             self . protocol 
464+                 . cast :: < u8 > ( ) 
465+                 . add ( self . length ( ) . into ( ) ) 
466+                 . cast :: < r_efi:: protocols:: device_path:: Protocol > ( ) 
467+         } ; 
468+         Self :: new ( node) 
469+     } 
470+ 
471+     #[ expect( dead_code) ]  
472+     pub ( crate )  fn  to_path ( & ' a  self )  -> BorrowedDevicePath < ' a >  { 
473+         BorrowedDevicePath :: new ( self . protocol ) 
474+     } 
475+ 
476+     pub ( crate )  fn  to_text ( & self )  -> io:: Result < OsString >  { 
477+         device_node_to_text ( self . protocol ) 
478+     } 
479+ } 
480+ 
481+ impl < ' a >  PartialEq  for  DevicePathNode < ' a >  { 
482+     fn  eq ( & self ,  other :  & Self )  -> bool  { 
483+         let  self_len = self . length ( ) ; 
484+         let  other_len = other. length ( ) ; 
485+ 
486+         self_len == other_len
487+             && unsafe  { 
488+                 compiler_builtins:: mem:: memcmp ( 
489+                     self . protocol . as_ptr ( ) . cast ( ) , 
490+                     other. protocol . as_ptr ( ) . cast ( ) , 
491+                     usize:: from ( self_len) , 
492+                 )  == 0 
493+             } 
494+     } 
495+ } 
496+ 
497+ impl < ' a >  crate :: fmt:: Debug  for  DevicePathNode < ' a >  { 
498+     fn  fmt ( & self ,  f :  & mut  crate :: fmt:: Formatter < ' _ > )  -> crate :: fmt:: Result  { 
499+         match  self . to_text ( )  { 
500+             Ok ( p)  => p. fmt ( f) , 
501+             Err ( _)  => f
502+                 . debug_struct ( "DevicePathNode" ) 
503+                 . field ( "type" ,  & self . node_type ( ) ) 
504+                 . field ( "sub_type" ,  & self . sub_type ( ) ) 
505+                 . field ( "length" ,  & self . length ( ) ) 
506+                 . field ( "specific_device_path_data" ,  & self . data ( ) ) 
507+                 . finish ( ) , 
508+         } 
509+     } 
510+ } 
511+ 
333512pub ( crate )  struct  OwnedProtocol < T >  { 
334513    guid :  r_efi:: efi:: Guid , 
335514    handle :  NonNull < crate :: ffi:: c_void > , 
0 commit comments