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: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:14Z kientzle $");
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. */
47 int
48 archive_api_feature(void)
49 {
50 	return (ARCHIVE_API_FEATURE);
51 }
52 
53 /* Deprecated. */
54 int
55 archive_api_version(void)
56 {
57 	return (ARCHIVE_API_VERSION);
58 }
59 
60 /* Deprecated synonym for archive_version_number() */
61 int
62 archive_version_stamp(void)
63 {
64 	return (archive_version_number());
65 }
66 
67 /* Deprecated synonym for archive_version_string() */
68 const char *
69 archive_version(void)
70 {
71 	return (archive_version_string());
72 }
73 #endif
74 
75 int
76 archive_version_number(void)
77 {
78 	return (ARCHIVE_VERSION_NUMBER);
79 }
80 
81 const char *
82 archive_version_string(void)
83 {
84 	return (ARCHIVE_VERSION_STRING);
85 }
86 
87 int
88 archive_errno(struct archive *a)
89 {
90 	return (a->archive_error_number);
91 }
92 
93 const char *
94 archive_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 
103 int
104 archive_file_count(struct archive *a)
105 {
106 	return (a->file_count);
107 }
108 
109 int
110 archive_format(struct archive *a)
111 {
112 	return (a->archive_format);
113 }
114 
115 const char *
116 archive_format_name(struct archive *a)
117 {
118 	return (a->archive_format_name);
119 }
120 
121 
122 int
123 archive_compression(struct archive *a)
124 {
125 	return (a->compression_code);
126 }
127 
128 const char *
129 archive_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  */
138 int64_t
139 archive_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  */
147 int64_t
148 archive_position_uncompressed(struct archive *a)
149 {
150 	return (a->file_position);
151 }
152 
153 void
154 archive_clear_error(struct archive *a)
155 {
156 	archive_string_empty(&a->error_string);
157 	a->error = NULL;
158 }
159 
160 void
161 archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
162 {
163 	va_list ap;
164 
165 	a->archive_error_number = error_number;
166 	if (fmt == NULL) {
167 		a->error = NULL;
168 		return;
169 	}
170 
171 	va_start(ap, fmt);
172 	archive_string_vsprintf(&(a->error_string), fmt, ap);
173 	va_end(ap);
174 	a->error = a->error_string.s;
175 }
176 
177 void
178 archive_copy_error(struct archive *dest, struct archive *src)
179 {
180 	dest->archive_error_number = src->archive_error_number;
181 
182 	archive_string_copy(&dest->error_string, &src->error_string);
183 	dest->error = dest->error_string.s;
184 }
185 
186 void
187 __archive_errx(int retvalue, const char *msg)
188 {
189 	static const char *msg1 = "Fatal Internal Error in libarchive: ";
190 	size_t s;
191 
192 	s = write(2, msg1, strlen(msg1));
193 	(void)s; /* UNUSED */
194 	s = write(2, msg, strlen(msg));
195 	(void)s; /* UNUSED */
196 	s = write(2, "\n", 1);
197 	(void)s; /* UNUSED */
198 	exit(retvalue);
199 }
200 
201 /*
202  * Parse option strings
203  *  Detail of option format.
204  *    - The option can accept:
205  *     "opt-name", "!opt-name", "opt-name=value".
206  *
207  *    - The option entries are separated by comma.
208  *        e.g  "compression=9,opt=XXX,opt-b=ZZZ"
209  *
210  *    - The name of option string consist of '-' and alphabet
211  *      but character '-' cannot be used for the first character.
212  *      (Regular expression is [a-z][-a-z]+)
213  *
214  *    - For a specfic format/filter, using the format name with ':'.
215  *        e.g  "zip:compression=9"
216  *        (This "compression=9" option entry is for "zip" format only)
217  *
218  *      If another entries follow it, those are not for
219  *      the specfic format/filter.
220  *        e.g  handle "zip:compression=9,opt=XXX,opt-b=ZZZ"
221  *          "zip" format/filter handler will get "compression=9"
222  *          all format/filter handler will get "opt=XXX"
223  *          all format/filter handler will get "opt-b=ZZZ"
224  *
225  *    - Whitespace and tab are bypassed.
226  *
227  */
228 int
229 __archive_parse_options(const char *p, const char *fn, int keysize, char *key,
230     int valsize, char *val)
231 {
232 	const char *p_org;
233 	int apply;
234 	int kidx, vidx;
235 	int negative;
236 	enum {
237 		/* Requested for initialization. */
238 		INIT,
239 		/* Finding format/filter-name and option-name. */
240 		F_BOTH,
241 		/* Finding option-name only.
242 		 * (already detected format/filter-name) */
243 		F_NAME,
244 		/* Getting option-value. */
245 		G_VALUE,
246 	} state;
247 
248 	p_org = p;
249 	state = INIT;
250 	kidx = vidx = negative = 0;
251 	apply = 1;
252 	while (*p) {
253 		switch (state) {
254 		case INIT:
255 			kidx = vidx = 0;
256 			negative = 0;
257 			apply = 1;
258 			state = F_BOTH;
259 			break;
260 		case F_BOTH:
261 		case F_NAME:
262 			if ((*p >= 'a' && *p <= 'z') ||
263 			    (*p >= '0' && *p <= '9') || *p == '-') {
264 				if (kidx == 0 && !(*p >= 'a' && *p <= 'z'))
265 					/* Illegal sequence. */
266 					return (-1);
267 				if (kidx >= keysize -1)
268 					/* Too many characters. */
269 					return (-1);
270 				key[kidx++] = *p++;
271 			} else if (*p == '!') {
272 				if (kidx != 0)
273 					/* Illegal sequence. */
274 					return (-1);
275 				negative = 1;
276 				++p;
277 			} else if (*p == ',') {
278 				if (kidx == 0)
279 					/* Illegal sequence. */
280 					return (-1);
281 				if (!negative)
282 					val[vidx++] = '1';
283 				/* We have got boolean option data. */
284 				++p;
285 				if (apply)
286 					goto complete;
287 				else
288 					/* This option does not apply to the
289 					 * format which the fn variable
290 					 * indicate. */
291 					state = INIT;
292 			} else if (*p == ':') {
293 				/* obuf data is format name */
294 				if (state == F_NAME)
295 					/* We already found it. */
296 					return (-1);
297 				if (kidx == 0)
298 					/* Illegal sequence. */
299 					return (-1);
300 				if (negative)
301 					/* We cannot accept "!format-name:". */
302 					return (-1);
303 				key[kidx] = '\0';
304 				if (strcmp(fn, key) != 0)
305 					/* This option does not apply to the
306 					 * format which the fn variable
307 					 * indicate. */
308 					apply = 0;
309 				kidx = 0;
310 				++p;
311 				state = F_NAME;
312 			} else if (*p == '=') {
313 				if (kidx == 0)
314 					/* Illegal sequence. */
315 					return (-1);
316 				if (negative)
317 					/* We cannot accept "!opt-name=value". */
318 					return (-1);
319 				++p;
320 				state = G_VALUE;
321 			} else if (*p == ' ') {
322 				/* Pass the space character */
323 				++p;
324 			} else {
325 				/* Illegal character. */
326 				return (-1);
327 			}
328 			break;
329 		case G_VALUE:
330 			if (*p == ',') {
331 				if (vidx == 0)
332 					/* Illegal sequence. */
333 					return (-1);
334 				/* We have got option data. */
335 				++p;
336 				if (apply)
337 					goto complete;
338 				else
339 					/* This option does not apply to the
340 					 * format which the fn variable
341 					 * indicate. */
342 					state = INIT;
343 			} else if (*p == ' ') {
344 				/* Pass the space character */
345 				++p;
346 			} else {
347 				if (vidx >= valsize -1)
348 					/* Too many characters. */
349 					return (-1);
350 				val[vidx++] = *p++;
351 			}
352 			break;
353 		}
354 	}
355 
356 	switch (state) {
357 	case F_BOTH:
358 	case F_NAME:
359 		if (kidx != 0) {
360 			if (!negative)
361 				val[vidx++] = '1';
362 			/* We have got boolean option. */
363 			if (apply)
364 				/* This option apply to the format which the
365 				 * fn variable indicate. */
366 				goto complete;
367 		}
368 		break;
369 	case G_VALUE:
370 		if (vidx == 0)
371 			/* Illegal sequence. */
372 			return (-1);
373 		/* We have got option value. */
374 		if (apply)
375 			/* This option apply to the format which the fn
376 			 * variable indicate. */
377 			goto complete;
378 		break;
379 	case INIT:/* nothing */
380 		break;
381 	}
382 
383 	/* End of Option string. */
384 	return (0);
385 
386 complete:
387 	key[kidx] = '\0';
388 	val[vidx] = '\0';
389 	/* Return a size which we've consumed for detecting option */
390 	return ((int)(p - p_org));
391 }
392