c - 使用 fwrite 将 ar_hdr 结构存储到文件

标签 c fwrite unix-ar

我正在解决创建我自己的 C 版本的 unix ar 的问题。现在我正在尝试创建标题并将其写入文件。

最初,我使用了一个 stat 结构并使用 fprintf 打印了内容。但是,当我尝试在用这种方法打印的文件上使用 ar 命令时,它不起作用。有人告诉我更好的解决方案是使用 fwrite 将结构直接写入文件。所以我现在正在尝试实现它。

我尝试填充然后用统计信息 fwrite 我的 ar_hdr 结构,但是当我写入文件时,我得到了垃圾。

更新 2:根据@fvu 的建议仅使用 fprintf。 fprintf 上的最后一项是 ar.h 中的常量 ARFMAG,我相信它与打印这两个字符相同。

void header(char *archive, char *read_file){
    struct stat sb;
    FILE *fp;

    if (stat(read_file, &sb) == -1)
        fail('s');

    fp = fopen(archive, "a");
    if (!fp)
        fail('f');

    fprintf(fp, "%-16s%-12ld%-6ld%-6ld%-8d%-10lld%s", read_file, (long)sb.st_mtimespec.tv_sec,
            (long)sb.st_uid, (long)sb.st_gid, sb.st_mode, (long long)sb.st_size, ARFMAG);

    fclose(fp);
}

我程序的测试输出现在是这样的:

!<arch>
b.txt           1359332639  502   20    33188   28        `
Appending B. shortb long b

d.txt           1359332655  502   20    33188   28        `
Appending D. shortb long b

c.txt           1359332646  502   20    33188   17        `
COpy this.

当我尝试 unix 命令时:ar -tv myfile.a

结果是:不合适的文件类型或格式

如果我用nano看test.a是这个结果

!<arch>
^@b.txt           1359332639  502   20    100644  28        `
Appending B. shortb long b

d.txt           1359332655  502   20    100644  28        `
Appending D. shortb long b

c.txt           1359332646  502   20    100644  17        `
COpy this shit.

第一个标题前有一个奇怪的 shift@ 符号。这是我编写整个文件头的代码,如有任何提示,我们将不胜感激。

char title[] = ARMAG; //constant defined in ar.h


    //open or create the output file
    sf = open(argv[2], O_WRONLY | O_CREAT | O_APPEND, perms);
    if (sf == -1)
        fail('o');  //open fail

    title_num = write(sf, title, sizeof(title));

从 od -x 文件中添加结果 |头-n 2:

0000000      3c21    7261    6863    0a3e    2e62    7874    2074    2020
0000020      2020    2020    2020    2020    3331    3935    3333    3632

最佳答案

不是你的错误的原因(见下文)但是很奇怪

struct ar_hdr d;
struct ar_hdr* bob = &d;
...
bob = malloc(sizeof(struct ar_hdr));
...
fwrite(bob, sizeof(d),1, fp);

非常复杂,我只是将所有内容都放入 d 中,仅此而已。

现在,您的 ar_hdr 看起来像这样:

 struct  ar_hdr                  /* file member header */
 {
     char    ar_name[16];        /* '/' terminated file member name */
     char    ar_date[12];        /* file member date */
     char    ar_uid[6]           /* file member user identification */
     char    ar_gid[6]           /* file member group identification */
     char    ar_mode[8]          /* file member mode (octal) */
     char    ar_size[10];        /* file member size */
     char    ar_fmag[2];         /* header trailer string */
 };

The Wikipedia article提到文本标题是最常用的格式:

Offset  Length  Name                            Format
0           16  File name                       ASCII
16          12  File modification timestamp     Decimal
28           6  Owner ID                        Decimal
34           6  Group ID                        Decimal
40           8  File mode                       Octal
48          10  File size in bytes              Decimal
58           2  File magic                      0x60 0x0A

这意味着将结构直接写入文件不是您需要做的:由各个 sprintf 生成的 C 字符串以空值终止,而空值后面的内容(直到数组的长度)是垃圾。文件格式需要空格字符而不是垃圾字符,也没有空字符....

实际上我认为您最初的 fprintf 非常接近:

fprintf(fp, "%-16s%-12ld%-6ld%-6ld%-8o%-10lld%c%c", 
    fname, (long)sb.st_mtimespec.tv_sec,
    (long)sb.st_uid, (long)sb.st_gid, sb.st_mode, (long long)sb.st_size,0x60,0xa);
  • 将 ar_name 字段填充为 16
  • ar_mode 转八进制
  • 添加了文件魔法

由于我无法在这里快速测试,可能仍然存在一些小问题,但应该非常接近。

附录:对于这种工作,一个逐字节查看文件内容的工具(如所有 linux 发行版附带的 od)和一个按字节比较两个文件的工具(如 dhex)确实是必须的,因为仅仅测试 ar 愿意打开的内容太困难且耗时。

关于c - 使用 fwrite 将 ar_hdr 结构存储到文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14656026/

相关文章:

c - 在某些平台上向文件写入字节会被交换

c++ - 将不同类型的变量写入二进制文件,然后将它们读入类变量会给出错误的值

C 不从文件加载信息(fread、fwrite)

linux - 如何将两个 "ar"静态库合并为一个?

c - 为什么 fprintf() 不写入文件?

c - 如何在C中获取数组前N个值的索引

c - XOR 加密适用于不在 Visual Studio 2017 上的代码块

c++ - 如何从 Windows 中的 session ID 获取用户名/SID?

build - 如何将具有自定义扩展名的对象添加到 cmake 库?

C 静态库无法与 librt 链接