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/.
39 #include "wimlib/win32_common.h"
40 #include "wimlib/win32.h"
41 #include "wimlib/assert.h"
42 #include "wimlib/error.h"
43 #include "wimlib/util.h"
44 #include "wimlib/wimboot.h"
45 #include "wimlib/wof.h"
48 win32_get_drive_path(const wchar_t *file_path, wchar_t drive_path[7])
52 file_abspath = realpath(file_path, NULL);
54 return WIMLIB_ERR_NOMEM;
56 if (file_abspath[0] == L'\0' || file_abspath[1] != L':') {
57 ERROR("\"%ls\": Path format not recognized", file_abspath);
59 return WIMLIB_ERR_UNSUPPORTED;
62 wsprintf(drive_path, L"\\\\.\\%lc:", file_abspath[0]);
67 /* Try to attach an instance of the Windows Overlay File System Filter Driver to
68 * the specified drive (such as C:) */
70 try_to_attach_wof(const wchar_t *drive)
75 /* Use FilterAttach() from Fltlib.dll. */
77 fltlib = LoadLibrary(L"Fltlib.dll");
80 WARNING("Failed to load Fltlib.dll");
84 HRESULT (WINAPI *func_FilterAttach)(LPCWSTR lpFilterName,
86 LPCWSTR lpInstanceName,
87 DWORD dwCreatedInstanceNameLength,
88 LPWSTR lpCreatedInstanceName);
90 func_FilterAttach = (void *)GetProcAddress(fltlib, "FilterAttach");
92 if (func_FilterAttach) {
95 res = (*func_FilterAttach)(L"WoF", drive, NULL, 0, NULL);
100 WARNING("FilterAttach() does not exist in Fltlib.dll");
109 * Allocate a WOF data source ID for a WIM file.
112 * Absolute path to the WIM file. This must include a drive letter and use
113 * backslash path separators.
115 * Index of the image in the WIM being applied.
117 * Path to the target drive.
118 * @data_source_id_ret
119 * On success, an identifier for the backing WIM file will be returned
122 * Returns 0 on success, or a positive error code on failure.
125 wimboot_alloc_data_source_id(const wchar_t *wim_path, int image,
126 const wchar_t *target, u64 *data_source_id_ret)
129 size_t wim_path_nchars;
130 size_t wim_file_name_length;
133 struct wof_external_info *wof_info;
134 struct wim_provider_add_overlay_input *wim_info;
137 DWORD bytes_returned;
139 const wchar_t *prefix = L"\\??\\";
140 const size_t prefix_nchars = 4;
141 bool tried_to_attach_wof = false;
143 ret = win32_get_drive_path(target, drive_path);
147 wimlib_assert(!wcschr(wim_path, L'/'));
148 wimlib_assert(wim_path[0] != L'\0' && wim_path[1] == L':');
150 wim_path_nchars = wcslen(wim_path);
151 wim_file_name_length = sizeof(wchar_t) *
152 (wim_path_nchars + prefix_nchars);
154 insize = sizeof(struct wof_external_info) +
155 sizeof(struct wim_provider_add_overlay_input) +
156 wim_file_name_length;
160 ret = WIMLIB_ERR_NOMEM;
164 wof_info = (struct wof_external_info *)in;
165 wof_info->version = WOF_CURRENT_VERSION;
166 wof_info->provider = WOF_PROVIDER_WIM;
168 wim_info = (struct wim_provider_add_overlay_input *)(wof_info + 1);
169 wim_info->wim_type = WIM_BOOT_NOT_OS_WIM;
170 wim_info->wim_index = image;
171 wim_info->wim_file_name_offset = offsetof(struct wim_provider_add_overlay_input,
173 wim_info->wim_file_name_length = wim_file_name_length;
174 wmemcpy(&wim_info->wim_file_name[0], prefix, prefix_nchars);
175 wmemcpy(&wim_info->wim_file_name[prefix_nchars], wim_path, wim_path_nchars);
178 h = CreateFile(drive_path, GENERIC_WRITE,
179 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
180 NULL, OPEN_EXISTING, 0, NULL);
182 if (h == INVALID_HANDLE_VALUE) {
183 set_errno_from_GetLastError();
184 ERROR_WITH_ERRNO("Failed to open \"%ls\"", drive_path + 4);
185 ret = WIMLIB_ERR_OPEN;
189 if (!DeviceIoControl(h, FSCTL_ADD_OVERLAY,
191 &data_source_id, sizeof(data_source_id),
192 &bytes_returned, NULL))
194 DWORD err = GetLastError();
195 if (err == ERROR_INVALID_FUNCTION) {
196 if (!tried_to_attach_wof) {
198 h = INVALID_HANDLE_VALUE;
199 tried_to_attach_wof = true;
200 if (try_to_attach_wof(drive_path + 4))
203 ERROR("The version of Windows you are running does not appear to support\n"
204 " the Windows Overlay File System Filter Driver. Therefore, wimlib\n"
205 " cannot apply WIMBoot information. Please run from Windows 8.1\n"
206 " Update 1 or later.");
207 ret = WIMLIB_ERR_UNSUPPORTED;
208 goto out_close_handle;
210 set_errno_from_win32_error(err);
211 ERROR_WITH_ERRNO("Failed to add overlay source \"%ls\" "
212 "to volume \"%ls\" (err=0x%08"PRIu32")",
213 wim_path, drive_path + 4, (uint32_t)err);
214 ret = WIMLIB_ERR_WIMBOOT;
215 goto out_close_handle;
219 if (bytes_returned != sizeof(data_source_id)) {
220 set_errno_from_win32_error(ERROR_INVALID_DATA);
221 ret = WIMLIB_ERR_WIMBOOT;
222 ERROR("Unexpected result size when adding "
223 "overlay source \"%ls\" to volume \"%ls\"",
224 wim_path, drive_path + 4);
225 goto out_close_handle;
228 *data_source_id_ret = data_source_id;
241 * Set WIMBoot information on the specified file.
244 * Path to extracted file (already created).
246 * Identifier for backing WIM file.
248 * SHA-1 message digest of the file's unnamed data stream.
250 * Returns 0 on success, or a positive error code on failure.
253 wimboot_set_pointer(const wchar_t *path, u64 data_source_id,
257 struct wof_external_info wof_info;
258 struct wim_provider_external_info wim_info;
261 DWORD bytes_returned;
264 in.wof_info.version = WOF_CURRENT_VERSION;
265 in.wof_info.provider = WOF_PROVIDER_WIM;
267 in.wim_info.version = WIM_PROVIDER_CURRENT_VERSION;
268 in.wim_info.flags = 0;
269 in.wim_info.data_source_id = data_source_id;
270 memcpy(in.wim_info.resource_hash, hash, 20);
272 h = win32_open_existing_file(path, GENERIC_WRITE);
273 if (h == INVALID_HANDLE_VALUE) {
274 set_errno_from_GetLastError();
275 ret = WIMLIB_ERR_OPEN;
279 if (!DeviceIoControl(h, FSCTL_SET_EXTERNAL_BACKING,
280 &in, sizeof(in), NULL, 0, &bytes_returned, NULL))
282 DWORD err = GetLastError();
283 set_errno_from_win32_error(err);
284 ERROR_WITH_ERRNO("\"%ls\": Couldn't set WIMBoot pointer data "
285 "(err=0x%08x)", path, (uint32_t)err);
286 ret = WIMLIB_ERR_WIMBOOT;
287 goto out_close_handle;
296 #endif /* __WIN32__ */