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