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 unsigned 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 (r1 == ARCHIVE_WARN - 1) 94 return r2; 95 if (r2 == ARCHIVE_WARN -1) 96 return r1; 97 return r1 > r2 ? r1 : r2; 98 } 99 100 int 101 _archive_set_options(struct archive *a, const char *options, 102 unsigned int magic, const char *fn, option_handler use_option) 103 { 104 int allok = 1, anyok = 0, ignore_mod_err = 0, r; 105 char *data; 106 const char *s, *mod, *opt, *val; 107 108 archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn); 109 110 if (options == NULL || options[0] == '\0') 111 return ARCHIVE_OK; 112 113 if ((data = strdup(options)) == NULL) { 114 archive_set_error(a, 115 ENOMEM, "Out of memory adding file to list"); 116 return (ARCHIVE_FATAL); 117 } 118 s = (const char *)data; 119 120 do { 121 mod = opt = val = NULL; 122 123 parse_option(&s, &mod, &opt, &val); 124 if (mod == NULL && opt != NULL && 125 strcmp("__ignore_wrong_module_name__", opt) == 0) { 126 /* Ignore module name error */ 127 if (val != NULL) { 128 ignore_mod_err = 1; 129 anyok = 1; 130 } 131 continue; 132 } 133 134 r = use_option(a, mod, opt, val); 135 if (r == ARCHIVE_FATAL) { 136 free(data); 137 return (ARCHIVE_FATAL); 138 } 139 if (r == ARCHIVE_FAILED && mod != NULL) { 140 free(data); 141 return (ARCHIVE_FAILED); 142 } 143 if (r == ARCHIVE_WARN - 1) { 144 if (ignore_mod_err) 145 continue; 146 /* The module name is wrong. */ 147 archive_set_error(a, ARCHIVE_ERRNO_MISC, 148 "Unknown module name: `%s'", mod); 149 free(data); 150 return (ARCHIVE_FAILED); 151 } 152 if (r == ARCHIVE_WARN) { 153 /* The option name is wrong. No-one used this. */ 154 archive_set_error(a, ARCHIVE_ERRNO_MISC, 155 "Undefined option: `%s%s%s'", 156 mod?mod:"", mod?":":"", opt); 157 free(data); 158 return (ARCHIVE_FAILED); 159 } 160 if (r == ARCHIVE_OK) 161 anyok = 1; 162 else 163 allok = 0; 164 } while (s != NULL); 165 166 free(data); 167 return allok ? ARCHIVE_OK : anyok ? ARCHIVE_WARN : ARCHIVE_FAILED; 168 } 169 170 static const char * 171 parse_option(const char **s, const char **m, const char **o, const char **v) 172 { 173 const char *end, *mod, *opt, *val; 174 char *p; 175 176 end = NULL; 177 mod = NULL; 178 opt = *s; 179 val = "1"; 180 181 p = strchr(opt, ','); 182 183 if (p != NULL) { 184 *p = '\0'; 185 end = ((const char *)p) + 1; 186 } 187 188 if (0 == strlen(opt)) { 189 *s = end; 190 *m = NULL; 191 *o = NULL; 192 *v = NULL; 193 return end; 194 } 195 196 p = strchr(opt, ':'); 197 if (p != NULL) { 198 *p = '\0'; 199 mod = opt; 200 opt = ++p; 201 } 202 203 p = strchr(opt, '='); 204 if (p != NULL) { 205 *p = '\0'; 206 val = ++p; 207 } else if (opt[0] == '!') { 208 ++opt; 209 val = NULL; 210 } 211 212 *s = end; 213 *m = mod; 214 *o = opt; 215 *v = val; 216 217 return end; 218 } 219 220