@@ -26,6 +26,9 @@ use crate::{component::*, packagesystem};
26
26
/// Well-known paths to the ESP that may have been mounted external to us.
27
27
pub ( crate ) const ESP_MOUNTS : & [ & str ] = & [ "boot/efi" , "efi" , "boot" ] ;
28
28
29
+ /// Temp EFI dir
30
+ const TEMP_EFI_DIR : & str = ".EFI.tmp" ;
31
+
29
32
/// The binary to change EFI boot ordering
30
33
const EFIBOOTMGR : & str = "efibootmgr" ;
31
34
#[ cfg( target_arch = "aarch64" ) ]
@@ -349,12 +352,35 @@ impl Component for Efi {
349
352
. context ( "opening update dir" ) ?;
350
353
let updatef = filetree:: FileTree :: new_from_dir ( & updated) . context ( "reading update dir" ) ?;
351
354
let diff = currentf. diff ( & updatef) ?;
352
- self . ensure_mounted_esp ( Path :: new ( "/" ) ) ?;
353
- let destdir = self . open_esp ( ) . context ( "opening EFI dir" ) ?;
354
- validate_esp ( & destdir) ?;
355
+ let mountdir = self . ensure_mounted_esp ( Path :: new ( "/" ) ) ?;
356
+
357
+ let efipath = self . esp_path ( ) ?;
358
+ let tmp_efipath = mountdir. join ( TEMP_EFI_DIR ) ;
359
+ // remove a previous directory if it exists in order to handle being interrupted in the middle.
360
+ if tmp_efipath. exists ( ) {
361
+ std:: fs:: remove_dir_all ( & tmp_efipath) ?;
362
+ }
363
+ copy_dir ( & efipath, & tmp_efipath) . with_context ( || "copying existing files to temp dir" ) ?;
364
+
365
+ let tmpdir = sysroot. sub_dir ( & tmp_efipath) ?;
366
+ validate_esp ( & tmpdir) ?;
355
367
log:: trace!( "applying diff: {}" , & diff) ;
356
- filetree:: apply_diff ( & updated, & destdir, & diff, None )
357
- . context ( "applying filesystem changes" ) ?;
368
+ filetree:: apply_diff ( & updated, & tmpdir, & diff, None )
369
+ . context ( "applying filesystem changes to temp EFI" ) ?;
370
+ {
371
+ let esp = sysroot. sub_dir ( & mountdir) ?;
372
+ log:: trace!(
373
+ "doing local exchange for {} and {}" ,
374
+ tmp_efipath. display( ) ,
375
+ efipath. display( )
376
+ ) ;
377
+
378
+ esp. local_exchange ( & tmp_efipath, & efipath)
379
+ . with_context ( || format ! ( "exchange for {:?} and {:?}" , tmp_efipath, efipath) ) ?;
380
+ // finally remove the temp dir
381
+ log:: trace!( "cleanup: {}" , tmp_efipath. display( ) ) ;
382
+ std:: fs:: remove_dir_all ( & tmp_efipath) . context ( "clean up temp" ) ?;
383
+ }
358
384
let adopted_from = None ;
359
385
Ok ( InstalledContent {
360
386
meta : updatemeta,
@@ -584,6 +610,18 @@ fn find_file_recursive<P: AsRef<Path>>(dir: P, target_file: &str) -> Result<Vec<
584
610
Ok ( result)
585
611
}
586
612
613
+ fn copy_dir ( src : & Path , dst : & Path ) -> Result < ( ) > {
614
+ let r = std:: process:: Command :: new ( "cp" )
615
+ . args ( [ "-a" ] )
616
+ . arg ( src)
617
+ . arg ( dst)
618
+ . status ( ) ?;
619
+ if !r. success ( ) {
620
+ anyhow:: bail!( "Failed to copy" ) ;
621
+ }
622
+ Ok ( ( ) )
623
+ }
624
+
587
625
#[ cfg( test) ]
588
626
mod tests {
589
627
use super :: * ;
0 commit comments