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