From: Joel Rosdahl Date: Tue, 7 Jun 2022 13:12:03 +0000 (+0200) Subject: fix: Create temporary file with cpp extension instead of hard linking X-Git-Tag: v4.6.2~35 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=87cbd482009c2fabc62ae68e18d77ffbaa02b04f;p=thirdparty%2Fccache.git fix: Create temporary file with cpp extension instead of hard linking [1] added a suitable file extension to the temporary file used for capturing the preprocessed output by creating a hard link. This fails when the temporary directory is on a file system that doesn't support hard links. Fix this by making it possible to pass a suffix to TemporaryFile and passing the proper cpp suffix for the tmp stdout file instead of creating a hard link as an alias. [1]: 4da9f2b474b7ee39cd54ab4261f90936f3c944ec Closes #1079. (cherry picked from commit e55d7e6d97e65580e21389b1b5b69d35421720be) --- diff --git a/src/TemporaryFile.cpp b/src/TemporaryFile.cpp index 3b6ccabd1..56cc8f887 100644 --- a/src/TemporaryFile.cpp +++ b/src/TemporaryFile.cpp @@ -21,27 +21,33 @@ #include "Util.hpp" #include +#include + +#include + +#ifdef HAVE_UNISTD_H +# include +#endif #ifdef _WIN32 # include "third_party/win32/mktemp.h" #endif -using nonstd::string_view; - -TemporaryFile::TemporaryFile(string_view path_prefix) - : path(std::string(path_prefix) + ".XXXXXX") +TemporaryFile::TemporaryFile(nonstd::string_view path_prefix, + nonstd::string_view suffix) + : path(FMT("{}.XXXXXX{}", path_prefix, suffix)) { Util::ensure_dir_exists(Util::dir_name(path)); #ifdef _WIN32 - // MSVC lacks mkstemp() and Mingw-w64's implementation[1] is problematic, as + // MSVC lacks mkstemps() and Mingw-w64's implementation[1] is problematic, as // it can reuse the names of recently-deleted files unless the caller // remembers to call srand(). // [1]: - fd = Fd(bsd_mkstemp(&path[0])); + fd = Fd(bsd_mkstemps(&path[0], suffix.length())); #else - fd = Fd(mkstemp(&path[0])); + fd = Fd(mkstemps(&path[0], suffix.length())); #endif if (!fd) { throw core::Fatal( diff --git a/src/TemporaryFile.hpp b/src/TemporaryFile.hpp index 032cbfa8d..dc04b3741 100644 --- a/src/TemporaryFile.hpp +++ b/src/TemporaryFile.hpp @@ -30,9 +30,10 @@ class TemporaryFile { 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); + // plus a unique string plus `suffix`. If `path_prefix` refers to a + // nonexistent directory the directory will be created if possible.` + TemporaryFile(nonstd::string_view path_prefix, + nonstd::string_view suffix = {}); TemporaryFile(TemporaryFile&& other) noexcept = default; diff --git a/src/ccache.cpp b/src/ccache.cpp index b0c27d064..23d282922 100644 --- a/src/ccache.cpp +++ b/src/ccache.cpp @@ -1121,14 +1121,12 @@ get_result_key_from_cpp(Context& ctx, Args& args, Hash& hash) } else { // Run cpp on the input file to obtain the .i. - TemporaryFile tmp_stdout( - FMT("{}/tmp.cpp_stdout", ctx.config.temporary_dir())); - ctx.register_pending_tmp_file(tmp_stdout.path); - // stdout_path needs the proper cpp_extension for the compiler to do its // thing correctly. - stdout_path = FMT("{}.{}", tmp_stdout.path, ctx.config.cpp_extension()); - Util::hard_link(tmp_stdout.path, stdout_path); + TemporaryFile tmp_stdout( + FMT("{}/tmp.cpp_stdout", ctx.config.temporary_dir()), + FMT(".{}", ctx.config.cpp_extension())); + stdout_path = tmp_stdout.path; ctx.register_pending_tmp_file(stdout_path); TemporaryFile tmp_stderr( diff --git a/src/third_party/win32/mktemp.h b/src/third_party/win32/mktemp.h index 40e0c167b..0612001b1 100644 --- a/src/third_party/win32/mktemp.h +++ b/src/third_party/win32/mktemp.h @@ -1,5 +1,4 @@ -#ifndef CCACHE_THIRD_PARTY_WIN32_MKTEMP_H_ -#define CCACHE_THIRD_PARTY_WIN32_MKTEMP_H_ +#pragma once #include @@ -7,12 +6,11 @@ extern "C" { #endif -int bsd_mkstemp(char *); +int bsd_mkstemps(char* path, int slen); // Exposed for testing. -void bsd_mkstemp_set_random_source(void (*)(void *buf, size_t n)); +void bsd_mkstemp_set_random_source(void (*)(void* buf, size_t n)); #ifdef __cplusplus } #endif -#endif diff --git a/unittest/test_bsdmkstemp.cpp b/unittest/test_bsdmkstemp.cpp index d17e89e2d..881b06759 100644 --- a/unittest/test_bsdmkstemp.cpp +++ b/unittest/test_bsdmkstemp.cpp @@ -88,9 +88,9 @@ private: } // namespace -TEST_SUITE_BEGIN("bsd_mkstemp"); +TEST_SUITE_BEGIN("bsd_mkstemps"); -TEST_CASE("bsd_mkstemp") +TEST_CASE("bsd_mkstemps") { TestContext test_context; @@ -108,11 +108,19 @@ TEST_CASE("bsd_mkstemp") SUBCASE("successful") { std::string path = "XXXXXX"; - Fd fd(bsd_mkstemp(&path[0])); + Fd fd(bsd_mkstemps(&path[0], 0)); CHECK_MESSAGE(fd, "errno=" << errno); CHECK(path == "AAAAAA"); } + SUBCASE("successful with suffix") + { + std::string path = "XXXXXX123"; + Fd fd(bsd_mkstemps(&path[0], 3)); + CHECK_MESSAGE(fd, "errno=" << errno); + CHECK(path == "AAAAAA123"); + } + SUBCASE("existing file") { ScopedHANDLE handle(CreateFileA("AAAAAA", @@ -125,7 +133,7 @@ TEST_CASE("bsd_mkstemp") CHECK_MESSAGE(handle, "errno=" << errno); std::string path = "XXXXXX"; - Fd fd(bsd_mkstemp(&path[0])); + Fd fd(bsd_mkstemps(&path[0], 0)); CHECK_MESSAGE(fd, "errno=" << errno); CHECK(path == "BBBBBB"); } @@ -152,7 +160,7 @@ TEST_CASE("bsd_mkstemp") "errno=" << errno); std::string path = "XXXXXX"; - Fd fd(bsd_mkstemp(&path[0])); + Fd fd(bsd_mkstemps(&path[0], 0)); CHECK_MESSAGE(fd, "errno=" << errno); CHECK(path == "BBBBBB"); } @@ -162,7 +170,7 @@ TEST_CASE("bsd_mkstemp") CHECK_MESSAGE(CreateDirectoryA("AAAAAA", nullptr), "errno=" << errno); std::string path = "XXXXXX"; - Fd fd(bsd_mkstemp(&path[0])); + Fd fd(bsd_mkstemps(&path[0], 0)); CHECK_MESSAGE(fd, "errno=" << errno); CHECK(path == "BBBBBB"); } @@ -202,7 +210,7 @@ TEST_CASE("bsd_mkstemp") if (!broken_acls) { std::string path = "my_readonly_dir/XXXXXX"; - CHECK(!Fd(bsd_mkstemp(&path[0]))); + CHECK(!Fd(bsd_mkstemps(&path[0], 0))); CHECK(errno == EACCES); } else { MESSAGE("ACLs do not appear to function properly on this filesystem");