1

I'm working on a problem to create my own C version of unix ar. Right now I'm trying to create the header and write it to the file.

Initially, I used a stat struct and printed the contents using an fprintf. However, when I try to use the ar command on a file printed with such a method, it does not work. I was told that the better solution would be to use an fwrite to write the struct directly to the file. So I'm now trying to implement that.

I've tried to populate then fwrite my ar_hdr struct with the stat info, however when I write to the file, I get garbage.

Update 2: using just an fprintf based upon @fvu's recommendations. Last item on fprintf is the constant ARFMAG from ar.h which I believe is the same as printing the two characters.

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);
}

The test output of my program is now something like this:

!<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.

When I try the unix command: ar -tv myfile.a

result is: Inappropriate file type or format

If I use nano to look at test.a this is the result

!<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.

There's a weird shift@ symbol before the first header. Here's my code to write the overall file header, any hints would be appreciated.

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));

Adding results from od -x file | head -n 2:

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

1 回答 1

2

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

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 */
 };

维基百科文章提到文本标题是最常用的格式:

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愿意打开就是太难了,太费时间了。

于 2013-02-01T22:35:46.307 回答