A wrapper for atomically writing a file, also optionally setting a SELinux label.
(
root: &Dir,
destname: impl AsRef<Utf8Path>,
mode: rustix::fs::Mode,
policy: Option<&ostree::SePolicy>,
f: F,
)
| 523 | |
| 524 | /// A wrapper for atomically writing a file, also optionally setting a SELinux label. |
| 525 | pub(crate) fn atomic_replace_labeled<F>( |
| 526 | root: &Dir, |
| 527 | destname: impl AsRef<Utf8Path>, |
| 528 | mode: rustix::fs::Mode, |
| 529 | policy: Option<&ostree::SePolicy>, |
| 530 | f: F, |
| 531 | ) -> Result<()> |
| 532 | where |
| 533 | F: FnOnce(&mut std::io::BufWriter<cap_std_ext::cap_tempfile::TempFile>) -> Result<()>, |
| 534 | { |
| 535 | let destname = destname.as_ref(); |
| 536 | let label = policy |
| 537 | .map(|policy| { |
| 538 | let abs_destname = Utf8Path::new("/").join(destname); |
| 539 | require_label(policy, &abs_destname, libc::S_IFREG | mode.as_raw_mode()) |
| 540 | }) |
| 541 | .transpose()?; |
| 542 | |
| 543 | root.atomic_replace_with(destname, |w| { |
| 544 | // Peel through the bufwriter to get the fd |
| 545 | let fd = w.get_mut(); |
| 546 | let fd = fd.as_file_mut(); |
| 547 | let fd = fd.as_fd(); |
| 548 | // Apply the target mode bits |
| 549 | rustix::fs::fchmod(fd, mode).context("fchmod")?; |
| 550 | // If we have a label, apply it |
| 551 | if let Some(label) = label { |
| 552 | tracing::debug!("Setting label for {destname} to {label}"); |
| 553 | set_security_selinux(fd, label.as_bytes())?; |
| 554 | } else { |
| 555 | tracing::debug!("No label for {destname}"); |
| 556 | } |
| 557 | // Finally call the underlying writer function |
| 558 | f(w) |
| 559 | }) |
| 560 | } |
| 561 | |
| 562 | #[cfg(test)] |
| 563 | mod tests { |
no test coverage detected