1 /*- 2 * Copyright (c) 2009 Michihiro NAKAJIMA 3 * Copyright (c) 2003-2007 Tim Kientzle 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "archive_platform.h" 28 __FBSDID("$FreeBSD: src/lib/libarchive/archive_util.c,v 1.19 2008/10/21 12:10:30 des Exp $"); 29 30 #ifdef HAVE_SYS_TYPES_H 31 #include <sys/types.h> 32 #endif 33 #ifdef HAVE_STDLIB_H 34 #include <stdlib.h> 35 #endif 36 #ifdef HAVE_STRING_H 37 #include <string.h> 38 #endif 39 40 #include "archive.h" 41 #include "archive_private.h" 42 #include "archive_string.h" 43 44 #if ARCHIVE_VERSION_NUMBER < 3000000 45 /* These disappear in libarchive 3.0 */ 46 /* Deprecated. */ 47 int 48 archive_api_feature(void) 49 { 50 return (ARCHIVE_API_FEATURE); 51 } 52 53 /* Deprecated. */ 54 int 55 archive_api_version(void) 56 { 57 return (ARCHIVE_API_VERSION); 58 } 59 60 /* Deprecated synonym for archive_version_number() */ 61 int 62 archive_version_stamp(void) 63 { 64 return (archive_version_number()); 65 } 66 67 /* Deprecated synonym for archive_version_string() */ 68 const char * 69 archive_version(void) 70 { 71 return (archive_version_string()); 72 } 73 #endif 74 75 int 76 archive_version_number(void) 77 { 78 return (ARCHIVE_VERSION_NUMBER); 79 } 80 81 const char * 82 archive_version_string(void) 83 { 84 return (ARCHIVE_VERSION_STRING); 85 } 86 87 int 88 archive_errno(struct archive *a) 89 { 90 return (a->archive_error_number); 91 } 92 93 const char * 94 archive_error_string(struct archive *a) 95 { 96 97 if (a->error != NULL && *a->error != '\0') 98 return (a->error); 99 else 100 return ("(Empty error message)"); 101 } 102 103 104 int 105 archive_format(struct archive *a) 106 { 107 return (a->archive_format); 108 } 109 110 const char * 111 archive_format_name(struct archive *a) 112 { 113 return (a->archive_format_name); 114 } 115 116 117 int 118 archive_compression(struct archive *a) 119 { 120 return (a->compression_code); 121 } 122 123 const char * 124 archive_compression_name(struct archive *a) 125 { 126 return (a->compression_name); 127 } 128 129 130 /* 131 * Return a count of the number of compressed bytes processed. 132 */ 133 int64_t 134 archive_position_compressed(struct archive *a) 135 { 136 return (a->raw_position); 137 } 138 139 /* 140 * Return a count of the number of uncompressed bytes processed. 141 */ 142 int64_t 143 archive_position_uncompressed(struct archive *a) 144 { 145 return (a->file_position); 146 } 147 148 void 149 archive_clear_error(struct archive *a) 150 { 151 archive_string_empty(&a->error_string); 152 a->error = NULL; 153 } 154 155 void 156 archive_set_error(struct archive *a, int error_number, const char *fmt, ...) 157 { 158 va_list ap; 159 160 a->archive_error_number = error_number; 161 if (fmt == NULL) { 162 a->error = NULL; 163 return; 164 } 165 166 va_start(ap, fmt); 167 archive_string_vsprintf(&(a->error_string), fmt, ap); 168 va_end(ap); 169 a->error = a->error_string.s; 170 } 171 172 void 173 archive_copy_error(struct archive *dest, struct archive *src) 174 { 175 dest->archive_error_number = src->archive_error_number; 176 177 archive_string_copy(&dest->error_string, &src->error_string); 178 dest->error = dest->error_string.s; 179 } 180 181 void 182 __archive_errx(int retvalue, const char *msg) 183 { 184 static const char *msg1 = "Fatal Internal Error in libarchive: "; 185 write(2, msg1, strlen(msg1)); 186 write(2, msg, strlen(msg)); 187 write(2, "\n", 1); 188 exit(retvalue); 189 } 190 191 /* 192 * Parse option strings 193 * Detail of option format. 194 * - The option can accept: 195 * "opt-name", "!opt-name", "opt-name=value". 196 * 197 * - The option entries are separated by comma. 198 * e.g "compression=9,opt=XXX,opt-b=ZZZ" 199 * 200 * - The name of option string consist of '-' and alphabet 201 * but character '-' cannot be used for the first character. 202 * (Regular expression is [a-z][-a-z]+) 203 * 204 * - For a specfic format/filter, using the format name with ':'. 205 * e.g "zip:compression=9" 206 * (This "compression=9" option entry is for "zip" format only) 207 * 208 * If another entries follow it, those are not for 209 * the specfic format/filter. 210 * e.g handle "zip:compression=9,opt=XXX,opt-b=ZZZ" 211 * "zip" format/filter handler will get "compression=9" 212 * all format/filter handler will get "opt=XXX" 213 * all format/filter handler will get "opt-b=ZZZ" 214 * 215 * - Whitespace and tab are bypassed. 216 * 217 */ 218 int 219 __archive_parse_options(const char *p, const char *fn, int keysize, char *key, 220 int valsize, char *val) 221 { 222 const char *p_org; 223 int apply; 224 int kidx, vidx; 225 int negative; 226 enum { 227 /* Requested for initialization. */ 228 INIT, 229 /* Finding format/filter-name and option-name. */ 230 F_BOTH, 231 /* Finding option-name only. 232 * (already detected format/filter-name) */ 233 F_NAME, 234 /* Getting option-value. */ 235 G_VALUE, 236 } state; 237 238 p_org = p; 239 state = INIT; 240 kidx = vidx = negative = 0; 241 apply = 1; 242 while (*p) { 243 switch (state) { 244 case INIT: 245 kidx = vidx = 0; 246 negative = 0; 247 apply = 1; 248 state = F_BOTH; 249 break; 250 case F_BOTH: 251 case F_NAME: 252 if ((*p >= 'a' && *p <= 'z') || 253 (*p >= '0' && *p <= '9') || *p == '-') { 254 if (kidx == 0 && !(*p >= 'a' && *p <= 'z')) 255 /* Illegal sequence. */ 256 return (-1); 257 if (kidx >= keysize -1) 258 /* Too many characters. */ 259 return (-1); 260 key[kidx++] = *p++; 261 } else if (*p == '!') { 262 if (kidx != 0) 263 /* Illegal sequence. */ 264 return (-1); 265 negative = 1; 266 ++p; 267 } else if (*p == ',') { 268 if (kidx == 0) 269 /* Illegal sequence. */ 270 return (-1); 271 if (!negative) 272 val[vidx++] = '1'; 273 /* We have got boolean option data. */ 274 ++p; 275 if (apply) 276 goto complete; 277 else 278 /* This option does not apply to the 279 * format which the fn variable 280 * indicate. */ 281 state = INIT; 282 } else if (*p == ':') { 283 /* obuf data is format name */ 284 if (state == F_NAME) 285 /* We already found it. */ 286 return (-1); 287 if (kidx == 0) 288 /* Illegal sequence. */ 289 return (-1); 290 if (negative) 291 /* We cannot accept "!format-name:". */ 292 return (-1); 293 key[kidx] = '\0'; 294 if (strcmp(fn, key) != 0) 295 /* This option does not apply to the 296 * format which the fn variable 297 * indicate. */ 298 apply = 0; 299 kidx = 0; 300 ++p; 301 state = F_NAME; 302 } else if (*p == '=') { 303 if (kidx == 0) 304 /* Illegal sequence. */ 305 return (-1); 306 if (negative) 307 /* We cannot accept "!opt-name=value". */ 308 return (-1); 309 ++p; 310 state = G_VALUE; 311 } else if (*p == ' ') { 312 /* Pass the space character */ 313 ++p; 314 } else { 315 /* Illegal character. */ 316 return (-1); 317 } 318 break; 319 case G_VALUE: 320 if (*p == ',') { 321 if (vidx == 0) 322 /* Illegal sequence. */ 323 return (-1); 324 /* We have got option data. */ 325 ++p; 326 if (apply) 327 goto complete; 328 else 329 /* This option does not apply to the 330 * format which the fn variable 331 * indicate. */ 332 state = INIT; 333 } else if (*p == ' ') { 334 /* Pass the space character */ 335 ++p; 336 } else { 337 if (vidx >= valsize -1) 338 /* Too many characters. */ 339 return (-1); 340 val[vidx++] = *p++; 341 } 342 break; 343 } 344 } 345 346 switch (state) { 347 case F_BOTH: 348 case F_NAME: 349 if (kidx != 0) { 350 if (!negative) 351 val[vidx++] = '1'; 352 /* We have got boolean option. */ 353 if (apply) 354 /* This option apply to the format which the 355 * fn variable indicate. */ 356 goto complete; 357 } 358 break; 359 case G_VALUE: 360 if (vidx == 0) 361 /* Illegal sequence. */ 362 return (-1); 363 /* We have got option value. */ 364 if (apply) 365 /* This option apply to the format which the fn 366 * variable indicate. */ 367 goto complete; 368 break; 369 case INIT:/* nothing */ 370 break; 371 } 372 373 /* End of Option string. */ 374 return (0); 375 376 complete: 377 key[kidx] = '\0'; 378 val[vidx] = '\0'; 379 /* Return a size which we've consumed for detecting option */ 380 return ((int)(p - p_org)); 381 } 382