1

私はunixarの独自のCバージョンを作成するための問題に取り組んでいます。現在、ヘッダーを作成してファイルに書き込もうとしています。

最初は、stat構造体を使用し、fprintfを使用してコンテンツを印刷しました。しかし、そのような方法で印刷されたファイルにarコマンドを使用しようとすると、機能しません。より良い解決策は、fwriteを使用して構造体をファイルに直接書き込むことであると言われました。だから私は今それを実装しようとしています。

ar_hdr構造体に統計情報を入力してからfwriteしようとしましたが、ファイルに書き込むとガベージが発生します。

アップデート2:@fvuの推奨に基づいてfprintfのみを使用します。fprintfの最後の項目は、ar.hからの定数ARFMAGであり、2文字を印刷するのと同じだと思います。

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ファイルからの結果の追加| ヘッド-n2:

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

つまり、構造体をファイルに直接fwriteすることは、必要なことではありません。個々のsprintfによって生成されたC文字列はnullで終了し、nullの背後にあるもの(配列の長さまで)はガベージです。ファイル形式では、そのガベージの代わりにスペース文字が必要であり、nullも必要ありません...。

実際、最初の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から8進数
  • ファイルマジックを追加しました

ここではすぐにテストできないため、まだいくつかの小さな問題がある可能性がありますが、かなり近いはずです。

補遺:この種の作業では、ファイルの内容をバイトごとに確認するツール(すべてのLinuxディストリビューションに付属するodなど)と2つのファイルをバイト単位で比較するツール(dhexなど)が本当に必要です。開こうとすると、大変で時間がかかります。

于 2013-02-01T22:35:46.307 に答える