Как стать автором
Обновить

CPIO под микроскопом

Время на прочтение 4 мин
Количество просмотров 15K
cpioCPIO — это достаточно старый (1990 год), но в то же время очень удобный вариант архива. Он достаточно прост, и, возможно поэтому, получил широкое распространение. Например данный формат используют RPM, initramfs ядра Linux, а также установщик архивов «pax» от Apple.

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

Давайте на примерах рассмотрим формат этого архива.

Каждый объект файловой системы в таком архиве состоит из заголовка с базовыми метаданными, за которым следует полный путь к объекту и содержимое этого объекта. Заголовок содержит набор целочисленных значений, которые во многом повторяют поля структуры stat(2) файла в *nix системах. Конец архива помечается специальной записью (аналогичной остальным) с названием 'TRAILER!!!'.

Формат Файла.

На данный момент самым распространенным является старый формат записей файла CPIO. Именно его описание и будет приведено.

Заголовок формата записи имеет следующую структуру:

struct header_old_cpio {
	unsigned short c_magic;
	unsigned short c_dev;
	unsigned short c_ino;
	unsigned short c_mode;
	unsigned short c_uid;
	unsigned short c_gid;
	unsigned short c_nlink;
	unsigned short c_rdev;
	unsigned short c_mtime[2];
	unsigned short c_namesize;
	unsigned short c_filesize[2];
};

Здесь предполагается, что тип unsigned short имеет размер 16 бит.

c_magic
Целочисленное значение, равное 070707 (в восьмеричной СС), или 0x71c7 (в шестнадцатеричной СС). Используется для определения порядка байт (little-endian vs big-endian).

c_dev,c_ino
Номера устройства и инода (inode) с диска. Соответствуют значениям, в структуре stat. Если значение inode больше 65535, то старшие разряды будут утеряны.

c_mode
Поле одновременно определяет права доступа и тип объекта:
0170000 Маскирует биты типа файла
0140000 Сокет
0120000 Символическая ссылка. Для символических ссылок, тело ссылки будет содержать путь к файлу, на который та ссылается.
0100000 Обычный файл
0060000 Специальное блочное устройство
0040000 Каталог
0020000 Специальное символьное устройство
0010000 Именованный канал(named pipe) или очередь(FIFO).
0004000 SUID
0002000 SGID
0001000 Sticky bit.
0000777 Младшие 9 бит определяют права доступа к объекту.

c_uid,c_gid
Идентификаторы пользователя и группы владельца файла.

c_nlink
Количество ссылок на этот файл. Для каталогов значение этого поля всегда не меньше двух.

c_rdev
Только для специальных символьных и блочных устройств. Поле содержит
ассоциированный номер устройства. Для всех остальных типов файлов значение
данного поля должно быть нулевым.

c_mtime
Время последнего изменения файла. Формат соответствует количеству секунд,
прошедшего с начала эпохи UNIX. 32-битное целое записывается как массив двух
16-битных целых: сначала старшие разряды, потом младшие.

c_namesize
Длина строки полного пути к файлу включая терминальный NULL.

c_filesize
Размер файла.

Сразу за заголовком помещается полный путь к объекту. Если длина строки пути не кратна степени двойки, то в конец добавляется еще один NULL. Затем помещается содержимое файла. Если размер содержимого не кратен степени двойки, то дополняется нулями.

Пример архива.

Теперь давайте возьмем микроскоп. Я в качестве микроскопа возьму Bless. Не скажу, что мне этот hex-редактор очень нравится, но название того, который мне нравится я забыл.

Создадим простой каталог:

cpio_test
 |
 + test.txt
 |
 + testl.txt


Здесь testl.txt — это символическая ссылка на файл test.txt.
Содержимое файла test.txt:
Simple example of cpio usage.

Затем создадим архив:
$ find cpio_test | cpio -ov > example.cpio

и откроем получившийся архив в любимом hex-редакторе.

У меня этот архив выглядит так:
0000 | C7 71 09 08 9A 34 FD 41 F4 01 F4 01 02 00 00 00 | .q...4.A........
0010 | 8C 4E 09 31 0A 00 00 00 00 00 63 70 69 6F 5F 74 | .N.1......cpio_t
0020 | 65 73 74 00 C7 71 09 08 A2 34 B4 81 F4 01 F4 01 | est..q...4......
0030 | 01 00 00 00 8C 4E 09 31 13 00 00 00 1E 00 63 70 | .....N.1......cp
0040 | 69 6F 5F 74 65 73 74 2F 74 65 73 74 2E 74 78 74 | io_test/test.txt
0050 | 00 00 53 69 6D 70 6C 65 20 65 78 61 6D 70 6C 65 | ..Simple example
0060 | 20 6F 66 20 63 70 69 6F 20 75 73 61 67 65 2E 0A |  of cpio usage..
0070 | C7 71 09 08 9C 34 FF A1 F4 01 F4 01 01 00 00 00 | .q...4..........
0080 | 8C 4E 1A 2F 14 00 00 00 08 00 63 70 69 6F 5F 74 | .N./......cpio_t
0090 | 65 73 74 2F 74 65 73 74 6C 2E 74 78 74 00 74 65 | est/testl.txt.te
00A0 | 73 74 2E 74 78 74 C7 71 00 00 00 00 00 00 00 00 | st.txt.q........
00B0 | 00 00 01 00 00 00 00 00 00 00 0B 00 00 00 00 00 | ................
00C0 | 54 52 41 49 4C 45 52 21 21 21 00 00 00 00 00 00 | TRAILER!!!......


Ну что ж, давайте разбираться.

0x71c7 = 070707 — начало заголовка. И мы уже можем сказать, что порядок байт при создании архива — little-endian.
0x0809 — это c_dev — номер устройства на котором находится файл.
0x349a — это c_ino — inode. В данном случае как раз старшие разряды были утеряны.
0x41fd = 0040775 — c_mode. То есть заголовок описывает каталог с правами доступа 0775.
0x01f4 = 500 — c_uid.
0x01f4 = 500 — c_gid.
0x0002 — c_nlink. На каждый каталог существует как минимум две ссылки (. и ..)
0x0000 — c_rdev.
0x4e8c и 0x3109 — это старший и младший разряды 32-битного значения времени модификации файла. 0x31094e8c = 1317810441.
0x000a — длина имени каталога.
0x00000000 — у каталога нет тела.
Далее идет название каталога.

Затем сразу следует заголовок следующей записи. Не будем подробно на ней останавливаться — только заметим некоторые отличия:
c_mode: 0x34a2 = 0100664 — показывает, что это обычный файл с правами доступа 664.
0x0000001e — размер содержимого файла.
В остальном запись похожа не описание каталога.

Далее идет запись символической ссылки. Содержимое символической ссылки — название файла, на который она указывает. В остальном и заголовок с метаданными и путь к файлу похожи на структуры для обычного файла.

Вот таким не хитрым образом создается архив CPIO. В будущем хотелось бы в аналогичной манере рассмотреть формат файла, создаваемого Gzip. В частности при помощи связки cpio+gzip создается ramfs, используемая ядром GNU/Linux.

Надеюсь статья будет полезна.

Ссылки по теме:
Описание утилиты CPIO
Описание формата CPIO
Теги:
Хабы:
+26
Комментарии 9
Комментарии Комментарии 9

Публикации

Истории

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн