X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fwimboot.c;h=47c4d3a4de40f23154ec7154cfda71ffd5152024;hp=5e5ae7bc6731dc48bc5a0b31be896dc79adb562f;hb=HEAD;hpb=3df2989aaef4c627f4fea630859ae9f72e9c307e diff --git a/src/wimboot.c b/src/wimboot.c index 5e5ae7bc..115a5699 100644 --- a/src/wimboot.c +++ b/src/wimboot.c @@ -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 @@ -24,10 +24,10 @@ * 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" @@ -37,6 +37,7 @@ #include "wimlib/assert.h" #include "wimlib/blob_table.h" +#include "wimlib/inode.h" #include "wimlib/error.h" #include "wimlib/util.h" #include "wimlib/wimboot.h" @@ -186,8 +187,8 @@ query_partition_and_disk_info(const wchar_t *path, } if (part_info->PartitionStyle == PARTITION_STYLE_GPT) { - BUILD_BUG_ON(sizeof(part_info->Gpt.PartitionId) != - sizeof(drive_info->Gpt.DiskId)); + STATIC_ASSERT(sizeof(part_info->Gpt.PartitionId) == + sizeof(drive_info->Gpt.DiskId)); if (!memcmp(&part_info->Gpt.PartitionId, &drive_info->Gpt.DiskId, sizeof(drive_info->Gpt.DiskId))) @@ -217,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. * @@ -262,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; } @@ -365,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], @@ -394,14 +370,14 @@ fill_in_wimoverlay_dat(u8 *buf, new_entry_1->entry_2_length = new_entry_2_size; new_entry_1->wim_type = WIM_BOOT_NOT_OS_WIM; new_entry_1->wim_index = image; - BUILD_BUG_ON(sizeof(new_entry_1->guid) != GUID_SIZE); + STATIC_ASSERT(sizeof(new_entry_1->guid) == GUID_SIZE); copy_guid(new_entry_1->guid, wim_guid); p += sizeof(struct WimOverlay_dat_entry_1); /* 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); @@ -437,21 +413,21 @@ fill_in_wimoverlay_dat(u8 *buf, new_entry_2->disk.mbr.padding[1] = 0x00000000; new_entry_2->disk.mbr.padding[2] = 0x00000000; } else { - BUILD_BUG_ON(sizeof(new_entry_2->partition.gpt.part_unique_guid) != - sizeof(part_info->Gpt.PartitionId)); + STATIC_ASSERT(sizeof(new_entry_2->partition.gpt.part_unique_guid) == + sizeof(part_info->Gpt.PartitionId)); memcpy(new_entry_2->partition.gpt.part_unique_guid, &part_info->Gpt.PartitionId, sizeof(part_info->Gpt.PartitionId)); new_entry_2->partition_table_type = WIMOVERLAY_PARTITION_TYPE_GPT; - BUILD_BUG_ON(sizeof(new_entry_2->disk.gpt.disk_guid) != - sizeof(disk_info->Gpt.DiskId)); + STATIC_ASSERT(sizeof(new_entry_2->disk.gpt.disk_guid) == + sizeof(disk_info->Gpt.DiskId)); memcpy(new_entry_2->disk.gpt.disk_guid, &disk_info->Gpt.DiskId, sizeof(disk_info->Gpt.DiskId)); - BUILD_BUG_ON(sizeof(new_entry_2->disk.gpt.disk_guid) != - sizeof(new_entry_2->partition.gpt.part_unique_guid)); + STATIC_ASSERT(sizeof(new_entry_2->disk.gpt.disk_guid) == + sizeof(new_entry_2->partition.gpt.part_unique_guid)); } new_entry_2->unknown_0x58[0] = 0x00000000; new_entry_2->unknown_0x58[1] = 0x00000000; @@ -510,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)); @@ -535,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. * @@ -585,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; @@ -636,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) { @@ -651,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) @@ -702,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", @@ -797,10 +790,10 @@ update_wimoverlay_manually(const wchar_t *drive, const wchar_t *wim_path, wchar_t path_backup[] = L"A:\\System Volume Information\\WimOverlay.backup"; wchar_t path_wimlib_backup[] = L"A:\\System Volume Information\\WimOverlay.wimlib_backup"; wchar_t path_new[] = L"A:\\System Volume Information\\WimOverlay.wimlib_new"; - void *old_contents; - void *new_contents; - u32 new_contents_size; - u64 new_data_source_id; + void *old_contents = NULL; + void *new_contents = NULL; + u32 new_contents_size = 0; + u64 new_data_source_id = -1; int ret; wimlib_assert(drive[0] != L'\0' && @@ -865,47 +858,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. * @@ -935,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; @@ -956,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); @@ -1000,7 +950,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; @@ -1031,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); @@ -1083,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 */ @@ -1130,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; - BUILD_BUG_ON(sizeof(in) != 8 + - sizeof(struct wof_external_info) + - sizeof(struct wim_provider_rpdata)); + STATIC_ASSERT(sizeof(in) == 8 + + sizeof(WOF_EXTERNAL_INFO) + + sizeof(struct wim_provider_rpdata)); - in.hdr.rptag = WIMLIB_REPARSE_TAG_WOF; + 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; @@ -1178,4 +1120,4 @@ wimboot_set_pointer(HANDLE h, return true; } -#endif /* __WIN32__ */ +#endif /* _WIN32 */