summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Rosdahl <joel@rosdahl.net>2020-07-25 15:56:29 +0200
committerJoel Rosdahl <joel@rosdahl.net>2020-07-25 16:04:39 +0200
commit53b35a42b7cde0038369ef33fd687942f4dfb64d (patch)
tree8e53dd3eb93cf9bd37323884c388eab63fa6c620
parent60d774d42c0900696a5bb95ebac59134bf3091b8 (diff)
downloadccache-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.cpp7
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/InodeCache.cpp17
-rw-r--r--src/MiniTrace.cpp7
-rw-r--r--src/TemporaryFile.cpp92
-rw-r--r--src/TemporaryFile.hpp48
-rw-r--r--src/ccache.cpp105
-rw-r--r--src/execute.cpp29
-rw-r--r--src/execute.hpp4
-rw-r--r--src/legacy_util.cpp11
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) {