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