Factor out Win32 => NT path conversion and use in win32_capture.c
authorEric Biggers <ebiggers3@gmail.com>
Sat, 21 Jun 2014 21:06:00 +0000 (16:06 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sat, 21 Jun 2014 21:06:00 +0000 (16:06 -0500)
include/wimlib/win32_common.h
src/win32_apply.c
src/win32_capture.c
src/win32_common.c

index 2921caa..691af74 100644 (file)
@@ -156,6 +156,7 @@ windows_version_is_at_least(unsigned major, unsigned minor);
 #define running_on_windows_7_or_later() \
                        windows_version_is_at_least(6, 1)
 
-
+extern int
+win32_path_to_nt_path(const wchar_t *win32_path, UNICODE_STRING *nt_path);
 
 #endif /* _WIMLIB_WIN32_COMMON_H */
index 6879445..48d3ccb 100644 (file)
@@ -510,33 +510,15 @@ current_path(struct win32_apply_ctx *ctx)
 static int
 prepare_target(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
 {
+       int ret;
        NTSTATUS status;
        size_t path_max;
 
        /* Open handle to the target directory (possibly creating it).  */
 
-       if (func_RtlDosPathNameToNtPathName_U_WithStatus) {
-               status = (*func_RtlDosPathNameToNtPathName_U_WithStatus)(ctx->common.target,
-                                                                        &ctx->target_ntpath,
-                                                                        NULL, NULL);
-       } else {
-               if ((*func_RtlDosPathNameToNtPathName_U)(ctx->common.target,
-                                                        &ctx->target_ntpath,
-                                                        NULL, NULL))
-                       status = STATUS_SUCCESS;
-               else
-                       status = STATUS_NO_MEMORY;
-       }
-       if (!NT_SUCCESS(status)) {
-               if (status == STATUS_NO_MEMORY) {
-                       return WIMLIB_ERR_NOMEM;
-               } else {
-                       ERROR("\"%ls\": invalid path name "
-                             "(status=0x%08"PRIx32")",
-                             ctx->common.target, (u32)status);
-                       return WIMLIB_ERR_INVALID_PARAM;
-               }
-       }
+       ret = win32_path_to_nt_path(ctx->common.target, &ctx->target_ntpath);
+       if (ret)
+               return ret;
 
        ctx->attr.Length = sizeof(ctx->attr);
        ctx->attr.ObjectName = &ctx->target_ntpath;
index 7a836a5..6223ed2 100644 (file)
@@ -1385,9 +1385,8 @@ win32_build_dentry_tree(struct wim_dentry **root_ret,
                        struct add_image_params *params)
 {
        wchar_t *path;
-       DWORD dret;
-       size_t path_nchars;
        int ret;
+       UNICODE_STRING ntpath;
        struct winnt_scan_stats stats;
 
        /* WARNING: There is no check for overflow later when this buffer is
@@ -1397,33 +1396,31 @@ win32_build_dentry_tree(struct wim_dentry **root_ret,
        if (!path)
                return WIMLIB_ERR_NOMEM;
 
-       /* Translate into full path.  */
-       dret = GetFullPathName(root_disk_path, WINDOWS_NT_MAX_PATH - 3,
-                              &path[4], NULL);
+       ret = win32_path_to_nt_path(root_disk_path, &ntpath);
+       if (ret)
+               goto out_free_path;
 
-       if (unlikely(dret == 0 || dret >= WINDOWS_NT_MAX_PATH - 3)) {
-               ERROR("Can't get full path name for \"%ls\"", root_disk_path);
-               return WIMLIB_ERR_UNSUPPORTED;
+       if (ntpath.Length < 4 * sizeof(wchar_t) ||
+           ntpath.Length > WINDOWS_NT_MAX_PATH * sizeof(wchar_t) ||
+           wmemcmp(ntpath.Buffer, L"\\??\\", 4))
+       {
+               ERROR("\"%ls\": unrecognized path format", root_disk_path);
+               ret = WIMLIB_ERR_INVALID_PARAM;
+               goto out_free_path;
        }
 
-       /* Add \??\ prefix to form the NT namespace path.  */
-       wmemcpy(path, L"\\??\\", 4);
-       path_nchars = dret + 4;
-
-       /* Strip trailing slashes.  If we don't do this, we may create a path
-       * with multiple consecutive backslashes, which for some reason causes
-       * Windows to report that the file cannot be found.  */
-       while (unlikely(path[path_nchars - 1] == L'\\' &&
-                       path[path_nchars - 2] != L':'))
-               path[--path_nchars] = L'\0';
+       params->capture_root_nchars = ntpath.Length / sizeof(wchar_t);
+       wmemcpy(path, ntpath.Buffer, params->capture_root_nchars);
+       path[params->capture_root_nchars] = L'\0';
 
-       params->capture_root_nchars = path_nchars;
+       HeapFree(GetProcessHeap(), 0, ntpath.Buffer);
 
        memset(&stats, 0, sizeof(stats));
 
        ret = winnt_build_dentry_tree_recursive(root_ret, NULL,
-                                               path, path_nchars, L"", 0,
-                                               params, &stats, 0);
+                                               path, params->capture_root_nchars,
+                                               L"", 0, params, &stats, 0);
+out_free_path:
        FREE(path);
        if (ret == 0)
                winnt_do_scan_warnings(root_disk_path, &stats);
index 7016fe2..412421e 100644 (file)
@@ -622,4 +622,42 @@ win32_global_cleanup(void)
        cleanup_dll(&ntdll_spec);
 }
 
+/*
+ * Translates a Win32-namespace path into an NT-namespace path.
+ *
+ * On success, returns 0.  The NT-namespace path will be stored in the
+ * UNICODE_STRING structure pointed to by nt_path.  nt_path->Buffer will be set
+ * to a new buffer that must later be freed with HeapFree().  (Really
+ * RtlHeapFree(), but HeapFree() seems to be the same thing.)
+ *
+ * On failure, returns WIMLIB_ERR_NOMEM or WIMLIB_ERR_INVALID_PARAM.
+ */
+int
+win32_path_to_nt_path(const wchar_t *win32_path, UNICODE_STRING *nt_path)
+{
+       NTSTATUS status;
+
+       if (func_RtlDosPathNameToNtPathName_U_WithStatus) {
+               status = (*func_RtlDosPathNameToNtPathName_U_WithStatus)(win32_path,
+                                                                        nt_path,
+                                                                        NULL, NULL);
+       } else {
+               if ((*func_RtlDosPathNameToNtPathName_U)(win32_path, nt_path,
+                                                        NULL, NULL))
+                       status = STATUS_SUCCESS;
+               else
+                       status = STATUS_NO_MEMORY;
+       }
+
+       if (likely(NT_SUCCESS(status)))
+               return 0;
+
+       if (status == STATUS_NO_MEMORY)
+               return WIMLIB_ERR_NOMEM;
+
+       ERROR("\"%ls\": invalid path name (status=0x%08"PRIx32")",
+             win32_path, (u32)status);
+       return WIMLIB_ERR_INVALID_PARAM;
+}
+
 #endif /* __WIN32__ */