system compression: try to attach WOF if compression fails
authorEric Biggers <ebiggers3@gmail.com>
Thu, 24 Sep 2015 02:54:32 +0000 (21:54 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Thu, 24 Sep 2015 03:53:03 +0000 (22:53 -0500)
include/wimlib/win32_common.h
src/wimboot.c
src/win32_apply.c
src/win32_common.c

index 9b87355..0e2db43 100644 (file)
@@ -154,6 +154,9 @@ win32_path_to_nt_path(const wchar_t *win32_path, UNICODE_STRING *nt_path);
 extern int
 win32_get_drive_path(const wchar_t *file_path, wchar_t drive_path[7]);
 
+extern bool
+win32_try_to_attach_wof(const wchar_t *drive);
+
 extern void
 win32_warning(DWORD err, const wchar_t *format, ...) _cold_attribute;
 
index d4643d6..467f9fb 100644 (file)
@@ -866,47 +866,6 @@ out:
        return ret;
 }
 
-/* Try to attach an instance of the Windows Overlay File System Filter Driver to
- * the specified drive (such as C:)  */
-static bool
-try_to_attach_wof(const wchar_t *drive)
-{
-       HMODULE fltlib;
-       bool retval = false;
-
-       /* Use FilterAttach() from Fltlib.dll.  */
-
-       fltlib = LoadLibrary(L"Fltlib.dll");
-
-       if (!fltlib) {
-               WARNING("Failed to load Fltlib.dll");
-               return retval;
-       }
-
-       HRESULT (WINAPI *func_FilterAttach)(LPCWSTR lpFilterName,
-                                           LPCWSTR lpVolumeName,
-                                           LPCWSTR lpInstanceName,
-                                           DWORD dwCreatedInstanceNameLength,
-                                           LPWSTR lpCreatedInstanceName);
-
-       func_FilterAttach = (void *)GetProcAddress(fltlib, "FilterAttach");
-
-       if (func_FilterAttach) {
-               HRESULT res;
-
-               res = (*func_FilterAttach)(L"WoF", drive, NULL, 0, NULL);
-
-               if (res == S_OK)
-                       retval = true;
-       } else {
-               WARNING("FilterAttach() does not exist in Fltlib.dll");
-       }
-
-       FreeLibrary(fltlib);
-
-       return retval;
-}
-
 /*
  * Allocate a WOF data source ID for a WIM file.
  *
@@ -1001,7 +960,7 @@ retry_ioctl:
                                CloseHandle(h);
                                h = INVALID_HANDLE_VALUE;
                                tried_to_attach_wof = true;
-                               if (try_to_attach_wof(drive_path + 4))
+                               if (win32_try_to_attach_wof(drive_path + 4))
                                        goto retry_ioctl;
                        }
                        ret = WIMLIB_ERR_UNSUPPORTED;
index 7a93c41..ce62d6a 100644 (file)
@@ -2299,6 +2299,38 @@ set_system_compression(HANDLE h, int format)
        return status;
 }
 
+static NTSTATUS
+set_system_compression_on_inode(struct wim_inode *inode, int format,
+                               struct win32_apply_ctx *ctx)
+{
+       bool retried = false;
+       NTSTATUS status;
+       HANDLE h;
+
+       /* Open the extracted file.  */
+       status = create_file(&h, GENERIC_READ | GENERIC_WRITE, NULL,
+                            0, FILE_OPEN, 0,
+                            inode_first_extraction_dentry(inode), ctx);
+
+       if (!NT_SUCCESS(status))
+               return status;
+retry:
+       /* Compress the file.  If the attempt fails with "invalid device
+        * request", then attach wof.sys (or wofadk.sys) and retry.  */
+       status = set_system_compression(h, format);
+       if (unlikely(status == STATUS_INVALID_DEVICE_REQUEST && !retried)) {
+               wchar_t drive_path[7];
+               if (!win32_get_drive_path(ctx->common.target, drive_path) &&
+                   win32_try_to_attach_wof(drive_path + 4)) {
+                       retried = true;
+                       goto retry;
+               }
+       }
+
+       (*func_NtClose)(h);
+       return status;
+}
+
 /*
  * This function is called when doing a "compact-mode" extraction and we just
  * finished extracting a blob to one or more locations.  For each location that
@@ -2325,7 +2357,6 @@ handle_system_compression(struct blob_descriptor *blob, struct win32_apply_ctx *
        for (u32 i = 0; i < blob->out_refcnt; i++) {
                struct wim_inode *inode = targets[i].inode;
                struct wim_inode_stream *strm = targets[i].stream;
-               HANDLE h;
                NTSTATUS status;
 
                if (!stream_is_unnamed_data_stream(strm))
@@ -2334,14 +2365,9 @@ handle_system_compression(struct blob_descriptor *blob, struct win32_apply_ctx *
                if (will_externally_back_inode(inode, ctx, NULL, false) != 0)
                        continue;
 
-               status = create_file(&h, GENERIC_READ | GENERIC_WRITE, NULL,
-                                    0, FILE_OPEN, 0,
-                                    inode_first_extraction_dentry(inode), ctx);
-
-               if (NT_SUCCESS(status)) {
-                       status = set_system_compression(h, format);
-                       (*func_NtClose)(h);
-               }
+               status = set_system_compression_on_inode(inode, format, ctx);
+               if (likely(NT_SUCCESS(status)))
+                       continue;
 
                if (status == STATUS_INVALID_DEVICE_REQUEST) {
                        WARNING(
@@ -2353,16 +2379,14 @@ handle_system_compression(struct blob_descriptor *blob, struct win32_apply_ctx *
                        return;
                }
 
-               if (!NT_SUCCESS(status)) {
-                       ctx->num_system_compression_failures++;
-                       if (ctx->num_system_compression_failures < 10) {
-                               winnt_warning(status, L"\"%ls\": Failed to compress "
-                                             "extracted file using System Compression",
-                                             current_path(ctx));
-                       } else if (ctx->num_system_compression_failures == 10) {
-                               WARNING("Suppressing further warnings about "
-                                       "System Compression failures.");
-                       }
+               ctx->num_system_compression_failures++;
+               if (ctx->num_system_compression_failures < 10) {
+                       winnt_warning(status, L"\"%ls\": Failed to compress "
+                                     "extracted file using System Compression",
+                                     current_path(ctx));
+               } else if (ctx->num_system_compression_failures == 10) {
+                       WARNING("Suppressing further warnings about "
+                               "System Compression failures.");
                }
        }
 }
index aa5be37..3b0d9e8 100644 (file)
@@ -379,6 +379,48 @@ win32_get_drive_path(const wchar_t *file_path, wchar_t drive_path[7])
        return 0;
 }
 
+/* Try to attach an instance of the Windows Overlay File System Filter Driver to
+ * the specified drive (such as C:)  */
+bool
+win32_try_to_attach_wof(const wchar_t *drive)
+{
+       HMODULE fltlib;
+       bool retval = false;
+
+       /* Use FilterAttach() from Fltlib.dll.  */
+
+       fltlib = LoadLibrary(L"Fltlib.dll");
+
+       if (!fltlib) {
+               WARNING("Failed to load Fltlib.dll");
+               return retval;
+       }
+
+       HRESULT (WINAPI *func_FilterAttach)(LPCWSTR lpFilterName,
+                                           LPCWSTR lpVolumeName,
+                                           LPCWSTR lpInstanceName,
+                                           DWORD dwCreatedInstanceNameLength,
+                                           LPWSTR lpCreatedInstanceName);
+
+       func_FilterAttach = (void *)GetProcAddress(fltlib, "FilterAttach");
+
+       if (func_FilterAttach) {
+               HRESULT res;
+
+               res = (*func_FilterAttach)(L"WoF", drive, NULL, 0, NULL);
+
+               if (res == S_OK)
+                       retval = true;
+       } else {
+               WARNING("FilterAttach() does not exist in Fltlib.dll");
+       }
+
+       FreeLibrary(fltlib);
+
+       return retval;
+}
+
+
 static void
 windows_msg(u32 code, const wchar_t *format, va_list va,
            bool is_ntstatus, bool is_error)