Skip to content

Commit b8fd9a9

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

File tree

1 file changed

+51
-4
lines changed

1 file changed

+51
-4
lines changed

src/efi.rs

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

622+
fn copy_dir(src: &Path, dst: &Path) -> Result<()> {
623+
let r = std::process::Command::new("cp")
624+
.args(["-a"])
625+
.arg(src)
626+
.arg(dst)
627+
.status()?;
628+
if !r.success() {
629+
anyhow::bail!("Failed to copy");
630+
}
631+
Ok(())
632+
}
633+
587634
#[cfg(test)]
588635
mod tests {
589636
use super::*;

0 commit comments

Comments
 (0)