Skip to content

Commit 6bf2e6f

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 f90b45e commit 6bf2e6f

File tree

1 file changed

+51
-4
lines changed

1 file changed

+51
-4
lines changed

src/efi.rs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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)]
584631
mod tests {
585632
use super::*;

0 commit comments

Comments
 (0)