Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 59 additions & 46 deletions src/create.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,90 +116,103 @@ const wchar_t* make_mdstring(std::ios::openmode mode) noexcept {
#endif
} // namespace

open_handle_type create_file(std::ios::openmode mode) {
fs::path create_directory(std::string_view prefix) {
validate_prefix(prefix); // throws std::invalid_argument with a proper text

std::error_code ec;
open_handle_type handle = create_file(mode, ec);
fs::path directory = create_directory(prefix, ec);

if (ec) {
throw fs::filesystem_error("Cannot create a temporary file", ec);
throw fs::filesystem_error("Cannot create a temporary directory", ec);
}

return handle;
return directory;
}

open_handle_type create_file(std::ios::openmode mode, std::error_code& ec) {
fs::path create_directory(std::string_view prefix, std::error_code& ec) {
if (!is_prefix_valid(prefix)) {
ec = std::make_error_code(std::errc::invalid_argument);
return fs::path();
}

#ifdef _WIN32
fs::path::string_type path = make_path("");
fs::path::string_type path = make_path(prefix);
#else
fs::path::string_type path = make_pattern("");
fs::path::string_type path = make_pattern(prefix);
#endif

#ifdef _WIN32
if (!CreateDirectory(path.c_str(), nullptr)) {
ec = std::error_code(GetLastError(), std::system_category());
}
#else
if (mkdtemp(path.data()) == nullptr) {
ec = std::error_code(errno, std::system_category());
}
#endif

return path;
}

#if defined(_WIN32)
std::FILE* create_file(std::ios::openmode mode) {
std::error_code ec;
std::FILE* handle = create_file(mode, ec);

if (ec) {
throw fs::filesystem_error("Cannot create a temporary file", ec);
}

return handle;
}

std::FILE* create_file(std::ios::openmode mode, std::error_code& ec) {
fs::path::string_type path = make_path("");

mode |= std::ios::in | std::ios::out;

#ifdef _WIN32
std::FILE* handle;

// FIXME: use _wfopen_s
if (const wchar_t* mdstr = make_mdstring(mode)) {
handle = _wfopen(path.c_str(), mdstr);
if (handle == nullptr) {
ec = std::error_code(errno, std::system_category());
return {};
return nullptr;
}
} else {
ec = std::make_error_code(std::errc::invalid_argument);
return {};
}
#else
int handle = mkstemp(path.data());
if (handle == -1) {
ec = std::error_code(errno, std::system_category());
return {};
return nullptr;
}

unlink(path.c_str());
#endif

(void)mode;
ec.clear();
return handle;
}

fs::path create_directory(std::string_view prefix) {
validate_prefix(prefix); // throws std::invalid_argument with a proper text

#else
int create_file() {
std::error_code ec;
fs::path directory = create_directory(prefix, ec);
int handle = create_file(ec);

if (ec) {
throw fs::filesystem_error("Cannot create a temporary directory", ec);
throw fs::filesystem_error("Cannot create a temporary file", ec);
}

return directory;
return handle;
}

fs::path create_directory(std::string_view prefix, std::error_code& ec) {
if (!is_prefix_valid(prefix)) {
ec = std::make_error_code(std::errc::invalid_argument);
return fs::path();
}

#ifdef _WIN32
fs::path::string_type path = make_path(prefix);
#else
fs::path::string_type path = make_pattern(prefix);
#endif
int create_file(std::error_code& ec) {
fs::path::string_type path = make_pattern("");

#ifdef _WIN32
if (!CreateDirectory(path.c_str(), nullptr)) {
ec = std::error_code(GetLastError(), std::system_category());
}
#else
if (mkdtemp(path.data()) == nullptr) {
int handle = mkstemp(path.data());
if (handle == -1) {
ec = std::error_code(errno, std::system_category());
return -1;
}
#endif

return path;
unlink(path.c_str());

ec.clear();
return handle;
}
#endif
} // namespace tmp
56 changes: 31 additions & 25 deletions src/create.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,10 @@
#include <ios>
#include <string_view>
#include <system_error>
#include <utility>

namespace tmp {
namespace fs = std::filesystem;

/// Implementation-defined handle type to the open file
#if defined(_WIN32)
using open_handle_type = std::FILE*;
#elif __has_include(<unistd.h>)
using open_handle_type = int; // POSIX file descriptor
#else
#error "Target platform not supported"
#endif

/// Creates a temporary file in the system's temporary directory,
/// and opens it for reading and writing
/// @param[in] mode Specifies stream open mode
/// @returns A handle to the created temporary file
/// @throws fs::filesystem_error if cannot create a temporary file
open_handle_type create_file(std::ios::openmode mode);

/// Creates a temporary file in the system's temporary directory,
/// and opens it for reading and writing
/// @param[in] mode Specifies stream open mode
/// @param[out] ec Parameter for error reporting
/// @returns A handle to the created temporary file
open_handle_type create_file(std::ios::openmode mode, std::error_code& ec);

/// Creates a temporary directory with the given prefix in the system's
/// temporary directory
/// @param[in] prefix A prefix to attach to the temporary directory name
Expand All @@ -44,9 +20,39 @@ fs::path create_directory(std::string_view prefix);
/// Creates a temporary directory with the given prefix in the system's
/// temporary directory
/// @param[in] prefix A prefix to attach to the temporary directory name
/// @param[out] ec Parameter for error reporting
/// @param[out] ec Parameter for error reporting
/// @returns A path to the created temporary directory
fs::path create_directory(std::string_view prefix, std::error_code& ec);

#if defined(_WIN32)
/// Creates a temporary file in the system's temporary directory,
/// and opens it for reading and writing
/// @param[in] mode Specifies stream open mode
/// @returns A handle to the created temporary file
/// @throws fs::filesystem_error if cannot create a temporary file
std::FILE* create_file(std::ios::openmode mode);

/// Creates a temporary file in the system's temporary directory,
/// and opens it for reading and writing
/// @param[in] mode Specifies stream open mode
/// @param[out] ec Parameter for error reporting
/// @returns A handle to the created temporary file
std::FILE* create_file(std::ios::openmode mode, std::error_code& ec);
#elif __has_include(<unistd.h>)
/// Creates a temporary file in the system's temporary directory,
/// and opens it for reading and writing
/// @returns A handle to the created temporary file
/// @throws fs::filesystem_error if cannot create a temporary file
int create_file();

/// Creates a temporary file in the system's temporary directory,
/// and opens it for reading and writing
/// @param[out] ec Parameter for error reporting
/// @returns A handle to the created temporary file
int create_file(std::error_code& ec);
#else
#error "Target platform not supported"
#endif
} // namespace tmp

#endif // TMP_CREATE_H
5 changes: 3 additions & 2 deletions src/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,22 +151,23 @@ file::file(std::ios::openmode mode)
#endif
{
mode |= std::ios::in | std::ios::out;
open_handle_type handle = create_file(mode);

#if defined(__GLIBCXX__)
int handle = create_file();
sb = __gnu_cxx::stdio_filebuf<char>(handle, mode);
if (!sb.is_open()) {
close(handle);
throw fs::filesystem_error("", std::make_error_code(std::io_errc::stream));
}
#elif defined(_LIBCPP_VERSION)
this->handle = handle;
this->handle = create_file();
sb.__open(handle, mode);
if (!sb.is_open()) {
close(handle);
throw fs::filesystem_error("", std::make_error_code(std::io_errc::stream));
}
#else // MSVC
std::FILE* handle = create_file(mode);
underlying.reset(handle);
sb = std::filebuf(underlying.get());
#endif
Expand Down