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 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 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 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 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 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 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 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