diff options
-rw-r--r-- | lib/Makefile.am | 7 | ||||
-rw-r--r-- | lib/bidimap.c | 175 | ||||
-rw-r--r-- | lib/filemap.c | 66 | ||||
-rw-r--r-- | lib/gdbmmap.c | 6 | ||||
-rw-r--r-- | lib/ldapmap.c | 46 | ||||
-rw-r--r-- | lib/libeclat.h | 12 | ||||
-rw-r--r-- | lib/map.c | 44 | ||||
-rw-r--r-- | lib/nullmap.c | 2 | ||||
-rw-r--r-- | lib/seqmap.c | 4 | ||||
-rw-r--r-- | src/eclat.c | 3 | ||||
-rw-r--r-- | src/util.c | 18 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rw-r--r-- | tests/bidimap.at | 58 | ||||
-rw-r--r-- | tests/filemap.at | 15 | ||||
-rw-r--r-- | tests/testsuite.at | 1 |
15 files changed, 423 insertions, 35 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index e418134..8bd147c 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -25,9 +25,12 @@ if COND_LDAP endif maps = \ + bidimap.c\ $(GDBMMAP)\ filemap.c\ - $(LDAPMAP) + nullmap.c\ + $(LDAPMAP)\ + seqmap.c libeclat_a_SOURCES=\ base64.c\ @@ -44,14 +47,12 @@ libeclat_a_SOURCES=\ hmac_sha1.c\ libeclat.h\ map.c\ - nullmap.c\ q2url.c\ qaddparm.c\ qcreat.c\ qencode.c\ qfree.c\ reqsign.c\ - seqmap.c\ sha1.c\ sha1.h\ urlencode.c\ diff --git a/lib/bidimap.c b/lib/bidimap.c new file mode 100644 index 0000000..022e821 --- /dev/null +++ b/lib/bidimap.c @@ -0,0 +1,175 @@ +/* This file is part of Eclat. + Copyright (C) 2012 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include "libeclat.h" +#include <errno.h> + +struct bidimap { + struct submap { + char *name; + struct eclat_map *map; + int dir; + } submap[2]; +}; + +static int +cb_submap(enum grecs_callback_command cmd, + grecs_locus_t *locus, + void *varptr, + grecs_value_t *value, + void *cb_data) +{ + struct submap *submap = varptr; + char *name, *q; + int dir; + + if (cmd != grecs_callback_set_value) { + grecs_error(locus, 0, "Unexpected block statement"); + return 1; + } + if (!value || value->type != GRECS_TYPE_STRING) { + grecs_error(locus, 0, "expected a string"); + return 1; + } + + dir = eclat_map_name_split(value->v.string, &submap->name, &q); + if (dir == -1) { + grecs_error(locus, 0, "bad qualifier: %s", q); + return 1; + } + + submap->dir = dir; + return 0; +} + +static struct grecs_keyword bidimap_kw[] = { + { "type", "'bidi", "Set bi-directional map type", grecs_type_null }, + { "key", "<arg: string>", "key expression", grecs_type_null }, + { "direct-map", "arg", "map for direct lookups", + grecs_type_string, GRECS_DFLT, + NULL, offsetof(struct bidimap, submap[MAP_DIR]), cb_submap }, + { "reverse-map", "arg", "map for reverse lookups", + grecs_type_string, GRECS_DFLT, + NULL, offsetof(struct bidimap, submap[MAP_REV]), cb_submap }, + { NULL } +}; + +static void +bidimap_confhelp() +{ + static struct grecs_keyword bidimap_top[] = { + { "map", "name: string", + "Configuration for a generic bi-directional map", + grecs_type_section, GRECS_INAC, NULL, 0, NULL, NULL, + bidimap_kw }, + { NULL } + }; + grecs_print_statement_array(bidimap_top, 1, 0, stdout); +} + +static void +bidimap_free(int dbg, void *data) +{ + struct bidimap *bidimap = data; + +#if 0 + /* FIXME: Uncomment this when reference + counters are implemented */ + eclat_map_free(bidimap->submap[MAP_DIR].map); + eclat_map_free(bidimap->submap[MAP_REV].map); +#endif + free(bidimap); +} + +static int +bidimap_config(int dbg, struct grecs_node *node, void *data) +{ + struct bidimap *map, **return_map = data; + int i; + + map = grecs_malloc(sizeof(*map)); + for (i = 0; bidimap_kw[i].ident; i++) + bidimap_kw[i].varptr = map; + if (grecs_tree_process(node->down, bidimap_kw)) { + bidimap_free(dbg, map); + return eclat_map_failure; + } + + if (!map->submap[MAP_DIR].name && !map->submap[MAP_REV].name) { + grecs_error(&node->locus, 0, "no maps declared"); + bidimap_free(dbg, map); + return eclat_map_failure; + } + + *return_map = map; + return eclat_map_ok; +} + +static int +bidimap_open(int dbg, void *data) +{ + struct bidimap *bidimap = data; + struct eclat_map *map; + int i; + int rc; + + for (i = 0; i < 2; i++) { + map = eclat_map_lookup(bidimap->submap[i].name); + if (!map) + continue; + if ((rc = eclat_map_open(map)) != eclat_map_ok) + return rc; + bidimap->submap[i].map = map; + } + return eclat_map_ok; +} + +static int +bidimap_close(int dbg, void *data) +{ + struct bidimap *map = data; + int i; + + for (i = 0; i < 2; i++) { + if (map->submap[i].map) + eclat_map_close(map->submap[i].map); + } + return eclat_map_ok; +} + +static int +bidimap_get(int dbg, int dir, void *data, const char *key, char **return_value) +{ + struct bidimap *map = data; + + if (!map->submap[dir].map) + return eclat_map_bad_dir; + + return eclat_map_get(map->submap[dir].map, map->submap[dir].dir, + key, return_value); +} + +struct eclat_map_drv eclat_map_drv_bidi = { + "bidi", + bidimap_config, + bidimap_open, + bidimap_close, + bidimap_get, + bidimap_free, + bidimap_confhelp +}; + + diff --git a/lib/filemap.c b/lib/filemap.c index c43ba35..e797169 100644 --- a/lib/filemap.c +++ b/lib/filemap.c @@ -111,7 +111,7 @@ skipline(FILE *fp) } static int -filemap_get(int dbg, void *data, const char *key, char **return_value) +filemap_get_0(int dbg, void *data, const char *key, char **return_value) { struct filemap *filemap = data; FILE *fp = filemap->fp; @@ -161,6 +161,70 @@ filemap_get(int dbg, void *data, const char *key, char **return_value) return rc; } +static int +filemap_get_1(int dbg, void *data, const char *key, char **return_value) +{ + struct filemap *filemap = data; + FILE *fp = filemap->fp; + int line = 0; + int rc, c; + const char *p; + size_t len; + + rewind(fp); + while ((c = getc(fp)) != EOF) { + line++; + while (c != EOF && (c == ' ' || c == '\t')) + c = getc(fp); + if (c == '\n') + continue; + if (c == '#') { + skipline(fp); + continue; + } + if (c == EOF) + break; + for (len = 0; c != EOF && c != ':'; len++) + c = getc(fp); + if (c == EOF) + break; + if (c == '\n') + continue; + if (c == ':') { + for (p = key, c = getc(fp), len++; + c != EOF && c != '\n' && *p == c; + p++, len++, c = getc(fp)); + if (c == EOF || c == '\n') + break; + skipline(fp); + } + } + + if (c == '\n') { + struct grecs_txtacc *acc; + + debug(dbg, 2, ("%s:%d: found key", filemap->name, line)); + fseek(fp, - (len + 1), SEEK_CUR); + acc = grecs_txtacc_create(); + while ((c = getc(fp)) != EOF && c != ':') + grecs_txtacc_grow_char(acc, c); + grecs_txtacc_grow_char(acc, 0); + *return_value = grecs_txtacc_finish(acc, 1); + grecs_txtacc_free(acc); + rc = eclat_map_ok; + } else + rc = eclat_map_not_found; + + return rc; +} + +static int +filemap_get(int dbg, int dir, void *data, const char *key, char **return_value) +{ + return (dir ? filemap_get_1 : filemap_get_0)(dbg, data, key, + return_value); +} + struct eclat_map_drv eclat_map_drv_file = { "file", filemap_config, diff --git a/lib/gdbmmap.c b/lib/gdbmmap.c index 8433923..aa87a8e 100644 --- a/lib/gdbmmap.c +++ b/lib/gdbmmap.c @@ -111,11 +111,15 @@ gdbm_map_close(int dbg, void *data) } static int -gdbm_map_get(int dbg, void *data, const char *key, char **return_value) +gdbm_map_get(int dbg, int dir, void *data, const char *key, + char **return_value) { struct gdbm_map *gdbm_map = data; datum keydat, content; + if (dir == MAP_REV) + return eclat_map_bad_dir; + keydat.dptr = (char*)key; keydat.dsize = strlen(key) + (gdbm_map->nullflag ? 1 : 0); gdbm_errno = 0; diff --git a/lib/ldapmap.c b/lib/ldapmap.c index 4e780af..092daa2 100644 --- a/lib/ldapmap.c +++ b/lib/ldapmap.c @@ -33,8 +33,8 @@ struct ldap_map { char *passfile; int tls; int prompt; - char *filter; - char *attr; + char *filter[2]; + char *attr[2]; int dbg; LDAP *ld; }; @@ -99,11 +99,19 @@ static struct grecs_keyword ldapmap_kw[] = { { "filter", "arg", "Filter expression", grecs_type_string, GRECS_DFLT, - NULL, offsetof(struct ldap_map, filter) }, + NULL, offsetof(struct ldap_map, filter[0]) }, + { "reverse-filter", "arg", + "Reverse filter expression", + grecs_type_string, GRECS_DFLT, + NULL, offsetof(struct ldap_map, filter[1]) }, { "attr", "arg", "Attribute to return", grecs_type_string, GRECS_DFLT, - NULL, offsetof(struct ldap_map, attr) }, + NULL, offsetof(struct ldap_map, attr[0]) }, + { "reverse-attr", "arg", + "Attribute to return from reverse lookup", + grecs_type_string, GRECS_DFLT, + NULL, offsetof(struct ldap_map, attr[1]) }, { "debug", "n", "Set LDAP debug level", grecs_type_int, GRECS_DFLT, @@ -137,14 +145,18 @@ ldap_map_config(int dbg, struct grecs_node *node, void *data) grecs_error(&node->locus, 0, "LDAP URI not supplied"); rc = 1; } - if (!ldap_map->filter) { + if (!ldap_map->filter[0] && !ldap_map->filter[1]) { grecs_error(&node->locus, 0, "LDAP filter not supplied"); rc = 1; } - if (!ldap_map->attr) { + if (ldap_map->filter[0] && !ldap_map->attr[0]) { grecs_error(&node->locus, 0, "LDAP attr not supplied"); rc = 1; } + if (ldap_map->filter[1] && !ldap_map->attr[1]) { + grecs_error(&node->locus, 0, "LDAP reverse-attr not supplied"); + rc = 1; + } if (rc) { ldap_map_free(dbg, ldap_map); @@ -179,8 +191,10 @@ ldap_map_free(int dbg, void *data) free(map->base); free(map->binddn); free(map->bindpw); - free(map->filter); - free(map->attr); + free(map->filter[0]); + free(map->filter[1]); + free(map->attr[0]); + free(map->attr[1]); free(data); } @@ -558,7 +572,8 @@ get_ldap_attrs(LDAP *ld, LDAPMessage *msg, const char *attr) } static int -ldap_map_get(int dbg, void *data, const char *key, char **return_value) +ldap_map_get(int dbg, int dir, void *data, const char *key, + char **return_value) { struct ldap_map *map = data; int rc, i; @@ -568,13 +583,16 @@ ldap_map_get(int dbg, void *data, const char *key, char **return_value) char **ret; const char *kwe[3]; char *filter; - + + if (!map->filter[dir]) + return eclat_map_bad_dir; + kwe[0] = "key"; kwe[1] = key; kwe[2] = NULL; - filter = eclat_expand_kw(map->filter, kwe); + filter = eclat_expand_kw(map->filter[dir], kwe); - attrs[0] = (char*) map->attr; + attrs[0] = (char*) map->attr[dir]; attrs[1] = NULL; rc = ldap_search_ext(map->ld, map->base, LDAP_SCOPE_SUBTREE, filter, attrs, 0, @@ -595,10 +613,10 @@ ldap_map_get(int dbg, void *data, const char *key, char **return_value) msg = ldap_first_entry(map->ld, res); if (!msg) { ldap_msgfree(res); - return eclat_map_failure; + return eclat_map_not_found; } - ret = get_ldap_attrs(map->ld, msg, map->attr); + ret = get_ldap_attrs(map->ld, msg, map->attr[dir]); ldap_msgfree(res); diff --git a/lib/libeclat.h b/lib/libeclat.h index a558dae..a0ae6d7 100644 --- a/lib/libeclat.h +++ b/lib/libeclat.h @@ -129,7 +129,7 @@ struct eclat_map_drv { int (*map_config)(int, struct grecs_node *, void *); int (*map_open)(int, void *); int (*map_close)(int, void *); - int (*map_get)(int, void *, const char *, char **); + int (*map_get)(int, int, void *, const char *, char **); void (*map_free)(int, void *); void (*map_confhelp)(void); }; @@ -145,22 +145,29 @@ struct eclat_map { enum eclat_map_status { eclat_map_ok, eclat_map_failure, + eclat_map_bad_dir, eclat_map_not_found }; +#define MAP_DIR 0 +#define MAP_REV 1 + void eclat_map_init(void); struct eclat_map *eclat_map_lookup(const char *name); int eclat_map_config(struct grecs_node *node, struct eclat_map **return_map); void eclat_map_free(struct eclat_map *map); int eclat_map_open(struct eclat_map *map); int eclat_map_close(struct eclat_map *map); -int eclat_map_get(struct eclat_map *map, const char *key, char **value); +int eclat_map_get(struct eclat_map *map, int dir, const char *key, + char **value); const char *eclat_map_strerror(int rc); int eclat_map_drv_register(struct eclat_map_drv *drv); void eclat_map_foreach(int (*fun)(struct eclat_map *, void *), void *data); void eclat_map_free_all(void); void eclat_map_confhelp(void); +int eclat_map_name_split(const char *mapname, char **name, char **endp); + int eclat_get_string_node(struct grecs_node *node, const char *name, int optional, struct grecs_node **pret); @@ -170,3 +177,4 @@ extern struct eclat_map_drv eclat_map_drv_gdbm; extern struct eclat_map_drv eclat_map_drv_ldap; extern struct eclat_map_drv eclat_map_drv_null; extern struct eclat_map_drv eclat_map_drv_seq; +extern struct eclat_map_drv eclat_map_drv_bidi; @@ -18,6 +18,7 @@ #include "wordsplit.h" #include <sysexits.h> #include <string.h> +#include <assert.h> static int map_dbg = -1; static struct grecs_symtab *openmap_symtab, *mapdrv_symtab; @@ -238,25 +239,28 @@ eclat_map_close(struct eclat_map *map) } int -eclat_map_get(struct eclat_map *map, const char *key, char **value) +eclat_map_get(struct eclat_map *map, int dir, const char *key, char **value) { int rc; char *p = NULL; debug(map_dbg, 1, - ("looking up \"%s\" in map \"%s\"", key, map->name)); + ("looking up \"%s\" in map \"%s\", dir=%d", key, map->name, + dir)); if (!(map->flags & ECLAT_MAP_OPEN)) { debug(map_dbg, 1, ("map \"%s\" not open", map->name)); return eclat_map_failure; } if (map->keytrans) { - const char *kwe[5]; + const char *kwe[7]; kwe[0] = "key"; kwe[1] = key; kwe[2] = "map"; kwe[3] = map->name; - kwe[4] = NULL; + kwe[4] = "dir"; + kwe[5] = dir ? "1" : "0"; + kwe[6] = NULL; p = eclat_expand_kw(map->keytrans, kwe); debug(map_dbg, 1, @@ -265,7 +269,7 @@ eclat_map_get(struct eclat_map *map, const char *key, char **value) key = p; } - rc = map->drv->map_get(map_dbg, map->data, key, value); + rc = map->drv->map_get(map_dbg, dir, map->data, key, value); free(p); @@ -285,6 +289,8 @@ eclat_map_strerror(int rc) return "failure"; case eclat_map_not_found: return "not found"; + case eclat_map_bad_dir: + return "wrond lookup direction"; } return "unknown error"; } @@ -340,3 +346,31 @@ eclat_map_confhelp() { grecs_symtab_enumerate(mapdrv_symtab, drv_help, NULL); } + +int +eclat_map_name_split(const char *mapname, char **name, char **endp) +{ + size_t len = strcspn(mapname, ":"); + int dir; + + if (endp) + *endp = (char*) mapname + len; + if (!mapname[len]) { + *name = grecs_strdup(mapname); + dir = MAP_DIR; + } else { + const char *q = mapname + len + 1; + + if (strcmp(q, "0") == 0 || strcmp(q, "dir") == 0) + dir = MAP_DIR; + else if (strcmp(q, "1") == 0 || strcmp(q, "rev") == 0) + dir = MAP_REV; + else + return -1; + + *name = grecs_malloc(len + 1); + memcpy(*name, mapname, len); + (*name)[len] = 0; + } + return dir; +} diff --git a/lib/nullmap.c b/lib/nullmap.c index 7d29191..ff446d9 100644 --- a/lib/nullmap.c +++ b/lib/nullmap.c @@ -63,7 +63,7 @@ nullmap_close(int dbg, void *data) } static int -nullmap_get(int dbg, void *data, const char *key, char **return_value) +nullmap_get(int dbg, int dir, void *data, const char *key, char **return_value) { *return_value = grecs_strdup(key); return eclat_map_ok; diff --git a/lib/seqmap.c b/lib/seqmap.c index 777bbd7..fe0aeba 100644 --- a/lib/seqmap.c +++ b/lib/seqmap.c @@ -126,7 +126,7 @@ seqmap_close(int dbg, void *data) } static int -seqmap_get(int dbg, void *data, const char *key, char **return_value) +seqmap_get(int dbg, int dir, void *data, const char *key, char **return_value) { struct seqmap *seqmap = data; size_t i; @@ -134,7 +134,7 @@ seqmap_get(int dbg, void *data, const char *key, char **return_value) char *v; for (i = 0; i < seqmap->nmaps; i++) { - int rc = eclat_map_get(seqmap->maps[i], p, &v); + int rc = eclat_map_get(seqmap->maps[i], dir, p, &v); free(p); if (rc != eclat_map_ok) { debug(dbg, 1, ("map %s returned %s", diff --git a/src/eclat.c b/src/eclat.c index 75e7c7d..0bc79ae 100644 --- a/src/eclat.c +++ b/src/eclat.c @@ -642,6 +642,7 @@ main(int argc, char **argv) eclat_map_drv_register(&eclat_map_drv_null); eclat_map_drv_register(&eclat_map_drv_file); eclat_map_drv_register(&eclat_map_drv_seq); + eclat_map_drv_register(&eclat_map_drv_bidi); #ifdef WITH_GDBM eclat_map_drv_register(&eclat_map_drv_gdbm); #endif @@ -696,7 +697,7 @@ main(int argc, char **argv) if (test_map_name) { int i; - + if (argc < 1) die(EX_USAGE, "wrong number of arguments"); translate_ids(argc, argv, test_map_name); @@ -27,21 +27,29 @@ translate_ids(int argc, char **argv, const char *mapname) int i; struct eclat_map *map; char *val; + char *p, *q, *realname; + int dir; if (!translate_option || argc == 0) return; if (custom_map) mapname = custom_map; - map = eclat_map_lookup(mapname); - if (!map) - die(EX_UNAVAILABLE, "no such map: %s", mapname); + dir = eclat_map_name_split(mapname, &realname, &q); + if (dir == -1) + die(EX_USAGE, "bad qualifier: %s", q); + + map = eclat_map_lookup(realname); + if (!map) + die(EX_UNAVAILABLE, "no such map: %s", realname); + free(realname); + if (eclat_map_open(map) != eclat_map_ok) exit(EX_UNAVAILABLE); for (i = 0; i < argc; i++) { if (!strchr(argv[i], '=')) { - int rc = eclat_map_get(map, argv[i], &val); + int rc = eclat_map_get(map, dir, argv[i], &val); if (rc != eclat_map_ok) { die(EX_UNAVAILABLE, "cannot translate %s: %s", argv[i], eclat_map_strerror(rc)); @@ -94,7 +102,7 @@ translate_resource_ids(int argc, char **argv) ws.ws_wordv[j]); if (eclat_map_open(map) != eclat_map_ok) exit(EX_UNAVAILABLE); - rc = eclat_map_get(map, p, &val); + rc = eclat_map_get(map, MAP_DIR, p, &val); if (rc != eclat_map_ok) { die(EX_UNAVAILABLE, "cannot translate %s using map %s: %s", diff --git a/tests/Makefile.am b/tests/Makefile.am index 8d12342..0a302a6 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -42,6 +42,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac TESTSUITE_AT = \ allocate-address.at\ associate-address.at\ + bidimap.at\ create-snapshot.at\ decode.at\ delete-snapshot.at\ diff --git a/tests/bidimap.at b/tests/bidimap.at new file mode 100644 index 0000000..ed3b6b9 --- /dev/null +++ b/tests/bidimap.at @@ -0,0 +1,58 @@ +# This file is part of Eclat -*- Autotest -*- +# Copyright (C) 2012 Sergey Poznyakoff +# +# Eclat is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# Eclat is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Eclat. If not, see <http://www.gnu.org/licenses/>. + +AT_SETUP([bidi]) +AT_KEYWORDS([map bidimap]) + +AT_DATA([test.conf], +[map dir { + type file; + file "dir.txt"; +} + +map rev { + type file; + file "rev.txt"; +}; + +map inst { + type bidi; + direct-map dir; + reverse-map rev; +} +]) + +AT_DATA([dir.txt], +[db:i-feed1234 +web:i-deadbeef +]) + +AT_DATA([rev.txt], +[i-deadbeef:web +i-feed1234:db +]) + +AT_CHECK([eclat --config-file test.conf --test-map inst:0 db], +[0], +[i-feed1234 +]) + +AT_CHECK([eclat --config-file test.conf --test-map inst:1 i-feed1234], +[0], +[db +]) + +AT_CLEANUP diff --git a/tests/filemap.at b/tests/filemap.at index b84da7c..52c5e83 100644 --- a/tests/filemap.at +++ b/tests/filemap.at @@ -35,4 +35,19 @@ AT_CHECK([eclat --config-file test.conf --test-map file dbserv], [i-deadbeef ]) +AT_CHECK([eclat --config-file test.conf --test-map file:rev i-feed1234], +[0], +[web +]) + +AT_CHECK([eclat --config-file test.conf --test-map file:rev i-12345678], +[0], +[dbserver +]) + +AT_CHECK([eclat --config-file test.conf --test-map file:rev i-deadbeef], +[0], +[dbserv +]) + AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index 65e1d99..35640e8 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -83,5 +83,6 @@ m4_include([nullmap.at]) m4_include([filemap.at]) m4_include([gdbmmap.at]) m4_include([seqmap.at]) +m4_include([bidimap.at]) # End of testsuite.at |