]> wimlib.net Git - wimlib/blobdiff - src/win32_apply.c
Update docs for capture config and paths files
[wimlib] / src / win32_apply.c
index 9eb8bad005f9fa6b2ef23d4fcee6e5be835d2f25..87582d60d93b3649e76e7e02e7289f6d3c65dd74 100644 (file)
 #include "wimlib/apply.h"
 #include "wimlib/error.h"
 #include "wimlib/lookup_table.h"
+#include "wimlib/xml.h"
+#include "wimlib/wim.h"
+#include "wimlib/wimboot.h"
+
+static void
+ctx_save_data_source_id(struct apply_ctx *ctx, u64 data_source_id)
+{
+       ctx->private[0] = data_source_id & 0xFFFFFFFF;
+       ctx->private[1] = data_source_id >> 32;
+}
+
+static u64
+ctx_get_data_source_id(const struct apply_ctx *ctx)
+{
+       return (u32)ctx->private[0] | ((u64)(u32)ctx->private[1] << 32);
+}
 
 static int
 win32_start_extract(const wchar_t *path, struct apply_ctx *ctx)
@@ -78,95 +94,42 @@ win32_start_extract(const wchar_t *path, struct apply_ctx *ctx)
 
        if (supports_SetFileShortName)
                ctx->supported_features.short_names = 1;
-       return 0;
-}
 
-/* Create a normal file, overwriting one already present.  */
-static int
-win32_create_file(const wchar_t *path, struct apply_ctx *ctx, u64 *cookie_ret)
-{
-       HANDLE h;
-       unsigned retry_count = 0;
-       DWORD dwFlagsAndAttributes = FILE_FLAG_BACKUP_SEMANTICS;
+       if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT) {
 
-retry:
-       /* WRITE_OWNER and WRITE_DAC privileges are required for some reason,
-        * even through we're creating a new file.  */
-       h = CreateFile(path, WRITE_OWNER | WRITE_DAC, 0, NULL,
-                      CREATE_ALWAYS, dwFlagsAndAttributes, NULL);
-       if (h == INVALID_HANDLE_VALUE) {
-               /* File couldn't be created.  */
-               DWORD err = GetLastError();
-               if (err == ERROR_ACCESS_DENIED && retry_count == 0) {
+               u64 data_source_id;
 
-                       /* Access denied error for the first time.  Try
-                        * adjusting file attributes.  */
+               if (!wim_info_get_wimboot(ctx->wim->wim_info,
+                                         ctx->wim->current_image))
+                       WARNING("Image is not marked as WIMBoot compatible!");
 
-                       /* Get attributes of the existing file.  */
-                       DWORD attribs = GetFileAttributes(path);
-                       if (attribs != INVALID_FILE_ATTRIBUTES &&
-                           (attribs & (FILE_ATTRIBUTE_HIDDEN |
-                                       FILE_ATTRIBUTE_SYSTEM |
-                                       FILE_ATTRIBUTE_READONLY)))
-                       {
-                               /* If the existing file has
-                                * FILE_ATTRIBUTE_HIDDEN and/or
-                                * FILE_ATTRIBUTE_SYSTEM, they must be set in
-                                * the call to CreateFile().  This is true even
-                                * when FILE_ATTRIBUTE_NORMAL was not specified,
-                                * contrary to the MS "documentation".  */
-                               dwFlagsAndAttributes |= (attribs &
-                                                        (FILE_ATTRIBUTE_HIDDEN |
-                                                         FILE_ATTRIBUTE_SYSTEM));
-                               /* If the existing file has
-                                * FILE_ATTRIBUTE_READONLY, it must be cleared
-                                * before attempting to create a new file over
-                                * it.  This is true even when the process has
-                                * the SE_RESTORE_NAME privilege and requested
-                                * the FILE_FLAG_BACKUP_SEMANTICS flag to
-                                * CreateFile().  */
-                               if (attribs & FILE_ATTRIBUTE_READONLY) {
-                                       SetFileAttributes(path,
-                                                         attribs & ~FILE_ATTRIBUTE_READONLY);
-                               }
-                               retry_count++;
-                               goto retry;
-                       }
-               }
-               set_errno_from_win32_error(err);
-               return WIMLIB_ERR_OPEN;
+               ret = wimboot_alloc_data_source_id(ctx->wim->filename,
+                                                  ctx->wim->current_image,
+                                                  path, &data_source_id);
+               if (ret)
+                       return ret;
+
+               ctx_save_data_source_id(ctx, data_source_id);
        }
-       CloseHandle(h);
-       return 0;
-}
 
-static int
-win32_create_directory(const wchar_t *path, struct apply_ctx *ctx,
-                      u64 *cookie_ret)
-{
-       if (!CreateDirectory(path, NULL))
-               if (GetLastError() != ERROR_ALREADY_EXISTS)
-                       goto error;
        return 0;
-
-error:
-       set_errno_from_GetLastError();
-       return WIMLIB_ERR_MKDIR;
 }
 
 /* Delete a non-directory file, working around Windows quirks.  */
 static BOOL
 win32_delete_file_wrapper(const wchar_t *path)
 {
-       DWORD attrib;
        DWORD err;
+       DWORD attrib;
 
        if (DeleteFile(path))
                return TRUE;
 
        err = GetLastError();
        attrib = GetFileAttributes(path);
-       if (attrib & FILE_ATTRIBUTE_READONLY) {
+       if ((attrib != INVALID_FILE_ATTRIBUTES) &&
+           (attrib & FILE_ATTRIBUTE_READONLY))
+       {
                /* Try again with FILE_ATTRIBUTE_READONLY cleared.  */
                attrib &= ~FILE_ATTRIBUTE_READONLY;
                if (SetFileAttributes(path, attrib)) {
@@ -181,6 +144,60 @@ win32_delete_file_wrapper(const wchar_t *path)
        return FALSE;
 }
 
+
+/* Create a normal file, overwriting one already present.  */
+static int
+win32_create_file(const wchar_t *path, struct apply_ctx *ctx, u64 *cookie_ret)
+{
+       HANDLE h;
+
+       /* Notes:
+        *
+        * WRITE_OWNER and WRITE_DAC privileges are required for some reason,
+        * even through we're creating a new file.
+        *
+        * FILE_FLAG_OPEN_REPARSE_POINT is required to prevent an existing
+        * reparse point from redirecting the creation of the new file
+        * (potentially to an arbitrary location).
+        *
+        * CREATE_ALWAYS could be used instead of CREATE_NEW.  However, there
+        * are quirks that would need to be handled (e.g. having to set
+        * FILE_ATTRIBUTE_HIDDEN and/or FILE_ATTRIBUTE_SYSTEM if the existing
+        * file had them specified, and/or having to clear
+        * FILE_ATTRIBUTE_READONLY on the existing file).  It's simpler to just
+        * call win32_delete_file_wrapper() to delete the existing file in such
+        * a way that already handles the FILE_ATTRIBUTE_READONLY quirk.
+        */
+retry:
+       h = CreateFile(path, WRITE_OWNER | WRITE_DAC, 0, NULL, CREATE_NEW,
+                      FILE_FLAG_BACKUP_SEMANTICS |
+                               FILE_FLAG_OPEN_REPARSE_POINT, NULL);
+       if (h == INVALID_HANDLE_VALUE) {
+               DWORD err = GetLastError();
+
+               if (err == ERROR_FILE_EXISTS && win32_delete_file_wrapper(path))
+                       goto retry;
+               set_errno_from_win32_error(err);
+               return WIMLIB_ERR_OPEN;
+       }
+       CloseHandle(h);
+       return 0;
+}
+
+static int
+win32_create_directory(const wchar_t *path, struct apply_ctx *ctx,
+                      u64 *cookie_ret)
+{
+       if (!CreateDirectory(path, NULL))
+               if (GetLastError() != ERROR_ALREADY_EXISTS)
+                       goto error;
+       return 0;
+
+error:
+       set_errno_from_GetLastError();
+       return WIMLIB_ERR_MKDIR;
+}
+
 static int
 win32_create_hardlink(const wchar_t *oldpath, const wchar_t *newpath,
                      struct apply_ctx *ctx)
@@ -282,6 +299,16 @@ win32_extract_unnamed_stream(file_spec_t file,
                             struct wim_lookup_table_entry *lte,
                             struct apply_ctx *ctx)
 {
+       if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT
+           && lte
+           && lte->resource_location == RESOURCE_IN_WIM
+           && lte->rspec->wim == ctx->wim)
+       {
+               return wimboot_set_pointer(file.path,
+                                          ctx_get_data_source_id(ctx),
+                                          lte->hash);
+       }
+
        return win32_extract_stream(file.path, NULL, 0, lte, ctx);
 }