Skip to content

Commit 3cf8636

Browse files
committed
efi: update the ESP by creating a tmpdir and RENAME_EXCHANGE
See Timothée's comment #454 (comment) Fixes #454
1 parent 8a40a4e commit 3cf8636

File tree

1 file changed

+47
-5
lines changed

1 file changed

+47
-5
lines changed

src/efi.rs

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ use crate::{component::*, packagesystem};
2626
/// Well-known paths to the ESP that may have been mounted external to us.
2727
pub(crate) const ESP_MOUNTS: &[&str] = &["boot/efi", "efi", "boot"];
2828

29+
/// Backup EFI dir
30+
const TEMP_EFI_DIR: &str = ".EFI.tmp";
31+
2932
/// The binary to change EFI boot ordering
3033
const EFIBOOTMGR: &str = "efibootmgr";
3134
#[cfg(target_arch = "aarch64")]
@@ -349,12 +352,39 @@ impl Component for Efi {
349352
.context("opening update dir")?;
350353
let updatef = filetree::FileTree::new_from_dir(&updated).context("reading update dir")?;
351354
let diff = currentf.diff(&updatef)?;
352-
self.ensure_mounted_esp(Path::new("/"))?;
353-
let destdir = self.open_esp().context("opening EFI dir")?;
354-
validate_esp(&destdir)?;
355+
let mountdir = self.ensure_mounted_esp(Path::new("/"))?;
356+
357+
/* copy "lowest" directory that we need to make the change
358+
* e.g. we only affect EFI/fedora for example and not all of EFI
359+
*/
360+
361+
let efipath = self.esp_path()?;
362+
let tmp_efipath = mountdir.join(TEMP_EFI_DIR);
363+
// remove a previous directory if it exists in order to handle being interrupted in the middle.
364+
if tmp_efipath.exists() {
365+
std::fs::remove_dir_all(&tmp_efipath)?;
366+
}
367+
copy_dir(&efipath, &tmp_efipath).with_context(|| "copying existing files to temp dir")?;
368+
369+
let tmpdir = sysroot.sub_dir(&tmp_efipath)?;
370+
validate_esp(&tmpdir)?;
355371
log::trace!("applying diff: {}", &diff);
356-
filetree::apply_diff(&updated, &destdir, &diff, None)
357-
.context("applying filesystem changes")?;
372+
filetree::apply_diff(&updated, &tmpdir, &diff, None)
373+
.context("applying filesystem changes to temp EFI")?;
374+
{
375+
let esp = sysroot.sub_dir(&mountdir)?;
376+
log::trace!(
377+
"doing local exchange for {} and {}",
378+
tmp_efipath.display(),
379+
efipath.display()
380+
);
381+
382+
esp.local_exchange(&tmp_efipath, &efipath)
383+
.with_context(|| format!("exchange for {:?} and {:?}", tmp_efipath, efipath))?;
384+
// finally remove the temp dir
385+
log::trace!("cleanup: {}", tmp_efipath.display());
386+
std::fs::remove_dir_all(&tmp_efipath).context("clean up temp")?;
387+
}
358388
let adopted_from = None;
359389
Ok(InstalledContent {
360390
meta: updatemeta,
@@ -584,6 +614,18 @@ fn find_file_recursive<P: AsRef<Path>>(dir: P, target_file: &str) -> Result<Vec<
584614
Ok(result)
585615
}
586616

617+
fn copy_dir(src: &Path, dst: &Path) -> Result<()> {
618+
let r = std::process::Command::new("cp")
619+
.args(["-a"])
620+
.arg(src)
621+
.arg(dst)
622+
.status()?;
623+
if !r.success() {
624+
anyhow::bail!("Failed to copy");
625+
}
626+
Ok(())
627+
}
628+
587629
#[cfg(test)]
588630
mod tests {
589631
use super::*;

0 commit comments

Comments
 (0)