Использование fwrite для сохранения структуры ar_hdr в файл

Я работаю над проблемой создания собственной версии unix ar для C. Прямо сейчас я пытаюсь создать заголовок и записать его в файл.

Первоначально я использовал структуру stat и распечатывал содержимое с помощью fprintf. Однако, когда я пытаюсь использовать команду ar для файла, напечатанного таким методом, это не работает. Мне сказали, что лучшим решением будет использование fwrite для записи структуры непосредственно в файл. Поэтому я сейчас пытаюсь это реализовать.

Я пытался заполнить, а затем fwrite мою структуру ar_hdr информацией о статистике, однако, когда я пишу в файл, я получаю мусор.

Обновление 2: использование только fprintf на основе рекомендаций @fvu. Последний элемент в fprintf — это константа ARFMAG из ar.h, которая, я считаю, аналогична печати двух символов.

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

person hobbes131    schedule 01.02.2013    source источник
comment
вы не можете выделить переменную без указателя, как в обновленной версии struct ar_hdr bob;. Для него уже выделено необходимое пространство, и он готов к использованию.   -  person fvu    schedule 02.02.2013
comment
@fvu спасибо за помощь. Я все еще новичок в C, и malloc очень сложен. Я удалил его, и все работает нормально, за исключением очевидного мусора.   -  person hobbes131    schedule 02.02.2013
comment
намного лучше, вы просто забыли переключить поле режима файла на восьмеричное (%-8o в строке формата, а не %-8d, которое выдает десятичное). остальное выглядит вполне разумно на первый взгляд.   -  person fvu    schedule 02.02.2013
comment
не могли бы вы добавить вывод od -x yourfilename | head -n 2 (шестнадцатеричный дамп первых 32 символов вашего файла? - этот ложный символ, скорее всего, является 0, который находится в конце строки с завершающим нулем ARMAG. write(sf, title, strlen(title)); должен позаботиться об этом.   -  person fvu    schedule 02.02.2013
comment
Вот и все, СПАСИБО! Я буду следить за этими нулевыми терминаторами.   -  person hobbes131    schedule 02.02.2013
comment
Отлично, рад, что смог помочь. И последнее замечание: в комментариях в заголовочном файле указано, что поле ar_name должно иметь символ / в качестве последнего непустого символа, и я могу подтвердить, что именно это и создает ar. Может быть, просто позаботьтесь об этой последней маленькой проблеме, чтобы быть в безопасности.   -  person fvu    schedule 02.02.2013
comment
Хороший улов, не могли бы вы просто изменить первую часть fprintf на: %-15s/   -  person hobbes131    schedule 02.02.2013
comment
Нет, вы не можете, потому что имя файла выровнено по левому краю, дополнено справа пробелами до указанной длины. Однако / должен стоять сразу после последнего символа имени файла. Просто используйте strcat(read_file,/) в качестве параметра при вызове fprintf.   -  person fvu    schedule 02.02.2013


Ответы (1)


Не причина вашей ошибки (см. ниже), но тем не менее очень странно

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'ing структуры непосредственно в файл не то, что вам нужно делать: строки C, созданные отдельными sprintf, заканчиваются нулем, и то, что стоит за нулем (до длины массив) это мусор. Формат файла требует пробелов вместо этого мусора, а также никаких нулей....

На самом деле я думаю, что ваш первоначальный 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 в восьмеричное
  • добавлена ​​файловая магия

Поскольку я не могу быстро проверить это здесь, могут быть некоторые незначительные проблемы, но это должно быть довольно близко.

Приложение: для такого рода работы инструмент для просмотра содержимого файла побайтно (например, od, который поставляется со всеми дистрибутивами Linux) и инструмент для побайтового сравнения двух файлов (например, dhex) действительно необходимы, потому что простое тестирование того, что ar хочет открыть, слишком сложно и требует много времени.

person fvu    schedule 01.02.2013
comment
Спасибо за быстрый ответ. Я использую структуру ar_hdr из ar.h, насколько я понял, это все char. lehman.cuny.edu/cgi-bin/man- cgi?ar.h+3 - person hobbes131; 02.02.2013
comment
Хм... Я понимаю, что вы имеете в виду. Однако, когда я использовал оригинальный fprintf, я смог воссоздать заголовок ar, но он не был доступен для чтения утилите ar, поэтому я не знал, что я что-то упустил. - person hobbes131; 02.02.2013
comment
На самом деле ваш оригинальный fprintf был довольно близок. Дайте мне 2 минуты, чтобы переделать мой ответ, используя вашу версию ar.h. - person fvu; 02.02.2013
comment
Спасибо. Я хотел бы знать, как сделать и то, и другое, но я открыт для реализации любого из них, если смогу заставить их работать! - person hobbes131; 02.02.2013
comment
Еще раз спасибо fvu, поищу dhex. Кажется, я не могу открыть файл, и использование diff в unix говорит, что файлы разные, но я понятия не имею, почему. - person hobbes131; 02.02.2013
comment
У меня есть еще один дополнительный вопрос к вам, если можно. Я использовал nano, чтобы открыть файл test.a, и после публикации общего заголовка файла появляется странный символ. Мне интересно, так ли это и почему. Выложу вывод и позову писать выше. - person hobbes131; 02.02.2013