Skip to content

Commit 366b8eb

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 366b8eb

File tree

1 file changed

+49
-5
lines changed

1 file changed

+49
-5
lines changed

src/efi.rs

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -348,12 +348,44 @@ impl Component for Efi {
348348
.context("opening update dir")?;
349349
let updatef = filetree::FileTree::new_from_dir(&updated).context("reading update dir")?;
350350
let diff = currentf.diff(&updatef)?;
351-
self.ensure_mounted_esp(Path::new("/"))?;
352-
let destdir = self.open_esp().context("opening EFI dir")?;
353-
validate_esp(&destdir)?;
351+
352+
/* copy "lowest" directory that we need to make the change
353+
* e.g. we only affect EFI/fedora for example and not all of EFI
354+
*/
355+
let vendor = if let Some(v) = self.get_efi_vendor(&sysroot)? {
356+
v
357+
} else {
358+
bail!("Failed to get vendor dir");
359+
};
360+
361+
let esp = self.esp_path()?;
362+
let vendordir = esp.join(&vendor);
363+
let tmp_vendordir = esp.join(format!(".{vendor}.tmp"));
364+
// remove a previous directory if it exists in order to handle being interrupted in the middle.
365+
if tmp_vendordir.exists() {
366+
std::fs::remove_dir_all(&tmp_vendordir)?;
367+
}
368+
copy_dir(&vendordir, &tmp_vendordir)
369+
.with_context(|| "copying existing files to temp dir")?;
370+
assert!(tmp_vendordir.exists());
371+
372+
let tmpdir = sysroot.sub_dir(&vendordir)?;
373+
validate_esp(&tmpdir)?;
354374
log::trace!("applying diff: {}", &diff);
355-
filetree::apply_diff(&updated, &destdir, &diff, None)
356-
.context("applying filesystem changes")?;
375+
filetree::apply_diff(&updated, &tmpdir, &diff, None).context("applying filesystem changes to temp EFI")?;
376+
{
377+
let esp = self.open_esp()?;
378+
log::trace!(
379+
"doing local exchange for {} and {}",
380+
tmp_vendordir.display(),
381+
vendordir.display()
382+
);
383+
esp.local_exchange(&tmp_vendordir, &vendordir)
384+
.with_context(|| format!("local exchange for {:?} and {:?}", tmp_vendordir, vendordir))?;
385+
// finally remove the temp dir
386+
std::fs::remove_dir_all(&tmp_vendordir)
387+
.with_context(|| format!("clean up {:?}", tmp_vendordir))?;
388+
}
357389
let adopted_from = None;
358390
Ok(InstalledContent {
359391
meta: updatemeta,
@@ -580,6 +612,18 @@ fn find_file_recursive<P: AsRef<Path>>(dir: P, target_file: &str) -> Result<Vec<
580612
Ok(result)
581613
}
582614

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

0 commit comments

Comments
 (0)