win32_capture.c: Load volume information on first chance
authorEric Biggers <ebiggers3@gmail.com>
Tue, 13 May 2014 22:41:22 +0000 (17:41 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Tue, 13 May 2014 22:41:22 +0000 (17:41 -0500)
include/wimlib/win32_common.h
src/win32_capture.c
src/win32_common.c

index 1a710d2..4e2d791 100644 (file)
@@ -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,
index ef53f1a..7ae4b5f 100644 (file)
@@ -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,
-                                        &params->capture_root_ino,
-                                        &params->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);
index 9f5c72f..1768fd9 100644 (file)
@@ -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),