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
10 changes: 3 additions & 7 deletions include/tmp/file
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,12 @@ public:
static file copy(const std::filesystem::path& path,
std::ios::openmode mode = std::ios::in | std::ios::out);

#if __cpp_lib_fstream_native_handle >= 202306L
/// Implementation-defined handle type to the temporary file
using native_handle_type = std::filebuf::native_handle_type;
using native_handle_type = filebuf::native_handle_type;

/// Returns an implementation-defined handle to this entry
/// Returns an implementation-defined handle to this file
/// @returns The underlying implementation-defined handle
native_handle_type native_handle() const noexcept {
return rdbuf()->native_handle();
}
#endif
native_handle_type native_handle() const noexcept;

/// Returns pointer to the underlying raw file device object
/// @returns A pointer to the underlying raw file device
Expand Down
24 changes: 22 additions & 2 deletions include/tmp/filebuf
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,40 @@ namespace tmp {
/// opening a file fails
class filebuf : public std::filebuf {
public:
/// 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

/// Implementation-defined handle type to the file
#if defined(_WIN32)
using native_handle_type = std::FILE*;
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

/// Creates a file buffer that is not associated with any file
filebuf() noexcept;

/// Opens a file and configures it as the associated character sequence
/// @param handle A handle to the open file
/// @param mode The file opening mode
/// @returns `this` file buffer, or a null pointer on failure
filebuf* open(native_handle_type handle, std::ios::openmode mode);
filebuf* open(open_handle_type handle, std::ios::openmode mode);

/// Returns an implementation-defined handle to this file
/// @returns The underlying implementation-defined handle
native_handle_type native_handle() const noexcept;

private:
/// Native handle to the open file
open_handle_type handle;
};
} // namespace tmp

Expand Down
2 changes: 1 addition & 1 deletion src/create.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ const wchar_t* make_mdstring(std::ios::openmode mode) noexcept {

/// Closes the given handle, ignoring any errors
/// @param[in] handle The handle to close
void close(filebuf::native_handle_type handle) noexcept {
void close(filebuf::open_handle_type handle) noexcept {
#ifdef _WIN32
fclose(handle);
#else
Expand Down
4 changes: 4 additions & 0 deletions src/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ file file::copy(const fs::path& path, std::ios::openmode mode) {
return tmpfile;
}

file::native_handle_type file::native_handle() const noexcept {
return sb.native_handle();
}

std::filebuf* file::rdbuf() const noexcept {
return const_cast<filebuf*>(std::addressof(sb)); // NOLINT(*-const-cast)
}
Expand Down
42 changes: 41 additions & 1 deletion src/filebuf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,40 @@

#include <ios>

#ifdef _WIN32
#include <Windows.h>
#include <io.h>
#endif

#if __has_include(<__config>)
#include <__config> // libc++ configuration
#endif

namespace tmp {

filebuf* filebuf::open(native_handle_type handle, std::ios::openmode mode) {
// Confirm that native_handle_type matches `TriviallyCopyable` named requirement
static_assert(std::is_trivially_copyable_v<filebuf::native_handle_type>);

#ifdef _WIN32
// Confirm that `HANDLE` is as implemented in `entry`
static_assert(std::is_same_v<HANDLE, filebuf::native_handle_type>);
#endif

filebuf::filebuf() noexcept
:
#if defined(_LIBCPP_VERSION) || defined(__GLIBCXX__)
handle(-1)
#elif defined(_MSC_VER)
handle(nullptr)
#elif
#error "Target C++ standard library is not supported"
#endif
{
}

filebuf* filebuf::open(open_handle_type handle, std::ios::openmode mode) {
this->handle = handle;

#if defined(_LIBCPP_VERSION)
return this->__open(handle, mode) != nullptr ? this : nullptr;
#elif defined(__GLIBCXX__)
Expand Down Expand Up @@ -40,4 +67,17 @@ filebuf* filebuf::open(native_handle_type handle, std::ios::openmode mode) {
#error "Target C++ standard library is not supported"
#endif
}

filebuf::native_handle_type filebuf::native_handle() const noexcept {
#ifdef _WIN32
intptr_t osfhandle = _get_osfhandle(_fileno(handle));
if (osfhandle == -1) {
return nullptr;
}

return reinterpret_cast<void*>(osfhandle);
#else
return handle;
#endif
}
} // namespace tmp
11 changes: 0 additions & 11 deletions tests/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ bool is_open(const file& file) {
return file.rdbuf()->is_open();
}

#if __cpp_lib_fstream_native_handle >= 202306L
/// Checks if the given file handle is valid
/// @param handle handle to check
/// @returns whether the handle is valid
Expand All @@ -38,7 +37,6 @@ bool is_open(file::native_handle_type handle) {
return fcntl(handle, F_GETFD) != -1;
#endif
}
#endif

/// Tests file type traits and member types
TEST(file, type_traits) {
Expand All @@ -61,10 +59,7 @@ TEST(file, create) {
EXPECT_TRUE(fs::is_regular_file(tmpfile));
EXPECT_TRUE(fs::equivalent(parent, fs::temp_directory_path()));
EXPECT_TRUE(is_open(tmpfile));

#if __cpp_lib_fstream_native_handle >= 202306L
EXPECT_TRUE(is_open(tmpfile.native_handle()));
#endif

fs::perms permissions = fs::status(tmpfile).permissions();
#ifdef _WIN32
Expand Down Expand Up @@ -199,22 +194,16 @@ TEST(file, move_to_non_existing_directory) {
/// Tests that destructor removes a file
TEST(file, destructor) {
fs::path path;
#if __cpp_lib_fstream_native_handle >= 202306L
file::native_handle_type handle;
#endif

{
file tmpfile = file();
path = tmpfile;
#if __cpp_lib_fstream_native_handle >= 202306L
handle = tmpfile.native_handle();
#endif
}

EXPECT_FALSE(fs::exists(path));
#if __cpp_lib_fstream_native_handle >= 202306L
EXPECT_FALSE(is_open(handle));
#endif
}

/// Tests file move constructor
Expand Down
Loading