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 #include "archive_options_private.h" 30 31 static const char * 32 parse_option(const char **str, 33 const char **mod, const char **opt, const char **val); 34 35 int 36 _archive_set_option(struct archive *a, 37 const char *m, const char *o, const char *v, 38 int magic, const char *fn, option_handler use_option) 39 { 40 const char *mp, *op, *vp; 41 int r; 42 43 archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn); 44 45 mp = m != NULL && m[0] == '\0' ? NULL : m; 46 op = o != NULL && o[0] == '\0' ? NULL : o; 47 vp = v != NULL && v[0] == '\0' ? NULL : v; 48 49 if (op == NULL && vp == NULL) 50 return (ARCHIVE_OK); 51 if (op == NULL) { 52 archive_set_error(a, ARCHIVE_ERRNO_MISC, "Empty option"); 53 return (ARCHIVE_FAILED); 54 } 55 56 r = use_option(a, mp, op, vp); 57 if (r == ARCHIVE_WARN - 1) { 58 archive_set_error(a, ARCHIVE_ERRNO_MISC, 59 "Unknown module name: `%s'", mp); 60 return (ARCHIVE_FAILED); 61 } 62 if (r == ARCHIVE_WARN) { 63 archive_set_error(a, ARCHIVE_ERRNO_MISC, 64 "Undefined option: `%s%s%s%s%s%s'", 65 vp?"":"!", mp?mp:"", mp?":":"", op, vp?"=":"", vp?vp:""); 66 return (ARCHIVE_FAILED); 67 } 68 return (r); 69 } 70 71 int 72 _archive_set_either_option(struct archive *a, const char *m, const char *o, const char *v, 73 option_handler use_format_option, option_handler use_filter_option) 74 { 75 int r1, r2; 76 77 if (o == NULL && v == NULL) 78 return (ARCHIVE_OK); 79 if (o == NULL) 80 return (ARCHIVE_FAILED); 81 82 r1 = use_format_option(a, m, o, v); 83 if (r1 == ARCHIVE_FATAL) 84 return (ARCHIVE_FATAL); 85 86 r2 = use_filter_option(a, m, o, v); 87 if (r2 == ARCHIVE_FATAL) 88 return (ARCHIVE_FATAL); 89 90 if (r2 == ARCHIVE_WARN - 1) 91 return r1; 92 return r1 > r2 ? r1 : r2; 93 } 94 95 int 96 _archive_set_options(struct archive *a, const char *options, 97 int magic, const char *fn, option_handler use_option) 98 { 99 int allok = 1, anyok = 0, ignore_mod_err = 0, r; 100 char *data; 101 const char *s, *mod, *opt, *val; 102 103 archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn); 104 105 if (options == NULL || options[0] == '\0') 106 return ARCHIVE_OK; 107 108 data = (char *)malloc(strlen(options) + 1); 109 strcpy(data, options); 110 s = (const char *)data; 111 112 do { 113 mod = opt = val = NULL; 114 115 parse_option(&s, &mod, &opt, &val); 116 if (mod == NULL && opt != NULL && 117 strcmp("__ignore_wrong_module_name__", opt) == 0) { 118 /* Ignore module name error */ 119 if (val != NULL) { 120 ignore_mod_err = 1; 121 anyok = 1; 122 } 123 continue; 124 } 125 126 r = use_option(a, mod, opt, val); 127 if (r == ARCHIVE_FATAL) { 128 free(data); 129 return (ARCHIVE_FATAL); 130 } 131 if (r == ARCHIVE_FAILED && mod != NULL) { 132 free(data); 133 return (ARCHIVE_FAILED); 134 } 135 if (r == ARCHIVE_WARN - 1) { 136 if (ignore_mod_err) 137 continue; 138 /* The module name is wrong. */ 139 archive_set_error(a, ARCHIVE_ERRNO_MISC, 140 "Unknown module name: `%s'", mod); 141 free(data); 142 return (ARCHIVE_FAILED); 143 } 144 if (r == ARCHIVE_WARN) { 145 /* The option name is wrong. No-one used this. */ 146 archive_set_error(a, ARCHIVE_ERRNO_MISC, 147 "Undefined option: `%s%s%s'", 148 mod?mod:"", mod?":":"", opt); 149 free(data); 150 return (ARCHIVE_FAILED); 151 } 152 if (r == ARCHIVE_OK) 153 anyok = 1; 154 else 155 allok = 0; 156 } while (s != NULL); 157 158 free(data); 159 return allok ? ARCHIVE_OK : anyok ? ARCHIVE_WARN : ARCHIVE_FAILED; 160 } 161 162 static const char * 163 parse_option(const char **s, const char **m, const char **o, const char **v) 164 { 165 const char *end, *mod, *opt, *val; 166 char *p; 167 168 end = NULL; 169 mod = NULL; 170 opt = *s; 171 val = "1"; 172 173 p = strchr(opt, ','); 174 175 if (p != NULL) { 176 *p = '\0'; 177 end = ((const char *)p) + 1; 178 } 179 180 if (0 == strlen(opt)) { 181 *s = end; 182 *m = NULL; 183 *o = NULL; 184 *v = NULL; 185 return end; 186 } 187 188 p = strchr(opt, ':'); 189 if (p != NULL) { 190 *p = '\0'; 191 mod = opt; 192 opt = ++p; 193 } 194 195 p = strchr(opt, '='); 196 if (p != NULL) { 197 *p = '\0'; 198 val = ++p; 199 } else if (opt[0] == '!') { 200 ++opt; 201 val = NULL; 202 } 203 204 *s = end; 205 *m = mod; 206 *o = opt; 207 *v = val; 208 209 return end; 210 } 211 212