mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-25 22:54:57 +02:00
Introduce AtomicFile
This commit is contained in:
parent
cc1e9c05ec
commit
53af4f2dd4
@ -163,7 +163,7 @@ else()
|
|||||||
set(LOGROTATE_CREATE "\n\tcreate 644 ${ICINGA2_USER} ${ICINGA2_GROUP}")
|
set(LOGROTATE_CREATE "\n\tcreate 644 ${ICINGA2_USER} ${ICINGA2_GROUP}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Boost ${BOOST_MIN_VERSION} COMPONENTS coroutine context date_time filesystem thread system program_options regex REQUIRED)
|
find_package(Boost ${BOOST_MIN_VERSION} COMPONENTS coroutine context date_time filesystem iostreams thread system program_options regex REQUIRED)
|
||||||
|
|
||||||
# Boost.Coroutine2 (the successor of Boost.Coroutine)
|
# Boost.Coroutine2 (the successor of Boost.Coroutine)
|
||||||
# (1) doesn't even exist in old Boost versions and
|
# (1) doesn't even exist in old Boost versions and
|
||||||
|
@ -16,6 +16,7 @@ set(base_SOURCES
|
|||||||
application.cpp application.hpp application-ti.hpp application-version.cpp application-environment.cpp
|
application.cpp application.hpp application-ti.hpp application-version.cpp application-environment.cpp
|
||||||
array.cpp array.hpp array-script.cpp
|
array.cpp array.hpp array-script.cpp
|
||||||
atomic.hpp
|
atomic.hpp
|
||||||
|
atomic-file.cpp atomic-file.hpp
|
||||||
base64.cpp base64.hpp
|
base64.cpp base64.hpp
|
||||||
boolean.cpp boolean.hpp boolean-script.cpp
|
boolean.cpp boolean.hpp boolean-script.cpp
|
||||||
bulker.hpp
|
bulker.hpp
|
||||||
|
116
lib/base/atomic-file.cpp
Normal file
116
lib/base/atomic-file.cpp
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/* Icinga 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||||
|
|
||||||
|
#include "base/atomic-file.hpp"
|
||||||
|
#include "base/exception.hpp"
|
||||||
|
#include "base/utility.hpp"
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# include <io.h>
|
||||||
|
# include <windows.h>
|
||||||
|
#else /* _WIN32 */
|
||||||
|
# include <errno.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
using namespace icinga;
|
||||||
|
|
||||||
|
AtomicFile::AtomicFile(String path, int mode) : m_Path(std::move(path))
|
||||||
|
{
|
||||||
|
m_TempFilename = m_Path + ".tmp.XXXXXX";
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
m_Fd = Utility::MksTemp(&m_TempFilename[0]);
|
||||||
|
#else /* _WIN32 */
|
||||||
|
m_Fd = mkstemp(&m_TempFilename[0]);
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
if (m_Fd < 0) {
|
||||||
|
auto error (errno);
|
||||||
|
|
||||||
|
BOOST_THROW_EXCEPTION(posix_error()
|
||||||
|
<< boost::errinfo_api_function("mkstemp")
|
||||||
|
<< boost::errinfo_errno(error)
|
||||||
|
<< boost::errinfo_file_name(m_TempFilename));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
exceptions(failbit | badbit);
|
||||||
|
|
||||||
|
open(boost::iostreams::file_descriptor(
|
||||||
|
m_Fd,
|
||||||
|
// Rationale: https://github.com/boostorg/iostreams/issues/152
|
||||||
|
boost::iostreams::never_close_handle
|
||||||
|
));
|
||||||
|
|
||||||
|
if (chmod(m_TempFilename.CStr(), mode) < 0) {
|
||||||
|
auto error (errno);
|
||||||
|
|
||||||
|
BOOST_THROW_EXCEPTION(posix_error()
|
||||||
|
<< boost::errinfo_api_function("chmod")
|
||||||
|
<< boost::errinfo_errno(error)
|
||||||
|
<< boost::errinfo_file_name(m_TempFilename));
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
if (is_open()) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)::close(m_Fd);
|
||||||
|
(void)unlink(m_TempFilename.CStr());
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AtomicFile::~AtomicFile()
|
||||||
|
{
|
||||||
|
if (is_open()) {
|
||||||
|
try {
|
||||||
|
close();
|
||||||
|
} catch (...) {
|
||||||
|
// Destructor must not throw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_Fd >= 0) {
|
||||||
|
(void)::close(m_Fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_TempFilename.IsEmpty()) {
|
||||||
|
(void)unlink(m_TempFilename.CStr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AtomicFile::Commit()
|
||||||
|
{
|
||||||
|
flush();
|
||||||
|
|
||||||
|
auto h ((*this)->handle());
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (!FlushFileBuffers(h)) {
|
||||||
|
auto err (GetLastError());
|
||||||
|
|
||||||
|
BOOST_THROW_EXCEPTION(win32_error()
|
||||||
|
<< boost::errinfo_api_function("FlushFileBuffers")
|
||||||
|
<< errinfo_win32_error(err)
|
||||||
|
<< boost::errinfo_file_name(m_TempFilename));
|
||||||
|
}
|
||||||
|
#else /* _WIN32 */
|
||||||
|
if (fsync(h)) {
|
||||||
|
auto err (errno);
|
||||||
|
|
||||||
|
BOOST_THROW_EXCEPTION(posix_error()
|
||||||
|
<< boost::errinfo_api_function("fsync")
|
||||||
|
<< boost::errinfo_errno(err)
|
||||||
|
<< boost::errinfo_file_name(m_TempFilename));
|
||||||
|
}
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
close();
|
||||||
|
(void)::close(m_Fd);
|
||||||
|
m_Fd = -1;
|
||||||
|
|
||||||
|
Utility::RenameFile(m_TempFilename, m_Path);
|
||||||
|
m_TempFilename = "";
|
||||||
|
}
|
34
lib/base/atomic-file.hpp
Normal file
34
lib/base/atomic-file.hpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* Icinga 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||||
|
|
||||||
|
#ifndef ATOMIC_FILE_H
|
||||||
|
#define ATOMIC_FILE_H
|
||||||
|
|
||||||
|
#include "base/string.hpp"
|
||||||
|
#include <boost/iostreams/device/file_descriptor.hpp>
|
||||||
|
#include <boost/iostreams/stream.hpp>
|
||||||
|
|
||||||
|
namespace icinga
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Atomically replaces a file's content.
|
||||||
|
*
|
||||||
|
* @ingroup base
|
||||||
|
*/
|
||||||
|
class AtomicFile : public boost::iostreams::stream<boost::iostreams::file_descriptor>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AtomicFile(String path, int mode);
|
||||||
|
~AtomicFile();
|
||||||
|
|
||||||
|
void Commit();
|
||||||
|
|
||||||
|
private:
|
||||||
|
String m_Path;
|
||||||
|
String m_TempFilename;
|
||||||
|
int m_Fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ATOMIC_FILE_H */
|
@ -134,6 +134,10 @@ public:
|
|||||||
|
|
||||||
static String CreateTempFile(const String& path, int mode, std::fstream& fp);
|
static String CreateTempFile(const String& path, int mode, std::fstream& fp);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static int MksTemp(char *tmpl);
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static String GetIcingaInstallPath();
|
static String GetIcingaInstallPath();
|
||||||
static String GetIcingaDataPath();
|
static String GetIcingaDataPath();
|
||||||
@ -185,10 +189,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
Utility();
|
Utility();
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
static int MksTemp (char *tmpl);
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
#ifdef I2_DEBUG
|
#ifdef I2_DEBUG
|
||||||
static double m_DebugTime;
|
static double m_DebugTime;
|
||||||
#endif /* I2_DEBUG */
|
#endif /* I2_DEBUG */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user