33 DWORD desired_access = 0;
35 desired_access = GENERIC_READ | GENERIC_WRITE;
37 desired_access = GENERIC_READ;
39 desired_access = GENERIC_WRITE;
41 throw io_error(std::format(
"{}: Invalid AccessMode; expecting Readable and/or Writeable.", path.string()));
48 share_mode = FILE_SHARE_READ;
51 share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
54 DWORD creation_disposition;
57 creation_disposition = CREATE_ALWAYS;
59 creation_disposition = OPEN_ALWAYS;
63 creation_disposition = CREATE_NEW;
67 creation_disposition = TRUNCATE_EXISTING;
69 creation_disposition = OPEN_EXISTING;
73 throw io_error(std::format(
"{}: Invalid AccessMode; expecting CreateFile and/or OpenFile.", path.string()));
76 DWORD flags_and_attributes = 0;
78 flags_and_attributes |= FILE_FLAG_RANDOM_ACCESS;
81 flags_and_attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
84 flags_and_attributes |= FILE_FLAG_WRITE_THROUGH;
88 desired_access |= DELETE;
91 auto const file_name = path.native();
92 if ((_file_handle = CreateFileW(
93 file_name.data(), desired_access, share_mode, NULL, creation_disposition, flags_and_attributes, NULL)) !=
94 INVALID_HANDLE_VALUE) {
98 auto const error = GetLastError();
100 (creation_disposition == CREATE_ALWAYS or creation_disposition == OPEN_ALWAYS or
101 creation_disposition == CREATE_NEW)) {
103 auto directory = path;
104 directory.remove_filename();
105 std::filesystem::create_directories(directory);
107 if ((_file_handle = CreateFileW(
108 file_name.data(), desired_access, share_mode, NULL, creation_disposition, flags_and_attributes, NULL)) !=
109 INVALID_HANDLE_VALUE) {
116 [[nodiscard]]
bool closed()
noexcept
118 return _file_handle ==
nullptr;
126 [[nodiscard]] HANDLE file_handle()
const noexcept
133 hi_assert_not_null(_file_handle);
135 if (not FlushFileBuffers(_file_handle)) {
142 if (_file_handle != INVALID_HANDLE_VALUE) {
143 if (not CloseHandle(_file_handle)) {
146 _file_handle = INVALID_HANDLE_VALUE;
152 BY_HANDLE_FILE_INFORMATION file_information;
154 if (not GetFileInformationByHandle(_file_handle, &file_information)) {
158 return merge_bit_cast<std::size_t>(file_information.nFileSizeHigh, file_information.nFileSizeLow);
163 hi_assert_not_null(_file_handle);
169 whence_ = FILE_BEGIN;
172 whence_ = FILE_CURRENT;
181 LARGE_INTEGER offset_;
182 LARGE_INTEGER new_offset;
183 offset_.QuadPart = narrow_cast<LONGLONG>(offset);
184 if (not SetFilePointerEx(_file_handle, offset_, &new_offset, whence_)) {
188 return narrow_cast<std::size_t>(new_offset.QuadPart);
191 void rename(std::filesystem::path
const& destination,
bool overwrite_existing)
193 auto dst_filename = destination.native();
194 auto dst_filename_wsize = (dst_filename.size() + 1) *
sizeof(WCHAR);
196 auto const rename_info_size = narrow_cast<DWORD>(
sizeof(_FILE_RENAME_INFO) + dst_filename_wsize);
199 rename_info_alloc.
resize(rename_info_size);
201 auto rename_info =
reinterpret_cast<PFILE_RENAME_INFO
>(rename_info_alloc.data());
203 rename_info->ReplaceIfExists = overwrite_existing;
204 rename_info->RootDirectory =
nullptr;
205 rename_info->FileNameLength = narrow_cast<DWORD>(dst_filename_wsize);
206 std::memcpy(rename_info->FileName, dst_filename.c_str(), dst_filename_wsize);
208 if (not SetFileInformationByHandle(_file_handle, FileRenameInfo, rename_info, rename_info_size)) {
215 hi_assert(_file_handle != INVALID_HANDLE_VALUE);
219 auto to_write = size < 0x8000 ? narrow_cast<DWORD>(size) : DWORD{0x8000};
220 auto written = DWORD{};
221 if (not WriteFile(_file_handle, data, to_write, &written,
nullptr)) {
224 }
else if (written == 0) {
225 throw io_error(
"Could not write to file. Reached end-of-file.");
228 advance_bytes(data, written);
235 hi_assert(_file_handle != INVALID_HANDLE_VALUE);
239 auto to_read = size < 0x8000 ? narrow_cast<DWORD>(size) : DWORD{0x8000};
240 auto has_read = DWORD{};
242 if (!ReadFile(_file_handle, data, to_read, &has_read,
nullptr)) {
245 }
else if (has_read == 0) {
250 advance_bytes(data, has_read);
252 total_read += has_read;
260 HANDLE _file_handle =
nullptr;