/* Number of files on which we couldn't set System Compression. */
unsigned long num_system_compression_failures;
- /* The number of files on which we used XPRESS4K System Compression
- * rather than a stronger variant, to be compatible with the Windows
- * bootloader. */
- unsigned long num_xpress4k_forced_files;
+ /* The number of files which, for compatibility with the Windows
+ * bootloader, were not compressed using the requested system
+ * compression format. This includes matches with the hardcoded pattern
+ * list only; it does not include matches with patterns in
+ * [PrepopulateList]. */
+ unsigned long num_system_compression_exclusions;
+
+ /* The Windows build number of the image being applied, or 0 if unknown.
+ */
+ u64 windows_build_number;
/* Have we tried to enable short name support on the target volume yet?
*/
}
}
+/* Is the image being extracted an OS image for Windows 10 or later? */
+static bool
+is_image_windows_10_or_later(struct win32_apply_ctx *ctx)
+{
+ /* Note: if no build number is available, this returns false. */
+ return ctx->windows_build_number >= 10240;
+}
+
static const wchar_t *
current_path(struct win32_apply_ctx *ctx);
int ret;
struct wim_dentry *dentry;
- if (!wim_info_get_wimboot(ctx->common.wim->wim_info,
- ctx->common.wim->current_image))
+ if (!xml_get_wimboot(ctx->common.wim->xml_info,
+ ctx->common.wim->current_image))
WARNING("The WIM image is not marked as WIMBoot compatible. This usually\n"
" means it is not intended to be used to back a Windows operating\n"
" system. Proceeding anyway.");
d = d->d_parent)
{
p -= d->d_extraction_name_nchars;
- wmemcpy(p, d->d_extraction_name, d->d_extraction_name_nchars);
+ if (d->d_extraction_name_nchars)
+ wmemcpy(p, d->d_extraction_name,
+ d->d_extraction_name_nchars);
*--p = '\\';
}
/* No leading slash */
ctx->attr.Length = sizeof(ctx->attr);
ctx->attr.RootDirectory = NULL;
ctx->attr.ObjectName = &ctx->target_ntpath;
+
+ /* Don't use FILE_OPEN_REPARSE_POINT here; we want the extraction to
+ * happen at the directory "pointed to" by the reparse point. */
status = (*func_NtCreateFile)(&ctx->h_target,
FILE_TRAVERSE,
&ctx->attr,
FILE_SHARE_VALID_FLAGS,
FILE_OPEN_IF,
FILE_DIRECTORY_FILE |
- FILE_OPEN_REPARSE_POINT |
FILE_OPEN_FOR_BACKUP_INTENT,
NULL,
0);
FILE_BASIC_INFORMATION info;
NTSTATUS status;
USHORT compression_state;
+ DWORD bytes_returned;
/* Get current attributes */
status = (*func_NtQueryInformationFile)(h, &ctx->iosb,
else
compression_state = COMPRESSION_FORMAT_NONE;
- status = (*func_NtFsControlFile)(h,
- NULL,
- NULL,
- NULL,
- &ctx->iosb,
- FSCTL_SET_COMPRESSION,
- &compression_state,
- sizeof(USHORT),
- NULL,
- 0);
- if (NT_SUCCESS(status))
+ /* Note: don't use NtFsControlFile() here unless prepared to handle
+ * STATUS_PENDING. */
+ if (DeviceIoControl(h, FSCTL_SET_COMPRESSION,
+ &compression_state, sizeof(USHORT), NULL, 0,
+ &bytes_returned, NULL))
return 0;
- winnt_error(status, L"Can't %s compression attribute on \"%ls\"",
+ win32_error(GetLastError(), L"Can't %s compression attribute on \"%ls\"",
(compressed ? "set" : "clear"), current_path(ctx));
return WIMLIB_ERR_SET_ATTRIBUTES;
}
return status;
}
-/* Hard-coded list of files which the Windows bootloader needs to access before
- * the WOF driver has been loaded. Since the Windows bootloader only supports
- * the XPRESS4K variant of System Compression, such files should not be
- * compressed using other variants. */
-static wchar_t *xpress4k_only_pattern_strings[] = {
+/* Hard-coded list of files which the Windows bootloader may need to access
+ * before the WOF driver has been loaded. */
+static wchar_t *bootloader_pattern_strings[] = {
L"*winload.*",
L"*winresume.*",
L"\\Windows\\AppPatch\\drvmain.sdb",
L"\\Windows\\System32\\CodeIntegrity\\driver.stl",
};
-static const struct string_set xpress4k_only_patterns = {
- .strings = xpress4k_only_pattern_strings,
- .num_strings = ARRAY_LEN(xpress4k_only_pattern_strings),
+static const struct string_set bootloader_patterns = {
+ .strings = bootloader_pattern_strings,
+ .num_strings = ARRAY_LEN(bootloader_pattern_strings),
};
static NTSTATUS
NTSTATUS status;
HANDLE h;
- /* If needed, force the XPRESS4K format for this file. */
- if (format != FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS4K) {
+ /* If it may be needed for compatibility with the Windows bootloader,
+ * force this file to XPRESS4K or uncompressed format. The bootloader
+ * of Windows 10 supports XPRESS4K only; older versions don't support
+ * system compression at all. */
+ if (!is_image_windows_10_or_later(ctx) ||
+ format != FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS4K)
+ {
/* We need to check the patterns against every name of the
* inode, in case any of them match. */
struct wim_dentry *dentry;
inode_for_each_extraction_alias(dentry, inode) {
bool incompatible;
+ bool warned;
if (calculate_dentry_full_path(dentry)) {
ERROR("Unable to compute file path!");
}
incompatible = match_pattern_list(dentry->d_full_path,
- &xpress4k_only_patterns);
+ &bootloader_patterns);
FREE(dentry->d_full_path);
dentry->d_full_path = NULL;
- if (incompatible) {
- if (ctx->num_xpress4k_forced_files++ == 0) {
+ if (!incompatible)
+ continue;
+
+ warned = (ctx->num_system_compression_exclusions++ > 0);
+
+ if (is_image_windows_10_or_later(ctx)) {
+ /* Force to XPRESS4K */
+ if (!warned) {
WARNING("For compatibility with the "
"Windows bootloader, some "
"files are being\n"
}
format = FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS4K;
break;
+ } else {
+ /* Force to uncompressed */
+ if (!warned) {
+ WARNING("For compatibility with the "
+ "Windows bootloader, some "
+ "files will not\n"
+ " be compressed with"
+ " system compression "
+ "(\"compacted\").");
+ }
+ return STATUS_SUCCESS;
}
+
}
}
goto out;
}
+ ctx->windows_build_number = xml_get_windows_build_number(ctx->common.wim->xml_info,
+ ctx->common.wim->current_image);
+
dentry_count = count_dentries(dentry_list);
ret = start_file_structure_phase(&ctx->common, dentry_count);