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