28c6a56
From f641455c06f18da52bf7fd9c5228d6e3c5ce1453 Mon Sep 17 00:00:00 2001
28c6a56
From: "Owen W. Taylor" <otaylor@fishsoup.net>
28c6a56
Date: Fri, 20 Oct 2023 11:26:17 -0400
28c6a56
Subject: [PATCH] Docker.py: Pass the use_ino option to fix hardlnks
28c6a56
28c6a56
When use libguestfs to mount the intermediate image to create a tarball,
28c6a56
pass the "use_ino" option so that original inode numbers are preserved.
28c6a56
This fixes a problem where hardlinks were not properly preserved in the
28c6a56
output.
28c6a56
28c6a56
This is a minimal-code-change fix - an edge case bug and better approach are
28c6a56
described in comments.
28c6a56
28c6a56
Resolves #412
28c6a56
---
28c6a56
 imagefactory_plugins/Docker/Docker.py | 22 +++++++++++++++++++++-
28c6a56
 1 file changed, 21 insertions(+), 1 deletion(-)
28c6a56
28c6a56
diff --git a/imagefactory_plugins/Docker/Docker.py b/imagefactory_plugins/Docker/Docker.py
28c6a56
index 68e12c3926bb..960b0e43325c 100644
28c6a56
--- a/imagefactory_plugins/Docker/Docker.py
28c6a56
+++ b/imagefactory_plugins/Docker/Docker.py
28c6a56
@@ -312,12 +312,32 @@ class Docker(object):
28c6a56
         # we call a blocking function to activate the mount, which requires a thread
28c6a56
         # We also need a temp dir to mount it to - do our best to clean up when things
28c6a56
         # go wrong
28c6a56
+        #
28c6a56
+        # A better approach here would be to use:
28c6a56
+        #   g.tar_out_opts("/", dest_filename, excludes=[excludes])
28c6a56
+        # Though that would break compatibility with the tar_options parameter.
28c6a56
+        #
28c6a56
         tempdir = None
28c6a56
         fuse_thread = None
28c6a56
         try:
28c6a56
             tempdir = tempfile.mkdtemp(dir=storagedir)
28c6a56
             self.log.debug("Mounting input image locally at (%s)" % (tempdir))
28c6a56
-            guestfs_handle.mount_local(tempdir)
28c6a56
+
28c6a56
+            # The "use_ino" option causes FUSE to pass through the original inode
28c6a56
+            # numbers. Without it tar cannot properly detect hardlinks, possibly greatly
28c6a56
+            # increasing the size of the image.  This does create an edge case. If there
28c6a56
+            # are:
28c6a56
+            #
28c6a56
+            #  - Two separate groups of > 1 files hardlinked together
28c6a56
+            #  - On different partitions
28c6a56
+            #  - With the same inode number
28c6a56
+            #
28c6a56
+            # Then the groups will be incorrectly merged in the output image. This
28c6a56
+            # is unlikely to be encountered with typical container images, where almost
28c6a56
+            # all files are on a single partition. The correct fix is to use
28c6a56
+            # g.tar_out_opts() as described above.
28c6a56
+
28c6a56
+            guestfs_handle.mount_local(tempdir, options="use_ino")
28c6a56
             def _run_guestmount(g):
28c6a56
                 g.mount_local_run()
28c6a56
             self.log.debug("Launching mount_local_run thread")
28c6a56
-- 
28c6a56
2.41.0
28c6a56