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 35static const char * 36parse_option(const char **str, 37 const char **mod, const char **opt, const char **val); 38 39int 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 75int 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 99int 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 169static const char * 170parse_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 219