From 4116d56809feb0c7bafe0eb6cdf759cd1abafa4b Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Thu, 18 Jun 2020 11:44:00 +0100
Subject: [PATCH] tree-copy: Split into its own translation unit

Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 src/meson.build    |   2 +
 src/runtime.c      |   1 +
 src/tree-copy.c    | 173 +++++++++++++++++++++++++++++++++++++++++++++
 src/tree-copy.h    |  29 ++++++++
 src/utils.c        | 137 -----------------------------------
 src/utils.h        |   4 --
 tests/cheap-copy.c |   1 +
 7 files changed, 206 insertions(+), 141 deletions(-)
 create mode 100644 src/tree-copy.c
 create mode 100644 src/tree-copy.h

diff --git a/src/meson.build b/src/meson.build
index 0ac2f0a4f..27242f101 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -54,6 +54,8 @@ pressure_vessel_utils = static_library(
     'glib-backports.h',
     'resolve-in-sysroot.c',
     'resolve-in-sysroot.h',
+    'tree-copy.c',
+    'tree-copy.h',
     'utils.c',
     'utils.h',
   ],
diff --git a/src/runtime.c b/src/runtime.c
index c7dd569f7..c221a4d59 100644
--- a/src/runtime.c
+++ b/src/runtime.c
@@ -36,6 +36,7 @@
 #include "enumtypes.h"
 #include "flatpak-run-private.h"
 #include "resolve-in-sysroot.h"
+#include "tree-copy.h"
 #include "utils.h"
 
 /*
diff --git a/src/tree-copy.c b/src/tree-copy.c
new file mode 100644
index 000000000..8666668a0
--- /dev/null
+++ b/src/tree-copy.c
@@ -0,0 +1,173 @@
+/*
+ * Contains code taken from Flatpak.
+ *
+ * Copyright © 2014-2019 Red Hat, Inc
+ * Copyright © 2017-2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tree-copy.h"
+
+#include <ftw.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+
+#include "libglnx/libglnx.h"
+
+#include "glib-backports.h"
+#include "flatpak-bwrap-private.h"
+#include "flatpak-utils-base-private.h"
+#include "flatpak-utils-private.h"
+
+/* nftw() doesn't have a user_data argument so we need to use a global
+ * variable :-( */
+static struct
+{
+  gchar *source_root;
+  gchar *dest_root;
+  GError *error;
+} nftw_data;
+
+static int
+copy_tree_helper (const char *fpath,
+                  const struct stat *sb,
+                  int typeflag,
+                  struct FTW *ftwbuf)
+{
+  size_t len;
+  const char *suffix;
+  g_autofree gchar *dest = NULL;
+  g_autofree gchar *target = NULL;
+  GError **error = &nftw_data.error;
+
+  g_return_val_if_fail (g_str_has_prefix (fpath, nftw_data.source_root), 1);
+
+  if (strcmp (fpath, nftw_data.source_root) == 0)
+    {
+      if (typeflag != FTW_D)
+        {
+          glnx_throw (error, "\"%s\" is not a directory", fpath);
+          return 1;
+        }
+
+      if (!glnx_shutil_mkdir_p_at (-1, nftw_data.dest_root,
+                                   sb->st_mode & 07777, NULL, error))
+        return 1;
+
+      return 0;
+    }
+
+  len = strlen (nftw_data.source_root);
+  g_return_val_if_fail (fpath[len] == '/', 1);
+  suffix = &fpath[len + 1];
+  dest = g_build_filename (nftw_data.dest_root, suffix, NULL);
+
+  switch (typeflag)
+    {
+      case FTW_D:
+        if (!glnx_shutil_mkdir_p_at (-1, dest, sb->st_mode & 07777,
+                                     NULL, error))
+          return 1;
+        break;
+
+      case FTW_SL:
+        target = glnx_readlinkat_malloc (-1, fpath, NULL, error);
+
+        if (target == NULL)
+          return 1;
+
+        if (symlink (target, dest) != 0)
+          {
+            glnx_throw_errno_prefix (error,
+                                     "Unable to create symlink at \"%s\"",
+                                     dest);
+            return 1;
+          }
+        break;
+
+      case FTW_F:
+        /* Fast path: try to make a hard link. */
+        if (link (fpath, dest) == 0)
+          break;
+
+        /* Slow path: fall back to copying.
+         *
+         * This does a FICLONE or copy_file_range to get btrfs reflinks
+         * if possible, making the copy as cheap as cp --reflink=auto.
+         *
+         * Rather than second-guessing which errno values would result
+         * in link() failing but a copy succeeding, we just try it
+         * unconditionally - the worst that can happen is that this
+         * fails too. */
+        if (!glnx_file_copy_at (AT_FDCWD, fpath, sb,
+                                AT_FDCWD, dest,
+                                GLNX_FILE_COPY_OVERWRITE,
+                                NULL, error))
+          {
+            glnx_prefix_error (error, "Unable to copy \"%s\" to \"%s\"",
+                               fpath, dest);
+            return 1;
+          }
+        break;
+
+      default:
+        glnx_throw (&nftw_data.error,
+                    "Don't know how to handle ftw type flag %d at %s",
+                    typeflag, fpath);
+        return 1;
+    }
+
+  return 0;
+}
+
+gboolean
+pv_cheap_tree_copy (const char *source_root,
+                    const char *dest_root,
+                    GError **error)
+{
+  int res;
+
+  g_return_val_if_fail (source_root != NULL, FALSE);
+  g_return_val_if_fail (dest_root != NULL, FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+  /* Can't run concurrently */
+  g_return_val_if_fail (nftw_data.source_root == NULL, FALSE);
+
+  nftw_data.source_root = flatpak_canonicalize_filename (source_root);
+  nftw_data.dest_root = flatpak_canonicalize_filename (dest_root);
+  nftw_data.error = NULL;
+
+  res = nftw (nftw_data.source_root, copy_tree_helper, 100, FTW_PHYS);
+
+  if (res == -1)
+    {
+      g_assert (nftw_data.error == NULL);
+      glnx_throw_errno_prefix (error, "Unable to copy \"%s\" to \"%s\"",
+                               source_root, dest_root);
+    }
+  else if (res != 0)
+    {
+      g_propagate_error (error, g_steal_pointer (&nftw_data.error));
+    }
+
+  g_clear_pointer (&nftw_data.source_root, g_free);
+  g_clear_pointer (&nftw_data.dest_root, g_free);
+  g_assert (nftw_data.error == NULL);
+  return (res == 0);
+}
diff --git a/src/tree-copy.h b/src/tree-copy.h
new file mode 100644
index 000000000..b15e13fad
--- /dev/null
+++ b/src/tree-copy.h
@@ -0,0 +1,29 @@
+/*
+ * Contains code taken from Flatpak.
+ *
+ * Copyright © 2014-2019 Red Hat, Inc
+ * Copyright © 2017-2020 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <glib.h>
+
+gboolean pv_cheap_tree_copy (const char *source_root,
+                             const char *dest_root,
+                             GError **error);
diff --git a/src/utils.c b/src/utils.c
index 95f3bf803..e646399bd 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -286,143 +286,6 @@ pv_hash_table_get_arbitrary_key (GHashTable *table)
     return NULL;
 }
 
-/* nftw() doesn't have a user_data argument so we need to use a global
- * variable :-( */
-static struct
-{
-  gchar *source_root;
-  gchar *dest_root;
-  GError *error;
-} nftw_data;
-
-static int
-copy_tree_helper (const char *fpath,
-                  const struct stat *sb,
-                  int typeflag,
-                  struct FTW *ftwbuf)
-{
-  size_t len;
-  const char *suffix;
-  g_autofree gchar *dest = NULL;
-  g_autofree gchar *target = NULL;
-  GError **error = &nftw_data.error;
-
-  g_return_val_if_fail (g_str_has_prefix (fpath, nftw_data.source_root), 1);
-
-  if (strcmp (fpath, nftw_data.source_root) == 0)
-    {
-      if (typeflag != FTW_D)
-        {
-          glnx_throw (error, "\"%s\" is not a directory", fpath);
-          return 1;
-        }
-
-      if (!glnx_shutil_mkdir_p_at (-1, nftw_data.dest_root,
-                                   sb->st_mode & 07777, NULL, error))
-        return 1;
-
-      return 0;
-    }
-
-  len = strlen (nftw_data.source_root);
-  g_return_val_if_fail (fpath[len] == '/', 1);
-  suffix = &fpath[len + 1];
-  dest = g_build_filename (nftw_data.dest_root, suffix, NULL);
-
-  switch (typeflag)
-    {
-      case FTW_D:
-        if (!glnx_shutil_mkdir_p_at (-1, dest, sb->st_mode & 07777,
-                                     NULL, error))
-          return 1;
-        break;
-
-      case FTW_SL:
-        target = glnx_readlinkat_malloc (-1, fpath, NULL, error);
-
-        if (target == NULL)
-          return 1;
-
-        if (symlink (target, dest) != 0)
-          {
-            glnx_throw_errno_prefix (error,
-                                     "Unable to create symlink at \"%s\"",
-                                     dest);
-            return 1;
-          }
-        break;
-
-      case FTW_F:
-        /* Fast path: try to make a hard link. */
-        if (link (fpath, dest) == 0)
-          break;
-
-        /* Slow path: fall back to copying.
-         *
-         * This does a FICLONE or copy_file_range to get btrfs reflinks
-         * if possible, making the copy as cheap as cp --reflink=auto.
-         *
-         * Rather than second-guessing which errno values would result
-         * in link() failing but a copy succeeding, we just try it
-         * unconditionally - the worst that can happen is that this
-         * fails too. */
-        if (!glnx_file_copy_at (AT_FDCWD, fpath, sb,
-                                AT_FDCWD, dest,
-                                GLNX_FILE_COPY_OVERWRITE,
-                                NULL, error))
-          {
-            glnx_prefix_error (error, "Unable to copy \"%s\" to \"%s\"",
-                               fpath, dest);
-            return 1;
-          }
-        break;
-
-      default:
-        glnx_throw (&nftw_data.error,
-                    "Don't know how to handle ftw type flag %d at %s",
-                    typeflag, fpath);
-        return 1;
-    }
-
-  return 0;
-}
-
-gboolean
-pv_cheap_tree_copy (const char *source_root,
-                    const char *dest_root,
-                    GError **error)
-{
-  int res;
-
-  g_return_val_if_fail (source_root != NULL, FALSE);
-  g_return_val_if_fail (dest_root != NULL, FALSE);
-  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-  /* Can't run concurrently */
-  g_return_val_if_fail (nftw_data.source_root == NULL, FALSE);
-
-  nftw_data.source_root = flatpak_canonicalize_filename (source_root);
-  nftw_data.dest_root = flatpak_canonicalize_filename (dest_root);
-  nftw_data.error = NULL;
-
-  res = nftw (nftw_data.source_root, copy_tree_helper, 100, FTW_PHYS);
-
-  if (res == -1)
-    {
-      g_assert (nftw_data.error == NULL);
-      glnx_throw_errno_prefix (error, "Unable to copy \"%s\" to \"%s\"",
-                               source_root, dest_root);
-    }
-  else if (res != 0)
-    {
-      g_propagate_error (error, g_steal_pointer (&nftw_data.error));
-    }
-
-  g_clear_pointer (&nftw_data.source_root, g_free);
-  g_clear_pointer (&nftw_data.dest_root, g_free);
-  g_assert (nftw_data.error == NULL);
-  return (res == 0);
-}
-
 static gint
 ftw_remove (const gchar *path,
             const struct stat *sb,
diff --git a/src/utils.h b/src/utils.h
index 3d89b7ced..0966efedb 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -54,10 +54,6 @@ gchar *pv_capture_output (const char * const * argv,
 
 gpointer pv_hash_table_get_arbitrary_key (GHashTable *table);
 
-gboolean pv_cheap_tree_copy (const char *source_root,
-                             const char *dest_root,
-                             GError **error);
-
 gboolean pv_rm_rf (const char *directory);
 
 gboolean pv_boolean_environment (const gchar *name,
diff --git a/tests/cheap-copy.c b/tests/cheap-copy.c
index 9a5bf686c..912da297e 100644
--- a/tests/cheap-copy.c
+++ b/tests/cheap-copy.c
@@ -26,6 +26,7 @@
 #include "libglnx/libglnx.h"
 
 #include "glib-backports.h"
+#include "tree-copy.h"
 #include "utils.h"
 
 static GOptionEntry options[] =
-- 
GitLab