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
60 changes: 47 additions & 13 deletions src/create.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#define _CRT_SECURE_NO_WARNINGS // NOLINT

#include "create.hpp"

#include <fcntl.h>
#include <filesystem>
#include <iostream>
#include <stdexcept>
Expand All @@ -10,10 +13,10 @@
#define UNICODE
#include <Windows.h>
#include <array>
#include <corecrt_io.h>
#include <cwchar>
#else
#include <cerrno>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#endif
Expand Down Expand Up @@ -58,7 +61,7 @@ fs::path make_path(std::string_view prefix) {
}

/// Makes a mode string for opening a temporary file using `_wfsopen`
/// @param mode The file opening mode
/// @param[in] mode The file opening mode
/// @returns A suitable mode string
const wchar_t* make_mdstring(std::ios::openmode mode) noexcept {
switch (mode & ~std::ios::in & ~std::ios::out & ~std::ios::ate) {
Expand All @@ -76,6 +79,46 @@ const wchar_t* make_mdstring(std::ios::openmode mode) noexcept {
return nullptr;
}
}

/// Creates and opens a temporary file in the current user's temporary directory
/// @param[in] mode The file opening mode
/// @param[out] ec Parameter for error reporting
/// @returns A handle to the created temporary file
/// @throws std::invalid_argument if the given openmode is invalid
std::FILE* create_file(std::ios::openmode mode, std::error_code& ec) {
const wchar_t* mdstr = make_mdstring(mode);
if (mdstr == nullptr) {
throw std::invalid_argument(
"Cannot create a temporary file: invalid openmode");
}

std::FILE* file = std::tmpfile();
if (file == nullptr) {
ec.assign(errno, std::generic_category());
return nullptr;
}

HANDLE handle = reinterpret_cast<void*>(_get_osfhandle(_fileno(file)));

std::wstring path;
path.resize(MAX_PATH);
DWORD ret = GetFinalPathNameByHandle(handle, path.data(), MAX_PATH, 0);
if (ret == 0) {
ec.assign(GetLastError(), std::system_category());
return nullptr;
}

path.resize(ret);

file = _wfreopen(path.c_str(), make_mdstring(mode), file);
Comment thread
bugdea1er marked this conversation as resolved.
if (file == nullptr) {
ec.assign(errno, std::generic_category());
return nullptr;
}

ec.clear();
return file;
}
#endif
} // namespace

Expand Down Expand Up @@ -112,21 +155,12 @@ fs::path create_directory(std::string_view prefix) {

#ifdef _WIN32
std::FILE* create_file(std::ios::openmode mode) {
const wchar_t* mdstr = make_mdstring(mode);
if (mdstr == nullptr) {
throw std::invalid_argument(
"Cannot create a temporary file: invalid openmode");
}

fs::path::string_type path = make_path("");

std::FILE* file = _wfsopen(path.c_str(), mdstr, _SH_DENYNO);
std::error_code ec;
std::FILE* file = create_file(mode, ec);
if (file == nullptr) {
std::error_code ec = std::error_code(errno, std::system_category());
throw fs::filesystem_error("Cannot create a temporary file", ec);
}

DeleteFile(path.c_str());
return file;
}
#else
Expand Down
1 change: 0 additions & 1 deletion tests/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ TEST(file, create) {

EXPECT_EQ(file_info.dwVolumeSerialNumber,
temp_directory_info.dwVolumeSerialNumber);
EXPECT_EQ(file_info.nNumberOfLinks, 0); // Has no hardlinks
#else
struct stat file_stat;
fstat(tmpfile.native_handle(), &file_stat);
Expand Down
Loading