9 const std::array<DWORD, Windows_Handle::mode_count> Windows_Handle::desired_access
12 GENERIC_READ | GENERIC_WRITE,
13 GENERIC_READ | GENERIC_WRITE,
14 GENERIC_READ | GENERIC_WRITE,
15 GENERIC_READ | GENERIC_WRITE,
16 GENERIC_READ | GENERIC_WRITE
19 const std::array<DWORD, Windows_Handle::mode_count> Windows_Handle::share_mode
21 FILE_SHARE_READ | FILE_SHARE_WRITE,
25 FILE_SHARE_READ | FILE_SHARE_WRITE,
26 FILE_SHARE_READ | FILE_SHARE_WRITE
29 const std::array<DWORD, Windows_Handle::mode_count> Windows_Handle::creation_disposition
40 static DWORD size_to_dword(
size_t size)
43 return DWORD(std::min(size,
size_t(1ULL << 31)));
47 void Windows_Handle::throw_last_error
54 const DWORD last_error = GetLastError();
59 FORMAT_MESSAGE_ALLOCATE_BUFFER |
60 FORMAT_MESSAGE_FROM_SYSTEM,
63 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
69 std::string error((
const char *)buffer);
71 while (!error.empty() && std::isspace(error.back()))
76 std::string(action) +
' ' + std::string(file_name) +
": " + error
81 BOOL Windows_Handle::lock(Lock_Operation op, int64_t start, int64_t size)
84 if (start < 0 || size < 0)
87 ULARGE_INTEGER large_start;
88 ULARGE_INTEGER large_size;
90 large_start.QuadPart = uint64_t(start);
91 large_size.QuadPart = size > 0 ? uint64_t(size) : uint64_t(-1);
93 OVERLAPPED overlapped{};
94 overlapped.Offset = large_start.u.LowPart;
95 overlapped.OffsetHigh = large_start.u.HighPart;
99 case Lock_Operation::shared_lock:
105 large_size.u.LowPart,
106 large_size.u.HighPart,
111 case Lock_Operation::exclusive_lock:
115 LOCKFILE_EXCLUSIVE_LOCK,
117 large_size.u.LowPart,
118 large_size.u.HighPart,
123 case Lock_Operation::unlock:
128 large_size.u.LowPart,
129 large_size.u.HighPart,
139 void Windows_Handle::shared_lock(int64_t start, int64_t size)
142 if (!lock(Lock_Operation::shared_lock, start, size))
143 throw_last_error(
"Read-locking",
"file");
147 void Windows_Handle::exclusive_lock(int64_t start, int64_t size)
150 if (!lock(Lock_Operation::exclusive_lock, start, size))
151 throw_last_error(
"Write-locking",
"file");
155 void Windows_Handle::unlock(int64_t start, int64_t size)
noexcept
158 lock(Lock_Operation::unlock, start, size);
165 OVERLAPPED overlapped{};
166 overlapped.Pointer = PVOID(offset);
170 if (ReadFile(file, buffer, size_to_dword(size), &result, &overlapped))
171 return size_t(result);
174 if (GetLastError() == ERROR_HANDLE_EOF)
177 throw_last_error(
"Reading",
"file");
194 while (written < size)
196 OVERLAPPED overlapped{};
197 overlapped.Pointer = PVOID(offset + written);
199 DWORD actually_written;
207 size_to_dword(size - written),
213 throw_last_error(
"Writing",
"file");
216 written += actually_written;
224 if (FlushFileBuffers(file) == 0)
225 throw_last_error(
"syncing",
"file");
237 desired_access[static_cast<size_t>(mode)],
238 share_mode[static_cast<size_t>(mode)],
240 creation_disposition[static_cast<size_t>(mode)],
241 FILE_ATTRIBUTE_NORMAL,
246 if (file == INVALID_HANDLE_VALUE)
247 throw_last_error(
"Opening", file_name);
263 LARGE_INTEGER result;
265 if (GetFileSizeEx(file, &result))
266 return int64_t(result.QuadPart);
268 throw_last_error(
"Getting size of",
"file");
void exclusive_lock_tail()
void destructor_flush() noexcept
Windows_File(const char *file_name, Open_Mode mode)
void sync() override
Write data and meta-data (such as file size) durably to permanent storage.
Windows_Handle(const char *file_name, Open_Mode mode)
void pwrite(const char *data, size_t size, int64_t offset) override
Write a range of bytes. Extend file size if necessary.
int64_t get_size() const override
Get the size of the file, or -1 if it is unknown.
size_t pread(char *data, size_t size, int64_t offset) const override
Read a range of bytes.
~Windows_Handle() override
@ write_lock
like write_existing_or_create_new, but waits instead of failing if already locked