7777
7878pub  mod  build; 
7979pub  mod  text; 
80+ pub  mod  util; 
8081
8182mod  device_path_gen; 
8283pub  use  device_path_gen:: { 
8384    acpi,  bios_boot_spec,  end,  hardware,  media,  messaging,  DevicePathNodeEnum , 
8485} ; 
8586pub  use  uefi_raw:: protocol:: device_path:: { DeviceSubType ,  DeviceType } ; 
8687
88+ use  crate :: mem:: PoolAllocation ; 
8789use  crate :: proto:: { unsafe_protocol,  ProtocolPointer } ; 
8890use  core:: ffi:: c_void; 
8991use  core:: fmt:: { self ,  Debug ,  Display ,  Formatter } ; 
@@ -94,6 +96,7 @@ use ptr_meta::Pointee;
9496use  { 
9597    crate :: boot:: { self ,  OpenProtocolAttributes ,  OpenProtocolParams ,  ScopedProtocol ,  SearchType } , 
9698    crate :: proto:: device_path:: text:: { AllowShortcuts ,  DevicePathToText ,  DisplayOnly } , 
99+     crate :: proto:: device_path:: util:: DevicePathUtilities , 
97100    crate :: { CString16 ,  Identify } , 
98101    alloc:: borrow:: ToOwned , 
99102    alloc:: boxed:: Box , 
@@ -108,6 +111,30 @@ opaque_type! {
108111     pub  struct  FfiDevicePath ; 
109112} 
110113
114+ /// Device path allocated from UEFI pool memory. 
115+ #[ derive( Debug ) ]  
116+ pub  struct  PoolDevicePath ( pub ( crate )  PoolAllocation ) ; 
117+ 
118+ impl  Deref  for  PoolDevicePath  { 
119+     type  Target  = DevicePath ; 
120+ 
121+     fn  deref ( & self )  -> & Self :: Target  { 
122+         unsafe  {  DevicePath :: from_ffi_ptr ( self . 0 . as_ptr ( ) . as_ptr ( ) . cast ( ) )  } 
123+     } 
124+ } 
125+ 
126+ /// Device path node allocated from UEFI pool memory. 
127+ #[ derive( Debug ) ]  
128+ pub  struct  PoolDevicePathNode ( pub ( crate )  PoolAllocation ) ; 
129+ 
130+ impl  Deref  for  PoolDevicePathNode  { 
131+     type  Target  = DevicePathNode ; 
132+ 
133+     fn  deref ( & self )  -> & Self :: Target  { 
134+         unsafe  {  DevicePathNode :: from_ffi_ptr ( self . 0 . as_ptr ( ) . as_ptr ( ) . cast ( ) )  } 
135+     } 
136+ } 
137+ 
111138/// Header that appears at the start of every [`DevicePathNode`]. 
112139#[ derive( Clone ,  Copy ,  Debug ,  Eq ,  PartialEq ) ]  
113140#[ repr( C ,  packed) ]  
@@ -499,6 +526,25 @@ impl DevicePath {
499526            } ) 
500527            . map_err ( |_| DevicePathToTextError :: OutOfMemory ) 
501528    } 
529+ 
530+     /// Allocates and returns a new [`DevicePath`] by copying this one and appending the given `right` path. 
531+      #[ cfg( feature = "alloc" ) ]  
532+     pub  fn  append_path ( & self ,  right :  & Self )  -> Result < PoolDevicePath ,  DevicePathUtilitiesError >  { 
533+         open_utility_protocol ( ) ?
534+             . append_path ( self ,  right) 
535+             . map_err ( |_| DevicePathUtilitiesError :: OutOfMemory ) 
536+     } 
537+ 
538+     /// Allocates and returns a new [`DevicePath`] by copying this one and appending the given `right` node. 
539+      #[ cfg( feature = "alloc" ) ]  
540+     pub  fn  append_node ( 
541+         & self , 
542+         right :  & DevicePathNode , 
543+     )  -> Result < PoolDevicePath ,  DevicePathUtilitiesError >  { 
544+         open_utility_protocol ( ) ?
545+             . append_node ( self ,  right) 
546+             . map_err ( |_| DevicePathUtilitiesError :: OutOfMemory ) 
547+     } 
502548} 
503549
504550impl  Debug  for  DevicePath  { 
@@ -745,6 +791,63 @@ fn open_text_protocol() -> Result<ScopedProtocol<DevicePathToText>, DevicePathTo
745791    . map_err ( DevicePathToTextError :: CantOpenProtocol ) 
746792} 
747793
794+ /// Errors that may occur when working with the [`DevicePathUtilities`] protocol. 
795+ /// 
796+ /// These errors are typically encountered during operations involving device 
797+ /// paths, such as appending or manipulating path segments. 
798+ #[ derive( Debug ) ]  
799+ pub  enum  DevicePathUtilitiesError  { 
800+     /// Can't locate a handle buffer with handles associated with the 
801+      /// [`DevicePathUtilities`] protocol. 
802+      CantLocateHandleBuffer ( crate :: Error ) , 
803+     /// No handle supporting the [`DevicePathUtilities`] protocol was found. 
804+      NoHandle , 
805+     /// The handle supporting the [`DevicePathUtilities`] protocol exists but 
806+      /// it could not be opened. 
807+      CantOpenProtocol ( crate :: Error ) , 
808+     /// Memory allocation failed during device path operations. 
809+      OutOfMemory , 
810+ } 
811+ 
812+ impl  Display  for  DevicePathUtilitiesError  { 
813+     fn  fmt ( & self ,  f :  & mut  Formatter < ' _ > )  -> fmt:: Result  { 
814+         write ! ( f,  "{self:?}" ) 
815+     } 
816+ } 
817+ 
818+ impl  core:: error:: Error  for  DevicePathUtilitiesError  { 
819+     fn  source ( & self )  -> Option < & ( dyn  core:: error:: Error  + ' static ) >  { 
820+         match  self  { 
821+             Self :: CantLocateHandleBuffer ( e)  => Some ( e) , 
822+             Self :: CantOpenProtocol ( e)  => Some ( e) , 
823+             _ => None , 
824+         } 
825+     } 
826+ } 
827+ 
828+ /// Helper function to open the [`DevicePathUtilities`] protocol using the boot 
829+ /// services. 
830+ #[ cfg( feature = "alloc" ) ]  
831+ fn  open_utility_protocol ( )  -> Result < ScopedProtocol < DevicePathUtilities > ,  DevicePathUtilitiesError > 
832+ { 
833+     let  & handle = boot:: locate_handle_buffer ( SearchType :: ByProtocol ( & DevicePathToText :: GUID ) ) 
834+         . map_err ( DevicePathUtilitiesError :: CantLocateHandleBuffer ) ?
835+         . first ( ) 
836+         . ok_or ( DevicePathUtilitiesError :: NoHandle ) ?; 
837+ 
838+     unsafe  { 
839+         boot:: open_protocol :: < DevicePathUtilities > ( 
840+             OpenProtocolParams  { 
841+                 handle, 
842+                 agent :  boot:: image_handle ( ) , 
843+                 controller :  None , 
844+             } , 
845+             OpenProtocolAttributes :: GetProtocol , 
846+         ) 
847+     } 
848+     . map_err ( DevicePathUtilitiesError :: CantOpenProtocol ) 
849+ } 
850+ 
748851#[ cfg( test) ]  
749852mod  tests { 
750853    use  super :: * ; 
0 commit comments