AppxBlockMap.xml中的Block是否与MSIX包Deflate压缩块直接关联?
我正试图理解MSIX包中AppxBlockMap.xml文件定义的Block与压缩过程(尤其是ZIP格式使用的Deflate算法)之间的关系。官方MSIX文档表明,AppxBlockMap.xml中的Block对应64KB未压缩数据块,用于差分更新和完整性校验。但查看实际的AppxBlockMap.xml文件时,我发现<Block>元素的Size属性是可变的,不符合64KB标准,似乎反映的是压缩后的大小。
以下是某MSIX包中AppxBlockMap.xml文件的节选:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <BlockMap xmlns="http://schemas.microsoft.com/appx/2010/blockmap" HashMethod="http://www.w3.org/2001/04/xmlenc#sha256"> <File Name="Registry.dat" Size="8192" LfhSize="42"> <Block Hash="SujdWPx0WfMpCDMB6Ys6qrkz7utejAXDDWUE8gY/+OI=" Size="370"/> </File> <File Name="ConsoleApp2\ConsoleApp2.exe" Size="4608" LfhSize="57"> <Block Hash="odjuNrwIpr3INWyUyzc0U5er4vFA0s+YtTT0qUW0khM=" Size="1955"/> </File> <File Name="PsfLauncher32.exe" Size="419704" LfhSize="47"> <Block Hash="7nY/HTgnGs/L1e33p//FCMYqiIJvg6NqVoR771Nqm6M=" Size="33031"/> <Block Hash="z0UFVqT3NtYzK3U3G1T0oJLSW/GME2DxUYyxPCtLB5w=" Size="40610"/> <Block Hash="u97F08AaEkjfUIEnanZC+19NHwFcFTL37II5WQzXvxQ=" Size="39077"/> <!-- More blocks omitted for brevity --> </File> <!-- More files omitted for brevity --> </BlockMap>
观察到的细节:
<File>元素的Size属性(例如Registry.dat的8192)代表文件的未压缩大小。<Block>元素的Size属性(例如Registry.dat的370)差异很大,远小于64KB,这表明它可能是每个块的压缩大小。
这让我认为AppxBlockMap.xml中的Block大小可能与Deflate算法在ZIP压缩期间生成的可变大小块直接相关,而非固定的64KB未压缩数据块。但这似乎与哈希是基于64KB未压缩块计算的观点相矛盾。
核心问题
AppxBlockMap.xml中的<Block>元素是否与Deflate算法生成的压缩块直接相关,还是代表其他内容(例如固定大小的未压缩数据块)?如果它们是压缩大小,这与MSIX文档中提到的用于哈希和差分更新的64KB块如何对齐?
解答
哈希基于固定64KB未压缩块计算
官方文档的描述完全准确:MSIX的块映射会将每个文件分割为固定64KB的未压缩数据块(最后一个块如果不足64KB则取实际大小),每个<Block>的Hash值就是对应这个未压缩数据块的哈希。这一设计是为了差分更新——当文件部分内容变更时,只需传输哈希值变化的对应块;同时也用于完整性校验,确保解压后的每个未压缩块内容未被篡改。<Block>的Size属性是压缩后块的实际大小
你看到的可变Size值,是对应64KB未压缩块经过Deflate压缩后的实际字节数。Deflate算法会根据数据的冗余度生成大小不一的压缩结果,所以不同未压缩块的压缩后Size会有明显差异;对于小于64KB的小文件,其唯一的未压缩块本身就小于64KB,压缩后的Size自然更小。两者的对齐逻辑
生成AppxBlockMap.xml的流程是:
- 先将文件按64KB分割为未压缩块,计算每个块的哈希;
- 对每个未压缩块单独执行Deflate压缩,记录压缩后的字节数(即
<Block>的Size属性); - 在MSIX包中,这些压缩后的块按顺序连续存储,系统通过块映射可以快速定位每个未压缩块对应的压缩数据位置,解压后验证哈希,同时在差分更新时,对比新旧版本的块哈希,只同步哈希不同的块对应的压缩数据。
比如示例中的PsfLauncher32.exe,未压缩大小419704字节,除以64KB(65536字节)得到约6.4个块,所以会看到多个<Block>元素,每个对应一个64KB(最后一个不足64KB)的未压缩块,它们的Size是各自压缩后的实际大小。
内容的提问来源于stack exchange,提问作者SuperJMN

