X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fwin32_capture.c;h=06a5f343eb70299cd5ec867735749fdd4a01514b;hb=ef03f83cc940d87f75140b7a8bc1199f4ff22aab;hp=196342e6ed76699281d8d8220cb4e755fdb80614;hpb=1c142989478a3e670fbb6953d98adfa988441e5b;p=wimlib diff --git a/src/win32_capture.c b/src/win32_capture.c index 196342e6..06a5f343 100644 --- a/src/win32_capture.c +++ b/src/win32_capture.c @@ -240,39 +240,37 @@ get_windows_file_path(const struct windows_file *file) } /* - * If cur_dir is not NULL, open an existing file relative to the already-open - * directory cur_dir. - * - * Otherwise, open the file specified by @path, which must be a Windows NT - * namespace path. + * Open the file named by the NT namespace path @path of length @path_nchars + * characters. If @cur_dir is not NULL then the path is given relative to + * @cur_dir; otherwise the path is absolute. @perms is the access mask of + * permissions to request on the handle. SYNCHRONIZE permision is always added. */ static NTSTATUS winnt_openat(HANDLE cur_dir, const wchar_t *path, size_t path_nchars, ACCESS_MASK perms, HANDLE *h_ret) { - UNICODE_STRING name; - OBJECT_ATTRIBUTES attr; + UNICODE_STRING name = { + .Length = path_nchars * sizeof(wchar_t), + .MaximumLength = path_nchars * sizeof(wchar_t), + .Buffer = (wchar_t *)path, + }; + OBJECT_ATTRIBUTES attr = { + .Length = sizeof(attr), + .RootDirectory = cur_dir, + .ObjectName = &name, + }; IO_STATUS_BLOCK iosb; NTSTATUS status; + ULONG options = FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT; - name.Length = path_nchars * sizeof(wchar_t); - name.MaximumLength = name.Length; - name.Buffer = (wchar_t *)path; - - attr.Length = sizeof(attr); - attr.RootDirectory = cur_dir; - attr.ObjectName = &name; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - + perms |= SYNCHRONIZE; + if (perms & (FILE_READ_DATA | FILE_LIST_DIRECTORY)) { + options |= FILE_SYNCHRONOUS_IO_NONALERT; + options |= FILE_SEQUENTIAL_ONLY; + } retry: - status = (*func_NtOpenFile)(h_ret, perms, &attr, &iosb, - FILE_SHARE_VALID_FLAGS, - FILE_OPEN_REPARSE_POINT | - FILE_OPEN_FOR_BACKUP_INTENT | - FILE_SYNCHRONOUS_IO_NONALERT | - FILE_SEQUENTIAL_ONLY); + status = NtOpenFile(h_ret, perms, &attr, &iosb, + FILE_SHARE_VALID_FLAGS, options); if (!NT_SUCCESS(status)) { /* Try requesting fewer permissions */ if (status == STATUS_ACCESS_DENIED || @@ -334,14 +332,14 @@ read_winnt_stream_prefix(const struct windows_file *file, u64 bytes_remaining; int ret; - status = (*func_NtOpenFile)(&h, FILE_READ_DATA | SYNCHRONIZE, - &attr, &iosb, - FILE_SHARE_VALID_FLAGS, - FILE_OPEN_REPARSE_POINT | - FILE_OPEN_FOR_BACKUP_INTENT | - FILE_SYNCHRONOUS_IO_NONALERT | - FILE_SEQUENTIAL_ONLY | - (file->is_file_id ? FILE_OPEN_BY_FILE_ID : 0)); + status = NtOpenFile(&h, FILE_READ_DATA | SYNCHRONIZE, + &attr, &iosb, + FILE_SHARE_VALID_FLAGS, + FILE_OPEN_REPARSE_POINT | + FILE_OPEN_FOR_BACKUP_INTENT | + FILE_SYNCHRONOUS_IO_NONALERT | + FILE_SEQUENTIAL_ONLY | + (file->is_file_id ? FILE_OPEN_BY_FILE_ID : 0)); if (unlikely(!NT_SUCCESS(status))) { if (status == STATUS_SHARING_VIOLATION) { ERROR("Can't open %ls for reading:\n" @@ -361,22 +359,42 @@ read_winnt_stream_prefix(const struct windows_file *file, IO_STATUS_BLOCK iosb; ULONG count; ULONG bytes_read; + const unsigned max_tries = 5; + unsigned tries_remaining = max_tries; count = min(sizeof(buf), bytes_remaining); - status = (*func_NtReadFile)(h, NULL, NULL, NULL, - &iosb, buf, count, NULL, NULL); + retry_read: + status = NtReadFile(h, NULL, NULL, NULL, + &iosb, buf, count, NULL, NULL); if (unlikely(!NT_SUCCESS(status))) { if (status == STATUS_END_OF_FILE) { ERROR("%ls: File was concurrently truncated", windows_file_to_string(file, buf, sizeof(buf))); ret = WIMLIB_ERR_CONCURRENT_MODIFICATION_DETECTED; } else { - winnt_error(status, L"Error reading data from %ls", - windows_file_to_string(file, buf, sizeof(buf))); + winnt_warning(status, L"Error reading data from %ls", + windows_file_to_string(file, buf, sizeof(buf))); + + /* Currently these retries are purely a guess; + * there is no reproducible problem that they solve. */ + if (--tries_remaining) { + int delay = 100; + if (status == STATUS_INSUFFICIENT_RESOURCES || + status == STATUS_NO_MEMORY) { + delay *= 25; + } + WARNING("Retrying after %dms...", delay); + Sleep(delay); + goto retry_read; + } + ERROR("Too many retries; returning failure"); ret = WIMLIB_ERR_READ; } break; + } else if (unlikely(tries_remaining != max_tries)) { + WARNING("A read request had to be retried multiple times " + "before it succeeded!"); } bytes_read = iosb.Information; @@ -386,7 +404,7 @@ read_winnt_stream_prefix(const struct windows_file *file, if (ret) break; } - (*func_NtClose)(h); + NtClose(h); return ret; } @@ -494,8 +512,8 @@ winnt_get_short_name(HANDLE h, struct wim_dentry *dentry) u8 buf[128] _aligned_attribute(8); const FILE_NAME_INFORMATION *info; - status = (*func_NtQueryInformationFile)(h, &iosb, buf, sizeof(buf), - FileAlternateNameInformation); + status = NtQueryInformationFile(h, &iosb, buf, sizeof(buf), + FileAlternateNameInformation); info = (const FILE_NAME_INFORMATION *)buf; if (NT_SUCCESS(status) && info->FileNameLength != 0) { dentry->d_short_name = utf16le_dupz(info->FileName, @@ -576,11 +594,11 @@ winnt_load_security_descriptor(HANDLE h, struct wim_inode *inode, * ntdll function and therefore not officially part of the Win32 API. * Oh well. */ - while (!(NT_SUCCESS(status = (*func_NtQuerySecurityObject)(h, - requestedInformation, - (PSECURITY_DESCRIPTOR)buf, - bufsize, - &len_needed)))) + while (!NT_SUCCESS(status = NtQuerySecurityObject(h, + requestedInformation, + (PSECURITY_DESCRIPTOR)buf, + bufsize, + &len_needed))) { switch (status) { case STATUS_BUFFER_TOO_SMALL: @@ -616,8 +634,13 @@ winnt_load_security_descriptor(HANDLE h, struct wim_inode *inode, } } + /* We can get a length of 0 with Samba. Assume that means "no security + * descriptor". */ + if (len_needed == 0) + goto out; + /* Add the security descriptor to the WIM image, and save its ID in - * file's inode. */ + * the file's inode. */ inode->i_security_id = sd_set_add_sd(ctx->params->sd_set, buf, len_needed); if (unlikely(inode->i_security_id < 0)) status = STATUS_NO_MEMORY; @@ -662,10 +685,10 @@ winnt_recurse_directory(HANDLE h, /* Using NtQueryDirectoryFile() we can re-use the same open handle, * which we opened with FILE_FLAG_BACKUP_SEMANTICS. */ - while (NT_SUCCESS(status = (*func_NtQueryDirectoryFile)(h, NULL, NULL, NULL, - &iosb, buf, bufsize, - FileNamesInformation, - FALSE, NULL, FALSE))) + while (NT_SUCCESS(status = NtQueryDirectoryFile(h, NULL, NULL, NULL, + &iosb, buf, bufsize, + FileNamesInformation, + FALSE, NULL, FALSE))) { const FILE_NAMES_INFORMATION *info = buf; for (;;) { @@ -733,18 +756,17 @@ file_has_ino_and_dev(HANDLE h, u64 ino, u64 dev) FILE_INTERNAL_INFORMATION int_info; FILE_FS_VOLUME_INFORMATION vol_info; - status = (*func_NtQueryInformationFile)(h, &iosb, - &int_info, sizeof(int_info), - FileInternalInformation); + status = NtQueryInformationFile(h, &iosb, &int_info, sizeof(int_info), + FileInternalInformation); if (!NT_SUCCESS(status)) return false; if (int_info.IndexNumber.QuadPart != ino) return false; - status = (*func_NtQueryVolumeInformationFile)(h, &iosb, - &vol_info, sizeof(vol_info), - FileFsVolumeInformation); + status = NtQueryVolumeInformationFile(h, &iosb, + &vol_info, sizeof(vol_info), + FileFsVolumeInformation); if (!(NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW)) return false; @@ -816,17 +838,17 @@ winnt_relativize_link_target(const wchar_t *target, size_t target_nbytes, name.MaximumLength = name.Length; /* Try opening the file */ - status = (*func_NtOpenFile) (&h, - FILE_READ_ATTRIBUTES | FILE_TRAVERSE, - &attr, - &iosb, - FILE_SHARE_VALID_FLAGS, - FILE_OPEN_FOR_BACKUP_INTENT); + status = NtOpenFile(&h, + FILE_READ_ATTRIBUTES | FILE_TRAVERSE, + &attr, + &iosb, + FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT); if (NT_SUCCESS(status)) { /* Reset root directory */ if (attr.RootDirectory) - (*func_NtClose)(attr.RootDirectory); + NtClose(attr.RootDirectory); attr.RootDirectory = h; name.Buffer = (wchar_t *)p; name.Length = 0; @@ -840,7 +862,7 @@ winnt_relativize_link_target(const wchar_t *target, size_t target_nbytes, out_close_root_dir: if (attr.RootDirectory) - (*func_NtClose)(attr.RootDirectory); + NtClose(attr.RootDirectory); while (p > target && *(p - 1) == L'\\') p--; return p; @@ -959,7 +981,8 @@ winnt_load_reparse_data(HANDLE h, struct wim_inode *inode, const wchar_t *full_path, struct capture_params *params) { struct reparse_buffer_disk rpbuf; - DWORD bytes_returned; + NTSTATUS status; + u32 len; u16 rpbuflen; int ret; @@ -970,16 +993,15 @@ winnt_load_reparse_data(HANDLE h, struct wim_inode *inode, return 0; } - if (!DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, - NULL, 0, &rpbuf, REPARSE_POINT_MAX_SIZE, - &bytes_returned, NULL)) - { - win32_error(GetLastError(), L"\"%ls\": Can't get reparse point", + status = winnt_fsctl(h, FSCTL_GET_REPARSE_POINT, + NULL, 0, &rpbuf, sizeof(rpbuf), &len); + if (!NT_SUCCESS(status)) { + winnt_error(status, L"\"%ls\": Can't get reparse point", printable_path(full_path)); return WIMLIB_ERR_READLINK; } - rpbuflen = bytes_returned; + rpbuflen = len; if (unlikely(rpbuflen < REPARSE_DATA_OFFSET)) { ERROR("\"%ls\": reparse point buffer is too short", @@ -1174,11 +1196,11 @@ winnt_scan_data_streams(HANDLE h, const wchar_t *path, size_t path_nchars, goto unnamed_only; /* Get a buffer containing the stream information. */ - while (!NT_SUCCESS(status = (*func_NtQueryInformationFile)(h, - &iosb, - buf, - bufsize, - FileStreamInformation))) + while (!NT_SUCCESS(status = NtQueryInformationFile(h, + &iosb, + buf, + bufsize, + FileStreamInformation))) { switch (status) { @@ -1276,12 +1298,9 @@ get_sort_key(HANDLE h) { STARTING_VCN_INPUT_BUFFER in = { .StartingVcn.QuadPart = 0 }; RETRIEVAL_POINTERS_BUFFER out; - DWORD bytesReturned; - if (!DeviceIoControl(h, FSCTL_GET_RETRIEVAL_POINTERS, - &in, sizeof(in), - &out, sizeof(out), - &bytesReturned, NULL)) + if (!NT_SUCCESS(winnt_fsctl(h, FSCTL_GET_RETRIEVAL_POINTERS, + &in, sizeof(in), &out, sizeof(out), NULL))) return 0; return extract_starting_lcn(&out); @@ -1377,14 +1396,12 @@ try_to_use_wimboot_hash(HANDLE h, struct wim_inode *inode, struct wof_external_info wof_info; struct wim_provider_external_info wim_info; } out; - IO_STATUS_BLOCK iosb; NTSTATUS status; /* WOF may be attached. Try reading this file's external * backing info. */ - status = (*func_NtFsControlFile)(h, NULL, NULL, NULL, &iosb, - FSCTL_GET_EXTERNAL_BACKING, - NULL, 0, &out, sizeof(out)); + status = winnt_fsctl(h, FSCTL_GET_EXTERNAL_BACKING, + NULL, 0, &out, sizeof(out), NULL); /* Is WOF not attached? */ if (status == STATUS_INVALID_DEVICE_REQUEST || @@ -1468,9 +1485,8 @@ get_file_info(HANDLE h, struct file_info *info) NTSTATUS status; FILE_ALL_INFORMATION all_info; - status = (*func_NtQueryInformationFile)(h, &iosb, &all_info, - sizeof(all_info), - FileAllInformation); + status = NtQueryInformationFile(h, &iosb, &all_info, sizeof(all_info), + FileAllInformation); if (unlikely(!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW)) return status; @@ -1497,9 +1513,9 @@ get_volume_information(HANDLE h, const wchar_t *full_path, NTSTATUS status; /* Get volume flags */ - status = (*func_NtQueryVolumeInformationFile)(h, &iosb, attr_info, - sizeof(_attr_info), - FileFsAttributeInformation); + status = NtQueryVolumeInformationFile(h, &iosb, attr_info, + sizeof(_attr_info), + FileFsAttributeInformation); if (NT_SUCCESS(status)) { ctx->vol_flags = attr_info->FileSystemAttributes; ctx->is_ntfs = (attr_info->FileSystemNameLength == 4 * sizeof(wchar_t)) && @@ -1510,9 +1526,9 @@ get_volume_information(HANDLE h, const wchar_t *full_path, } /* Get volume ID. */ - status = (*func_NtQueryVolumeInformationFile)(h, &iosb, &vol_info, - sizeof(vol_info), - FileFsVolumeInformation); + status = NtQueryVolumeInformationFile(h, &iosb, &vol_info, + sizeof(vol_info), + FileFsVolumeInformation); if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) && (iosb.Information >= offsetof(FILE_FS_VOLUME_INFORMATION, VolumeSerialNumber) + @@ -1550,7 +1566,6 @@ winnt_build_dentry_tree_recursive(struct wim_dentry **root_ret, int ret; NTSTATUS status; struct file_info file_info; - ACCESS_MASK requestedPerms; u64 sort_key; ret = try_exclude(full_path, ctx->params); @@ -1559,15 +1574,16 @@ winnt_build_dentry_tree_recursive(struct wim_dentry **root_ret, if (unlikely(ret > 0)) /* Error? */ goto out; - /* Open the file. */ - requestedPerms = FILE_READ_DATA | - FILE_READ_ATTRIBUTES | - READ_CONTROL | - ACCESS_SYSTEM_SECURITY | - SYNCHRONIZE; -retry_open: + /* Open the file with permission to read metadata. Although we will + * later need a handle with FILE_LIST_DIRECTORY permission (or, + * equivalently, FILE_READ_DATA; they're the same numeric value) if the + * file is a directory, it can significantly slow things down to request + * this permission on all nondirectories. Perhaps it causes Windows to + * start prefetching the file contents... */ status = winnt_openat(cur_dir, relative_path, relative_path_nchars, - requestedPerms, &h); + FILE_READ_ATTRIBUTES | READ_CONTROL | + ACCESS_SYSTEM_SECURITY, + &h); if (unlikely(!NT_SUCCESS(status))) { if (status == STATUS_DELETE_PENDING) { WARNING("\"%ls\": Deletion pending; skipping file", @@ -1575,12 +1591,6 @@ retry_open: ret = 0; goto out; } - if (status == STATUS_ACCESS_DENIED && - (requestedPerms & FILE_READ_DATA)) { - /* This happens on encrypted files. */ - requestedPerms &= ~FILE_READ_DATA; - goto retry_open; - } if (status == STATUS_SHARING_VIOLATION) { ERROR("Can't open \"%ls\":\n" " File is in use by another process! " @@ -1607,15 +1617,6 @@ retry_open: goto out; } - if (unlikely(!(requestedPerms & FILE_READ_DATA)) && - !(file_info.attributes & FILE_ATTRIBUTE_ENCRYPTED)) - { - ERROR("\"%ls\": Permission to read data was denied", - printable_path(full_path)); - ret = WIMLIB_ERR_OPEN; - goto out; - } - /* Create a WIM dentry with an associated inode, which may be shared. * * However, we need to explicitly check for directories and files with @@ -1690,7 +1691,7 @@ retry_open: * ERROR_SHARING_VIOLATION if there are any open handles to the * file, we have to close the file and re-open it later if * needed. */ - (*func_NtClose)(h); + NtClose(h); h = NULL; ret = winnt_scan_efsrpc_raw_data(inode, full_path, full_path_nchars, ctx); @@ -1729,21 +1730,19 @@ retry_open: /* Directory: recurse to children. */ - if (unlikely(!h)) { - /* Re-open handle that was closed to read raw encrypted - * data. */ - status = winnt_openat(cur_dir, - relative_path, - relative_path_nchars, - FILE_LIST_DIRECTORY | SYNCHRONIZE, - &h); - if (!NT_SUCCESS(status)) { - winnt_error(status, - L"\"%ls\": Can't re-open file", - printable_path(full_path)); - ret = WIMLIB_ERR_OPEN; - goto out; - } + /* Re-open the directory with FILE_LIST_DIRECTORY access. */ + if (h) { + NtClose(h); + h = NULL; + } + status = winnt_openat(cur_dir, relative_path, + relative_path_nchars, FILE_LIST_DIRECTORY, + &h); + if (!NT_SUCCESS(status)) { + winnt_error(status, L"\"%ls\": Can't open directory", + printable_path(full_path)); + ret = WIMLIB_ERR_OPEN; + goto out; } ret = winnt_recurse_directory(h, full_path, @@ -1762,7 +1761,7 @@ out_progress: ret = do_capture_progress(ctx->params, WIMLIB_SCAN_DENTRY_EXCLUDED, NULL); out: if (likely(h)) - (*func_NtClose)(h); + NtClose(h); if (unlikely(ret)) { free_dentry_tree(root, ctx->params->blob_table); root = NULL; @@ -2347,14 +2346,11 @@ load_files_from_mft(const wchar_t *path, struct ntfs_inode_map *inode_map) }; const size_t outsize = 32768; QUERY_FILE_LAYOUT_OUTPUT *out = NULL; - DWORD bytes_returned; int ret; - DWORD err; NTSTATUS status; status = winnt_open(path, wcslen(path), - FILE_READ_DATA | SYNCHRONIZE | FILE_READ_ATTRIBUTES, - &h); + FILE_READ_DATA | FILE_READ_ATTRIBUTES, &h); if (!NT_SUCCESS(status)) { ret = -1; /* Silently try standard recursive scan instead */ goto out; @@ -2366,8 +2362,9 @@ load_files_from_mft(const wchar_t *path, struct ntfs_inode_map *inode_map) goto out; } - while (DeviceIoControl(h, FSCTL_QUERY_FILE_LAYOUT, &in, sizeof(in), - out, outsize, &bytes_returned, NULL)) + while (NT_SUCCESS(status = winnt_fsctl(h, FSCTL_QUERY_FILE_LAYOUT, + &in, sizeof(in), + out, outsize, NULL))) { const FILE_LAYOUT_ENTRY *file = (const void *)out + out->FirstFileOffset; @@ -2382,16 +2379,15 @@ load_files_from_mft(const wchar_t *path, struct ntfs_inode_map *inode_map) in.Flags &= ~QUERY_FILE_LAYOUT_RESTART; } - /* Normally, FSCTL_QUERY_FILE_LAYOUT fails with error code 38 after all - * files have been enumerated. */ - err = GetLastError(); - if (err != 38) { - if (err == ERROR_INVALID_FUNCTION || - err == ERROR_INVALID_PARAMETER) { + /* Normally, FSCTL_QUERY_FILE_LAYOUT fails with STATUS_END_OF_FILE after + * all files have been enumerated. */ + if (status != STATUS_END_OF_FILE) { + if (status == STATUS_INVALID_DEVICE_REQUEST /* old OS */ || + status == STATUS_INVALID_PARAMETER /* not root directory */ ) { /* Silently try standard recursive scan instead */ ret = -1; } else { - win32_error(err, + winnt_error(status, L"Error enumerating files on volume \"%ls\"", path); /* Try standard recursive scan instead */ @@ -2402,7 +2398,7 @@ load_files_from_mft(const wchar_t *path, struct ntfs_inode_map *inode_map) ret = 0; out: FREE(out); - (*func_NtClose)(h); + NtClose(h); return ret; } @@ -2477,6 +2473,9 @@ security_map_lookup(struct security_map *map, u32 disk_security_id) struct security_map_node tmp; const struct avl_tree_node *res; + if (disk_security_id == 0) /* No on-disk security ID; uncacheable */ + return -1; + tmp.disk_security_id = disk_security_id; res = avl_tree_lookup_node(map->root, &tmp.index_node, _avl_cmp_security_map_nodes); @@ -2491,6 +2490,9 @@ security_map_insert(struct security_map *map, u32 disk_security_id, { struct security_map_node *node; + if (disk_security_id == 0) /* No on-disk security ID; uncacheable */ + return 0; + node = MALLOC(sizeof(*node)); if (!node) return WIMLIB_ERR_NOMEM; @@ -2618,8 +2620,7 @@ generate_wim_structures_recursive(struct wim_dentry **root_ret, status = winnt_open(path, path_nchars, READ_CONTROL | - ACCESS_SYSTEM_SECURITY | - SYNCHRONIZE, &h); + ACCESS_SYSTEM_SECURITY, &h); if (!NT_SUCCESS(status)) { winnt_error(status, L"Can't open \"%ls\" to " "read security descriptor", @@ -2628,7 +2629,7 @@ generate_wim_structures_recursive(struct wim_dentry **root_ret, goto out; } ret = winnt_load_security_descriptor(h, inode, path, ctx); - (*func_NtClose)(h); + NtClose(h); if (ret) goto out; @@ -2643,22 +2644,22 @@ generate_wim_structures_recursive(struct wim_dentry **root_ret, ns = FIRST_STREAM(ni); for (u32 i = 0; i < ni->num_streams; i++) { struct windows_file *windows_file; - size_t stream_name_nchars; + /* Reference the stream by path if it's a named data stream, or + * if the volume doesn't support "open by file ID", or if the + * application hasn't explicitly opted in to "open by file ID". + * Otherwise, only save the inode number (file ID). */ if (*ns->name || - !(ctx->vol_flags & FILE_SUPPORTS_OPEN_BY_FILE_ID)) + !(ctx->vol_flags & FILE_SUPPORTS_OPEN_BY_FILE_ID) || + !(ctx->params->add_flags & WIMLIB_ADD_FLAG_FILE_PATHS_UNNEEDED)) { - /* Named data stream: reference by path */ - stream_name_nchars = wcslen(ns->name); windows_file = alloc_windows_file(path, path_nchars, ns->name, - stream_name_nchars, + wcslen(ns->name), ctx->snapshot, false); } else { - /* Unamed data stream: reference by file ID (inode number) */ - stream_name_nchars = 0; windows_file = alloc_windows_file_for_file_id(ni->ino, path, ctx->params->capture_root_nchars + 1, @@ -2833,9 +2834,7 @@ win32_build_dentry_tree(struct wim_dentry **root_ret, if (ret) goto out; - status = winnt_open(path, ntpath_nchars, - FILE_TRAVERSE | FILE_READ_ATTRIBUTES | SYNCHRONIZE, - &h); + status = winnt_open(path, ntpath_nchars, FILE_READ_ATTRIBUTES, &h); if (!NT_SUCCESS(status)) { winnt_error(status, L"Can't open \"%ls\"", printable_path(path)); if (status == STATUS_FVE_LOCKED_VOLUME) @@ -2847,7 +2846,7 @@ win32_build_dentry_tree(struct wim_dentry **root_ret, get_volume_information(h, path, &ctx); - (*func_NtClose)(h); + NtClose(h); #ifdef ENABLE_FAST_MFT_SCAN if (ctx.is_ntfs && !_wgetenv(L"WIMLIB_DISABLE_QUERY_FILE_LAYOUT")) {