[icinga-checkins] icinga.org: icinga2/fix/temp-file-10948: wip

git at icinga.org git at icinga.org
Mon Feb 22 16:47:56 CET 2016


Module: icinga2
Branch: fix/temp-file-10948
Commit: 0682f6ab3ee4c53a723bfe5507cb43093fa5050c
URL:    https://git.icinga.org/?p=icinga2.git;a=commit;h=0682f6ab3ee4c53a723bfe5507cb43093fa5050c

Author: Michael Friedrich <michael.friedrich at netways.de>
Date:   Mon Feb 22 16:47:41 2016 +0100

wip

---

 lib/base/configobject.cpp |    4 +-
 lib/base/utility.cpp      |  129 +++++++++++++++++++++++++++++++++++++++++++++
 lib/base/utility.hpp      |    5 ++
 3 files changed, 135 insertions(+), 3 deletions(-)

diff --git a/lib/base/configobject.cpp b/lib/base/configobject.cpp
index 20426a6..214b78c 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/utility.cpp b/lib/base/utility.cpp
index e02d72d..c94efb5 100644
--- a/lib/base/utility.cpp
+++ b/lib/base/utility.cpp
@@ -1703,3 +1703,132 @@ String Utility::ValidateUTF8(const String& input)
 
 	return output;
 }
+
+String Utility::CreateTempFile(const String& path, std::fstream& fp)
+{
+	std::vector<char> 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.  */
+
+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 b986e68..15fc50e 100644
--- a/lib/base/utility.hpp
+++ b/lib/base/utility.hpp
@@ -141,6 +141,11 @@ public:
 
 	static String ValidateUTF8(const String& input);
 
+	static String CreateTempFile(const String& path, std::fstream& fp);
+#ifdef _WIN32
+	static int MksTemp (char *tmpl);
+#endif /* _WIN32 */
+
 private:
 	Utility(void);
 	static void CollectPaths(const String& path, std::vector<String>& paths);



More information about the icinga-checkins mailing list