4 * Support for creating WIMBoot pointer files.
6 * See http://technet.microsoft.com/en-us/library/dn594399.aspx for general
7 * information about WIMBoot.
9 * Note that WIMBoot pointer files are actually implemented on top of the
10 * Windows Overlay File System Filter (WOF). See wof.h for more info.
14 * Copyright (C) 2014 Eric Biggers
16 * This file is part of wimlib, a library for working with WIM files.
18 * wimlib is free software; you can redistribute it and/or modify it under the
19 * terms of the GNU General Public License as published by the Free
20 * Software Foundation; either version 3 of the License, or (at your option)
23 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
24 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
25 * A PARTICULAR PURPOSE. See the GNU General Public License for more
28 * You should have received a copy of the GNU General Public License
29 * along with wimlib; if not, see http://www.gnu.org/licenses/.
33 # error "This file contains Windows code!"
40 #include "wimlib/win32_common.h"
41 #include "wimlib/win32.h"
42 #include "wimlib/assert.h"
43 #include "wimlib/error.h"
44 #include "wimlib/util.h"
45 #include "wimlib/wimboot.h"
46 #include "wimlib/wof.h"
49 win32_get_drive_path(const wchar_t *file_path, wchar_t drive_path[7])
53 file_abspath = realpath(file_path, NULL);
55 return WIMLIB_ERR_NOMEM;
57 if (file_abspath[0] == L'\0' || file_abspath[1] != L':') {
58 ERROR("\"%ls\": Path format not recognized", file_abspath);
60 return WIMLIB_ERR_UNSUPPORTED;
63 wsprintf(drive_path, L"\\\\.\\%lc:", file_abspath[0]);
68 /* Try to attach an instance of the Windows Overlay File System Filter Driver to
69 * the specified drive (such as C:) */
71 try_to_attach_wof(const wchar_t *drive)
76 /* Use FilterAttach() from Fltlib.dll. */
78 fltlib = LoadLibrary(L"Fltlib.dll");
81 WARNING("Failed to load Fltlib.dll");
85 HRESULT (WINAPI *func_FilterAttach)(LPCWSTR lpFilterName,
87 LPCWSTR lpInstanceName,
88 DWORD dwCreatedInstanceNameLength,
89 LPWSTR lpCreatedInstanceName);
91 func_FilterAttach = (void *)GetProcAddress(fltlib, "FilterAttach");
93 if (func_FilterAttach) {
96 res = (*func_FilterAttach)(L"WoF", drive, NULL, 0, NULL);
101 WARNING("FilterAttach() does not exist in Fltlib.dll");
110 * Allocate a WOF data source ID for a WIM file.
113 * Absolute path to the WIM file. This must include a drive letter and use
114 * backslash path separators.
116 * Index of the image in the WIM being applied.
118 * Path to the target drive.
119 * @data_source_id_ret
120 * On success, an identifier for the backing WIM file will be returned
123 * Returns 0 on success, or a positive error code on failure.
126 wimboot_alloc_data_source_id(const wchar_t *wim_path, int image,
127 const wchar_t *target, u64 *data_source_id_ret)
130 size_t wim_path_nchars;
131 size_t wim_file_name_length;
134 struct wof_external_info *wof_info;
135 struct wim_provider_add_overlay_input *wim_info;
138 DWORD bytes_returned;
140 const wchar_t *prefix = L"\\??\\";
141 const size_t prefix_nchars = 4;
142 bool tried_to_attach_wof = false;
144 ret = win32_get_drive_path(target, drive_path);
148 wimlib_assert(!wcschr(wim_path, L'/'));
149 wimlib_assert(wim_path[0] != L'\0' && wim_path[1] == L':');
151 wim_path_nchars = wcslen(wim_path);
152 wim_file_name_length = sizeof(wchar_t) *
153 (wim_path_nchars + prefix_nchars);
155 insize = sizeof(struct wof_external_info) +
156 sizeof(struct wim_provider_add_overlay_input) +
157 wim_file_name_length;
161 ret = WIMLIB_ERR_NOMEM;
165 wof_info = (struct wof_external_info *)in;
166 wof_info->version = WOF_CURRENT_VERSION;
167 wof_info->provider = WOF_PROVIDER_WIM;
169 wim_info = (struct wim_provider_add_overlay_input *)(wof_info + 1);
170 wim_info->wim_type = WIM_BOOT_NOT_OS_WIM;
171 wim_info->wim_index = image;
172 wim_info->wim_file_name_offset = offsetof(struct wim_provider_add_overlay_input,
174 wim_info->wim_file_name_length = wim_file_name_length;
175 wmemcpy(&wim_info->wim_file_name[0], prefix, prefix_nchars);
176 wmemcpy(&wim_info->wim_file_name[prefix_nchars], wim_path, wim_path_nchars);
179 h = CreateFile(drive_path, GENERIC_WRITE,
180 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
181 NULL, OPEN_EXISTING, 0, NULL);
183 if (h == INVALID_HANDLE_VALUE) {
184 set_errno_from_GetLastError();
185 ERROR_WITH_ERRNO("Failed to open \"%ls\"", drive_path + 4);
186 ret = WIMLIB_ERR_OPEN;
190 if (!DeviceIoControl(h, FSCTL_ADD_OVERLAY,
192 &data_source_id, sizeof(data_source_id),
193 &bytes_returned, NULL))
195 DWORD err = GetLastError();
196 if (err == ERROR_INVALID_FUNCTION) {
197 if (!tried_to_attach_wof) {
199 h = INVALID_HANDLE_VALUE;
200 tried_to_attach_wof = true;
201 if (try_to_attach_wof(drive_path + 4))
204 ERROR("The version of Windows you are running does not appear to support\n"
205 " the Windows Overlay File System Filter Driver. Therefore, wimlib\n"
206 " cannot apply WIMBoot information. Please run from Windows 8.1\n"
207 " Update 1 or later.");
208 ret = WIMLIB_ERR_UNSUPPORTED;
209 goto out_close_handle;
211 set_errno_from_win32_error(err);
212 ERROR_WITH_ERRNO("Failed to add overlay source \"%ls\" "
213 "to volume \"%ls\" (err=0x%08"PRIu32")",
214 wim_path, drive_path + 4, (uint32_t)err);
215 ret = WIMLIB_ERR_WIMBOOT;
216 goto out_close_handle;
220 if (bytes_returned != sizeof(data_source_id)) {
221 set_errno_from_win32_error(ERROR_INVALID_DATA);
222 ret = WIMLIB_ERR_WIMBOOT;
223 ERROR("Unexpected result size when adding "
224 "overlay source \"%ls\" to volume \"%ls\"",
225 wim_path, drive_path + 4);
226 goto out_close_handle;
229 *data_source_id_ret = data_source_id;
242 * Set WIMBoot information on the specified file.
245 * Path to extracted file (already created).
247 * Identifier for backing WIM file.
249 * SHA-1 message digest of the file's unnamed data stream.
251 * Returns 0 on success, or a positive error code on failure.
254 wimboot_set_pointer(const wchar_t *path, u64 data_source_id,
258 struct wof_external_info wof_info;
259 struct wim_provider_external_info wim_info;
262 DWORD bytes_returned;
265 in.wof_info.version = WOF_CURRENT_VERSION;
266 in.wof_info.provider = WOF_PROVIDER_WIM;
268 in.wim_info.version = WIM_PROVIDER_CURRENT_VERSION;
269 in.wim_info.flags = 0;
270 in.wim_info.data_source_id = data_source_id;
271 memcpy(in.wim_info.resource_hash, hash, 20);
273 h = win32_open_existing_file(path, GENERIC_WRITE);
274 if (h == INVALID_HANDLE_VALUE) {
275 set_errno_from_GetLastError();
276 ret = WIMLIB_ERR_OPEN;
280 if (!DeviceIoControl(h, FSCTL_SET_EXTERNAL_BACKING,
281 &in, sizeof(in), NULL, 0, &bytes_returned, NULL))
283 DWORD err = GetLastError();
284 set_errno_from_win32_error(err);
285 ERROR_WITH_ERRNO("\"%ls\": Couldn't set WIMBoot pointer data "
286 "(err=0x%08x)", path, (uint32_t)err);
287 ret = WIMLIB_ERR_WIMBOOT;
288 goto out_close_handle;