]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
fix: Adapt util::LockFile to MSYS2 (#1416)
authorKreijstal <rainb@tfwno.gf>
Sat, 23 Mar 2024 15:07:49 +0000 (16:07 +0100)
committerGitHub <noreply@github.com>
Sat, 23 Mar 2024 15:07:49 +0000 (16:07 +0100)
MSYS2 will not let you create a symlink to a nonexistent file, only to
an already existing file. To overcome this issue we use files, and write
content on it.

For Cygwin/MSYS2, the patch leverages POSIX `open` with the flags
`O_WRONLY | O_CREAT | O_EXCL`, effectively creating an exclusive lock
file. As suggested by @jrosdahl , thank you so much for the suggestion.
This still does not pass the test suite, but makes ccache usable.

src/ccache/util/LockFile.cpp
unittest/test_Util.cpp

index 43b62cd10dec126f6af8d32463703921c0b89f5a..d2f2a48b8c556eebb5401150d965d19dc3b8a0fc 100644 (file)
@@ -43,7 +43,9 @@ const uint32_t k_max_sleep_time_ms = 50;
 #ifndef _WIN32
 const util::Duration k_staleness_limit(2);
 #endif
-
+#ifdef __CYGWIN__
+#  include <fcntl.h>
+#endif
 namespace fs = util::filesystem;
 
 using pstr = util::PathString;
@@ -236,16 +238,31 @@ LockFile::do_acquire(const bool blocking)
     const auto now = TimePoint::now();
     const auto my_content =
       FMT("{}-{}.{}", content_prefix, now.sec(), now.nsec_decimal_part());
-
+#  ifdef __CYGWIN__
+    // Cygwin-specific file-based lock
+    int fd = open(m_lock_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0666);
+    if (fd != -1) {
+      // Lock file successfully created, write the content and close the file
+      write(fd, my_content.c_str(), my_content.size());
+      close(fd); // Lock acquired
+      return true;
+    }
+#  else
     if (fs::create_symlink(my_content, m_lock_file)) {
       // We got the lock.
       return true;
     }
+#  endif
 
     int saved_errno = errno;
     if (saved_errno == ENOENT) {
       // Directory doesn't exist?
+#  ifdef __CYGWIN__
+      if (!fs::exists(m_lock_file.parent_path())
+          && fs::create_directories(m_lock_file.parent_path())) {
+#  else
       if (fs::create_directories(m_lock_file.parent_path())) {
+#  endif
         // OK. Retry.
         continue;
       }
@@ -262,7 +279,17 @@ LockFile::do_acquire(const bool blocking)
       // Directory doesn't exist or isn't writable?
       return false;
     }
-
+#  ifdef __CYGWIN__
+    // Cygwin-specific code to read the content of the lock file
+    std::ifstream lock_file(m_lock_file);
+    if (!lock_file.is_open()) {
+      // Handle error: the lock file couldn't be opened
+      return false;
+    }
+    std::string content;
+    lock_file >> content;
+    lock_file.close();
+#  else
     auto content_path = fs::read_symlink(m_lock_file);
     if (!content_path) {
       if (content_path.error() == std::errc::no_such_file_or_directory) {
@@ -278,6 +305,7 @@ LockFile::do_acquire(const bool blocking)
     }
     auto content = content_path->string();
 
+#  endif
     if (content == my_content) {
       // Lost NFS reply?
       LOG("Symlinking {} failed but we got the lock anyway", m_lock_file);
index e670464b09c2f693366040554b069492bfd4021e..6120a82a74041e2ceabe07aa8fe851b22c7b8bee 100644 (file)
@@ -102,7 +102,7 @@ TEST_CASE("Util::make_relative_path")
 
   const std::string cwd = util::actual_cwd();
   const std::string actual_cwd = FMT("{}/d", cwd);
-#ifdef _WIN32
+#if defined(_WIN32) || defined(__CYGWIN__)
   const std::string apparent_cwd = actual_cwd;
 #else
   const std::string apparent_cwd = FMT("{}/s", cwd);
@@ -114,7 +114,6 @@ TEST_CASE("Util::make_relative_path")
 #endif
   REQUIRE(fs::current_path("d"));
   util::setenv("PWD", apparent_cwd);
-
   SUBCASE("No base directory")
   {
     CHECK(make_relative_path("", "/a", "/a", "/a/x") == "/a/x");
@@ -198,7 +197,7 @@ TEST_CASE("Util::normalize_abstract_absolute_path")
 
 TEST_CASE("Util::normalize_concrete_absolute_path")
 {
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(__CYGWIN__)
   TestContext test_context;
 
   util::write_file("file", "");