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