1228753Smm/*-
2228753Smm * Copyright (c) 2009 Michihiro NAKAJIMA
3228753Smm * Copyright (c) 2003-2007 Tim Kientzle
4228753Smm * All rights reserved.
5228753Smm *
6228753Smm * Redistribution and use in source and binary forms, with or without
7228753Smm * modification, are permitted provided that the following conditions
8228753Smm * are met:
9228753Smm * 1. Redistributions of source code must retain the above copyright
10228753Smm *    notice, this list of conditions and the following disclaimer.
11228753Smm * 2. Redistributions in binary form must reproduce the above copyright
12228753Smm *    notice, this list of conditions and the following disclaimer in the
13228753Smm *    documentation and/or other materials provided with the distribution.
14228753Smm *
15228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25228753Smm */
26228753Smm
27228753Smm#include "archive_platform.h"
28229592Smm__FBSDID("$FreeBSD$");
29228753Smm
30228753Smm#ifdef HAVE_SYS_TYPES_H
31228753Smm#include <sys/types.h>
32228753Smm#endif
33228753Smm#ifdef HAVE_STDLIB_H
34228753Smm#include <stdlib.h>
35228753Smm#endif
36228753Smm#ifdef HAVE_STRING_H
37228753Smm#include <string.h>
38228753Smm#endif
39228753Smm
40228753Smm#include "archive.h"
41228753Smm#include "archive_private.h"
42228753Smm#include "archive_string.h"
43228753Smm
44228753Smm#if ARCHIVE_VERSION_NUMBER < 3000000
45228753Smm/* These disappear in libarchive 3.0 */
46228753Smm/* Deprecated. */
47228753Smmint
48228753Smmarchive_api_feature(void)
49228753Smm{
50228753Smm	return (ARCHIVE_API_FEATURE);
51228753Smm}
52228753Smm
53228753Smm/* Deprecated. */
54228753Smmint
55228753Smmarchive_api_version(void)
56228753Smm{
57228753Smm	return (ARCHIVE_API_VERSION);
58228753Smm}
59228753Smm
60228753Smm/* Deprecated synonym for archive_version_number() */
61228753Smmint
62228753Smmarchive_version_stamp(void)
63228753Smm{
64228753Smm	return (archive_version_number());
65228753Smm}
66228753Smm
67228753Smm/* Deprecated synonym for archive_version_string() */
68228753Smmconst char *
69228753Smmarchive_version(void)
70228753Smm{
71228753Smm	return (archive_version_string());
72228753Smm}
73228753Smm#endif
74228753Smm
75228753Smmint
76228753Smmarchive_version_number(void)
77228753Smm{
78228753Smm	return (ARCHIVE_VERSION_NUMBER);
79228753Smm}
80228753Smm
81228753Smmconst char *
82228753Smmarchive_version_string(void)
83228753Smm{
84228753Smm	return (ARCHIVE_VERSION_STRING);
85228753Smm}
86228753Smm
87228753Smmint
88228753Smmarchive_errno(struct archive *a)
89228753Smm{
90228753Smm	return (a->archive_error_number);
91228753Smm}
92228753Smm
93228753Smmconst char *
94228753Smmarchive_error_string(struct archive *a)
95228753Smm{
96228753Smm
97228753Smm	if (a->error != NULL  &&  *a->error != '\0')
98228753Smm		return (a->error);
99228753Smm	else
100228753Smm		return ("(Empty error message)");
101228753Smm}
102228753Smm
103228753Smmint
104228753Smmarchive_file_count(struct archive *a)
105228753Smm{
106228753Smm	return (a->file_count);
107228753Smm}
108228753Smm
109228753Smmint
110228753Smmarchive_format(struct archive *a)
111228753Smm{
112228753Smm	return (a->archive_format);
113228753Smm}
114228753Smm
115228753Smmconst char *
116228753Smmarchive_format_name(struct archive *a)
117228753Smm{
118228753Smm	return (a->archive_format_name);
119228753Smm}
120228753Smm
121228753Smm
122228753Smmint
123228753Smmarchive_compression(struct archive *a)
124228753Smm{
125228753Smm	return (a->compression_code);
126228753Smm}
127228753Smm
128228753Smmconst char *
129228753Smmarchive_compression_name(struct archive *a)
130228753Smm{
131228753Smm	return (a->compression_name);
132228753Smm}
133228753Smm
134228753Smm
135228753Smm/*
136228753Smm * Return a count of the number of compressed bytes processed.
137228753Smm */
138228753Smmint64_t
139228753Smmarchive_position_compressed(struct archive *a)
140228753Smm{
141228753Smm	return (a->raw_position);
142228753Smm}
143228753Smm
144228753Smm/*
145228753Smm * Return a count of the number of uncompressed bytes processed.
146228753Smm */
147228753Smmint64_t
148228753Smmarchive_position_uncompressed(struct archive *a)
149228753Smm{
150228753Smm	return (a->file_position);
151228753Smm}
152228753Smm
153228753Smmvoid
154228753Smmarchive_clear_error(struct archive *a)
155228753Smm{
156228753Smm	archive_string_empty(&a->error_string);
157228753Smm	a->error = NULL;
158228753Smm	a->archive_error_number = 0;
159228753Smm}
160228753Smm
161228753Smmvoid
162228753Smmarchive_set_error(struct archive *a, int error_number, const char *fmt, ...)
163228753Smm{
164228753Smm	va_list ap;
165228753Smm
166228753Smm	a->archive_error_number = error_number;
167228753Smm	if (fmt == NULL) {
168228753Smm		a->error = NULL;
169228753Smm		return;
170228753Smm	}
171228753Smm
172228753Smm	va_start(ap, fmt);
173228753Smm	archive_string_vsprintf(&(a->error_string), fmt, ap);
174228753Smm	va_end(ap);
175228753Smm	a->error = a->error_string.s;
176228753Smm}
177228753Smm
178228753Smmvoid
179228753Smmarchive_copy_error(struct archive *dest, struct archive *src)
180228753Smm{
181228753Smm	dest->archive_error_number = src->archive_error_number;
182228753Smm
183228753Smm	archive_string_copy(&dest->error_string, &src->error_string);
184228753Smm	dest->error = dest->error_string.s;
185228753Smm}
186228753Smm
187228753Smmvoid
188228753Smm__archive_errx(int retvalue, const char *msg)
189228753Smm{
190228753Smm	static const char *msg1 = "Fatal Internal Error in libarchive: ";
191228753Smm	size_t s;
192228753Smm
193228753Smm	s = write(2, msg1, strlen(msg1));
194228753Smm	(void)s; /* UNUSED */
195228753Smm	s = write(2, msg, strlen(msg));
196228753Smm	(void)s; /* UNUSED */
197228753Smm	s = write(2, "\n", 1);
198228753Smm	(void)s; /* UNUSED */
199228753Smm	exit(retvalue);
200228753Smm}
201228753Smm
202228753Smm/*
203228753Smm * Parse option strings
204228753Smm *  Detail of option format.
205228753Smm *    - The option can accept:
206228753Smm *     "opt-name", "!opt-name", "opt-name=value".
207228753Smm *
208228753Smm *    - The option entries are separated by comma.
209228753Smm *        e.g  "compression=9,opt=XXX,opt-b=ZZZ"
210228753Smm *
211228753Smm *    - The name of option string consist of '-' and alphabet
212228753Smm *      but character '-' cannot be used for the first character.
213228753Smm *      (Regular expression is [a-z][-a-z]+)
214228753Smm *
215228753Smm *    - For a specfic format/filter, using the format name with ':'.
216228753Smm *        e.g  "zip:compression=9"
217228753Smm *        (This "compression=9" option entry is for "zip" format only)
218228753Smm *
219228753Smm *      If another entries follow it, those are not for
220228753Smm *      the specfic format/filter.
221228753Smm *        e.g  handle "zip:compression=9,opt=XXX,opt-b=ZZZ"
222228753Smm *          "zip" format/filter handler will get "compression=9"
223228753Smm *          all format/filter handler will get "opt=XXX"
224228753Smm *          all format/filter handler will get "opt-b=ZZZ"
225228753Smm *
226228753Smm *    - Whitespace and tab are bypassed.
227228753Smm *
228228753Smm */
229228753Smmint
230228753Smm__archive_parse_options(const char *p, const char *fn, int keysize, char *key,
231228753Smm    int valsize, char *val)
232228753Smm{
233228753Smm	const char *p_org;
234228753Smm	int apply;
235228753Smm	int kidx, vidx;
236228753Smm	int negative;
237228753Smm	enum {
238228753Smm		/* Requested for initialization. */
239228753Smm		INIT,
240228753Smm		/* Finding format/filter-name and option-name. */
241228753Smm		F_BOTH,
242228753Smm		/* Finding option-name only.
243228753Smm		 * (already detected format/filter-name) */
244228753Smm		F_NAME,
245228753Smm		/* Getting option-value. */
246228753Smm		G_VALUE,
247228753Smm	} state;
248228753Smm
249228753Smm	p_org = p;
250228753Smm	state = INIT;
251228753Smm	kidx = vidx = negative = 0;
252228753Smm	apply = 1;
253228753Smm	while (*p) {
254228753Smm		switch (state) {
255228753Smm		case INIT:
256228753Smm			kidx = vidx = 0;
257228753Smm			negative = 0;
258228753Smm			apply = 1;
259228753Smm			state = F_BOTH;
260228753Smm			break;
261228753Smm		case F_BOTH:
262228753Smm		case F_NAME:
263228753Smm			if ((*p >= 'a' && *p <= 'z') ||
264228753Smm			    (*p >= '0' && *p <= '9') || *p == '-') {
265228753Smm				if (kidx == 0 && !(*p >= 'a' && *p <= 'z'))
266228753Smm					/* Illegal sequence. */
267228753Smm					return (-1);
268228753Smm				if (kidx >= keysize -1)
269228753Smm					/* Too many characters. */
270228753Smm					return (-1);
271228753Smm				key[kidx++] = *p++;
272228753Smm			} else if (*p == '!') {
273228753Smm				if (kidx != 0)
274228753Smm					/* Illegal sequence. */
275228753Smm					return (-1);
276228753Smm				negative = 1;
277228753Smm				++p;
278228753Smm			} else if (*p == ',') {
279228753Smm				if (kidx == 0)
280228753Smm					/* Illegal sequence. */
281228753Smm					return (-1);
282228753Smm				if (!negative)
283228753Smm					val[vidx++] = '1';
284228753Smm				/* We have got boolean option data. */
285228753Smm				++p;
286228753Smm				if (apply)
287228753Smm					goto complete;
288228753Smm				else
289228753Smm					/* This option does not apply to the
290228753Smm					 * format which the fn variable
291228753Smm					 * indicate. */
292228753Smm					state = INIT;
293228753Smm			} else if (*p == ':') {
294228753Smm				/* obuf data is format name */
295228753Smm				if (state == F_NAME)
296228753Smm					/* We already found it. */
297228753Smm					return (-1);
298228753Smm				if (kidx == 0)
299228753Smm					/* Illegal sequence. */
300228753Smm					return (-1);
301228753Smm				if (negative)
302228753Smm					/* We cannot accept "!format-name:". */
303228753Smm					return (-1);
304228753Smm				key[kidx] = '\0';
305228753Smm				if (strcmp(fn, key) != 0)
306228753Smm					/* This option does not apply to the
307228753Smm					 * format which the fn variable
308228753Smm					 * indicate. */
309228753Smm					apply = 0;
310228753Smm				kidx = 0;
311228753Smm				++p;
312228753Smm				state = F_NAME;
313228753Smm			} else if (*p == '=') {
314228753Smm				if (kidx == 0)
315228753Smm					/* Illegal sequence. */
316228753Smm					return (-1);
317228753Smm				if (negative)
318228753Smm					/* We cannot accept "!opt-name=value". */
319228753Smm					return (-1);
320228753Smm				++p;
321228753Smm				state = G_VALUE;
322228753Smm			} else if (*p == ' ') {
323228753Smm				/* Pass the space character */
324228753Smm				++p;
325228753Smm			} else {
326228753Smm				/* Illegal character. */
327228753Smm				return (-1);
328228753Smm			}
329228753Smm			break;
330228753Smm		case G_VALUE:
331228753Smm			if (*p == ',') {
332228753Smm				if (vidx == 0)
333228753Smm					/* Illegal sequence. */
334228753Smm					return (-1);
335228753Smm				/* We have got option data. */
336228753Smm				++p;
337228753Smm				if (apply)
338228753Smm					goto complete;
339228753Smm				else
340228753Smm					/* This option does not apply to the
341228753Smm					 * format which the fn variable
342228753Smm					 * indicate. */
343228753Smm					state = INIT;
344228753Smm			} else if (*p == ' ') {
345228753Smm				/* Pass the space character */
346228753Smm				++p;
347228753Smm			} else {
348228753Smm				if (vidx >= valsize -1)
349228753Smm					/* Too many characters. */
350228753Smm					return (-1);
351228753Smm				val[vidx++] = *p++;
352228753Smm			}
353228753Smm			break;
354228753Smm		}
355228753Smm	}
356228753Smm
357228753Smm	switch (state) {
358228753Smm	case F_BOTH:
359228753Smm	case F_NAME:
360228753Smm		if (kidx != 0) {
361228753Smm			if (!negative)
362228753Smm				val[vidx++] = '1';
363228753Smm			/* We have got boolean option. */
364228753Smm			if (apply)
365228753Smm				/* This option apply to the format which the
366228753Smm				 * fn variable indicate. */
367228753Smm				goto complete;
368228753Smm		}
369228753Smm		break;
370228753Smm	case G_VALUE:
371228753Smm		if (vidx == 0)
372228753Smm			/* Illegal sequence. */
373228753Smm			return (-1);
374228753Smm		/* We have got option value. */
375228753Smm		if (apply)
376228753Smm			/* This option apply to the format which the fn
377228753Smm			 * variable indicate. */
378228753Smm			goto complete;
379228753Smm		break;
380228753Smm	case INIT:/* nothing */
381228753Smm		break;
382228753Smm	}
383228753Smm
384228753Smm	/* End of Option string. */
385228753Smm	return (0);
386228753Smm
387228753Smmcomplete:
388228753Smm	key[kidx] = '\0';
389228753Smm	val[vidx] = '\0';
390228753Smm	/* Return a size which we've consumed for detecting option */
391228753Smm	return ((int)(p - p_org));
392228753Smm}
393