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