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,
17 GENERIC_READ | GENERIC_WRITE
20 const std::array<DWORD, Windows_Handle::mode_count> Windows_Handle::share_mode
22 FILE_SHARE_READ | FILE_SHARE_WRITE,
26 FILE_SHARE_READ | FILE_SHARE_WRITE,
27 FILE_SHARE_READ | FILE_SHARE_WRITE,
31 const std::array<DWORD, Windows_Handle::mode_count> Windows_Handle::creation_disposition
43 static DWORD size_to_dword(
size_t size)
46 return DWORD(std::min(size,
size_t(1ULL << 31)));
50 void Windows_Handle::throw_last_error
57 const DWORD last_error = GetLastError();
62 FORMAT_MESSAGE_ALLOCATE_BUFFER |
63 FORMAT_MESSAGE_FROM_SYSTEM,
66 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
72 std::string error((
const char *)buffer);
74 while (!error.empty() && std::isspace(error.back()))
79 std::string(action) +
' ' + std::string(file_name) +
": " + error
84 BOOL Windows_Handle::lock(Lock_Operation op, int64_t start, int64_t size)
87 if (start < 0 || size < 0)
90 ULARGE_INTEGER large_start;
91 ULARGE_INTEGER large_size;
93 large_start.QuadPart = uint64_t(start);
94 large_size.QuadPart = size > 0 ? uint64_t(size) : uint64_t(-1);
96 OVERLAPPED overlapped{};
97 overlapped.Offset = large_start.u.LowPart;
98 overlapped.OffsetHigh = large_start.u.HighPart;
102 case Lock_Operation::shared_lock:
108 large_size.u.LowPart,
109 large_size.u.HighPart,
114 case Lock_Operation::exclusive_lock:
118 LOCKFILE_EXCLUSIVE_LOCK,
120 large_size.u.LowPart,
121 large_size.u.HighPart,
126 case Lock_Operation::unlock:
131 large_size.u.LowPart,
132 large_size.u.HighPart,
142 void Windows_Handle::shared_lock(int64_t start, int64_t size)
145 if (!lock(Lock_Operation::shared_lock, start, size))
146 throw_last_error(
"read-locking",
"file");
150 void Windows_Handle::exclusive_lock(int64_t start, int64_t size)
153 if (!lock(Lock_Operation::exclusive_lock, start, size))
154 throw_last_error(
"write-locking",
"file");
158 void Windows_Handle::unlock(int64_t start, int64_t size)
noexcept
161 lock(Lock_Operation::unlock, start, size);
168 OVERLAPPED overlapped{};
169 overlapped.Pointer = PVOID(offset);
173 if (ReadFile(file, buffer, size_to_dword(size), &result, &overlapped))
174 return size_t(result);
177 if (GetLastError() == ERROR_HANDLE_EOF)
180 throw_last_error(
"reading",
"file");
197 while (written < size)
199 OVERLAPPED overlapped{};
200 overlapped.Pointer = PVOID(offset + written);
202 DWORD actually_written;
210 size_to_dword(size - written),
216 throw_last_error(
"writing",
"file");
219 written += actually_written;
227 if (FlushFileBuffers(file) == 0)
228 throw_last_error(
"syncing",
"file");
240 desired_access[static_cast<size_t>(mode)],
241 share_mode[static_cast<size_t>(mode)],
243 creation_disposition[static_cast<size_t>(mode)],
244 FILE_ATTRIBUTE_NORMAL,
249 if (file == INVALID_HANDLE_VALUE)
250 throw_last_error(
"opening", file_name);
266 LARGE_INTEGER result;
268 if (GetFileSizeEx(file, &result))
269 return int64_t(result.QuadPart);
271 throw_last_error(
"getting size of",
"file");
void exclusive_lock_tail()
Windows_File(const char *file_name, Open_Mode mode)
void sync() override
Write data durably (including file-size change)
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