archive_util.c revision 228753
190075Sobrien/*- 290075Sobrien * Copyright (c) 2009 Michihiro NAKAJIMA 390075Sobrien * Copyright (c) 2003-2007 Tim Kientzle 490075Sobrien * All rights reserved. 590075Sobrien * 690075Sobrien * Redistribution and use in source and binary forms, with or without 790075Sobrien * modification, are permitted provided that the following conditions 890075Sobrien * are met: 990075Sobrien * 1. Redistributions of source code must retain the above copyright 1090075Sobrien * notice, this list of conditions and the following disclaimer. 1190075Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1290075Sobrien * notice, this list of conditions and the following disclaimer in the 1390075Sobrien * documentation and/or other materials provided with the distribution. 1490075Sobrien * 1590075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 1690075Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1790075Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1890075Sobrien * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 1990075Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2090075Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2190075Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2290075Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2390075Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2490075Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2590075Sobrien */ 2690075Sobrien 2790075Sobrien#include "archive_platform.h" 2890075Sobrien__FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:14Z kientzle $"); 2990075Sobrien 3090075Sobrien#ifdef HAVE_SYS_TYPES_H 3190075Sobrien#include <sys/types.h> 3290075Sobrien#endif 3390075Sobrien#ifdef HAVE_STDLIB_H 3490075Sobrien#include <stdlib.h> 3590075Sobrien#endif 3690075Sobrien#ifdef HAVE_STRING_H 3790075Sobrien#include <string.h> 3890075Sobrien#endif 39117395Skan 4090075Sobrien#include "archive.h" 4190075Sobrien#include "archive_private.h" 4290075Sobrien#include "archive_string.h" 4390075Sobrien 4490075Sobrien#if ARCHIVE_VERSION_NUMBER < 3000000 4590075Sobrien/* These disappear in libarchive 3.0 */ 4690075Sobrien/* Deprecated. */ 4790075Sobrienint 4890075Sobrienarchive_api_feature(void) 4990075Sobrien{ 5090075Sobrien return (ARCHIVE_API_FEATURE); 5190075Sobrien} 5290075Sobrien 5390075Sobrien/* Deprecated. */ 5490075Sobrienint 5590075Sobrienarchive_api_version(void) 5690075Sobrien{ 5790075Sobrien return (ARCHIVE_API_VERSION); 5890075Sobrien} 5990075Sobrien 6090075Sobrien/* Deprecated synonym for archive_version_number() */ 6190075Sobrienint 6290075Sobrienarchive_version_stamp(void) 6390075Sobrien{ 6490075Sobrien return (archive_version_number()); 6590075Sobrien} 6690075Sobrien 6790075Sobrien/* Deprecated synonym for archive_version_string() */ 6890075Sobrienconst char * 6990075Sobrienarchive_version(void) 7090075Sobrien{ 7190075Sobrien return (archive_version_string()); 7290075Sobrien} 7390075Sobrien#endif 7490075Sobrien 7590075Sobrienint 7690075Sobrienarchive_version_number(void) 7790075Sobrien{ 7890075Sobrien return (ARCHIVE_VERSION_NUMBER); 7990075Sobrien} 8090075Sobrien 8190075Sobrienconst char * 8290075Sobrienarchive_version_string(void) 8390075Sobrien{ 8490075Sobrien return (ARCHIVE_VERSION_STRING); 8590075Sobrien} 8690075Sobrien 8790075Sobrienint 8890075Sobrienarchive_errno(struct archive *a) 8990075Sobrien{ 9090075Sobrien return (a->archive_error_number); 9190075Sobrien} 9290075Sobrien 9390075Sobrienconst char * 9490075Sobrienarchive_error_string(struct archive *a) 9590075Sobrien{ 9690075Sobrien 9790075Sobrien if (a->error != NULL && *a->error != '\0') 9890075Sobrien return (a->error); 9990075Sobrien else 10090075Sobrien return ("(Empty error message)"); 10190075Sobrien} 10290075Sobrien 10390075Sobrienint 10490075Sobrienarchive_file_count(struct archive *a) 10590075Sobrien{ 10690075Sobrien return (a->file_count); 10790075Sobrien} 10890075Sobrien 10990075Sobrienint 11090075Sobrienarchive_format(struct archive *a) 11190075Sobrien{ 11290075Sobrien return (a->archive_format); 11390075Sobrien} 11490075Sobrien 11590075Sobrienconst char * 11690075Sobrienarchive_format_name(struct archive *a) 11790075Sobrien{ 11890075Sobrien return (a->archive_format_name); 11990075Sobrien} 12090075Sobrien 12190075Sobrien 12290075Sobrienint 12390075Sobrienarchive_compression(struct archive *a) 12490075Sobrien{ 12590075Sobrien return (a->compression_code); 12690075Sobrien} 12790075Sobrien 12890075Sobrienconst char * 12990075Sobrienarchive_compression_name(struct archive *a) 13090075Sobrien{ 13190075Sobrien return (a->compression_name); 13290075Sobrien} 13390075Sobrien 13490075Sobrien 13590075Sobrien/* 13690075Sobrien * Return a count of the number of compressed bytes processed. 13790075Sobrien */ 13890075Sobrienint64_t 13990075Sobrienarchive_position_compressed(struct archive *a) 14090075Sobrien{ 14190075Sobrien return (a->raw_position); 14290075Sobrien} 14390075Sobrien 14490075Sobrien/* 14590075Sobrien * Return a count of the number of uncompressed bytes processed. 14690075Sobrien */ 14790075Sobrienint64_t 14890075Sobrienarchive_position_uncompressed(struct archive *a) 14990075Sobrien{ 15090075Sobrien return (a->file_position); 15190075Sobrien} 15290075Sobrien 15390075Sobrienvoid 15490075Sobrienarchive_clear_error(struct archive *a) 15590075Sobrien{ 15690075Sobrien archive_string_empty(&a->error_string); 15790075Sobrien a->error = NULL; 15890075Sobrien a->archive_error_number = 0; 15990075Sobrien} 16090075Sobrien 16190075Sobrienvoid 16290075Sobrienarchive_set_error(struct archive *a, int error_number, const char *fmt, ...) 16390075Sobrien{ 16490075Sobrien va_list ap; 16590075Sobrien 16690075Sobrien a->archive_error_number = error_number; 16790075Sobrien if (fmt == NULL) { 16890075Sobrien a->error = NULL; 16990075Sobrien return; 17090075Sobrien } 17190075Sobrien 17290075Sobrien va_start(ap, fmt); 17390075Sobrien archive_string_vsprintf(&(a->error_string), fmt, ap); 17490075Sobrien va_end(ap); 17590075Sobrien a->error = a->error_string.s; 17690075Sobrien} 17790075Sobrien 17890075Sobrienvoid 17990075Sobrienarchive_copy_error(struct archive *dest, struct archive *src) 18090075Sobrien{ 18190075Sobrien dest->archive_error_number = src->archive_error_number; 18290075Sobrien 18390075Sobrien archive_string_copy(&dest->error_string, &src->error_string); 18490075Sobrien dest->error = dest->error_string.s; 18590075Sobrien} 18690075Sobrien 18790075Sobrienvoid 18890075Sobrien__archive_errx(int retvalue, const char *msg) 18990075Sobrien{ 19090075Sobrien static const char *msg1 = "Fatal Internal Error in libarchive: "; 19190075Sobrien size_t s; 19290075Sobrien 19390075Sobrien s = write(2, msg1, strlen(msg1)); 19490075Sobrien (void)s; /* UNUSED */ 19590075Sobrien s = write(2, msg, strlen(msg)); 19690075Sobrien (void)s; /* UNUSED */ 19790075Sobrien s = write(2, "\n", 1); 19890075Sobrien (void)s; /* UNUSED */ 19990075Sobrien exit(retvalue); 20090075Sobrien} 20190075Sobrien 20290075Sobrien/* 20390075Sobrien * Parse option strings 20490075Sobrien * Detail of option format. 20590075Sobrien * - The option can accept: 20690075Sobrien * "opt-name", "!opt-name", "opt-name=value". 20790075Sobrien * 20890075Sobrien * - The option entries are separated by comma. 20990075Sobrien * e.g "compression=9,opt=XXX,opt-b=ZZZ" 21090075Sobrien * 21190075Sobrien * - The name of option string consist of '-' and alphabet 21290075Sobrien * but character '-' cannot be used for the first character. 21390075Sobrien * (Regular expression is [a-z][-a-z]+) 21490075Sobrien * 21590075Sobrien * - For a specfic format/filter, using the format name with ':'. 21690075Sobrien * e.g "zip:compression=9" 21790075Sobrien * (This "compression=9" option entry is for "zip" format only) 21890075Sobrien * 21990075Sobrien * If another entries follow it, those are not for 22090075Sobrien * the specfic format/filter. 22190075Sobrien * e.g handle "zip:compression=9,opt=XXX,opt-b=ZZZ" 22290075Sobrien * "zip" format/filter handler will get "compression=9" 22390075Sobrien * all format/filter handler will get "opt=XXX" 22490075Sobrien * all format/filter handler will get "opt-b=ZZZ" 22590075Sobrien * 22690075Sobrien * - Whitespace and tab are bypassed. 22790075Sobrien * 22890075Sobrien */ 22990075Sobrienint 23090075Sobrien__archive_parse_options(const char *p, const char *fn, int keysize, char *key, 23190075Sobrien int valsize, char *val) 23290075Sobrien{ 23390075Sobrien const char *p_org; 23490075Sobrien int apply; 23590075Sobrien int kidx, vidx; 23690075Sobrien int negative; 23790075Sobrien enum { 23890075Sobrien /* Requested for initialization. */ 23990075Sobrien INIT, 24090075Sobrien /* Finding format/filter-name and option-name. */ 24190075Sobrien F_BOTH, 24290075Sobrien /* Finding option-name only. 24390075Sobrien * (already detected format/filter-name) */ 24490075Sobrien F_NAME, 24590075Sobrien /* Getting option-value. */ 24690075Sobrien G_VALUE, 24790075Sobrien } state; 24890075Sobrien 24990075Sobrien p_org = p; 25090075Sobrien state = INIT; 25190075Sobrien kidx = vidx = negative = 0; 25290075Sobrien apply = 1; 25390075Sobrien while (*p) { 25490075Sobrien switch (state) { 25590075Sobrien case INIT: 25690075Sobrien kidx = vidx = 0; 25790075Sobrien negative = 0; 25890075Sobrien apply = 1; 25990075Sobrien state = F_BOTH; 26090075Sobrien break; 26190075Sobrien case F_BOTH: 26290075Sobrien case F_NAME: 26390075Sobrien if ((*p >= 'a' && *p <= 'z') || 26490075Sobrien (*p >= '0' && *p <= '9') || *p == '-') { 26590075Sobrien if (kidx == 0 && !(*p >= 'a' && *p <= 'z')) 26690075Sobrien /* Illegal sequence. */ 26790075Sobrien return (-1); 26890075Sobrien if (kidx >= keysize -1) 26990075Sobrien /* Too many characters. */ 27090075Sobrien return (-1); 27190075Sobrien key[kidx++] = *p++; 27290075Sobrien } else if (*p == '!') { 27390075Sobrien if (kidx != 0) 27490075Sobrien /* Illegal sequence. */ 27590075Sobrien return (-1); 27690075Sobrien negative = 1; 27790075Sobrien ++p; 27890075Sobrien } else if (*p == ',') { 27990075Sobrien if (kidx == 0) 28090075Sobrien /* Illegal sequence. */ 28190075Sobrien return (-1); 28290075Sobrien if (!negative) 28390075Sobrien val[vidx++] = '1'; 28490075Sobrien /* We have got boolean option data. */ 28590075Sobrien ++p; 28690075Sobrien if (apply) 28790075Sobrien goto complete; 28890075Sobrien else 28990075Sobrien /* This option does not apply to the 29090075Sobrien * format which the fn variable 29190075Sobrien * indicate. */ 29290075Sobrien state = INIT; 29390075Sobrien } else if (*p == ':') { 29490075Sobrien /* obuf data is format name */ 29590075Sobrien if (state == F_NAME) 29690075Sobrien /* We already found it. */ 29790075Sobrien return (-1); 29890075Sobrien if (kidx == 0) 29990075Sobrien /* Illegal sequence. */ 30090075Sobrien return (-1); 30190075Sobrien if (negative) 30290075Sobrien /* We cannot accept "!format-name:". */ 30390075Sobrien return (-1); 30490075Sobrien key[kidx] = '\0'; 30590075Sobrien if (strcmp(fn, key) != 0) 30690075Sobrien /* This option does not apply to the 30790075Sobrien * format which the fn variable 30890075Sobrien * indicate. */ 30990075Sobrien apply = 0; 31090075Sobrien kidx = 0; 31190075Sobrien ++p; 31290075Sobrien state = F_NAME; 31390075Sobrien } else if (*p == '=') { 31490075Sobrien if (kidx == 0) 31590075Sobrien /* Illegal sequence. */ 31690075Sobrien return (-1); 31790075Sobrien if (negative) 31890075Sobrien /* We cannot accept "!opt-name=value". */ 31990075Sobrien return (-1); 32090075Sobrien ++p; 32190075Sobrien state = G_VALUE; 32290075Sobrien } else if (*p == ' ') { 32390075Sobrien /* Pass the space character */ 32490075Sobrien ++p; 32590075Sobrien } else { 32690075Sobrien /* Illegal character. */ 32790075Sobrien return (-1); 32890075Sobrien } 32990075Sobrien break; 33090075Sobrien case G_VALUE: 33190075Sobrien if (*p == ',') { 33290075Sobrien if (vidx == 0) 33390075Sobrien /* Illegal sequence. */ 33490075Sobrien return (-1); 33590075Sobrien /* We have got option data. */ 33690075Sobrien ++p; 33790075Sobrien if (apply) 338117395Skan goto complete; 33990075Sobrien else 34090075Sobrien /* This option does not apply to the 34190075Sobrien * format which the fn variable 34290075Sobrien * indicate. */ 34390075Sobrien state = INIT; 34490075Sobrien } else if (*p == ' ') { 34590075Sobrien /* Pass the space character */ 34690075Sobrien ++p; 34790075Sobrien } else { 34890075Sobrien if (vidx >= valsize -1) 34990075Sobrien /* Too many characters. */ 35090075Sobrien return (-1); 35190075Sobrien val[vidx++] = *p++; 35290075Sobrien } 35390075Sobrien break; 35490075Sobrien } 35590075Sobrien } 35690075Sobrien 35790075Sobrien switch (state) { 35890075Sobrien case F_BOTH: 35990075Sobrien case F_NAME: 36090075Sobrien if (kidx != 0) { 36190075Sobrien if (!negative) 36290075Sobrien val[vidx++] = '1'; 36390075Sobrien /* We have got boolean option. */ 36490075Sobrien if (apply) 36590075Sobrien /* This option apply to the format which the 36690075Sobrien * fn variable indicate. */ 36790075Sobrien goto complete; 36890075Sobrien } 36990075Sobrien break; 37090075Sobrien case G_VALUE: 37190075Sobrien if (vidx == 0) 37290075Sobrien /* Illegal sequence. */ 37390075Sobrien return (-1); 37490075Sobrien /* We have got option value. */ 37590075Sobrien if (apply) 37690075Sobrien /* This option apply to the format which the fn 37790075Sobrien * variable indicate. */ 37890075Sobrien goto complete; 37990075Sobrien break; 38090075Sobrien case INIT:/* nothing */ 38190075Sobrien break; 38290075Sobrien } 38390075Sobrien 38490075Sobrien /* End of Option string. */ 38590075Sobrien return (0); 38690075Sobrien 38790075Sobriencomplete: 38890075Sobrien key[kidx] = '\0'; 38990075Sobrien val[vidx] = '\0'; 39090075Sobrien /* Return a size which we've consumed for detecting option */ 39190075Sobrien return ((int)(p - p_org)); 39290075Sobrien} 39390075Sobrien