]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/libarchive/libarchive/archive_util.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / libarchive / libarchive / archive_util.c
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. */
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         a->archive_error_number = 0;
159 }
160
161 void
162 archive_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
178 void
179 archive_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
187 void
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  */
229 int
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
387 complete:
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 }