]> wimlib.net Git - wimlib/blobdiff - src/wimboot.c
Capitalize "Windows Overlay Filesystem" consistently
[wimlib] / src / wimboot.c
index 3dd6da1eded2135c0db75660292a75290d13cd61..16ea1c6da0ebaba7f639b3b728876562291b1068 100644 (file)
@@ -7,50 +7,48 @@
  * information about WIMBoot.
  *
  * 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-2016 Eric Biggers
  *
- * This file is part of wimlib, a library for working with WIM files.
+ * 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
+ * Software Foundation; either version 3 of the License, or (at your option) any
+ * later version.
  *
- * wimlib is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  * details.
  *
- * You should have received a copy of the GNU General Public License
- * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ * 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/.
  */
 
+#ifdef __WIN32__
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
 #endif
 
-#ifdef __WIN32__
-
 #include "wimlib/win32_common.h"
-#include "wimlib/win32.h"
+
 #include "wimlib/assert.h"
+#include "wimlib/blob_table.h"
+#include "wimlib/inode.h"
 #include "wimlib/error.h"
-#include "wimlib/lookup_table.h"
 #include "wimlib/util.h"
 #include "wimlib/wimboot.h"
+#include "wimlib/win32.h"
 #include "wimlib/wof.h"
 
 static HANDLE
 open_file(const wchar_t *device_name, DWORD desiredAccess)
 {
        return CreateFile(device_name, desiredAccess,
-                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                         NULL, OPEN_EXISTING,
+                         FILE_SHARE_VALID_FLAGS, NULL, OPEN_EXISTING,
                          FILE_FLAG_BACKUP_SEMANTICS, NULL);
 }
 
@@ -79,19 +77,17 @@ query_device(HANDLE h, DWORD code, void *out, DWORD out_size)
  */
 static int
 query_partition_and_disk_info(const wchar_t *path,
-                             PARTITION_INFORMATION_EX *part_info_ret,
+                             PARTITION_INFORMATION_EX *part_info,
                              DRIVE_LAYOUT_INFORMATION_EX *drive_info_ret)
 {
-       HANDLE h;
        wchar_t vol_name[] = L"\\\\.\\X:";
        wchar_t disk_name[] = L"\\\\?\\PhysicalDriveXXXXXXXXXX";
-
-       PARTITION_INFORMATION_EX part_info;
-       size_t extents_size = sizeof(VOLUME_DISK_EXTENTS) + 4 * sizeof(DISK_EXTENT);
-       VOLUME_DISK_EXTENTS *extents = alloca(extents_size);
-       size_t drive_info_size = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
-                                       8 * sizeof(PARTITION_INFORMATION_EX);
-       DRIVE_LAYOUT_INFORMATION_EX *drive_info = alloca(drive_info_size);
+       HANDLE h = INVALID_HANDLE_VALUE;
+       VOLUME_DISK_EXTENTS *extents = NULL;
+       size_t extents_size;
+       DRIVE_LAYOUT_INFORMATION_EX *drive_info = NULL;
+       size_t drive_info_size;
+       int ret;
 
        wimlib_assert(path[0] != L'\0' && path[1] == L':');
 
@@ -99,36 +95,52 @@ query_partition_and_disk_info(const wchar_t *path,
 
        h = open_file(vol_name, GENERIC_READ);
        if (h == INVALID_HANDLE_VALUE) {
-               set_errno_from_GetLastError();
-               ERROR_WITH_ERRNO("\"%ls\": Can't open volume device", vol_name);
-               return WIMLIB_ERR_OPEN;
+               win32_error(GetLastError(), L"\"%ls\": Can't open volume device",
+                           vol_name);
+               ret = WIMLIB_ERR_OPEN;
+               goto out;
        }
 
        if (!query_device(h, IOCTL_DISK_GET_PARTITION_INFO_EX,
-                         &part_info, sizeof(part_info)))
+                         part_info, sizeof(PARTITION_INFORMATION_EX)))
        {
-               ERROR("\"%ls\": Can't get partition info (err=0x%08"PRIx32")",
-                     vol_name, (u32)GetLastError());
-               CloseHandle(h);
-               return WIMLIB_ERR_READ;
+               win32_error(GetLastError(),
+                           L"\"%ls\": Can't get partition info", vol_name);
+               ret = WIMLIB_ERR_READ;
+               goto out;
        }
 
