@@ -72,6 +72,17 @@ impl Efi {
72
72
Ok ( esp)
73
73
}
74
74
75
+ fn esp_path_tmp ( & self ) -> Result < PathBuf > {
76
+ self . ensure_mounted_esp ( Path :: new ( "/" ) )
77
+ . map ( |v| v. join ( ".EFI.tmp" ) )
78
+ }
79
+
80
+ fn open_esp_tmp_optional ( & self ) -> Result < Option < openat:: Dir > > {
81
+ let sysroot = openat:: Dir :: open ( "/" ) ?;
82
+ let esp = sysroot. sub_dir_optional ( & self . esp_path_tmp ( ) ?) ?;
83
+ Ok ( esp)
84
+ }
85
+
75
86
pub ( crate ) fn ensure_mounted_esp ( & self , root : & Path ) -> Result < PathBuf > {
76
87
let mut mountpoint = self . mountpoint . borrow_mut ( ) ;
77
88
if let Some ( mountpoint) = mountpoint. as_deref ( ) {
@@ -348,12 +359,40 @@ impl Component for Efi {
348
359
. context ( "opening update dir" ) ?;
349
360
let updatef = filetree:: FileTree :: new_from_dir ( & updated) . context ( "reading update dir" ) ?;
350
361
let diff = currentf. diff ( & updatef) ?;
351
- self . ensure_mounted_esp ( Path :: new ( "/" ) ) ?;
352
- let destdir = self . open_esp ( ) . context ( "opening EFI dir" ) ?;
353
- validate_esp ( & destdir) ?;
362
+ let mountdir = self . ensure_mounted_esp ( Path :: new ( "/" ) ) ?;
363
+
364
+ // copy esp dir to temp to do apply diff
365
+ let esp = & self . esp_path ( ) ?;
366
+ let tmpesp = & self . esp_path_tmp ( ) ?;
367
+ copy_dir_all ( esp, tmpesp) . context ( "copying esp dir to temp dir" ) ?;
368
+ assert ! ( tmpesp. exists( ) ) ;
369
+
370
+ let tmpdir = if let Some ( p) = self . open_esp_tmp_optional ( ) ? {
371
+ p
372
+ } else {
373
+ bail ! ( "Failed to open temp efi dir" ) ;
374
+ } ;
375
+ validate_esp ( & tmpdir) ?;
354
376
log:: trace!( "applying diff: {}" , & diff) ;
355
- filetree:: apply_diff ( & updated, & destdir, & diff, None )
356
- . context ( "applying filesystem changes" ) ?;
377
+ filetree:: apply_diff ( & updated, & tmpdir, & diff, None )
378
+ . context ( "applying filesystem changes to temp EFI" ) ?;
379
+ {
380
+ // do local exchange of the temp dir and esp dir
381
+ let parentdir = if let Some ( p) = sysroot. sub_dir_optional ( & mountdir) ? {
382
+ p
383
+ } else {
384
+ bail ! ( "Failed to get parent dir" ) ;
385
+ } ;
386
+ parentdir. local_exchange ( tmpesp, esp) . with_context ( || {
387
+ format ! (
388
+ "local exchange for {} and {}" ,
389
+ tmpesp. display( ) ,
390
+ esp. display( )
391
+ )
392
+ } ) ?;
393
+ // finally remove the temp dir
394
+ std:: fs:: remove_dir_all ( tmpesp) ?;
395
+ }
357
396
let adopted_from = None ;
358
397
Ok ( InstalledContent {
359
398
meta : updatemeta,
@@ -580,6 +619,28 @@ fn find_file_recursive<P: AsRef<Path>>(dir: P, target_file: &str) -> Result<Vec<
580
619
Ok ( result)
581
620
}
582
621
622
+ fn copy_dir_all ( src : & Path , dst : & Path ) -> Result < ( ) > {
623
+ // Create the destination directory if it doesn't exist
624
+ if !dst. exists ( ) {
625
+ std:: fs:: create_dir_all ( dst) ?;
626
+ }
627
+
628
+ // Iterate over directory entries
629
+ for entry in std:: fs:: read_dir ( src) ? {
630
+ let entry = entry?;
631
+ let path = entry. path ( ) ;
632
+ let relative_path = path. strip_prefix ( src) ?;
633
+ let destination = dst. join ( relative_path) ;
634
+
635
+ if path. is_dir ( ) {
636
+ copy_dir_all ( & path, & destination) ?;
637
+ } else {
638
+ std:: fs:: copy ( & path, & destination) ?;
639
+ }
640
+ }
641
+ Ok ( ( ) )
642
+ }
643
+
583
644
#[ cfg( test) ]
584
645
mod tests {
585
646
use super :: * ;
@@ -655,4 +716,25 @@ Boot0003* test";
655
716
) ;
656
717
Ok ( ( ) )
657
718
}
719
+
720
+ #[ test]
721
+ fn test_copy_dir_all ( ) -> Result < ( ) > {
722
+ env_logger:: init ( ) ;
723
+ let td = tempfile:: tempdir ( ) ?;
724
+ let tdp = td. path ( ) ;
725
+ let src = tdp. join ( "efi" ) ;
726
+ std:: fs:: create_dir_all ( & src) ?;
727
+ std:: fs:: create_dir_all ( tdp. join ( "efi/BOOT" ) ) ?;
728
+ std:: fs:: create_dir_all ( tdp. join ( "efi/fedora" ) ) ?;
729
+ std:: fs:: write ( tdp. join ( "efi/BOOT" ) . join ( "fbx64.efi" ) , "fall back data" ) ?;
730
+ std:: fs:: write ( tdp. join ( "efi/fedora" ) . join ( crate :: efi:: SHIM ) , "shim data" ) ?;
731
+ std:: fs:: write ( tdp. join ( "efi/fedora" ) . join ( "grub.cfg" ) , "grub config data" ) ?;
732
+ let dest = tdp. join ( "tmpefi" ) ;
733
+ copy_dir_all ( src. as_path ( ) , dest. as_path ( ) ) ?;
734
+ assert_eq ! ( dest. join( "BOOT/fbx64.efi" ) . exists( ) , true ) ;
735
+ assert_eq ! ( dest. join( "fedora" ) . join( crate :: efi:: SHIM ) . exists( ) , true ) ;
736
+ assert_eq ! ( dest. join( "fedora/grub.cfg" ) . exists( ) , true ) ;
737
+
738
+ Ok ( ( ) )
739
+ }
658
740
}
0 commit comments