diff --git a/include/tmp/directory.hpp b/include/tmp/directory.hpp index a91b4fe..e9b1059 100644 --- a/include/tmp/directory.hpp +++ b/include/tmp/directory.hpp @@ -44,7 +44,7 @@ class directory final : public path { /// for temporary files. If a prefix is provided to the constructor, the /// directory is created in the path /prefix/. The prefix can be /// a path consisting of multiple segments. - explicit directory(std::string_view prefix = "") : path(prefix, mkdtemp) {} + explicit directory(std::string_view prefix = "") : path(create(prefix)) {} /// Concatenates this directory path with a given @p source std::filesystem::path operator/(std::string_view source) const { @@ -58,6 +58,18 @@ class directory final : public path { directory& operator=(directory&&) noexcept = default; ///< move-assignable directory(const directory&) = delete; ///< not copy-constructible auto operator=(const directory&) = delete; ///< not copy-assignable + +private: + /// Creates a unique temporary directory based on the given @p prefix + static std::filesystem::path create(std::string_view prefix) { + auto pattern = make_pattern(prefix); + if (mkdtemp(pattern.data()) == nullptr) { + auto ec = std::error_code(errno, std::system_category()); + throw error("Cannot create temporary directory", ec); + } + + return pattern; + } }; } // namespace tmp diff --git a/include/tmp/file.hpp b/include/tmp/file.hpp index d5dccb3..3060831 100644 --- a/include/tmp/file.hpp +++ b/include/tmp/file.hpp @@ -86,9 +86,20 @@ class file final : public path { /// for temporary files. If a prefix is provided to the constructor, the /// directory is created in the path /prefix/. The prefix can be /// a path consisting of multiple segments. - explicit file(std::string_view prefix, bool binary) : path(prefix, mkstemp), + explicit file(std::string_view prefix, bool binary) : path(create(prefix)), binary(binary) {} + /// Creates a unique temporary file based on the given @p prefix + static std::filesystem::path create(std::string_view prefix) { + auto pattern = make_pattern(prefix); + if (mkstemp(pattern.data()) == -1) { + auto ec = std::error_code(errno, std::system_category()); + throw error("Cannot create temporary file", ec); + } + + return pattern; + } + /// Returns a stream for this file std::ofstream stream(bool append) const noexcept { std::ios::openmode mode = append ? std::ios::app : std::ios::trunc; diff --git a/include/tmp/path.hpp b/include/tmp/path.hpp index b36a441..dde0be2 100644 --- a/include/tmp/path.hpp +++ b/include/tmp/path.hpp @@ -44,18 +44,23 @@ class path { } protected: + /// Exception type that should be used by subclasses to signal errors + using error = std::filesystem::filesystem_error; + std::filesystem::path underlying; ///< This file path - /// Creates a unique temporary path using the given constructor function - template - explicit path(std::string_view prefix, C constructor) { + /// Creates a unique temporary path using the given constructor function. + /// @param prefix the path between system temp + /// @param creator wrapped mktemp-like function that returns resulting path + explicit path(std::filesystem::path path) : underlying(std::move(path)) {} + + /// Creates a pattern for the mktemp-like functions. + /// If @p prefix is not empty, it is appended to the tempdir + static std::string make_pattern(std::string_view prefix) { const auto parent = std::filesystem::temp_directory_path() / prefix; std::filesystem::create_directories(parent); - std::string arg = parent / "XXXXXX"; - constructor(arg.data()); - - this->underlying = std::move(arg); + return parent / "XXXXXX"; } private: