From a837198bbcae76a8c90d13cd7ce8385d0b848bfb Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Mon, 22 Feb 2016 16:47:41 +0100 Subject: [PATCH] Fix unique creation of temp files fixes #10948 --- lib/base/configobject.cpp | 4 +- lib/base/scriptglobal.cpp | 4 +- lib/base/utility.cpp | 146 ++++++++++++++++++++++++++- lib/base/utility.hpp | 6 ++ lib/cli/apisetuputility.cpp | 22 ++-- lib/cli/nodesetupcommand.cpp | 20 ++-- lib/cli/nodeutility.cpp | 13 ++- lib/cli/nodewizardcommand.cpp | 19 ++-- lib/cli/repositoryutility.cpp | 16 +-- lib/compat/statusdatawriter.cpp | 26 +++-- lib/config/configcompilercontext.cpp | 12 +-- lib/config/configcompilercontext.hpp | 1 + lib/icinga/clusterevents.cpp | 9 +- lib/icinga/icingaapplication.cpp | 11 +- 14 files changed, 217 insertions(+), 92 deletions(-) diff --git a/lib/base/configobject.cpp b/lib/base/configobject.cpp index 20426a603..214b78c2f 100644 --- a/lib/base/configobject.cpp +++ b/lib/base/configobject.cpp @@ -482,10 +482,8 @@ void ConfigObject::DumpObjects(const String& filename, int attributeTypes) Log(LogInformation, "ConfigObject") << "Dumping program state to file '" << filename << "'"; - String tempFilename = filename + ".tmp"; - std::fstream fp; - fp.open(tempFilename.CStr(), std::ios_base::out); + String tempFilename = Utility::CreateTempFile(filename + ".XXXXXX", fp); if (!fp) BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file")); diff --git a/lib/base/scriptglobal.cpp b/lib/base/scriptglobal.cpp index 237e66cd1..a80484cb6 100644 --- a/lib/base/scriptglobal.cpp +++ b/lib/base/scriptglobal.cpp @@ -65,10 +65,8 @@ void ScriptGlobal::WriteToFile(const String& filename) Log(LogInformation, "ScriptGlobal") << "Dumping variables to file '" << filename << "'"; - String tempFilename = filename + ".tmp"; - std::fstream fp; - fp.open(tempFilename.CStr(), std::ios_base::out); + String tempFilename = Utility::CreateTempFile(filename + ".XXXXXX", fp); if (!fp) BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file")); diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp index e02d72db2..4a11b9c31 100644 --- a/lib/base/utility.cpp +++ b/lib/base/utility.cpp @@ -53,6 +53,8 @@ #ifdef _WIN32 # include +# include +# include #endif /*_WIN32*/ using namespace icinga; @@ -1327,9 +1329,9 @@ Value Utility::LoadJsonFile(const String& path) void Utility::SaveJsonFile(const String& path, const Value& value) { - String tempPath = path + ".tmp"; + std::fstream fp; + String tempFilename = Utility::CreateTempFile(path + ".XXXXXX", fp); - std::ofstream fp(tempPath.CStr(), std::ofstream::out | std::ostream::trunc); fp.exceptions(std::ofstream::failbit | std::ofstream::badbit); fp << JsonEncode(value); fp.close(); @@ -1338,11 +1340,11 @@ void Utility::SaveJsonFile(const String& path, const Value& value) _unlink(path.CStr()); #endif /* _WIN32 */ - if (rename(tempPath.CStr(), path.CStr()) < 0) { + if (rename(tempFilename.CStr(), path.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) - << boost::errinfo_file_name(tempPath)); + << boost::errinfo_file_name(tempFilename)); } } @@ -1703,3 +1705,139 @@ String Utility::ValidateUTF8(const String& input) return output; } + +String Utility::CreateTempFile(const String& path, std::fstream& fp) +{ + std::vector targetPath(path.Begin(), path.End()); + targetPath.push_back('\0'); + + int fd; +#ifndef _WIN32 + fd = mkstemp(&targetPath[0]); +#else /* _WIN32 */ + fd = MksTemp(&targetPath[0]); +#endif /*_WIN32*/ + + if (fd < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << boost::errinfo_api_function("mkstemp") + << boost::errinfo_errno(errno) + << boost::errinfo_file_name(path)); + } + + try { + fp.open(&targetPath[0], std::ios_base::trunc | std::ios_base::out); + } catch (const std::fstream::failure& e) { + close(fd); + throw; + } + + close(fd); + + return String(targetPath.begin(), targetPath.end() - 1); +} + +#ifdef _WIN32 +/* mkstemp extracted from libc/sysdeps/posix/tempname.c. Copyright + (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. */ + +#define _O_EXCL 0x0400 +#define _O_CREAT 0x0100 +#define _O_RDWR 0x0002 +#define O_EXCL _O_EXCL +#define O_CREAT _O_CREAT +#define O_RDWR _O_RDWR + +static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +/* Generate a temporary file name based on TMPL. TMPL must match the + rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed + does not exist at the time of the call to mkstemp. TMPL is + overwritten with the result. */ +int Utility::MksTemp(char *tmpl) +{ + int len; + char *XXXXXX; + static unsigned long long value; + unsigned long long random_time_bits; + unsigned int count; + int fd = -1; + int save_errno = errno; + + /* A lower bound on the number of temporary files to attempt to + generate. The maximum total number of temporary file names that + can exist for a given template is 62**6. It should never be + necessary to try all these combinations. Instead if a reasonable + number of names is tried (we define reasonable as 62**3) fail to + give the system administrator the chance to remove the problems. */ +#define ATTEMPTS_MIN (62 * 62 * 62) + + /* The number of times to attempt to generate a temporary file. To + conform to POSIX, this must be no smaller than TMP_MAX. */ +#if ATTEMPTS_MIN < TMP_MAX + unsigned int attempts = TMP_MAX; +#else + unsigned int attempts = ATTEMPTS_MIN; +#endif + + len = strlen (tmpl); + if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX")) { + errno = EINVAL; + return -1; + } + + /* This is where the Xs start. */ + XXXXXX = &tmpl[len - 6]; + + /* Get some more or less random data. */ + { + SYSTEMTIME stNow; + FILETIME ftNow; + + // get system time + GetSystemTime(&stNow); + stNow.wMilliseconds = 500; + if (!SystemTimeToFileTime(&stNow, &ftNow)) { + errno = -1; + return -1; + } + + random_time_bits = (((unsigned long long)ftNow.dwHighDateTime << 32) | (unsigned long long)ftNow.dwLowDateTime); + } + + value += random_time_bits ^ (unsigned long long)GetCurrentThreadId(); + + for (count = 0; count < attempts; value += 7777, ++count) { + unsigned long long v = value; + + /* Fill in the random bits. */ + XXXXXX[0] = letters[v % 62]; + v /= 62; + XXXXXX[1] = letters[v % 62]; + v /= 62; + XXXXXX[2] = letters[v % 62]; + v /= 62; + XXXXXX[3] = letters[v % 62]; + v /= 62; + XXXXXX[4] = letters[v % 62]; + v /= 62; + XXXXXX[5] = letters[v % 62]; + + fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE); + if (fd >= 0) { + errno = save_errno; + return fd; + } else if (errno != EEXIST) + return -1; + } + + /* We got out of the loop because we ran out of combinations to try. */ + errno = EEXIST; + return -1; +} +#endif /*_WIN32*/ diff --git a/lib/base/utility.hpp b/lib/base/utility.hpp index b986e6820..b27ac7612 100644 --- a/lib/base/utility.hpp +++ b/lib/base/utility.hpp @@ -141,10 +141,16 @@ public: static String ValidateUTF8(const String& input); + static String CreateTempFile(const String& path, std::fstream& fp); + private: Utility(void); static void CollectPaths(const String& path, std::vector& paths); +#ifdef _WIN32 + static int MksTemp (char *tmpl); +#endif /* _WIN32 */ + static boost::thread_specific_ptr m_ThreadName; static boost::thread_specific_ptr m_RandSeed; }; diff --git a/lib/cli/apisetuputility.cpp b/lib/cli/apisetuputility.cpp index 55ef0aa50..abe7c38d6 100644 --- a/lib/cli/apisetuputility.cpp +++ b/lib/cli/apisetuputility.cpp @@ -157,23 +157,21 @@ bool ApiSetupUtility::SetupMasterApiUser(void) { String api_username = "root"; // TODO make this available as cli parameter? String api_password = RandomString(8); - String apiuserspath = GetConfdPath() + "/api-users.conf"; + String apiUsersPath = GetConfdPath() + "/api-users.conf"; - if (Utility::PathExists(apiuserspath)) { + if (Utility::PathExists(apiUsersPath)) { Log(LogInformation, "cli") - << "API user config file '" << apiuserspath << "' already exists, not creating config file."; + << "API user config file '" << apiUsersPath << "' already exists, not creating config file."; return true; } Log(LogInformation, "cli") - << "Adding new ApiUser '" << api_username << "' in '" << apiuserspath << "'."; + << "Adding new ApiUser '" << api_username << "' in '" << apiUsersPath << "'."; - NodeUtility::CreateBackupFile(apiuserspath); + NodeUtility::CreateBackupFile(apiUsersPath); - String apiuserspathtmp = apiuserspath + ".tmp"; - - std::ofstream fp; - fp.open(apiuserspathtmp.CStr(), std::ofstream::out | std::ofstream::trunc); + std::fstream fp; + String tempFilename = Utility::CreateTempFile(apiUsersPath + ".XXXXXX", fp); fp << "/**\n" << " * The APIUser objects are used for authentication against the API.\n" @@ -188,14 +186,14 @@ bool ApiSetupUtility::SetupMasterApiUser(void) fp.close(); #ifdef _WIN32 - _unlink(apiuserspath.CStr()); + _unlink(apiUsersPath.CStr()); #endif /* _WIN32 */ - if (rename(apiuserspathtmp.CStr(), apiuserspath.CStr()) < 0) { + if (rename(tempFilename.CStr(), apiUsersPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) - << boost::errinfo_file_name(apiuserspathtmp)); + << boost::errinfo_file_name(tempFilename)); } return true; diff --git a/lib/cli/nodesetupcommand.cpp b/lib/cli/nodesetupcommand.cpp index 2428f557a..a86d02293 100644 --- a/lib/cli/nodesetupcommand.cpp +++ b/lib/cli/nodesetupcommand.cpp @@ -169,10 +169,8 @@ int NodeSetupCommand::SetupMaster(const boost::program_options::variables_map& v String apipath = FeatureUtility::GetFeaturesAvailablePath() + "/api.conf"; NodeUtility::CreateBackupFile(apipath); - String apipathtmp = apipath + ".tmp"; - - std::ofstream fp; - fp.open(apipathtmp.CStr(), std::ofstream::out | std::ofstream::trunc); + std::fstream fp; + String tempApiPath = Utility::CreateTempFile(apipath + ".XXXXXX", fp); fp << "/**\n" << " * The API listener is used for distributed monitoring setups.\n" @@ -202,11 +200,11 @@ int NodeSetupCommand::SetupMaster(const boost::program_options::variables_map& v _unlink(apipath.CStr()); #endif /* _WIN32 */ - if (rename(apipathtmp.CStr(), apipath.CStr()) < 0) { + if (rename(tempApiPath.CStr(), apipath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) - << boost::errinfo_file_name(apipathtmp)); + << boost::errinfo_file_name(tempApiPath)); } /* update constants.conf with NodeName = CN + TicketSalt = random value */ @@ -376,10 +374,8 @@ int NodeSetupCommand::SetupNode(const boost::program_options::variables_map& vm, String apipath = FeatureUtility::GetFeaturesAvailablePath() + "/api.conf"; NodeUtility::CreateBackupFile(apipath); - String apipathtmp = apipath + ".tmp"; - - std::ofstream fp; - fp.open(apipathtmp.CStr(), std::ofstream::out | std::ofstream::trunc); + std::fstream fp; + String tempApiPath = Utility::CreateTempFile(apipath + ".XXXXXX", fp); fp << "/**\n" << " * The API listener is used for distributed monitoring setups.\n" @@ -421,11 +417,11 @@ int NodeSetupCommand::SetupNode(const boost::program_options::variables_map& vm, _unlink(apipath.CStr()); #endif /* _WIN32 */ - if (rename(apipathtmp.CStr(), apipath.CStr()) < 0) { + if (rename(tempApiPath.CStr(), apipath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) - << boost::errinfo_file_name(apipathtmp)); + << boost::errinfo_file_name(tempApiPath)); } /* generate local zones.conf with zone+endpoint */ diff --git a/lib/cli/nodeutility.cpp b/lib/cli/nodeutility.cpp index a7a2e43b8..3d46c66ba 100644 --- a/lib/cli/nodeutility.cpp +++ b/lib/cli/nodeutility.cpp @@ -385,9 +385,8 @@ bool NodeUtility::WriteNodeConfigObjects(const String& filename, const Array::Pt << "Cannot set ownership for user '" << user << "' group '" << group << "' on path '" << path << "'. Verify it yourself!"; } - String tempPath = filename + ".tmp"; - - std::ofstream fp(tempPath.CStr(), std::ofstream::out | std::ostream::trunc); + std::fstream fp; + String tempFilename = Utility::CreateTempFile(filename + ".XXXXXX", fp); fp << "/*\n"; fp << " * Generated by Icinga 2 node setup commands\n"; @@ -406,11 +405,11 @@ bool NodeUtility::WriteNodeConfigObjects(const String& filename, const Array::Pt _unlink(filename.CStr()); #endif /* _WIN32 */ - if (rename(tempPath.CStr(), filename.CStr()) < 0) { + if (rename(tempFilename.CStr(), filename.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) - << boost::errinfo_file_name(tempPath)); + << boost::errinfo_file_name(tempFilename)); } return true; @@ -638,10 +637,10 @@ void NodeUtility::SerializeObject(std::ostream& fp, const Dictionary::Ptr& objec void NodeUtility::UpdateConstant(const String& name, const String& value) { String constantsFile = Application::GetSysconfDir() + "/icinga2/constants.conf"; - String tempFile = constantsFile + ".tmp"; std::ifstream ifp(constantsFile.CStr()); - std::ofstream ofp(tempFile.CStr()); + std::fstream ofp; + String tempFile = Utility::CreateTempFile(constantsFile + ".XXXXXX", ofp); bool found = false; diff --git a/lib/cli/nodewizardcommand.cpp b/lib/cli/nodewizardcommand.cpp index 1d71749ef..079bb5a13 100644 --- a/lib/cli/nodewizardcommand.cpp +++ b/lib/cli/nodewizardcommand.cpp @@ -412,10 +412,8 @@ wizard_ticket: String apipath = FeatureUtility::GetFeaturesAvailablePath() + "/api.conf"; NodeUtility::CreateBackupFile(apipath); - String apipathtmp = apipath + ".tmp"; - - std::ofstream fp; - fp.open(apipathtmp.CStr(), std::ofstream::out | std::ofstream::trunc); + std::fstream fp; + String tempApiPath = Utility::CreateTempFile(apipath + ".XXXXXX", fp); fp << "/**\n" << " * The API listener is used for distributed monitoring setups.\n" @@ -443,11 +441,11 @@ wizard_ticket: _unlink(apipath.CStr()); #endif /* _WIN32 */ - if (rename(apipathtmp.CStr(), apipath.CStr()) < 0) { + if (rename(tempApiPath.CStr(), apipath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) - << boost::errinfo_file_name(apipathtmp)); + << boost::errinfo_file_name(tempApiPath)); } /* apilistener config */ @@ -538,10 +536,9 @@ wizard_ticket: String apipath = FeatureUtility::GetFeaturesAvailablePath() + "/api.conf"; NodeUtility::CreateBackupFile(apipath); - String apipathtmp = apipath + ".tmp"; - std::ofstream fp; - fp.open(apipathtmp.CStr(), std::ofstream::out | std::ofstream::trunc); + std::fstream fp; + String tempApiPath = Utility::CreateTempFile(apipath + ".XXXXXX", fp); fp << "/**\n" << " * The API listener is used for distributed monitoring setups.\n" @@ -566,11 +563,11 @@ wizard_ticket: _unlink(apipath.CStr()); #endif /* _WIN32 */ - if (rename(apipathtmp.CStr(), apipath.CStr()) < 0) { + if (rename(tempApiPath.CStr(), apipath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) - << boost::errinfo_file_name(apipathtmp)); + << boost::errinfo_file_name(tempApiPath)); } /* update constants.conf with NodeName = CN + TicketSalt = random value */ diff --git a/lib/cli/repositoryutility.cpp b/lib/cli/repositoryutility.cpp index e8c49a05d..157c371fb 100644 --- a/lib/cli/repositoryutility.cpp +++ b/lib/cli/repositoryutility.cpp @@ -356,9 +356,9 @@ bool RepositoryUtility::WriteObjectToRepositoryChangeLog(const String& path, con CreateRepositoryPath(Utility::DirName(path)); - String tempPath = path + ".tmp"; + std::fstream fp; + String tempFilename = Utility::CreateTempFile(path + ".XXXXXX", fp); - std::ofstream fp(tempPath.CStr(), std::ofstream::out | std::ostream::trunc); fp << JsonEncode(item); fp.close(); @@ -366,11 +366,11 @@ bool RepositoryUtility::WriteObjectToRepositoryChangeLog(const String& path, con _unlink(path.CStr()); #endif /* _WIN32 */ - if (rename(tempPath.CStr(), path.CStr()) < 0) { + if (rename(tempFilename.CStr(), path.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) - << boost::errinfo_file_name(tempPath)); + << boost::errinfo_file_name(tempFilename)); } return true; @@ -496,9 +496,9 @@ bool RepositoryUtility::WriteObjectToRepository(const String& path, const String CreateRepositoryPath(Utility::DirName(path)); - String tempPath = path + ".tmp"; + std::fstream fp; + String tempFilename = Utility::CreateTempFile(path + ".XXXXXX", fp); - std::ofstream fp(tempPath.CStr(), std::ofstream::out | std::ostream::trunc); SerializeObject(fp, name, type, item); fp << std::endl; fp.close(); @@ -507,11 +507,11 @@ bool RepositoryUtility::WriteObjectToRepository(const String& path, const String _unlink(path.CStr()); #endif /* _WIN32 */ - if (rename(tempPath.CStr(), path.CStr()) < 0) { + if (rename(tempFilename.CStr(), path.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) - << boost::errinfo_file_name(tempPath)); + << boost::errinfo_file_name(tempFilename)); } return true; diff --git a/lib/compat/statusdatawriter.cpp b/lib/compat/statusdatawriter.cpp index 818db2761..bfd90bb47 100644 --- a/lib/compat/statusdatawriter.cpp +++ b/lib/compat/statusdatawriter.cpp @@ -536,11 +536,10 @@ void StatusDataWriter::UpdateObjectsCache(void) { CONTEXT("Writing objects.cache file"); - String objectspath = GetObjectsPath(); - String objectspathtmp = objectspath + ".tmp"; + String objectsPath = GetObjectsPath(); - std::ofstream objectfp; - objectfp.open(objectspathtmp.CStr(), std::ofstream::out | std::ofstream::trunc); + std::fstream objectfp; + String tempObjectsPath = Utility::CreateTempFile(objectsPath + ".XXXXXX", objectfp); objectfp << std::fixed; @@ -760,14 +759,14 @@ void StatusDataWriter::UpdateObjectsCache(void) objectfp.close(); #ifdef _WIN32 - _unlink(objectspath.CStr()); + _unlink(objectsPath.CStr()); #endif /* _WIN32 */ - if (rename(objectspathtmp.CStr(), objectspath.CStr()) < 0) { + if (rename(tempObjectsPath.CStr(), objectsPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) - << boost::errinfo_file_name(objectspathtmp)); + << boost::errinfo_file_name(tempObjectsPath)); } } @@ -783,11 +782,10 @@ void StatusDataWriter::StatusTimerHandler(void) double start = Utility::GetTime(); - String statuspath = GetStatusPath(); - String statuspathtmp = statuspath + ".tmp"; /* XXX make this a global definition */ + String statusPath = GetStatusPath(); - std::ofstream statusfp; - statusfp.open(statuspathtmp.CStr(), std::ofstream::out | std::ofstream::trunc); + std::fstream statusfp; + String tempStatusPath = Utility::CreateTempFile(statusPath + ".XXXXXX", statusfp); statusfp << std::fixed; @@ -843,14 +841,14 @@ void StatusDataWriter::StatusTimerHandler(void) statusfp.close(); #ifdef _WIN32 - _unlink(statuspath.CStr()); + _unlink(statusPath.CStr()); #endif /* _WIN32 */ - if (rename(statuspathtmp.CStr(), statuspath.CStr()) < 0) { + if (rename(tempStatusPath.CStr(), statusPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) - << boost::errinfo_file_name(statuspathtmp)); + << boost::errinfo_file_name(tempStatusPath)); } Log(LogNotice, "StatusDataWriter") diff --git a/lib/config/configcompilercontext.cpp b/lib/config/configcompilercontext.cpp index e4dcddd12..917ee9e9f 100644 --- a/lib/config/configcompilercontext.cpp +++ b/lib/config/configcompilercontext.cpp @@ -36,13 +36,11 @@ void ConfigCompilerContext::OpenObjectsFile(const String& filename) { m_ObjectsPath = filename; - String tempFilename = m_ObjectsPath + ".tmp"; - std::fstream *fp = new std::fstream(); - fp->open(tempFilename.CStr(), std::ios_base::out); + m_ObjectsTempFile = Utility::CreateTempFile(filename + ".XXXXXX", *fp); if (!*fp) - BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file")); + BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + m_ObjectsTempFile + "' file")); m_ObjectsFP = new StdioStream(fp, true); } @@ -65,17 +63,15 @@ void ConfigCompilerContext::FinishObjectsFile(void) m_ObjectsFP->Close(); m_ObjectsFP.reset(); - String tempFilename = m_ObjectsPath + ".tmp"; - #ifdef _WIN32 _unlink(m_ObjectsPath.CStr()); #endif /* _WIN32 */ - if (rename(tempFilename.CStr(), m_ObjectsPath.CStr()) < 0) { + if (rename(m_ObjectsTempFile.CStr(), m_ObjectsPath.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) - << boost::errinfo_file_name(tempFilename)); + << boost::errinfo_file_name(m_ObjectsTempFile)); } } diff --git a/lib/config/configcompilercontext.hpp b/lib/config/configcompilercontext.hpp index d0601f762..cd4f2b006 100644 --- a/lib/config/configcompilercontext.hpp +++ b/lib/config/configcompilercontext.hpp @@ -42,6 +42,7 @@ public: private: String m_ObjectsPath; + String m_ObjectsTempFile; StdioStream::Ptr m_ObjectsFP; mutable boost::mutex m_Mutex; diff --git a/lib/icinga/clusterevents.cpp b/lib/icinga/clusterevents.cpp index 7c4e021c2..4e712cf82 100644 --- a/lib/icinga/clusterevents.cpp +++ b/lib/icinga/clusterevents.cpp @@ -722,9 +722,10 @@ Value ClusterEvents::UpdateRepositoryAPIHandler(const MessageOrigin::Ptr& origin return Empty; String repositoryFile = GetRepositoryDir() + SHA256(params->Get("endpoint")) + ".repo"; - String repositoryTempFile = repositoryFile + ".tmp"; - std::ofstream fp(repositoryTempFile.CStr(), std::ofstream::out | std::ostream::trunc); + std::fstream fp; + String tempRepositoryFile = Utility::CreateTempFile(repositoryFile + ".XXXXXX", fp); + fp << JsonEncode(params); fp.close(); @@ -732,11 +733,11 @@ Value ClusterEvents::UpdateRepositoryAPIHandler(const MessageOrigin::Ptr& origin _unlink(repositoryFile.CStr()); #endif /* _WIN32 */ - if (rename(repositoryTempFile.CStr(), repositoryFile.CStr()) < 0) { + if (rename(tempRepositoryFile.CStr(), repositoryFile.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) - << boost::errinfo_file_name(repositoryTempFile)); + << boost::errinfo_file_name(tempRepositoryFile)); } ApiListener::Ptr listener = ApiListener::GetInstance(); diff --git a/lib/icinga/icingaapplication.cpp b/lib/icinga/icingaapplication.cpp index 1a5ea429e..2825030d1 100644 --- a/lib/icinga/icingaapplication.cpp +++ b/lib/icinga/icingaapplication.cpp @@ -133,7 +133,7 @@ void IcingaApplication::OnShutdown(void) DumpProgramState(); } -static void PersistModAttrHelper(std::ofstream& fp, ConfigObject::Ptr& previousObject, const ConfigObject::Ptr& object, const String& attr, const Value& value) +static void PersistModAttrHelper(std::fstream& fp, ConfigObject::Ptr& previousObject, const ConfigObject::Ptr& object, const String& attr, const Value& value) { if (object != previousObject) { if (previousObject) { @@ -173,10 +173,9 @@ void IcingaApplication::DumpProgramState(void) void IcingaApplication::DumpModifiedAttributes(void) { String path = GetModAttrPath(); - String pathtmp = path + ".tmp"; - std::ofstream fp; - fp.open(pathtmp.CStr(), std::ofstream::out | std::ofstream::trunc); + std::fstream fp; + String tempFilename = Utility::CreateTempFile(path + ".XXXXXX", fp); ConfigObject::Ptr previousObject; ConfigObject::DumpModifiedAttributes(boost::bind(&PersistModAttrHelper, boost::ref(fp), boost::ref(previousObject), _1, _2, _3)); @@ -193,11 +192,11 @@ void IcingaApplication::DumpModifiedAttributes(void) _unlink(path.CStr()); #endif /* _WIN32 */ - if (rename(pathtmp.CStr(), path.CStr()) < 0) { + if (rename(tempFilename.CStr(), path.CStr()) < 0) { BOOST_THROW_EXCEPTION(posix_error() << boost::errinfo_api_function("rename") << boost::errinfo_errno(errno) - << boost::errinfo_file_name(pathtmp)); + << boost::errinfo_file_name(tempFilename)); } }