# include "legacy_util.hpp"
namespace {
+
std::string
get_system_tmp_dir()
{
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
{
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,
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()));
+ }
}
}
#include "Context.hpp"
#include "Fd.hpp"
#include "FormatNonstdStringView.hpp"
+#include "TemporaryFile.hpp"
#include "legacy_util.hpp"
#include "logging.hpp"
# include "win32compat.hpp"
#endif
+#ifdef __linux__
+# ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+# endif
+# ifdef HAVE_LINUX_FS_H
+# include <linux/fs.h>
+# ifndef FICLONE
+# define FICLONE _IOW(0x94, 9, int)
+# endif
+# define FILE_CLONING_SUPPORTED 1
+# endif
+#endif
+
+#ifdef __APPLE__
+# ifdef HAVE_SYS_CLONEFILE_H
+# include <sys/clonefile.h>
+# define FILE_CLONING_SUPPORTED 1
+# endif
+#endif
+
using nonstd::string_view;
namespace {
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,
{
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());
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
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)
{
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.
#include "legacy_util.hpp"
#include "Fd.hpp"
-#include "TemporaryFile.hpp"
-#include "Util.hpp"
#include "exceptions.hpp"
#include "logging.hpp"
# include "win32compat.hpp"
#endif
-#include "third_party/fmt/core.h"
-
-#include <string>
-
#ifdef HAVE_PWD_H
# include <pwd.h>
#endif
# include <sys/time.h>
#endif
-#ifdef __linux__
-# ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-# endif
-# ifdef HAVE_LINUX_FS_H
-# include <linux/fs.h>
-# ifndef FICLONE
-# define FICLONE _IOW(0x94, 9, int)
-# endif
-# define FILE_CLONING_SUPPORTED 1
-# endif
-#endif
-
-#ifdef __APPLE__
-# ifdef HAVE_SYS_CLONEFILE_H
-# include <sys/clonefile.h>
-# define FILE_CLONING_SUPPORTED 1
-# endif
-#endif
-
// Something went badly wrong!
void
fatal(const char* format, ...)
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()
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);