为啥将原始字节写入分区不起作用[扇区写入]?

Posted

技术标签:

【中文标题】为啥将原始字节写入分区不起作用[扇区写入]?【英文标题】:Why does writing raw byte to a partition not working [sector writing]?为什么将原始字节写入分区不起作用[扇区写入]? 【发布时间】:2021-06-06 11:24:44 【问题描述】:

我有一个 USB 密钥,我想直接写入它的第一个扇区,但它根本不起作用。我试图为此编写一个跨平台(BSD/Linux/Windows)代码(下面的代码),但它什么也没做:

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>

int main(int argc, char * argv[])

    if(argc < 4)
    
        printf("Usage : %s src_path dst_path bytecount", argv[0]);
       

    FILE * src;
    FILE * dst;
    char buffer[512];

    int readcount;
    int writecount;

    src = fopen(argv[1], "rb");
    if(src == NULL)
    
        printf("Couldn't open file %s for reading : %s\n", argv[1], strerror(errno));
        exit(EXIT_FAILURE);
    

    dst = fopen(argv[2], "wb");
    if(dst == NULL)
    
        printf("Couldn't open file %s for writing : %s\n", argv[2], strerror(errno));
        exit(EXIT_FAILURE);
    

    readcount  = fread(buffer,  1, atoi(argv[3]), src);
    writecount = fwrite(buffer, 1, atoi(argv[3]), dst);

    fclose(src);
    fclose(dst);

    return(EXIT_SUCCESS);

因为它不起作用,我想至少我会尝试使用 posix 函数的平台特定代码,如下所示:

//same previous headers plus some extra
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>

int main(int argc, char * argv[])

    //same condition here   

    int src;
    int dst;
    char buffer[512];

    int readcount;
    int writecount;

    src = open(argv[1], O_RDONLY);
    if(src == -1)
    
        //same error message
    

    dst = open(argv[2], O_WRONLY);
    if(dst == -1)
    
        //same error message
    

    readcount  = read(src,  buffer, atoi(argv[3]));
    writecount = write(dst, buffer, atoi(argv[3]));

    close(src);
    close(dst);

    return(EXIT_SUCCESS);

它也没有工作。我不得不提一下,我在 FreeBSD 上以 sudo 的身份尝试了这两个代码,在 Windows 上以管理员身份尝试了第一个代码 因为我知道,从我发现的另一个代码中,我需要权限才能运行这个东西。

如上所述,我发现另一个代码几乎可以满足我的要求,但它位于 WIN API C++ 中(C++ 使用一些 Windows 特定指令)。不幸的是,它不仅不是跨平台的,而且我对 WIN API C++ 的了解还不够,无法制作它的跨平台 C 版本或更改它,而不是填充整个扇区或更多扇区,而是从源文件中复制足够多的内容,我想要复制到目标扇区。

[编辑]

当我在 FreeBSD 上运行我的程序时,我使用命令 sudo ./copier source.bin /dev/da0s1 436 它运行时不会告诉我发生任何错误,对于 Windows,我在管理员 cmd 中使用命令 copier.exe e:\source.bin \\.\N:(N:作为分区 N),我得到“权限被拒绝”

另外,我刚刚添加了更多指令以了解读取和写入的字节数:

printf("read %d byte(s)\n", readcount);
printf("wrote %d byte(s)\n", writecount);

我用上面的命令读取了 436 个字节,写入了 -1 个字节。至少在posix代码上。跨平台代码告诉我写入了 436 个字节,但是当我检查分区的十六进制原始数据时;什么都没有改变。

按照 Erdal Küçük 的建议,我添加了以下指令以在写入后获取错误消息:

在 Posix 代码中:

if(writecount == -1)

    printf("Couldn't write to file %s : %s\n", argv[2], strerror(errno));

在 ANSI C 代码中:

if(writecount != atoi(argv[3]))

    printf("Couldn't write to file %s : %s\n", argv[2], strerror(errno));

当我在 FreeBSD 上运行 POSIX 代码时,我收到一条错误消息

无法写入文件 /dev/da0s1:参数无效

当我在 FreeBSD 上运行跨平台代码时;错误消息根本没有出现。在 Windows 上,跨平台代码给了我一个奇怪的错误信息:

无法写入文件 \\.\N: : 没有错误

基本上它不能写但是errno不是一个错误?

Windows 告诉我 0 字节的写入位置。

【问题讨论】:

它“根本”不起作用是什么意思?您也应该检查read()write() 的返回值。即使在open() 上检查了Unixen 上的权限问题,它们也可能会告诉你一些事情。 你如何确定它不起作用?如果您怀疑某些读/写失败,那么可能需要进行一些错误检查? @ilkkachu 和@HAL9000 我使用命令sudo od -t x1 -A n path_to_file &gt; output_file 检查源和目标的输出,但它们不匹配。我将为read()write() 添加一个测试,以了解读取和写入的数量 @ilkkachu 和 @HAL9000 我添加了一些 printf 来显示 readcountwritecount 的值。它打印“read 436 byte(s)”和“wrote -1 byte(s)”。显然写作是问题所在。另外,如果我不使用 sudo 我会得到可预测的“权限被拒绝” 现在,在write 之后执行printf("%s\n", strerror(errno)) 并告诉我们结果。 【参考方案1】:

也许你应该通过运行 sudo mount 来检查设备的挂载标志。

确保主题设备安装为 r/w 而不是 ro。如果这没有帮助,我怀疑你可以通过调用 sync() 来解决这个问题

另一个相关的设计选择是通过调用 malloc() 来动态分配缓冲区,而不是使用可能导致缓冲区溢出和未定义行为的固定大小。请务必使用相应的 free() 调用来释放该内存

【讨论】:

问题是关于写入原始设备,而不是访问其文件系统。无需安装。 据我所见,我不应该挂载设备(如果我这样做,结果挂载点是一个文件夹):BSD 将其设备视为文件,所以我应该能够覆盖其中的一部分以某种方式归档。事实上,我什至用十六进制视图(命令 od)检查了文件的内容(不是挂载点)是否与 FAT32 分区相同,实际上是这样。 其他评论 - 在本网站上提供诸如此类的建议(即直接解决问题的不明确的答案)通常是一个好主意。在原始帖子下使用 cmets。这样,如果您的评论有帮助,每个人都会赢,如果没有,没有人会输。

以上是关于为啥将原始字节写入分区不起作用[扇区写入]?的主要内容,如果未能解决你的问题,请参考以下文章

磁盘分区 操作

为啥使用套接字源和多个接收器的流式查询不起作用?

通过 PrintServer 将原始 ZPL 发送到 Zebra 打印机不起作用

为啥百分号 (%) 在 crontab 中不起作用? [复制]

波形写入功能不起作用,我做错了啥?

多维动态数组,为啥不起作用?