Last active
January 2, 2016 19:49
-
-
Save maxlapshin/8353034 to your computer and use it in GitHub Desktop.
Catalog -> rpm without librpm.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env escript | |
-mode(compile). | |
-include_lib("kernel/include/file.hrl"). | |
main(["readcpio", Path]) -> | |
dump_cpio(Path); | |
main(["show", Path]) -> | |
{ok, F} = file:open(Path, [binary, read, raw]), | |
{ok, RPMLead} = file:read(F, 96), | |
<<Magic:4/binary, Major, Minor, Type:16, Arch:16, Name0:66/binary, OS:16, SigType:16, _Reserve:16/binary>> = RPMLead, | |
<<16#ed, 16#ab, 16#ee, 16#db>> = Magic, | |
3 = Major, | |
0 = Minor, | |
0 = Type, | |
1 = OS, % Linux | |
5 = SigType, % new "Header-style" signatures | |
[Name, _] = binary:split(Name0, <<0>>), | |
io:format("[Lead] OK\n"), | |
io:format("arch: ~p, name: ~p\n", [Arch, Name]), | |
{ok, SigPos} = file:position(F, cur), | |
io:format("[Signature] OK at offset ~B\n", [SigPos]), | |
{ok, {Sig, SigData, SigLen}} = read_signatures(F), | |
io:format("signature: pad:~B, ~p\n---\n~p\n", [SigLen rem 8, Sig, SigData]), | |
file:read(F, SigLen rem 8), | |
{ok, HeaderStart} = file:position(F,cur), | |
io:format("[Header] OK at offset ~B\n", [HeaderStart]), | |
{ok, {_Entries, D, _}} = read_headers(F), | |
io:format("data: ~p\n", [D]), | |
{ok, Pos} = file:position(F,cur), | |
{ok, Eof} = file:position(F,eof), | |
io:format("Payload offset: ~B, size: ~B, signed_size: ~B, payload_size: ~B\n", [Pos, Eof - Pos, | |
Eof - HeaderStart, hd(proplists:get_value(signature_size,SigData))]), | |
{ok, HeaderBin} = file:pread(F, HeaderStart, Pos - HeaderStart), | |
{ok, PayloadStart} = file:pread(F, Pos, 40), | |
% {ok, CPIO} = file:pread(F, Pos, Eof - Pos), | |
% file:write_file("out.cpio.xz", CPIO), | |
io:format("Payload starts from: ~240p\n", [PayloadStart]), | |
{ok, Signed} = file:pread(F, HeaderStart, Eof - HeaderStart), | |
MD5_ = crypto:hash(md5, Signed), | |
MD5 = hd(proplists:get_value(md5_header, SigData)), | |
MD5_ = MD5, | |
case proplists:get_value(sha1_header, SigData) of | |
[SHA1] -> | |
SHA1_ = hex(crypto:hash(sha, [HeaderBin])), | |
io:format("SHA\n~s\n~s\n", [SHA1, SHA1_]); | |
undefined -> | |
ok | |
end, | |
% io:format("CPIO offset on pos ~B, size: ~p\n", [Pos, Eof - Pos]), | |
% {ok, C} = file:open("arch.cpio", [binary,write,raw]), | |
% {ok, Cpio} = file:pread(F, Pos, Eof - Pos), | |
% file:write(C, Cpio), | |
ok; | |
main(["write", RPM | Dirs]) when length(Dirs) > 0 -> | |
write(RPM, Dirs); | |
main([]) -> | |
io:format("show path\nwrite path dir\n"), | |
ok. | |
-record(entry, { | |
tag, | |
tag_id, | |
type, | |
offset, | |
size = 0, | |
count | |
}). | |
header_tag_to_sig(name) -> signature_size; | |
header_tag_to_sig(release) -> pgp_header; | |
header_tag_to_sig(summary) -> md5_header; | |
header_tag_to_sig(buildhost) -> signature_payloadsize; | |
header_tag_to_sig(T) -> T. | |
read_signatures(F) -> | |
{ok, {Sig0, SigData0, SigLen}} = read_headers(F), | |
Sig = [E#entry{tag = header_tag_to_sig(T)} || #entry{tag = T} = E <- Sig0], | |
SigData = [{header_tag_to_sig(T),V} || {T,V} <- SigData0], | |
{ok, {Sig, SigData, SigLen}}. | |
read_headers(F) -> | |
% {ok, 96} = file:position(F, cur), | |
{ok, <<16#8e, 16#ad, 16#e8, 16#01, 0:32, EntryCount:32, Bytes:32>>} = file:read(F, 4*4), | |
{ok, IndexPos} = file:position(F,cur), | |
{ok, IndexEntries} = file:read(F, 16*EntryCount), | |
Entries1 = read_index_entries(IndexEntries, EntryCount), | |
{ok, Data} = file:read(F, Bytes), | |
D = read_entries(Data, Entries1), | |
Entries2 = lists:zipwith(fun | |
(#entry{type = bin} = E, {_, Bin}) -> E#entry{size = iolist_size(Bin)}; | |
(#entry{type = string_array} = E, {_, Array}) -> E#entry{size = lists:sum([size(S)+1 || S <- Array])}; | |
(#entry{type = string} = E, {_, [S]}) -> E#entry{size = size(S)+1}; | |
(#entry{type = i18n_string} = E, {_, [S]}) -> E#entry{size = size(S)+1}; | |
(#entry{type = int32} = E, {_, I}) when is_integer(I) -> E#entry{size = 4}; | |
(#entry{type = int32} = E, {_, I}) when is_list(I) -> E#entry{size = 4*length(I)}; | |
(#entry{type = int16} = E, {_, I}) when is_integer(I) -> E#entry{size = 2}; | |
(#entry{type = int16} = E, {_, I}) when is_list(I) -> E#entry{size = 2*length(I)} | |
end, Entries1, D), | |
io:format("index entries (entry_count(il): ~B, byte_count(dl): ~B, offset: ~B, index_size: ~B):\n", [EntryCount, Bytes, IndexPos, 16*EntryCount]), | |
io:format("~8.. s ~8.. s ~5.. s ~20.. s [type]\n", ["offset", "next", "count", "tag(tagid)"]), | |
[io:format("~8.. B ~8.. B ~5.. B ~20.. s(~4.. B) [~p]\n", [Offset, Offset+Size, Count,Tag,TagId,Type]) || | |
#entry{tag = Tag, size = Size, tag_id = TagId, type = Type, offset = Offset, count = Count} <- Entries2], | |
io:format("\n"), | |
% Lead size + magic + reserve + entries + bytes + 16*entries | |
% BaseOffset = 96 + 4*4 + 16*EntryCount, | |
% {ok, BaseOffset} = file:position(F, cur), | |
{ok, {Entries2, D, Bytes}}. | |
read_index_entries(<<>>, 0) -> | |
[]; | |
read_index_entries(<<Tag:32, Type:32, Offset:32, Count:32, Bin/binary>>, Cnt) -> | |
% io:format("index. tag: ~p, type: ~p, offset: ~p, count: ~p, rest: ~200p\n", [read_tag(Tag), read_type(Type), Offset, Count, h(Bin)]), | |
Entry = #entry{tag = read_tag(Tag), tag_id = Tag, type = read_type(Type), offset = Offset, count = Count}, | |
[Entry|read_index_entries(Bin, Cnt-1)]. | |
% h(<<Bin:20/binary, _/binary>>) -> Bin; | |
% h(<<Bin/binary>>) -> Bin. | |
read_type(0) -> null; | |
read_type(1) -> char; | |
read_type(2) -> int8; | |
read_type(3) -> int16; | |
read_type(4) -> int32; | |
read_type(5) -> int64; | |
read_type(6) -> string; | |
read_type(7) -> bin; | |
read_type(8) -> string_array; | |
read_type(9) -> i18n_string. | |
read_tag(62) -> header_signatures; | |
read_tag(63) -> headerimmutable; | |
read_tag(100) -> headeri18ntable; | |
read_tag(268) -> rsa_header; | |
read_tag(269) -> sha1_header; | |
read_tag(1000) -> name; % size for signature | |
read_tag(1001) -> version; | |
read_tag(1002) -> release; % pgp for signature | |
read_tag(1004) -> summary; % md5 for signature | |
read_tag(1005) -> description; | |
read_tag(1006) -> buildtime; | |
read_tag(1007) -> buildhost; % this is payloadsize for signature | |
read_tag(1009) -> size; | |
read_tag(1010) -> distribution; | |
read_tag(1011) -> vendor; | |
read_tag(1014) -> license; | |
read_tag(1015) -> packager; | |
read_tag(1016) -> group; | |
read_tag(1020) -> url; | |
read_tag(1021) -> os; | |
read_tag(1022) -> arch; | |
read_tag(1028) -> filesizes; | |
read_tag(1030) -> filemodes; | |
read_tag(1033) -> filerdevs; | |
read_tag(1034) -> filemtimes; | |
read_tag(1035) -> filedigests; | |
read_tag(1036) -> filelinktos; | |
read_tag(1037) -> fileflags; | |
read_tag(1039) -> fileusername; | |
read_tag(1040) -> filegroupname; | |
read_tag(1044) -> sourcerpm; | |
read_tag(1045) -> fileverifyflags; | |
read_tag(1047) -> providename; | |
read_tag(1048) -> requireflags; | |
read_tag(1049) -> requirename; | |
read_tag(1050) -> requireversion; | |
read_tag(1064) -> rpmversion; | |
read_tag(1080) -> changelogtime; | |
read_tag(1081) -> changelogname; | |
read_tag(1082) -> changelogtext; | |
read_tag(1090) -> obsoletename; | |
read_tag(1095) -> filedevices; | |
read_tag(1096) -> fileinodes; | |
read_tag(1097) -> filelangs; | |
read_tag(1112) -> provideflags; | |
read_tag(1113) -> provideversion; | |
read_tag(1116) -> dirindexes; | |
read_tag(1117) -> basenames; | |
read_tag(1118) -> dirnames; | |
read_tag(1122) -> optflags; | |
read_tag(1124) -> payloadformat; | |
read_tag(1125) -> payloadcompressor; | |
read_tag(1126) -> payloadflags; | |
read_tag(1132) -> platform; | |
read_tag(1140) -> filecolors; | |
read_tag(1141) -> fileclass; | |
read_tag(1142) -> classdict; | |
read_tag(1143) -> filedependsx; | |
read_tag(1144) -> filedependsn; | |
read_tag(1145) -> filedependsdict; | |
read_tag(5011) -> filedigestalgo; | |
read_tag(I) -> list_to_atom(integer_to_list(I)). | |
read_entries(_F, []) -> | |
[]; | |
read_entries(F, [#entry{tag = Tag, offset = O, count = Count, type = Type}|Entries]) -> | |
Values = read_values(F, O, Type, Count), | |
[{Tag,Values}|read_entries(F, Entries)]. | |
read_values(_F, _Offset, _, 0) -> | |
[]; | |
read_values(F, Offset, int32, Count) -> | |
% {ok, <<I:32>>} = file:pread(F, Offset, 4), | |
<<_:Offset/binary, I:32, _After/binary>> = F, | |
[I|read_values(F, Offset + 4, int32, Count - 1)]; | |
read_values(F, Offset, int16, Count) -> | |
% {ok, <<I:32>>} = file:pread(F, Offset, 4), | |
<<_:Offset/binary, I:16, _After/binary>> = F, | |
[I|read_values(F, Offset + 2, int16, Count - 1)]; | |
read_values(F, Offset, string, _Count) -> | |
{EOL, 1} = binary:match(F, <<0>>, [{scope,{Offset,size(F) - Offset}}]), | |
Len = EOL - Offset, | |
<<_:Offset/binary, String:Len/binary, _/binary>> = F, | |
[String]; | |
read_values(F, _Offset, i18n_string, _Count) -> | |
[String, _] = binary:split(F, <<0>>), | |
[String]; | |
read_values(F, Offset, bin, Count) -> | |
% {ok, _Bin} = file:pread(F, Offset, Count), | |
% Bin = {bin,Offset,Count}, | |
<<_:Offset/binary, Bin:Count/binary, _/binary>> = F, | |
[Bin]; | |
read_values(F, Offset, string_array, Count) -> | |
extract_n_strings(F, Offset, Count); | |
read_values(_, _, _, _) -> | |
[unknown]. | |
extract_n_strings(_F, _Offset, 0) -> []; | |
extract_n_strings(F, Offset, Count) -> | |
{EOL, 1} = binary:match(F, <<0>>, [{scope,{Offset,size(F) - Offset}}]), | |
Len = EOL - Offset, | |
<<_:Offset/binary, String:Len/binary, _/binary>> = F, | |
[String|extract_n_strings(F, Offset + Len + 1, Count - 1)]. | |
% $$\ $$\ $$$$$$$\ $$$$$$\ $$$$$$$$\ $$$$$$$$\ | |
% $$ | $\ $$ |$$ __$$\ \_$$ _|\__$$ __|$$ _____| | |
% $$ |$$$\ $$ |$$ | $$ | $$ | $$ | $$ | | |
% $$ $$ $$\$$ |$$$$$$$ | $$ | $$ | $$$$$\ | |
% $$$$ _$$$$ |$$ __$$< $$ | $$ | $$ __| | |
% $$$ / \$$$ |$$ | $$ | $$ | $$ | $$ | | |
% $$ / \$$ |$$ | $$ |$$$$$$\ $$ | $$$$$$$$\ | |
% \__/ \__|\__| \__|\______| \__| \________| | |
% magic() -> | |
% <<16#8e, 16#ad, 16#e8, 16#01, 0:32>>. | |
write(RPMPath, Dirs0) -> | |
% It is a problem: how to store directory names. RPM requires storing them in "/etc/" and "flussonic.conf" | |
% cpio required: "etc/flussonic.conf" | |
Dirs = lists:map(fun | |
("./" ++ Dir) -> Dir; | |
("/" ++ _ = Dir) -> error({absoulte_dir_not_allowed,Dir}); | |
(Dir) -> Dir | |
end, Dirs0), | |
{match, [Name, Version, Arch]} = re:run(RPMPath, "([^-]+)-(.+)\\.([^\\.]+)\\.rpm", [{capture,all_but_first,binary}]), | |
% Need to sort files because mapFind will make bsearch to find them | |
Files = lists:sort(lists:flatmap(fun(Dir) -> list(Dir) end, Dirs)), | |
CPIO = cpio(Files), | |
Header = header([{name,Name},{version,Version},{arch,Arch},{size,iolist_size(CPIO)}], Files), | |
MD5 = crypto:hash(md5, [Header, CPIO]), | |
Signature = [ | |
{sha1_header,hex(crypto:hash(sha, [Header]))}, | |
{signature_size,iolist_size(Header) + iolist_size(CPIO)},{signature_md5,{bin,MD5}} | |
], | |
{ok, F} = file:open(RPMPath, [binary, write, raw]), | |
ok = file:write(F, rpm_lead(Name)), | |
ok = file:write(F, signatures(Signature)), | |
ok = file:write(F, Header), | |
% {ok, CpioPos} = file:position(F, cur), | |
% io:format("Write cpio at offset ~B\n", [CpioPos]), | |
ok = file:write(F, CPIO), | |
ok. | |
hex(Bin) -> | |
iolist_to_binary(string:to_lower(lists:flatten([io_lib:format("~2.16.0B", [I]) || <<I>> <= Bin]))). | |
rpm_lead(Name) -> | |
Magic = <<16#ed, 16#ab, 16#ee, 16#db>>, | |
Major = 3, | |
Minor = 0, | |
Type = 0, | |
Arch = 1, | |
OS = 1, % Linux | |
SigType = 5, % new "Header-style" signatures | |
Name0 = iolist_to_binary([Name, binary:copy(<<0>>, 66 - size(Name))]), | |
Reserve = binary:copy(<<0>>, 16), | |
Lead = <<Magic:4/binary, Major, Minor, Type:16, Arch:16, Name0:66/binary, OS:16, SigType:16, Reserve:16/binary>>, | |
96 = size(Lead), | |
Lead. | |
signatures(Headers) -> | |
{_Magic,Index0, Data0} = pack_header(Headers), | |
HeaderSign = <<0,0,0,62, 0,0,0,7, (-(iolist_size(Index0)+16)):32/signed, 0,0,0,16>>, | |
{Magic,Index, Data} = magic(length(Headers)+1, [pack_index({header_signatures,bin,iolist_size(Data0),size(HeaderSign)})|Index0], [Data0,HeaderSign]), | |
Pad = pad8(Data), | |
% io:format("Write signature index_size:~B, header_size:~B, pad:~B\n", [iolist_size(Index), iolist_size(Data), iolist_size(Pad)]), | |
[Magic, Index, [Data,Pad]]. | |
pad8(Data) -> pad(Data, 8). | |
% pad4(Data) -> pad(Data, 4). | |
pad(Data, N) -> | |
Pad = binary:copy(<<0>>, iolist_size(Data) rem N), | |
Pad. | |
list(Dir) -> | |
lists:filter(fun(Path) -> | |
{ok, #file_info{type = T}} = file:read_file_info(Path), | |
T == regular | |
end, filelib:fold_files(Dir, ".*", true, fun(P,L) -> [list_to_binary(P)|L] end, [])). | |
utc({{_Y,_Mon,_D},{_H,_Min,_S}} = DateTime) -> | |
calendar:datetime_to_gregorian_seconds(DateTime) - calendar:datetime_to_gregorian_seconds({{1970,1,1}, {0,0,0}}). | |
dump_cpio(Path) -> | |
{ok, C} = file:read_file(Path), | |
dump_cpio0(C). | |
from_b(<<Bin:8/binary>>) -> | |
list_to_integer(binary_to_list(Bin),16). | |
cpio_pad4(I) when I rem 4 == 0 -> 0; | |
cpio_pad4(I) -> 4 - (I rem 4). | |
dump_cpio0(<<>>) -> | |
ok; | |
dump_cpio0(<<"070701", Inode:8/binary, Mode:8/binary, _UID:8/binary, _GID:8/binary, Nlinks:8/binary, Mtime:8/binary, | |
Fsize:8/binary, Major:8/binary, Minor:8/binary, _RMajor:8/binary, _RMinor:8/binary, NameLen:8/binary, _Check:8/binary, | |
Rest1/binary>>) -> | |
NameLen0 = from_b(NameLen) - 1, | |
Size = from_b(Fsize), | |
Pad1 = cpio_pad4(110 + NameLen0 + 1), | |
Pad2 = cpio_pad4(Size), | |
<<Name:NameLen0/binary, 0, _:Pad1/binary, _Body:Size/binary, _:Pad2/binary, Rest2/binary>> = Rest1, | |
Meta = [{inode,from_b(Inode)},{mode,from_b(Mode)}, | |
{nlinks,from_b(Nlinks)},{mtime,from_b(Mtime)},{fsize,from_b(Fsize)},{major,from_b(Major)},{minor,from_b(Minor)},{name,Name}], | |
io:format("~240p, pad: ~p, ~p\n",[Meta, Pad1, Pad2]), | |
dump_cpio0(Rest2). | |
to_b(I) when is_integer(I) -> | |
iolist_to_binary(string:to_lower(lists:flatten(io_lib:format("~8.16.0B", [I])))). | |
cpio([]) -> | |
cpio_pack("TRAILER!!!", 0, 0, 0); | |
cpio([Path|Paths]) -> | |
{ok, #file_info{inode = Inode, size = Size, mode = Mode}} = file:read_file_info(Path), | |
Rest = cpio(Paths), | |
Pack1 = cpio_pack(<<"/", Path/binary>>, Size, Inode, Mode), | |
Pad2 = binary:copy(<<0>>, cpio_pad4(Size)), | |
{ok, Bin} = file:read_file(Path), | |
Pack1 ++ [Bin, Pad2] ++ Rest. | |
now_s() -> | |
{Mega, Sec, _} = os:timestamp(), | |
Mega*1000000 + Sec. | |
cpio_pack(Name, Size, Inode, Mode) -> | |
Nlinks = case Inode of | |
0 -> 0; | |
_ -> 1 | |
end, | |
Major = case Inode of | |
0 -> 0; | |
_ -> 263 | |
end, | |
["070701", to_b(Inode), to_b(Mode), to_b(0), to_b(0), to_b(Nlinks), to_b(now_s()), to_b(Size), to_b(Major), to_b(0), to_b(Major), to_b(0), | |
to_b(iolist_size(Name)+1), to_b(0), Name, 0, binary:copy(<<0>>, cpio_pad4(iolist_size(Name) + 1 + 110))]. | |
header(Addons, Files) -> | |
Infos = [begin | |
{ok, Info} = file:read_file_info(File), | |
Info | |
end || File <- Files], | |
Dirs0 = lists:usort([filename:dirname(F) || F <- Files]), | |
Dirs = lists:zip(Dirs0, lists:seq(0,length(Dirs0)-1)), | |
Headers = [ | |
{headeri18ntable, [<<"C">>]} | |
] ++ | |
Addons ++ | |
[ | |
{summary, <<"Video streaming server">>}, | |
{description, <<"Flussonic is a highly performant video streaming server\nwith graphical configurator, stats, reports, etc.">>}, | |
{buildtime, utc(erlang:universaltime())}, | |
{buildhost, <<"dev.flussonic.com">>}, | |
{vendor, <<"Flussonic, LLC">>}, | |
{license, <<"EULA">>}, | |
{packager, <<"Flussonic, LLC">>}, | |
{group, <<"Servers/Video">>}, | |
{url, <<"http://www.flussonic.com/">>}, | |
{os, <<"linux">>}, | |
{filesizes, [Size || #file_info{size = Size} <- Infos]}, | |
{filemodes, {int16, [Mode || #file_info{mode = Mode} <- Infos]}}, | |
{filemtimes, [utc(Mtime) || #file_info{mtime = Mtime} <- Infos]}, | |
{fileflags, [2 || _ <- Files]}, | |
{fileusername, [<<"root">> || _ <- Files]}, | |
{filegroupname, [<<"root">> || _ <- Files]}, | |
{filelinktos, [<<>> || _ <- Files]}, | |
{filerdevs, [0 || _ <- Files]}, | |
% {requirename,[<<"/bin/bash">>, <<"rpmlib(CompressedFileNames)">>, | |
% <<"rpmlib(FileDigests)">>, | |
% <<"rpmlib(PayloadFilesHavePrefix)">>, | |
% <<"rpmlib(PayloadIsXz)">>]}, | |
% {requireversion,[<<>>,<<"3.0.4-1">>,<<"4.6.0-1">>,<<"4.0-1">>,<<"5.2-1">>]}, | |
{rpmversion, <<"4.8.0">>}, | |
{fileinodes, [inode(F) || F <- Files]}, | |
{filelangs, [<<>> || _ <- Files]}, | |
{dirindexes, [proplists:get_value(filename:dirname(F),Dirs) || F <- Files]}, | |
{basenames, [filename:basename(File) || File <- Files]}, | |
{dirnames, [<<"/", Dir/binary, "/">> || {Dir, _} <- Dirs]}, | |
{payloadformat, <<"cpio">>}, | |
% {payloadcompressor, <<"xz">>}, | |
{payloadflags, <<"2">>}, | |
{platform, <<"x86_64-redhat-linux-gnu">>}, | |
{filecolors, [0 || _ <- Files]}, | |
{fileclass, [1 || _ <- Files]}, | |
{classdict, [<<>>, <<"file">>]}, | |
{filedependsx, [0 || _ <- Files]}, | |
{filedependsn, [0 || _ <- Files]}, | |
{filedigestalgo, [8]} | |
], | |
{_,Index0, Data0} = pack_header(Headers), | |
% Data1 = [Data0, align(16, iolist_size(Data0))], | |
Data1 = Data0, | |
% io:format("aligned offset of magic: ~B, ~B\n", [iolist_size(Data1), iolist_size(Data1) rem 16]), | |
Immutable = <<0,0,0,63, 0,0,0,7, (-(iolist_size(Index0)+16)):32, 0,0,0,16>>, | |
{Magic, Index, Data} = magic(length(Headers)+1, [pack_index({headerimmutable,bin,iolist_size(Data1),size(Immutable)})|Index0], [Data1,Immutable]), | |
% io:format("header. index: ~B entries, ~B bytes, data: ~B bytes\n", [length(Headers)+1, iolist_size(Index), iolist_size(Data)]), | |
[Magic, Index, Data]. | |
inode(File) -> | |
{ok, #file_info{inode = Inode}} = file:read_file_info(File), | |
Inode. | |
pack_header(Headers) -> | |
{Index, Data} = pack_header0(Headers, [], [], 0), | |
magic(length(Headers), Index, Data). | |
magic(EntryCount, Index, Data) -> | |
Bytes = iolist_size(Data), | |
Magic = <<16#8e, 16#ad, 16#e8, 16#01, 0:32, EntryCount:32, Bytes:32>>, | |
% io:format("pack magic: entries:~B, bytes:~B\n", [EntryCount, Bytes]), | |
{Magic,Index, Data}. | |
pack_header0([], Index, Data, _) -> | |
{lists:reverse([pack_index(I) || I <- Index]), lists:reverse(Data)}; | |
pack_header0([{Key,{bin,Value}}|Headers], Index, Data, Offset) when is_binary(Value) -> | |
pack_header0(Headers, [{Key,bin,Offset,size(Value)}|Index], [Value|Data], Offset + size(Value)); | |
pack_header0([{Key,Value}|Headers], Index, Data, Offset) when is_integer(Value) -> | |
Align = align(4, Offset), | |
% Align = <<>>, | |
pack_header0(Headers, [{Key,int32,Offset+size(Align),1}|Index], [<<Value:32>>, Align|Data], Offset + size(Align) + 4); | |
pack_header0([{Key,{int16, Values}}|Headers], Index, Data, Offset) -> | |
Align = align(2, Offset), | |
% Align = <<>>, | |
pack_header0(Headers, [{Key,int16,Offset+size(Align),length(Values)}|Index], [[<<V:16>> || V <- Values],Align|Data], Offset + size(Align) + 2*length(Values)); | |
pack_header0([{Key,[Value|_] = Values}|Headers], Index, Data, Offset) when is_integer(Value) -> | |
Align = align(4, Offset), | |
% Align = <<>>, | |
pack_header0(Headers, [{Key,int32,Offset+size(Align),length(Values)}|Index], [[<<V:32>> || V <- Values],Align|Data], Offset + size(Align) + 4*length(Values)); | |
pack_header0([{Key,Value}|Headers], Index, Data, Offset) when is_binary(Value) -> | |
String = <<Value/binary, 0>>, | |
Pad = <<>>, | |
pack_header0(Headers, [{Key,string,Offset,1}|Index], [Pad,String|Data], Offset + size(String)+size(Pad)); | |
pack_header0([{Key,[Value|_] = Values}|Headers], Index, Data, Offset) when is_binary(Value) -> | |
Size = lists:sum([size(V) + 1 || V <- Values]), | |
pack_header0(Headers, [{Key,string_array,Offset,length(Values)}|Index], [[<<V/binary, 0>> || V <- Values]|Data], Offset + Size). | |
align(N, Offset) when Offset rem N == 0 -> <<>>; | |
align(N, Offset) -> binary:copy(<<0>>, N - (Offset rem N)). | |
pack_index({Tag, Type, Offset, Count}) -> | |
<<(write_tag(Tag)):32, (write_type(Type)):32, Offset:32, Count:32>>. | |
write_tag(header_signatures) -> 62; | |
write_tag(headerimmutable) -> 63; | |
write_tag(headeri18ntable) -> 100; | |
write_tag(sha1_header) -> 269; | |
write_tag(signature_size) -> 1000; | |
write_tag(name) -> 1000; | |
write_tag(version) -> 1001; | |
write_tag(signature_md5) -> 1004; | |
write_tag(summary) -> 1004; | |
write_tag(description) -> 1005; | |
write_tag(buildtime) -> 1006; | |
write_tag(signature_payloadsize) -> 1007; | |
write_tag(buildhost) -> 1007; | |
write_tag(size) -> 1009; | |
write_tag(vendor) -> 1011; | |
write_tag(license) -> 1014; | |
write_tag(packager) -> 1015; | |
write_tag(group) -> 1016; | |
write_tag(url) -> 1020; | |
write_tag(os) -> 1021; | |
write_tag(arch) -> 1022; | |
write_tag(filesizes) -> 1028; | |
write_tag(filemodes) -> 1030; | |
write_tag(filerdevs) -> 1033; | |
write_tag(filemtimes) -> 1034; | |
write_tag(filelinktos) -> 1036; | |
write_tag(fileflags) -> 1037; | |
write_tag(fileusername) -> 1039; | |
write_tag(filegroupname) -> 1040; | |
write_tag(requirename) -> 1049; | |
write_tag(requireversion) -> 1050; | |
write_tag(rpmversion) -> 1064; | |
write_tag(fileinodes) -> 1096; | |
write_tag(filelangs) -> 1097; | |
write_tag(dirindexes) -> 1116; | |
write_tag(basenames) -> 1117; | |
write_tag(dirnames) -> 1118; | |
write_tag(payloadformat) -> 1124; | |
write_tag(payloadcompressor) -> 1125; | |
write_tag(payloadflags) -> 1126; | |
write_tag(platform) -> 1132; | |
write_tag(filecolors) -> 1140; | |
write_tag(fileclass) -> 1141; | |
write_tag(classdict) -> 1142; | |
write_tag(filedependsx) -> 1143; | |
write_tag(filedependsn) -> 1144; | |
write_tag(filedigestalgo) -> 5011. | |
write_type(int16) -> 3; | |
write_type(int32) -> 4; | |
write_type(bin) -> 7; | |
write_type(string_array) -> 8; | |
write_type(string) -> 6. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment