1 /*-
2 * Copyright (c) 2014-2018 MongoDB, Inc.
3 * Copyright (c) 2008-2014 WiredTiger, Inc.
4 * All rights reserved.
5 *
6 * See the file LICENSE for redistribution information.
7 */
8
9 #include "wt_internal.h"
10
11 /*
12 * __win_fs_exist --
13 * Return if the file exists.
14 */
15 static int
__win_fs_exist(WT_FILE_SYSTEM * file_system,WT_SESSION * wt_session,const char * name,bool * existp)16 __win_fs_exist(WT_FILE_SYSTEM *file_system,
17 WT_SESSION *wt_session, const char *name, bool *existp)
18 {
19 WT_DECL_ITEM(name_wide);
20 WT_SESSION_IMPL *session;
21
22 WT_UNUSED(file_system);
23
24 session = (WT_SESSION_IMPL *)wt_session;
25 *existp = false;
26
27 WT_RET(__wt_to_utf16_string(session, name, &name_wide));
28
29 if (GetFileAttributesW(name_wide->data) != INVALID_FILE_ATTRIBUTES)
30 *existp = true;
31
32 __wt_scr_free(session, &name_wide);
33 return (0);
34 }
35
36 /*
37 * __win_fs_remove --
38 * Remove a file.
39 */
40 static int
__win_fs_remove(WT_FILE_SYSTEM * file_system,WT_SESSION * wt_session,const char * name,uint32_t flags)41 __win_fs_remove(WT_FILE_SYSTEM *file_system,
42 WT_SESSION *wt_session, const char *name, uint32_t flags)
43 {
44 DWORD windows_error;
45 WT_DECL_ITEM(name_wide);
46 WT_DECL_RET;
47 WT_SESSION_IMPL *session;
48
49 WT_UNUSED(file_system);
50 WT_UNUSED(flags);
51
52 session = (WT_SESSION_IMPL *)wt_session;
53
54 WT_RET(__wt_to_utf16_string(session, name, &name_wide));
55
56 if (DeleteFileW(name_wide->data) == FALSE) {
57 windows_error = __wt_getlasterror();
58 ret = __wt_map_windows_error(windows_error);
59 __wt_err(session, ret,
60 "%s: file-remove: DeleteFileW: %s",
61 name, __wt_formatmessage(session, windows_error));
62 WT_ERR(ret);
63 }
64
65 err: __wt_scr_free(session, &name_wide);
66 return (ret);
67 }
68
69 /*
70 * __win_fs_rename --
71 * Rename a file.
72 */
73 static int
__win_fs_rename(WT_FILE_SYSTEM * file_system,WT_SESSION * wt_session,const char * from,const char * to,uint32_t flags)74 __win_fs_rename(WT_FILE_SYSTEM *file_system,
75 WT_SESSION *wt_session, const char *from, const char *to, uint32_t flags)
76 {
77 DWORD windows_error;
78 WT_DECL_ITEM(from_wide);
79 WT_DECL_ITEM(to_wide);
80 WT_DECL_RET;
81 WT_SESSION_IMPL *session;
82
83 WT_UNUSED(file_system);
84 WT_UNUSED(flags);
85 session = (WT_SESSION_IMPL *)wt_session;
86
87 WT_ERR(__wt_to_utf16_string(session, from, &from_wide));
88 WT_ERR(__wt_to_utf16_string(session, to, &to_wide));
89
90 /*
91 * We want an atomic rename, but that's not guaranteed by MoveFileExW
92 * (or by any MSDN API). Don't set the MOVEFILE_COPY_ALLOWED flag to
93 * prevent the system from falling back to a copy and delete process.
94 * Do set the MOVEFILE_WRITE_THROUGH flag so the window is as small
95 * as possible, just in case. WiredTiger renames are done in a single
96 * directory and we expect that to be an atomic metadata update on any
97 * modern filesystem.
98 */
99 if (MoveFileExW(from_wide->data, to_wide->data,
100 MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) == FALSE) {
101 windows_error = __wt_getlasterror();
102 ret = __wt_map_windows_error(windows_error);
103 __wt_err(session, ret,
104 "%s to %s: file-rename: MoveFileExW: %s",
105 from, to, __wt_formatmessage(session, windows_error));
106 WT_ERR(ret);
107 }
108
109 err: __wt_scr_free(session, &from_wide);
110 __wt_scr_free(session, &to_wide);
111 return (ret);
112 }
113
114 /*
115 * __wt_win_fs_size --
116 * Get the size of a file in bytes, by file name.
117 */
118 int
__wt_win_fs_size(WT_FILE_SYSTEM * file_system,WT_SESSION * wt_session,const char * name,wt_off_t * sizep)119 __wt_win_fs_size(WT_FILE_SYSTEM *file_system,
120 WT_SESSION *wt_session, const char *name, wt_off_t *sizep)
121 {
122 DWORD windows_error;
123 WIN32_FILE_ATTRIBUTE_DATA data;
124 WT_DECL_ITEM(name_wide);
125 WT_DECL_RET;
126 WT_SESSION_IMPL *session;
127
128 WT_UNUSED(file_system);
129 session = (WT_SESSION_IMPL *)wt_session;
130
131 WT_RET(__wt_to_utf16_string(session, name, &name_wide));
132
133 if (GetFileAttributesExW(
134 name_wide->data, GetFileExInfoStandard, &data) == 0) {
135 windows_error = __wt_getlasterror();
136 ret = __wt_map_windows_error(windows_error);
137 __wt_err(session, ret,
138 "%s: file-size: GetFileAttributesEx: %s",
139 name, __wt_formatmessage(session, windows_error));
140 WT_ERR(ret);
141 }
142
143 *sizep = ((int64_t)data.nFileSizeHigh << 32) | data.nFileSizeLow;
144
145 err: __wt_scr_free(session, &name_wide);
146 return (ret);
147 }
148
149 /*
150 * __win_file_close --
151 * ANSI C close.
152 */
153 static int
__win_file_close(WT_FILE_HANDLE * file_handle,WT_SESSION * wt_session)154 __win_file_close(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session)
155 {
156 DWORD windows_error;
157 WT_DECL_RET;
158 WT_FILE_HANDLE_WIN *win_fh;
159 WT_SESSION_IMPL *session;
160
161 win_fh = (WT_FILE_HANDLE_WIN *)file_handle;
162 session = (WT_SESSION_IMPL *)wt_session;
163
164 /*
165 * Close the primary and secondary handles.
166 *
167 * We don't open Windows system handles when opening directories for
168 * flushing, as it's not necessary (or possible) to flush a directory
169 * on Windows. Confirm the file handle is open before closing it.
170 */
171 if (win_fh->filehandle != INVALID_HANDLE_VALUE &&
172 CloseHandle(win_fh->filehandle) == 0) {
173 windows_error = __wt_getlasterror();
174 ret = __wt_map_windows_error(windows_error);
175 __wt_err(session, ret,
176 "%s: handle-close: CloseHandle: %s",
177 file_handle->name,
178 __wt_formatmessage(session, windows_error));
179 }
180
181 if (win_fh->filehandle_secondary != INVALID_HANDLE_VALUE &&
182 CloseHandle(win_fh->filehandle_secondary) == 0) {
183 windows_error = __wt_getlasterror();
184 ret = __wt_map_windows_error(windows_error);
185 __wt_err(session, ret,
186 "%s: handle-close: secondary: CloseHandle: %s",
187 file_handle->name,
188 __wt_formatmessage(session, windows_error));
189 }
190
191 __wt_free(session, file_handle->name);
192 __wt_free(session, win_fh);
193 return (ret);
194 }
195
196 /*
197 * __win_file_lock --
198 * Lock/unlock a file.
199 */
200 static int
__win_file_lock(WT_FILE_HANDLE * file_handle,WT_SESSION * wt_session,bool lock)201 __win_file_lock(
202 WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, bool lock)
203 {
204 DWORD windows_error;
205 WT_DECL_RET;
206 WT_FILE_HANDLE_WIN *win_fh;
207 WT_SESSION_IMPL *session;
208
209 win_fh = (WT_FILE_HANDLE_WIN *)file_handle;
210 session = (WT_SESSION_IMPL *)wt_session;
211
212 /*
213 * WiredTiger requires this function be able to acquire locks past
214 * the end of file.
215 *
216 * http://msdn.microsoft.com/
217 * en-us/library/windows/desktop/aa365202%28v=vs.85%29.aspx
218 *
219 * You can lock bytes that are beyond the end of the current file.
220 * This is useful to coordinate adding records to the end of a file.
221 */
222 if (lock) {
223 if (LockFile(win_fh->filehandle, 0, 0, 1, 0) == FALSE) {
224 windows_error = __wt_getlasterror();
225 ret = __wt_map_windows_error(windows_error);
226 __wt_err(session, ret,
227 "%s: handle-lock: LockFile: %s",
228 file_handle->name,
229 __wt_formatmessage(session, windows_error));
230 }
231 } else
232 if (UnlockFile(win_fh->filehandle, 0, 0, 1, 0) == FALSE) {
233 windows_error = __wt_getlasterror();
234 ret = __wt_map_windows_error(windows_error);
235 __wt_err(session, ret,
236 "%s: handle-lock: UnlockFile: %s",
237 file_handle->name,
238 __wt_formatmessage(session, windows_error));
239 }
240 return (ret);
241 }
242
243 /*
244 * __win_file_read --
245 * Read a chunk.
246 */
247 static int
__win_file_read(WT_FILE_HANDLE * file_handle,WT_SESSION * wt_session,wt_off_t offset,size_t len,void * buf)248 __win_file_read(WT_FILE_HANDLE *file_handle,
249 WT_SESSION *wt_session, wt_off_t offset, size_t len, void *buf)
250 {
251 DWORD chunk, nr, windows_error;
252 OVERLAPPED overlapped = { 0 };
253 WT_DECL_RET;
254 WT_FILE_HANDLE_WIN *win_fh;
255 WT_SESSION_IMPL *session;
256 uint8_t *addr;
257
258 win_fh = (WT_FILE_HANDLE_WIN *)file_handle;
259 session = (WT_SESSION_IMPL *)wt_session;
260
261 nr = 0;
262
263 /* Assert direct I/O is aligned and a multiple of the alignment. */
264 WT_ASSERT(session,
265 !win_fh->direct_io ||
266 S2C(session)->buffer_alignment == 0 ||
267 (!((uintptr_t)buf &
268 (uintptr_t)(S2C(session)->buffer_alignment - 1)) &&
269 len >= S2C(session)->buffer_alignment &&
270 len % S2C(session)->buffer_alignment == 0));
271
272 /* Break reads larger than 1GB into 1GB chunks. */
273 for (addr = buf; len > 0; addr += nr, len -= (size_t)nr, offset += nr) {
274 chunk = (DWORD)WT_MIN(len, WT_GIGABYTE);
275 overlapped.Offset = UINT32_MAX & offset;
276 overlapped.OffsetHigh = UINT32_MAX & (offset >> 32);
277
278 if (!ReadFile(
279 win_fh->filehandle, addr, chunk, &nr, &overlapped)) {
280 windows_error = __wt_getlasterror();
281 ret = __wt_map_windows_error(windows_error);
282 if (ret == WT_ERROR)
283 F_SET(S2C(session), WT_CONN_DATA_CORRUPTION);
284 __wt_err(session, ret,
285 "%s: handle-read: ReadFile: failed to read %lu "
286 "bytes at offset %" PRIuMAX ": %s",
287 file_handle->name, chunk, (uintmax_t)offset,
288 __wt_formatmessage(session, windows_error));
289 return (ret);
290 }
291 }
292 return (0);
293 }
294
295 /*
296 * __win_file_size --
297 * Get the size of a file in bytes, by file handle.
298 */
299 static int
__win_file_size(WT_FILE_HANDLE * file_handle,WT_SESSION * wt_session,wt_off_t * sizep)300 __win_file_size(
301 WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, wt_off_t *sizep)
302 {
303 DWORD windows_error;
304 LARGE_INTEGER size;
305 WT_DECL_RET;
306 WT_FILE_HANDLE_WIN *win_fh;
307 WT_SESSION_IMPL *session;
308
309 win_fh = (WT_FILE_HANDLE_WIN *)file_handle;
310 session = (WT_SESSION_IMPL *)wt_session;
311
312 if (GetFileSizeEx(win_fh->filehandle, &size) != 0) {
313 *sizep = size.QuadPart;
314 return (0);
315 }
316
317 windows_error = __wt_getlasterror();
318 ret = __wt_map_windows_error(windows_error);
319 __wt_err(session, ret,
320 "%s: handle-size: GetFileSizeEx: %s",
321 file_handle->name, __wt_formatmessage(session, windows_error));
322 return (ret);
323 }
324
325 /*
326 * __win_file_sync --
327 * MSVC fsync.
328 */
329 static int
__win_file_sync(WT_FILE_HANDLE * file_handle,WT_SESSION * wt_session)330 __win_file_sync(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session)
331 {
332 DWORD windows_error;
333 WT_DECL_RET;
334 WT_FILE_HANDLE_WIN *win_fh;
335 WT_SESSION_IMPL *session;
336
337 win_fh = (WT_FILE_HANDLE_WIN *)file_handle;
338 session = (WT_SESSION_IMPL *)wt_session;
339
340 /*
341 * We don't open Windows system handles when opening directories
342 * for flushing, as it is not necessary (or possible) to flush
343 * a directory on Windows. Confirm the file handle is set before
344 * attempting to sync it.
345 */
346 if (win_fh->filehandle == INVALID_HANDLE_VALUE)
347 return (0);
348
349 if (FlushFileBuffers(win_fh->filehandle) == FALSE) {
350 windows_error = __wt_getlasterror();
351 ret = __wt_map_windows_error(windows_error);
352 __wt_err(session, ret,
353 "%s handle-sync: FlushFileBuffers: %s",
354 file_handle->name,
355 __wt_formatmessage(session, windows_error));
356 return (ret);
357 }
358 return (0);
359 }
360
361 /*
362 * __win_file_set_end --
363 * Truncate or extend a file.
364 */
365 static int
__win_file_set_end(WT_FILE_HANDLE * file_handle,WT_SESSION * wt_session,wt_off_t len)366 __win_file_set_end(
367 WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, wt_off_t len)
368 {
369 DWORD windows_error;
370 LARGE_INTEGER largeint;
371 WT_DECL_RET;
372 WT_FILE_HANDLE_WIN *win_fh;
373 WT_SESSION_IMPL *session;
374
375 win_fh = (WT_FILE_HANDLE_WIN *)file_handle;
376 session = (WT_SESSION_IMPL *)wt_session;
377
378 largeint.QuadPart = len;
379
380 if (win_fh->filehandle_secondary == INVALID_HANDLE_VALUE)
381 WT_RET_MSG(session, EINVAL,
382 "%s: handle-set-end: no secondary handle",
383 file_handle->name);
384
385 if (SetFilePointerEx(win_fh->filehandle_secondary,
386 largeint, NULL, FILE_BEGIN) == FALSE) {
387 windows_error = __wt_getlasterror();
388 ret = __wt_map_windows_error(windows_error);
389 __wt_err(session, ret,
390 "%s: handle-set-end: SetFilePointerEx: %s",
391 file_handle->name,
392 __wt_formatmessage(session, windows_error));
393 return (ret);
394 }
395
396 if (SetEndOfFile(win_fh->filehandle_secondary) == FALSE) {
397 if (GetLastError() == ERROR_USER_MAPPED_FILE)
398 return (__wt_set_return(session, EBUSY));
399 windows_error = __wt_getlasterror();
400 ret = __wt_map_windows_error(windows_error);
401 __wt_err(session, ret,
402 "%s: handle-set-end: SetEndOfFile: %s",
403 file_handle->name,
404 __wt_formatmessage(session, windows_error));
405 return (ret);
406 }
407 return (0);
408 }
409
410 /*
411 * __win_file_write --
412 * Write a chunk.
413 */
414 static int
__win_file_write(WT_FILE_HANDLE * file_handle,WT_SESSION * wt_session,wt_off_t offset,size_t len,const void * buf)415 __win_file_write(WT_FILE_HANDLE *file_handle,
416 WT_SESSION *wt_session, wt_off_t offset, size_t len, const void *buf)
417 {
418 DWORD chunk, nw, windows_error;
419 OVERLAPPED overlapped = { 0 };
420 WT_DECL_RET;
421 WT_FILE_HANDLE_WIN *win_fh;
422 WT_SESSION_IMPL *session;
423 const uint8_t *addr;
424
425 win_fh = (WT_FILE_HANDLE_WIN *)file_handle;
426 session = (WT_SESSION_IMPL *)wt_session;
427
428 nw = 0;
429
430 /* Assert direct I/O is aligned and a multiple of the alignment. */
431 WT_ASSERT(session,
432 !win_fh->direct_io ||
433 S2C(session)->buffer_alignment == 0 ||
434 (!((uintptr_t)buf &
435 (uintptr_t)(S2C(session)->buffer_alignment - 1)) &&
436 len >= S2C(session)->buffer_alignment &&
437 len % S2C(session)->buffer_alignment == 0));
438
439 /* Break writes larger than 1GB into 1GB chunks. */
440 for (addr = buf; len > 0; addr += nw, len -= (size_t)nw, offset += nw) {
441 chunk = (DWORD)WT_MIN(len, WT_GIGABYTE);
442 overlapped.Offset = UINT32_MAX & offset;
443 overlapped.OffsetHigh = UINT32_MAX & (offset >> 32);
444
445 if (!WriteFile(
446 win_fh->filehandle, addr, chunk, &nw, &overlapped)) {
447 windows_error = __wt_getlasterror();
448 ret = __wt_map_windows_error(windows_error);
449 __wt_err(session, ret,
450 "%s: handle-write: WriteFile: failed to write %lu "
451 "bytes at offset %" PRIuMAX ": %s",
452 file_handle->name, chunk, (uintmax_t)offset,
453 __wt_formatmessage(session, windows_error));
454 return (ret);
455 }
456 }
457 return (0);
458 }
459
460 /*
461 * __win_open_file --
462 * Open a file handle.
463 */
464 static int
__win_open_file(WT_FILE_SYSTEM * file_system,WT_SESSION * wt_session,const char * name,WT_FS_OPEN_FILE_TYPE file_type,uint32_t flags,WT_FILE_HANDLE ** file_handlep)465 __win_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session,
466 const char *name, WT_FS_OPEN_FILE_TYPE file_type, uint32_t flags,
467 WT_FILE_HANDLE **file_handlep)
468 {
469 DWORD dwCreationDisposition, windows_error;
470 WT_CONNECTION_IMPL *conn;
471 WT_DECL_ITEM(name_wide);
472 WT_DECL_RET;
473 WT_FILE_HANDLE *file_handle;
474 WT_FILE_HANDLE_WIN *win_fh;
475 WT_SESSION_IMPL *session;
476 int desired_access, f;
477
478 WT_UNUSED(file_system);
479 session = (WT_SESSION_IMPL *)wt_session;
480 conn = S2C(session);
481 *file_handlep = NULL;
482
483 WT_RET(__wt_calloc_one(session, &win_fh));
484 win_fh->direct_io = false;
485
486 /* Set up error handling. */
487 win_fh->filehandle =
488 win_fh->filehandle_secondary = INVALID_HANDLE_VALUE;
489
490 WT_ERR(__wt_to_utf16_string(session, name, &name_wide));
491
492 /*
493 * Opening a file handle on a directory is only to support filesystems
494 * that require a directory sync for durability, and Windows doesn't
495 * require that functionality: create an empty WT_FH structure with
496 * invalid handles.
497 */
498 if (file_type == WT_FS_OPEN_FILE_TYPE_DIRECTORY)
499 goto directory_open;
500
501 desired_access = GENERIC_READ;
502 if (!LF_ISSET(WT_FS_OPEN_READONLY))
503 desired_access |= GENERIC_WRITE;
504
505 /*
506 * Security:
507 * The application may spawn a new process, and we don't want another
508 * process to have access to our file handles.
509 *
510 * TODO: Set tighter file permissions but set bInheritHandle to false
511 * to prevent inheritance
512 */
513 f = FILE_ATTRIBUTE_NORMAL;
514
515 dwCreationDisposition = 0;
516 if (LF_ISSET(WT_FS_OPEN_CREATE)) {
517 dwCreationDisposition = CREATE_NEW;
518 if (LF_ISSET(WT_FS_OPEN_EXCLUSIVE))
519 dwCreationDisposition = CREATE_ALWAYS;
520 } else
521 dwCreationDisposition = OPEN_EXISTING;
522
523 /* Direct I/O. */
524 if (LF_ISSET(WT_FS_OPEN_DIRECTIO)) {
525 f |= FILE_FLAG_NO_BUFFERING;
526 win_fh->direct_io = true;
527 }
528
529 /* FILE_FLAG_WRITE_THROUGH does not require aligned buffers */
530 if (FLD_ISSET(conn->write_through, file_type))
531 f |= FILE_FLAG_WRITE_THROUGH;
532
533 if (file_type == WT_FS_OPEN_FILE_TYPE_LOG &&
534 FLD_ISSET(conn->txn_logsync, WT_LOG_DSYNC))
535 f |= FILE_FLAG_WRITE_THROUGH;
536
537 /* If the user indicated a random workload, disable read-ahead. */
538 if (file_type == WT_FS_OPEN_FILE_TYPE_DATA &&
539 LF_ISSET(WT_FS_OPEN_ACCESS_RAND))
540 f |= FILE_FLAG_RANDOM_ACCESS;
541
542 /* If the user indicated a sequential workload, set that. */
543 if (file_type == WT_FS_OPEN_FILE_TYPE_DATA &&
544 LF_ISSET(WT_FS_OPEN_ACCESS_SEQ))
545 f |= FILE_FLAG_SEQUENTIAL_SCAN;
546
547 win_fh->filehandle = CreateFileW(name_wide->data, desired_access,
548 FILE_SHARE_READ | FILE_SHARE_WRITE,
549 NULL, dwCreationDisposition, f, NULL);
550 if (win_fh->filehandle == INVALID_HANDLE_VALUE) {
551 if (LF_ISSET(WT_FS_OPEN_CREATE) &&
552 GetLastError() == ERROR_FILE_EXISTS)
553 win_fh->filehandle = CreateFileW(name_wide->data,
554 desired_access, FILE_SHARE_READ | FILE_SHARE_WRITE,
555 NULL, OPEN_EXISTING, f, NULL);
556 if (win_fh->filehandle == INVALID_HANDLE_VALUE) {
557 windows_error = __wt_getlasterror();
558 ret = __wt_map_windows_error(windows_error);
559 __wt_err(session, ret,
560 win_fh->direct_io ?
561 "%s: handle-open: CreateFileW: failed with direct "
562 "I/O configured, some filesystem types do not "
563 "support direct I/O: %s" :
564 "%s: handle-open: CreateFileW: %s",
565 name, __wt_formatmessage(session, windows_error));
566 WT_ERR(ret);
567 }
568 }
569
570 /*
571 * Open a second handle to file to support file extension/truncation
572 * concurrently with reads on the file. Writes would also move the
573 * file pointer.
574 */
575 if (!LF_ISSET(WT_FS_OPEN_READONLY)) {
576 win_fh->filehandle_secondary = CreateFileW(name_wide->data,
577 desired_access, FILE_SHARE_READ | FILE_SHARE_WRITE,
578 NULL, OPEN_EXISTING, f, NULL);
579 if (win_fh->filehandle_secondary == INVALID_HANDLE_VALUE) {
580 windows_error = __wt_getlasterror();
581 ret = __wt_map_windows_error(windows_error);
582 __wt_err(session, ret,
583 "%s: handle-open: Creatively: secondary: %s",
584 name, __wt_formatmessage(session, windows_error));
585 WT_ERR(ret);
586 }
587 }
588
589 directory_open:
590 /* Initialize public information. */
591 file_handle = (WT_FILE_HANDLE *)win_fh;
592 WT_ERR(__wt_strdup(session, name, &file_handle->name));
593
594 file_handle->close = __win_file_close;
595 file_handle->fh_lock = __win_file_lock;
596 #ifdef WORDS_BIGENDIAN
597 /*
598 * The underlying objects are little-endian, mapping objects isn't
599 * currently supported on big-endian systems.
600 */
601 #else
602 file_handle->fh_map = __wt_win_map;
603 file_handle->fh_unmap = __wt_win_unmap;
604 #endif
605 file_handle->fh_read = __win_file_read;
606 file_handle->fh_size = __win_file_size;
607 file_handle->fh_sync = __win_file_sync;
608
609 /* Extend and truncate share the same implementation. */
610 file_handle->fh_extend = __win_file_set_end;
611 file_handle->fh_truncate = __win_file_set_end;
612
613 file_handle->fh_write = __win_file_write;
614
615 *file_handlep = file_handle;
616
617 __wt_scr_free(session, &name_wide);
618 return (0);
619
620 err: __wt_scr_free(session, &name_wide);
621 WT_TRET(__win_file_close((WT_FILE_HANDLE *)win_fh, wt_session));
622 return (ret);
623 }
624
625 /*
626 * __win_terminate --
627 * Discard a Windows configuration.
628 */
629 static int
__win_terminate(WT_FILE_SYSTEM * file_system,WT_SESSION * wt_session)630 __win_terminate(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session)
631 {
632 WT_SESSION_IMPL *session;
633
634 session = (WT_SESSION_IMPL *)wt_session;
635
636 __wt_free(session, file_system);
637 return (0);
638 }
639
640 /*
641 * __wt_os_win --
642 * Initialize a MSVC configuration.
643 */
644 int
__wt_os_win(WT_SESSION_IMPL * session)645 __wt_os_win(WT_SESSION_IMPL *session)
646 {
647 WT_CONNECTION_IMPL *conn;
648 WT_FILE_SYSTEM *file_system;
649
650 conn = S2C(session);
651
652 WT_RET(__wt_calloc_one(session, &file_system));
653
654 /* Initialize the Windows jump table. */
655 file_system->fs_directory_list = __wt_win_directory_list;
656 file_system->fs_directory_list_single = __wt_win_directory_list_single;
657 file_system->fs_directory_list_free = __wt_win_directory_list_free;
658 file_system->fs_exist = __win_fs_exist;
659 file_system->fs_open_file = __win_open_file;
660 file_system->fs_remove = __win_fs_remove;
661 file_system->fs_rename = __win_fs_rename;
662 file_system->fs_size = __wt_win_fs_size;
663 file_system->terminate = __win_terminate;
664
665 /* Switch it into place. */
666 conn->file_system = file_system;
667
668 return (0);
669 }
670