]> wimlib.net Git - wimlib/blobdiff - src/win32.c
win32_read_file: Use UTF16-LE name
[wimlib] / src / win32.c
index 8b8620fe11b01fdea8345e7518fdcb4b3768e9a8..0c5c51cdb47594afcc5d7738f26b76bf418538ca 100644 (file)
 
 #include <errno.h>
 
+
+
+/* Pointers to functions that are not available on all targetted versions of
+ * Windows (XP and later).  NOTE: The WINAPI annotations seem to be important; I
+ * assume it specifies a certain calling convention. */
+
+/* Vista and later */
+static HANDLE (WINAPI *win32func_FindFirstStreamW)(LPCWSTR lpFileName,
+                                           STREAM_INFO_LEVELS InfoLevel,
+                                           LPVOID lpFindStreamData,
+                                           DWORD dwFlags) = NULL;
+
+/* Vista and later */
+static BOOL (WINAPI *win32func_FindNextStreamW)(HANDLE hFindStream,
+                                        LPVOID lpFindStreamData) = NULL;
+
+static HMODULE hKernel32 = NULL;
+
+/* Try to dynamically load some functions */
+void
+win32_global_init()
+{
+       DWORD err;
+       bool warned;
+
+
+       if (hKernel32 == NULL) {
+               DEBUG("Loading Kernel32.dll");
+               hKernel32 = LoadLibraryA("Kernel32.dll");
+               if (hKernel32 == NULL) {
+                       err = GetLastError();
+                       WARNING("Can't load Kernel32.dll");
+                       win32_error(err);
+                       return;
+               }
+       }
+
+       DEBUG("Looking for FindFirstStreamW");
+       win32func_FindFirstStreamW = (void*)GetProcAddress(hKernel32, "FindFirstStreamW");
+       if (!win32func_FindFirstStreamW) {
+               WARNING("Could not find function FindFirstStreamW() in Kernel32.dll!");
+               WARNING("Capturing alternate data streams will not be supported.");
+               return;
+       }
+
+       DEBUG("Looking for FindNextStreamW");
+       win32func_FindNextStreamW = (void*)GetProcAddress(hKernel32, "FindNextStreamW");
+       if (!win32func_FindNextStreamW) {
+               WARNING("Could not find function FindNextStreamW() in Kernel32.dll!");
+               WARNING("Capturing alternate data streams will not be supported.");
+               win32func_FindFirstStreamW = NULL;
+       }
+}
+
+void
+win32_global_cleanup()
+{
+       if (hKernel32 != NULL) {
+               DEBUG("Closing Kernel32.dll");
+               FreeLibrary(hKernel32);
+               hKernel32 = NULL;
+       }
+}
+
 static const char *access_denied_msg =
 "         If you are not running this program as the administrator, you may\n"
 "         need to do so, so that all data and metadata can be backed up.\n"
@@ -95,7 +159,7 @@ win32_open_file_data_only(const wchar_t *path)
 }
 
 int
-win32_read_file(const mbchar *filename,
+win32_read_file(const utf16lechar *win32_filename,
                void *handle, u64 offset, size_t size, void *buf)
 {
        HANDLE h = handle;
@@ -109,7 +173,7 @@ win32_read_file(const mbchar *filename,
                if (ReadFile(h, buf, size, &bytesRead, NULL) && bytesRead == size)
                        return 0;
        err = GetLastError();
-       ERROR("Error reading \"%s\"", filename);
+       ERROR("Error reading \"%ls\"", win32_filename);
        win32_error(err);
        return WIMLIB_ERR_READ;
 }
@@ -524,23 +588,33 @@ out_invalid_stream_name:
  *
  * @lookup_table:       Stream lookup table for the WIM.
  *
+ * @file_size:         Size of unnamed data stream.  (Used only if alternate
+ *                      data streams API appears to be unavailable.)
+ *
  * Returns 0 on success; nonzero on failure.
  */
 static int
 win32_capture_streams(const wchar_t *path_utf16,
                      size_t path_utf16_nchars,
                      struct wim_inode *inode,
-                     struct wim_lookup_table *lookup_table)
+                     struct wim_lookup_table *lookup_table,
+                     u64 file_size)
 {
        WIN32_FIND_STREAM_DATA dat;
        int ret;
        HANDLE hFind;
        DWORD err;
 
-       hFind = FindFirstStreamW(path_utf16, FindStreamInfoStandard, &dat, 0);
+       if (win32func_FindFirstStreamW == NULL)
+               goto unnamed_only;
+
+       hFind = win32func_FindFirstStreamW(path_utf16, FindStreamInfoStandard, &dat, 0);
        if (hFind == INVALID_HANDLE_VALUE) {
                err = GetLastError();
 
+               if (err == ERROR_CALL_NOT_IMPLEMENTED)
+                       goto unnamed_only;
+
                /* Seems legal for this to return ERROR_HANDLE_EOF on reparse
                 * points and directories */
                if ((inode->i_attributes &
@@ -569,7 +643,7 @@ win32_capture_streams(const wchar_t *path_utf16,
                                           &dat);
                if (ret)
                        goto out_find_close;
-       } while (FindNextStreamW(hFind, &dat));
+       } while (win32func_FindNextStreamW(hFind, &dat));
        err = GetLastError();
        if (err != ERROR_HANDLE_EOF) {
                ERROR("Win32 API: Error reading data streams from \"%ls\"", path_utf16);
@@ -579,6 +653,20 @@ win32_capture_streams(const wchar_t *path_utf16,
 out_find_close:
        FindClose(hFind);
        return ret;
+unnamed_only:
+       if (inode->i_attributes &
+            (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY))
+       {
+               ret = 0;
+       } else {
+               wcscpy(dat.cStreamName, L"::$DATA");
+               dat.StreamSize.QuadPart = file_size;
+               ret = win32_capture_stream(path_utf16,
+                                          path_utf16_nchars,
+                                          inode, lookup_table,
+                                          &dat);
+       }
+       return ret;
 }
 
 /* Win32 version of capturing a directory tree */
@@ -601,6 +689,7 @@ win32_build_dentry_tree(struct wim_dentry **root_ret,
        size_t path_utf16_nchars;
        struct sd_set *sd_set;
        DWORD err;
+       u64 file_size;
 
        if (exclude_path(root_disk_path, config, true)) {
                if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) {
@@ -691,6 +780,9 @@ win32_build_dentry_tree(struct wim_dentry **root_ret,
                        goto out_close_handle;
        }
 
+       file_size = ((u64)file_info.nFileSizeHigh << 32) |
+                    (u64)file_info.nFileSizeLow;
+
        if (inode_is_directory(inode)) {
                /* Directory (not a reparse point) --- recurse to children */
 
@@ -699,7 +791,8 @@ win32_build_dentry_tree(struct wim_dentry **root_ret,
                ret = win32_capture_streams(path_utf16,
                                            path_utf16_nchars,
                                            inode,
-                                           lookup_table);
+                                           lookup_table,
+                                           file_size);
                if (ret)
                        goto out_close_handle;
                ret = win32_recurse_directory(root,
@@ -724,7 +817,8 @@ win32_build_dentry_tree(struct wim_dentry **root_ret,
                ret = win32_capture_streams(path_utf16,
                                            path_utf16_nchars,
                                            inode,
-                                           lookup_table);
+                                           lookup_table,
+                                           file_size);
        }
 out_close_handle:
        CloseHandle(hFile);