2015-04-15 6 views
-2

Мне просто был назначен проект создания инструмента архивации для unix. Таким образом, после создания программы я хотел бы сделать что-то вродеСоздание моего собственного инструмента архива в C

"./bar -c test_archive.bar file.1" 

Было бы создать test_archive.bar с file.1 внутри него. Тогда я мог бы выполнить некоторую команду, где я перечисляю файлы внутри и т. Д. И т. Д. Но у меня возникли проблемы с пониманием концепции создания test_archive.bar, я понимаю, по сути, это просто файл, но если бы вы сказали, .tgz "vi file.tgz" он предоставит список каталогов/файлов внутри,

Итак, есть ли какие-либо хорошие способы создания архива/каталога, в котором я могу экстраполировать некоторые файлы внутри и перечислить их имена и т. д.

Примечание: я просмотрел tar.c и все файлы, включенные в это, но каждый файл настолько абстрагирован, что его очень сложно выполнить.

Примечание: я знаю, как читать флаги командной строки и т.д.

+1

делает http://www.gnu.org/software/tar/manual/html_node/Standard.html помочь? – mikyra

+1

Думайте о архиве, как будто это книга. У него есть главы (файлы), которые идут в последовательности, и оглавление, в котором говорится, где начинается каждая глава и что она называется. –

+0

спасибо @mikyra, что эта ссылка помогла много – StingRay21

ответ

2

Используя формат дегтя старый (но все еще действует) на самом деле очень легко сделать. Wikipedia has a nice explanation of the format here. Все, что вам нужно сделать, это:

Для каждого файла:

  • Заполните и испускать заголовок файла дегтя
  • испускают содержимое файла
  • Pad размером файла кратному 512 байт

самый основной действительный заголовок для файла дегтя: (Скопировано из Википедии, в основном)

  • 100 байт: Имя файла
  • 8 байт: Режим файла
  • 8 байт: Владелец числовой идентификатор
  • 8 байт: Группы Числовой ID
  • 12 байт: Размер файла
  • 12 байт: TIMESTAMP последнего времени изменения
  • 8 байт: Checksum
  • 1 байт: Тип файла
  • 100 байт: Наименование связанного фил e

Тип файла может быть 0 (обычный файл), 1 (жесткая ссылка) или 2 (символическая ссылка). Имя связанного файла - это имя файла, на который указывает ссылка. Если я правильно помню, если у вас жесткая ссылка или символическая ссылка, содержимое файла должно быть пустым.

Цитирую Википедию:

«Числовые значения кодируются в восьмеричных чисел с использованием ASCII цифр, с ведущими нулями По историческим причинам, окончательное NUL или пробел должен быть использован.»

«Контрольная сумма рассчитывается путем суммирования значений без знакового байта записи заголовка с восемью байтами контрольной суммы, принятыми как ascii-пробелы (десятичное значение 32). Оно хранится как восьмеричное восьмеричное число с ведущими нулями за которым следует NUL, а затем пробел."

Вот простой генератор тарбола. Создание экстрактора, имея дело с автоматической подачей файла и т.д., остаются в качестве упражнения для читателя.

#include<stdio.h> 
#include<string.h> 


struct tar_header{ 
    char name[100]; 
    char mode[8]; 
    char owner[8]; 
    char group[8]; 
    char size[12]; 
    char modified[12]; 
    char checksum[8]; 
    char type[1]; 
    char link[100]; 
    char padding[255]; 
}; 

void fexpand(FILE* f, size_t amount, int value){ 
    while(amount--){ 
     fputc(value, f); 
    } 
} 

