【技术·水】浅谈Windows10的CompactOS特性
本帖最后由 Mouri_Naruto 于 2016-8-16 19:56 编辑================================注释开始================================
转载前最好告知楼主一声
感谢不离不弃的包子,zifeityzyicq和ART-Master
本技术贴原名《【水·技术】浅谈Windows 10 Build 9879的磁盘清理的System Compression》
远景地址:http://bbs.pcbeta.com/viewthread-1567726-1-1.html
================================注释结束================================
一:前言
上次,我在远景发布了《【水·技术】浅谈Windows 10 Build 9879的磁盘清理的System Compression》;
虽然文笔稚嫩(可以算黑历史了),但依旧上了远景首页
这个帖子发布了快两年了,这个世界也有了不少变化
Windows10早已从Build 9879进入到了Build 14901;
System Compression也改名为CompactOS;
Windows10下可以使用compact命令行工具;Win7/8/8.1也有Dism++可以帮你;
MSDN也公开了CompactOS的调用方法
在这样的情形下,我打算写个总结帖子
二:CompactOS原理
CompactOS是通过Windows Overlay Filter过滤驱动实现的,该过滤驱动同时也负责WIMBoot的实现
CompactOS在一般人看来如同NTFS压缩和Bitlocker加密一样是透明的
但是CompactOS可以选用压缩率更高的用于压缩WIM文件的算法,你可以使用以下算法
XPRESS4K(WIMBoot压缩算法,CompactOS默认算法;压缩率最低,速度最快)
XPRESS8K
XPRESS16K
LZX(WIM最大压缩;压缩率最高,速度最慢)
于是这也是CompactOS比只使用LZNT压缩算法的NTFS压缩压缩率更高的奥秘所在
三:如何使用CompactOS压缩
第一种途径,你可以通过Windows10开始系统自带的compact命令行工具对文件使用CompactOS压缩
这个用法只适用于Windows 10 Build 10074或更高版本
同时按下键盘上的Win和X键,出现菜单;点击命令提示符(管理员);
接下来弹出用户账户控制对话框,点是就出现了命令提示符窗口。
若安装系统时想对系统文件使用默认CompactOS算法进行全盘压缩,可以执行这样的指令:
DISM /Apply-Image /ImageFile:install.wim /Index:1/ApplyDir:D:\ /compact (D为系统盘符)
如果你要查询你的系统有没有被CompactOS,可以在管理员权限的命令提示符下输入以下命令并回车(在线系统适用)
compact /compactos:query
如果你的系统被CompactOS的话,会显示以下信息:“系统处于压缩状态。它将保持此状态,除非管理员更改它。”
如果你想要进行OSCompact的话,可以在管理员权限的命令提示符下输入以下命令并回车(在线系统适用)
compact /compactos:always
如果你要撤销OSCompact,可以在管理员权限的命令提示符下输入以下命令并回车(在线系统适用)
compact /compactos:never
如果你想单独对一个文件进行CompactOS压缩,那怎么办呢?下面举个例子
如果我要对E:\ToolKit\procexp.exe进行lzx算法的Compact压缩,我可以输入以下命令并回车(在线和离线都可以)。
compact /c /exe:lzx E:\ToolKit\procexp.exe
既然介绍了压缩,那么介绍如何解压也是不可少的。
compact /u /exe E:\ToolKit\procexp.exe
如果你的系统不符合要求,或者不习惯命令提示符操作,推荐使用Dism++。使用方法参考Dism++的相关说明,这里不再叙述。
第二种途径,通过API调用对文件进行CompactOS压缩
你可以通过DeviceIoControl传入相应IO控制码实现对文件的CompactOS压缩
SDK要求Windows 10 Build 10240及之后版本;且使用CompactOS前要
#include <winioctl.h>
而且CompactOS压缩对传入和传出的结构有要求
WOF_EXTERNAL_INFO和FILE_PROVIDER_EXTERNAL_INFO_V1这两个结构的内容要放在一个Buffer内传输
且WOF_EXTERNAL_INFO结构的内容要放在FILE_PROVIDER_EXTERNAL_INFO_V1结构内容的前面
为了方便起见,我定义了一个结构
typedef struct _WOF_FILE_EXTERNAL_BACKING_V1
{
WOF_EXTERNAL_INFO WofInfo;
FILE_PROVIDER_EXTERNAL_INFO_V1 FileProviderInfo;
} WOF_FILE_EXTERNAL_BACKING_V1, *PWOF_FILE_EXTERNAL_BACKING_V1;
FSCTL_SET_EXTERNAL_BACKING - 压缩
FSCTL_GET_EXTERNAL_BACKING - 获取压缩信息
FSCTL_DELETE_EXTERNAL_BACKING - 解压缩
PS:CompactOS压缩过的文件,如果以可写方式打开系统会自动解压缩文件(也许微软这么做是为了保证性能)
为了方便起见,我用NativeAPI对CompactOS的调用做了封装
CompactLib.h
// CompactLib By Mouri_Naruto
#pragma once
// Wof压缩算法定义
#define FILE_PROVIDER_COMPRESSION_XPRESS4K (0x00000000)
#define FILE_PROVIDER_COMPRESSION_LZX (0x00000001)
#define FILE_PROVIDER_COMPRESSION_XPRESS8K (0x00000002)
#define FILE_PROVIDER_COMPRESSION_XPRESS16K(0x00000003)
#define FILE_PROVIDER_COMPRESSION_MAXIMUM (0x00000004)
/*
对指定文件执行Wof压缩
*/
HRESULT WINAPI WofCompactFile(
_In_ HANDLE FileHandle,
_In_ DWORD CompactAlgorithm
);
/*
对指定文件执行Wof解压缩
*/
HRESULT WINAPI WofUnCompactFile(
_In_ HANDLE FileHandle
);
/*
获取指定文件的Wof压缩算法
(如果文件未压缩或者执行失败返回 -1,否则为Wof压缩算法定义值)
*/
DWORD WINAPI WofGetFileCompactAlgorithm(
_In_ HANDLE FileHandle
);
/*
对指定文件执行NTFS压缩
*/
HRESULT WINAPI NTFSCompactFile(
_In_ HANDLE FileHandle
);
/*
对指定文件执行NTFS解压缩
*/
HRESULT WINAPI NTFSUnCompactFile(
_In_ HANDLE FileHandle
);
CompactLib.cpp
// CompactLib By Mouri_Naruto
#include <Windows.h>
#include "CompactLib.h"
#ifndef NativeAPI
#define NativeAPI
#pragma comment(lib,"ntdll.lib")
#define NT_SUCCESS(status) ((NTSTATUS)(status) >= 0)
typedef struct _IO_STATUS_BLOCK
{
union
{
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
typedef VOID(NTAPI *PIO_APC_ROUTINE)(
_In_ PVOID ApcContext,
_In_ PIO_STATUS_BLOCK IoStatusBlock,
_In_ ULONG Reserved
);
extern "C"
{
NTSYSCALLAPI NTSTATUS NTAPI NtFsControlFile(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_ ULONG FsControlCode,
_In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
_In_ ULONG InputBufferLength,
_Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
_In_ ULONG OutputBufferLength
);
NTSYSAPI ULONG NTAPI RtlNtStatusToDosError(
_In_ NTSTATUS Status
);
}
#endif
#include <winioctl.h>
typedef struct _WOF_FILE_EXTERNAL_BACKING_V1
{
WOF_EXTERNAL_INFO WofInfo;
FILE_PROVIDER_EXTERNAL_INFO_V1 FileProviderInfo;
} WOF_FILE_EXTERNAL_BACKING_V1, *PWOF_FILE_EXTERNAL_BACKING_V1;
HRESULT WINAPI WofCompactFile(
_In_ HANDLE FileHandle,
_In_ DWORD CompactAlgorithm
)
{
if (WofGetFileCompactAlgorithm(FileHandle) == CompactAlgorithm)
return S_OK;
NTSTATUS status;
IO_STATUS_BLOCK IoStatus = { 0 };
WOF_FILE_EXTERNAL_BACKING_V1 WofFileInfo = { 0 };
WofFileInfo.WofInfo.Version = WOF_CURRENT_VERSION;
WofFileInfo.WofInfo.Provider = WOF_PROVIDER_FILE;
WofFileInfo.FileProviderInfo.Version = FILE_PROVIDER_CURRENT_VERSION;
WofFileInfo.FileProviderInfo.Algorithm = CompactAlgorithm;
WofFileInfo.FileProviderInfo.Flags = 0;
status = NtFsControlFile(
FileHandle, NULL, NULL, NULL, &IoStatus, FSCTL_SET_EXTERNAL_BACKING,
&WofFileInfo, sizeof(WofFileInfo), NULL, 0);
return RtlNtStatusToDosError(status);
}
HRESULT WINAPI WofUnCompactFile(
_In_ HANDLE FileHandle
)
{
NTSTATUS status;
IO_STATUS_BLOCK IoStatus = { 0 };
status = NtFsControlFile(
FileHandle, NULL, NULL, NULL, &IoStatus,
FSCTL_DELETE_EXTERNAL_BACKING, NULL, 0, NULL, 0);
return RtlNtStatusToDosError(status);
}
DWORD WINAPI WofGetFileCompactAlgorithm(
_In_ HANDLE FileHandle
)
{
NTSTATUS status;
IO_STATUS_BLOCK IoStatus = { 0 };
WOF_FILE_EXTERNAL_BACKING_V1 WofFileInfo = { 0 };
status = NtFsControlFile(
FileHandle, NULL, NULL, NULL, &IoStatus, FSCTL_GET_EXTERNAL_BACKING,
NULL, 0, &WofFileInfo, sizeof(WofFileInfo));
return !NT_SUCCESS(status) ? -1 : WofFileInfo.FileProviderInfo.Algorithm;
}
HRESULT WINAPI NTFSCompactFile(
_In_ HANDLE FileHandle
)
{
NTSTATUS status;
IO_STATUS_BLOCK IoStatus = { 0 };
USHORT Type = COMPRESSION_FORMAT_DEFAULT;
status = NtFsControlFile(
FileHandle, NULL, NULL, NULL, &IoStatus,
FSCTL_SET_COMPRESSION, &Type, sizeof(Type), NULL, 0);
return RtlNtStatusToDosError(status);
}
HRESULT WINAPI NTFSUnCompactFile(
_In_ HANDLE FileHandle
)
{
NTSTATUS status;
IO_STATUS_BLOCK IoStatus = { 0 };
USHORT Type = COMPRESSION_FORMAT_NONE;
status = NtFsControlFile(
FileHandle, NULL, NULL, NULL, &IoStatus,
FSCTL_SET_COMPRESSION, &Type, sizeof(Type), NULL, 0);
return RtlNtStatusToDosError(status);
}
四:性能影响和效果
度娘看了看,几乎都表示CompactOS基本上不会影响性能。但CompactOS易产生难整理型文件碎片,在机械硬盘上应注意。
下面附带下个人的体验
由于我使用了LZX算法,于是系统盘比以前腾出了将近一半的空间(原本占用50GB,现在25GB左右)
而且感受不到性能的损失,也许是我的CPU是E3 1230 V2,硬盘是256GB SSD的缘故吧
五:移植CompactOS特性到其他系统
前提条件系统是Windows 7/8/8.1及对应的服务器版本;而且你要使用Windows ADK 10的wofadk.sys
曾经和Dism++作者解决Dism++在Windows Vista下的兼容性问题时
发现Vista下一旦安装了wofadk驱动,bootmgr阶段会报错“启动文件证书无效”
而且你要排除Windows加载wofadk驱动前Windows需要用到的文件
详情可以参考无忧;或者你也可以使用Dism++
附:Windows10 CompactOS排除列表
(IDA打开Windows10的compact.exe命令行工具就可以找到了)
// 文件排除列表
wchar_t *FileExclusionList[] =
{
L"\\aow.wim",
L"\\boot\\bcd",
L"\\boot\\bcd.log",
L"\\boot\\bootstat.dat",
L"\\config\\drivers",
L"\\config\\drivers.log",
L"\\config\\system",
L"\\config\\system.log",
L"\\windows\\bootstat.dat",
L"\\winload.efi",
L"\\winload.efi.mui",
L"\\winload.exe",
L"\\winload.exe.mui",
L"\\winresume.efi",
L"\\winresume.efi.mui",
L"\\winresume.exe",
L"\\winresume.exe.mui"
};
// 目录排除列表
wchar_t *DirectoryExclusionList[] =
{
L"\\Backup\\",
L"\\ManifestCache\\",
L"\\Manifests\\"
};
感谢阅读,毛利于2016/8/16
不明觉厉啊。。 我也是这么觉得 C++ 好久没看了 http://www.52pojie.cn/forum-24-1.html
建议放到这里
os51 发表于 2016-8-18 10:13
http://www.52pojie.cn/forum-24-1.html
建议放到这里
建议got,谢谢
不明觉厉啊。。 不明觉厉加1。。。 搜索到了.
谢楼主.
不明觉厉啊。。
页:
[1]
2