1 /*-
2 * Copyright (c) 2009 Michihiro NAKAJIMA
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "archive_platform.h"
27
28 #ifdef HAVE_ERRNO_H
29 #include <errno.h>
30 #endif
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34
35 #include "archive.h"
36 #include "archive_endian.h"
37 #include "archive_private.h"
38 #include "archive_read_private.h"
39
40 struct rpm {
41 int64_t total_in;
42 uint64_t hpos;
43 uint64_t hlen;
44 unsigned char header[16];
45 enum {
46 ST_LEAD, /* Skipping 'Lead' section. */
47 ST_HEADER, /* Reading 'Header' section;
48 * first 16 bytes. */
49 ST_HEADER_DATA, /* Skipping 'Header' section. */
50 ST_PADDING, /* Skipping padding data after the
51 * 'Header' section. */
52 ST_ARCHIVE /* Reading 'Archive' section. */
53 } state;
54 int first_header;
55 };
56 #define RPM_LEAD_SIZE 96 /* Size of 'Lead' section. */
57 #define RPM_MIN_HEAD_SIZE 16 /* Minimum size of 'Head'. */
58
59 static int rpm_bidder_bid(struct archive_read_filter_bidder *,
60 struct archive_read_filter *);
61 static int rpm_bidder_init(struct archive_read_filter *);
62
63 static ssize_t rpm_filter_read(struct archive_read_filter *,
64 const void **);
65 static int rpm_filter_close(struct archive_read_filter *);
66
67 static inline size_t rpm_limit_bytes(uint64_t, size_t);
68
69 #if ARCHIVE_VERSION_NUMBER < 4000000
70 /* Deprecated; remove in libarchive 4.0 */
71 int
archive_read_support_compression_rpm(struct archive * a)72 archive_read_support_compression_rpm(struct archive *a)
73 {
74 return archive_read_support_filter_rpm(a);
75 }
76 #endif
77
78 static const struct archive_read_filter_bidder_vtable
79 rpm_bidder_vtable = {
80 .bid = rpm_bidder_bid,
81 .init = rpm_bidder_init,
82 };
83
84 int
archive_read_support_filter_rpm(struct archive * _a)85 archive_read_support_filter_rpm(struct archive *_a)
86 {
87 struct archive_read *a = (struct archive_read *)_a;
88
89 return __archive_read_register_bidder(a, NULL, "rpm",
90 &rpm_bidder_vtable);
91 }
92
93 static int
rpm_bidder_bid(struct archive_read_filter_bidder * self,struct archive_read_filter * filter)94 rpm_bidder_bid(struct archive_read_filter_bidder *self,
95 struct archive_read_filter *filter)
96 {
97 const unsigned char *b;
98 ssize_t avail;
99 int bits_checked;
100
101 (void)self; /* UNUSED */
102
103 b = __archive_read_filter_ahead(filter, 8, &avail);
104 if (b == NULL)
105 return (0);
106
107 bits_checked = 0;
108 /*
109 * Verify Header Magic Bytes : 0XED 0XAB 0XEE 0XDB
110 */
111 if (memcmp(b, "\xED\xAB\xEE\xDB", 4) != 0)
112 return (0);
113 bits_checked += 32;
114 /*
115 * Check major version.
116 */
117 if (b[4] != 3 && b[4] != 4)
118 return (0);
119 bits_checked += 8;
120 /*
121 * Check package type; binary or source.
122 */
123 if (b[6] != 0)
124 return (0);
125 bits_checked += 8;
126 if (b[7] != 0 && b[7] != 1)
127 return (0);
128 bits_checked += 8;
129
130 return (bits_checked);
131 }
132
133 static const struct archive_read_filter_vtable
134 rpm_reader_vtable = {
135 .read = rpm_filter_read,
136 .close = rpm_filter_close,
137 };
138
139 static int
rpm_bidder_init(struct archive_read_filter * self)140 rpm_bidder_init(struct archive_read_filter *self)
141 {
142 struct rpm *rpm;
143
144 self->code = ARCHIVE_FILTER_RPM;
145 self->name = "rpm";
146
147 rpm = calloc(1, sizeof(*rpm));
148 if (rpm == NULL) {
149 archive_set_error(&self->archive->archive, ENOMEM,
150 "Can't allocate data for rpm");
151 return (ARCHIVE_FATAL);
152 }
153
154 self->data = rpm;
155 rpm->state = ST_LEAD;
156 self->vtable = &rpm_reader_vtable;
157
158 return (ARCHIVE_OK);
159 }
160
161 static inline size_t
rpm_limit_bytes(uint64_t bytes,size_t max)162 rpm_limit_bytes(uint64_t bytes, size_t max)
163 {
164 return (bytes > max ? max : (size_t)bytes);
165 }
166
167 static ssize_t
rpm_filter_read(struct archive_read_filter * self,const void ** buff)168 rpm_filter_read(struct archive_read_filter *self, const void **buff)
169 {
170 struct rpm *rpm;
171 const unsigned char *b;
172 ssize_t avail_in, total, used;
173 size_t n;
174 uint64_t section;
175 uint64_t bytes;
176
177 rpm = (struct rpm *)self->data;
178 *buff = NULL;
179 total = avail_in = 0;
180 b = NULL;
181 used = 0;
182 do {
183 if (b == NULL) {
184 b = __archive_read_filter_ahead(self->upstream, 1,
185 &avail_in);
186 if (b == NULL) {
187 if (avail_in < 0)
188 return (ARCHIVE_FATAL);
189 else
190 break;
191 }
192 }
193
194 switch (rpm->state) {
195 case ST_LEAD:
196 if (rpm->total_in + avail_in < RPM_LEAD_SIZE)
197 used += avail_in;
198 else {
199 n = (size_t)(RPM_LEAD_SIZE - rpm->total_in);
200 used += n;
201 b += n;
202 rpm->state = ST_HEADER;
203 rpm->hpos = 0;
204 rpm->hlen = 0;
205 rpm->first_header = 1;
206 }
207 break;
208 case ST_HEADER:
209 n = rpm_limit_bytes(RPM_MIN_HEAD_SIZE - rpm->hpos,
210 avail_in - used);
211 memcpy(rpm->header+rpm->hpos, b, n);
212 b += n;
213 used += n;
214 rpm->hpos += n;
215
216 if (rpm->hpos == RPM_MIN_HEAD_SIZE) {
217 if (rpm->header[0] != 0x8e ||
218 rpm->header[1] != 0xad ||
219 rpm->header[2] != 0xe8 ||
220 rpm->header[3] != 0x01) {
221 if (rpm->first_header) {
222 archive_set_error(
223 &self->archive->archive,
224 ARCHIVE_ERRNO_FILE_FORMAT,
225 "Unrecognized rpm header");
226 return (ARCHIVE_FATAL);
227 }
228 rpm->state = ST_ARCHIVE;
229 *buff = rpm->header;
230 total = RPM_MIN_HEAD_SIZE;
231 break;
232 }
233 /* Calculate 'Header' length. */
234 section = archive_be32dec(rpm->header+8);
235 bytes = archive_be32dec(rpm->header+12);
236 rpm->hlen = rpm->hpos + section * 16 + bytes;
237 rpm->state = ST_HEADER_DATA;
238 rpm->first_header = 0;
239 }
240 break;
241 case ST_HEADER_DATA:
242 n = rpm_limit_bytes(rpm->hlen - rpm->hpos,
243 avail_in - used);
244 b += n;
245 used += n;
246 rpm->hpos += n;
247 if (rpm->hpos == rpm->hlen)
248 rpm->state = ST_PADDING;
249 break;
250 case ST_PADDING:
251 while (used < avail_in) {
252 if (*b != 0) {
253 /* Read next header. */
254 rpm->state = ST_HEADER;
255 rpm->hpos = 0;
256 rpm->hlen = 0;
257 break;
258 }
259 b++;
260 used++;
261 }
262 break;
263 case ST_ARCHIVE:
264 *buff = b;
265 total = avail_in;
266 used = avail_in;
267 break;
268 }
269 if (used == avail_in) {
270 rpm->total_in += used;
271 __archive_read_filter_consume(self->upstream, used);
272 b = NULL;
273 used = 0;
274 }
275 } while (total == 0 && avail_in > 0);
276
277 if (used > 0 && b != NULL) {
278 rpm->total_in += used;
279 __archive_read_filter_consume(self->upstream, used);
280 }
281 return (total);
282 }
283
284 static int
rpm_filter_close(struct archive_read_filter * self)285 rpm_filter_close(struct archive_read_filter *self)
286 {
287 struct rpm *rpm;
288
289 rpm = (struct rpm *)self->data;
290 free(rpm);
291
292 return (ARCHIVE_OK);
293 }
294
295