return FILE_PROVIDER_COMPRESSION_FORMAT_LZX;
}
-static DWORD
+static NTSTATUS
set_system_compression(HANDLE h, int format)
{
- DWORD bytes_returned;
- DWORD err;
+ NTSTATUS status;
+ IO_STATUS_BLOCK iosb;
struct {
struct wof_external_info wof_info;
struct file_provider_external_info file_info;
},
};
- if (DeviceIoControl(h, FSCTL_SET_EXTERNAL_BACKING, &in, sizeof(in),
- NULL, 0, &bytes_returned, NULL))
- return 0;
+ /* We intentionally use NtFsControlFile() rather than DeviceIoControl()
+ * here because the "compressing this object would not save space"
+ * status code does not map to a valid Win32 error code on older
+ * versions of Windows (before Windows 10?). This can be a problem if
+ * the WOFADK driver is being used rather than the regular WOF, since
+ * WOFADK can be used on older versions of Windows. */
+ status = (*func_NtFsControlFile)(h, NULL, NULL, NULL, &iosb,
+ FSCTL_SET_EXTERNAL_BACKING,
+ &in, sizeof(in), NULL, 0);
- err = GetLastError();
+ if (status == 0xC000046F) /* "Compressing this object would not save space." */
+ return STATUS_SUCCESS;
- if (err == 344) /* "Compressing this object would not save space." */
- return 0;
+ return status;
+}
+
+static NTSTATUS
+set_system_compression_on_inode(struct wim_inode *inode, int format,
+ struct win32_apply_ctx *ctx)
+{
+ bool retried = false;
+ NTSTATUS status;
+ HANDLE h;
+
+ /* Open the extracted file. */
+ status = create_file(&h, GENERIC_READ | GENERIC_WRITE, NULL,
+ 0, FILE_OPEN, 0,
+ inode_first_extraction_dentry(inode), ctx);
- return err;
+ if (!NT_SUCCESS(status))
+ return status;
+retry:
+ /* Compress the file. If the attempt fails with "invalid device
+ * request", then attach wof.sys (or wofadk.sys) and retry. */
+ status = set_system_compression(h, format);
+ if (unlikely(status == STATUS_INVALID_DEVICE_REQUEST && !retried)) {
+ wchar_t drive_path[7];
+ if (!win32_get_drive_path(ctx->common.target, drive_path) &&
+ win32_try_to_attach_wof(drive_path + 4)) {
+ retried = true;
+ goto retry;
+ }
+ }
+
+ (*func_NtClose)(h);
+ return status;
}
/*
for (u32 i = 0; i < blob->out_refcnt; i++) {
struct wim_inode *inode = targets[i].inode;
struct wim_inode_stream *strm = targets[i].stream;
- HANDLE h;
NTSTATUS status;
- DWORD err;
if (!stream_is_unnamed_data_stream(strm))
continue;
if (will_externally_back_inode(inode, ctx, NULL, false) != 0)
continue;
- status = create_file(&h, GENERIC_READ | GENERIC_WRITE, NULL,
- 0, FILE_OPEN, 0,
- inode_first_extraction_dentry(inode), ctx);
-
- if (NT_SUCCESS(status)) {
- err = set_system_compression(h, format);
- (*func_NtClose)(h);
- } else {
- err = (*func_RtlNtStatusToDosError)(status);
- }
+ status = set_system_compression_on_inode(inode, format, ctx);
+ if (likely(NT_SUCCESS(status)))
+ continue;
- if (err == ERROR_INVALID_FUNCTION) {
+ if (status == STATUS_INVALID_DEVICE_REQUEST) {
WARNING(
"The request to compress the extracted files using System Compression\n"
" will not be honored because the operating system or target volume\n"
return;
}
- if (err) {
- ctx->num_system_compression_failures++;
- if (ctx->num_system_compression_failures < 10) {
- win32_warning(err, L"\"%ls\": Failed to compress "
- "extracted file using System Compression",
- current_path(ctx));
- } else if (ctx->num_system_compression_failures == 10) {
- WARNING("Suppressing further warnings about "
- "System Compression failures.");
- }
+ ctx->num_system_compression_failures++;
+ if (ctx->num_system_compression_failures < 10) {
+ winnt_warning(status, L"\"%ls\": Failed to compress "
+ "extracted file using System Compression",
+ current_path(ctx));
+ } else if (ctx->num_system_compression_failures == 10) {
+ WARNING("Suppressing further warnings about "
+ "System Compression failures.");
}
}
}