/* * __win_fs_remove -- * Remove a file. */ static int __win_fs_remove(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name, uint32_t flags) { DWORD windows_error; WT_DECL_ITEM(name_wide); WT_DECL_RET; WT_SESSION_IMPL *session; WT_UNUSED(file_system); WT_UNUSED(flags); session = (WT_SESSION_IMPL *)wt_session; WT_RET(__wt_to_utf16_string(session, name, &name_wide)); if (DeleteFileW(name_wide->data) == FALSE) { windows_error = __wt_getlasterror(); ret = __wt_map_windows_error(windows_error); __wt_err(session, ret, "%s: file-remove: DeleteFileW: %s", name, __wt_formatmessage(session, windows_error)); WT_ERR(ret); } err: __wt_scr_free(session, &name_wide); return (ret); }
/* * __wt_win_fs_size -- * Get the size of a file in bytes, by file name. */ int __wt_win_fs_size(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name, wt_off_t *sizep) { DWORD windows_error; WIN32_FILE_ATTRIBUTE_DATA data; WT_DECL_ITEM(name_wide); WT_DECL_RET; WT_SESSION_IMPL *session; WT_UNUSED(file_system); session = (WT_SESSION_IMPL *)wt_session; WT_RET(__wt_to_utf16_string(session, name, &name_wide)); if (GetFileAttributesExW( name_wide->data, GetFileExInfoStandard, &data) == 0) { windows_error = __wt_getlasterror(); ret = __wt_map_windows_error(windows_error); __wt_err(session, ret, "%s: file-size: GetFileAttributesEx: %s", name, __wt_formatmessage(session, windows_error)); WT_ERR(ret); } *sizep = ((int64_t)data.nFileSizeHigh << 32) | data.nFileSizeLow; err: __wt_scr_free(session, &name_wide); return (ret); }
/* * __win_fs_rename -- * Rename a file. */ static int __win_fs_rename(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *from, const char *to, uint32_t flags) { DWORD windows_error; WT_DECL_RET; WT_DECL_ITEM(from_wide); WT_DECL_ITEM(to_wide); WT_SESSION_IMPL *session; WT_UNUSED(file_system); WT_UNUSED(flags); session = (WT_SESSION_IMPL *)wt_session; WT_ERR(__wt_to_utf16_string(session, from, &from_wide)); WT_ERR(__wt_to_utf16_string(session, to, &to_wide)); /* * Check if file exists since Windows does not override the file if * it exists. */ if (GetFileAttributesW(to_wide->data) != INVALID_FILE_ATTRIBUTES) if (DeleteFileW(to_wide->data) == FALSE) { windows_error = __wt_getlasterror(); __wt_errx(session, "%s: file-rename: DeleteFileW: %s", to, __wt_formatmessage(session, windows_error)); WT_ERR(__wt_map_windows_error(windows_error)); } if (MoveFileW(from_wide->data, to_wide->data) == FALSE) { windows_error = __wt_getlasterror(); __wt_errx(session, "%s to %s: file-rename: MoveFileW: %s", from, to, __wt_formatmessage(session, windows_error)); WT_ERR(__wt_map_windows_error(windows_error)); } err: __wt_scr_free(session, &from_wide); __wt_scr_free(session, &to_wide); return (ret); }
/* * __win_fs_rename -- * Rename a file. */ static int __win_fs_rename(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *from, const char *to, uint32_t flags) { DWORD windows_error; WT_DECL_ITEM(from_wide); WT_DECL_ITEM(to_wide); WT_DECL_RET; WT_SESSION_IMPL *session; WT_UNUSED(file_system); WT_UNUSED(flags); session = (WT_SESSION_IMPL *)wt_session; WT_ERR(__wt_to_utf16_string(session, from, &from_wide)); WT_ERR(__wt_to_utf16_string(session, to, &to_wide)); /* * We want an atomic rename, but that's not guaranteed by MoveFileExW * (or by any MSDN API). Don't set the MOVEFILE_COPY_ALLOWED flag to * prevent the system from falling back to a copy and delete process. * Do set the MOVEFILE_WRITE_THROUGH flag so the window is as small * as possible, just in case. WiredTiger renames are done in a single * directory and we expect that to be an atomic metadata update on any * modern filesystem. */ if (MoveFileExW(from_wide->data, to_wide->data, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) == FALSE) { windows_error = __wt_getlasterror(); ret = __wt_map_windows_error(windows_error); __wt_err(session, ret, "%s to %s: file-rename: MoveFileExW: %s", from, to, __wt_formatmessage(session, windows_error)); WT_ERR(ret); } err: __wt_scr_free(session, &from_wide); __wt_scr_free(session, &to_wide); return (ret); }
/* * __win_fs_exist -- * Return if the file exists. */ static int __win_fs_exist(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name, bool *existp) { WT_DECL_ITEM(name_wide); WT_SESSION_IMPL *session; WT_UNUSED(file_system); session = (WT_SESSION_IMPL *)wt_session; *existp = false; WT_RET(__wt_to_utf16_string(session, name, &name_wide)); if (GetFileAttributesW(name_wide->data) != INVALID_FILE_ATTRIBUTES) *existp = true; __wt_scr_free(session, &name_wide); return (0); }
/* * __wt_win_directory_list -- * Get a list of files from a directory, MSVC version. */ int __wt_win_directory_list(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *directory, const char *prefix, char ***dirlistp, uint32_t *countp) { DWORD windows_error; HANDLE findhandle; WIN32_FIND_DATAW finddata; WT_DECL_ITEM(pathbuf); WT_DECL_ITEM(file_utf8); WT_DECL_ITEM(pathbuf_wide); WT_DECL_ITEM(prefix_wide); WT_DECL_RET; WT_SESSION_IMPL *session; size_t dirallocsz, pathlen, prefix_widelen; uint32_t count; char *dir_copy, **entries; session = (WT_SESSION_IMPL *)wt_session; *dirlistp = NULL; *countp = 0; findhandle = INVALID_HANDLE_VALUE; dirallocsz = 0; entries = NULL; WT_ERR(__wt_strdup(session, directory, &dir_copy)); pathlen = strlen(dir_copy); if (dir_copy[pathlen - 1] == '\\') dir_copy[pathlen - 1] = '\0'; WT_ERR(__wt_scr_alloc(session, pathlen + 3, &pathbuf)); WT_ERR(__wt_buf_fmt(session, pathbuf, "%s\\*", dir_copy)); WT_ERR(__wt_to_utf16_string(session, pathbuf->data, &pathbuf_wide)); WT_ERR(__wt_to_utf16_string(session, prefix, &prefix_wide)); prefix_widelen = wcslen(prefix_wide->data); findhandle = FindFirstFileW(pathbuf_wide->data, &finddata); if (findhandle == INVALID_HANDLE_VALUE) { windows_error = __wt_getlasterror(); __wt_errx(session, "%s: directory-list: FindFirstFile: %s", pathbuf->data, __wt_formatmessage(session, windows_error)); WT_ERR(__wt_map_windows_error(windows_error)); } count = 0; do { /* * Skip . and .. */ if (wcscmp(finddata.cFileName, L".") == 0 || wcscmp(finddata.cFileName, L"..") == 0) continue; /* The list of files is optionally filtered by a prefix. */ if (prefix != NULL && wcsncmp(finddata.cFileName, prefix_wide->data, prefix_widelen) != 0) continue; WT_ERR(__wt_realloc_def( session, &dirallocsz, count + 1, &entries)); WT_ERR(__wt_to_utf8_string( session, finddata.cFileName, &file_utf8)); WT_ERR(__wt_strdup(session, file_utf8->data, &entries[count])); ++count; __wt_scr_free(session, &file_utf8); } while (FindNextFileW(findhandle, &finddata) != 0); *dirlistp = entries; *countp = count; err: if (findhandle != INVALID_HANDLE_VALUE) if (FindClose(findhandle) == 0) { windows_error = __wt_getlasterror(); __wt_errx(session, "%s: directory-list: FindClose: %s", pathbuf->data, __wt_formatmessage(session, windows_error)); if (ret == 0) ret = __wt_map_windows_error(windows_error); } __wt_free(session, dir_copy); __wt_scr_free(session, &pathbuf); __wt_scr_free(session, &file_utf8); __wt_scr_free(session, &pathbuf_wide); __wt_scr_free(session, &prefix_wide); if (ret == 0) return (0); WT_TRET(__wt_win_directory_list_free( file_system, wt_session, entries, count)); WT_RET_MSG(session, ret, "%s: directory-list, prefix \"%s\"", directory, prefix == NULL ? "" : prefix); }
/* * __win_open_file -- * Open a file handle. */ 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) { DWORD dwCreationDisposition, windows_error; WT_CONNECTION_IMPL *conn; WT_DECL_ITEM(name_wide); WT_DECL_RET; WT_FILE_HANDLE *file_handle; WT_FILE_HANDLE_WIN *win_fh; WT_SESSION_IMPL *session; int desired_access, f; WT_UNUSED(file_system); session = (WT_SESSION_IMPL *)wt_session; conn = S2C(session); *file_handlep = NULL; WT_RET(__wt_calloc_one(session, &win_fh)); win_fh->direct_io = false; /* Set up error handling. */ win_fh->filehandle = win_fh->filehandle_secondary = INVALID_HANDLE_VALUE; WT_ERR(__wt_to_utf16_string(session, name, &name_wide)); /* * Opening a file handle on a directory is only to support filesystems * that require a directory sync for durability, and Windows doesn't * require that functionality: create an empty WT_FH structure with * invalid handles. */ if (file_type == WT_FS_OPEN_FILE_TYPE_DIRECTORY) goto directory_open; desired_access = GENERIC_READ; if (!LF_ISSET(WT_FS_OPEN_READONLY)) desired_access |= GENERIC_WRITE; /* * Security: * The application may spawn a new process, and we don't want another * process to have access to our file handles. * * TODO: Set tighter file permissions but set bInheritHandle to false * to prevent inheritance */ f = FILE_ATTRIBUTE_NORMAL; dwCreationDisposition = 0; if (LF_ISSET(WT_FS_OPEN_CREATE)) { dwCreationDisposition = CREATE_NEW; if (LF_ISSET(WT_FS_OPEN_EXCLUSIVE)) dwCreationDisposition = CREATE_ALWAYS; } else dwCreationDisposition = OPEN_EXISTING; /* Direct I/O. */ if (LF_ISSET(WT_FS_OPEN_DIRECTIO)) { f |= FILE_FLAG_NO_BUFFERING; win_fh->direct_io = true; } /* FILE_FLAG_WRITE_THROUGH does not require aligned buffers */ if (FLD_ISSET(conn->write_through, file_type)) f |= FILE_FLAG_WRITE_THROUGH; if (file_type == WT_FS_OPEN_FILE_TYPE_LOG && FLD_ISSET(conn->txn_logsync, WT_LOG_DSYNC)) f |= FILE_FLAG_WRITE_THROUGH; /* If the user indicated a random workload, disable read-ahead. */ if (file_type == WT_FS_OPEN_FILE_TYPE_DATA && LF_ISSET(WT_FS_OPEN_ACCESS_RAND)) f |= FILE_FLAG_RANDOM_ACCESS; /* If the user indicated a sequential workload, set that. */ if (file_type == WT_FS_OPEN_FILE_TYPE_DATA && LF_ISSET(WT_FS_OPEN_ACCESS_SEQ)) f |= FILE_FLAG_SEQUENTIAL_SCAN; win_fh->filehandle = CreateFileW(name_wide->data, desired_access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, dwCreationDisposition, f, NULL); if (win_fh->filehandle == INVALID_HANDLE_VALUE) { if (LF_ISSET(WT_FS_OPEN_CREATE) && GetLastError() == ERROR_FILE_EXISTS) win_fh->filehandle = CreateFileW(name_wide->data, desired_access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, f, NULL); if (win_fh->filehandle == INVALID_HANDLE_VALUE) { windows_error = __wt_getlasterror(); ret = __wt_map_windows_error(windows_error); __wt_err(session, ret, win_fh->direct_io ? "%s: handle-open: CreateFileW: failed with direct " "I/O configured, some filesystem types do not " "support direct I/O: %s" : "%s: handle-open: CreateFileW: %s", name, __wt_formatmessage(session, windows_error)); WT_ERR(ret); } } /* * Open a second handle to file to support file extension/truncation * concurrently with reads on the file. Writes would also move the * file pointer. */ if (!LF_ISSET(WT_FS_OPEN_READONLY)) { win_fh->filehandle_secondary = CreateFileW(name_wide->data, desired_access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, f, NULL); if (win_fh->filehandle_secondary == INVALID_HANDLE_VALUE) { windows_error = __wt_getlasterror(); ret = __wt_map_windows_error(windows_error); __wt_err(session, ret, "%s: handle-open: Creatively: secondary: %s", name, __wt_formatmessage(session, windows_error)); WT_ERR(ret); } } directory_open: /* Initialize public information. */ file_handle = (WT_FILE_HANDLE *)win_fh; WT_ERR(__wt_strdup(session, name, &file_handle->name)); file_handle->close = __win_file_close; file_handle->fh_lock = __win_file_lock; #ifdef WORDS_BIGENDIAN /* * The underlying objects are little-endian, mapping objects isn't * currently supported on big-endian systems. */ #else file_handle->fh_map = __wt_win_map; file_handle->fh_unmap = __wt_win_unmap; #endif file_handle->fh_read = __win_file_read; file_handle->fh_size = __win_file_size; file_handle->fh_sync = __win_file_sync; /* Extend and truncate share the same implementation. */ file_handle->fh_extend = __win_file_set_end; file_handle->fh_truncate = __win_file_set_end; file_handle->fh_write = __win_file_write; *file_handlep = file_handle; __wt_scr_free(session, &name_wide); return (0); err: __wt_scr_free(session, &name_wide); WT_TRET(__win_file_close((WT_FILE_HANDLE *)win_fh, wt_session)); return (ret); }