Формат архивов TAR
11.1 Стандартный формат *Архивный файл tar содержит серию записей. Каждая запись содержит
RECORDSIZE байт. Хотя этот формат имеет место при пользовании
магнитной лентой, часто используются и другие носители.
Каждый заархивированный файл представлен заглавием, описывающим
файл, за которым может следовать какое-то число записей, дающих
содержание файла. В конце архивного файла может быть запись, состоящая
из двоичных нулей, и маркер конца файла. Разумная система должна
записывать нули в конец, но такая запись не предполагается при чтении
архива.
Записи могут быть разбиты на блоки для физических операций I/O.
Каждый блок из n записей (где n задана с помощью опции
'--block-size=512-размер') записывается посредством операции 'write
()'. На магнитных лентах результат этого - отдельная запись на ленте.
При записывании архива последний блок записей должен быть записан в
полном размере, и его запись должна состоять из одних нулей. При
чтении архива разумная система должна иметь дело с архивами, последний
блок которых короче остальных или который содержит ненужную информацию
после нулей.
Заголовок определен в C (см. ниже). В GNU tar это часть файла
'src/tar.h':
/* Standard Archive Format - Standard TAR - USTAR. */
/* Header block on tape.
Здесь мы используем традиционные названия DP. "block" - большая
часть материала I/O. "record" - кусок информации, с которой мы имеем
дело. Обычно много "record" помещается в "block". */
#define RECORDSIZE 512
- 177 -
#define NAMSIZ 100
#define TUNMLEN 32
#define TGNMLEN 32
#define SPARSE_EXT_HDR 21
#define SPARSE_IN_HDR 4
struct sparse
{
char offset[12];
char numbytes[12];
};
union record
{
char charptr[RECORDSIZE]
struct header
{
char arch_name[NAMSIZ];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[8];
char linkflag;
char arch_linkname[NAMSIZ];
char magic[8];
char uname[TUNMLEN];
char gname[TGNMLEN];
char devmajor[8];
char devminor[8];
/* Следующие поля были добавлены в GNU и не являются стандартными. */
char atime[12];
char ctime[12];
char offset[12];
- 178 -
char longnames[4];
/* Некоторые компиляторы сами вставляют содержимое. Но проще всегда
его вставлять! */
char pad;
struct sparse sp[SPARSE_INHDR];
char isextended;
char realsize[12]; /* истинный размер разреженного файла */
#if 0
char ending_blanks[12]; /* число нулей в конце файла, если
любое */
#endif
}
header;
struct extended-header
{
struct sparse sp[21];
char isextended;
}
ext_hdr;
};
/* Поле контрольной суммы заполняется, когда сосчитана контрольная
сумма. */
#define CHKBLANKS " " /* 8 пропусков, не нулей */
/* Поле magic заполняется этим значением, если допустимы uname и
gname, отмечающие архив, как в стандарте POSIX (сам GNU не согласован
с POSIX). */
#define TMAGIC "ustar " /* 7 символов и ноль */
/* Поле magic заполняется этим, если это элемент дампа формата GNU.
Но я полагаю, что это теперь неверно. */
#define GNUMAGIC "GNUtar " /* 7 символов и ноль */
/* Указательный флаг определяет тип файла. */
#define LF_OLDNORMAL '\0' /* нормальный дисковый файл, Unix-
- 179 -
совместимый */
#define LF_NORMAL '0' /* нормальный дисковый файл */
#define LF_LINK '1' /* указатель на предыдущий
дампированный файл */
#define LF_SYNLINK '2' /* символьный указатель */
#define LF_CHR '3' /* символьный специальный файл */
#define LF_BLK '4' /* блочный специальный файл */
#define LF_DIR '5' /* каталог */
#define LF_FIFO '6' /* специальный файл FIFO */
#define LF_CONFIG '7' /* непрерывный файл */
/* Дальнейшие типы указателей определены позже */
/* Заметьте, что стандарты допускают только прописные буквы от А до Z
для расширения, определяющего пользователя. Это значит, что определять
что-нибудь с помощью, например, '8' - плохая идея. */
/* Это элемент каталога, содержащий имена файлов, которые были в
каталоге в то время, когда был сделан дамп. */
#define LF_DUMPDIR 'D'
/* Идентифицирует NEXT файл на ленте, как имеющий длинное имя
указателя. */
#define LF_LONGLINK 'K'
/* Идентифицирует NEXT файл на ленте, как имеющий длинное имя. */
#define LF_LONGNAME 'L'
/* Это продолжение файла, который начался в другом томе. */
#define LF_MULTIVOL 'M'
/* Для хранения имен файлов, которые занимают более 100 символов. */
#define LF_NAMES 'N'
/* Это для разреженных файлов. */
#define LF_SPARSE 'S'
/* Этот файл - заголовок ленты/тома. Игнорирует его при извлечении. */
#define LF_VOLHDR 'V'
- 180 -
#if 0
/* Следующие два блока #define'ов не используются в GNU tar. */
/* В поле режима используются двоичные разряды - значения в
восьмиричных числах. */
#define TSUID 04000 /* задайте UID при выполнении */
#define TSGID 12000 /* задайте GID при выполнении */
#define TSVTX 01000 /* сохраните текст (бит). */
/* Возможности файлов */
#define TUREAD 00400 /* читать создателю */
#define TUWRITE 00200 /* записывать создателю */
#define TUEXEC 00100 /* выполнять/искать создателю */
#define TGREAD 00040 /* читать группе */
#define TGWRITE 00020 /* записывать группе */
#define TGEXEC 00010 /* выполнять/искать группе */
#define TOREAD 00004 /* читать другим */
#define TOWRITE 00002 /* записывать другим */
#define TOEXEC 00001 /* выполнять/искать другим */
#endif
/* Конец описания Стандартного Формата Архива. */
Все символы в заглавных записях представлены 8-битными символами в
локальном варианте ASCII. Все поля структуры прилегают друг к другу,
т.е. не нужно заполнять промежутки. Все символы носителя архива
хранятся смежно.
Байты, представляющие содержание файлов (после заглавной записи
каждого файла) никак не транслируются и не ограничивают представленные
символы определенным символьным множеством. В формате tar текстовые
файлы не отличаются от двоичных файлов, и трансляция содержимого
файлов не производится.
name, linkname, magic, uname and gname - заканчивающиеся нулем
символьные строки. Все остальные поля в ASCII - заполняемые нулями
- 181 -
восьмиричные числа. Каждое числовое поле ширины w содержит w-2 цифр,
пробел и ноль, за исключением size и mtime, которые не содержат нуля.
Поле field - имя файла, в котором имя кaталога предшествует имени
файла, и они разделены '/'.
FIXME: Насколько большим должно быть имя, чтобы вызвать переполнение
поля?
Поле field обеспечивает 9 бит, задающих разрешения файлам, и три
бит для задания режимов Set UID, Set GID и Save Text. Значения для
этих бит определены выше. Когда требуются специальные разрешения для
создания файла с данным режимом, и у пользователя, обновляющего файлы
в архиве, нет такого разрешения, биты режима, задающие эти специальные
разрешения, игнорируются. Режимы, которые не поддерживаются
операционной системой, обновляющие файлы из архива, игнорируются.
Неподдерживаемые режимы должны быть определены при создании или
модификации архива; разрешение группы можно скопировать с других
разрешений.
Поля uid и gid - численные идентификаторы пользователя и группы
создателя файла соответственно. Если операционная система не
предполагает таких идентификаторов, эти поля должны игнорироваться.
Поле size - размер файла в байтах; указываемые файлы архивируются с
помощью поля, заданного как ноль.
FIXME: xref Modifiers
в частности, опцию '--incremental'.
Поле mtime - модификационное время файла во время, когда он был
заархивирован. Это представление ASCII восьмиричного значения
последнего времени, когда он был модифицирован, представляемое в целом
числе секунд с 1 января 1970г. 00:00 Координационного Универсального
Времени.
Поле chksum - представление ASCII восьмиричного числа простой суммы
- 182 -
всех байт заглавной записи. Каждый 8-битный байт в заглавии
прибавляется к числу без знака, инициализированному на ноль, точность
которого должна быть не меньше семнадцати бит. При вычислении
контрольной суммы поле chksum рассматривается, как состоящее из одних
пропусков.
Поле typeflag задает тип заархивированного файла. Если реализация не
рассматривает или разрешает указанный тип, файл извлекается, как если
бы он был регулярным файлом. Если же он рассматривается и не
разрешается, tar выдает предостережение на стандартный вывод.
Поля atime и ctime используются в проведении пошаговых резервных
копирований, они сохраняют соответственно время доступа файлов и
последнее измененное время.
offset используется для опции '--multi-volume' ('-M') при создании
многотомного архива. offset - число байтов файла, которые нам нужны
для того, чтобы продолжить файл на следующую ленту.
Следующие поля были добавлены для работы с разреженными файлами.
Файл разрежен, если он содержит блоки, концы которых представлены
нулями, т.е. неиспользуемыми данными. Проверить, разрежен ли файл -
значит, посмотреть число блоков, занимаемых файлом и сравнить его с
числом символов файла: если блоков, выделяемых под файл, меньше, чем
должно выделяться под файл такого размера, то файл разреженный. Этот
метод tar использует для определения разреженного файла, и если такой
файл найден, он рассматривается отдельно от неразреженных файлов.
Разреженные файлы - часто файлы dbm или других типов базы данных,
которые имеют данные на некоторых местах и пустоту в большей части
файла. Такие файлы возникают, когда к ним применяется 'ls -l', они
могут содержать очень мало важных данных. Таким образом нежелательно,
чтобы tar производил резервное копирование этих файлов, когда много
места занято пустыми блоками, что может привести к истощению места на
диске гораздо раньше, чем надо бы. Т.ч. нужно рассматривать вопрос
таким образом, чтобы пустые блоки не записывались на ленту. Вместо
этого на ленту записывается описание разреженного файла: сколько дыр,
насколько они велики, сколько данных находится в конце дыры. Таким
- 183 -
образом файлы потенциально занимают намного меньше места на ленте, и
когда они впоследствии извлекаются, это происходит таким же образом,
как описано выше. Следующее - описание полей, используемых для работы
с разреженными файлами:
sp - массив struct sparse. Каждый struct sparse содержит две
12-символьных строки, которые представлены смещением в файл и числом
байтов, подлежащих записи в это смещение. Смещение абсолютное и не
относится к смещению предыдущего элемента массива.
Заглавие может содержать четыре struct sparse одновременно; если
нужно больше, они не сохраняются в заглавии.
Флаг isextended задается, когда нужно иметь дело с файлом. Это
значит, что этот флаг может быть установлен только при работе с
разреженным файлом, и установлен только если описание файла не
помещается на место, предназначенное для разреженных структур в
заглавии. Другими словами, нужен extended_header.
Структура extended_header используется для разреженных файлов,
которым нужно больше разреженных структур, чем может поместиться в
заглавии. Заглавие может содержать четыре таких структуры; если нужно
больше, устанавливается флаг isextended и следующая запись -
extended_header.
Каждая структура extended_header содержит массив из 21 разреженной
структуры при наличии флага isextended у заглавия. Для описания
разреженного файла может потребоваться неопределенное число таких
extended_header.
LF_NORMAL
LF_OLDNORMAL
Эти флаги представляют регулярный файл. Для совместимости со
старыми версиями tar значение typeflag LF_OLDNORMAL должно
рассматриваться как регулярный файл. Новые архивы должны
создаваться при помощи IF_NORMAL. Также, для обратной
согласованности, tar рассматривает регулярные файлы, чьи
имена заканчиваются на '/', как каталоги.
- 184 -
LF_LINK
Этот флаг представляет файл, указывающий на другой файл
любого типа, заархивированный перед ним. Такие файлы
идентифицируются в Unix с помощью файлов, имеющих то же
устройство и номер. Указываемое имя задано на поле linkname
с последним нулем.
IF_SYMLINK
Это представляет символьный указатель на другой файл.
Указываемое имя задано на поле linkname с последним нулем.
LF_CHR
LF_BLK
Представляют символьные специальные файлы и блочные
специальные файлы соответственно. В этом случае поля
devmajor и devminor содержат номера большего и меньшего
устройств. Операционная система отображает описания
устройства в собственное локальное описание или может
игнорировать элемент.
LF_DIR
Этот флаг задает каталог или подкаталог.
Имя каталога на
поле name должно заканчиваться '/'. В системах, где
заполнение диска выполняется на основе каталога, поле size
содержит максимальное число байт (которые можно привести к
ближайшей единице дискового блока), которое может содержать
каталог. Нулевое поле size не указывает такого ограничения.
Системы, не предполагающие такого ограничения, игнорируют
поле size.
LF_FIFO
Задает специальный файл FIFO. Заметьте, что архивируется
только существование файла FIFO, а не содержимое.
LF_CONFIG
Задает непрерывный файл, который отличается от обыкновенного
тем, что в операционной системе, которая его поддерживает,
- 185 -
нет пропусков. Операционные системы, не позволяющие
непрерывного размещения, рассматривают этот файл как
обыкновенный.
A...Z
Зарезервированы для реализаций клиентов. Некоторые из них
используются в модификационном формате GNU (см.ниже).
Другие значения зарезервированы для задания при будущих проверках
стандарта P1003 и не должны использоваться программой tar.
Поле magic показывает, что этот архив был выведен в форматe P1003.
Если это поле содержит TMAGIC, поля uname и gname будут содержать
представление ASCII создателя и группы файла соответственно.
Идентификаторы пользователя и группы используются скорее, чем поля uid
и gid.
11.2 Дополнения GNU к формату архива *
Формат GNU использует дополнительные типы файлов для описания новых
типов файлов архива. Они перечислены ниже.
LF_DUMPDIR
'D'
Представляет каталог и список файлов, созданный опцией
'--incremental'. Поле size дает общий размер
ассоциированного списка файлов. Каждому имени файла
предшествует или 'Y' (этот файл должен быть в архиве) или
'N' (файл - каталог, или не хранится в архиве). Каждое имя
файла заканчивается нулем. Существует дополнительный ноль
после последнего имени файла.
LF_MULTIVOL
'M'
Представляет файл, продолжающийся из другого тома
многотомного архива, созданного с помощью опции
'--multi-volume'. Начальный тип файла здесь не дается. Поле
- 186 -
size дает максимальный размер этого куска файла
(предполагается, что том не кончается до тех пор, пока файл
не записан). Поле offset дает смещение от начала файла до
того места, где начинается эта часть файла. Таким образом,
size + offset - то же самое, что начальный размер файла.
LF_SPARSE
'S'
Этот флаг показывает, что мы имеем дело с разреженным
файлом. Нужно отметить, что архивирование разреженного файла
требует специальных операций для нахождения дырок в файле,
отмечающих положения этих дырок и выявляющих число
байт данных, найденных после дырки.
LF_VOLHDR
'V'
Этот тип файла используется для того, чтобы отмечать
заглавие тома, которое было дано с помощью опции
'--label=архивная_метка'. Поле size - нулевое. Только первый
файл каждого тома архива должен иметь этот тип.
У вас могут появиться сложности при чтении архива формата GNU в
не-GNU системах, если при этом были использованы опции '--incremental'
('-G'), '--multi-volume' ('-M'), '--sparse' ('-S') или
'--label=архивная_метка'. Обычно, если tar не использует поля,
добавленные GNU, в заглавии, другие версии tar могут читать архив. В
противном случае программа tar выдает ошибку, в лучшем случае это
ошибка контрольной суммы.
11.3 Сравнение tar и cpio *
Здесь приведен перечень различий между tar и cpio. Точность этой
информации еще не проверялась. Написанию этого раздела, в основном
через обзор 1991 года, способствовали следующие люди:
Бент Бертельсен dmdata@login.dkuug.dk
Давид Хупес talgras!david
- 187 -
Гей Харрис guy@auspex.com
Кай Петцке wpp@marie.physic.tu-berlin.de
Кристен Нильсен dmdata@login.dkuug.dk
Лесли Майкшелл les@chinet.chi.il.us
FIXME: Реорганизовать следующий материал
tar работает с символьными указателями в той форме, что в BSD; cpio
же не имеет дела с символьными указателями в форме System V,
предшествовавшей SVR4, и некоторые продавцы добавляли в свои системы
символьные указатели, в то же время не давая cpio о них никакой
информации. Другие делают это, но не тем способом, каким я это делал в
Sun и который был принят AT&T (и который, я думаю, присутствует в том,
что Беркли взял из AT&T и вложил в поздний BSD - мне кажется, туда
попали мои изменения).
(SYR4 не так хорош с tar; в основном его cpio может работать с
вводом формата tar и записывать его на вывод, и , вероятно, работает с
символьными указателями. Они могут ничего не пытаться сделать для
того, чтобы усилить tar.)
cpio работает со специальными файлами, а традиционный tar - нет.
tar произошел из V7, System III, System V и BSD; cpio - из System
III, System V и позднего BSD (4.3 и позже)
Способ tar обработки множественных указателей на файл может
обрабатывать системы файлов, предполагающие 32-битные номера (так же,
как система файлов BSD); метод сpio требует от вас игры в некоторые
игры (в его "двоичный" формат, i-числа и только 16 бит, и его
"мобильный формат ASCII", 18 бит; он должен играть в игры с
полем "идентификатора системы файлов" заглавия для того, чтобы
убедиться, что идентификатор системы файлов / i-число - пара разных
файлов - всегда разные).
При способе tar обработки множественных указателей на файл на ленту
помещается только одна копия указателя, но имя, относящееся к этой
копии - единственное, которое вы можете использовать для извлечения
- 188 -
этого файла; cpios тоже кладет только одну копию каждого указателя, но
вы можете извлечь его, используя любое из имен.
>Какой тип контрольной суммы используется, и как ее сосчитать.
О формате tar и cpio см. руководства. tar использует контрольную
сумму, которая является суммой всех байт заглавия файла; cpio не
использует контрольных сумм.
>Знает ли кто-нибудь, зачем нужно было делать cpio, когда уже был
tar? Сообщите мне, пожалуйста.
cpio впервые появился в PWB/UNIX 1.0; UNIX тогда не имел ни одной
общедоступной версии tar. Я не знаю, была ли в AT&T какая-нибудь
версия tar или, может быть, люди в AT&T, создавшие cpio, вообще не
знали о нем.
Если при обновлении на ленте есть повреждения, tar останавливается в
этом месте, а cpio его перескакивает и пытается обновить остаток
файлов.
Основное различие - в синтаксисе команд и формате заглавия.
tar более ориентирован на ленты, и во всем, что разбито на блоки,
начинает работу с границы блока.
> Есть ли какие-нибудь различия в способности обновлять поврежденные
архивы (если их вообще можно восстановить)?
Теоретически это должно быть легче под tar, т.к. разбиение на блоки
позволяет находить заглавие с помощью некоторых вариаций 'dd skip=nn'.
Однако в современном cpio и вариациях есть опция поиска заглавия
следующего файла после ошибки с возможностью ресинхронизации. Но
программное обеспечение драйверов многих лент не позволяет продолжать
работу после ошибки носителя, что является единственной причиной
использования синхронизации, если файлы не меняли размеров, когда вы
записывали архив.
- 189 -
>Знает ли кто-нибудь, зачем нужно было делать cpio, когда уже был
tar? Сообщите мне, пожалуйста.
Наверно, потому, что он более эффективен с точки зрения носителей
(не разбивая все на блоки и используя только место, необходимое для
заглавия, в то время как tar всегда использует для каждого файла
минимум 512 байт) и может архивировать специальные файлы.
Может, вы захотите ознакомиться с доступными альтернативами. Это
afio, GNU tar и pax, каждый из которых имеет свои расширения с
определенной обратной связью.
Разреженные файлы были определены как разреженные с помощью tar (и
их можно легко выявить, а GNU cpio их вообще не читает).