--- /dev/null
+/*
+ * wof.h
+ *
+ * Definitions for Windows Overlay File System Filter (WOF) ioctls. See
+ * http://msdn.microsoft.com/en-us/library/windows/hardware/ff540367(v=vs.85).aspx
+ * for more information.
+ */
+
+#ifndef _WOF_H_
+#define _WOF_H_
+
+#include "wimlib/types.h"
+
+#define WOF_CURRENT_VERSION 1
+#define WOF_PROVIDER_WIM 1
+#define WIM_PROVIDER_CURRENT_VERSION 1
+
+/* Identifies a backing provider for a specific overlay service version. */
+struct wof_external_info {
+
+ /* Version of the overlay service supported by the backing provider.
+ * Set to WOF_CURRENT_VERSION. */
+ u32 version;
+
+ /* Identifier for the backing provider. Example value:
+ * WOF_PROVIDER_WIM. */
+ u32 provider;
+};
+
+/* WOF reparse points can't be directly manipulated on Windows; setting the
+ * reparse data doesn't seem to work, and the WOF driver hides the reparse
+ * points so their data can't be read from Windows 8.1 and later. Use the
+ * ioctls (FSCTL_SET_EXTERNAL_BACKING, FSCTL_GET_EXTERNAL_BACKING,
+ * FSCTL_DELETE_EXTERNAL_BACKING) instead. */
+#if 0
+/*
+ * Format of the reparse data of WoF (Windows Overlay File System Filter)
+ * reparse points. These include WIMBoot "pointer files".
+ *
+ * Notes:
+ * - Reparse tag is 0x80000017
+ * - Don't make these if the file has no unnamed data stream, has an empty
+ * unnamed data stream, or already is a reparse point.
+ * - There is nowhere to put named data streams. They have to copied
+ * literally to the reparse point file.
+ */
+struct wof_rpdata_disk {
+ struct wof_external_info info;
+ union {
+ struct {
+ /* (Guess) Version of this structure --- set to 2. */
+ u64 version;
+
+ /* Integer ID that identifies the WIM. */
+ u64 data_source_id;
+
+ /* SHA1 message digest of the file's unnamed data
+ * stream. */
+ u8 stream_sha1[20];
+
+ /* SHA1 message digest of the WIM's lookup table. */
+ u8 wim_lookup_table_sha1[20];
+
+ /* Uncompressed size of the file's unnamed data stream,
+ * in bytes. */
+ u64 stream_uncompressed_size;
+
+ /* Compressed size of the file's unnamed data stream, in
+ * bytes. If stream is stored uncompressed, set this
+ * the same as the uncompressed size. */
+ u64 stream_compressed_size;
+
+ /* Byte offset of the file's unnamed data stream in the
+ * WIM. */
+ u64 stream_offset_in_wim;
+ } wim;
+ } provider_data;
+};
+#endif
+
+/*****************************************************************************
+ *
+ * --- FSCTL_SET_EXTERNAL_BACKING ---
+ *
+ * Sets the backing source of a file.
+ *
+ * DeviceType: 9 (FILE_DEVICE_FILE_SYSTEM)
+ * Access: 0 (FILE_ANY_ACCESS)
+ * Function: 195
+ * Method: 0 (METHOD_BUFFERED)
+ *
+ * Input buffer: 'struct wof_external_info' followed by provider-specific data
+ * ('struct wim_provider_external_info' in the case of WIM).
+ *
+ * Output buffer: None
+ */
+#define FSCTL_SET_EXTERNAL_BACKING 0x9030C
+
+struct wim_provider_external_info {
+
+ /* Set to WIM_PROVIDER_CURRENT_VERSION. */
+ u32 version;
+
+ /* 0 when WIM provider active, otherwise
+ * WIM_PROVIDER_EXTERNAL_FLAG_NOT_ACTIVE or
+ * WIM_PROVIDER_EXTERNAL_FLAG_SUSPENDED. */
+ u32 flags;
+
+ /* Integer ID that identifies the WIM. Get this with the
+ * FSCTL_ADD_OVERLAY ioctl. */
+ u64 data_source_id;
+
+ /* SHA1 message digest of the file's unnamed data stream. */
+ u8 resource_hash[20];
+};
+
+/*****************************************************************************
+ *
+ * --- FSCTL_ADD_OVERLAY ---
+ *
+ * Adds a new external backing source to a volume.
+ *
+ * DeviceType: 9 (FILE_DEVICE_FILE_SYSTEM)
+ * Access: 2 (FILE_WRITE_ACCESS)
+ * Function: 204
+ * Method: 0 (METHOD_BUFFERED)
+ *
+ * Input buffer: 'struct wof_external_info' followed by provider-specific data
+ * ('struct wim_provider_add_overlay_input' in the case of WIM).
+ *
+ * Output buffer: Buffer large enough to receive any information resulting from
+ * the add operation. For the WIM provider, this must be an 8 byte buffer that
+ * receives the 64-bit WIM file ID.
+ */
+#define FSCTL_ADD_OVERLAY 0x98330
+
+struct wim_provider_add_overlay_input {
+
+ /* Type of WIM file. */
+ u32 wim_type;
+#define WIM_BOOT_OS_WIM 0
+#define WIM_BOOT_NOT_OS_WIM 1
+
+ /* Index of the image in the WIM to use??? (This doesn't really make
+ * sense, since WIM files combine streams for all images into a single
+ * table. Set to 1 if unsure...) */
+ u32 wim_index;
+
+ /* Byte offset of wim_file_name in this buffer, not including the
+ * preceding 'struct wof_external_info' (should be 16). */
+ u32 wim_file_name_offset;
+
+ /* Number of bytes in wim_file_name. */
+ u32 wim_file_name_length;
+
+ /* Full path to the WIM, e.g. "\??\d:\test-wimboot.wim".
+ * Does NOT need to be null terminated (MS docs claim otherwise). */
+ wchar_t wim_file_name[];
+};
+
+#endif /* _WOF_H_ */
--- /dev/null
+/*
+ * wimboot.c
+ *
+ * Support for creating WIMBoot pointer files.
+ *
+ * See http://technet.microsoft.com/en-us/library/dn594399.aspx for general
+ * 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.
+ */
+
+/*
+ * Copyright (C) 2014 Eric Biggers
+ *
+ * This file is part of wimlib, a library for working with WIM files.
+ *
+ * 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
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ */
+
+#ifndef __WIN32__
+# error "This file contains Windows code!"
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "wimlib/win32_common.h"
+#include "wimlib/win32.h"
+#include "wimlib/assert.h"
+#include "wimlib/error.h"
+#include "wimlib/util.h"
+#include "wimlib/wimboot.h"
+#include "wimlib/wof.h"
+
+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;
+}
+
+/*
+ * Allocate a WOF data source ID for a WIM file.
+ *
+ * @wim_path
+ * Absolute path to the WIM file. This must include a drive letter and use
+ * backslash path separators.
+ * @image
+ * Index of the image in the WIM being applied.
+ * @target
+ * Path to the target drive.
+ * @data_source_id_ret
+ * On success, an identifier for the backing WIM file will be returned
+ * here.
+ *
+ * Returns 0 on success, or a positive error code on failure.
+ */
+int
+wimboot_alloc_data_source_id(const wchar_t *wim_path, int image,
+ const wchar_t *target, u64 *data_source_id_ret)
+{
+ tchar drive_path[7];
+ size_t wim_path_nchars;
+ 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;
+ HANDLE h;
+ u64 data_source_id;
+ DWORD bytes_returned;
+ int ret;
+ const wchar_t *prefix = L"\\??\\";
+ const size_t prefix_nchars = 4;
+
+ ret = win32_get_drive_path(target, drive_path);
+ if (ret)
+ return ret;
+
+ wimlib_assert(!wcschr(wim_path, L'/'));
+ wimlib_assert(wim_path[0] != L'\0' && wim_path[1] == L':');
+
+ wim_path_nchars = wcslen(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);
+ 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;
+
+ 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);
+
+ h = CreateFile(drive_path, GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING, 0, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ set_errno_from_GetLastError();
+ ERROR_WITH_ERRNO("Failed to open \"%ls\"", drive_path);
+ ret = WIMLIB_ERR_OPEN;
+ goto out_free_in;
+ }
+
+ if (!DeviceIoControl(h, FSCTL_ADD_OVERLAY,
+ in, insize,
+ &data_source_id, sizeof(data_source_id),
+ &bytes_returned, NULL))
+ {
+ set_errno_from_GetLastError();
+ ERROR_WITH_ERRNO("Failed to add overlay source \"%ls\" "
+ "to volume \"%ls\"", wim_path, drive_path);
+ 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\"",
+ wim_path, drive_path);
+ goto out_close_handle;
+ }
+
+ *data_source_id_ret = data_source_id;
+ ret = 0;
+
+out_close_handle:
+ CloseHandle(h);
+out_free_in:
+ FREE(in);
+out:
+ return ret;
+}
+
+
+/*
+ * Set WIMBoot information on the specified file.
+ *
+ * @path
+ * Path to extracted file (already created).
+ * @data_source_id
+ * Identifier for backing WIM file.
+ * @hash
+ * SHA-1 message digest of the file's unnamed data stream.
+ *
+ * Returns 0 on success, or a positive error code on failure.
+ */
+int
+wimboot_set_pointer(const wchar_t *path, u64 data_source_id,
+ const u8 hash[20])
+{
+ struct {
+ struct wof_external_info wof_info;
+ struct wim_provider_external_info wim_info;
+ } in;
+ HANDLE h;
+ DWORD bytes_returned;
+ int ret;
+
+ 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;
+ memcpy(in.wim_info.resource_hash, hash, 20);
+
+ h = win32_open_existing_file(path, GENERIC_WRITE);
+ if (h == INVALID_HANDLE_VALUE) {
+ set_errno_from_GetLastError();
+ ret = WIMLIB_ERR_OPEN;
+ goto out;
+ }
+
+ if (!DeviceIoControl(h, FSCTL_SET_EXTERNAL_BACKING,
+ &in, sizeof(in), NULL, 0, &bytes_returned, NULL))
+ {
+ set_errno_from_GetLastError();
+ ret = WIMLIB_ERR_WIMBOOT;
+ goto out_close_handle;
+ }
+ ret = 0;
+out_close_handle:
+ CloseHandle(h);
+out:
+ return ret;
+}