@@ -33,24 +33,29 @@ constexpr std::size_t block_size = 4096;
3333// / A type of buffer for I/O file operations
3434using buffer_type = std::array<std::byte, block_size>;
3535
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
36+ // / Opens a file and returns its handle
37+ // / @param[in] path The path to the file to open
38+ // / @param[in] readonly Whether to open file only for reading
39+ // / @param[out] ec Parameter for error reporting
3940// / @returns A handle to the open file
40- file::native_handle_type open (const fs::path& path,
41+ file::native_handle_type open (const fs::path& path, bool readonly,
4142 std::error_code& ec) noexcept {
4243 ec.clear ();
4344
4445#ifdef _WIN32
46+ DWORD access = readonly ? GENERIC_READ : GENERIC_WRITE;
47+ DWORD creation_disposition = readonly ? OPEN_EXISTING : CREATE_ALWAYS;
48+ DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
49+
4550 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 );
51+ CreateFile (path.c_str (), access, share_mode, nullptr ,
52+ creation_disposition, FILE_ATTRIBUTE_NORMAL, nullptr );
4953 if (handle == INVALID_HANDLE_VALUE) {
5054 ec = std::error_code (GetLastError (), std::system_category ());
5155 }
5256#else
53- int handle = ::open (path.c_str (), O_RDONLY | O_NONBLOCK);
57+ int oflag = readonly ? O_RDONLY | O_NONBLOCK : O_RDWR | O_TRUNC | O_CREAT;
58+ int handle = ::open (path.c_str (), oflag);
5459 if (handle == -1 ) {
5560 ec = std::error_code (errno, std::system_category ());
5661 }
@@ -69,28 +74,23 @@ void close(file::native_handle_type handle) noexcept {
6974#endif
7075}
7176
72- // / Copies a file contents from the given path to the given file descriptor
73- // / @param[in] from The path to the source file
77+ // / Copies file contents from one file descriptor to another
78+ // / @param[in] from The source file descriptor
7479// / @param[in] to The target file descriptor
7580// / @param[out] ec Parameter for error reporting
76- void copy_file (const fs::path& from, file::native_handle_type to,
81+ void copy_file (file::native_handle_type from, file::native_handle_type to,
7782 std::error_code& ec) noexcept {
7883 // 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-
8484 buffer_type buffer = buffer_type ();
8585 while (true ) {
8686#ifdef _WIN32
8787 DWORD bytes_read;
88- if (!ReadFile (source , buffer.data (), block_size, &bytes_read, nullptr )) {
88+ if (!ReadFile (from , buffer.data (), block_size, &bytes_read, nullptr )) {
8989 ec = std::error_code (GetLastError (), std::system_category ());
9090 break ;
9191 }
9292#else
93- ssize_t bytes_read = read (source , buffer.data (), block_size);
93+ ssize_t bytes_read = read (from , buffer.data (), block_size);
9494 if (bytes_read < 0 ) {
9595 ec = std::error_code (errno, std::system_category ());
9696 break ;
@@ -114,8 +114,32 @@ void copy_file(const fs::path& from, file::native_handle_type to,
114114 }
115115#endif
116116 }
117+ }
117118
118- close (source);
119+ // / Copies file contents from the given path to the given file descriptor
120+ // / @param[in] from The path to the source file
121+ // / @param[in] to The target file descriptor
122+ // / @param[out] ec Parameter for error reporting
123+ void copy_file (const fs::path& from, file::native_handle_type to,
124+ std::error_code& ec) noexcept {
125+ file::native_handle_type source = open (from, /* readonly=*/ true , ec);
126+ if (!ec) {
127+ copy_file (source, to, ec);
128+ close (source);
129+ }
130+ }
131+
132+ // / Copies file contents from the given path to the given file descriptor
133+ // / @param[in] from The source file descriptor
134+ // / @param[in] to The path to the target file
135+ // / @param[out] ec Parameter for error reporting
136+ void copy_file (file::native_handle_type from, const fs::path& to,
137+ std::error_code& ec) noexcept {
138+ file::native_handle_type target = open (to, /* readonly=*/ false , ec);
139+ if (!ec) {
140+ copy_file (from, target, ec);
141+ close (target);
142+ }
119143}
120144} // namespace
121145
@@ -145,13 +169,16 @@ file::native_handle_type file::native_handle() const noexcept {
145169}
146170
147171void file::move (const fs::path& to) {
148- sb.close ();
172+ // TODO: I couldn't figure out how to create a hard link to a file without
173+ // hard links, so I just copy it even within the same file system
174+
175+ seekg (0 , std::ios::beg);
149176
150177 std::error_code ec;
151- tmp::move (* this , to, ec);
178+ copy_file ( native_handle () , to, ec);
152179
153180 if (ec) {
154- throw fs::filesystem_error (" Cannot move a temporary file" , path (), to, ec);
181+ throw fs::filesystem_error (" Cannot move a temporary file" , to, ec);
155182 }
156183
157184 entry::clear ();
0 commit comments