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
44 changes: 35 additions & 9 deletions include/tmp/file
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,31 @@
#define TMP_FILE_H

#include <cstddef>
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <ios>
#include <istream>
#include <memory>

#ifdef __GLIBCXX__
#include <ext/stdio_filebuf.h>
#endif

namespace tmp {

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

extern "C++" std::FILE* create_file();
extern "C++" file_native_handle get_native_handle(std::FILE* file) noexcept;

/// tmp::file is a smart handle that manages a binary temporary file, ensuring
/// its deletion when the handle goes out of scope
///
Expand Down Expand Up @@ -53,17 +67,27 @@ namespace tmp {
class file : public std::iostream {
public:
/// Implementation-defined handle type to the file
#if defined(_WIN32)
using native_handle_type = void*; // HANDLE
#elif __has_include(<unistd.h>)
using native_handle_type = int; // POSIX file descriptor
#else
#error "Target platform not supported"
#endif
using native_handle_type = file_native_handle;

/// Creates and opens a binary temporary file as if by POSIX `tmpfile`
/// @throws std::filesystem::filesystem_error if cannot create a file
explicit file();
explicit file()
: std::iostream(std::addressof(sb)),
underlying(create_file(), &std::fclose) {
#if defined(_MSC_VER)
sb = std::filebuf(underlying.get());
#elif defined(_LIBCPP_VERSION)
sb.__open(fileno(underlying.get()), binary | in | out);
#else
sb = __gnu_cxx::stdio_filebuf<char>(underlying.get(), binary | in | out);
#endif

if (!sb.is_open()) {
std::error_code ec = std::make_error_code(std::io_errc::stream);
throw std::filesystem::filesystem_error("Cannot create a temporary file",
ec);
}
}

file(const file&) = delete;
file& operator=(const file&) = delete;
Expand All @@ -87,7 +111,9 @@ public:

/// Returns an implementation-defined handle to this file
/// @returns The underlying implementation-defined handle
native_handle_type native_handle() const noexcept;
native_handle_type native_handle() const noexcept {
return get_native_handle(underlying.get());
}

/// Closes and deletes this file
~file() noexcept override = default;
Expand Down
13 changes: 10 additions & 3 deletions src/abi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#ifndef TMP_ABI_H
#define TMP_ABI_H

#include <cstdio>
#include <filesystem>
#include <string_view>

Expand All @@ -15,10 +16,16 @@

namespace tmp {

std::filesystem::path abi create_directory(std::string_view prefix);
void abi remove_all(const std::filesystem::path& path) noexcept;
auto abi create_directory(std::string_view prefix) -> std::filesystem::path;
auto abi remove_all(const std::filesystem::path& path) noexcept -> void;

class abi file;
auto abi create_file() -> std::FILE*;
auto abi get_native_handle(std::FILE* file) noexcept ->
#if defined(_WIN32)
void*;
#elif __has_include(<unistd.h>)
int;
#endif
} // namespace tmp

#endif // TMP_ABI_H
1 change: 1 addition & 0 deletions src/directory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

namespace tmp {
namespace {

namespace fs = std::filesystem;

/// Checks if the given prefix is valid to attach to a temporary directory name
Expand Down
42 changes: 7 additions & 35 deletions src/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
#endif

namespace tmp {
namespace {

namespace fs = std::filesystem;

Expand All @@ -35,22 +34,6 @@ static_assert(std::is_trivially_copyable_v<file::native_handle_type>);
static_assert(std::is_same_v<HANDLE, file::native_handle_type>);
#endif

#ifndef _MSC_VER
/// Open mode for binary temporary files
constexpr auto mode = std::ios::binary | std::ios::in | std::ios::out;
#endif

/// Returns an implementation-defined handle to the file
/// @param[in] file The file to the native handle for
/// @returns The underlying implementation-defined handle
file::native_handle_type get_native_handle(std::FILE* file) noexcept {
#ifdef _WIN32
return reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(file)));
#else
return fileno(file);
#endif
}

/// Creates and opens a binary temporary file as if by POSIX `tmpfile`
/// @returns A pointer to the file stream associated with the temporary file
/// @throws fs::filesystem_error if cannot create a temporary file
Expand All @@ -63,26 +46,15 @@ std::FILE* create_file() {

return file;
}
} // namespace

file::file()
: std::iostream(std::addressof(sb)),
underlying(create_file(), &std::fclose) {
#if defined(_MSC_VER)
sb = std::filebuf(underlying.get());
#elif defined(_LIBCPP_VERSION)
sb.__open(get_native_handle(underlying.get()), mode);
/// Returns an implementation-defined handle to the file
/// @param[in] file The file to the native handle for
/// @returns The underlying implementation-defined handle
file::native_handle_type get_native_handle(std::FILE* file) noexcept {
#ifdef _WIN32
return reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(file)));
#else
sb = __gnu_cxx::stdio_filebuf<char>(underlying.get(), mode);
return fileno(file);
#endif

if (!sb.is_open()) {
std::error_code ec = std::make_error_code(std::io_errc::stream);
throw fs::filesystem_error("Cannot create a temporary file", ec);
}
}

file::native_handle_type file::native_handle() const noexcept {
return get_native_handle(underlying.get());
}
} // namespace tmp