X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=include%2Fwimlib%2Fwof.h;h=da1546c01d47fbacbedaff258806ed89dd6a9ac4;hp=5158985061b8697a2399c96416e121799150cc8a;hb=18f09fc4fa05185897b2c3789f90cc8e3fd872c8;hpb=0f7725a7cd14830b484b241d56f66bf7743d7351 diff --git a/include/wimlib/wof.h b/include/wimlib/wof.h index 51589850..da1546c0 100644 --- a/include/wimlib/wof.h +++ b/include/wimlib/wof.h @@ -1,19 +1,70 @@ /* * wof.h * - * Definitions for Windows Overlay File System Filter (WOF) ioctls. See + * Definitions for the Windows Overlay File System Filter (WOF) ioctls, as well + * some definitions for associated undocumented data structures. See * http://msdn.microsoft.com/en-us/library/windows/hardware/ff540367(v=vs.85).aspx - * for more information. + * for more information about the documented ioctls. + * + * The author dedicates this file to the public domain. + * You can do whatever you want with this file. */ #ifndef _WOF_H_ #define _WOF_H_ +#include "wimlib/compiler.h" #include "wimlib/types.h" -#define WOF_CURRENT_VERSION 1 -#define WOF_PROVIDER_WIM 1 -#define WIM_PROVIDER_CURRENT_VERSION 1 +/* + * The Windows Overlay FileSystem Filter (WOF, a.k.a. wof.sys) is a filesystem + * filter driver, available in Windows 8.1 and later, which allows files to be + * "externally backed", meaning that their data is stored in another location, + * possibly in compressed form. + * + * WOF implements a plug-in mechanism by which a specific "provider" is + * responsible for actually externally backing a given file. The currently + * known providers are: + * + * - The WIM provider: allows a file to be externally backed by a + * compressed resource in a WIM archive + * - The file provider: allows a file to be "externally backed" by a named + * data stream stored with the file itself, where that named data stream + * has the format of a compressed WIM resource + * + * For both of these providers, externally backed files are effectively + * read-only. If you try to write to such a file, Windows automatically + * decompresses it and turns it into a regular, non-externally-backed file. + * + * WOF provides various ioctls that control its operation. For example, + * FSCTL_SET_EXTERNAL_BACKING sets up a file as externally backed. + * + * WOF external backings are implemented using reparse points. One consequence + * of this is that WOF external backings can only be set on files that do not + * already have a reparse point set. Another consequence of this is that it is + * possible to create a WOF external backing by manually creating the reparse + * point, although this requires dealing with undocumented data structures and + * it only works when the WOF driver is not currently attached to the volume. + * + * Note that only the unnamed data stream portion of a file can be externally + * backed. Other NTFS streams and metadata are not externally backed. + */ + + +/* Current version of the WOF driver/protocol */ +#define WOF_CURRENT_VERSION 1 + +/* Specifies the WIM backing provider */ +#define WOF_PROVIDER_WIM 1 + +/* Specifies the "file" backing provider (a.k.a. System Compression) */ +#define WOF_PROVIDER_FILE 2 + +/* The current version of the WIM backing provider */ +#define WIM_PROVIDER_CURRENT_VERSION 1 + +/* The current version of the file backing provider */ +#define FILE_PROVIDER_CURRENT_VERSION 1 /* Identifies a backing provider for a specific overlay service version. */ struct wof_external_info { @@ -27,56 +78,222 @@ struct wof_external_info { u32 provider; }; -/* WOF reparse points can't be directly manipulated on Windows; setting the - * reparse data doesn't seem to work, and the WOF driver hides the reparse - * points so their data can't be read from Windows 8.1 and later. Use the - * ioctls (FSCTL_SET_EXTERNAL_BACKING, FSCTL_GET_EXTERNAL_BACKING, - * FSCTL_DELETE_EXTERNAL_BACKING) instead. */ -#if 0 + /* - * Format of the reparse data of WoF (Windows Overlay File System Filter) - * reparse points. These include WIMBoot "pointer files". - * - * Notes: - * - Reparse tag is 0x80000017 - * - Don't make these if the file has no unnamed data stream, has an empty - * unnamed data stream, or already is a reparse point. - * - There is nowhere to put named data streams. They have to copied - * literally to the reparse point file. + * Format of the WIM provider reparse data. This is the data which follows the + * portion of the reparse point common to WOF. (The common portion consists of + * a reparse point header where the reparse tag is 0x80000017, then a 'struct + * wof_external_info' which specifies the provider.) + * + * Note that Microsoft does not document any of the reparse point formats for + * WOF, although they document the structures which must be passed into the + * ioctls, which are often similar. */ -struct wof_rpdata_disk { - struct wof_external_info info; - union { - struct { - /* (Guess) Version of this structure --- set to 2. */ - u64 version; - - /* Integer ID that identifies the WIM. */ - u64 data_source_id; - - /* SHA1 message digest of the file's unnamed data - * stream. */ - u8 stream_sha1[20]; - - /* SHA1 message digest of the WIM's lookup table. */ - u8 wim_lookup_table_sha1[20]; - - /* Uncompressed size of the file's unnamed data stream, - * in bytes. */ - u64 stream_uncompressed_size; - - /* Compressed size of the file's unnamed data stream, in - * bytes. If stream is stored uncompressed, set this - * the same as the uncompressed size. */ - u64 stream_compressed_size; - - /* Byte offset of the file's unnamed data stream in the - * WIM. */ - u64 stream_offset_in_wim; - } wim; - } provider_data; -}; -#endif +struct wim_provider_rpdata { + /* Set to 2. Uncertain meaning. */ + le32 version; + + /* 0 when WIM provider active, otherwise + * WIM_PROVIDER_EXTERNAL_FLAG_NOT_ACTIVE or + * WIM_PROVIDER_EXTERNAL_FLAG_SUSPENDED. */ + le32 flags; + + /* Integer ID that identifies the WIM. */ + le64 data_source_id; + + /* SHA-1 message digest of the file's unnamed data stream. */ + u8 unnamed_data_stream_hash[20]; + + /* SHA-1 message digest of the WIM's blob table as stored on disk. */ + u8 blob_table_hash[20]; + + /* Uncompressed size of the file's unnamed data stream, in bytes. */ + le64 unnamed_data_stream_size; + + /* Size of the file's unnamed data stream as stored in the WIM file. + * If this is the same as unnamed_data_stream_size, then the stream is + * uncompressed. If this is the *not* the same as + * unnamed_data_stream_size, then the stream is compressed. */ + le64 unnamed_data_stream_size_in_wim; + + /* Byte offset of the file's unnamed data stream in the WIM. */ + le64 unnamed_data_stream_offset_in_wim; +} _packed_attribute; + +/* WIM-specific information about a WIM data source */ +struct WimOverlay_dat_entry_1 { + + /* Identifier for the WIM data source, (normally allocated by + * FSCTL_ADD_OVERLAY). Every 'WimOverlay_dat_entry_1' should have a + * different value for this. */ + le64 data_source_id; + + /* Byte offset, from the beginning of the file, of the corresponding + * 'struct WimOverlay_dat_entry_2' for this WIM data source. */ + le32 entry_2_offset; + + /* Size, in bytes, of the corresponding 'struct WimOverlay_dat_entry_2 + * for this WIM data source, including wim_file_name and its null + * terminator. */ + le32 entry_2_length; + + /* Type of the WIM file: WIM_BOOT_OS_WIM or WIM_BOOT_NOT_OS_WIM. */ + le32 wim_type; + + /* Index of the image in the WIM to use??? (This doesn't really make + * sense, since WIM files combine file data "blobs" for all images into + * a single table. Set to 1 if unsure...) */ + le32 wim_index; + + /* GUID of the WIM file (copied from the WIM header, offset +0x18). */ + u8 guid[16]; +} _packed_attribute; + +/* + * Format of file: "\System Volume Information\WimOverlay.dat" + * + * Not documented by Microsoft. + * + * The file consists of a 'struct WimOverlay_dat_header' followed by one or more + * 'struct WimOverlay_dat_entry_1', followed by the same number of 'struct + * WimOverlay_dat_entry_2'. Note that 'struct WimOverlay_dat_entry_1' is of + * fixed length, whereas 'struct WimOverlay_dat_entry_2' is of variable length. + */ +struct WimOverlay_dat_header { + /* Set to WIMOVERLAY_DAT_MAGIC */ + le32 magic; +#define WIMOVERLAY_DAT_MAGIC 0x66436F57 + + /* Set to 1 (WIM_PROVIDER_CURRENT_VERSION) */ + le32 wim_provider_version; + + /* Set to 0x00000028 */ + le32 unknown_0x08; + + /* Set to number of WIMs registered (listed in the file) */ + le32 num_entries; + + /* The next available data source ID. This is tracked so that data + * source IDs are never reused, even if a WIM is unregistered. */ + le64 next_data_source_id; + + struct WimOverlay_dat_entry_1 entry_1s[]; +} _packed_attribute; + +/* Location information about a WIM data source */ +struct WimOverlay_dat_entry_2 { + /* Set to 0 */ + le32 unknown_0x00; + + /* Set to 0 */ + le32 unknown_0x04; + + /* Size, in bytes, of this 'struct WimOverlay_dat_entry_2', including + * wim_file_name and its null terminator. */ + le32 entry_2_length; + + /* Set to 0 */ + le32 unknown_0x0C; + + /* Set to 5 */ + le32 unknown_0x10; + + struct { + /* Set to 1 */ + le32 unknown_0x14; + + /* Size of this inner structure, in bytes. */ + le32 inner_struct_size; + + /* Set to 5 */ + le32 unknown_0x1C; + + /* Set to 6 */ + le32 unknown_0x20; + + /* Set to 0 */ + le32 unknown_0x24; + + /* Set to 0x48 */ + le32 unknown_0x28; + + /* Set to 0 */ + le32 unknown_0x2C; + + /************************* + * Partition information + ************************/ + + /* Partition identifier */ + union { + /* (For MBR-formatted disks) */ + struct { + /* Offset, in bytes, of the MBR partition, from + * the beginning of the disk. */ + le64 part_start_offset; + + /* Set to 0 */ + le64 padding; + } mbr; + + /* (For GPT-formatted disks) */ + struct { + /* Unique GUID of the GPT partition */ + u8 part_unique_guid[16]; + } gpt; + } partition; + + /* Set to 0 */ + le32 unknown_0x40; + + /*********************** + * Disk information + **********************/ + + /* 1 for MBR, 0 for GPT */ + le32 partition_table_type; + #define WIMOVERLAY_PARTITION_TYPE_MBR 1 + #define WIMOVERLAY_PARTITION_TYPE_GPT 0 + + /* Disk identifier */ + union { + /* (For MBR-formatted disks) */ + struct { + /* 4-byte ID of the MBR disk */ + le32 disk_id; + + /* Set to 0 */ + le32 padding[3]; + } mbr; + + /* (For GPT-formatted disks) */ + struct { + /* GUID of the GPT disk */ + u8 disk_guid[16]; + } gpt; + } disk; + + /* Set to 0. (This is the right size for some sort of optional + * GUID...) */ + le32 unknown_0x58[4]; + + /************************** + * Location in filesystem + *************************/ + + /* Null-terminated path to WIM file. Begins with \ but does + * *not* include drive letter! */ + utf16lechar wim_file_name[]; + } _packed_attribute; +} _packed_attribute; + +static _unused_attribute void +wof_check_structs(void) +{ + STATIC_ASSERT(sizeof(struct WimOverlay_dat_header) == 24); + STATIC_ASSERT(sizeof(struct WimOverlay_dat_entry_1) == 40); + STATIC_ASSERT(sizeof(struct WimOverlay_dat_entry_2) == 104); +} /***************************************************************************** * @@ -110,8 +327,20 @@ struct wim_provider_external_info { * FSCTL_ADD_OVERLAY ioctl. */ u64 data_source_id; - /* SHA1 message digest of the file's unnamed data stream. */ - u8 resource_hash[20]; + /* SHA-1 message digest of the file's unnamed data stream. */ + u8 unnamed_data_stream_hash[20]; +}; + +struct file_provider_external_info { + + /* Set to FILE_PROVIDER_CURRENT_VERSION. */ + u32 version; + + u32 compression_format; +#define FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS4K 0 +#define FILE_PROVIDER_COMPRESSION_FORMAT_LZX 1 +#define FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS8K 2 +#define FILE_PROVIDER_COMPRESSION_FORMAT_XPRESS16K 3 }; /***************************************************************************** @@ -131,6 +360,8 @@ struct wim_provider_external_info { */ #define FSCTL_GET_EXTERNAL_BACKING 0x90310 +#define STATUS_OBJECT_NOT_EXTERNALLY_BACKED 0xC000046D + /***************************************************************************** * * --- FSCTL_DELETE_EXTERNAL_BACKING --- @@ -195,32 +426,32 @@ struct wim_provider_external_info { struct wim_provider_overlay_entry { /* Byte offset of the next entry from the beginning of this structure, * or 0 if there are no more entries. */ - uint32_t next_entry_offset; + u32 next_entry_offset; - uint32_t padding; + u32 padding; /* Identifier for the WIM file. */ - uint64_t data_source_id; + u64 data_source_id; /* GUID of the WIM file. */ - uint8_t guid[16]; + u8 guid[16]; /* Byte offset of the WIM's file name from the beginning of this * structure. */ - uint32_t wim_file_name_offset; + u32 wim_file_name_offset; /* Type of WIM file: WIM_BOOT_OS_WIM or WIM_BOOT_NOT_OS_WIM. */ - uint32_t wim_type; + u32 wim_type; - /* Index of the backing image in the WIM??? (This doesn't really make - * sense, since WIM files combine streams for all images into a single - * table.) */ - uint32_t wim_index; + /* Index of the image in the WIM to use??? (This doesn't really make + * sense, since WIM files combine file data "blobs" for all images into + * a single table. Set to 1 if unsure...) */ + u32 wim_index; /* 0 when WIM provider active, otherwise * WIM_PROVIDER_EXTERNAL_FLAG_NOT_ACTIVE or * WIM_PROVIDER_EXTERNAL_FLAG_SUSPENDED. */ - uint32_t flags; + u32 flags; /* Full path to the WIM in the NT device namespace, e.g. * "\Device\HardDiskVolume2\test.wim". Seems to be null-terminated, @@ -259,8 +490,8 @@ struct wim_provider_add_overlay_input { #define WIM_BOOT_NOT_OS_WIM 1 /* Index of the image in the WIM to use??? (This doesn't really make - * sense, since WIM files combine streams for all images into a single - * table. Set to 1 if unsure...) */ + * sense, since WIM files combine file data "blobs" for all images into + * a single table. Set to 1 if unsure...) */ u32 wim_index; /* Byte offset of wim_file_name in this buffer, not including the