From 64dbf255c9a9f273b4f4d9c752a5452dffdc82b2 Mon Sep 17 00:00:00 2001 From: Jerry Marino Date: Wed, 9 Jun 2021 19:15:27 -0700 Subject: [PATCH] Fix race condition in MakeDirs If there are 2 concurrent processes creating the same directories, then it will fail I noticed this on the CI errors of #567, and a co-worker was hitting it today. I suspect invalidating the worker or other updates triggered big rebuilds. I don't know of a perfect repro but, at a 10% rate: invoking Bazel to build 2 swift libraries in the same BUILD file. --- tools/common/file_system.cc | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/tools/common/file_system.cc b/tools/common/file_system.cc index 15b2c274f..f71586f75 100644 --- a/tools/common/file_system.cc +++ b/tools/common/file_system.cc @@ -18,6 +18,7 @@ #include #include +#include #include #ifdef __APPLE__ @@ -99,7 +100,13 @@ bool MakeDirs(const std::string &path, int mode) { struct stat dir_stats; if (stat(path.c_str(), &dir_stats) == 0) { // Return true if the directory already exists. - return S_ISDIR(dir_stats.st_mode); + if (!S_ISDIR(dir_stats.st_mode)) { + std::cerr << "error: path exists and isn't a directory (" << path.c_str() + << ") \n"; + return false; + } else { + return true; + } } // Recurse to create the parent directory. @@ -108,5 +115,22 @@ bool MakeDirs(const std::string &path, int mode) { } // Create the directory that was requested. - return mkdir(path.c_str(), mode) == 0; + int mkdir_ret = mkdir(path.c_str(), mode); + if (mkdir_ret == 0) { + return true; + } else if (mkdir_ret == EEXIST) { + int chmod_ret = chmod(path.c_str(), S_IRWXU); + if (chmod_ret == 0) { + return true; + } + std::cerr << "error:" << strerror(errno) << ":" << path.c_str() << "\n"; + return false; + } + + // If we can access the directory assume it's valid + if (access(path.c_str(), F_OK) == 0) { + return true; + } + std::cerr << "error:" << strerror(errno) << ":" << path.c_str() << "\n"; + return false; }