diff options
author | Joel Rosdahl <joel@rosdahl.net> | 2020-07-25 15:56:29 +0200 |
---|---|---|
committer | Joel Rosdahl <joel@rosdahl.net> | 2020-07-25 16:04:39 +0200 |
commit | 53b35a42b7cde0038369ef33fd687942f4dfb64d (patch) | |
tree | 8e53dd3eb93cf9bd37323884c388eab63fa6c620 | |
parent | 60d774d42c0900696a5bb95ebac59134bf3091b8 (diff) | |
download | ccache-53b35a42b7cde0038369ef33fd687942f4dfb64d.tar.gz |
Introduce and use TemporaryFile class
In addition to improving code clarity, this fixes a bug where the
fallback code for “-fdiagnostics-color” tried to operate on a closed
file descriptor.
-rw-r--r-- | src/AtomicFile.cpp | 7 | ||||
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/InodeCache.cpp | 17 | ||||
-rw-r--r-- | src/MiniTrace.cpp | 7 | ||||
-rw-r--r-- | src/TemporaryFile.cpp | 92 | ||||
-rw-r--r-- | src/TemporaryFile.hpp | 48 | ||||
-rw-r--r-- | src/ccache.cpp | 105 | ||||
-rw-r--r-- | src/execute.cpp | 29 | ||||
-rw-r--r-- | src/execute.hpp | 4 | ||||
-rw-r--r-- | src/legacy_util.cpp | 11 |
10 files changed, 232 insertions, 89 deletions
diff --git a/src/AtomicFile.cpp b/src/AtomicFile.cpp index ca998189..795c45fb 100644 --- a/src/AtomicFile.cpp +++ b/src/AtomicFile.cpp @@ -18,6 +18,7 @@ #include "AtomicFile.hpp" +#include "TemporaryFile.hpp" #include "Util.hpp" #include "exceptions.hpp" @@ -25,9 +26,9 @@ AtomicFile::AtomicFile(const std::string& path, Mode mode) : m_path(path) { - auto fd_and_path = Util::create_temp_fd(path + ".tmp"); - m_stream = fdopen(fd_and_path.first, mode == Mode::binary ? "w+b" : "w+"); - m_tmp_path = std::move(fd_and_path.second); + TemporaryFile tmp_file(path + ".tmp"); + m_stream = fdopen(tmp_file.fd.release(), mode == Mode::binary ? "w+b" : "w+"); + m_tmp_path = std::move(tmp_file.path); } AtomicFile::~AtomicFile() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1d3d25ed..2a24a208 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,6 +23,7 @@ set( ResultRetriever.cpp SignalHandler.cpp Stat.cpp + TemporaryFile.cpp ThreadPool.cpp Util.cpp ZstdCompressor.cpp diff --git a/src/InodeCache.cpp b/src/InodeCache.cpp index adac7cac..a8a9c9d6 100644 --- a/src/InodeCache.cpp +++ b/src/InodeCache.cpp @@ -23,6 +23,7 @@ #include "Finalizer.hpp" #include "Hash.hpp" #include "Stat.hpp" +#include "TemporaryFile.hpp" #include "Util.hpp" #include "ccache.hpp" #include "logging.hpp" @@ -255,21 +256,19 @@ InodeCache::create_new_file(const std::string& filename) // Create the new file to a temporary name to prevent other processes from // mapping it before it is fully initialized. - auto temp_fd_and_path = Util::create_temp_fd(filename); - const auto& temp_path = temp_fd_and_path.second; + TemporaryFile tmp_file(filename); - Fd temp_fd(temp_fd_and_path.first); - Finalizer temp_file_remover([=] { unlink(temp_path.c_str()); }); + Finalizer temp_file_remover([&] { unlink(tmp_file.path.c_str()); }); bool is_nfs; - if (Util::is_nfs_fd(*temp_fd, &is_nfs) == 0 && is_nfs) { + if (Util::is_nfs_fd(*tmp_file.fd, &is_nfs) == 0 && is_nfs) { cc_log( "Inode cache not supported because the cache file would be located on" " nfs: %s", filename.c_str()); return false; } - int err = Util::fallocate(*temp_fd, sizeof(SharedRegion)); + int err = Util::fallocate(*tmp_file.fd, sizeof(SharedRegion)); if (err) { cc_log("Failed to allocate file space for inode cache: %s", strerror(err)); return false; @@ -279,7 +278,7 @@ InodeCache::create_new_file(const std::string& filename) sizeof(SharedRegion), PROT_READ | PROT_WRITE, MAP_SHARED, - *temp_fd, + *tmp_file.fd, 0)); if (sr == reinterpret_cast<void*>(-1)) { cc_log("Failed to mmap new inode cache: %s", strerror(errno)); @@ -299,14 +298,14 @@ InodeCache::create_new_file(const std::string& filename) } munmap(sr, sizeof(SharedRegion)); - temp_fd.close(); + tmp_file.fd.close(); // link() will fail silently if a file with the same name already exists. // This will be the case if two processes try to create a new file // simultaneously. Thus close the current file handle and reopen a new one, // which will make us use the first created file even if we didn't win the // race. - if (link(temp_path.c_str(), filename.c_str()) != 0) { + if (link(tmp_file.path.c_str(), filename.c_str()) != 0) { cc_log("Failed to link new inode cache: %s", strerror(errno)); return false; } diff --git a/src/MiniTrace.cpp b/src/MiniTrace.cpp index 90caad30..f82b27e1 100644 --- a/src/MiniTrace.cpp +++ b/src/MiniTrace.cpp @@ -22,6 +22,7 @@ # include "ArgsInfo.hpp" # include "MiniTrace.hpp" +# include "TemporaryFile.hpp" # include "Util.hpp" # include "legacy_util.hpp" @@ -49,10 +50,8 @@ get_system_tmp_dir() MiniTrace::MiniTrace(const ArgsInfo& args_info) : m_args_info(args_info), m_trace_id(reinterpret_cast<void*>(getpid())) { - auto fd_and_path = - Util::create_temp_fd(get_system_tmp_dir() + "/ccache-trace"); - m_tmp_trace_file = fd_and_path.second; - close(fd_and_path.first); + TemporaryFile tmp_file(get_system_tmp_dir() + "/ccache-trace"); + m_tmp_trace_file = tmp_file.path; mtr_init(m_tmp_trace_file.c_str()); MTR_INSTANT_C("", "", "time", fmt::format("{:f}", time_seconds()).c_str()); diff --git a/src/TemporaryFile.cpp b/src/TemporaryFile.cpp new file mode 100644 index 00000000..f91f3b99 --- /dev/null +++ b/src/TemporaryFile.cpp @@ -0,0 +1,92 @@ +// Copyright (C) 2020 Joel Rosdahl and other contributors +// +// See doc/AUTHORS.adoc for a complete list of contributors. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This program 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 General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the Free Software Foundation, Inc., 51 +// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#include "TemporaryFile.hpp" + +#include "Util.hpp" +#include "legacy_util.hpp" + +using nonstd::string_view; + +namespace { + +#ifndef _WIN32 +mode_t +get_umask() +{ + static bool mask_retrieved = false; + static mode_t mask; + if (!mask_retrieved) { + mask = umask(0); + umask(mask); + mask_retrieved = true; + } + return mask; +} +#endif + +#ifndef HAVE_MKSTEMP +// Cheap and nasty mkstemp replacement. +int +mkstemp(char* name_template) +{ +# ifdef __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +# endif + mktemp(name_template); +# ifdef __GNUC__ +# pragma GCC diagnostic pop +# endif + return open(name_template, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600); +} +#endif + +} // namespace + +TemporaryFile::TemporaryFile(string_view path_prefix) +{ + if (!initialize(path_prefix) && errno == ENOENT) { + auto dir = Util::dir_name(path); + if (!Util::create_dir(dir)) { + fatal("Failed to create directory %s: %s", + std::string(dir).c_str(), + strerror(errno)); + } + initialize(path_prefix); + } + if (!fd) { + fatal("Failed to create temporary file for %s: %s", + path.c_str(), + strerror(errno)); + } + + set_cloexec_flag(*fd); +#ifndef _WIN32 + fchmod(*fd, 0666 & ~get_umask()); +#endif +} + +bool +TemporaryFile::initialize(string_view path_prefix) +{ + path = std::string(path_prefix); + path += ".XXXXXX"; + fd = Fd(mkstemp(const_cast<char*>(path.data()))); // cast needed before C++17 + return bool(fd); +} diff --git a/src/TemporaryFile.hpp b/src/TemporaryFile.hpp new file mode 100644 index 00000000..dc64f8b4 --- /dev/null +++ b/src/TemporaryFile.hpp @@ -0,0 +1,48 @@ +// Copyright (C) 2020 Joel Rosdahl and other contributors +// +// See doc/AUTHORS.adoc for a complete list of contributors. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This program 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 General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the Free Software Foundation, Inc., 51 +// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#pragma once + +#include "Fd.hpp" +#include "NonCopyable.hpp" + +#include "third_party/nonstd/string_view.hpp" + +// This class represents a unique temporary file created by mkstemp. The file is +// not deleted by the destructor. +class TemporaryFile : NonCopyable +{ +public: + // `path_prefix` is the base path. The resulting filename will be this path + // plus a unique suffix. If `path_prefix` refers to a nonexistent directory + // the directory will be created if possible.` + TemporaryFile(nonstd::string_view path_prefix); + + TemporaryFile(TemporaryFile&& other) = default; + + TemporaryFile& operator=(TemporaryFile&& other) = default; + + // The resulting open file descriptor in read/write mode. Unset on error. + Fd fd; + + // The actual filename. Empty on error. + std::string path; + +private: + bool initialize(nonstd::string_view path_prefix); +}; diff --git a/src/ccache.cpp b/src/ccache.cpp index 9c5d56ef..70d0eaa5 100644 --- a/src/ccache.cpp +++ b/src/ccache.cpp @@ -34,6 +34,7 @@ #include "ResultRetriever.hpp" #include "SignalHandler.hpp" #include "StdMakeUnique.hpp" +#include "TemporaryFile.hpp" #include "Util.hpp" #include "argprocessing.hpp" #include "cleanup.hpp" @@ -622,8 +623,7 @@ use_relative_paths_in_depfile(const Context& ctx) return; } - std::string tmp_file = fmt::format("{}.tmp{}", output_dep, tmp_string()); - + std::string tmp_file = output_dep + ".tmp"; try { Util::write_file(tmp_file, adjusted_file_content); } catch (const Error& e) { @@ -696,38 +696,48 @@ result_name_from_depfile(Context& ctx, Hash& hash) // Execute the compiler/preprocessor, with logic to retry without requesting // colored diagnostics messages if that fails. static int -execute(Context& ctx, - Args& args, - const std::string& stdout_path, - int stdout_fd, - const std::string& stderr_path, - int stderr_fd) +do_execute(Context& ctx, + Args& args, + TemporaryFile&& tmp_stdout, + TemporaryFile&& tmp_stderr) { if (ctx.diagnostics_color_failed && ctx.guessed_compiler == GuessedCompiler::gcc) { args.erase_with_prefix("-fdiagnostics-color"); } - int status = - execute(args.to_argv().data(), stdout_fd, stderr_fd, &ctx.compiler_pid); + int status = execute(args.to_argv().data(), + std::move(tmp_stdout.fd), + std::move(tmp_stderr.fd), + &ctx.compiler_pid); if (status != 0 && !ctx.diagnostics_color_failed && ctx.guessed_compiler == GuessedCompiler::gcc) { - auto errors = Util::read_file(stderr_path); + auto errors = Util::read_file(tmp_stderr.path); if (errors.find("unrecognized command line option") != std::string::npos && errors.find("-fdiagnostics-color") != std::string::npos) { - // Old versions of GCC did not support colored diagnostics. + // Old versions of GCC do not support colored diagnostics. cc_log("-fdiagnostics-color is unsupported; trying again without it"); - if (ftruncate(stdout_fd, 0) < 0 || lseek(stdout_fd, 0, SEEK_SET) < 0) { - cc_log( - "Failed to truncate %s: %s", stdout_path.c_str(), strerror(errno)); + + tmp_stdout.fd = Fd(open( + tmp_stdout.path.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0600)); + if (!tmp_stdout.fd) { + cc_log("Failed to truncate %s: %s", + tmp_stdout.path.c_str(), + strerror(errno)); failed(STATS_ERROR); } - if (ftruncate(stderr_fd, 0) < 0 || lseek(stderr_fd, 0, SEEK_SET) < 0) { - cc_log( - "Failed to truncate %s: %s", stderr_path.c_str(), strerror(errno)); + + tmp_stderr.fd = Fd(open( + tmp_stderr.path.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0600)); + if (!tmp_stderr.fd) { + cc_log("Failed to truncate %s: %s", + tmp_stderr.path.c_str(), + strerror(errno)); failed(STATS_ERROR); } + ctx.diagnostics_color_failed = true; - return execute(ctx, args, stdout_path, stdout_fd, stderr_path, stderr_fd); + return do_execute( + ctx, args, std::move(tmp_stdout), std::move(tmp_stderr)); } } return status; @@ -856,22 +866,20 @@ to_cache(Context& ctx, cc_log("Running real compiler"); MTR_BEGIN("execute", "compiler"); - const auto tmp_stdout_fd_and_path = Util::create_temp_fd( + TemporaryFile tmp_stdout( fmt::format("{}/tmp.stdout", ctx.config.temporary_dir())); - int tmp_stdout_fd = tmp_stdout_fd_and_path.first; - const std::string& tmp_stdout = tmp_stdout_fd_and_path.second; - ctx.register_pending_tmp_file(tmp_stdout); + ctx.register_pending_tmp_file(tmp_stdout.path); + std::string tmp_stdout_path = tmp_stdout.path; - const auto tmp_stderr_fd_and_path = Util::create_temp_fd( + TemporaryFile tmp_stderr( fmt::format("{}/tmp.stderr", ctx.config.temporary_dir())); - int tmp_stderr_fd = tmp_stderr_fd_and_path.first; - const std::string& tmp_stderr = tmp_stderr_fd_and_path.second; - ctx.register_pending_tmp_file(tmp_stderr); + ctx.register_pending_tmp_file(tmp_stderr.path); + std::string tmp_stderr_path = tmp_stderr.path; int status; if (!ctx.config.depend_mode()) { status = - execute(ctx, args, tmp_stdout, tmp_stdout_fd, tmp_stderr, tmp_stderr_fd); + do_execute(ctx, args, std::move(tmp_stdout), std::move(tmp_stderr)); args.pop_back(3); } else { // Use the original arguments (including dependency options) in depend @@ -882,16 +890,12 @@ to_cache(Context& ctx, add_prefix(ctx, depend_mode_args, ctx.config.prefix_command()); ctx.time_of_compilation = time(nullptr); - status = execute(ctx, - depend_mode_args, - tmp_stdout, - tmp_stdout_fd, - tmp_stderr, - tmp_stderr_fd); + status = do_execute( + ctx, depend_mode_args, std::move(tmp_stdout), std::move(tmp_stderr)); } MTR_END("execute", "compiler"); - auto st = Stat::stat(tmp_stdout, Stat::OnError::log); + auto st = Stat::stat(tmp_stdout_path, Stat::OnError::log); if (!st) { // The stdout file was removed - cleanup in progress? Better bail out. failed(STATS_MISSING); @@ -908,15 +912,15 @@ to_cache(Context& ctx, // compiler into tmp_stderr. if (!ctx.cpp_stderr.empty()) { std::string combined_stderr = - Util::read_file(ctx.cpp_stderr) + Util::read_file(tmp_stderr); - Util::write_file(tmp_stderr, combined_stderr); + Util::read_file(ctx.cpp_stderr) + Util::read_file(tmp_stderr_path); + Util::write_file(tmp_stderr_path, combined_stderr); } if (status != 0) { cc_log("Compiler gave exit status %d", status); // We can output stderr immediately instead of rerunning the compiler. - Util::send_to_stderr(Util::read_file(tmp_stderr), + Util::send_to_stderr(Util::read_file(tmp_stderr_path), ctx.args_info.strip_diagnostics_colors); failed(STATS_STATUS, status); @@ -948,7 +952,7 @@ to_cache(Context& ctx, failed(STATS_EMPTYOUTPUT); } - st = Stat::stat(tmp_stderr, Stat::OnError::log); + st = Stat::stat(tmp_stderr_path, Stat::OnError::log); if (!st) { failed(STATS_ERROR); } @@ -957,7 +961,7 @@ to_cache(Context& ctx, Result::Writer result_writer(ctx, ctx.result_path()); if (st.size() > 0) { - result_writer.write(Result::FileType::stderr_output, tmp_stderr); + result_writer.write(Result::FileType::stderr_output, tmp_stderr_path); } result_writer.write(Result::FileType::object, ctx.args_info.output_obj); if (ctx.args_info.generating_dependencies) { @@ -1008,7 +1012,7 @@ to_cache(Context& ctx, } // Everything OK. - Util::send_to_stderr(Util::read_file(tmp_stderr), + Util::send_to_stderr(Util::read_file(tmp_stderr_path), ctx.args_info.strip_diagnostics_colors); } @@ -1030,20 +1034,14 @@ get_result_name_from_cpp(Context& ctx, Args& args, Hash& hash) } else { // Run cpp on the input file to obtain the .i. - // Limit the basename to 10 characters in order to cope with filesystem with - // small maximum filename length limits. - string_view input_base = - Util::get_truncated_base_name(ctx.args_info.input_file, 10); - auto stdout_fd_and_path = Util::create_temp_fd( - fmt::format("{}/{}.stdout", ctx.config.temporary_dir(), input_base)); - int stdout_fd = stdout_fd_and_path.first; - stdout_path = stdout_fd_and_path.second; + TemporaryFile tmp_stdout( + fmt::format("{}/tmp.cpp_stdout", ctx.config.temporary_dir())); + stdout_path = tmp_stdout.path; ctx.register_pending_tmp_file(stdout_path); - auto stderr_fd_and_path = Util::create_temp_fd( + TemporaryFile tmp_stderr( fmt::format("{}/tmp.cpp_stderr", ctx.config.temporary_dir())); - int stderr_fd = stderr_fd_and_path.first; - stderr_path = stderr_fd_and_path.second; + stderr_path = tmp_stderr.path; ctx.register_pending_tmp_file(stderr_path); size_t args_added = 2; @@ -1056,7 +1054,8 @@ get_result_name_from_cpp(Context& ctx, Args& args, Hash& hash) add_prefix(ctx, args, ctx.config.prefix_command_cpp()); cc_log("Running preprocessor"); MTR_BEGIN("execute", "preprocessor"); - status = execute(ctx, args, stdout_path, stdout_fd, stderr_path, stderr_fd); + status = + do_execute(ctx, args, std::move(tmp_stdout), std::move(tmp_stderr)); MTR_END("execute", "preprocessor"); args.pop_back(args_added); } diff --git a/src/execute.cpp b/src/execute.cpp index bbf9ceb7..6f317d8d 100644 --- a/src/execute.cpp +++ b/src/execute.cpp @@ -24,6 +24,7 @@ #include "Fd.hpp" #include "SignalHandler.hpp" #include "Stat.hpp" +#include "TemporaryFile.hpp" #include "Util.hpp" #include "ccache.hpp" #include "logging.hpp" @@ -36,9 +37,9 @@ using nonstd::string_view; #ifdef _WIN32 int -execute(const char* const* argv, int fd_out, int fd_err, pid_t* /*pid*/) +execute(const char* const* argv, Fd&& fd_out, Fd&& fd_err, pid_t* /*pid*/) { - return win32execute(argv[0], argv, 1, fd_out, fd_err); + return win32execute(argv[0], argv, 1, fd_out.release(), fd_err.release()); } // Re-create a win32 command line string based on **argv. @@ -195,13 +196,11 @@ win32execute(const char* path, add_exe_ext_if_no_to_fullpath(full_path_win_ext, MAX_PATH, ext, path); BOOL ret = FALSE; if (length > 8192) { - auto fd_and_path = Util::create_temp_fd(path); - Fd fd(fd_and_path.first); - const char* tmp_file = fd_and_path.second.c_str(); - if (!write_fd(*fd, args, length)) { + TemporaryFile tmp_file(path); + if (!write_fd(*tmp_file.fd, args, length)) { cc_log("Error writing @file; this command will probably fail: %s", args); } - std::string atfile = fmt::format("\"@{}\"", tmp_file); + std::string atfile = fmt::format("\"@{}\"", tmp_file.path); ret = CreateProcess(nullptr, const_cast<char*>(atfile.c_str()), nullptr, @@ -212,7 +211,7 @@ win32execute(const char* path, nullptr, &si, &pi); - Util::unlink_tmp(tmp_file); + Util::unlink_tmp(tmp_file.path); } if (!ret) { ret = CreateProcess(full_path_win_ext, @@ -257,7 +256,7 @@ win32execute(const char* path, // Execute a compiler backend, capturing all output to the given paths the full // path to the compiler to run is in argv[0]. int -execute(const char* const* argv, int fd_out, int fd_err, pid_t* pid) +execute(const char* const* argv, Fd&& fd_out, Fd&& fd_err, pid_t* pid) { cc_log_argv("Executing ", argv); @@ -272,15 +271,15 @@ execute(const char* const* argv, int fd_out, int fd_err, pid_t* pid) if (*pid == 0) { // Child. - dup2(fd_out, STDOUT_FILENO); - close(fd_out); - dup2(fd_err, STDERR_FILENO); - close(fd_err); + dup2(*fd_out, STDOUT_FILENO); + fd_out.close(); + dup2(*fd_err, STDERR_FILENO); + fd_err.close(); x_exit(execv(argv[0], const_cast<char* const*>(argv))); } - close(fd_out); - close(fd_err); + fd_out.close(); + fd_err.close(); int status; if (waitpid(*pid, &status, 0) != *pid) { diff --git a/src/execute.hpp b/src/execute.hpp index a8f7fc17..e66f73a2 100644 --- a/src/execute.hpp +++ b/src/execute.hpp @@ -20,11 +20,13 @@ #include "system.hpp" +#include "Fd.hpp" + #include <string> class Context; -int execute(const char* const* argv, int fd_out, int fd_err, pid_t* pid); +int execute(const char* const* argv, Fd&& fd_out, Fd&& fd_err, pid_t* pid); std::string find_executable(const Context& ctx, const char* name, const char* exclude_name); std::string find_executable_in_path(const char* name, diff --git a/src/legacy_util.cpp b/src/legacy_util.cpp index 51434f85..126eb74b 100644 --- a/src/legacy_util.cpp +++ b/src/legacy_util.cpp @@ -20,6 +20,7 @@ #include "legacy_util.hpp" #include "Fd.hpp" +#include "TemporaryFile.hpp" #include "Util.hpp" #include "exceptions.hpp" #include "logging.hpp" @@ -159,8 +160,9 @@ clone_file(const char* src, const char* dest, bool via_tmp_file) Fd dest_fd; char* tmp_file = nullptr; if (via_tmp_file) { - tmp_file = x_strdup(dest); - dest_fd = Fd(create_tmp_fd(&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) { @@ -220,8 +222,9 @@ copy_file(const char* src, const char* dest, bool via_tmp_file) Fd dest_fd; char* tmp_file = nullptr; if (via_tmp_file) { - tmp_file = x_strdup(dest); - dest_fd = Fd(create_tmp_fd(&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) { |