Joedb 10.2.1
The Journal-Only Embedded Database
Loading...
Searching...
No Matches
Windows_File.cpp
Go to the documentation of this file.
3
4#include <algorithm>
5#include <cctype>
6
7namespace joedb
8{
9 const std::array<DWORD, Windows_Handle::mode_count> Windows_Handle::desired_access
10 {
11 GENERIC_READ,
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
18 };
19
20 const std::array<DWORD, Windows_Handle::mode_count> Windows_Handle::share_mode
21 {
22 FILE_SHARE_READ | FILE_SHARE_WRITE,
23 FILE_SHARE_READ,
24 FILE_SHARE_READ,
25 FILE_SHARE_READ,
26 FILE_SHARE_READ | FILE_SHARE_WRITE,
27 FILE_SHARE_READ | FILE_SHARE_WRITE,
28 FILE_SHARE_READ,
29 };
30
31 const std::array<DWORD, Windows_Handle::mode_count> Windows_Handle::creation_disposition
32 {
33 OPEN_EXISTING,
34 OPEN_EXISTING,
35 CREATE_NEW,
36 OPEN_ALWAYS,
37 OPEN_ALWAYS,
38 OPEN_ALWAYS,
39 CREATE_ALWAYS
40 };
41
42 /////////////////////////////////////////////////////////////////////////////
43 static DWORD size_to_dword(size_t size)
44 /////////////////////////////////////////////////////////////////////////////
45 {
46 return DWORD(std::min(size, size_t(1ULL << 31)));
47 }
48
49 /////////////////////////////////////////////////////////////////////////////
50 void Windows_Handle::throw_last_error
51 /////////////////////////////////////////////////////////////////////////////
52 (
53 const char *action,
54 const char *file_name
55 )
56 {
57 const DWORD last_error = GetLastError();
58 LPVOID buffer;
59
60 FormatMessage
61 (
62 FORMAT_MESSAGE_ALLOCATE_BUFFER |
63 FORMAT_MESSAGE_FROM_SYSTEM,
64 NULL,
65 last_error,
66 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
67 (LPTSTR)&buffer,
68 0,
69 NULL
70 );
71
72 std::string error((const char *)buffer);
73 LocalFree(buffer);
74 while (!error.empty() && std::isspace(error.back()))
75 error.pop_back();
76
77 throw Exception
78 (
79 std::string(action) + ' ' + std::string(file_name) + ": " + error
80 );
81 }
82
83 /////////////////////////////////////////////////////////////////////////////
84 BOOL Windows_Handle::lock(Lock_Operation op, int64_t start, int64_t size)
85 /////////////////////////////////////////////////////////////////////////////
86 {
87 if (start < 0 || size < 0)
88 return FALSE;
89
90 ULARGE_INTEGER large_start;
91 ULARGE_INTEGER large_size;
92
93 large_start.QuadPart = uint64_t(start);
94 large_size.QuadPart = size > 0 ? uint64_t(size) : uint64_t(-1);
95
96 OVERLAPPED overlapped{};
97 overlapped.Offset = large_start.u.LowPart;
98 overlapped.OffsetHigh = large_start.u.HighPart;
99
100 switch(op)
101 {
102 case Lock_Operation::shared_lock:
103 return LockFileEx
104 (
105 file,
106 0,
107 0,
108 large_size.u.LowPart,
109 large_size.u.HighPart,
110 &overlapped
111 );
112 break;
113
114 case Lock_Operation::exclusive_lock:
115 return LockFileEx
116 (
117 file,
118 LOCKFILE_EXCLUSIVE_LOCK,
119 0,
120 large_size.u.LowPart,
121 large_size.u.HighPart,
122 &overlapped
123 );
124 break;
125
126 case Lock_Operation::unlock:
127 return UnlockFileEx
128 (
129 file,
130 0,
131 large_size.u.LowPart,
132 large_size.u.HighPart,
133 &overlapped
134 );
135 break;
136 }
137
138 return FALSE;
139 }
140
141 /////////////////////////////////////////////////////////////////////////////
142 void Windows_Handle::shared_lock(int64_t start, int64_t size)
143 /////////////////////////////////////////////////////////////////////////////
144 {
145 if (!lock(Lock_Operation::shared_lock, start, size))
146 throw_last_error("read-locking", "file");
147 }
148
149 /////////////////////////////////////////////////////////////////////////////
150 void Windows_Handle::exclusive_lock(int64_t start, int64_t size)
151 /////////////////////////////////////////////////////////////////////////////
152 {
153 if (!lock(Lock_Operation::exclusive_lock, start, size))
154 throw_last_error("write-locking", "file");
155 }
156
157 /////////////////////////////////////////////////////////////////////////////
158 void Windows_Handle::unlock(int64_t start, int64_t size) noexcept
159 /////////////////////////////////////////////////////////////////////////////
160 {
161 lock(Lock_Operation::unlock, start, size);
162 }
163
164 /////////////////////////////////////////////////////////////////////////////
165 size_t Windows_Handle::pread(char* buffer, size_t size, int64_t offset) const
166 /////////////////////////////////////////////////////////////////////////////
167 {
168 OVERLAPPED overlapped{};
169 overlapped.Pointer = PVOID(offset);
170
171 DWORD result;
172
173 if (ReadFile(file, buffer, size_to_dword(size), &result, &overlapped))
174 return size_t(result);
175 else
176 {
177 if (GetLastError() == ERROR_HANDLE_EOF)
178 return 0;
179 else
180 throw_last_error("reading", "file");
181 }
182
183 return 0;
184 }
185
186 /////////////////////////////////////////////////////////////////////////////
188 /////////////////////////////////////////////////////////////////////////////
189 (
190 const char* buffer,
191 size_t size,
192 int64_t offset
193 )
194 {
195 size_t written = 0;
196
197 while (written < size)
198 {
199 OVERLAPPED overlapped{};
200 overlapped.Pointer = PVOID(offset + written);
201
202 DWORD actually_written;
203
204 if
205 (
206 !WriteFile
207 (
208 file,
209 buffer + written,
210 size_to_dword(size - written),
211 &actually_written,
212 &overlapped
213 )
214 )
215 {
216 throw_last_error("writing", "file");
217 }
218
219 written += actually_written;
220 }
221 }
222
223 /////////////////////////////////////////////////////////////////////////////
225 /////////////////////////////////////////////////////////////////////////////
226 {
227 if (FlushFileBuffers(file) == 0)
228 throw_last_error("syncing", "file");
229 }
230
231 /////////////////////////////////////////////////////////////////////////////
232 Windows_Handle::Windows_Handle(const char *file_name, const Open_Mode mode):
233 /////////////////////////////////////////////////////////////////////////////
234 Abstract_File(mode),
235 file
236 (
237 CreateFileA
238 (
239 file_name,
240 desired_access[static_cast<size_t>(mode)],
241 share_mode[static_cast<size_t>(mode)],
242 NULL,
243 creation_disposition[static_cast<size_t>(mode)],
244 FILE_ATTRIBUTE_NORMAL,
245 NULL
246 )
247 )
248 {
249 if (file == INVALID_HANDLE_VALUE)
250 throw_last_error("opening", file_name);
251 }
252
253 /////////////////////////////////////////////////////////////////////////////
254 Windows_File::Windows_File(const char *file_name, const Open_Mode mode):
255 /////////////////////////////////////////////////////////////////////////////
256 Windows_Handle(file_name, mode)
257 {
258 if (mode == Open_Mode::write_lock)
260 }
261
262 /////////////////////////////////////////////////////////////////////////////
264 /////////////////////////////////////////////////////////////////////////////
265 {
266 LARGE_INTEGER result;
267
268 if (GetFileSizeEx(file, &result))
269 return int64_t(result.QuadPart);
270 else
271 throw_last_error("getting size of", "file");
272
273 return -1;
274 }
275
276 /////////////////////////////////////////////////////////////////////////////
278 /////////////////////////////////////////////////////////////////////////////
279 {
280 CloseHandle(file);
281 }
282}
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.
Open_Mode
Definition Open_Mode.h:8
@ write_lock
like write_existing_or_create_new, but waits instead of failing if already locked