Как проанализировать файл tar в C++

То, что я хочу сделать, загрузить .tar файл несколькими каталогами с 2 файлами каждый. Проблема, я не могу найти способ считать файл tar, на самом деле не извлекая файлы (использование tar).

Идеальное решение было бы чем-то как:

#include <easytar>

Tarfile tar("somefile.tar");
std::string currentFile, currentFileName;
for(int i=0; i<tar.size(); i++){
  file = tar.getFileText(i);
  currentFileName = tar.getFileName(i);
  // do stuff with it
}

Я, вероятно, оказываюсь перед необходимостью писать это сам, но любые идеи ценились бы..

14
задан Reinstate Monica 24 March 2010 в 02:54
поделиться

2 ответа

Я сам понял это после небольшой работы. Спецификация tar-файла фактически сообщает вам все, что вам нужно знать.

Во-первых, каждый файл начинается с 512-байтового заголовка, поэтому вы можете представить его с помощью символа [512] или символа *, указывающего где-то в вашем большом массиве символов (если у вас есть весь файл, загруженный в один массив для пример).

Заголовок выглядит так:

location  size  field
0         100   File name
100       8     File mode
108       8     Owner's numeric user ID
116       8     Group's numeric user ID
124       12    File size in bytes
136       12    Last modification time in numeric Unix time format
148       8     Checksum for header block
156       1     Link indicator (file type)
157       100   Name of linked file

Итак, если вам нужно имя файла, вы берете его прямо здесь с помощью string filename (buffer [0], 100); . Имя файла дополняется нулем, поэтому вы можете проверить, есть ли хотя бы один нуль, а затем оставить размер, если вы хотите сэкономить место.

Теперь мы хотим знать, файл это или папка. Поле «индикатор ссылки» содержит эту информацию, поэтому:

// Note that we're comparing to ascii numbers, not ints
switch(buffer[156]){
    case '0': // intentionally dropping through
    case '\0':
        // normal file
        break;
    case '1':
        // hard link
        break;
    case '2':
        // symbolic link
        break;
    case '3':
        // device file/special file
        break;
    case '4':
        // block device
        break;
    case '5':
        // directory
        break;
    case '6':
        // named pipe
        break;
}

На данный момент у нас уже есть вся необходимая информация о каталогах, но нам нужна еще одна вещь из обычных файлов: фактическое содержимое файла.

Длина файла может быть сохранена двумя разными способами: либо в виде восьмеричной строки с нулевым символом в конце, дополненной нулями или пробелами, либо в виде «кодировки base-256, которая указывается установкой старшего бита крайний левый байт числового поля ".

Числовые значения кодируются восьмеричными числами с использованием цифр ASCII с ведущими нулями. По историческим причинам следует использовать последний символ NUL или пробел.Таким образом, хотя для хранения размера файла зарезервировано 12 байтов, можно сохранить только 11 восьмеричных цифр. Это дает максимальный размер заархивированных файлов 8 гигабайт. Чтобы преодолеть это ограничение, в 2001 году компания Star ввела кодирование по основанию 256, которое указывается установкой старшего бита крайнего левого байта числового поля. GNU-tar и BSD-tar последовали этой идее. Кроме того, в версиях tar, предшествующих первому стандарту POSIX 1988 г., значения добавляются пробелами вместо нулей.

Вот как вы читаете восьмеричный формат, но я не писал код для версии base-256:

// in one function
int size_of_file = octal_string_to_int(&buffer[124], 11);

// elsewhere
int octal_string_to_int(char *current_char, unsigned int size){
    unsigned int output = 0;
    while(size > 0){
        output = output * 8 + *current_char - '0';
        current_char++;
        size--;
    }
    return output;
}

Итак, теперь у нас есть все, кроме фактического содержимого файла. Все, что нам нужно сделать, это взять следующий размер байт данных из файла tar, и у нас будет содержимое нашего файла:

// Get to the next block after the header ends
location += 512;
file_contents = new char[size];
memcpy(file_contents, &buffer[location], size);
// Go to the next block by rounding up to 512
// This isn't necessarily the most efficient way to do this,
// but it's the most obvious.
location += (int)ceil(size / 512.0)
32
ответ дан 1 December 2019 в 06:23
поделиться

Вы смотрели libtar ?

Из информации о пакете fink:

libtar-1.2-1: API для управления файлами Tar libtar - это библиотека C для управления POSIX tar-файлы. Он обрабатывает добавление и извлечение файлов в / из tar-архива. libtar предлагает следующие функции:
* Гибкий API - вы можете управлять отдельными файлами или просто {{ 1}} распаковать сразу весь архив.
* Разрешает определенные пользователем функции read () и write (), такие как zlib's gzread () и gzwrite ().
* Поддерживает форматы файлов tar POSIX 1003.1-1990 и GNU.

Не c ++ как таковой , но вы можете довольно легко связать с c ...

12
ответ дан 1 December 2019 в 06:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: