diff options
author | syl <syl@cvs.openbsd.org> | 2013-07-11 11:41:14 +0000 |
---|---|---|
committer | syl <syl@cvs.openbsd.org> | 2013-07-11 11:41:14 +0000 |
commit | 7af59e9ed5721cb4e58cd41207ba61a521d546d7 (patch) | |
tree | 074b5a35bfdc5eeb68c5993006e3c7d0ca5fd2cf /lib | |
parent | e910acc1c82238c0f5107464ffb55739430ba0d7 (diff) |
Merge fuse_opt code with stsp@ fuse_opt code.
ok tedu@
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libfuse/fuse_opt.c | 269 | ||||
-rw-r--r-- | lib/libfuse/fuse_opt.h | 9 |
2 files changed, 231 insertions, 47 deletions
diff --git a/lib/libfuse/fuse_opt.c b/lib/libfuse/fuse_opt.c index 28f5661a723..4d8b609aa32 100644 --- a/lib/libfuse/fuse_opt.c +++ b/lib/libfuse/fuse_opt.c @@ -1,6 +1,7 @@ -/* $OpenBSD: fuse_opt.c,v 1.4 2013/06/12 22:44:42 tedu Exp $ */ +/* $OpenBSD: fuse_opt.c,v 1.5 2013/07/11 11:41:12 syl Exp $ */ /* * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com> + * Copyright (c) 2013 Stefan Sperling <stsp@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,6 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <assert.h> #include <stdlib.h> #include <string.h> @@ -22,44 +24,197 @@ #include "fuse_opt.h" #include "fuse_private.h" -int -fuse_opt_add_arg(struct fuse_args *args, const char *name) +static void +free_argv(char **argv, int argc) { - char **av; int i; - /* copy argv, we cannot reallocate the orignal argv */ - if (args->allocated == 0) { - av = malloc((args->argc + 1) * sizeof(*av)); - if (av == NULL) - return (-1); + for (i = 0; i < argc; i++) + free(argv[i]); + free(argv); +} + +static int +alloc_argv(struct fuse_args *args) +{ + char **argv; + int i; + + assert(!args->allocated); + + argv = calloc(args->argc, sizeof(*argv)); + if (argv == NULL) + return (-1); + if (args->argv) { for (i = 0; i < args->argc; i++) { - av[i] = strdup(args->argv[i]); - if (av[i] == NULL) + argv[i] = strdup(args->argv[i]); + if (argv[i] == NULL) { + free_argv(argv, i + 1); return (-1); + } + } + } + + args->allocated = 1; + args->argv = argv; + + return (0); +} + +static int +match_opt(const char *templ, const char *opt) +{ + const char *o, *t; + char *arg; + + arg = strpbrk(templ, " ="); + + /* verify template */ + t = templ; + if (*t == '-') { + t++; + if (*t == '-') + t++; + if (*t == 'o' || t == '\0') + return (0); + } + + /* skip leading -, -o, and -- in option name */ + o = opt; + if (*o == '-') { + o++; + if (*o == 'o' || *o == '-') + o++; + } + + /* empty option name is invalid */ + if (*o == '\0') + return (0); + + /* match option name */ + while (*t && *o) { + if (*t++ != *o++) + return (0); + if (arg && t == arg) { + if (*o != ' ' && *o != '=') + return (0); + o++; /* o now points at argument */ + if (*o == '\0') + return (0); + break; } + } + + /* match argument */ + if (arg) { + if (t != arg) + return (0); + t++; + /* does template have an argument? */ + if (*t != '%' && *t != '\0') + return (0); + if (*t == '%' && t[1] == '\0') + return (0); + /* yes it does, consume argument in opt */ + while (*o && *o != ' ') + o++; + } else if (*t != '\0') + return (0); + + /* we should have consumed entire opt string */ + if (*o != '\0') + return (0); + + return (1); +} + +static int +add_opt(char **opts, const char *opt) +{ + char *new_opts; - av[args->argc] = strdup(name); - if (av[args->argc] == NULL) + if (*opts == NULL) { + *opts = strdup(opt); + if (*opts == NULL) return (-1); + return (0); + } - args->argc++; - args->argv = av; - args->allocated = 1; - } else { - av = realloc(args->argv, (args->argc + 1) * sizeof(*av)); - if (av == NULL) + if (asprintf(&new_opts, "%s,%s", *opts, opt) == -1) + return (-1); + + free(*opts); + *opts = new_opts; + return (0); +} + +int +fuse_opt_add_opt(char **opts, const char *opt) +{ + int ret; + + if (opt == NULL || opt[0] == '\0') + return (-1); + + ret = add_opt(opts, opt); + return (ret); +} + +int +fuse_opt_add_opt_escaped(char **opts, const char *opt) +{ + size_t size = 0, escaped = 0; + const char *s = opt; + char *escaped_opt, *p; + int ret; + + if (opt == NULL || opt[0] == '\0') + return (-1); + + while (*s) { + /* malloc(size + escaped) overflow check */ + if (size >= (SIZE_T_MAX / 2)) return (-1); - args->argv = av; - args->argc++; - args->argv[args->argc - 1] = strdup(name); - if (args->argv[args->argc - 1] == NULL) + if (*s == ',' || *s == '\\') + escaped++; + s++; + size++; + } + + if (escaped > 0) { + escaped_opt = malloc(size + escaped); + if (escaped_opt == NULL) + return (-1); + s = opt; + p = escaped_opt; + while (*s) { + switch (*s) { + case ',': + case '\\': + *p++ = '\\'; + /* FALLTHROUGH */ + default: + *p++ = *s++; + } + } + *p = '\0'; + } else { + escaped_opt = strdup(opt); + if (escaped_opt == NULL) return (-1); } - return (0); + ret = add_opt(opts, escaped_opt); + free(escaped_opt); + return (ret); +} + +int +fuse_opt_add_arg(struct fuse_args *args, const char *name) +{ + return (fuse_opt_insert_arg(args, args->argc, name)); } int @@ -115,42 +270,66 @@ fuse_opt_parse(struct fuse_args *args, void *data, struct fuse_opt *opt, } int -fuse_opt_insert_arg(struct fuse_args *args, int p, const char *arg) +fuse_opt_insert_arg(struct fuse_args *args, int p, const char *name) { char **av; + char *this_arg, *next_arg; int i; - if (p > args->argc + 1) - return -1; + if (name == NULL || name[0] == '\0') + return (-1); - if (args->allocated) { - av = realloc(args->argv, (args->argc + 1) * sizeof(char *)); - if (av == NULL) - return (-1); + if (!args->allocated && alloc_argv(args)) + return (-1); - args->argv = av; - args->argc++; - for (i = args->argc - 1; i > p; i++) - args->argv[i] = args->argv[i - 1]; + if (p < 0 || p > args->argc) + return (-1); - args->argv[p] = strdup(arg); - if (args->argv[p] == NULL) - return (-1); + av = realloc(args->argv, (args->argc + 1) * sizeof(*av)); + if (av == NULL) + return (-1); + + this_arg = strdup(name); + if (this_arg == NULL) { + free(av); + return (-1); + } + + args->argc++; + args->argv = av; + for (i = p; i < args->argc; i++) { + next_arg = args->argv[i]; + args->argv[i] = this_arg; + this_arg = next_arg; } return (0); } -int +void fuse_opt_free_args(struct fuse_args *args) { - int i; + if (!args->allocated) + return; - if (args->allocated) - for (i = 0; i < args->argc; i++) - free(args->argv[i]); - free(args->argv); - args->allocated = 0; + free_argv(args->argv, args->argc); + args->argv = 0; args->argc = 0; + args->allocated = 0; +} + +int +fuse_opt_match(const struct fuse_opt *opts, const char *opt) +{ + const struct fuse_opt *this_opt = opts; + + if (opt == NULL || opt[0] == '\0') + return (0); + + while (this_opt->templ) { + if (match_opt(this_opt->templ, opt)) + return (1); + this_opt++; + } return (0); } diff --git a/lib/libfuse/fuse_opt.h b/lib/libfuse/fuse_opt.h index a3ff5ae0b42..c1ae74be1ea 100644 --- a/lib/libfuse/fuse_opt.h +++ b/lib/libfuse/fuse_opt.h @@ -1,4 +1,4 @@ -/* $OpenBSD: fuse_opt.h,v 1.1 2013/06/12 22:36:06 tedu Exp $ */ +/* $OpenBSD: fuse_opt.h,v 1.2 2013/07/11 11:41:13 syl Exp $ */ /* * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com> * @@ -37,7 +37,10 @@ struct fuse_opt { typedef int (*fuse_opt_proc_t)(void *, const char *, int, struct fuse_args *); int fuse_opt_add_arg(struct fuse_args *, const char *); int fuse_opt_insert_arg(struct fuse_args *, int, const char *); -int fuse_opt_free_args(struct fuse_args *); +void fuse_opt_free_args(struct fuse_args *); +int fuse_opt_add_opt(char **, const char *); +int fuse_opt_add_opt_escaped(char **, const char *); +int fuse_opt_match(const struct fuse_opt *, const char *); int fuse_opt_parse(struct fuse_args *, void *, struct fuse_opt *, fuse_opt_proc_t); @@ -47,6 +50,8 @@ int fuse_opt_parse(struct fuse_args *, void *, struct fuse_opt *, #define FUSE_OPT_END { NULL, 0, 0 } #define FUSE_OPT_KEY_OPT -1 #define FUSE_OPT_KEY_NONOPT -2 +#define FUSE_OPT_KEY_KEEP -3 +#define FUSE_OPT_KEY_DISCARD -4 #ifdef __cplusplus } |