-       if (!query_device(h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
-                         extents, extents_size))
-       {
-               ERROR("\"%ls\": Can't get volume extent info (err=0x%08"PRIx32")",
-                     vol_name, (u32)GetLastError());
-               CloseHandle(h);
-               return WIMLIB_ERR_READ;
+       extents_size = sizeof(VOLUME_DISK_EXTENTS);
+       for (;;) {
+               extents_size += 4 * sizeof(DISK_EXTENT);
+               extents = MALLOC(extents_size);
+               if (!extents) {
+                       ret = WIMLIB_ERR_NOMEM;
+                       goto out;
+               }
+
+               if (query_device(h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
+                                extents, extents_size))
+                       break;
+               if (GetLastError() != ERROR_MORE_DATA) {
+                       win32_error(GetLastError(),
+                                   L"\"%ls\": Can't get volume extent info",
+                                   vol_name);
+                       ret = WIMLIB_ERR_READ;
+                       goto out;
+               }
+               FREE(extents);
        }
 
        CloseHandle(h);
+       h = INVALID_HANDLE_VALUE;
 
        if (extents->NumberOfDiskExtents != 1) {
                ERROR("\"%ls\": This volume has %"PRIu32" disk extents, "
                      "but this code is untested for more than 1",
                      vol_name, (u32)extents->NumberOfDiskExtents);
-               return WIMLIB_ERR_UNSUPPORTED;
+               ret = WIMLIB_ERR_UNSUPPORTED;
+               goto out;
        }
 
        wsprintf(wcschr(disk_name, L'X'), L"%"PRIu32,
@@ -136,76 +148,74 @@ query_partition_and_disk_info(const wchar_t *path,
 
        h = open_file(disk_name, GENERIC_READ);
        if (h == INVALID_HANDLE_VALUE) {
-               set_errno_from_GetLastError();
-               ERROR_WITH_ERRNO("\"%ls\": Can't open disk device", disk_name);
-               return WIMLIB_ERR_OPEN;
+               win32_error(GetLastError(),
+                           L"\"%ls\": Can't open disk device", disk_name);
+               ret = WIMLIB_ERR_OPEN;
+               goto out;
        }
 
-       if (!query_device(h, IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
-                         drive_info, drive_info_size))
-       {
-               ERROR("\"%ls\": Can't get disk info (err=0x%08"PRIx32")",
-                     disk_name, (u32)GetLastError());
-               CloseHandle(h);
-               return WIMLIB_ERR_READ;
+       drive_info_size = sizeof(DRIVE_LAYOUT_INFORMATION_EX);
+       for (;;) {
+               drive_info_size += 4 * sizeof(PARTITION_INFORMATION_EX);
+               drive_info = MALLOC(drive_info_size);
+               if (!drive_info) {
+                       ret = WIMLIB_ERR_NOMEM;
+                       goto out;
+               }
+
+               if (query_device(h, IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
+                                drive_info, drive_info_size))
+                       break;
+               if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+                       win32_error(GetLastError(),
+                                   L"\"%ls\": Can't get disk info", disk_name);
+                       ret = WIMLIB_ERR_READ;
+                       goto out;
+               }
+               FREE(drive_info);
        }
 
+       *drive_info_ret = *drive_info;  /* doesn't include partitions */
        CloseHandle(h);
+       h = INVALID_HANDLE_VALUE;
 
-       if (drive_info->PartitionStyle != part_info.PartitionStyle) {
+       if (drive_info->PartitionStyle != part_info->PartitionStyle) {
                ERROR("\"%ls\", \"%ls\": Inconsistent partition table type!",
                      vol_name, disk_name);
-               return WIMLIB_ERR_UNSUPPORTED;
+               ret = WIMLIB_ERR_UNSUPPORTED;
+               goto out;
        }
 
-       if (part_info.PartitionStyle == PARTITION_STYLE_GPT) {
-               BUILD_BUG_ON(sizeof(part_info.Gpt.PartitionId) !=
-                            sizeof(drive_info->Gpt.DiskId));
-               if (!memcmp(&part_info.Gpt.PartitionId,
+       if (part_info->PartitionStyle == PARTITION_STYLE_GPT) {
+               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)))
                {
                        ERROR("\"%ls\", \"%ls\": Partition GUID is the "
                              "same as the disk GUID???", vol_name, disk_name);
-                       return WIMLIB_ERR_UNSUPPORTED;
+                       ret = WIMLIB_ERR_UNSUPPORTED;
+                       goto out;
                }
        }
 
-       if (part_info.PartitionStyle != PARTITION_STYLE_MBR &&
-           part_info.PartitionStyle != PARTITION_STYLE_GPT)
+       if (part_info->PartitionStyle != PARTITION_STYLE_MBR &&
+           part_info->PartitionStyle != PARTITION_STYLE_GPT)
        {
                ERROR("\"%ls\": Unknown partition style 0x%08"PRIx32,
-                     vol_name, (u32)part_info.PartitionStyle);
-               return WIMLIB_ERR_UNSUPPORTED;
+                     vol_name, (u32)part_info->PartitionStyle);
+               ret = WIMLIB_ERR_UNSUPPORTED;
+               goto out;
        }
 
-       *part_info_ret = part_info;
-       *drive_info_ret = *drive_info;
-       return 0;
-}
-
-/*
- * 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:
-               ;
-       }
+       ret = 0;
+out:
+       FREE(extents);
+       FREE(drive_info);
+       if (h != INVALID_HANDLE_VALUE)
+               CloseHandle(h);
+       return ret;
 }
 
 /*
@@ -229,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;
                }
@@ -259,23 +269,24 @@ write_wimoverlay_dat(const wchar_t *path, const void *contents, u32 size)
        h = CreateFile(path, GENERIC_WRITE, 0, NULL,
                       CREATE_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL);
        if (h == INVALID_HANDLE_VALUE) {
-               set_errno_from_GetLastError();
-               ERROR_WITH_ERRNO("\"%ls\": Can't open file for writing", path);
+               win32_error(GetLastError(),
+                           L"\"%ls\": Can't open file for writing", path);
                return WIMLIB_ERR_OPEN;
        }
 
+       SetLastError(0);
        if (!WriteFile(h, contents, size, &bytes_written, NULL) ||
            bytes_written != size)
        {
-               set_errno_from_GetLastError();
-               ERROR_WITH_ERRNO("\"%ls\": Can't write file", path);
+               win32_error(GetLastError(),
+                           L"\"%ls\": Can't write file", path);
                CloseHandle(h);
                return WIMLIB_ERR_WRITE;
        }
 
        if (!CloseHandle(h)) {
-               set_errno_from_GetLastError();
-               ERROR_WITH_ERRNO("\"%ls\": Can't close handle", path);
+               win32_error(GetLastError(),
+                           L"\"%ls\": Can't close handle", path);
                return WIMLIB_ERR_WRITE;
        }
 
@@ -312,7 +323,7 @@ static u8 *
 fill_in_wimoverlay_dat(u8 *buf,
                       const struct WimOverlay_dat_header *old_hdr,
                       const wchar_t *wim_path,
-                      const u8 wim_guid[WIM_GUID_LEN],
+                      const u8 wim_guid[GUID_SIZE],
                       int image,
                       u64 new_data_source_id,
                       const PARTITION_INFORMATION_EX *part_info,
@@ -331,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],
@@ -360,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) != WIM_GUID_LEN);
-       memcpy(new_entry_1->guid, wim_guid, WIM_GUID_LEN);
+       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);
@@ -403,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;
@@ -457,7 +467,7 @@ fill_in_wimoverlay_dat(u8 *buf,
 static int
 prepare_wimoverlay_dat(const struct WimOverlay_dat_header *old_hdr,
                       const wchar_t *wim_path,
-                      const u8 wim_guid[WIM_GUID_LEN],
+                      const u8 wim_guid[GUID_SIZE],
                       int image,
                       void **new_contents_ret,
                       u32 *new_contents_size_ret,
@@ -476,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));
@@ -551,7 +561,7 @@ retry:
 
                        status = (*func_RtlCreateSystemVolumeInformationFolder)(&str);
 
-                       err2 = (*func_RtlNtStatusToDosError)(status);
+                       err2 = RtlNtStatusToDosError(status);
                        if (err2 == ERROR_SUCCESS) {
                                if (!already_retried) {
                                        already_retried = true;
@@ -561,13 +571,11 @@ retry:
                                err = err2;
                        }
                }
-               set_errno_from_win32_error(err);
-               ERROR_WITH_ERRNO("\"%ls\": Can't open for reading", path);
+               win32_error(err, L"\"%ls\": Can't open for reading", path);
                return WIMLIB_ERR_OPEN;
        }
        if (!GetFileInformationByHandle(h, &info)) {
-               set_errno_from_GetLastError();
-               ERROR_WITH_ERRNO("\"%ls\": Can't query metadata", path);
+               win32_error(GetLastError(), L"\"%ls\": Can't query metadata", path);
                CloseHandle(h);
                return WIMLIB_ERR_STAT;
        }
@@ -581,11 +589,11 @@ retry:
                return WIMLIB_ERR_NOMEM;
        }
 
+       SetLastError(0);
        if (!ReadFile(h, contents, info.nFileSizeLow, &bytes_read, NULL) ||
            bytes_read != info.nFileSizeLow)
        {
-               set_errno_from_GetLastError();
-               ERROR_WITH_ERRNO("\"%ls\": Can't read data", path);
+               win32_error(GetLastError(), L"\"%ls\": Can't read data", path);
                CloseHandle(h);
                ret = WIMLIB_ERR_READ;
                goto out_free_contents;
@@ -604,38 +612,46 @@ 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) {
                        print_byte_field((const u8 *)hdr,
                                         sizeof(struct WimOverlay_dat_header),
-                                        stderr);
-                       fputc('\n', stderr);
+                                        wimlib_error_file);
+                       fputc('\n', wimlib_error_file);
                }
                ret = WIMLIB_ERR_UNSUPPORTED;
                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)
@@ -683,8 +699,9 @@ retry:
                              path, i, entry_1->data_source_id);
                        if (wimlib_print_errors) {
                                print_byte_field((const u8 *)entry_2->wim_file_name,
-                                                wim_file_name_length, stderr);
-                               fputc('\n', stderr);
+                                                wim_file_name_length,
+                                                wimlib_error_file);
+                               fputc('\n', wimlib_error_file);
                        }
                        ret = WIMLIB_ERR_UNSUPPORTED;
                        goto out_free_contents;
@@ -721,8 +738,8 @@ retry:
                        if (wimlib_print_errors) {
                                print_byte_field((const u8 *)entry_2,
                                                 entry_1->entry_2_length,
-                                                stderr);
-                               fputc('\n', stderr);
+                                                wimlib_error_file);
+                               fputc('\n', wimlib_error_file);
                        }
                        ret = WIMLIB_ERR_UNSUPPORTED;
                        goto out_free_contents;
@@ -757,17 +774,17 @@ out_free_contents:
  */
 static int
 update_wimoverlay_manually(const wchar_t *drive, const wchar_t *wim_path,
-                          const u8 wim_guid[WIM_GUID_LEN],
+                          const u8 wim_guid[GUID_SIZE],
                           int image, u64 *data_source_id_ret)
 {
        wchar_t path_main[] = L"A:\\System Volume Information\\WimOverlay.dat";
        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' &&
@@ -808,6 +825,7 @@ update_wimoverlay_manually(const wchar_t *drive, const wchar_t *wim_path,
                if (ret) {
                        ERROR_WITH_ERRNO("Can't rename \"%ls\" => \"%ls\"",
                                         path_main, path_wimlib_backup);
+                       ret = WIMLIB_ERR_RENAME;
                        goto out_free_new_contents;
                }
        }
@@ -817,6 +835,7 @@ update_wimoverlay_manually(const wchar_t *drive, const wchar_t *wim_path,
        if (ret) {
                ERROR_WITH_ERRNO("Can't rename \"%ls\" => \"%ls\"",
                                 path_new, path_main);
+               ret = WIMLIB_ERR_RENAME;
        }
 out_free_new_contents:
        FREE(new_contents);
@@ -830,67 +849,6 @@ out:
        return ret;
 }
 
-static int
-win32_get_drive_path(const wchar_t *file_path, wchar_t drive_path[7])
-{
-       tchar *file_abspath;
-
-       file_abspath = realpath(file_path, NULL);
-       if (!file_abspath)
-               return WIMLIB_ERR_NOMEM;
-
-       if (file_abspath[0] == L'\0' || file_abspath[1] != L':') {
-               ERROR("\"%ls\": Path format not recognized", file_abspath);
-               FREE(file_abspath);
-               return WIMLIB_ERR_UNSUPPORTED;
-       }
-
-       wsprintf(drive_path, L"\\\\.\\%lc:", file_abspath[0]);
-       FREE(file_abspath);
-       return 0;
-}
-
-/* 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.
  *
@@ -902,7 +860,7 @@ try_to_attach_wof(const wchar_t *drive)
  * @image
  *     Number of the image in the WIM being applied.
  * @target
- *     Path to the target drive.
+ *     Path to the target directory.
  * @data_source_id_ret
  *     On success, an identifier for the backing WIM file will be returned
  *     here.
@@ -911,7 +869,7 @@ try_to_attach_wof(const wchar_t *drive)
  */
 int
 wimboot_alloc_data_source_id(const wchar_t *wim_path,
-                            const u8 wim_guid[WIM_GUID_LEN],
+                            const u8 wim_guid[GUID_SIZE],
                             int image, const wchar_t *target,
                             u64 *data_source_id_ret, bool *wof_running_ret)
 {
@@ -968,8 +926,8 @@ retry_ioctl:
        h = open_file(drive_path, GENERIC_WRITE);
 
        if (h == INVALID_HANDLE_VALUE) {
-               set_errno_from_GetLastError();
-               ERROR_WITH_ERRNO("Failed to open \"%ls\"", drive_path + 4);
+               win32_error(GetLastError(),
+                           L"Failed to open \"%ls\"", drive_path + 4);
                ret = WIMLIB_ERR_OPEN;
                goto out_free_in;
        }
@@ -985,23 +943,20 @@ 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;
                        goto out_close_handle;
                } else {
-                       set_errno_from_win32_error(err);
-                       ERROR_WITH_ERRNO("Failed to add overlay source \"%ls\" "
-                                        "to volume \"%ls\" (err=0x%08"PRIx32")",
-                                        wim_path, drive_path + 4, (u32)err);
+                       win32_error(err, L"Failed to add overlay source \"%ls\" "
+                                   "to volume \"%ls\"", wim_path, drive_path + 4);
                        ret = WIMLIB_ERR_WIMBOOT;
                        goto out_close_handle;
                }
        }
 
        if (bytes_returned != sizeof(data_source_id)) {
-               set_errno_from_win32_error(ERROR_INVALID_DATA);
                ret = WIMLIB_ERR_WIMBOOT;
                ERROR("Unexpected result size when adding "
                      "overlay source \"%ls\" to volume \"%ls\"",
@@ -1019,15 +974,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,62 +990,70 @@ out:
  * This turns it into a reparse point that redirects accesses to it, to the
  * corresponding resource in the WIM archive.
  *
- * @path
- *     Path to extracted file (already created).
- * @lte
- *     Unnamed data stream of the file.
+ * @h
+ *     Open handle to the file, with GENERIC_WRITE access.
+ * @blob
+ *     The blob for the unnamed data stream of the file.
  * @data_source_id
  *     Allocated identifier for the WIM data source on the destination volume.
- * @lookup_table_hash
- *     SHA-1 message digest of the WIM's lookup table.
+ * @blob_table_hash
+ *     SHA-1 message digest of the WIM's blob table.
  * @wof_running
  *     %true if the WOF driver appears to be available and working; %false if
  *     not.
  *
- * Returns 0 on success, or a positive error code on failure.
+ * Returns %true on success, or %false on failure with GetLastError() set.
  */
-int
-wimboot_set_pointer(const wchar_t *path,
-                   const struct wim_lookup_table_entry *lte,
+bool
+wimboot_set_pointer(HANDLE h,
+                   const struct blob_descriptor *blob,
                    u64 data_source_id,
-                   const u8 lookup_table_hash[SHA1_HASH_SIZE],
+                   const u8 blob_table_hash[SHA1_HASH_SIZE],
                    bool wof_running)
 {
-       HANDLE h;
        DWORD bytes_returned;
-       int ret;
-
-
-       /* Open the file  */
-       h = win32_open_existing_file(path, GENERIC_WRITE);
-       if (h == INVALID_HANDLE_VALUE) {
-               set_errno_from_GetLastError();
-               ret = WIMLIB_ERR_OPEN;
-               goto out;
-       }
 
        if (wof_running) {
                /* The WOF driver is running.  We can create the reparse point
                 * using FSCTL_SET_EXTERNAL_BACKING.  */
-
+               unsigned int max_retries = 4;
                struct {
                        struct wof_external_info wof_info;
                        struct 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.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.resource_hash, lte->hash);
+               copy_hash(in.wim_info.unnamed_data_stream_hash, blob->hash);
 
-               /* lookup_table_hash is not necessary  */
+               /* blob_table_hash is not necessary  */
 
                if (!DeviceIoControl(h, FSCTL_SET_EXTERNAL_BACKING,
-                                    &in, sizeof(in), NULL, 0, &bytes_returned, NULL))
-                       goto fail;
+                                    &in, sizeof(in), NULL, 0,
+                                    &bytes_returned, NULL))
+               {
+                       /* Try to track down sporadic errors  */
+                       if (wimlib_print_errors) {
+                               WARNING("FSCTL_SET_EXTERNAL_BACKING failed (err=%u); data was %zu bytes:",
+                                       (u32)GetLastError(), sizeof(in));
+                               print_byte_field((const u8 *)&in, sizeof(in), wimlib_error_file);
+                               putc('\n', wimlib_error_file);
+                       }
+                       if (--max_retries) {
+                               WARNING("Retrying after 100ms...");
+                               Sleep(100);
+                               goto retry;
+                       }
+                       WARNING("Too many retries; returning failure");
+                       return false;
+               }
        } else {
 
                /* The WOF driver is running.  We need to create the reparse
@@ -1114,11 +1069,11 @@ wimboot_set_pointer(const wchar_t *path,
                        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(struct 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;
 
@@ -1128,15 +1083,15 @@ wimboot_set_pointer(const wchar_t *path,
                in.wim_info.version = 2;
                in.wim_info.flags = 0;
                in.wim_info.data_source_id = data_source_id;
-               copy_hash(in.wim_info.resource_hash, lte->hash);
-               copy_hash(in.wim_info.wim_lookup_table_hash, lookup_table_hash);
-               in.wim_info.stream_uncompressed_size = lte->size;
-               in.wim_info.stream_compressed_size = lte->rspec->size_in_wim;
-               in.wim_info.stream_offset_in_wim = lte->rspec->offset_in_wim;
+               copy_hash(in.wim_info.unnamed_data_stream_hash, blob->hash);
+               copy_hash(in.wim_info.blob_table_hash, blob_table_hash);
+               in.wim_info.unnamed_data_stream_size = blob->size;
+               in.wim_info.unnamed_data_stream_size_in_wim = blob->rdesc->size_in_wim;
+               in.wim_info.unnamed_data_stream_offset_in_wim = blob->rdesc->offset_in_wim;
 
                if (!DeviceIoControl(h, FSCTL_SET_REPARSE_POINT,
                                     &in, sizeof(in), NULL, 0, &bytes_returned, NULL))
-                       goto fail;
+                       return false;
 
                /* We also need to create an unnamed data stream of the correct
                 * size.  Otherwise the file shows up as zero length.  It can be
@@ -1144,32 +1099,18 @@ wimboot_set_pointer(const wchar_t *path,
                 * are unimportant.  */
                if (!DeviceIoControl(h, FSCTL_SET_SPARSE, NULL, 0, NULL, 0,
                                     &bytes_returned, NULL))
-                       goto fail;
+                       return false;
 
                if (!SetFilePointerEx(h,
-                                     (LARGE_INTEGER){ .QuadPart = lte->size},
+                                     (LARGE_INTEGER){ .QuadPart = blob->size},
                                      NULL, FILE_BEGIN))
-                       goto fail;
+                       return false;
 
                if (!SetEndOfFile(h))
-                       goto fail;
+                       return false;
        }
 
-       ret = 0;
-out_close_handle:
-       CloseHandle(h);
-out:
-       return ret;
-
-fail:
-       {
-               DWORD err = GetLastError();
-               set_errno_from_win32_error(err);
-               ERROR_WITH_ERRNO("\"%ls\": Couldn't set WIMBoot pointer data "
-                                "(err=0x%08"PRIx32")", path, (u32)err);
-               ret = WIMLIB_ERR_WIMBOOT;
-               goto out_close_handle;
-       }
+       return true;
 }
 
 #endif /* __WIN32__ */