【问题标题】:Full implementation of exfat boot checksupexfat 启动检查的全面实施
【发布时间】:2021-02-20 11:34:12
【问题描述】:

尝试实施 exFAT 引导校验和,如以下 3.4 节所述:

https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification

我的代码没有产生正确的校验和。 :(

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int main ( int argc, char *argv[] )
{
/* test for filename in parameters */
if ( argc != 2 )
    {
    /* assume argv[0] has the program name */
    printf( "usage: %s filename", argv[0] );
    }
else 
    {
    /* assume argv[1] has the filename to process */
    FILE *filename = fopen( argv[1], "rb" );

    /* check that file exists */
    if ( filename == 0 )
        {
        printf( "Could not open %s\n", argv[1] );
        exit (1);
        }
    else 
        {
        unsigned char cbytes[5632];
        int ibytes = fread(cbytes, 1, sizeof(cbytes), filename);
        if (ibytes != 5632)
            {
            printf( "Can't read 5632 bytes from %s\n", argv[1] );
            exit (1);
            }
        fclose( filename );

        uint32_t chksum=0;

        for (int index = 0; index < 5632; index++)
            {
            if ((index == 106) || (index == 107) || (index == 112))
                { continue; }
            chksum = ((chksum&1) ? 0x80000000 : 0) + (chksum>>1) + cbytes[index];
            }

        printf("%8x\n", chksum);
        }
    }
}

是的,我已经检查过这个过去的问题(作者显然也永远无法获得正确的校验和)。

Calculation of exFAT checksum

谁能发现我做错了什么?

【问题讨论】:

  • 尝试unsigned char cbytes[5632];,就像 MS 页面所做的那样,链接的问题建议。
  • 它确实有所作为(输出不同的结果),但它仍然不会产生正确的值。
  • 介绍一下你真正使用的代码怎么样?您实际提供的代码似乎不是它,因为它在几个地方拼错了uint32_t
  • 您似乎假设扇区为 512 字节,但 exFAT 允许其他扇区大小。引导扇区中有一个字段表示扇区大小。
  • 正是我用gcc编译并使用的代码。我会重新检查拼写。 :) 是的,我确实假设了 512 字节扇区(我在闪存介质上从未见过其他任何东西),在这种情况下,偏移量 108 确实有 0x09(512 字节)。

标签: c


【解决方案1】:

假设有

#include <stdint.h>
typedef uint32_t u_int32_t;

出现在您的 main() 之前,我会看到您的代码存在两个主要问题:

  1. 正如我在 cmets 中已经提到的,exFAT 提供了多种扇区大小,并且校验和针对文件系统上正在使用的任何大小的扇区。这就是为什么 MS 文档中的示例代码接受指定扇区大小的参数的原因。您的代码假定扇区为 512 字节,这不仅会在使用不同扇区大小时为您提供错误的校验和,而且在这种情况下还会导致您在错误的位置写入错误数量的校验和数据。

  2. 即使为特定 exFAT 文件系统选择的扇区大小确实是 512 字节,在您的实现的 char 是有符号而不是无符号的(可能)事件中,您执行的求和与 MS 示例代码不同。最好将cbytes 简单地声明为unsigned char 的数组。或者,将其声明为(已签名)char,将元素转换为 unsigned charuint8_t 将产生等效的结果——在许多情况下,与转换为 uint32_t 的结果不同,这无论如何都不是必需的当值已经被解释为无符号时。

除了这两个(重要)因素之外,您的计算似乎等同于 MS 示例代码。

【讨论】:

  • 在继续之前,我确实想将自己描述为一个完整的 C 新手(最熟悉 perl)。根据 user58697 的建议,我已经将 cbyets 的声明更改为 unsigned(现在已编辑问题)。我无法让您的 typedef 语句起作用(如果我已经有等效语句,我也不明白它的原因)。 xftchksm.c:3:9: error: unknown type name 'uint32_t' typedef uint32_t u_int32_t; ^~~~~~~~ xftchksm.c:3:18: error: conflicting types for 'u_int32_t' typedef uint32_t u_int32_t; ^~~~~~~~~
  • 对于您的第 1 点,是的,我承认 exFat 提供了各种不同的扇区大小。在我得到一个“基本案例”工作之后,我会担心这个(有一个额外的参数)。对于第 2 点,我现在已将 cbytes 声明为 unsigned char。您(正确地)指出我不需要将 cbytes 声明为 unsigned char 转换为 u_int32_t (我得到相同的结果)。但是仍然无法获得正确的校验和。
  • @confused,特别担心您的实现抱怨 typedef,因为您报告的诊断表明无论 u_int32_t 适合您,以及为什么声明它,这并不意味着uint32_t 的含义:具有正好 32 个值位且没有填充位的无符号整数类型。我建议忘记 typedef,包括 stdint.h,只需将 u_unit32_t 的使用更改为标准 uint32_t
  • 如果在更改 cbytes 的类型的同时,它没有为您提供正确的校验和,那么您可能正在校验错误的设备(例如 /dev/sdb 而不是 /dev/sdb1,或者类似),或者 MS 示例代码不正确,但您的代码与 MS 匹配。
  • 然而,@confused,你可以考虑用更简单的(chksum &lt;&lt; 31) 替换尴尬的((chksum&amp;1) ? 0x80000000 : 0)。如果数据类型正确,应该不会有什么不同,但至少会更干净。
猜你喜欢
  • 2015-04-10
  • 1970-01-01
  • 2017-07-25
  • 1970-01-01
  • 2016-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-26
相关资源
最近更新 更多