void tar_add(FILE* tar_file, const char* file, const char* internal_name){ 
    //Get current position; round to a multiple of 512 if we aren't there already 
    size_t index = ftell(tar_file); 
    size_t offset = index % 512; 
    if(offset != 0){ 
     fexpand(tar_file, 512 - offset, 0); 
    } 
    //Store the index for the header to return to later 
    index = ftell(tar_file); 
    //Write some space for our header 
    fexpand(tar_file, sizeof(struct tar_header), 0); 
    //Write the input file to the tar file 
    FILE* input = fopen(file, "rb"); 
    if(input == NULL){ 
     fprintf(stderr, "Failed to open %s for reading\n", file); 
     return; 
    } 
    //Copy the file content to the tar file 
    while(!feof(input)){ 
     char buffer[2000]; 
     size_t read = fread(buffer, 1, 2000, input); 
     fwrite(buffer, 1, read, tar_file); 
    } 
    //Get the end to calculate the size of the file 
    size_t end = ftell(tar_file); 
    //Round the file size to a multiple of 512 bytes 
    offset = end % 512; 
    if(end != 0){ 
     fexpand(tar_file, 512 - offset, 0); 
    } 
    //Fill out a new tar header 
    struct tar_header header; 
    memset(&header, 0, sizeof(struct tar_header)); 
    snprintf(header.name, 100, "%s", internal_name ); 
    snprintf(header.mode, 8, "%06o ", 0777); //You should probably query the input file for this info 
    snprintf(header.owner, 8, "%06o ", 0); //^ 
    snprintf(header.group, 8, "%06o ", 0); //^ 
    snprintf(header.size, 12, "%011o", end - 512 - index); 
    snprintf(header.modified, 12, "%011o ", time(0)); //Again, get this from the filesystem 
    memset(header.checksum, ' ', 8); 
    header.type[0] = '0'; 

    //Calculate the checksum 
    size_t checksum = 0; 
    int i; 
    const unsigned char* bytes = &header; 
    for(i = 0; i < sizeof(struct tar_header); ++i){ 
     checksum += bytes[i]; 
    } 

    snprintf(header.checksum, 8, "%06o ", checksum); 

    //Save the new end to return to after writing the header 
    end = ftell(tar_file); 

    //Write the header 
    fseek(tar_file, index, SEEK_SET); 
    fwrite(bytes, 1, sizeof(struct tar_header), tar_file); 

    //Return to the end 
    fseek(tar_file, end, SEEK_SET); 
    fclose(input); 
} 

int main(int argc, char* argv[]){ 
    if(argc > 1){ 
     FILE* tar = fopen(argv[1], "wb"); 
     if(!tar){ 
      fprintf(stderr, "Failed to open %s for writing\n", argv[1]); 
      return 1; 
     } 
     int i; 
     for(i = 2; i < argc; ++i){ 
      tar_add(tar, argv[i], argv[i]); 
     } 
     //Pad out the end of the tar file 
     fexpand(tar, 1024, 0); 
     fclose(tar); 
     return 0; 
    } 
    fprintf(stderr, "Please specify some file names!\n"); 
    return 0; 
} 
1

Итак, есть ли хорошие способы идти о создании архива каталога/ , в котором я могу экстраполировать некоторые файлы в их имена, и т.д ..

есть два основных подхода:

  1. Копирование содержимого файла один за другим, каждый с префиксом «заголовочный» блок, содержащий информацию о имени файла, размере и (необязательно) других атрибутах. Тар - пример этого. Пример:

  2. Скопируйте содержимое файла один за другим и поместите где-нибудь (в начале в конце) «индекс», который содержит список имен файлов с их размерами и (необязательно) другими атрибутами. Когда вы смотрите на размеры файлов, вы можете вычислить, где начинаются и заканчиваются отдельные файлы.

Большинство архиваторов реального мира используют комбинацию этих функций и добавляют другие функции, такие как контрольные суммы, сжатие и шифрование.

Пример

Предположим, что у нас есть два файла с именем hello.txtHello, World! (с указанной 12 байт) и bar.txtfoobar (с указанной 6 байт).

В первом методе, архив будет выглядеть, что

[hello.txt,12][Hello, World!][bar.txt,6][foobar] 
^- fixed size ^- 12 bytes ^- fixed size ^- 6 bytes 

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

В второй:

[Hello, World!foobar][hello.txt,12,bar.txt,6] 
^- 12+6 bytes 
+0

Отличный пример, который вы сочетаете с приведенным выше, действительно помог мне. Большое спасибо. – StingRay21

Смежные вопросы