diff --git a/source/lib/file/file_system.cpp b/source/lib/file/file_system.cpp index 5a70872ff5..6d3eef4d78 100644 --- a/source/lib/file/file_system.cpp +++ b/source/lib/file/file_system.cpp @@ -130,7 +130,7 @@ Status GetDirectoryEntries(const OsPath& path, CFileInfos* files, DirectoryNames } -Status CreateDirectories(const OsPath& path, mode_t mode) +Status CreateDirectories(const OsPath& path, mode_t mode, bool breakpoint) { if(path.empty()) return INFO::OK; @@ -146,7 +146,7 @@ Status CreateDirectories(const OsPath& path, mode_t mode) // If we were passed a path ending with '/', strip the '/' now so that // we can consistently use Parent to find parent directory names if(path.IsDirectory()) - return CreateDirectories(path.Parent(), mode); + return CreateDirectories(path.Parent(), mode, breakpoint); RETURN_STATUS_IF_ERR(CreateDirectories(path.Parent(), mode)); @@ -154,7 +154,10 @@ Status CreateDirectories(const OsPath& path, mode_t mode) if(wmkdir(path, mode) != 0) { debug_printf("CreateDirectories: failed to mkdir %s (mode %d)\n", path.string8().c_str(), mode); - WARN_RETURN(StatusFromErrno()); + if (breakpoint) + WARN_RETURN(StatusFromErrno()); + else + return StatusFromErrno(); } return INFO::OK; diff --git a/source/lib/file/file_system.h b/source/lib/file/file_system.h index ae0db3634e..95589b01f6 100644 --- a/source/lib/file/file_system.h +++ b/source/lib/file/file_system.h @@ -80,7 +80,7 @@ LIB_API Status GetDirectoryEntries(const OsPath& path, CFileInfos* files, Direct // same as boost::filesystem::create_directories, except that mkdir is invoked with // instead of 0755. -LIB_API Status CreateDirectories(const OsPath& path, mode_t mode); +LIB_API Status CreateDirectories(const OsPath& path, mode_t mode, bool breakpoint = true); LIB_API Status DeleteDirectory(const OsPath& dirPath); diff --git a/source/ps/Replay.cpp b/source/ps/Replay.cpp index ccd291d773..cf2e458c0e 100644 --- a/source/ps/Replay.cpp +++ b/source/ps/Replay.cpp @@ -72,7 +72,6 @@ void CReplayLogger::StartGame(JS::MutableHandleValue attribs) m_Directory = getDateIndexSubdirectory(VisualReplay::GetDirectoryName()); debug_printf("Writing replay to %s\n", m_Directory.string8().c_str()); - CreateDirectories(m_Directory, 0700); m_Stream = new std::ofstream(OsString(m_Directory / L"commands.txt").c_str(), std::ofstream::out | std::ofstream::trunc); *m_Stream << "start " << m_ScriptInterface.StringifyJSON(attribs, false) << "\n"; diff --git a/source/ps/Util.cpp b/source/ps/Util.cpp index f46cd84338..e0070e628b 100644 --- a/source/ps/Util.cpp +++ b/source/ps/Util.cpp @@ -201,6 +201,10 @@ OsPath getDateIndexSubdirectory(const OsPath& parentDir) const std::time_t timestamp = std::time(nullptr); const struct std::tm* now = std::localtime(×tamp); + // Two processes executing this simultaneously might attempt to create the same directory. + int tries = 0; + const int maxTries = 10; + int i = 0; OsPath path; char directory[256]; @@ -209,7 +213,14 @@ OsPath getDateIndexSubdirectory(const OsPath& parentDir) { sprintf(directory, "%04d-%02d-%02d_%04d", now->tm_year+1900, now->tm_mon+1, now->tm_mday, ++i); path = parentDir / CStr(directory); - } while (DirectoryExists(path) || FileExists(path)); + + if (DirectoryExists(path) || FileExists(path)) + continue; + + if (CreateDirectories(path, 0700, ++tries > maxTries) == INFO::OK) + break; + + } while(tries <= maxTries); return path; } diff --git a/source/simulation2/Simulation2.cpp b/source/simulation2/Simulation2.cpp index 7df98104fd..4e3da533bf 100644 --- a/source/simulation2/Simulation2.cpp +++ b/source/simulation2/Simulation2.cpp @@ -298,7 +298,6 @@ void CSimulation2Impl::ReportSerializationFailure( { const OsPath path = getDateIndexSubdirectory(psLogDir() / "serializationtest"); debug_printf("Writing serializationtest-data to %s\n", path.string8().c_str()); - CreateDirectories(path, 0700); // Clean up obsolete files from previous runs wunlink(path / "hash.before.a"); @@ -554,7 +553,6 @@ void CSimulation2Impl::DumpState() std::stringstream name;\ name << std::setw(5) << std::setfill('0') << m_TurnNumber << ".txt"; const OsPath path = m_OOSLogPath / name.str(); - CreateDirectories(path.Parent(), 0700); std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); file << "State hash: " << std::hex;