44#include " create.hpp"
55#include " move.hpp"
66
7+ #include < array>
78#include < filesystem>
89#include < fstream>
910#include < ios>
1213#include < system_error>
1314#include < utility>
1415
16+ #ifdef _WIN32
17+ #define NOMINMAX
18+ #define UNICODE
19+ #include < Windows.h>
20+ #else
21+ #include < cerrno>
22+ #include < fcntl.h>
23+ #include < unistd.h>
24+ #endif
25+
1526namespace tmp {
27+ namespace {
28+
29+ // / A block size for file reading
30+ // / @note should always be less than INT_MAX
31+ constexpr std::size_t block_size = 4096 ;
32+
33+ // / A type of buffer for I/O file operations
34+ using buffer_type = std::array<std::byte, block_size>;
35+
36+ // / Opens a file in read-only mode
37+ // / @param[in] path The path to the file to open
38+ // / @param[out] ec Parameter for error reporting
39+ // / @returns A handle to the open file
40+ file::native_handle_type open (const fs::path& path,
41+ std::error_code& ec) noexcept {
42+ ec.clear ();
43+
44+ #ifdef _WIN32
45+ HANDLE handle =
46+ CreateFile (path.c_str (), GENERIC_READ,
47+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL ,
48+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
49+ if (handle == INVALID_HANDLE_VALUE) {
50+ ec = std::error_code (GetLastError (), std::system_category ());
51+ }
52+ #else
53+ int handle = ::open (path.c_str (), O_RDONLY | O_NONBLOCK);
54+ if (handle == -1 ) {
55+ ec = std::error_code (errno, std::system_category ());
56+ }
57+ #endif
58+
59+ return handle;
60+ }
61+
62+ // / Closes the given handle, ignoring any errors
63+ // / @param[in] handle The handle to close
64+ void close (file::native_handle_type handle) noexcept {
65+ #ifdef _WIN32
66+ CloseHandle (handle);
67+ #else
68+ ::close (handle);
69+ #endif
70+ }
71+
72+ // / Copies a file contents from the given path to the given file descriptor
73+ // / @param[in] from The path to the source file
74+ // / @param[in] to The target file descriptor
75+ // / @param[out] ec Parameter for error reporting
76+ void copy_file (const fs::path& from, file::native_handle_type to,
77+ std::error_code& ec) noexcept {
78+ // TODO: can be optimized using `sendfile`, `copyfile` or other system API
79+ file::native_handle_type source = open (from, ec);
80+ if (ec) {
81+ return ;
82+ }
83+
84+ buffer_type buffer = buffer_type ();
85+ while (true ) {
86+ #ifdef _WIN32
87+ DWORD bytes_read;
88+ if (!ReadFile (source, buffer.data (), block_size, &bytes_read, nullptr )) {
89+ ec = std::error_code (GetLastError (), std::system_category ());
90+ break ;
91+ }
92+ #else
93+ ssize_t bytes_read = read (source, buffer.data (), block_size);
94+ if (bytes_read < 0 ) {
95+ ec = std::error_code (errno, std::system_category ());
96+ break ;
97+ }
98+ #endif
99+ if (bytes_read == 0 ) {
100+ break ;
101+ }
102+
103+ #ifdef _WIN32
104+ DWORD written;
105+ if (!WriteFile (to, buffer.data (), bytes_read, &written, nullptr )) {
106+ ec = std::error_code (GetLastError (), std::system_category ());
107+ return ;
108+ }
109+ #else
110+ ssize_t written = write (to, buffer.data (), bytes_read);
111+ if (written < 0 ) {
112+ ec = std::error_code (errno, std::system_category ());
113+ break ;
114+ }
115+ #endif
116+ }
117+
118+ close (source);
119+ }
120+ } // namespace
16121
17122file::file (std::pair<fs::path, filebuf> handle) noexcept
18123 : entry(std::move(handle.first)),
@@ -26,7 +131,7 @@ file file::copy(const fs::path& path, std::ios::openmode mode) {
26131 file tmpfile = file (mode);
27132
28133 std::error_code ec;
29- fs:: copy_file (path, tmpfile, fs::copy_options::overwrite_existing , ec);
134+ copy_file (path, tmpfile. native_handle () , ec);
30135
31136 if (ec) {
32137 throw fs::filesystem_error (" Cannot create a temporary copy" , path, ec);
0 commit comments