From 117e52b79b02f1889f1bccd9d8560b73a965c559 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 13 May 2014 17:41:22 -0500 Subject: [PATCH] win32_capture.c: Load volume information on first chance --- include/wimlib/win32_common.h | 6 ++++ src/win32_capture.c | 60 ++++++++++++++++++++--------------- src/win32_common.c | 7 ++++ 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/include/wimlib/win32_common.h b/include/wimlib/win32_common.h index 1a710d20..4e2d7915 100644 --- a/include/wimlib/win32_common.h +++ b/include/wimlib/win32_common.h @@ -79,6 +79,12 @@ extern NTSTATUS (WINAPI *func_NtQueryDirectoryFile) (HANDLE FileHandle, PUNICODE_STRING FileName, BOOLEAN RestartScan); +extern NTSTATUS (WINAPI *func_NtQueryVolumeInformationFile) (HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FsInformation, + ULONG Length, + FS_INFORMATION_CLASS FsInformationClass); + extern NTSTATUS (WINAPI *func_NtSetSecurityObject)(HANDLE Handle, SECURITY_INFORMATION SecurityInformation, diff --git a/src/win32_capture.c b/src/win32_capture.c index ef53f1aa..7ae4b5fa 100644 --- a/src/win32_capture.c +++ b/src/win32_capture.c @@ -352,7 +352,7 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret, size_t filename_nchars, struct add_image_params *params, struct win32_capture_state *state, - unsigned vol_flags); + DWORD vol_flags); /* Reads the directory entries of directory and recursively calls * win32_build_dentry_tree() on them. */ @@ -363,7 +363,7 @@ win32_recurse_directory(HANDLE h, struct wim_dentry *root, struct add_image_params *params, struct win32_capture_state *state, - unsigned vol_flags) + DWORD vol_flags) { int ret; @@ -834,7 +834,7 @@ win32_capture_streams(HANDLE *hFile_p, struct wim_inode *inode, struct list_head *unhashed_streams, u64 file_size, - unsigned vol_flags) + DWORD vol_flags) { int ret; u8 _buf[8192] _aligned_attribute(8); @@ -957,7 +957,7 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret, size_t filename_nchars, struct add_image_params *params, struct win32_capture_state *state, - unsigned vol_flags) + DWORD vol_flags) { struct wim_dentry *root = NULL; struct wim_inode *inode = NULL; @@ -1000,6 +1000,31 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret, goto out; } + if (!cur_dir) { + /* Root directory; get volume information. */ + FILE_FS_ATTRIBUTE_INFORMATION info; + IO_STATUS_BLOCK iosb; + + params->capture_root_ino = + ((u64)file_info.nFileIndexHigh << 32) | + file_info.nFileIndexLow; + params->capture_root_dev = file_info.dwVolumeSerialNumber; + + status = (*func_NtQueryVolumeInformationFile)(h, &iosb, + &info, sizeof(info), + FileFsAttributeInformation); + if ((NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW)) && + iosb.Information >= sizeof(FILE_FS_ATTRIBUTE_INFORMATION)) + { + vol_flags = info.FileSystemAttributes; + } else { + set_errno_from_nt_status(status); + WARNING_WITH_ERRNO("\"%ls\": Can't get volume information", + full_path); + vol_flags = 0; + } + } + if (file_info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { rpbuf = alloca(REPARSE_POINT_MAX_SIZE); ret = win32_get_reparse_data(h, full_path, @@ -1172,35 +1197,20 @@ win32_build_dentry_tree(struct wim_dentry **root_ret, const wchar_t *root_disk_path, struct add_image_params *params) { - size_t path_nchars; wchar_t *path; + DWORD dret; + size_t path_nchars; int ret; struct win32_capture_state state; - unsigned vol_flags; - DWORD dret; - - path_nchars = wcslen(root_disk_path); - if (path_nchars > WINDOWS_NT_MAX_PATH) - return WIMLIB_ERR_INVALID_PARAM; - - ret = win32_get_file_and_vol_ids(root_disk_path, - ¶ms->capture_root_ino, - ¶ms->capture_root_dev); - if (ret) { - ERROR_WITH_ERRNO("Can't open %ls", root_disk_path); - return ret; - } - - win32_get_vol_flags(root_disk_path, &vol_flags, NULL); /* WARNING: There is no check for overflow later when this buffer is * being used! But it's as long as the maximum path length understood - * by Windows NT (which is NOT the same as MAX_PATH). */ + * by Windows NT (which is NOT the same as MAX_PATH). */ path = MALLOC((WINDOWS_NT_MAX_PATH + 1) * sizeof(wchar_t)); if (!path) return WIMLIB_ERR_NOMEM; - /* Translate into full path */ + /* Translate into full path. */ dret = GetFullPathName(root_disk_path, WINDOWS_NT_MAX_PATH - 3, &path[4], NULL); @@ -1209,7 +1219,7 @@ win32_build_dentry_tree(struct wim_dentry **root_ret, return WIMLIB_ERR_UNSUPPORTED; } - /* Add \??\ prefix */ + /* Add \??\ prefix to form the NT namespace path. */ wmemcpy(path, L"\\??\\", 4); path_nchars = dret + 4; @@ -1228,7 +1238,7 @@ win32_build_dentry_tree(struct wim_dentry **root_ret, memset(&state, 0, sizeof(state)); ret = win32_build_dentry_tree_recursive(root_ret, NULL, path, path_nchars, L"", 0, - params, &state, vol_flags); + params, &state, 0); FREE(path); if (ret == 0) win32_do_capture_warnings(root_disk_path, &state, params->add_flags); diff --git a/src/win32_common.c b/src/win32_common.c index 9f5c72f1..1768fd9b 100644 --- a/src/win32_common.c +++ b/src/win32_common.c @@ -565,6 +565,12 @@ NTSTATUS (WINAPI *func_NtQueryDirectoryFile) (HANDLE FileHandle, PUNICODE_STRING FileName, BOOLEAN RestartScan); +NTSTATUS (WINAPI *func_NtQueryVolumeInformationFile) (HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FsInformation, + ULONG Length, + FS_INFORMATION_CLASS FsInformationClass); + NTSTATUS (WINAPI *func_NtSetSecurityObject)(HANDLE Handle, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor); @@ -615,6 +621,7 @@ struct dll_spec ntdll_spec = { DLL_SYM(NtQueryInformationFile, true), DLL_SYM(NtQuerySecurityObject, true), DLL_SYM(NtQueryDirectoryFile, true), + DLL_SYM(NtQueryVolumeInformationFile, true), DLL_SYM(NtSetSecurityObject, true), DLL_SYM(NtClose, true), DLL_SYM(RtlNtStatusToDosError, true), -- 2.43.0