diff --git a/src/efi.rs b/src/efi.rs index 060eedd9..c803c915 100644 --- a/src/efi.rs +++ b/src/efi.rs @@ -26,6 +26,9 @@ use crate::{component::*, packagesystem}; /// Well-known paths to the ESP that may have been mounted external to us. pub(crate) const ESP_MOUNTS: &[&str] = &["boot/efi", "efi", "boot"]; +/// Temp EFI dir +const TEMP_EFI_DIR: &str = ".EFI.tmp"; + /// The binary to change EFI boot ordering const EFIBOOTMGR: &str = "efibootmgr"; #[cfg(target_arch = "aarch64")] @@ -349,12 +352,35 @@ impl Component for Efi { .context("opening update dir")?; 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)?; + let mountdir = self.ensure_mounted_esp(Path::new("/"))?; + + let efipath = self.esp_path()?; + let tmp_efipath = mountdir.join(TEMP_EFI_DIR); + // remove a previous directory if it exists in order to handle being interrupted in the middle. + if tmp_efipath.exists() { + std::fs::remove_dir_all(&tmp_efipath)?; + } + copy_dir(&efipath, &tmp_efipath).with_context(|| "copying existing files to temp dir")?; + + let tmpdir = sysroot.sub_dir(&tmp_efipath)?; + 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 = sysroot.sub_dir(&mountdir)?; + log::trace!( + "doing local exchange for {} and {}", + tmp_efipath.display(), + efipath.display() + ); + + esp.local_exchange(&tmp_efipath, &efipath) + .with_context(|| format!("exchange for {:?} and {:?}", tmp_efipath, efipath))?; + // finally remove the temp dir + log::trace!("cleanup: {}", tmp_efipath.display()); + std::fs::remove_dir_all(&tmp_efipath).context("clean up temp")?; + } let adopted_from = None; Ok(InstalledContent { meta: updatemeta, @@ -584,6 +610,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::*;