]> wimlib.net Git - wimlib/blobdiff - include/wimlib/wof.h
add System Compression support
[wimlib] / include / wimlib / wof.h
index a588a953c524301014c2e3e3a918af02c2993db4..71d97d80674a716c1b4694ea31a11ace199122f5 100644 (file)
@@ -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,226 @@ 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;
+        * also the number of 'struct WimOverlay_dat_entry_1' that follow.  */
+       le32 num_entries_1;
+
+       /* Set to number of WIMs registered;
+        * also the number of 'struct WimOverlay_dat_entry_2' that follow.  */
+       le32 num_entries_2;
+
+       /* Set to 0  */
+       le32 unknown_0x14;
+
+       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 inline void
+wof_check_structs(void)
+{
+       BUILD_BUG_ON(sizeof(struct WimOverlay_dat_header) != 24);
+       BUILD_BUG_ON(sizeof(struct WimOverlay_dat_entry_1) != 40);
+       BUILD_BUG_ON(sizeof(struct WimOverlay_dat_entry_2) != 104);
+}
 
 /*****************************************************************************
  *
@@ -110,10 +331,137 @@ 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
 };
 
+/*****************************************************************************
+ *
+ * --- FSCTL_GET_EXTERNAL_BACKING ---
+ *
+ * Get external backing information for the specified file.
+ *
+ * DeviceType: 9 (FILE_DEVICE_FILE_SYSTEM)
+ * Access:     0 (FILE_ANY_ACCESS)
+ * Function:   196
+ * Method:     0 (METHOD_BUFFERED)
+ *
+ * Input buffer: None
+ * Output buffer:  'struct wof_external_info' followed by provider-specific data
+ * ('struct wim_provider_external_info' in the case of WIM).
+ */
+#define FSCTL_GET_EXTERNAL_BACKING 0x90310
+
+/*****************************************************************************
+ *
+ * --- FSCTL_DELETE_EXTERNAL_BACKING ---
+ *
+ * Copy a file from its backing source to its volume, then disassociate it from
+ * its backing provider.
+ *
+ * DeviceType: 9 (FILE_DEVICE_FILE_SYSTEM)
+ * Access:     0 (FILE_ANY_ACCESS)
+ * Function:   197
+ * Method:     0 (METHOD_BUFFERED)
+ *
+ * Input buffer: None
+ * Output buffer: None
+ */
+#define FSCTL_DELETE_EXTERNAL_BACKING 0x90314
+
+/*****************************************************************************
+ *
+ * --- FSCTL_ENUM_EXTERNAL_BACKING ---
+ *
+ * Enumerate externally backed files on a volume.
+ *
+ * DeviceType: 9 (FILE_DEVICE_FILE_SYSTEM)
+ * Access:     0 (FILE_ANY_ACCESS)
+ * Function:   198
+ * Method:     0 (METHOD_BUFFERED)
+ *
+ * Input buffer: None
+ * Output buffer: A 16-byte buffer that receives the 128-bit file ID for the
+ * next externally backed file.
+ *
+ * The handle used may be either the volume handle or the handle for any file or
+ * directory on the volume.
+ *
+ * When all externally backed files on the volume have been enumerated, the
+ * function fails with ERROR_NO_MORE_FILES.
+ */
+#define FSCTL_ENUM_EXTERNAL_BACKING 0x90318
+
+/*****************************************************************************
+ *
+ * --- FSCTL_ENUM_OVERLAY ---
+ *
+ * Enumerates the volume's overlay sources from the specified provider.
+ *
+ * DeviceType: 9 (FILE_DEVICE_FILE_SYSTEM)
+ * Access:     0 (FILE_ANY_ACCESS)
+ * Function:   199
+ * Method:     3 (METHOD_NEITHER)
+ *
+ * Input buffer:  'struct wof_external_info' to specify the provider for which
+ * to enumerate the overlay sources.
+ *
+ * Output buffer:  Provider-specific data.  For the WIM provider, an array of
+ * 'struct wim_provider_overlay_entry'.
+ *
+ * This ioctl must be performed on the volume handle, such as \\.\C:
+ */
+#define FSCTL_ENUM_OVERLAY 0x9031F
+
+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.  */
+       u32 next_entry_offset;
+
+       u32 padding;
+
+       /* Identifier for the WIM file.  */
+       u64 data_source_id;
+
+       /* GUID of the WIM file.  */
+       u8 guid[16];
+
+       /* Byte offset of the WIM's file name from the beginning of this
+        * structure.  */
+       u32 wim_file_name_offset;
+
+       /* Type of WIM file: WIM_BOOT_OS_WIM or WIM_BOOT_NOT_OS_WIM.  */
+       u32 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...)  */
+       u32 wim_index;
+
+       /* 0 when WIM provider active, otherwise
+        * WIM_PROVIDER_EXTERNAL_FLAG_NOT_ACTIVE or
+        * WIM_PROVIDER_EXTERNAL_FLAG_SUSPENDED.  */
+       u32 flags;
+
+       /* Full path to the WIM in the NT device namespace, e.g.
+        * "\Device\HardDiskVolume2\test.wim".  Seems to be null-terminated,
+        * although you probably shouldn't assume so.  */
+       wchar_t wim_file_name[];
+};
+
+
 /*****************************************************************************
  *
  * --- FSCTL_ADD_OVERLAY ---
@@ -131,6 +479,8 @@ struct wim_provider_external_info {
  * Output buffer:  Buffer large enough to receive any information resulting from
  * the add operation.  For the WIM provider, this must be an 8 byte buffer that
  * receives the 64-bit WIM file ID.
+ *
+ * This ioctl must be performed on the volume handle, such as \\.\C:
  */
 #define FSCTL_ADD_OVERLAY 0x98330
 
