Макс Лапшин (levgem) wrote,
Макс Лапшин
levgem

Category:

RPM

Я осилил самостоятельную генерацию каталога в rpm без тулзы rpm что бы можно было собирать rpm прям из под макоси.

Работающий код, который я буду допиливать до человеческого состояния.

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

Тут: http://www.rpm.org/max-rpm/s1-rpm-file-format-rpm-file-format.html есть примерное описание, которое надо прочесть если вдруг хочется что-то сделать с rpm. Описание это из серии: вот минное поле, на нём есть мины, наступать на мину нельзя, беги уже быстрее.

Дальше будет про детали.



Вкратце по терминологии



Продублирую немного то, что описано в документации.
RPM пакет состоит из 4-х частей: lead, signature, header, payload.

lead — это строго 96 байт которые описаны, там вроде никаких особенностей нет.

signature и header — это блоки с тегами, имеющие _почти_ одинаковую структуру. Почти — у них разные пространства тегов и signature обязательно надо выровнять по 16 байтам в конце.

Оба блока устроены так:

magic, index, header_values.

magic — это сначала 4 фиксированных байта 16#8e, 16#ad, 16#e8, 16#01, потом ещё 4 байта 0, потом 4 байта количество тегов и 4 байта размер в байтах header. Все числа хранятся в big endian.

index — это описание тегов (каждое по 16 байт) по количеству, указанному в magic. Теги упакованы в 16 байт (4 32-битных числа bigendian): номер тега, тип, смещение в header_values и количество (это очень плавающее число).

header_values — сами значения тегов.


payload — это cpio (который начинается 070701), опционально сжатый с помощью xz.


Это всё написано в документе по ссылке, так что перейдем уже к хитростям.


Хитрости



Tag name



В блоках signature и header используются пересекающиеся и разные пространства имен тегов. За этим надо следить внимательно.

Align


Некоторые значения тегов выравниваются. При упаковке header_values надо следить за длиной уже накопленного массива и если следующий тег — int32 или int16, то надо добить нулями до 4 или 2 байт. Это бывает нужно, если упаковывали строчку, у которой длина плавает.

Важно то, что просто выравнивать по 4 байтам те же строки нельзя. rpm перепроверяет header_value и если вы выбрали не предельно компактную упаковку значений, то rpm молча разломает внутренние структуры памяти вплоть до проезда по стеку.

Т.е. align делаем только если пишем инты.

header immutable



В signature и в header есть ужасный тег, под названием immutable. Он очень хитро записывается. Это binary размером в 16 байт и его value похож на содержимое описания в index. В самом value записан: код тега, его тип, отрицательная длина всего index (с этим тегом) и размер (16 байт). Очень путает, потому что в блоке header_values оказывается такая же запись, как и в index.

Схема его записи такая: сначала пакуем index + header_values без этого тега, потом вычисляем длину index, добавляем 16, формируем value этого тега, сам тег обязательно пишем в начало index, а его value дописываем в конец header_values.

Т.е. получается такая кошмарная конструкция. Если ошибиться хотя бы в одном байтике, rpm молча вываливается, ругаясь на попорченные внутренние структуры.

Signature



В блоке signature идёт несколько вариантов подписи содержимого. В мануале написано, что достаточно md5, но это наглая ложь. Без sha1 центос ничего ставить не будет.

md5 берется от header + payload
sha1 берется только от header.

Важное уточнение: header считается уже с magic + index + header_values.
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments