]> wimlib.net Git - wimlib/blobdiff - src/wimboot.c
mount_image.c: add fallback definitions of RENAME_* constants
[wimlib] / src / wimboot.c
index e8fecaf986a31e6a59260385e8aba97f3f8b62c1..115a56996e39759832ae62b3265f9a2bacfee725 100644 (file)
@@ -3,15 +3,15 @@
  *
  * Support for creating WIMBoot pointer files.
  *
- * See http://technet.microsoft.com/en-us/library/dn594399.aspx for general
- * information about WIMBoot.
+ * For general information about WIMBoot, see
+ * https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-8.1-and-8/dn594399(v=win.10)
  *
  * Note that WIMBoot pointer files are actually implemented on top of the
- * Windows Overlay File System Filter (WOF).  See wof.h for more info.
+ * Windows Overlay Filesystem filter (WOF).  See wof.h for more info.
  */
 
 /*
- * Copyright (C) 2014 Eric Biggers
+ * Copyright (C) 2014-2021 Eric Biggers
  *
  * This file is free software; you can redistribute it and/or modify it under
  * the terms of the GNU Lesser General Public License as published by the Free
  * details.
  *
  * You should have received a copy of the GNU Lesser General Public License
- * along with this file; if not, see http://www.gnu.org/licenses/.
+ * along with this file; if not, see https://www.gnu.org/licenses/.
  */
 
-#ifdef __WIN32__
+#ifdef _WIN32
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
@@ -218,30 +218,6 @@ out:
        return ret;
 }
 
-/*
- * Allocate a new WIM data source ID.
- *
- * @old_hdr
- *     Previous WimOverlay.dat contents, or NULL if file did not exist.
- *
- * Returns the new data source ID.
- */
-static u64
-alloc_new_data_source_id(const struct WimOverlay_dat_header *old_hdr)
-{
-       if (!old_hdr)
-               return 0;
-
-       for (u64 id = 0; ; id++) {
-               for (u32 i = 0; i < old_hdr->num_entries_1; i++)
-                       if (id == old_hdr->entry_1s[i].data_source_id)
-                               goto next;
-               return id;
-       next:
-               ;
-       }
-}
-
 /*
  * Calculate the size of WimOverlay.dat with one entry added.
  *
@@ -263,7 +239,7 @@ calculate_wimoverlay_dat_size(const struct WimOverlay_dat_header *old_hdr,
 
        size_64 = sizeof(struct WimOverlay_dat_header);
        if (old_hdr) {
-               for (u32 i = 0; i < old_hdr->num_entries_1; i++) {
+               for (u32 i = 0; i < old_hdr->num_entries; i++) {
                        size_64 += sizeof(struct WimOverlay_dat_entry_1);
                        size_64 += old_hdr->entry_1s[i].entry_2_length;
                }
@@ -366,17 +342,16 @@ fill_in_wimoverlay_dat(u8 *buf,
        new_hdr->magic = WIMOVERLAY_DAT_MAGIC;
        new_hdr->wim_provider_version = WIM_PROVIDER_CURRENT_VERSION;
        new_hdr->unknown_0x08 = 0x00000028;
-       new_hdr->num_entries_1 = (old_hdr ? old_hdr->num_entries_1 : 0) + 1;
-       new_hdr->num_entries_2 = (old_hdr ? old_hdr->num_entries_2 : 0) + 1;
-       new_hdr->unknown_0x14 = 0x00000000;
+       new_hdr->num_entries = (old_hdr ? old_hdr->num_entries : 0) + 1;
+       new_hdr->next_data_source_id = (old_hdr ? old_hdr->next_data_source_id : 0) + 1;
 
        p += sizeof(struct WimOverlay_dat_header);
 
        /* Copy WIM-specific information for old entries  */
        entry_2_offset = sizeof(struct WimOverlay_dat_header) +
-                       (new_hdr->num_entries_1 * sizeof(struct WimOverlay_dat_entry_1));
+                       (new_hdr->num_entries * sizeof(struct WimOverlay_dat_entry_1));
        if (old_hdr) {
-               for (u32 i = 0; i < old_hdr->num_entries_1; i++) {
+               for (u32 i = 0; i < old_hdr->num_entries; i++) {
                        new_entry_1 = (struct WimOverlay_dat_entry_1 *)p;
 
                        p = mempcpy(p, &old_hdr->entry_1s[i],
@@ -402,7 +377,7 @@ fill_in_wimoverlay_dat(u8 *buf,
 
        /* Copy WIM location information for old entries  */
        if (old_hdr) {
-               for (u32 i = 0; i < old_hdr->num_entries_1; i++) {
+               for (u32 i = 0; i < old_hdr->num_entries; i++) {
                        wimlib_assert(new_hdr->entry_1s[i].entry_2_offset == p - buf);
                        wimlib_assert(old_hdr->entry_1s[i].entry_2_length ==
                                      new_hdr->entry_1s[i].entry_2_length);
@@ -511,7 +486,7 @@ prepare_wimoverlay_dat(const struct WimOverlay_dat_header *old_hdr,
        if (ret)
                return ret;
 
-       new_data_source_id = alloc_new_data_source_id(old_hdr);
+       new_data_source_id = old_hdr ? old_hdr->next_data_source_id : 0;
 
        new_entry_2_size = sizeof(struct WimOverlay_dat_entry_2) +
                                ((wcslen(wim_path) - 2 + 1) * sizeof(wchar_t));
@@ -536,6 +511,21 @@ prepare_wimoverlay_dat(const struct WimOverlay_dat_header *old_hdr,
        return 0;
 }
 
+static bool
+valid_wim_filename(const struct WimOverlay_dat_entry_2 *entry, size_t name_len)
+{
+       size_t i;
+
+       if (name_len % sizeof(wchar_t))
+               return false;
+       name_len /= sizeof(wchar_t);
+       if (name_len < 2)
+               return false;
+       for (i = 0; i < name_len && entry->wim_file_name[i] != 0; i++)
+               ;
+       return i == name_len - 1;
+}
+
 /*
  * Reads and validates a WimOverlay.dat file.
  *
@@ -586,7 +576,7 @@ retry:
 
                        status = (*func_RtlCreateSystemVolumeInformationFolder)(&str);
 
-                       err2 = (*func_RtlNtStatusToDosError)(status);
+                       err2 = RtlNtStatusToDosError(status);
                        if (err2 == ERROR_SUCCESS) {
                                if (!already_retried) {
                                        already_retried = true;
@@ -637,9 +627,7 @@ retry:
 
        if (hdr->magic != WIMOVERLAY_DAT_MAGIC ||
            hdr->wim_provider_version != WIM_PROVIDER_CURRENT_VERSION ||
-           hdr->unknown_0x08 != 0x00000028 ||
-           (hdr->num_entries_1 != hdr->num_entries_2) ||
-           hdr->unknown_0x14 != 0x00000000)
+           hdr->unknown_0x08 != 0x00000028)
        {
                ERROR("\"%ls\": Header contains unexpected data:", path);
                if (wimlib_print_errors) {
@@ -652,23 +640,33 @@ retry:
                goto out_free_contents;
        }
 
-       if ((u64)hdr->num_entries_1 * sizeof(struct WimOverlay_dat_entry_1) >
+       if ((u64)hdr->num_entries * sizeof(struct WimOverlay_dat_entry_1) >
            info.nFileSizeLow - sizeof(struct WimOverlay_dat_header))
        {
                ERROR("\"%ls\": File is unexpectedly small "
                      "(only %"PRIu32" bytes, but has %"PRIu32" entries)",
-                     path, (u32)info.nFileSizeLow, hdr->num_entries_1);
+                     path, (u32)info.nFileSizeLow, hdr->num_entries);
                ret = WIMLIB_ERR_UNSUPPORTED;
                goto out_free_contents;
        }
 
-       for (u32 i = 0; i < hdr->num_entries_1; i++) {
+       for (u32 i = 0; i < hdr->num_entries; i++) {
                const struct WimOverlay_dat_entry_1 *entry_1;
                const struct WimOverlay_dat_entry_2 *entry_2;
                u32 wim_file_name_length;
 
                entry_1 = &hdr->entry_1s[i];
 
+               if (entry_1->data_source_id >= hdr->next_data_source_id) {
+                       ERROR("\"%ls\": value of next_data_source_id "
+                             "(0x%016"PRIx64") is unexpected, since entry "
+                             "%"PRIu32" has data source ID 0x%016"PRIx64,
+                             path, hdr->next_data_source_id,
+                             i, entry_1->data_source_id);
+                       ret = WIMLIB_ERR_UNSUPPORTED;
+                       goto out_free_contents;
+               }
+
                if (((u64)entry_1->entry_2_offset +
                     (u64)entry_1->entry_2_length) >
                    info.nFileSizeLow)
@@ -703,13 +701,7 @@ retry:
 
                wim_file_name_length = entry_1->entry_2_length -
                                        sizeof(struct WimOverlay_dat_entry_2);
-               if ((wim_file_name_length < 2 * sizeof(wchar_t)) ||
-                   (wim_file_name_length % sizeof(wchar_t) != 0) ||
-                   (wmemchr(entry_2->wim_file_name, L'\0',
-                            wim_file_name_length / sizeof(wchar_t))
-                    != &entry_2->wim_file_name[wim_file_name_length /
-                                               sizeof(wchar_t) - 1]))
-               {
+               if (!valid_wim_filename(entry_2, wim_file_name_length)) {
                        ERROR("\"%ls\": entry %"PRIu32" (2) "
                              "(data source ID 0x%016"PRIx64") "
                              "has invalid WIM file name",
@@ -895,8 +887,9 @@ wimboot_alloc_data_source_id(const wchar_t *wim_path,
        size_t wim_file_name_length;
        void *in;
        size_t insize;
-       struct wof_external_info *wof_info;
-       struct wim_provider_add_overlay_input *wim_info;
+       WOF_EXTERNAL_INFO *wof_info;
+       WIM_PROVIDER_ADD_OVERLAY_INPUT *wim_info;
+       wchar_t *WimFileName;
        HANDLE h;
        u64 data_source_id;
        DWORD bytes_returned;
@@ -916,28 +909,25 @@ wimboot_alloc_data_source_id(const wchar_t *wim_path,
        wim_file_name_length = sizeof(wchar_t) *
                               (wim_path_nchars + prefix_nchars);
 
-       insize = sizeof(struct wof_external_info) +
-                sizeof(struct wim_provider_add_overlay_input) +
-                wim_file_name_length;
-
-       in = MALLOC(insize);
+       insize = sizeof(*wof_info) + sizeof(*wim_info) + wim_file_name_length;
+       in = CALLOC(1, insize);
        if (!in) {
                ret = WIMLIB_ERR_NOMEM;
                goto out;
        }
 
-       wof_info = (struct wof_external_info *)in;
-       wof_info->version = WOF_CURRENT_VERSION;
-       wof_info->provider = WOF_PROVIDER_WIM;
+       wof_info = (WOF_EXTERNAL_INFO *)in;
+       wof_info->Version = WOF_CURRENT_VERSION;
+       wof_info->Provider = WOF_PROVIDER_WIM;
 
-       wim_info = (struct wim_provider_add_overlay_input *)(wof_info + 1);
-       wim_info->wim_type = WIM_BOOT_NOT_OS_WIM;
-       wim_info->wim_index = image;
-       wim_info->wim_file_name_offset = offsetof(struct wim_provider_add_overlay_input,
-                                                 wim_file_name);
-       wim_info->wim_file_name_length = wim_file_name_length;
-       wmemcpy(&wim_info->wim_file_name[0], prefix, prefix_nchars);
-       wmemcpy(&wim_info->wim_file_name[prefix_nchars], wim_path, wim_path_nchars);
+       wim_info = (WIM_PROVIDER_ADD_OVERLAY_INPUT *)(wof_info + 1);
+       wim_info->WimType = WIM_BOOT_NOT_OS_WIM;
+       wim_info->WimIndex = image;
+       wim_info->WimFileNameOffset = sizeof(*wim_info);
+       wim_info->WimFileNameLength = wim_file_name_length;
+       WimFileName = (wchar_t *)(wim_info + 1);
+       wmemcpy(WimFileName, prefix, prefix_nchars);
+       wmemcpy(&WimFileName[prefix_nchars], wim_path, wim_path_nchars);
 
 retry_ioctl:
        h = open_file(drive_path, GENERIC_WRITE);
@@ -991,15 +981,7 @@ out_free_in:
        FREE(in);
 out:
        if (ret == WIMLIB_ERR_UNSUPPORTED) {
-       #if 0
-               WARNING(
-               "The version of Windows you are running does not appear to support\n"
-               "        the Windows Overlay File System Filter Driver.  This is normally\n"
-               "        available on Windows 8.1 Update 1 or later.  Therefore, wimlib\n"
-               "        will attempt to update the WimOverlay.dat file directly.\n");
-       #else
                WARNING("WOF driver is not available; updating WimOverlay.dat directly.");
-       #endif
                ret = update_wimoverlay_manually(drive_path + 4, wim_path,
                                                 wim_guid, image,
                                                 data_source_id_ret);
@@ -1043,20 +1025,20 @@ wimboot_set_pointer(HANDLE h,
                 * using FSCTL_SET_EXTERNAL_BACKING.  */
                unsigned int max_retries = 4;
                struct {
-                       struct wof_external_info wof_info;
-                       struct wim_provider_external_info wim_info;
+                       WOF_EXTERNAL_INFO wof_info;
+                       WIM_PROVIDER_EXTERNAL_INFO wim_info;
                } in;
 
        retry:
                memset(&in, 0, sizeof(in));
 
-               in.wof_info.version = WOF_CURRENT_VERSION;
-               in.wof_info.provider = WOF_PROVIDER_WIM;
+               in.wof_info.Version = WOF_CURRENT_VERSION;
+               in.wof_info.Provider = WOF_PROVIDER_WIM;
 
-               in.wim_info.version = WIM_PROVIDER_CURRENT_VERSION;
-               in.wim_info.flags = 0;
-               in.wim_info.data_source_id = data_source_id;
-               copy_hash(in.wim_info.unnamed_data_stream_hash, blob->hash);
+               in.wim_info.Version = WIM_PROVIDER_CURRENT_VERSION;
+               in.wim_info.Flags = 0;
+               in.wim_info.DataSourceId.QuadPart = data_source_id;
+               copy_hash(in.wim_info.ResourceHash, blob->hash);
 
                /* blob_table_hash is not necessary  */
 
@@ -1090,20 +1072,20 @@ wimboot_set_pointer(HANDLE h,
                                le16 rpdatalen;
                                le16 rpreserved;
                        } hdr;
-                       struct wof_external_info wof_info;
+                       WOF_EXTERNAL_INFO wof_info;
                        struct wim_provider_rpdata wim_info;
                } in;
 
                STATIC_ASSERT(sizeof(in) == 8 +
-                             sizeof(struct wof_external_info) +
+                             sizeof(WOF_EXTERNAL_INFO) +
                              sizeof(struct wim_provider_rpdata));
 
                in.hdr.rptag = WIM_IO_REPARSE_TAG_WOF;
                in.hdr.rpdatalen = sizeof(in) - sizeof(in.hdr);
                in.hdr.rpreserved = 0;
 
-               in.wof_info.version = WOF_CURRENT_VERSION;
-               in.wof_info.provider = WOF_PROVIDER_WIM;
+               in.wof_info.Version = WOF_CURRENT_VERSION;
+               in.wof_info.Provider = WOF_PROVIDER_WIM;
 
                in.wim_info.version = 2;
                in.wim_info.flags = 0;
@@ -1138,4 +1120,4 @@ wimboot_set_pointer(HANDLE h,
        return true;
 }
 
-#endif /* __WIN32__ */
+#endif /* _WIN32 */