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