checkout: Always replace existing content in overlay mode
authorColin Walters <walters@verbum.org>
Wed, 13 Mar 2024 16:50:28 +0000 (12:50 -0400)
committerColin Walters <walters@verbum.org>
Wed, 13 Mar 2024 18:07:54 +0000 (14:07 -0400)
The combination of the "honor whiteout" and "union" flags
are intended to basically be "merge trees like overlayfs does".
But we were missing this case in order to support e.g. replacing
a symlink with a directory.

src/libostree/ostree-repo-checkout.c
tests/basic-test.sh

index f50654552924b31c607f5bb76438a9385f75fc64..650604446db571fd6368c603b674dc491a27d99b 100644 (file)
@@ -1062,6 +1062,22 @@ checkout_tree_at_recurse (OstreeRepo *self, OstreeRepoCheckoutAtOptions *options
         if (!glnx_shutil_rm_rf_at (destination_parent_fd, destination_name, cancellable, error))
           return FALSE;
       }
+    else if (options->process_whiteouts
+             && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES)
+      {
+        /* In this mode, we're flattening in a manner similar to overlayfs, so ensure
+         * any non-directory content there is gone. /
+         */
+        struct stat stbuf;
+        if (!glnx_fstatat_allow_noent (destination_parent_fd, destination_name, &stbuf,
+                                       AT_SYMLINK_NOFOLLOW, error))
+          return FALSE;
+        if (errno == 0 && !S_ISDIR (stbuf.st_mode))
+          {
+            if (!glnx_shutil_rm_rf_at (destination_parent_fd, destination_name, cancellable, error))
+              return FALSE;
+          }
+      }
 
     /* Create initially with mode 0700, then chown/chmod only when we're
      * done.  This avoids anyone else being able to operate on partially
index 7905e6ee68d2038ab6ba4087648c007bd4fe85a1..c8f853f8d68d09def2ae48933f1e1b58d1a88a08 100644 (file)
@@ -1159,6 +1159,18 @@ if touch overlay/baz/.wh.cow && touch overlay/.wh.deeper && touch overlay/baz/an
     assert_has_file overlay-co/baz
     test -L overlay-co/anewdir
 
+    rm overlay-co overlay -rf
+    mkdir -p overlay/somelink overlay/yet/ovlnewdir
+    echo ovlnewf > overlay/yet/ovlnewdir/ovlnewf
+    $OSTREE --repo=repo commit ${COMMIT_ARGS} -b overlay-symlink-convert --tree=dir=overlay
+    for branch in test2 overlay-symlink-convert; do
+        $OSTREE --repo=repo checkout --union --whiteouts ${branch} overlay-co
+    done
+    test -d overlay-co/somelink || fatal "should replace symlink with dir"
+    assert_has_dir overlay-co/yet/another
+    assert_has_dir overlay-co/yet/ovlnewdir
+    assert_file_has_content overlay-co/yet/ovlnewdir/ovlnewf ovlnewf
+    rm overlay-co overlay -rf
     echo "ok whiteouts enabled"
 
     # Now double check whiteouts are not processed without --whiteouts