/* * 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; }