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