archive_read_support_filter_rpm.c revision 238856
1248590Smm/*-
2248590Smm * Copyright (c) 2009 Michihiro NAKAJIMA
3248590Smm * All rights reserved.
4248590Smm *
5248590Smm * Redistribution and use in source and binary forms, with or without
6248590Smm * modification, are permitted provided that the following conditions
7248590Smm * are met:
8248590Smm * 1. Redistributions of source code must retain the above copyright
9248590Smm *    notice, this list of conditions and the following disclaimer.
10248590Smm * 2. Redistributions in binary form must reproduce the above copyright
11248590Smm *    notice, this list of conditions and the following disclaimer in the
12248590Smm *    documentation and/or other materials provided with the distribution.
13248590Smm *
14248590Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15248590Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16248590Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17248590Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18248590Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19248590Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20248590Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21248590Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22248590Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23248590Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24248590Smm */
25248590Smm
26248590Smm#include "archive_platform.h"
27248590Smm
28248590Smm#ifdef HAVE_ERRNO_H
29248590Smm#include <errno.h>
30248590Smm#endif
31248590Smm#ifdef HAVE_STDLIB_H
32248590Smm#include <stdlib.h>
33248590Smm#endif
34248590Smm
35248590Smm#include "archive.h"
36248590Smm#include "archive_endian.h"
37248590Smm#include "archive_private.h"
38248590Smm#include "archive_read_private.h"
39248590Smm
40248590Smmstruct rpm {
41248590Smm	int64_t		 total_in;
42248590Smm	size_t		 hpos;
43248590Smm	size_t		 hlen;
44248590Smm	unsigned char	 header[16];
45248590Smm	enum {
46248590Smm		ST_LEAD,	/* Skipping 'Lead' section. */
47248590Smm		ST_HEADER,	/* Reading 'Header' section;
48248590Smm				 * first 16 bytes. */
49248590Smm		ST_HEADER_DATA,	/* Skipping 'Header' section. */
50248590Smm		ST_PADDING,	/* Skipping padding data after the
51248590Smm				 * 'Header' section. */
52248590Smm		ST_ARCHIVE	/* Reading 'Archive' section. */
53248590Smm	}		 state;
54248590Smm	int		 first_header;
55248590Smm};
56248590Smm#define RPM_LEAD_SIZE	96	/* Size of 'Lead' section. */
57248590Smm
58248590Smmstatic int	rpm_bidder_bid(struct archive_read_filter_bidder *,
59248590Smm		    struct archive_read_filter *);
60248590Smmstatic int	rpm_bidder_init(struct archive_read_filter *);
61248590Smm
62248590Smmstatic ssize_t	rpm_filter_read(struct archive_read_filter *,
63248590Smm		    const void **);
64248590Smmstatic int	rpm_filter_close(struct archive_read_filter *);
65248590Smm
66248590Smm#if ARCHIVE_VERSION_NUMBER < 4000000
67248590Smm/* Deprecated; remove in libarchive 4.0 */
68248590Smmint
69248590Smmarchive_read_support_compression_rpm(struct archive *a)
70248590Smm{
71248590Smm	return archive_read_support_filter_rpm(a);
72248590Smm}
73248590Smm#endif
74248590Smm
75248590Smmint
76248590Smmarchive_read_support_filter_rpm(struct archive *_a)
77248590Smm{
78248590Smm	struct archive_read *a = (struct archive_read *)_a;
79248590Smm	struct archive_read_filter_bidder *bidder;
80248590Smm
81248590Smm	archive_check_magic(_a, ARCHIVE_READ_MAGIC,
82248590Smm	    ARCHIVE_STATE_NEW, "archive_read_support_filter_rpm");
83248590Smm
84248590Smm	if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
85248590Smm		return (ARCHIVE_FATAL);
86248590Smm
87248590Smm	bidder->data = NULL;
88248590Smm	bidder->bid = rpm_bidder_bid;
89248590Smm	bidder->init = rpm_bidder_init;
90248590Smm	bidder->options = NULL;
91248590Smm	bidder->free = NULL;
92248590Smm	return (ARCHIVE_OK);
93248590Smm}
94248590Smm
95248590Smmstatic int
96248590Smmrpm_bidder_bid(struct archive_read_filter_bidder *self,
97248590Smm    struct archive_read_filter *filter)
98248590Smm{
99248590Smm	const unsigned char *b;
100248590Smm	ssize_t avail;
101248590Smm	int bits_checked;
102248590Smm
103248590Smm	(void)self; /* UNUSED */
104248590Smm
105248590Smm	b = __archive_read_filter_ahead(filter, 8, &avail);
106248590Smm	if (b == NULL)
107248590Smm		return (0);
108248590Smm
109248590Smm	bits_checked = 0;
110248590Smm	/*
111248590Smm	 * Verify Header Magic Bytes : 0XED 0XAB 0XEE 0XDB
112248590Smm	 */
113248590Smm	if (memcmp(b, "\xED\xAB\xEE\xDB", 4) != 0)
114248590Smm		return (0);
115248590Smm	bits_checked += 32;
116248590Smm	/*
117248590Smm	 * Check major version.
118248590Smm	 */
119248590Smm	if (b[4] != 3 && b[4] != 4)
120248590Smm		return (0);
121248590Smm	bits_checked += 8;
122248590Smm	/*
123248590Smm	 * Check package type; binary or source.
124248590Smm	 */
125248590Smm	if (b[6] != 0)
126248590Smm		return (0);
127248590Smm	bits_checked += 8;
128248590Smm	if (b[7] != 0 && b[7] != 1)
129248590Smm		return (0);
130248590Smm	bits_checked += 8;
131248590Smm
132248590Smm	return (bits_checked);
133248590Smm}
134248590Smm
135248590Smmstatic int
136248590Smmrpm_bidder_init(struct archive_read_filter *self)
137248590Smm{
138248590Smm	struct rpm   *rpm;
139248590Smm
140248590Smm	self->code = ARCHIVE_COMPRESSION_RPM;
141248590Smm	self->name = "rpm";
142248590Smm	self->read = rpm_filter_read;
143248590Smm	self->skip = NULL; /* not supported */
144248590Smm	self->close = rpm_filter_close;
145248590Smm
146248590Smm	rpm = (struct rpm *)calloc(sizeof(*rpm), 1);
147248590Smm	if (rpm == NULL) {
148248590Smm		archive_set_error(&self->archive->archive, ENOMEM,
149248590Smm		    "Can't allocate data for rpm");
150248590Smm		return (ARCHIVE_FATAL);
151248590Smm	}
152248590Smm
153248590Smm	self->data = rpm;
154248590Smm	rpm->state = ST_LEAD;
155248590Smm
156248590Smm	return (ARCHIVE_OK);
157248590Smm}
158248590Smm
159248590Smmstatic ssize_t
160248590Smmrpm_filter_read(struct archive_read_filter *self, const void **buff)
161248590Smm{
162248590Smm	struct rpm *rpm;
163248590Smm	const unsigned char *b;
164248590Smm	ssize_t avail_in, total;
165248590Smm	size_t used, n;
166248590Smm	uint32_t section;
167248590Smm	uint32_t bytes;
168248590Smm
169248590Smm	rpm = (struct rpm *)self->data;
170248590Smm	*buff = NULL;
171248590Smm	total = avail_in = 0;
172248590Smm	b = NULL;
173248590Smm	used = 0;
174	do {
175		if (b == NULL) {
176			b = __archive_read_filter_ahead(self->upstream, 1,
177			    &avail_in);
178			if (b == NULL) {
179				if (avail_in < 0)
180					return (ARCHIVE_FATAL);
181				else
182					break;
183			}
184		}
185
186		switch (rpm->state) {
187		case ST_LEAD:
188			if (rpm->total_in + avail_in < RPM_LEAD_SIZE)
189				used += avail_in;
190			else {
191				n = (size_t)(RPM_LEAD_SIZE - rpm->total_in);
192				used += n;
193				b += n;
194				rpm->state = ST_HEADER;
195				rpm->hpos = 0;
196				rpm->hlen = 0;
197				rpm->first_header = 1;
198			}
199			break;
200		case ST_HEADER:
201			n = 16 - rpm->hpos;
202			if (n > avail_in - used)
203				n = avail_in - used;
204			memcpy(rpm->header+rpm->hpos, b, n);
205			b += n;
206			used += n;
207			rpm->hpos += n;
208
209			if (rpm->hpos == 16) {
210				if (rpm->header[0] != 0x8e ||
211				    rpm->header[1] != 0xad ||
212				    rpm->header[2] != 0xe8 ||
213				    rpm->header[3] != 0x01) {
214					if (rpm->first_header) {
215						archive_set_error(
216						    &self->archive->archive,
217						    ARCHIVE_ERRNO_FILE_FORMAT,
218						    "Unrecoginized rpm header");
219						return (ARCHIVE_FATAL);
220					}
221					rpm->state = ST_ARCHIVE;
222					*buff = rpm->header;
223					total = rpm->hpos;
224					break;
225				}
226				/* Calculate 'Header' length. */
227				section = archive_be32dec(rpm->header+8);
228				bytes = archive_be32dec(rpm->header+12);
229				rpm->hlen = 16 + section * 16 + bytes;
230				rpm->state = ST_HEADER_DATA;
231				rpm->first_header = 0;
232			}
233			break;
234		case ST_HEADER_DATA:
235			n = rpm->hlen - rpm->hpos;
236			if (n > avail_in - used)
237				n = avail_in - used;
238			b += n;
239			used += n;
240			rpm->hpos += n;
241			if (rpm->hpos == rpm->hlen)
242				rpm->state = ST_PADDING;
243			break;
244		case ST_PADDING:
245			while (used < (size_t)avail_in) {
246				if (*b != 0) {
247					/* Read next header. */
248					rpm->state = ST_HEADER;
249					rpm->hpos = 0;
250					rpm->hlen = 0;
251					break;
252				}
253				b++;
254				used++;
255			}
256			break;
257		case ST_ARCHIVE:
258			*buff = b;
259			total = avail_in;
260			used = avail_in;
261			break;
262		}
263		if (used == (size_t)avail_in) {
264			rpm->total_in += used;
265			__archive_read_filter_consume(self->upstream, used);
266			b = NULL;
267			used = 0;
268		}
269	} while (total == 0 && avail_in > 0);
270
271	if (used > 0 && b != NULL) {
272		rpm->total_in += used;
273		__archive_read_filter_consume(self->upstream, used);
274	}
275	return (total);
276}
277
278static int
279rpm_filter_close(struct archive_read_filter *self)
280{
281	struct rpm *rpm;
282
283	rpm = (struct rpm *)self->data;
284	free(rpm);
285
286	return (ARCHIVE_OK);
287}
288
289