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: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:14Z kientzle $"); 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 int 104 archive_file_count(struct archive *a) 105 { 106 return (a->file_count); 107 } 108 109 int 110 archive_format(struct archive *a) 111 { 112 return (a->archive_format); 113 } 114 115 const char * 116 archive_format_name(struct archive *a) 117 { 118 return (a->archive_format_name); 119 } 120 121 122 int 123 archive_compression(struct archive *a) 124 { 125 return (a->compression_code); 126 } 127 128 const char * 129 archive_compression_name(struct archive *a) 130 { 131 return (a->compression_name); 132 } 133 134 135 /* 136 * Return a count of the number of compressed bytes processed. 137 */ 138 int64_t 139 archive_position_compressed(struct archive *a) 140 { 141 return (a->raw_position); 142 } 143 144 /* 145 * Return a count of the number of uncompressed bytes processed. 146 */ 147 int64_t 148 archive_position_uncompressed(struct archive *a) 149 { 150 return (a->file_position); 151 } 152 153 void 154 archive_clear_error(struct archive *a) 155 { 156 archive_string_empty(&a->error_string); 157 a->error = NULL; 158 } 159 160 void 161 archive_set_error(struct archive *a, int error_number, const char *fmt, ...) 162 { 163 va_list ap; 164 165 a->archive_error_number = error_number; 166 if (fmt == NULL) { 167 a->error = NULL; 168 return; 169 } 170 171 va_start(ap, fmt); 172 archive_string_vsprintf(&(a->error_string), fmt, ap); 173 va_end(ap); 174 a->error = a->error_string.s; 175 } 176 177 void 178 archive_copy_error(struct archive *dest, struct archive *src) 179 { 180 dest->archive_error_number = src->archive_error_number; 181 182 archive_string_copy(&dest->error_string, &src->error_string); 183 dest->error = dest->error_string.s; 184 } 185 186 void 187 __archive_errx(int retvalue, const char *msg) 188 { 189 static const char *msg1 = "Fatal Internal Error in libarchive: "; 190 size_t s; 191 192 s = write(2, msg1, strlen(msg1)); 193 (void)s; /* UNUSED */ 194 s = write(2, msg, strlen(msg)); 195 (void)s; /* UNUSED */ 196 s = write(2, "\n", 1); 197 (void)s; /* UNUSED */ 198 exit(retvalue); 199 } 200 201 /* 202 * Parse option strings 203 * Detail of option format. 204 * - The option can accept: 205 * "opt-name", "!opt-name", "opt-name=value". 206 * 207 * - The option entries are separated by comma. 208 * e.g "compression=9,opt=XXX,opt-b=ZZZ" 209 * 210 * - The name of option string consist of '-' and alphabet 211 * but character '-' cannot be used for the first character. 212 * (Regular expression is [a-z][-a-z]+) 213 * 214 * - For a specfic format/filter, using the format name with ':'. 215 * e.g "zip:compression=9" 216 * (This "compression=9" option entry is for "zip" format only) 217 * 218 * If another entries follow it, those are not for 219 * the specfic format/filter. 220 * e.g handle "zip:compression=9,opt=XXX,opt-b=ZZZ" 221 * "zip" format/filter handler will get "compression=9" 222 * all format/filter handler will get "opt=XXX" 223 * all format/filter handler will get "opt-b=ZZZ" 224 * 225 * - Whitespace and tab are bypassed. 226 * 227 */ 228 int 229 __archive_parse_options(const char *p, const char *fn, int keysize, char *key, 230 int valsize, char *val) 231 { 232 const char *p_org; 233 int apply; 234 int kidx, vidx; 235 int negative; 236 enum { 237 /* Requested for initialization. */ 238 INIT, 239 /* Finding format/filter-name and option-name. */ 240 F_BOTH, 241 /* Finding option-name only. 242 * (already detected format/filter-name) */ 243 F_NAME, 244 /* Getting option-value. */ 245 G_VALUE, 246 } state; 247 248 p_org = p; 249 state = INIT; 250 kidx = vidx = negative = 0; 251 apply = 1; 252 while (*p) { 253 switch (state) { 254 case INIT: 255 kidx = vidx = 0; 256 negative = 0; 257 apply = 1; 258 state = F_BOTH; 259 break; 260 case F_BOTH: 261 case F_NAME: 262 if ((*p >= 'a' && *p <= 'z') || 263 (*p >= '0' && *p <= '9') || *p == '-') { 264 if (kidx == 0 && !(*p >= 'a' && *p <= 'z')) 265 /* Illegal sequence. */ 266 return (-1); 267 if (kidx >= keysize -1) 268 /* Too many characters. */ 269 return (-1); 270 key[kidx++] = *p++; 271 } else if (*p == '!') { 272 if (kidx != 0) 273 /* Illegal sequence. */ 274 return (-1); 275 negative = 1; 276 ++p; 277 } else if (*p == ',') { 278 if (kidx == 0) 279 /* Illegal sequence. */ 280 return (-1); 281 if (!negative) 282 val[vidx++] = '1'; 283 /* We have got boolean option data. */ 284 ++p; 285 if (apply) 286 goto complete; 287 else 288 /* This option does not apply to the 289 * format which the fn variable 290 * indicate. */ 291 state = INIT; 292 } else if (*p == ':') { 293 /* obuf data is format name */ 294 if (state == F_NAME) 295 /* We already found it. */ 296 return (-1); 297 if (kidx == 0) 298 /* Illegal sequence. */ 299 return (-1); 300 if (negative) 301 /* We cannot accept "!format-name:". */ 302 return (-1); 303 key[kidx] = '\0'; 304 if (strcmp(fn, key) != 0) 305 /* This option does not apply to the 306 * format which the fn variable 307 * indicate. */ 308 apply = 0; 309 kidx = 0; 310 ++p; 311 state = F_NAME; 312 } else if (*p == '=') { 313 if (kidx == 0) 314 /* Illegal sequence. */ 315 return (-1); 316 if (negative) 317 /* We cannot accept "!opt-name=value". */ 318 return (-1); 319 ++p; 320 state = G_VALUE; 321 } else if (*p == ' ') { 322 /* Pass the space character */ 323 ++p; 324 } else { 325 /* Illegal character. */ 326 return (-1); 327 } 328 break; 329 case G_VALUE: 330 if (*p == ',') { 331 if (vidx == 0) 332 /* Illegal sequence. */ 333 return (-1); 334 /* We have got option data. */ 335 ++p; 336 if (apply) 337 goto complete; 338 else 339 /* This option does not apply to the 340 * format which the fn variable 341 * indicate. */ 342 state = INIT; 343 } else if (*p == ' ') { 344 /* Pass the space character */ 345 ++p; 346 } else { 347 if (vidx >= valsize -1) 348 /* Too many characters. */ 349 return (-1); 350 val[vidx++] = *p++; 351 } 352 break; 353 } 354 } 355 356 switch (state) { 357 case F_BOTH: 358 case F_NAME: 359 if (kidx != 0) { 360 if (!negative) 361 val[vidx++] = '1'; 362 /* We have got boolean option. */ 363 if (apply) 364 /* This option apply to the format which the 365 * fn variable indicate. */ 366 goto complete; 367 } 368 break; 369 case G_VALUE: 370 if (vidx == 0) 371 /* Illegal sequence. */ 372 return (-1); 373 /* We have got option value. */ 374 if (apply) 375 /* This option apply to the format which the fn 376 * variable indicate. */ 377 goto complete; 378 break; 379 case INIT:/* nothing */ 380 break; 381 } 382 383 /* End of Option string. */ 384 return (0); 385 386 complete: 387 key[kidx] = '\0'; 388 val[vidx] = '\0'; 389 /* Return a size which we've consumed for detecting option */ 390 return ((int)(p - p_org)); 391 } 392