@@ -142,8 +492,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
@@ -153,9 +503,73 @@ struct wim_provider_add_overlay_input {
        /* Number of bytes in wim_file_name.  */
        u32 wim_file_name_length;
 
-       /* Full path to the WIM, e.g. "\??\d:\test-wimboot.wim".
+       /* Full path to the WIM, e.g. "\??\C:\test-wimboot.wim".
         * Does NOT need to be null terminated (MS docs claim otherwise).  */
        wchar_t wim_file_name[];
 };
 
+/*****************************************************************************
+ *
+ * --- FSCTL_REMOVE_OVERLAY ---
+ *
+ * Removes an external backing source from a volume.
+ *
+ * DeviceType: 9 (FILE_DEVICE_FILE_SYSTEM)
+ * Access:     2 (FILE_WRITE_ACCESS)
+ * Function:   205
+ * Method:     0 (METHOD_BUFFERED)
+ *
+ * Input buffer:  'struct wof_external_info' followed by provider-specific data
+ * ('struct wim_provider_remove_overlay_input' in the case of WIM).
+ *
+ * Output buffer:  None
+ *
+ * This ioctl must be performed on the volume handle, such as \\.\C:
+ */
+#define FSCTL_REMOVE_OVERLAY 0x98334
+
+struct wim_provider_remove_overlay_input {
+       /* Integer ID that identifies the WIM.  */
+       u64 data_source_id;
+};
+
+
+/*****************************************************************************
+ *
+ * --- FSCTL_UPDATE_OVERLAY ---
+ *
+ * Updates an overlay source for a volume.
+ *
+ * DeviceType: 9 (FILE_DEVICE_FILE_SYSTEM)
+ * Access:     2 (FILE_WRITE_ACCESS)
+ * Function:   206
+ * Method:     0 (METHOD_BUFFERED)
+ *
+ * Input buffer:  'struct wof_external_info' followed by provider-specific data
+ * ('struct wim_provider_update_overlay_input' in the case of WIM).
+ *
+ * Output buffer:  None
+ *
+ * This ioctl must be performed on the volume handle, such as \\.\C:
+ */
+#define FSCTL_UPDATE_OVERLAY 0x98338
+
+struct wim_provider_update_overlay_input {
+       /* Integer ID that identifies the WIM data source.  */
+       u64 data_source_id;
+
+       /* Byte offset of wim_file_name in this buffer, not including the
+        * preceding 'struct wof_external_info' (should be 16).  */
+       u32 wim_file_name_offset;
+
+       /* Number of bytes in wim_file_name.  */
+       u32 wim_file_name_length;
+
+       /* Full path to the WIM, e.g. "\??\C:\test-wimboot.wim".
+        * Does NOT need to be null terminated (MS docs claim otherwise).
+        * This WIM must be renamed from the original WIM, or at least be an
+        * identical copy of it!  (Maybe the WIM's GUID field is checked.)  */
+       wchar_t wim_file_name[];
+};
+
 #endif /* _WOF_H_ */