diff options
author | Jeroen Vermeulen <jtv@precisiontranslationtools.com> | 2015-04-17 20:21:18 +0300 |
---|---|---|
committer | Jeroen Vermeulen <jtv@precisiontranslationtools.com> | 2015-04-17 20:21:18 +0300 |
commit | abfdb61bc9c3281de2e5ef26df30634ed2c84d89 (patch) | |
tree | 8d276efc076442b3e53eaccedc705a50d46fd4a2 /util | |
parent | d56f317f2ee844beffc7f83e3e6ae2aeb80add61 (diff) |
Cross-platform tempfile implementation.
This makes temp_file and temp_dir work both on POSIX-like platforms and on
Windows.
It also fixes a bug where the temporary files/directories were created in
the current working directory, instead of in the system's standard
location for temporary files. Unfortunately the Windows and POSIX code
diverge quite a bit on that point.
Diffstat (limited to 'util')
-rw-r--r-- | util/tempfile.hh | 78 |
1 files changed, 75 insertions, 3 deletions
diff --git a/util/tempfile.hh b/util/tempfile.hh index 228238823..9b872a27e 100644 --- a/util/tempfile.hh +++ b/util/tempfile.hh @@ -3,18 +3,74 @@ // Utilities for creating temporary files and directories. +#include <climits> #include <cstdio> #include <cstdlib> #include <string> +#if defined(_WIN32) || defined(_WIN64) +#include <windows.h> +#endif + #include <boost/filesystem.hpp> #include <boost/noncopyable.hpp> #include "util/exception.hh" +#include "util/unistd.hh" namespace util { +/// Obtain a directory for temporary files, e.g. /tmp. +std::string temp_location() +{ +#if defined(_WIN32) || defined(_WIN64) + char dir_buffer[1000]; + if (GetTempPath(1000, dir_buffer) == 0) + throw std::runtime_error("Could not read temporary directory."); + return std::string(dir_buffer); +#else + // POSIX says to try these environment variables, in this order: + const char *const vars[] = {"TMPDIR", "TMP", "TEMPDIR", "TEMP", 0}; + for (int i=0; vars[i]; ++i) + { + const char *val = getenv(vars[i]); + // Environment variable is set and nonempty. Use it. + if (val && *val) return val; + } + // No environment variables set. Default to /tmp. + return "/tmp"; +#endif +} + + +#if defined(_WIN32) || defined(_WIN64) +/// Windows helper: create temporary filename. +std::string windows_tmpnam() +{ + const std::string tmp = temp_location(); + char output_buffer[MAX_PATH]; + if (GetTempFileName(tmp.c_str(), "tmp", 0, output_buffer) == 0) + throw std::runtime_error("Could not create temporary file name."); + return output_buffer; +} +#else +/** POSIX helper: create template for temporary filename. + * + * Writes the template into buf, which must have room for at least PATH_MAX + * bytes. The function fails if the template is too long. + */ +void posix_tmp_template(char *buf) +{ + const std::string tmp = temp_location(); + const std::string name_template = tmp + "/tmp.XXXXXX"; + if (name_template.size() >= PATH_MAX-1) + throw std::runtime_error("Path for temp files is too long: " + tmp); + strcpy(buf, name_template.c_str()); +} +#endif + + /** Temporary directory. * * Automatically creates, and on destruction deletes, a temporary directory. @@ -22,15 +78,21 @@ namespace util * object exists. * * If the directory no longer exists by the time the temp_dir is destroyed, - * no cleanup happens. + * cleanup is skipped. */ class temp_dir : boost::noncopyable { public: temp_dir() { - char buf[] = "tmpdir.XXXXXX"; +#if defined(_WIN32) || defined(_WIN64) + m_path = windows_tmpnam(); + boost::filesystem::create_directory(m_path); +#else + char buf[PATH_MAX]; + posix_tmp_template(buf); m_path = std::string(mkdtemp(buf)); +#endif } ~temp_dir() @@ -49,17 +111,27 @@ private: /** Temporary file. * * Automatically creates, and on destruction deletes, a temporary file. + * + * If the file no longer exists by the time the temp_file is destroyed, + * cleanup is skipped. */ class temp_file : boost::noncopyable { public: temp_file() { - char buf[] = "tmp.XXXXXX"; +#if defined(_WIN32) || defined(_WIN64) + m_path = windows_tmpnam(); + std::ofstream out(m_path.c_str()); + out.flush(); +#else + char buf[PATH_MAX]; + posix_tmp_template(buf); const int fd = mkstemp(buf); if (fd == -1) throw ErrnoException(); close(fd); m_path = buf; +#endif } ~temp_file() |