@@ -125,7 +125,7 @@ pub fn error_string(errno: RawOsError) -> String {
125125} 
126126
127127pub  fn  getcwd ( )  -> io:: Result < PathBuf >  { 
128-     match  uefi_shell :: open_shell ( )  { 
128+     match  helpers :: open_shell ( )  { 
129129        Some ( shell)  => { 
130130            // SAFETY: path_ptr is managed by UEFI shell and should not be deallocated 
131131            let  path_ptr = unsafe  {  ( ( * shell. as_ptr ( ) ) . get_cur_dir ) ( crate :: ptr:: null_mut ( ) )  } ; 
@@ -144,7 +144,7 @@ pub fn getcwd() -> io::Result<PathBuf> {
144144} 
145145
146146pub  fn  chdir ( p :  & path:: Path )  -> io:: Result < ( ) >  { 
147-     let  shell = uefi_shell :: open_shell ( ) . ok_or ( unsupported_err ( ) ) ?; 
147+     let  shell = helpers :: open_shell ( ) . ok_or ( unsupported_err ( ) ) ?; 
148148
149149    let  mut  p = helpers:: os_string_to_raw ( p. as_os_str ( ) ) 
150150        . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidData ,  "Invalid path" ) ) ?; 
@@ -192,44 +192,58 @@ pub fn current_exe() -> io::Result<PathBuf> {
192192    helpers:: device_path_to_text ( protocol) . map ( PathBuf :: from) 
193193} 
194194
195- pub  struct  Env ( !) ; 
195+ pub  struct  EnvStrDebug < ' a >  { 
196+     iter :  & ' a  [ ( OsString ,  OsString ) ] , 
197+ } 
198+ 
199+ impl  fmt:: Debug  for  EnvStrDebug < ' _ >  { 
200+     fn  fmt ( & self ,  f :  & mut  fmt:: Formatter < ' _ > )  -> fmt:: Result  { 
201+         let  mut  list = f. debug_list ( ) ; 
202+         for  ( a,  b)  in  self . iter  { 
203+             list. entry ( & ( a. to_str ( ) . unwrap ( ) ,  b. to_str ( ) . unwrap ( ) ) ) ; 
204+         } 
205+         list. finish ( ) 
206+     } 
207+ } 
208+ 
209+ pub  struct  Env ( crate :: vec:: IntoIter < ( OsString ,  OsString ) > ) ; 
196210
197211impl  Env  { 
198212    // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. 
199213    pub  fn  str_debug ( & self )  -> impl  fmt:: Debug  + ' _  { 
200-         let  Self ( inner)  = self ; 
201-         match  * inner { } 
214+         EnvStrDebug  {  iter :  self . 0 . as_slice ( )  } 
202215    } 
203216} 
204217
205218impl  Iterator  for  Env  { 
206219    type  Item  = ( OsString ,  OsString ) ; 
220+ 
207221    fn  next ( & mut  self )  -> Option < ( OsString ,  OsString ) >  { 
208-         self . 0 
222+         self . 0 . next ( ) 
209223    } 
210224} 
211225
212226impl  fmt:: Debug  for  Env  { 
213-     fn  fmt ( & self ,  _:  & mut  fmt:: Formatter < ' _ > )  -> fmt:: Result  { 
214-         let  Self ( inner)  = self ; 
215-         match  * inner { } 
227+     fn  fmt ( & self ,  f :  & mut  fmt:: Formatter < ' _ > )  -> fmt:: Result  { 
228+         self . 0 . fmt ( f) 
216229    } 
217230} 
218231
219232pub  fn  env ( )  -> Env  { 
220-     panic ! ( "not supported on this platform" ) 
233+     let  env = uefi_env:: get_all ( ) . expect ( "not supported on this platform" ) ; 
234+     Env ( env. into_iter ( ) ) 
221235} 
222236
223- pub  fn  getenv ( _ :  & OsStr )  -> Option < OsString >  { 
224-     None 
237+ pub  fn  getenv ( key :  & OsStr )  -> Option < OsString >  { 
238+     uefi_env :: get ( key ) 
225239} 
226240
227- pub  unsafe  fn  setenv ( _ :  & OsStr ,  _ :  & OsStr )  -> io:: Result < ( ) >  { 
228-     Err ( io :: const_io_error! ( io :: ErrorKind :: Unsupported ,   "cannot set env vars on this platform" ) ) 
241+ pub  unsafe  fn  setenv ( key :  & OsStr ,  val :  & OsStr )  -> io:: Result < ( ) >  { 
242+     uefi_env :: set ( key ,  val ) 
229243} 
230244
231- pub  unsafe  fn  unsetenv ( _ :  & OsStr )  -> io:: Result < ( ) >  { 
232-     Err ( io :: const_io_error! ( io :: ErrorKind :: Unsupported ,   "cannot  unset env vars on this platform" ) ) 
245+ pub  unsafe  fn  unsetenv ( key :  & OsStr )  -> io:: Result < ( ) >  { 
246+     uefi_env :: unset ( key ) 
233247} 
234248
235249pub  fn  temp_dir ( )  -> PathBuf  { 
@@ -261,36 +275,84 @@ pub fn getpid() -> u32 {
261275    panic ! ( "no pids on this platform" ) 
262276} 
263277
264- mod  uefi_shell  { 
265-     use  r_efi :: protocols :: shell ; 
266- 
267-     use  super :: super :: helpers ; 
278+ mod  uefi_env  { 
279+     use  crate :: ffi :: { OsStr ,   OsString } ; 
280+      use   crate :: io ; 
281+     use  crate :: os :: uefi :: ffi :: OsStringExt ; 
268282    use  crate :: ptr:: NonNull ; 
269-     use  crate :: sync:: atomic:: { AtomicPtr ,  Ordering } ; 
270- 
271-     pub  fn  open_shell ( )  -> Option < NonNull < shell:: Protocol > >  { 
272-         static  LAST_VALID_HANDLE :  AtomicPtr < crate :: ffi:: c_void >  =
273-             AtomicPtr :: new ( crate :: ptr:: null_mut ( ) ) ; 
274- 
275-         if  let  Some ( handle)  = NonNull :: new ( LAST_VALID_HANDLE . load ( Ordering :: Acquire ) )  { 
276-             if  let  Ok ( protocol)  = helpers:: open_protocol :: < shell:: Protocol > ( 
277-                 handle, 
278-                 r_efi:: protocols:: shell:: PROTOCOL_GUID , 
279-             )  { 
280-                 return  Some ( protocol) ; 
281-             } 
283+     use  crate :: sys:: { helpers,  unsupported_err} ; 
284+ 
285+     pub ( crate )  fn  get ( key :  & OsStr )  -> Option < OsString >  { 
286+         let  shell = helpers:: open_shell ( ) ?; 
287+         let  mut  key_ptr = helpers:: os_string_to_raw ( key) ?; 
288+         unsafe  {  get_raw ( shell,  key_ptr. as_mut_ptr ( ) )  } 
289+     } 
290+ 
291+     pub ( crate )  fn  set ( key :  & OsStr ,  val :  & OsStr )  -> io:: Result < ( ) >  { 
292+         let  mut  key_ptr = helpers:: os_string_to_raw ( key) 
293+             . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidInput ,  "Invalid Key" ) ) ?; 
294+         let  mut  val_ptr = helpers:: os_string_to_raw ( val) 
295+             . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidInput ,  "Invalid Value" ) ) ?; 
296+         unsafe  {  set_raw ( key_ptr. as_mut_ptr ( ) ,  val_ptr. as_mut_ptr ( ) )  } 
297+     } 
298+ 
299+     pub ( crate )  fn  unset ( key :  & OsStr )  -> io:: Result < ( ) >  { 
300+         let  mut  key_ptr = helpers:: os_string_to_raw ( key) 
301+             . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidInput ,  "Invalid Key" ) ) ?; 
302+         unsafe  {  set_raw ( key_ptr. as_mut_ptr ( ) ,  crate :: ptr:: null_mut ( ) )  } 
303+     } 
304+ 
305+     pub ( crate )  fn  get_all ( )  -> io:: Result < Vec < ( OsString ,  OsString ) > >  { 
306+         let  shell = helpers:: open_shell ( ) . ok_or ( unsupported_err ( ) ) ?; 
307+ 
308+         let  mut  vars = Vec :: new ( ) ; 
309+         let  val = unsafe  {  ( ( * shell. as_ptr ( ) ) . get_env ) ( crate :: ptr:: null_mut ( ) )  } ; 
310+ 
311+         if  val. is_null ( )  { 
312+             return  Ok ( vars) ; 
282313        } 
283314
284-         let  handles = helpers:: locate_handles ( shell:: PROTOCOL_GUID ) . ok ( ) ?; 
285-         for  handle in  handles { 
286-             if  let  Ok ( protocol)  =
287-                 helpers:: open_protocol :: < shell:: Protocol > ( handle,  shell:: PROTOCOL_GUID ) 
288-             { 
289-                 LAST_VALID_HANDLE . store ( handle. as_ptr ( ) ,  Ordering :: Release ) ; 
290-                 return  Some ( protocol) ; 
315+         let  mut  start = 0 ; 
316+ 
317+         // UEFI Shell returns all keys seperated by NULL. 
318+         // End of string is denoted by two NULLs 
319+         for  i in  0 .. { 
320+             if  unsafe  {  * val. add ( i)  }  == 0  { 
321+                 // Two NULL signal end of string 
322+                 if  i == start { 
323+                     break ; 
324+                 } 
325+ 
326+                 let  key = OsString :: from_wide ( unsafe  { 
327+                     crate :: slice:: from_raw_parts ( val. add ( start) ,  i - start) 
328+                 } ) ; 
329+                 // SAFETY: val.add(start) is always NULL terminated 
330+                 let  val = unsafe  {  get_raw ( shell,  val. add ( start) )  } 
331+                     . ok_or ( io:: const_io_error!( io:: ErrorKind :: InvalidInput ,  "Invalid Value" ) ) ?; 
332+ 
333+                 vars. push ( ( key,  val) ) ; 
334+                 start = i + 1 ; 
291335            } 
292336        } 
293337
294-         None 
338+         Ok ( vars) 
339+     } 
340+ 
341+     unsafe  fn  get_raw ( 
342+         shell :  NonNull < r_efi:: efi:: protocols:: shell:: Protocol > , 
343+         key_ptr :  * mut  r_efi:: efi:: Char16 , 
344+     )  -> Option < OsString >  { 
345+         let  val = unsafe  {  ( ( * shell. as_ptr ( ) ) . get_env ) ( key_ptr)  } ; 
346+         helpers:: os_string_from_raw ( val) 
347+     } 
348+ 
349+     unsafe  fn  set_raw ( 
350+         key_ptr :  * mut  r_efi:: efi:: Char16 , 
351+         val_ptr :  * mut  r_efi:: efi:: Char16 , 
352+     )  -> io:: Result < ( ) >  { 
353+         let  shell = helpers:: open_shell ( ) . ok_or ( unsupported_err ( ) ) ?; 
354+         let  r =
355+             unsafe  {  ( ( * shell. as_ptr ( ) ) . set_env ) ( key_ptr,  val_ptr,  r_efi:: efi:: Boolean :: FALSE )  } ; 
356+         if  r. is_error ( )  {  Err ( io:: Error :: from_raw_os_error ( r. as_usize ( ) ) )  }  else  {  Ok ( ( ) )  } 
295357    } 
296358} 
0 commit comments