为啥将原始字节写入分区不起作用[扇区写入]?
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 > output_file
检查源和目标的输出,但它们不匹配。我将为read()
和write()
添加一个测试,以了解读取和写入的数量
@ilkkachu 和 @HAL9000 我添加了一些 printf 来显示 readcount
和 writecount
的值。它打印“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 打印机不起作用