Skip to content

Commit 9a125ef

Browse files
allevatokeith
authored andcommitted
Avoid the race condition if multiple calls to MakeDirs occur simultaneously with overlapping paths.
Based on #644. PiperOrigin-RevId: 421565838 (cherry picked from commit aa8b3c6)
1 parent 2e7b9a5 commit 9a125ef

File tree

1 file changed

+30
-2
lines changed

1 file changed

+30
-2
lines changed

tools/common/file_system.cc

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include <sys/types.h>
2020
#include <unistd.h>
2121

22+
#include <cerrno>
23+
#include <iostream>
2224
#include <string>
2325

2426
#ifdef __APPLE__
@@ -100,7 +102,13 @@ bool MakeDirs(const std::string &path, int mode) {
100102
struct stat dir_stats;
101103
if (stat(path.c_str(), &dir_stats) == 0) {
102104
// Return true if the directory already exists.
103-
return S_ISDIR(dir_stats.st_mode);
105+
if (S_ISDIR(dir_stats.st_mode)) {
106+
return true;
107+
}
108+
109+
std::cerr << "error: path already exists but is not a directory: "
110+
<< path << "\n";
111+
return false;
104112
}
105113

106114
// Recurse to create the parent directory.
@@ -109,5 +117,25 @@ bool MakeDirs(const std::string &path, int mode) {
109117
}
110118

111119
// Create the directory that was requested.
112-
return mkdir(path.c_str(), mode) == 0;
120+
if (mkdir(path.c_str(), mode) == 0) {
121+
return true;
122+
}
123+
124+
// Race condition: The above call to `mkdir` could fail if there are multiple
125+
// calls to `MakeDirs` running at the same time with overlapping paths, so
126+
// check again to see if the directory exists despite the call failing. If it
127+
// does, that's ok.
128+
if (errno == EEXIST && stat(path.c_str(), &dir_stats) == 0) {
129+
if (S_ISDIR(dir_stats.st_mode)) {
130+
return true;
131+
}
132+
133+
std::cerr << "error: path already exists but is not a directory: "
134+
<< path << "\n";
135+
return false;
136+
}
137+
138+
std::cerr << "error: could not create directory: " << path
139+
<< " (" << strerror(errno) << ")\n";
140+
return false;
113141
}

0 commit comments

Comments
 (0)