]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/archive_options.c
MFC r368207,368607:
[FreeBSD/stable/10.git] / contrib / libarchive / libarchive / archive_options.c
1 /*-
2  * Copyright (c) 2011 Tim Kientzle
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "archive_platform.h"
27 __FBSDID("$FreeBSD$");
28
29 #ifdef HAVE_ERRNO_H
30 #include <errno.h>
31 #endif
32
33 #include "archive_options_private.h"
34
35 static const char *
36 parse_option(const char **str,
37     const char **mod, const char **opt, const char **val);
38
39 int
40 _archive_set_option(struct archive *a,
41     const char *m, const char *o, const char *v,
42     int magic, const char *fn, option_handler use_option)
43 {
44         const char *mp, *op, *vp;
45         int r;
46
47         archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
48
49         mp = (m != NULL && m[0] != '\0') ? m : NULL;
50         op = (o != NULL && o[0] != '\0') ? o : NULL;
51         vp = (v != NULL && v[0] != '\0') ? v : NULL;
52
53         if (op == NULL && vp == NULL)
54                 return (ARCHIVE_OK);
55         if (op == NULL) {
56                 archive_set_error(a, ARCHIVE_ERRNO_MISC, "Empty option");
57                 return (ARCHIVE_FAILED);
58         }
59
60         r = use_option(a, mp, op, vp);
61         if (r == ARCHIVE_WARN - 1) {
62                 archive_set_error(a, ARCHIVE_ERRNO_MISC,
63                     "Unknown module name: `%s'", mp);
64                 return (ARCHIVE_FAILED);
65         }
66         if (r == ARCHIVE_WARN) {
67                 archive_set_error(a, ARCHIVE_ERRNO_MISC,
68                     "Undefined option: `%s%s%s%s%s%s'",
69                     vp?"":"!", mp?mp:"", mp?":":"", op, vp?"=":"", vp?vp:"");
70                 return (ARCHIVE_FAILED);
71         }
72         return (r);
73 }
74
75 int
76 _archive_set_either_option(struct archive *a, const char *m, const char *o, const char *v,
77     option_handler use_format_option, option_handler use_filter_option)
78 {
79         int r1, r2;
80
81         if (o == NULL && v == NULL)
82                 return (ARCHIVE_OK);
83         if (o == NULL)
84                 return (ARCHIVE_FAILED);
85
86         r1 = use_format_option(a, m, o, v);
87         if (r1 == ARCHIVE_FATAL)
88                 return (ARCHIVE_FATAL);
89
90         r2 = use_filter_option(a, m, o, v);
91         if (r2 == ARCHIVE_FATAL)
92                 return (ARCHIVE_FATAL);
93
94         if (r2 == ARCHIVE_WARN - 1)
95                 return r1;
96         return r1 > r2 ? r1 : r2;
97 }
98
99 int
100 _archive_set_options(struct archive *a, const char *options,
101     int magic, const char *fn, option_handler use_option)
102 {
103         int allok = 1, anyok = 0, ignore_mod_err = 0, r;
104         char *data;
105         const char *s, *mod, *opt, *val;
106
107         archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
108
109         if (options == NULL || options[0] == '\0')
110                 return ARCHIVE_OK;
111
112         if ((data = strdup(options)) == NULL) {
113                 archive_set_error(a,
114                     ENOMEM, "Out of memory adding file to list");
115                 return (ARCHIVE_FATAL);
116         }
117         s = (const char *)data;
118
119         do {
120                 mod = opt = val = NULL;
121
122                 parse_option(&s, &mod, &opt, &val);
123                 if (mod == NULL && opt != NULL &&
124                     strcmp("__ignore_wrong_module_name__", opt) == 0) {
125                         /* Ignore module name error */
126                         if (val != NULL) {
127                                 ignore_mod_err = 1;
128                                 anyok = 1;
129                         }
130                         continue;
131                 }
132
133                 r = use_option(a, mod, opt, val);
134                 if (r == ARCHIVE_FATAL) {
135                         free(data);
136                         return (ARCHIVE_FATAL);
137                 }
138                 if (r == ARCHIVE_FAILED && mod != NULL) {
139                         free(data);
140                         return (ARCHIVE_FAILED);
141                 }
142                 if (r == ARCHIVE_WARN - 1) {
143                         if (ignore_mod_err)
144                                 continue;
145                         /* The module name is wrong. */
146                         archive_set_error(a, ARCHIVE_ERRNO_MISC,
147                             "Unknown module name: `%s'", mod);
148                         free(data);
149                         return (ARCHIVE_FAILED);
150                 }
151                 if (r == ARCHIVE_WARN) {
152                         /* The option name is wrong. No-one used this. */
153                         archive_set_error(a, ARCHIVE_ERRNO_MISC,
154                             "Undefined option: `%s%s%s'",
155                             mod?mod:"", mod?":":"", opt);
156                         free(data);
157                         return (ARCHIVE_FAILED);
158                 }
159                 if (r == ARCHIVE_OK)
160                         anyok = 1;
161                 else
162                         allok = 0;
163         } while (s != NULL);
164
165         free(data);
166         return allok ? ARCHIVE_OK : anyok ? ARCHIVE_WARN : ARCHIVE_FAILED;
167 }
168
169 static const char *
170 parse_option(const char **s, const char **m, const char **o, const char **v)
171 {
172         const char *end, *mod, *opt, *val;
173         char *p;
174
175         end = NULL;
176         mod = NULL;
177         opt = *s;
178         val = "1";
179
180         p = strchr(opt, ',');
181
182         if (p != NULL) {
183                 *p = '\0';
184                 end = ((const char *)p) + 1;
185         }
186
187         if (0 == strlen(opt)) {
188                 *s = end;
189                 *m = NULL;
190                 *o = NULL;
191                 *v = NULL;
192                 return end;
193         }
194
195         p = strchr(opt, ':');
196         if (p != NULL) {
197                 *p = '\0';
198                 mod = opt;
199                 opt = ++p;
200         }
201
202         p = strchr(opt, '=');
203         if (p != NULL) {
204                 *p = '\0';
205                 val = ++p;
206         } else if (opt[0] == '!') {
207                 ++opt;
208                 val = NULL;
209         }
210
211         *s = end;
212         *m = mod;
213         *o = opt;
214         *v = val;
215
216         return end;
217 }
218