1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
.TH XPAK 5 "Oct 2011" "Portage VERSION" "Portage"
.SH NAME
xpak \- The XPAK Data Format used with Portage binary packages
.SH DESCRIPTION
Every Gentoo binary package has a xpak attached to it which contains build
time information like the USE flags it was built with, the ebuild it was
built from, the environmental variables, CFLAGS, CXXFLAGS, etc...
.SH NOTES
.SS Data Types
The following conventions cover all occurrences in this documentation
.IP Integer
All offsets/lengths are big endian unsigned 32bit integers
.IP String
All strings are ASCII encoded, and not NUL terminated (quotes are for illustration only)
.IP Values
The actual values of the individual xpak entries are stored as Strings
.P
.SS Vertical Bars
The vertical bars '|' are not part of the file format; they are merely used to
illustrate how the offset values apply to the data.
.SH SYNOPSIS
.IP "binpkg (tbz2)"
|<-xpak_offset->|
<tar>|< xpak >|<xpak_offset>"STOP"
.IP xpak
"XPAKPACK"<index_len><data_len><index><data>"XPAKSTOP"
.IP index
|<-------------index_len------------->|
|<index1><index2><index3><index4><...>|
.IP indexN
|<-name_len->|
<name_len>|< name >|<data_offset><data_len>
.IP data
|<--------------data_len------------->|
|<-dataN_offset->|<-dataN_len->|
|< data >|< data_N >|<data>|
.SH DETAILS
.SS xpak
If you look at a Gentoo binary package (binpkg) with a hex-editor you'll
notice that after the tarball of files, you find a binary blob - the
\fIxpak\fR, an offset which holds the bytes from the start of the
\fIxpak\fR to the end of the file - \fIxpak_offset\fR and finally the
String \fI"STOP"\fR.
|<xpak_offset>|
<tar>|<---xpak---->|<xpak_offset>"STOP"
Here you see the \fItar\fR archive, the attached \fIxpak\fR blob, the
\fIxpak_offset\fR and the string \fI"STOP"\fR at the end. This metadata
is not considered "part" of the \fIxpak\fR, but rather part of the binpkg.
If we read the offset value and count \fIoffset\fR bytes backwards from
the start of \fIxpak_offset\fR, we have found the start of the \fIxpak\fR
block which starts with the String \fI"XPAKPACK"\fR.
This xpak block consists of the string \fI"XPAKPACK"\fR, the length of the
\fIindex\fR block (\fIindex_len\fR), the length of the \fIdata\fR block
(\fIdata_len\fR), an \fIindex_len\fR bytes long binary blob with the
\fIindex\fR, a \fIdata_len\fR bytes long binary blob with the \fIdata\fR,
and the string \fI"XPAKSTOP"\fR at the end:
|<index_len>|<data_len>|
"XPAKPACK"<index_len><data_len>|<--index-->|<--data-->|"XPAKSTOP"
To actually get the \fIindex\fR and the \fIdata\fR, we cut out \fIindex_len\fR
bytes after the end of \fIdata_len\fR for the \fIindex\fR block, and then cut
out the next \fIdata_len\fR bytes for the \fIdata\fR block. If we have done
everything right up to this point, the following bytes would be the ASCII
formatted string \fI"XPAKSTOP"\fR.
The actual \fIdata\fR is merged into one big block; so if we want to read it,
we need the actual positions of each information in this big data block. This
information can be obtained using the indices which are stored in the
\fIindex\fR block.
.SS Index block
The \fIindex\fR block consists of several indices:
|<-----------------------index_len---------------------->|
|<index1><index2><index3><index4><index5><index6><index7>|
The \fIindex\fR block holds all the information we need to find the data we
want in the \fIdata\fR block. It consists of multiple index elements, all of
which add up to the total length \fIindex_len\fR. It is not zero delimited
or anything else.
Each of those elements corresponds to one chunk of data in the \fIdata\fR
block: the length of that block's name (\fIname_len\fR), a \fIname_len\fR
bytes long string, the offset of that block (\fIdataN_offset\fR) and the
length of that block (\fIdataN_len\fR):
|<name_len>|
<name_len>|<--name-->|<dataN_offset><dataN_len>
.SS Data block
The \fIdata\fR block contains multiple chunks of data with a total length of
\fIdata_len\fR:
|<------------------------data_len------------------------>|
|<data1><data2><data3><data4><data5><data6><data7><data...>|
To select one data element, we need the \fIdata_offset\fR and the
\fIdata_len\fR from the \fIindex\fR. With those, we can count
\fIdata_offset\fR bytes from the start of the \fIdata\fR block,
and then cut out the next \fIdata_len\fR bytes. Then we got our
data block:
|<-----dataN_offset----->|<--dataN_len->|
|<data1data2data3data...>|<data-we-want>|
.SH EXAMPLES
Let's say we have an xpak with two chunks of data. The first has the name
"file1" with the contents "ddDddDdd" and the second has the name "file2" with
the contents "jjJjjJjj". There is no \fI"STOP"\fR or \fIxpak_offset\fR as
this xpak is not part of a binpkg.
Here is the hexdump output (we will break it down line by line below):
00 58 50 41 4b 50 41 43 4b 00 00 00 20 00 00 00 10 |XPAKPACK... ....|
10 00 00 00 04 66 69 6c 31 00 00 00 00 00 00 00 08 |....fil1........|
20 00 00 00 04 66 69 6c 32 00 00 00 08 00 00 00 08 |....fil2........|
30 64 64 44 64 64 44 64 64 6a 6a 4a 6a 6a 4a 6a 6a |ddDddDddjjJjjJjj|
40 58 50 41 4b 53 54 4f 50 |XPAKSTOP|
The \fIindex_len\fR is 32 and the \fIdata_len\fR 16 (as there are 16 bytes:
"ddDddDdd" and "jjJjjJjj").
|<------"XPAKPACK"----->|| 32 | 16 |
00 58 50 41 4b 50 41 43 4b 00 00 00 20 00 00 00 10
Now we have the first index element with a \fIname_len\fR of 4, followed
by the name string "fil1", followed by the data1 offset of 0 and a data1
len of 8 (since data1 has 8 bytes: "ddDddDdd").
| 4 |<--"fil1"->||data1_off:0|data1_len:8|
10 00 00 00 04 66 69 6c 31 00 00 00 00 00 00 00 08
Now we have the second index element with a \fIname_len\fR of 4, followed
by the name string "fil2", followed by the data2 offset of 8 and a data2
len of 8 (since data2 has 8 bytes: "jjJjjJjj").
| 4 |<--"fil2"->||data2_off:8|data2_len:8|
20 00 00 00 04 66 69 6c 32 00 00 00 08 00 00 00 08
|<------"XPAKSTOP"----->|
40 58 50 41 4b 53 54 4f 50
.SH AUTHORS
.nf
Lars Hartmann <lars@chaotika.org>
Mike Frysinger <vapier@gentoo.org>
.fi
.SH "SEE ALSO"
.BR qtbz2 (1),
.BR quickpkg (1),
.BR qxpak (1)
|