From d66dfc2815153b315f5b3fd9d3f93be670def26a Mon Sep 17 00:00:00 2001
From: Jaroslav Rohel <jrohel@redhat.com>
Date: Tue, 3 Sep 2019 12:55:51 +0200
Subject: [PATCH 09/10] Added dnf_move_recursive()
Moves a directory and its contents. If native move operations are
supported then this is used, otherwise a copy + delete fallback is used.
---
libdnf/hy-iutil-private.hpp | 1 +
libdnf/hy-iutil.cpp | 95 +++++++++++++++++++++++++++++++++++--
2 files changed, 93 insertions(+), 3 deletions(-)
diff --git a/libdnf/hy-iutil-private.hpp b/libdnf/hy-iutil-private.hpp
index 8b2b06d5..4920ad39 100644
--- a/libdnf/hy-iutil-private.hpp
+++ b/libdnf/hy-iutil-private.hpp
@@ -41,6 +41,7 @@ char *abspath(const char *path);
int is_readable_rpm(const char *fn);
int mkcachedir(char *path);
gboolean mv(const char *old_path, const char *new_path, GError **error);
+gboolean dnf_move_recursive(const gchar *src_dir, const gchar *dst_dir, GError **error);
char *this_username(void);
/* misc utils */
diff --git a/libdnf/hy-iutil.cpp b/libdnf/hy-iutil.cpp
index 2c5af481..d3b57c79 100644
--- a/libdnf/hy-iutil.cpp
+++ b/libdnf/hy-iutil.cpp
@@ -20,12 +20,14 @@
#include <assert.h>
#include <errno.h>
+#include <dirent.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <pwd.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
@@ -41,9 +43,6 @@ extern "C" {
#include <solv/pool_parserpmrichdep.h>
}
-// glib
-#include <glib.h>
-
// hawkey
#include "dnf-advisory-private.hpp"
#include "dnf-types.h"
@@ -58,6 +57,12 @@ extern "C" {
#include "utils/bgettext/bgettext-lib.h"
#include "sack/packageset.hpp"
+// glib
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <string>
+
#define BUF_BLOCK 4096
#define CHKSUM_TYPE REPOKEY_TYPE_SHA256
#define CHKSUM_IDENT "H000"
@@ -328,6 +333,90 @@ mv(const char* old_path, const char* new_path, GError** error)
return TRUE;
}
+static gboolean
+copyFile(const std::string & srcPath, const std::string & dstPath, GError ** error)
+{
+ g_autoptr(GFile) src = g_file_new_for_path(srcPath.c_str());
+ g_autoptr(GFile) dest = g_file_new_for_path(dstPath.c_str());
+ return g_file_copy(src, dest,
+ static_cast<GFileCopyFlags>(G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA)
+ , NULL, NULL, NULL, error);
+}
+
+static gboolean
+copyRecursive(const std::string & srcPath, const std::string & dstPath, GError ** error)
+{
+ struct stat info;
+ if (!stat(srcPath.c_str(), &info)) {
+ if (S_ISDIR(info.st_mode)) {
+ if (mkdir(dstPath.c_str(), info.st_mode) == -1) {
+ auto err = errno;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("cannot create directory %1$s: %2$s"),
+ dstPath.c_str(), strerror(err));
+ return FALSE;
+ }
+ if (auto fd = opendir(srcPath.c_str())) {
+ int ret = TRUE;
+ while (auto dent = readdir(fd)) {
+ auto name = dent->d_name;
+ if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
+ continue;
+ std::string srcItem = srcPath + "/" + name;
+ std::string dstItem = dstPath + "/" + name;
+ ret = copyRecursive(srcItem, dstItem, error);
+ if (!ret)
+ break;
+ }
+ closedir(fd);
+ return ret;
+ } else {
+ auto err = errno;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("cannot open directory %1$s: %2$s"),
+ srcPath.c_str(), strerror(err));
+ return FALSE;
+ }
+ } else {
+ return copyFile(srcPath, dstPath, error);
+ }
+ } else {
+ auto err = errno;
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_INTERNAL_ERROR,
+ _("cannot stat path %1$s: %2$s"),
+ srcPath.c_str(), strerror(err));
+ return FALSE;
+ }
+}
+
+/**
+ * dnf_move_recursive:
+ * @src_dir: A source directory path
+ * @dst_dir: A destination directory path
+ * @error: A #GError, or %NULL
+ *
+ * Moves a directory and its contents. Native move is preferred,
+ * if not supported copy and delete fallback is used.
+ *
+ * Returns: %TRUE on successful move, %FALSE otherwise
+ **/
+gboolean
+dnf_move_recursive(const char * srcDir, const char * dstDir, GError ** error)
+{
+ if (rename(srcDir, dstDir) == -1) {
+ if (!copyRecursive(srcDir, dstDir, error))
+ return FALSE;
+ return dnf_remove_recursive(srcDir, error);
+ }
+ return TRUE;
+}
+
char *
this_username(void)
{
--
2.21.0