From d66dfc2815153b315f5b3fd9d3f93be670def26a Mon Sep 17 00:00:00 2001 From: Jaroslav Rohel 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 #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -41,9 +43,6 @@ extern "C" { #include } -// glib -#include - // 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 +#include + +#include + #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(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