]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
fix: Create temporary file with cpp extension instead of hard linking
authorJoel Rosdahl <joel@rosdahl.net>
Tue, 7 Jun 2022 13:12:03 +0000 (15:12 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Tue, 7 Jun 2022 14:15:18 +0000 (16:15 +0200)
[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.

src/TemporaryFile.cpp
src/TemporaryFile.hpp
src/ccache.cpp
src/third_party/win32/mktemp.h
unittest/test_bsdmkstemp.cpp

index d4182855a61faf945ceeecc119ad493885406c9e..238dc011f587a936d15ed719d99cbce831b621e5 100644 (file)
 #include "Util.hpp"
 
 #include <core/exceptions.hpp>
+#include <fmtmacros.hpp>
+
+#include <cstdlib>
+
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
 
 #ifdef _WIN32
 #  include "third_party/win32/mktemp.h"
 #endif
 
-TemporaryFile::TemporaryFile(std::string_view path_prefix)
-  : path(std::string(path_prefix) + ".XXXXXX")
+TemporaryFile::TemporaryFile(std::string_view path_prefix,
+                             std::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]: <https://github.com/Alexpux/mingw-w64/blob/
   // d0d7f784833bbb0b2d279310ddc6afb52fe47a46/mingw-w64-crt/misc/mkstemp.c>
-  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(
index 5d1154becd9cef4d4203abf55200122b6b62a22f..29d8597e3e3e167cddbb07c344d9e539a76061e9 100644 (file)
@@ -29,9 +29,9 @@ 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(std::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(std::string_view path_prefix, std::string_view suffix = {});
 
   TemporaryFile(TemporaryFile&& other) noexcept = default;
 
index 203c2893b48272b4afc2583e421bcd7c4442cc5b..c6ad63ec1289c392a4478261b08a3d9adb9d3d80 100644 (file)
@@ -1118,14 +1118,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(
index 40e0c167b8b3d02d8e0ac2c6bf7206c70de1ed65..0612001b1af66945843acb8e7fbfb9a1fea774db 100644 (file)
@@ -1,5 +1,4 @@
-#ifndef CCACHE_THIRD_PARTY_WIN32_MKTEMP_H_
-#define CCACHE_THIRD_PARTY_WIN32_MKTEMP_H_
+#pragma once
 
 #include <stddef.h>
 
@@ -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 (*)(voidbuf, size_t n));
 
 #ifdef __cplusplus
 }
 #endif
-#endif
index d17e89e2d75e0bf1ea915967838fddf7c1e6ef29..881b06759a0a5e734d2863dfbc5976a64a35672a 100644 (file)
@@ -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");