diff --git a/src/efi.rs b/src/efi.rs index e89fb05b..8ac93d75 100644 --- a/src/efi.rs +++ b/src/efi.rs @@ -349,11 +349,46 @@ impl Component for Efi { let updatef = filetree::FileTree::new_from_dir(&updated).context("reading update dir")?; let diff = currentf.diff(&updatef)?; self.ensure_mounted_esp(Path::new("/"))?; - let destdir = self.open_esp().context("opening EFI dir")?; - validate_esp(&destdir)?; + + /* copy "lowest" directory that we need to make the change + * e.g. we only affect EFI/fedora for example and not all of EFI + */ + let vendor = if let Some(v) = self.get_efi_vendor(&sysroot)? { + v + } else { + bail!("Failed to get vendor dir"); + }; + + let esp = self.esp_path()?; + let vendordir = esp.join(&vendor); + let tmp_vendordir = esp.join(format!(".{vendor}.tmp")); + // remove a previous directory if it exists in order to handle being interrupted in the middle. + if tmp_vendordir.exists() { + std::fs::remove_dir_all(&tmp_vendordir)?; + } + copy_dir(&vendordir, &tmp_vendordir) + .with_context(|| "copying existing files to temp dir")?; + assert!(tmp_vendordir.exists()); + + let tmpdir = sysroot.sub_dir(&tmp_vendordir)?; + validate_esp(&tmpdir)?; log::trace!("applying diff: {}", &diff); - filetree::apply_diff(&updated, &destdir, &diff, None) - .context("applying filesystem changes")?; + filetree::apply_diff(&updated, &tmpdir, &diff, None) + .context("applying filesystem changes to temp EFI")?; + { + let esp = self.open_esp()?; + log::trace!( + "doing local exchange for {} and {}", + tmp_vendordir.display(), + vendordir.display() + ); + + esp.local_exchange(&tmp_vendordir, &vendordir) + .with_context(|| format!("exchange for {:?} and {:?}", tmp_vendordir, vendordir))?; + // finally remove the temp dir + std::fs::remove_dir_all(&tmp_vendordir).context("clean up temp")?; + assert!(!tmp_vendordir.exists()); + } let adopted_from = None; Ok(InstalledContent { meta: updatemeta, @@ -580,6 +615,18 @@ fn find_file_recursive>(dir: P, target_file: &str) -> Result Result<()> { + let r = std::process::Command::new("cp") + .args(["-a"]) + .arg(src) + .arg(dst) + .status()?; + if !r.success() { + anyhow::bail!("Failed to copy"); + } + Ok(()) +} + #[cfg(test)] mod tests { use super::*;