Skip to content

Commit ad56520

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 ad56520

File tree

1 file changed

+50
-5
lines changed

1 file changed

+50
-5
lines changed

src/efi.rs

+50-5
Original file line numberDiff line numberDiff line change
@@ -348,12 +348,45 @@ 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(&tmp_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)
376+
.context("applying filesystem changes to temp EFI")?;
377+
{
378+
let esp = self.open_esp()?;
379+
log::trace!(
380+
"doing local exchange for {} and {}",
381+
tmp_vendordir.display(),
382+
vendordir.display()
383+
);
384+
esp.local_exchange(&tmp_vendordir, &vendordir)
385+
.with_context(|| format!("exchange for {:?} and {:?}", tmp_vendordir, vendordir))?;
386+
// finally remove the temp dir
387+
let tmp_vendordir = esp.sub_dir(format!(".{vendor}.tmp"))?;
388+
std::fs::remove_dir_all(tmp_vendordir.recover_path()?).context("clean up temp")?;
389+
}
357390
let adopted_from = None;
358391
Ok(InstalledContent {
359392
meta: updatemeta,
@@ -580,6 +613,18 @@ fn find_file_recursive<P: AsRef<Path>>(dir: P, target_file: &str) -> Result<Vec<
580613
Ok(result)
581614
}
582615

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

0 commit comments

Comments
 (0)