From: Joel Rosdahl Date: Tue, 28 Jul 2020 07:03:05 +0000 (+0200) Subject: C++-ify {clone,copy,move}_file X-Git-Tag: v4.0~278 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a3f75ec9b1725bf519bd85a15f1283aa9bf0d94d;p=thirdparty%2Fccache.git C++-ify {clone,copy,move}_file --- diff --git a/src/MiniTrace.cpp b/src/MiniTrace.cpp index f82b27e10..07b6af079 100644 --- a/src/MiniTrace.cpp +++ b/src/MiniTrace.cpp @@ -27,6 +27,7 @@ # include "legacy_util.hpp" namespace { + std::string get_system_tmp_dir() { @@ -66,12 +67,9 @@ MiniTrace::~MiniTrace() mtr_shutdown(); if (!m_args_info.output_obj.empty()) { - std::string trace_file = - fmt::format("{}.ccache-trace", m_args_info.output_obj); - move_file(m_tmp_trace_file.c_str(), trace_file.c_str()); - } else { - Util::unlink_tmp(m_tmp_trace_file.c_str()); + Util::copy_file(m_tmp_trace_file, m_args_info.output_obj + ".ccache-trace"); } + Util::unlink_tmp(m_tmp_trace_file); } #endif diff --git a/src/Result.cpp b/src/Result.cpp index 68e5771ae..b5d76a2dc 100644 --- a/src/Result.cpp +++ b/src/Result.cpp @@ -401,9 +401,11 @@ Result::Writer::write_raw_file_entry(const std::string& path, { auto raw_file = get_raw_file_path(m_result_path, entry_number); auto old_stat = Stat::stat(raw_file); - if (!Util::clone_hard_link_or_copy_file(m_ctx, path, raw_file, true)) { - throw Error( - fmt::format("Failed to store {} as raw file {}", path, raw_file)); + try { + Util::clone_hard_link_or_copy_file(m_ctx, path, raw_file, true); + } catch (Error& e) { + throw Error(fmt::format( + "Failed to store {} as raw file {}: {}", path, raw_file, e.what())); } auto new_stat = Stat::stat(raw_file); stats_update_size(m_ctx.counter_updates, diff --git a/src/ResultExtractor.cpp b/src/ResultExtractor.cpp index 4409b0644..61349b05e 100644 --- a/src/ResultExtractor.cpp +++ b/src/ResultExtractor.cpp @@ -58,10 +58,13 @@ ResultExtractor::on_entry_start(uint32_t /*entry_number*/, throw Error(fmt::format( "Failed to open {} for writing: {}", m_dest_path, strerror(errno))); } - - } else if (!copy_file(raw_file->c_str(), m_dest_path.c_str(), false)) { - throw Error(fmt::format( - "Failed to copy {} to {}: {}", *raw_file, m_dest_path, strerror(errno))); + } else { + try { + Util::copy_file(*raw_file, m_dest_path, false); + } catch (Error& e) { + throw Error(fmt::format( + "Failed to copy {} to {}: {}", *raw_file, m_dest_path, e.what())); + } } } diff --git a/src/Util.cpp b/src/Util.cpp index 61b9506ed..6644962a7 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -22,6 +22,7 @@ #include "Context.hpp" #include "Fd.hpp" #include "FormatNonstdStringView.hpp" +#include "TemporaryFile.hpp" #include "legacy_util.hpp" #include "logging.hpp" @@ -40,6 +41,26 @@ # include "win32compat.hpp" #endif +#ifdef __linux__ +# ifdef HAVE_SYS_IOCTL_H +# include +# endif +# ifdef HAVE_LINUX_FS_H +# include +# ifndef FICLONE +# define FICLONE _IOW(0x94, 9, int) +# endif +# define FILE_CLONING_SUPPORTED 1 +# endif +#endif + +#ifdef __APPLE__ +# ifdef HAVE_SYS_CLONEFILE_H +# include +# define FILE_CLONING_SUPPORTED 1 +# endif +#endif + using nonstd::string_view; namespace { @@ -141,7 +162,64 @@ change_extension(string_view path, string_view new_ext) return std::string(without_ext).append(new_ext.data(), new_ext.length()); } -bool +void +clone_file(const std::string& src, const std::string& dest, bool via_tmp_file) +{ +#ifdef FILE_CLONING_SUPPORTED + +# if defined(__linux__) + Fd src_fd(open(src.c_str(), O_RDONLY)); + if (!src_fd) { + throw Error(fmt::format("{}: {}", src, strerror(errno))); + } + + Fd dest_fd; + std::string tmp_file; + if (via_tmp_file) { + TemporaryFile temp_file(dest); + dest_fd = std::move(temp_file.fd); + tmp_file = temp_file.path; + } else { + dest_fd = + Fd(open(dest.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)); + if (!dest_fd) { + throw Error(fmt::format("{}: {}", src, strerror(errno))); + } + } + + if (ioctl(*dest_fd, FICLONE, *src_fd) != 0) { + throw Error(strerror(errno)); + } + + dest_fd.close(); + src_fd.close(); + + if (via_tmp_file && x_rename(tmp_file.c_str(), dest.c_str()) != 0) { + throw Error(strerror(errno)); + } +# elif defined(__APPLE__) + (void)via_tmp_file; + if (clonefile(src.c_str(), dest.c_str(), CLONE_NOOWNERCOPY) != 0) { + throw Error(strerror(errno)); + } +# else + (void)src; + (void)dest; + (void)via_tmp_file; + throw Error(strerror(EOPNOTSUPP)); +# endif + +#else // FILE_CLONING_SUPPORTED + + (void)src; + (void)dest; + (void)via_tmp_file; + throw Error(strerror(EOPNOTSUPP)); + +#endif // FILE_CLONING_SUPPORTED +} + +void clone_hard_link_or_copy_file(const Context& ctx, const std::string& source, const std::string& dest, @@ -149,10 +227,12 @@ clone_hard_link_or_copy_file(const Context& ctx, { if (ctx.config.file_clone()) { cc_log("Cloning %s to %s", source.c_str(), dest.c_str()); - if (clone_file(source.c_str(), dest.c_str(), via_tmp_file)) { - return true; + try { + clone_file(source, dest, via_tmp_file); + return; + } catch (Error& e) { + cc_log("Failed to clone: %s", e.what()); } - cc_log("Failed to clone: %s", strerror(errno)); } if (ctx.config.hard_link()) { unlink(dest.c_str()); @@ -162,13 +242,13 @@ clone_hard_link_or_copy_file(const Context& ctx, if (chmod(dest.c_str(), 0444) != 0) { cc_log("Failed to chmod: %s", strerror(errno)); } - return true; + return; } cc_log("Failed to hard link: %s", strerror(errno)); } cc_log("Copying %s to %s", source.c_str(), dest.c_str()); - return copy_file(source.c_str(), dest.c_str(), via_tmp_file); + copy_file(source, dest, via_tmp_file); } size_t @@ -201,6 +281,40 @@ common_dir_prefix_length(string_view dir, string_view path) return i; } +void +copy_file(const std::string& src, const std::string& dest, bool via_tmp_file) +{ + Fd src_fd(open(src.c_str(), O_RDONLY)); + if (!src_fd) { + throw Error(fmt::format("{}: {}", src, strerror(errno))); + } + + Fd dest_fd; + std::string tmp_file; + if (via_tmp_file) { + TemporaryFile temp_file(dest); + dest_fd = std::move(temp_file.fd); + tmp_file = temp_file.path; + } else { + dest_fd = + Fd(open(dest.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)); + if (!dest_fd) { + throw Error(fmt::format("{}: {}", dest, strerror(errno))); + } + } + + if (!copy_fd(*src_fd, *dest_fd)) { + throw Error(strerror(errno)); + } + + dest_fd.close(); + src_fd.close(); + + if (via_tmp_file && x_rename(tmp_file.c_str(), dest.c_str()) != 0) { + throw Error(strerror(errno)); + } +} + bool create_dir(string_view dir) { diff --git a/src/Util.hpp b/src/Util.hpp index ca10f4bae..0f9b9b356 100644 --- a/src/Util.hpp +++ b/src/Util.hpp @@ -83,19 +83,31 @@ big_endian_to_int(const uint8_t* buffer, uint8_t& value) std::string change_extension(nonstd::string_view path, nonstd::string_view new_ext); +// Clone a file from `src` to `dest`. If `via_tmp_file` is true, `src` is cloned +// to a temporary file and then renamed to `dest`. Throws `Error` on error. +void clone_file(const std::string& src, + const std::string& dest, + bool via_tmp_file = false); + // Clone, hard link or copy a file from `source` to `dest` depending on settings // in `ctx`. If cloning or hard linking cannot and should not be done the file -// will be copied instead. Returns true if successful otherwise false. -bool clone_hard_link_or_copy_file(const Context& ctx, +// will be copied instead. Throws `Error` on error. +void clone_hard_link_or_copy_file(const Context& ctx, const std::string& source, const std::string& dest, - bool via_tmp_file); + bool via_tmp_file = false); // Compute the length of the longest directory path that is common to paths // `dir` (a directory) and `path` (any path). size_t common_dir_prefix_length(nonstd::string_view dir, nonstd::string_view path); +// Copy a file from `src` to `dest`. If via_tmp_file is true, `src` is copied to +// a temporary file and then renamed to dest. Throws `Error` on error. +void copy_file(const std::string& src, + const std::string& dest, + bool via_tmp_file = false); + // Create a directory if needed, including its parents if needed. // // Returns true if the directory exists or could be created, otherwise false. diff --git a/src/legacy_util.cpp b/src/legacy_util.cpp index cc08056db..24edc6aaa 100644 --- a/src/legacy_util.cpp +++ b/src/legacy_util.cpp @@ -20,8 +20,6 @@ #include "legacy_util.hpp" #include "Fd.hpp" -#include "TemporaryFile.hpp" -#include "Util.hpp" #include "exceptions.hpp" #include "logging.hpp" @@ -29,10 +27,6 @@ # include "win32compat.hpp" #endif -#include "third_party/fmt/core.h" - -#include - #ifdef HAVE_PWD_H # include #endif @@ -40,26 +34,6 @@ # include #endif -#ifdef __linux__ -# ifdef HAVE_SYS_IOCTL_H -# include -# endif -# ifdef HAVE_LINUX_FS_H -# include -# ifndef FICLONE -# define FICLONE _IOW(0x94, 9, int) -# endif -# define FILE_CLONING_SUPPORTED 1 -# endif -#endif - -#ifdef __APPLE__ -# ifdef HAVE_SYS_CLONEFILE_H -# include -# define FILE_CLONING_SUPPORTED 1 -# endif -#endif - // Something went badly wrong! void fatal(const char* format, ...) @@ -110,123 +84,6 @@ copy_fd(int fd_in, int fd_out) return true; } -// Clone a file from src to dest. If via_tmp_file is true, the file is cloned -// to a temporary file and then renamed to dest. -bool -clone_file(const char* src, const char* dest, bool via_tmp_file) -{ -#ifdef FILE_CLONING_SUPPORTED - bool result; - -# if defined(__linux__) - Fd src_fd(open(src, O_RDONLY)); - if (!src_fd) { - return false; - } - - Fd dest_fd; - char* tmp_file = nullptr; - if (via_tmp_file) { - TemporaryFile temp_file(dest); - dest_fd = std::move(temp_file.fd); - tmp_file = x_strdup(temp_file.path.c_str()); - } else { - dest_fd = Fd(open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)); - if (!dest_fd) { - return false; - } - } - - int saved_errno = 0; - if (ioctl(*dest_fd, FICLONE, *src_fd) == 0) { - result = true; - } else { - result = false; - saved_errno = errno; - } - - dest_fd.close(); - src_fd.close(); - - if (via_tmp_file) { - if (x_rename(tmp_file, dest) != 0) { - result = false; - } - free(tmp_file); - } - - errno = saved_errno; -# elif defined(__APPLE__) - (void)via_tmp_file; - result = clonefile(src, dest, CLONE_NOOWNERCOPY) == 0; -# endif - - return result; - -#else // FILE_CLONING_SUPPORTED - - (void)src; - (void)dest; - (void)via_tmp_file; - errno = EOPNOTSUPP; - return false; - -#endif // FILE_CLONING_SUPPORTED -} - -// Copy a file from src to dest. If via_tmp_file is true, the file is copied to -// a temporary file and then renamed to dest. -bool -copy_file(const char* src, const char* dest, bool via_tmp_file) -{ - bool result = false; - - Fd src_fd(open(src, O_RDONLY)); - if (!src_fd) { - return false; - } - - Fd dest_fd; - char* tmp_file = nullptr; - if (via_tmp_file) { - TemporaryFile temp_file(dest); - dest_fd = std::move(temp_file.fd); - tmp_file = x_strdup(temp_file.path.c_str()); - } else { - dest_fd = Fd(open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)); - if (!dest_fd) { - return false; - } - } - - if (copy_fd(*src_fd, *dest_fd)) { - result = true; - } - - dest_fd.close(); - src_fd.close(); - - if (via_tmp_file) { - if (x_rename(tmp_file, dest) != 0) { - result = false; - } - free(tmp_file); - } - - return result; -} - -// Run copy_file() and, if successful, delete the source file. -bool -move_file(const char* src, const char* dest) -{ - bool ok = copy_file(src, dest, false); - if (ok) { - Util::unlink_safe(src); - } - return ok; -} - // Return a static string with the current hostname. const char* get_hostname() diff --git a/src/legacy_util.hpp b/src/legacy_util.hpp index 4ec3ac269..122a083c6 100644 --- a/src/legacy_util.hpp +++ b/src/legacy_util.hpp @@ -26,9 +26,6 @@ void fatal(const char* format, ...) ATTR_FORMAT(printf, 1, 2) ATTR_NORETURN; bool write_fd(int fd, const void* buf, size_t size); bool copy_fd(int fd_in, int fd_out); -bool clone_file(const char* src, const char* dest, bool via_tmp_file); -bool copy_file(const char* src, const char* dest, bool via_tmp_file); -bool move_file(const char* src, const char* dest); const char* get_hostname(); char* format(const char* format, ...) ATTR_FORMAT(printf, 1, 2); char* x_strdup(const char* s);