@@ -350,11 +350,46 @@ impl Component for Efi {
350
350
let updatef = filetree:: FileTree :: new_from_dir ( & updated) . context ( "reading update dir" ) ?;
351
351
let diff = currentf. diff ( & updatef) ?;
352
352
self . ensure_mounted_esp ( Path :: new ( "/" ) ) ?;
353
- let destdir = self . open_esp ( ) . context ( "opening EFI dir" ) ?;
354
- validate_esp ( & destdir) ?;
353
+
354
+ /* copy "lowest" directory that we need to make the change
355
+ * e.g. we only affect EFI/fedora for example and not all of EFI
356
+ */
357
+ let vendor = if let Some ( v) = self . get_efi_vendor ( & sysroot) ? {
358
+ v
359
+ } else {
360
+ bail ! ( "Failed to get vendor dir" ) ;
361
+ } ;
362
+
363
+ let esp = self . esp_path ( ) ?;
364
+ let vendordir = esp. join ( & vendor) ;
365
+ let tmp_vendordir = esp. join ( format ! ( ".{vendor}.tmp" ) ) ;
366
+ // remove a previous directory if it exists in order to handle being interrupted in the middle.
367
+ if tmp_vendordir. exists ( ) {
368
+ std:: fs:: remove_dir_all ( & tmp_vendordir) ?;
369
+ }
370
+ copy_dir ( & vendordir, & tmp_vendordir)
371
+ . with_context ( || "copying existing files to temp dir" ) ?;
372
+ assert ! ( tmp_vendordir. exists( ) ) ;
373
+
374
+ let tmpdir = sysroot. sub_dir ( & tmp_vendordir) ?;
375
+ validate_esp ( & tmpdir) ?;
355
376
log:: trace!( "applying diff: {}" , & diff) ;
356
- filetree:: apply_diff ( & updated, & destdir, & diff, None )
357
- . context ( "applying filesystem changes" ) ?;
377
+ filetree:: apply_diff ( & updated, & tmpdir, & diff, None )
378
+ . context ( "applying filesystem changes to temp EFI" ) ?;
379
+ {
380
+ let esp = self . open_esp ( ) ?;
381
+ log:: trace!(
382
+ "doing local exchange for {} and {}" ,
383
+ tmp_vendordir. display( ) ,
384
+ vendordir. display( )
385
+ ) ;
386
+
387
+ esp. local_exchange ( & tmp_vendordir, & vendordir)
388
+ . with_context ( || format ! ( "exchange for {:?} and {:?}" , tmp_vendordir, vendordir) ) ?;
389
+ // finally remove the temp dir
390
+ std:: fs:: remove_dir_all ( & tmp_vendordir) . context ( "clean up temp" ) ?;
391
+ assert ! ( !tmp_vendordir. exists( ) ) ;
392
+ }
358
393
let adopted_from = None ;
359
394
Ok ( InstalledContent {
360
395
meta : updatemeta,
@@ -584,6 +619,18 @@ fn find_file_recursive<P: AsRef<Path>>(dir: P, target_file: &str) -> Result<Vec<
584
619
Ok ( result)
585
620
}
586
621
622
+ fn copy_dir ( src : & Path , dst : & Path ) -> Result < ( ) > {
623
+ let r = std:: process:: Command :: new ( "cp" )
624
+ . args ( [ "-a" ] )
625
+ . arg ( src)
626
+ . arg ( dst)
627
+ . status ( ) ?;
628
+ if !r. success ( ) {
629
+ anyhow:: bail!( "Failed to copy" ) ;
630
+ }
631
+ Ok ( ( ) )
632
+ }
633
+
587
634
#[ cfg( test) ]
588
635
mod tests {
589
636
use super :: * ;
0 commit comments