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$");
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