archive_options.c revision 311042
1142425Snectar/*-
2142425Snectar * Copyright (c) 2011 Tim Kientzle
3142425Snectar * All rights reserved.
4142425Snectar *
5142425Snectar * Redistribution and use in source and binary forms, with or without
6142425Snectar * modification, are permitted provided that the following conditions
7142425Snectar * are met:
8142425Snectar * 1. Redistributions of source code must retain the above copyright
9142425Snectar *    notice, this list of conditions and the following disclaimer.
10142425Snectar * 2. Redistributions in binary form must reproduce the above copyright
11142425Snectar *    notice, this list of conditions and the following disclaimer in the
12142425Snectar *    documentation and/or other materials provided with the distribution.
13142425Snectar *
14142425Snectar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15142425Snectar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16142425Snectar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17142425Snectar * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18142425Snectar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19142425Snectar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20142425Snectar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21142425Snectar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22160814Ssimon * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23160814Ssimon * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24160814Ssimon */
25142425Snectar
26142425Snectar#include "archive_platform.h"
27160814Ssimon__FBSDID("$FreeBSD$");
28160814Ssimon
29160814Ssimon#ifdef HAVE_ERRNO_H
30142425Snectar#include <errno.h>
31142425Snectar#endif
32142425Snectar
33142425Snectar#include "archive_options_private.h"
34142425Snectar
35142425Snectarstatic const char *
36142425Snectarparse_option(const char **str,
37142425Snectar    const char **mod, const char **opt, const char **val);
38142425Snectar
39142425Snectarint
40142425Snectar_archive_set_option(struct archive *a,
41142425Snectar    const char *m, const char *o, const char *v,
42142425Snectar    int magic, const char *fn, option_handler use_option)
43142425Snectar{
44194206Ssimon	const char *mp, *op, *vp;
45142425Snectar	int r;
46142425Snectar
47142425Snectar	archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
48142425Snectar
49142425Snectar	mp = (m != NULL && m[0] != '\0') ? m : NULL;
50142425Snectar	op = (o != NULL && o[0] != '\0') ? o : NULL;
51142425Snectar	vp = (v != NULL && v[0] != '\0') ? v : NULL;
52142425Snectar
53142425Snectar	if (op == NULL && vp == NULL)
54142425Snectar		return (ARCHIVE_OK);
55142425Snectar	if (op == NULL) {
56142425Snectar		archive_set_error(a, ARCHIVE_ERRNO_MISC, "Empty option");
57160814Ssimon		return (ARCHIVE_FAILED);
58160814Ssimon	}
59142425Snectar
60142425Snectar	r = use_option(a, mp, op, vp);
61142425Snectar	if (r == ARCHIVE_WARN - 1) {
62142425Snectar		archive_set_error(a, ARCHIVE_ERRNO_MISC,
63142425Snectar		    "Unknown module name: `%s'", mp);
64142425Snectar		return (ARCHIVE_FAILED);
65142425Snectar	}
66142425Snectar	if (r == ARCHIVE_WARN) {
67142425Snectar		archive_set_error(a, ARCHIVE_ERRNO_MISC,
68142425Snectar		    "Undefined option: `%s%s%s%s%s%s'",
69142425Snectar		    vp?"":"!", mp?mp:"", mp?":":"", op, vp?"=":"", vp?vp:"");
70142425Snectar		return (ARCHIVE_FAILED);
71142425Snectar	}
72142425Snectar	return (r);
73160814Ssimon}
74142425Snectar
75142425Snectarint
76142425Snectar_archive_set_either_option(struct archive *a, const char *m, const char *o, const char *v,
77142425Snectar    option_handler use_format_option, option_handler use_filter_option)
78142425Snectar{
79142425Snectar	int r1, r2;
80142425Snectar
81142425Snectar	if (o == NULL && v == NULL)
82142425Snectar		return (ARCHIVE_OK);
83142425Snectar	if (o == NULL)
84142425Snectar		return (ARCHIVE_FAILED);
85194206Ssimon
86194206Ssimon	r1 = use_format_option(a, m, o, v);
87194206Ssimon	if (r1 == ARCHIVE_FATAL)
88194206Ssimon		return (ARCHIVE_FATAL);
89194206Ssimon
90194206Ssimon	r2 = use_filter_option(a, m, o, v);
91194206Ssimon	if (r2 == ARCHIVE_FATAL)
92194206Ssimon		return (ARCHIVE_FATAL);
93142425Snectar
94194206Ssimon	if (r2 == ARCHIVE_WARN - 1)
95194206Ssimon		return r1;
96142425Snectar	return r1 > r2 ? r1 : r2;
97194206Ssimon}
98160814Ssimon
99194206Ssimonint
100194206Ssimon_archive_set_options(struct archive *a, const char *options,
101194206Ssimon    int magic, const char *fn, option_handler use_option)
102194206Ssimon{
103194206Ssimon	int allok = 1, anyok = 0, ignore_mod_err = 0, r;
104142425Snectar	char *data;
105194206Ssimon	const char *s, *mod, *opt, *val;
106194206Ssimon
107194206Ssimon	archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
108142425Snectar
109194206Ssimon	if (options == NULL || options[0] == '\0')
110194206Ssimon		return ARCHIVE_OK;
111194206Ssimon
112194206Ssimon	if ((data = strdup(options)) == NULL) {
113160814Ssimon		archive_set_error(a,
114194206Ssimon		    ENOMEM, "Out of memory adding file to list");
115205128Ssimon		return (ARCHIVE_FATAL);
116205128Ssimon	}
117194206Ssimon	s = (const char *)data;
118194206Ssimon
119205128Ssimon	do {
120205128Ssimon		mod = opt = val = NULL;
121205128Ssimon
122160814Ssimon		parse_option(&s, &mod, &opt, &val);
123160814Ssimon		if (mod == NULL && opt != NULL &&
124160814Ssimon		    strcmp("__ignore_wrong_module_name__", opt) == 0) {
125194206Ssimon			/* Ignore module name error */
126205128Ssimon			if (val != NULL) {
127205128Ssimon				ignore_mod_err = 1;
128205128Ssimon				anyok = 1;
129205128Ssimon			}
130194206Ssimon			continue;
131194206Ssimon		}
132194206Ssimon
133194206Ssimon		r = use_option(a, mod, opt, val);
134194206Ssimon		if (r == ARCHIVE_FATAL) {
135194206Ssimon			free(data);
136194206Ssimon			return (ARCHIVE_FATAL);
137194206Ssimon		}
138142425Snectar		if (r == ARCHIVE_FAILED && mod != NULL) {
139142425Snectar			free(data);
140194206Ssimon			return (ARCHIVE_FAILED);
141194206Ssimon		}
142194206Ssimon		if (r == ARCHIVE_WARN - 1) {
143194206Ssimon			if (ignore_mod_err)
144194206Ssimon				continue;
145194206Ssimon			/* The module name is wrong. */
146194206Ssimon			archive_set_error(a, ARCHIVE_ERRNO_MISC,
147194206Ssimon			    "Unknown module name: `%s'", mod);
148194206Ssimon			free(data);
149142425Snectar			return (ARCHIVE_FAILED);
150194206Ssimon		}
151194206Ssimon		if (r == ARCHIVE_WARN) {
152194206Ssimon			/* The option name is wrong. No-one used this. */
153142425Snectar			archive_set_error(a, ARCHIVE_ERRNO_MISC,
154194206Ssimon			    "Undefined option: `%s%s%s'",
155194206Ssimon			    mod?mod:"", mod?":":"", opt);
156194206Ssimon			free(data);
157194206Ssimon			return (ARCHIVE_FAILED);
158194206Ssimon		}
159194206Ssimon		if (r == ARCHIVE_OK)
160194206Ssimon			anyok = 1;
161194206Ssimon		else
162194206Ssimon			allok = 0;
163194206Ssimon	} while (s != NULL);
164194206Ssimon
165194206Ssimon	free(data);
166194206Ssimon	return allok ? ARCHIVE_OK : anyok ? ARCHIVE_WARN : ARCHIVE_FAILED;
167194206Ssimon}
168194206Ssimon
169194206Ssimonstatic const char *
170194206Ssimonparse_option(const char **s, const char **m, const char **o, const char **v)
171194206Ssimon{
172194206Ssimon	const char *end, *mod, *opt, *val;
173194206Ssimon	char *p;
174194206Ssimon
175194206Ssimon	end = NULL;
176142425Snectar	mod = NULL;
177194206Ssimon	opt = *s;
178194206Ssimon	val = "1";
179194206Ssimon
180142425Snectar	p = strchr(opt, ',');
181194206Ssimon
182194206Ssimon	if (p != NULL) {
183194206Ssimon		*p = '\0';
184194206Ssimon		end = ((const char *)p) + 1;
185194206Ssimon	}
186194206Ssimon
187194206Ssimon	if (0 == strlen(opt)) {
188194206Ssimon		*s = end;
189194206Ssimon		*m = NULL;
190194206Ssimon		*o = NULL;
191194206Ssimon		*v = NULL;
192194206Ssimon		return end;
193142425Snectar	}
194142425Snectar
195194206Ssimon	p = strchr(opt, ':');
196194206Ssimon	if (p != NULL) {
197194206Ssimon		*p = '\0';
198194206Ssimon		mod = opt;
199194206Ssimon		opt = ++p;
200194206Ssimon	}
201194206Ssimon
202194206Ssimon	p = strchr(opt, '=');
203194206Ssimon	if (p != NULL) {
204194206Ssimon		*p = '\0';
205194206Ssimon		val = ++p;
206194206Ssimon	} else if (opt[0] == '!') {
207142425Snectar		++opt;
208194206Ssimon		val = NULL;
209194206Ssimon	}
210194206Ssimon
211194206Ssimon	*s = end;
212194206Ssimon	*m = mod;
213194206Ssimon	*o = opt;
214194206Ssimon	*v = val;
215194206Ssimon
216194206Ssimon	return end;
217194206Ssimon}
218194206Ssimon
219194206Ssimon