-
Notifications
You must be signed in to change notification settings - Fork 103
Description
在内核篇第13章的第3小节“文件管理之NTFS解析”一文中,由于有网友测试反馈说该小结代码偶尔会出现定位不到存在的文件问题!经过我的排查,是由于配套代码中,多个Data Run的处理逻辑有问题!
现在为了方便大家理解修改后的源代码,我在此补充下多个Data Run的处理说明。
在NTFS文件系统中,如果数据很大的话,通常会使用Data Run来记录开辟的新空间,而且这些数据可能会不连续,所以就会出现多个Data Run的情况。
Data Run的含义分析如下:
Data Run的第一个字节分高4位和低4位。其中,高4位表示文件内容的起始簇号在Data Run List中占用的字节数。低4位表示文件内容簇数在Data Run List中占用的字节数。
Data Run的第二个字节开始表示文件内容的簇数,接着表示文件内容的起始簇号。
Data Run可以指示空间的大小以及偏移位置,例如上述中给的例子,起始簇号为:A2 59 00(10639616),数据大小为:C0 14(49172)。
现在需要补充的知识点是针对多个Data Run的,如下所示!!!
对于多个Data Run的情况,第一个Data Run的起始簇号是一个正整数,而第二个Data Run开始,起始簇号偏移是分正负的。可以根据起始簇号偏移的最高位是否来判断,若为1,则是负整数(补码表示);否则,是正整数。而且,从第二个Data Run开始,起始簇号偏移都是相对于上一个Data Run的起始簇号来说的。下面举个例子,方便大家理解。
例如,有这么一个Data Run如下所示:
31 01 FD 0A 28 21 01 AB FA 21 01 4A F5 21 01 91 C1 00
我们可以看到上面一共有4个Data Run,分别如下:
第1个Data Run
-
31 01 FD 0A 28
-
正整数:第一个Data Run的起始簇号都是正整数
-
起始簇号:28 0A FD(2624253)
-
第2个Data Run
- 21 01 AB FA
- 负整数:起始簇号偏移FA AB的最高位是1,所以是负整数(补码),所以FA AB(-1365)
- 起始簇号:相对于上一个Data Run的偏移,所以为:2624253-1365=2622888
第3个Data Run
- 21 01 4A F5
- 负整数:起始簇号偏移F5 4A的最高位是1,所以是负整数(补码),所以F5 4A(-2742)
- 起始簇号:相对于上一个Data Run的偏移,所以为:2622888-2742=2620146
第4个Data Run
- 21 01 91 C1
- 负整数:起始簇号偏移C1 91的最高位是1,所以是负整数(补码),所以C1 91(-15983)
- 起始簇号:相对于上一个Data Run的偏移,所以为:2620146-15983=2604163
配套代码修正
对该小节配套代码中的HandleAttribute_A0函数和FileContentOffset函数的Data Run处理修改为上述补充的多个Data Run处理:
计算Data Run的其实簇号代码修改为如下所示:
if (0 == llClusterOffet)
{
// 第一个Data Run
for (DWORD i = bHi; i > 0; i--)
{
liDataRunOffset.QuadPart = liDataRunOffset.QuadPart << 8;
liDataRunOffset.QuadPart = liDataRunOffset.QuadPart | lpBuffer[wAttributeOffset + wIndxOffset + dwCount + bLo + i];
}
}
else
{
// 第二个及多个Data Run
// 判断正负
if (0 != (0x80 & lpBuffer[wAttributeOffset + wIndxOffset + dwCount + bLo + bHi]))
{
// 负整数
for (DWORD i = bHi; i > 0; i--)
{
// 补码的原码=反码+1
liDataRunOffset.QuadPart = liDataRunOffset.QuadPart << 8;
liDataRunOffset.QuadPart = liDataRunOffset.QuadPart | (BYTE)(~lpBuffer[wAttributeOffset + wIndxOffset + dwCount + bLo + i]);
}
liDataRunOffset.QuadPart = liDataRunOffset.QuadPart + 1;
liDataRunOffset.QuadPart = 0 - liDataRunOffset.QuadPart;
}
else
{
// 正整数
for (DWORD i = bHi; i > 0; i--)
{
liDataRunOffset.QuadPart = liDataRunOffset.QuadPart << 8;
liDataRunOffset.QuadPart = liDataRunOffset.QuadPart | lpBuffer[wAttributeOffset + wIndxOffset + dwCount + bLo + i];
}
}
}
// 注意加上上一个Data Run的逻辑簇号(第二个Data Run可能是正整数、也可能是负整数(补码表示), 可以根据最高位是否为1来判断, 若为1, 则是负整数, 否则是正整数)
liDataRunOffset.QuadPart = llClusterOffet + liDataRunOffset.QuadPart;
llClusterOffet = liDataRunOffset.QuadPart;修改后的源码,重新上传在下面的附件中了!!!
