exFAT校验和的计算
Calculation of exFAT checksum
我目前正在尝试使用微控制器将磁盘格式化为 exFAT。我的问题是我需要计算一个校验和,该校验和使用 VBR(卷引导区域)的扇区 1 到 11 的字节将其存储到扇区 12,但我的结果不正确。当校验和不正确时,磁盘不能被 Windows 或任何其他识别 exFAT 的 OS 使用,因为校验和已被验证,如果不正确则会发生致命错误。
这是计算 32 位校验和的函数:
uint32_t BootChecksum(char * data, long bytes){
uint32_t checksum = 0;
for (uint32_t i = 0 ; i < bytes ; i++){
if (i == 106 || i == 107 || i == 112)
continue;
checksum = ((checksum << 31) | (checksum >> 1)) + (uint32_t) data[i];
if(checksum == 0xF1924082){
printf("%02X | i = %d", checksum, i);
}
}
return checksum;
}
据我所知,函数是正确的,所以我猜测我使用的数据不正确。我只是简单地获取所需的 11 个扇区,因此每个扇区 512 字节,它会产生一个 5632 字节的数组。
我使用了类似的函数来计算条目集的校验和(16 位校验和),结果是正确的,它确实必须是数据,但我不明白我遗漏了什么那里!
哪位知道exFAT的可以帮帮我?谢谢!
我怀疑这是运算符优先级的问题。
在this page中我看到crc定义checksum
是这样修改的
checksum = (checksum<<31) | (checksum>> 1) + data[i];
也就是说,如果我没记错的话,相当于
checksum = (checksum<<31) | ((checksum>> 1) + data[i]);
因为(如果我没记错的话)加号运算符 (+
) 的优先级高于位或运算符 (|
)。
相反,你的代码是
checksum = ((checksum << 31) | (checksum >> 1)) + (uint32_t) data[i];
这是完全不同的代码,因为您首先应用按位或,然后应用加号。
我想可以和
一起工作
checksum = (checksum << 31) | ((checksum >> 1) + (uint32_t) data[i]);
p.s.: 对不起我的英语不好
---编辑 2016.06.09---
另一个问题应该是 data
的符号性。
你将data
定义为char
的指针; ntfs.com 将 data
定义为 const unsigned char
.
的数组
pointer/array 差异不是问题; const
部分并不重要(但我建议您也将 data
定义为 const
);问题(我想)是 char
到 uint32_t
的转换,如果 char
是用负值签名的,而不是 unsigned char
.
举个例子:假设你的data[i]
的值为-1;对于 (uint32_t) data[i]
,如果我没记错的话,首先 data[i]
在 int(-1)
中转换,然后在 uint32_t(-1)
中转换。所以你得到 4294967295.
如果你的 data[i]
是一个 unsigned char
,而不是 -1 data[i]
值是 255;所以(uint32_t) data[i]
首先将255转换为int(255)
,也就是255,紧接着uint32_t(255)
,剩下的就是255.
简而言之,我的建议是:改变
checksum = (checksum << 31) | ((checksum >> 1) + (uint32_t) data[i]);
在
checksum = (checksum << 31) | ((checksum >> 1) + (uint32_t) (unsigned char) data[i]);
或干脆
checksum = (checksum << 31) | ((checksum >> 1) + (unsigned char) data[i]);
我目前正在尝试使用微控制器将磁盘格式化为 exFAT。我的问题是我需要计算一个校验和,该校验和使用 VBR(卷引导区域)的扇区 1 到 11 的字节将其存储到扇区 12,但我的结果不正确。当校验和不正确时,磁盘不能被 Windows 或任何其他识别 exFAT 的 OS 使用,因为校验和已被验证,如果不正确则会发生致命错误。
这是计算 32 位校验和的函数:
uint32_t BootChecksum(char * data, long bytes){
uint32_t checksum = 0;
for (uint32_t i = 0 ; i < bytes ; i++){
if (i == 106 || i == 107 || i == 112)
continue;
checksum = ((checksum << 31) | (checksum >> 1)) + (uint32_t) data[i];
if(checksum == 0xF1924082){
printf("%02X | i = %d", checksum, i);
}
}
return checksum;
}
据我所知,函数是正确的,所以我猜测我使用的数据不正确。我只是简单地获取所需的 11 个扇区,因此每个扇区 512 字节,它会产生一个 5632 字节的数组。
我使用了类似的函数来计算条目集的校验和(16 位校验和),结果是正确的,它确实必须是数据,但我不明白我遗漏了什么那里!
哪位知道exFAT的可以帮帮我?谢谢!
我怀疑这是运算符优先级的问题。
在this page中我看到crc定义checksum
是这样修改的
checksum = (checksum<<31) | (checksum>> 1) + data[i];
也就是说,如果我没记错的话,相当于
checksum = (checksum<<31) | ((checksum>> 1) + data[i]);
因为(如果我没记错的话)加号运算符 (+
) 的优先级高于位或运算符 (|
)。
相反,你的代码是
checksum = ((checksum << 31) | (checksum >> 1)) + (uint32_t) data[i];
这是完全不同的代码,因为您首先应用按位或,然后应用加号。
我想可以和
一起工作checksum = (checksum << 31) | ((checksum >> 1) + (uint32_t) data[i]);
p.s.: 对不起我的英语不好
---编辑 2016.06.09---
另一个问题应该是 data
的符号性。
你将data
定义为char
的指针; ntfs.com 将 data
定义为 const unsigned char
.
pointer/array 差异不是问题; const
部分并不重要(但我建议您也将 data
定义为 const
);问题(我想)是 char
到 uint32_t
的转换,如果 char
是用负值签名的,而不是 unsigned char
.
举个例子:假设你的data[i]
的值为-1;对于 (uint32_t) data[i]
,如果我没记错的话,首先 data[i]
在 int(-1)
中转换,然后在 uint32_t(-1)
中转换。所以你得到 4294967295.
如果你的 data[i]
是一个 unsigned char
,而不是 -1 data[i]
值是 255;所以(uint32_t) data[i]
首先将255转换为int(255)
,也就是255,紧接着uint32_t(255)
,剩下的就是255.
简而言之,我的建议是:改变
checksum = (checksum << 31) | ((checksum >> 1) + (uint32_t) data[i]);
在
checksum = (checksum << 31) | ((checksum >> 1) + (uint32_t) (unsigned char) data[i]);
或干脆
checksum = (checksum << 31) | ((checksum >> 1) + (unsigned char) data[i]);