我正在解决创建自己的C版本unix ar的问题。现在我正在尝试创建头并将其写入文件。
最初,我使用了一个stat结构,并使用fprintf打印内容。然而,当我尝试在用这种方法打印的文件上使用ar命令时,它不起作用。有人告诉我,更好的解决方案是使用fwrite将结构直接写入文件。所以我现在正在努力实现这一点。
我试着用stat信息填充然后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看测试。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.
在第一个标题之前有一个奇怪的移位@符号。这是我编写整个文件头的代码,任何提示都将不胜感激。
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文件的结果|head-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 */
};
维基百科的文章提到,文本标题是最常用的格式:
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字符串以null结尾,null后面的内容(直到数组的长度)是垃圾。文件格式需要空格字符而不是垃圾,并且没有null。。。。
事实上,我认为你最初的指纹非常接近:
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愿意打开什么太难了,也太耗时了。