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