diff options
-rw-r--r-- | src/anydb.c | 2 | ||||
-rw-r--r-- | src/cache.c | 2 | ||||
-rw-r--r-- | src/cyn-server.c | 34 | ||||
-rw-r--r-- | src/cynagora.c | 10 | ||||
-rw-r--r-- | src/cynagora.h | 2 | ||||
-rw-r--r-- | src/dbinit.c | 3 | ||||
-rw-r--r-- | src/expire.c | 114 | ||||
-rw-r--r-- | src/expire.h | 8 | ||||
-rw-r--r-- | src/main-cynagoracli.c | 7 |
9 files changed, 141 insertions, 41 deletions
diff --git a/src/anydb.c b/src/anydb.c index bfd2c09..ef41af7 100644 --- a/src/anydb.c +++ b/src/anydb.c @@ -209,6 +209,8 @@ expired( time_t expire, time_t now ) { + if (expire < 0) + expire = -(expire + 1); return expire && expire <= now; } diff --git a/src/cache.c b/src/cache.c index df346a8..d14e877 100644 --- a/src/cache.c +++ b/src/cache.c @@ -284,7 +284,7 @@ cache_put( item_t *item; size_t size; - if (cache == NULL || value < -128 || value > 127) + if (cache == NULL || value < -128 || value > 127 || expire < 0) return -EINVAL; item = search(cache, key); diff --git a/src/cyn-server.c b/src/cyn-server.c index 78143a4..8339d09 100644 --- a/src/cyn-server.c +++ b/src/cyn-server.c @@ -272,7 +272,7 @@ entercb( /** translate optional expire value */ static const char * -exp2txt( +exp2check( time_t expire, char *buffer, size_t bufsz @@ -280,11 +280,37 @@ exp2txt( if (!expire) return NULL; + if (expire < 0) + return "-"; /* no cache */ + /* TODO: check size */ snprintf(buffer, bufsz, "%lld", (long long)expire); return buffer; } +/** translate optional expire value */ +static +const char * +exp2get( + time_t expire, + char *buffer, + size_t bufsz +) { + if (!expire) + return NULL; + + if (expire < 0) { + expire = -(expire + 1); + if (!expire) + return "-"; + *buffer++ = '-'; + bufsz--; + } + + snprintf(buffer, bufsz, "%lld", (long long)expire); + return buffer; +} + /** callback of checking */ static void @@ -299,7 +325,7 @@ testcheckcb( if (!value) { vtxt = _no_; - etxt = 0; + etxt = NULL; } else { if (!strcmp(value->value, ALLOW)) vtxt = _yes_; @@ -307,7 +333,7 @@ testcheckcb( vtxt = _no_; else vtxt = _done_; - etxt = exp2txt(value->expire, text, sizeof text); + etxt = exp2check(value->expire, text, sizeof text); } putx(cli, vtxt, etxt, NULL); flushw(cli); @@ -346,7 +372,7 @@ getcb( char text[30]; putx(cli, _item_, key->client, key->session, key->user, key->permission, - value->value, exp2txt(value->expire, text, sizeof text), NULL); + value->value, exp2get(value->expire, text, sizeof text), NULL); } /** handle a request */ diff --git a/src/cynagora.c b/src/cynagora.c index ee55dc6..4434d89 100644 --- a/src/cynagora.c +++ b/src/cynagora.c @@ -363,10 +363,12 @@ status_check( else rc = -EPROTO; - if (cynagora->reply.count >= 2) - *expire = strtoll(cynagora->reply.fields[1], NULL, 10); - else + if (cynagora->reply.count < 2) *expire = 0; + else if (cynagora->reply.fields[1][0] == '-') + *expire = -1; + else + *expire = strtoll(cynagora->reply.fields[1], NULL, 10); return rc; } @@ -553,7 +555,7 @@ check_or_test( rc = wait_pending_reply(cynagora); if (rc >= 0) { rc = status_check(cynagora, &expire); - if (rc >= 0 && action == _check_ && cynagora->cache) + if (rc >= 0 && action == _check_) cache_put(cynagora->cache, key, rc, expire); } } diff --git a/src/cynagora.h b/src/cynagora.h index d17476c..b77c0f4 100644 --- a/src/cynagora.h +++ b/src/cynagora.h @@ -58,7 +58,7 @@ struct cynagora_key { struct cynagora_value { /** the associated value */ const char *value; - /** the expiration */ + /** the expiration in seconds since epoch, negative to avoid cache */ time_t expire; }; diff --git a/src/dbinit.c b/src/dbinit.c index e2366ad..67738f4 100644 --- a/src/dbinit.c +++ b/src/dbinit.c @@ -96,8 +96,7 @@ int dbinit_add_file(const char *path) key.user = item[2]; key.permission = item[3]; value.value = item[4]; - value.expire = txt2exp(item[5]); - if (value.expire < 0) { + if (!txt2exp(item[5], &value.expire)) { fprintf(stderr, "bad expiration %s (%s:%d)\n", item[5], path, lino); rc = -EINVAL; goto error2; diff --git a/src/expire.c b/src/expire.c index 23ce6ae..2207d3c 100644 --- a/src/expire.c +++ b/src/expire.c @@ -20,9 +20,11 @@ /******************************************************************************/ /******************************************************************************/ +#include <stdbool.h> #include <time.h> #include <string.h> #include <stdio.h> +#include <limits.h> #include "expire.h" @@ -31,52 +33,116 @@ static const int MIN = 60; static const int HOUR = 60*60; static const int DAY = 24*60*60; static const int WEEK = 7*24*60*60; -static const int YEAR = 365*24*60*60 + 24*60*60/4; +static const int YEAR = 365*24*60*60 + 24*60*60/4; /* average includes leap */ +static const time_t TMIN = (time_t)1 << ((CHAR_BIT * sizeof(time_t)) - 1); +static const time_t TMAX = ~TMIN; -/* see expire.h */ -time_t txt2exp(const char *txt) +/** add positives x and y with saturation */ +static time_t pt_add(time_t x, time_t y) { - time_t r, x; + time_t r = x + y; + return r < 0 ? TMAX : r; +} - /* infinite time */ - if (!strcmp(txt, "always") || !strcmp(txt, "forever") || !strcmp(txt, "*")) - return 0; +/** multiply positive x by m with saturation */ +static time_t pt_mul(time_t x, int m) +{ + time_t r; + + if (m <= 1) + r = 0; + else { + r = pt_mul(x, m >> 1) << 1; + if (r < 0) + r = TMAX; + } + return (m & 1) ? pt_add(r, x) : r; +} + +/** multiply positive x by m and then add y with saturation */ +static time_t pt_muladd(time_t x, int m, time_t y) +{ + return pt_add(pt_mul(x, m), y); +} + +/** multiply positive x by 10 and then add d with saturation */ +static time_t pt_tm10a(time_t x, int d) +{ + return pt_muladd(x, 10, (time_t)d); +} + +/** translate the string 'txt' to its time representation */ +static bool parse_time_spec(const char *txt, time_t *time_out) +{ + time_t r, x; /* parse */ - r = time(NULL); + r = 0; while(*txt) { x = 0; while('0' <= *txt && *txt <= '9') - x = (x << 3) + (x << 1) + (time_t)(*txt++ - '0'); + x = pt_tm10a(x, *txt++ - '0'); switch(*txt) { - case 'y': r += x * YEAR; txt++; break; - case 'w': r += x * WEEK; txt++; break; - case 'd': r += x * DAY; txt++; break; - case 'h': r += x * HOUR; txt++; break; - case 'm': r += x * MIN; txt++; break; + case 'y': r = pt_muladd(x, YEAR, r); txt++; break; + case 'w': r = pt_muladd(x, WEEK, r); txt++; break; + case 'd': r = pt_muladd(x, DAY, r); txt++; break; + case 'h': r = pt_muladd(x, HOUR, r); txt++; break; + case 'm': r = pt_muladd(x, MIN, r); txt++; break; case 's': txt++; /*@fallthrough@*/ - case 0: r += x * SEC; break; - default: return -1; + case 0: r = pt_muladd(x, SEC, r); break; + default: return false; } } - return r; + *time_out = r; + return true; +} + + +/* see expire.h */ +bool txt2exp(const char *txt, time_t *time_out) +{ + bool nocache; + time_t r; + + /* no cache */ + nocache = txt[0] == '-'; + txt += nocache; + + /* infinite time */ + if (!txt[0] || !strcmp(txt, "always") || !strcmp(txt, "forever") || !strcmp(txt, "*")) { + r = 0; + } else { + /* parse */ + if (!parse_time_spec(txt, &r)) + return false; + /* relative time */ + r = pt_add(r, time(NULL)); + } + + *time_out = nocache ? -(r + 1) : r; + return true; } /* see expire.h */ size_t exp2txt(time_t expire, char *buffer, size_t buflen) { char b[100]; - size_t l; - int n; + size_t l, n; - if (!expire) - strncpy(b, "forever", sizeof b); - else { + n = 0; + if (expire < 0) { + b[n++] = '-'; + b[n] = 0; + expire = -(expire + 1); + } + if (!expire) { + if (!n) + strncpy(b, "forever", sizeof b); + } else { expire -= time(NULL); - n = 0; #define ADD(C,U) \ if (expire >= U) { \ - n += snprintf(&b[n], sizeof b - (size_t)n, "%lld" #C, (long long)(expire / U)); \ + n += (size_t)snprintf(&b[n], sizeof b - (size_t)n, "%lld" #C, (long long)(expire / U)); \ expire %= U; \ } ADD(y,YEAR) diff --git a/src/expire.h b/src/expire.h index 1de82c2..4d996f8 100644 --- a/src/expire.h +++ b/src/expire.h @@ -34,12 +34,14 @@ * - 2m2w means two months and 2 weeks * * @param txt the text to convert - * @return the value for the text + * @param time_out where to store the result + * @return true if valid false otherwise */ extern -time_t +bool txt2exp( - const char *txt + const char *txt, + time_t *time_out ); /** diff --git a/src/main-cynagoracli.c b/src/main-cynagoracli.c index db36243..af84760 100644 --- a/src/main-cynagoracli.c +++ b/src/main-cynagoracli.c @@ -334,9 +334,12 @@ int get_csupve(int ac, char **av, int *used, const char *def) key.user = n > 3 ? av[3] : def; key.permission = n > 4 ? av[4] : def; value.value = n > 5 ? av[5] : "no"; - value.expire = n > 6 ? txt2exp(av[6]) : 0; + if (n <= 6) + value.expire = 0; + else if (!txt2exp(av[6], &value.expire)) + return -EINVAL; - return key.client && key.session && key.user && key.permission && value.value && value.expire >= 0 ? 0 : -EINVAL; + return key.client && key.session && key.user && key.permission && value.value ? 0 : -EINVAL; } int get_csup(int ac, char **av, int *used, const char *def) |