Blame SOURCES/0001-compose-Handle-embedded-whiteouts.patch

bee4a9
From 0049dbdd91cc0c1900132374645c5114063db04d Mon Sep 17 00:00:00 2001
bee4a9
From: Colin Walters <walters@verbum.org>
bee4a9
Date: Thu, 29 Sep 2022 14:01:07 -0400
bee4a9
Subject: [PATCH] compose: Handle embedded whiteouts
bee4a9
bee4a9
This pairs with
bee4a9
https://github.com/ostreedev/ostree/pull/2722/commits/0085494e350c72599fc5c0e00422885d80b3c660
bee4a9
bee4a9
Basically, while I think it'd make sense actually for the baseline
bee4a9
`ostree commit` process to handle this, for now let's put it
bee4a9
here in rpm-ostree (where it can be in Rust too).  Though
bee4a9
a definite negative is that we're now traversing the whole filesystem
bee4a9
again.
bee4a9
bee4a9
(cherry picked from commit fea26bdd5db59fcf0853a9bb4ab6dcb340be9470)
bee4a9
---
bee4a9
 rust/src/composepost.rs           | 63 ++++++++++++++++++++++++++++++-
bee4a9
 tests/compose/test-installroot.sh |  8 ++++
bee4a9
 2 files changed, 70 insertions(+), 1 deletion(-)
bee4a9
bee4a9
diff --git a/rust/src/composepost.rs b/rust/src/composepost.rs
bee4a9
index ab5cc176..70a01497 100644
bee4a9
--- a/rust/src/composepost.rs
bee4a9
+++ b/rust/src/composepost.rs
bee4a9
@@ -202,6 +202,47 @@ fn postprocess_presets(rootfs_dfd: &Dir) -> Result<()> {
bee4a9
     Ok(())
bee4a9
 }
bee4a9
 
bee4a9
+fn is_overlay_whiteout(meta: &cap_std::fs::Metadata) -> bool {
bee4a9
+    (meta.mode() & libc::S_IFMT) == libc::S_IFCHR && meta.rdev() == 0
bee4a9
+}
bee4a9
+
bee4a9
+/// Auto-synthesize embedded overlayfs whiteouts; for more information
bee4a9
+/// see https://github.com/ostreedev/ostree/pull/2722/commits/0085494e350c72599fc5c0e00422885d80b3c660
bee4a9
+#[context("Postprocessing embedded overlayfs")]
bee4a9
+fn postprocess_embedded_ovl_whiteouts(root: &Dir) -> Result<()> {
bee4a9
+    const OSTREE_WHITEOUT_PREFIX: &str = ".ostree-wh.";
bee4a9
+    fn recurse(root: &Dir, path: &Utf8Path) -> Result<u32> {
bee4a9
+        let mut n = 0;
bee4a9
+        for entry in root.read_dir(path)? {
bee4a9
+            let entry = entry?;
bee4a9
+            let meta = entry.metadata()?;
bee4a9
+            let name = PathBuf::from(entry.file_name());
bee4a9
+            let name: Utf8PathBuf = name.try_into()?;
bee4a9
+            if meta.is_dir() {
bee4a9
+                n += recurse(root, &path.join(name))?;
bee4a9
+                continue;
bee4a9
+            }
bee4a9
+            if !is_overlay_whiteout(&meta) {
bee4a9
+                continue;
bee4a9
+            };
bee4a9
+            let srcpath = path.join(&name);
bee4a9
+            let targetname = format!("{OSTREE_WHITEOUT_PREFIX}{name}");
bee4a9
+            let destpath = path.join(&targetname);
bee4a9
+            root.remove_file(srcpath)?;
bee4a9
+            root.atomic_write_with_perms(destpath, "", meta.permissions())?;
bee4a9
+            n += 1;
bee4a9
+        }
bee4a9
+        Ok(n)
bee4a9
+    }
bee4a9
+    let n = recurse(root, ".".into())?;
bee4a9
+    if n > 0 {
bee4a9
+        println!("Processed {n} embedded whiteouts");
bee4a9
+    } else {
bee4a9
+        println!("No embedded whiteouts found");
bee4a9
+    }
bee4a9
+    Ok(())
bee4a9
+}
bee4a9
+
bee4a9
 /// Write an RPM macro file to ensure the rpmdb path is set on the client side.
bee4a9
 pub fn compose_postprocess_rpm_macro(rootfs_dfd: i32) -> CxxResult<()> {
bee4a9
     let rootfs = unsafe { &crate::ffiutil::ffi_dirfd(rootfs_dfd)? };
bee4a9
@@ -290,13 +331,17 @@ pub(crate) fn postprocess_cleanup_rpmdb(rootfs_dfd: i32) -> CxxResult<()> {
bee4a9
 /// on the target host.
bee4a9
 pub fn compose_postprocess_final(rootfs_dfd: i32) -> CxxResult<()> {
bee4a9
     let rootfs_dfd = unsafe { &crate::ffiutil::ffi_dirfd(rootfs_dfd)? };
bee4a9
+    // These tasks can safely run in parallel, so just for fun we do so via rayon.
bee4a9
     let tasks = [
bee4a9
         postprocess_useradd,
bee4a9
         postprocess_presets,
bee4a9
         postprocess_subs_dist,
bee4a9
         postprocess_rpm_macro,
bee4a9
     ];
bee4a9
-    Ok(tasks.par_iter().try_for_each(|f| f(rootfs_dfd))?)
bee4a9
+    tasks.par_iter().try_for_each(|f| f(rootfs_dfd))?;
bee4a9
+    // This task recursively traverses the filesystem and hence should be serial.
bee4a9
+    postprocess_embedded_ovl_whiteouts(rootfs_dfd)?;
bee4a9
+    Ok(())
bee4a9
 }
bee4a9
 
bee4a9
 #[context("Handling treefile 'units'")]
bee4a9
@@ -1290,6 +1335,22 @@ OSTREE_VERSION='33.4'
bee4a9
         Ok(())
bee4a9
     }
bee4a9
 
bee4a9
+    #[test]
bee4a9
+    fn test_overlay() -> Result<()> {
bee4a9
+        // We don't actually test creating whiteout devices here as that
bee4a9
+        // may not work.
bee4a9
+        let td = cap_tempfile::tempdir(cap_std::ambient_authority())?;
bee4a9
+        // Verify no-op case
bee4a9
+        postprocess_embedded_ovl_whiteouts(&td).unwrap();
bee4a9
+        td.create("foo")?;
bee4a9
+        td.symlink("foo", "bar")?;
bee4a9
+        postprocess_embedded_ovl_whiteouts(&td).unwrap();
bee4a9
+        assert!(td.try_exists("foo")?);
bee4a9
+        assert!(td.try_exists("bar")?);
bee4a9
+
bee4a9
+        Ok(())
bee4a9
+    }
bee4a9
+
bee4a9
     #[test]
bee4a9
     fn test_tmpfiles_d_translation() {
bee4a9
         use nix::sys::stat::{umask, Mode};
bee4a9
diff --git a/tests/compose/test-installroot.sh b/tests/compose/test-installroot.sh
bee4a9
index 1ac09b9a..3e40f679 100755
bee4a9
--- a/tests/compose/test-installroot.sh
bee4a9
+++ b/tests/compose/test-installroot.sh
bee4a9
@@ -54,6 +54,8 @@ echo "ok postprocess with treefile"
bee4a9
 
bee4a9
 testdate=$(date)
bee4a9
 runasroot sh -xec "
bee4a9
+# https://github.com/ostreedev/ostree/pull/2717/commits/e234b630f85b97e48ecf45d5aaba9b1aa64e6b54
bee4a9
+mknod -m 000 ${instroot}-directcommit/usr/share/foowhiteout c 0 0
bee4a9
 echo \"${testdate}\" > ${instroot}-directcommit/usr/share/rpm-ostree-composetest-split.txt
bee4a9
 ! test -f ${instroot}-directcommit/${integrationconf}
bee4a9
 rpm-ostree compose commit --repo=${repo} ${treefile} ${instroot}-directcommit
bee4a9
@@ -61,6 +63,12 @@ ostree --repo=${repo} ls ${treeref} /usr/bin/bash
bee4a9
 if ostree --repo=${repo} ls ${treeref} /var/lib/rpm >/dev/null; then
bee4a9
   echo found /var/lib/rpm in commit 1>&2; exit 1
bee4a9
 fi
bee4a9
+
bee4a9
+# Verify whiteout renames
bee4a9
+ostree --repo=${repo} ls ${treeref} /usr/share
bee4a9
+ostree --repo=${repo} ls ${treeref} /usr/share/.ostree-wh.foowhiteout >out.txt
bee4a9
+grep -Ee '^-00000' out.txt
bee4a9
+
bee4a9
 ostree --repo=${repo} cat ${treeref} /usr/share/rpm-ostree-composetest-split.txt >out.txt
bee4a9
 grep \"${testdate}\" out.txt
bee4a9
 ostree --repo=${repo} cat ${treeref} /${integrationconf}
bee4a9
-- 
bee4a9
2.38.1
bee4a9