ed78476a6e5993de0934b9ea859e3faca2e93325
[obnox/samba/samba-obnox.git] / source3 / lib / gencache.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Generic, persistent and shared between processes cache mechanism for use
5    by various parts of the Samba code
6
7    Copyright (C) Rafal Szczesniak    2002
8    Copyright (C) Volker Lendecke     2009
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "system/filesys.h"
26 #include "system/glob.h"
27 #include "util_tdb.h"
28 #include "tdb_wrap/tdb_wrap.h"
29 #include "../lib/util/memcache.h"
30
31 #undef  DBGC_CLASS
32 #define DBGC_CLASS DBGC_TDB
33
34 #define TIMEOUT_LEN 12
35 #define CACHE_DATA_FMT  "%12u/"
36 #define READ_CACHE_DATA_FMT_TEMPLATE "%%12u/%%%us"
37 #define BLOB_TYPE "DATA_BLOB"
38 #define BLOB_TYPE_LEN 9
39
40 static struct tdb_wrap *cache;
41 static struct tdb_wrap *cache_notrans;
42 static int cache_notrans_seqnum;
43
44 /**
45  * @file gencache.c
46  * @brief Generic, persistent and shared between processes cache mechanism
47  *        for use by various parts of the Samba code
48  *
49  **/
50
51
52 /**
53  * Cache initialisation function. Opens cache tdb file or creates
54  * it if does not exist.
55  *
56  * @return true on successful initialisation of the cache or
57  *         false on failure
58  **/
59
60 static bool gencache_init(void)
61 {
62         char* cache_fname = NULL;
63         int open_flags = O_RDWR|O_CREAT;
64
65         /* skip file open if it's already opened */
66         if (cache) {
67                 return true;
68         }
69
70         cache_fname = cache_path("gencache.tdb");
71         if (cache_fname == NULL) {
72                 return false;
73         }
74
75         DEBUG(5, ("Opening cache file at %s\n", cache_fname));
76
77         cache = tdb_wrap_open(NULL, cache_fname, 0,
78                               TDB_DEFAULT|TDB_INCOMPATIBLE_HASH,
79                               open_flags, 0644);
80         if (cache) {
81                 int ret;
82                 ret = tdb_check(cache->tdb, NULL, NULL);
83                 if (ret != 0) {
84                         TALLOC_FREE(cache);
85
86                         /*
87                          * Retry with CLEAR_IF_FIRST.
88                          *
89                          * Warning: Converting this to dbwrap won't work
90                          * directly. gencache.c does transactions on this tdb,
91                          * and dbwrap forbids this for CLEAR_IF_FIRST
92                          * databases. tdb does allow transactions on
93                          * CLEAR_IF_FIRST databases, so lets use it here to
94                          * clean up a broken database.
95                          */
96                         cache = tdb_wrap_open(NULL, cache_fname, 0,
97                                               TDB_DEFAULT|
98                                               TDB_INCOMPATIBLE_HASH|
99                                               TDB_CLEAR_IF_FIRST,
100                                               open_flags, 0644);
101                 }
102         }
103
104         if (!cache && (errno == EACCES)) {
105                 open_flags = O_RDONLY;
106                 cache = tdb_wrap_open(NULL, cache_fname, 0,
107                                       TDB_DEFAULT|TDB_INCOMPATIBLE_HASH,
108                                       open_flags, 0644);
109                 if (cache) {
110                         DEBUG(5, ("gencache_init: Opening cache file %s read-only.\n", cache_fname));
111                 }
112         }
113         TALLOC_FREE(cache_fname);
114
115         if (!cache) {
116                 DEBUG(5, ("Attempt to open gencache.tdb has failed.\n"));
117                 return false;
118         }
119
120         cache_fname = lock_path("gencache_notrans.tdb");
121         if (cache_fname == NULL) {
122                 TALLOC_FREE(cache);
123                 return false;
124         }
125
126         DEBUG(5, ("Opening cache file at %s\n", cache_fname));
127
128         cache_notrans = tdb_wrap_open(NULL, cache_fname, 0,
129                                       TDB_CLEAR_IF_FIRST|
130                                       TDB_INCOMPATIBLE_HASH|
131                                       TDB_SEQNUM|
132                                       TDB_NOSYNC|
133                                       TDB_MUTEX_LOCKING,
134                                       open_flags, 0644);
135         if (cache_notrans == NULL) {
136                 DEBUG(5, ("Opening %s failed: %s\n", cache_fname,
137                           strerror(errno)));
138                 TALLOC_FREE(cache_fname);
139                 TALLOC_FREE(cache);
140                 return false;
141         }
142         TALLOC_FREE(cache_fname);
143
144         return true;
145 }
146
147 static TDB_DATA last_stabilize_key(void)
148 {
149         TDB_DATA result;
150         result.dptr = discard_const_p(uint8_t, "@LAST_STABILIZED");
151         result.dsize = 17;
152         return result;
153 }
154
155 struct gencache_have_val_state {
156         time_t new_timeout;
157         const DATA_BLOB *data;
158         bool gotit;
159 };
160
161 static void gencache_have_val_parser(time_t old_timeout, DATA_BLOB data,
162                                      void *private_data)
163 {
164         struct gencache_have_val_state *state =
165                 (struct gencache_have_val_state *)private_data;
166         time_t now = time(NULL);
167         int cache_time_left, new_time_left, additional_time;
168
169         /*
170          * Excuse the many variables, but these time calculations are
171          * confusing to me. We do not want to write to gencache with a
172          * possibly expensive transaction if we are about to write the same
173          * value, just extending the remaining timeout by less than 10%.
174          */
175
176         cache_time_left = old_timeout - now;
177         if (cache_time_left <= 0) {
178                 /*
179                  * timed out, write new value
180                  */
181                 return;
182         }
183
184         new_time_left = state->new_timeout - now;
185         if (new_time_left <= 0) {
186                 /*
187                  * Huh -- no new timeout?? Write it.
188                  */
189                 return;
190         }
191
192         if (new_time_left < cache_time_left) {
193                 /*
194                  * Someone wants to shorten the timeout. Let it happen.
195                  */
196                 return;
197         }
198
199         /*
200          * By how much does the new timeout extend the remaining cache time?
201          */
202         additional_time = new_time_left - cache_time_left;
203
204         if (additional_time * 10 < 0) {
205                 /*
206                  * Integer overflow. We extend by so much that we have to write it.
207                  */
208                 return;
209         }
210
211         /*
212          * The comparison below is essentially equivalent to
213          *
214          *    new_time_left > cache_time_left * 1.10
215          *
216          * but without floating point calculations.
217          */
218
219         if (additional_time * 10 > cache_time_left) {
220                 /*
221                  * We extend the cache timeout by more than 10%. Do it.
222                  */
223                 return;
224         }
225
226         /*
227          * Now the more expensive data compare.
228          */
229         if (data_blob_cmp(state->data, &data) != 0) {
230                 /*
231                  * Write a new value. Certainly do it.
232                  */
233                 return;
234         }
235
236         /*
237          * Extending the timeout by less than 10% for the same cache value is
238          * not worth the trouble writing a value into gencache under a
239          * possibly expensive transaction.
240          */
241         state->gotit = true;
242 }
243
244 static bool gencache_have_val(const char *keystr, const DATA_BLOB *data,
245                               time_t timeout)
246 {
247         struct gencache_have_val_state state;
248
249         state.new_timeout = timeout;
250         state.data = data;
251         state.gotit = false;
252
253         if (!gencache_parse(keystr, gencache_have_val_parser, &state)) {
254                 return false;
255         }
256         return state.gotit;
257 }
258
259 static int last_stabilize_parser(TDB_DATA key, TDB_DATA data,
260                                  void *private_data)
261 {
262         time_t *last_stabilize = private_data;
263
264         if ((data.dsize != 0) && (data.dptr[data.dsize-1] == '\0')) {
265                 *last_stabilize = atoi((char *)data.dptr);
266         }
267         return 0;
268 }
269
270 /**
271  * Set an entry in the cache file. If there's no such
272  * one, then add it.
273  *
274  * @param keystr string that represents a key of this entry
275  * @param blob DATA_BLOB value being cached
276  * @param timeout time when the value is expired
277  *
278  * @retval true when entry is successfully stored
279  * @retval false on failure
280  **/
281
282 bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob,
283                             time_t timeout)
284 {
285         int ret;
286         char* val;
287         time_t last_stabilize;
288         static int writecount;
289
290         if (tdb_data_cmp(string_term_tdb_data(keystr),
291                          last_stabilize_key()) == 0) {
292                 DEBUG(10, ("Can't store %s as a key\n", keystr));
293                 return false;
294         }
295
296         if ((keystr == NULL) || (blob == NULL)) {
297                 return false;
298         }
299
300         if (!gencache_init()) {
301                 return false;
302         }
303
304         if (gencache_have_val(keystr, blob, timeout)) {
305                 DEBUG(10, ("Did not store value for %s, we already got it\n",
306                            keystr));
307                 return true;
308         }
309
310         val = talloc_asprintf(talloc_tos(), CACHE_DATA_FMT, (int)timeout);
311         if (val == NULL) {
312                 return false;
313         }
314         val = talloc_realloc(NULL, val, char, talloc_array_length(val)-1);
315         if (val == NULL) {
316                 return false;
317         }
318         val = (char *)talloc_append_blob(NULL, val, *blob);
319         if (val == NULL) {
320                 return false;
321         }
322
323         DEBUG(10, ("Adding cache entry with key=[%s] and timeout="
324                    "[%s] (%d seconds %s)\n", keystr,
325                    timestring(talloc_tos(), timeout),
326                    (int)(timeout - time(NULL)), 
327                    timeout > time(NULL) ? "ahead" : "in the past"));
328
329         ret = tdb_store_bystring(
330                 cache_notrans->tdb, keystr,
331                 make_tdb_data((uint8_t *)val, talloc_array_length(val)),
332                 0);
333         TALLOC_FREE(val);
334
335         if (ret != 0) {
336                 return false;
337         }
338
339         /*
340          * Every 100 writes within a single process, stabilize the cache with
341          * a transaction. This is done to prevent a single transaction to
342          * become huge and chew lots of memory.
343          */
344         writecount += 1;
345         if (writecount > lp_parm_int(-1, "gencache", "stabilize_count", 100)) {
346                 gencache_stabilize();
347                 writecount = 0;
348                 goto done;
349         }
350
351         /*
352          * Every 5 minutes, call gencache_stabilize() to not let grow
353          * gencache_notrans.tdb too large.
354          */
355
356         last_stabilize = 0;
357
358         tdb_parse_record(cache_notrans->tdb, last_stabilize_key(),
359                          last_stabilize_parser, &last_stabilize);
360
361         if ((last_stabilize
362              + lp_parm_int(-1, "gencache", "stabilize_interval", 300))
363             < time(NULL)) {
364                 gencache_stabilize();
365         }
366
367 done:
368         return ret == 0;
369 }
370
371 /**
372  * Delete one entry from the cache file.
373  *
374  * @param keystr string that represents a key of this entry
375  *
376  * @retval true upon successful deletion
377  * @retval false in case of failure
378  **/
379
380 bool gencache_del(const char *keystr)
381 {
382         bool exists, was_expired;
383         bool ret = false;
384         DATA_BLOB value;
385
386         if (keystr == NULL) {
387                 return false;
388         }
389
390         if (!gencache_init()) {
391                 return false;
392         }
393
394         DEBUG(10, ("Deleting cache entry (key=[%s])\n", keystr));
395
396         /*
397          * We delete an element by setting its timeout to 0. This way we don't
398          * have to do a transaction on gencache.tdb every time we delete an
399          * element.
400          */
401
402         exists = gencache_get_data_blob(keystr, NULL, &value, NULL,
403                                         &was_expired);
404
405         if (!exists && was_expired) {
406                 /*
407                  * gencache_get_data_blob has implicitly deleted this
408                  * entry, so we have to return success here.
409                  */
410                 return true;
411         }
412
413         if (exists) {
414                 data_blob_free(&value);
415                 ret = gencache_set(keystr, "", 0);
416         }
417         return ret;
418 }
419
420 static bool gencache_pull_timeout(char *val, time_t *pres, char **pendptr)
421 {
422         time_t res;
423         char *endptr;
424
425         if (val == NULL) {
426                 return false;
427         }
428
429         res = strtol(val, &endptr, 10);
430
431         if ((endptr == NULL) || (*endptr != '/')) {
432                 DEBUG(2, ("Invalid gencache data format: %s\n", val));
433                 return false;
434         }
435         if (pres != NULL) {
436                 *pres = res;
437         }
438         if (pendptr != NULL) {
439                 *pendptr = endptr;
440         }
441         return true;
442 }
443
444 struct gencache_parse_state {
445         void (*parser)(time_t timeout, DATA_BLOB blob, void *private_data);
446         void *private_data;
447         bool is_memcache;
448 };
449
450 static int gencache_parse_fn(TDB_DATA key, TDB_DATA data, void *private_data)
451 {
452         struct gencache_parse_state *state;
453         DATA_BLOB blob;
454         time_t t;
455         char *endptr;
456         bool ret;
457
458         if (data.dptr == NULL) {
459                 return -1;
460         }
461         ret = gencache_pull_timeout((char *)data.dptr, &t, &endptr);
462         if (!ret) {
463                 return -1;
464         }
465         state = (struct gencache_parse_state *)private_data;
466         blob = data_blob_const(
467                 endptr+1, data.dsize - PTR_DIFF(endptr+1, data.dptr));
468         state->parser(t, blob, state->private_data);
469
470         if (!state->is_memcache) {
471                 memcache_add(NULL, GENCACHE_RAM,
472                              data_blob_const(key.dptr, key.dsize),
473                              data_blob_const(data.dptr, data.dsize));
474         }
475
476         return 0;
477 }
478
479 bool gencache_parse(const char *keystr,
480                     void (*parser)(time_t timeout, DATA_BLOB blob,
481                                    void *private_data),
482                     void *private_data)
483 {
484         struct gencache_parse_state state;
485         TDB_DATA key = string_term_tdb_data(keystr);
486         DATA_BLOB memcache_val;
487         int ret;
488
489         if (keystr == NULL) {
490                 return false;
491         }
492         if (tdb_data_cmp(key, last_stabilize_key()) == 0) {
493                 return false;
494         }
495         if (!gencache_init()) {
496                 return false;
497         }
498
499         state.parser = parser;
500         state.private_data = private_data;
501
502         if (memcache_lookup(NULL, GENCACHE_RAM,
503                             data_blob_const(key.dptr, key.dsize),
504                             &memcache_val)) {
505                 /*
506                  * Make sure that nobody has changed the gencache behind our
507                  * back.
508                  */
509                 int current_seqnum = tdb_get_seqnum(cache_notrans->tdb);
510                 if (current_seqnum == cache_notrans_seqnum) {
511                         /*
512                          * Ok, our memcache is still current, use it without
513                          * going to the tdb files.
514                          */
515                         state.is_memcache = true;
516                         gencache_parse_fn(key, make_tdb_data(memcache_val.data,
517                                                              memcache_val.length),
518                                           &state);
519                         return true;
520                 }
521                 memcache_flush(NULL, GENCACHE_RAM);
522                 cache_notrans_seqnum = current_seqnum;
523         }
524
525         state.is_memcache = false;
526
527         ret = tdb_parse_record(cache_notrans->tdb, key,
528                                gencache_parse_fn, &state);
529         if (ret == 0) {
530                 return true;
531         }
532         ret = tdb_parse_record(cache->tdb, key, gencache_parse_fn, &state);
533         return (ret == 0);
534 }
535
536 struct gencache_get_data_blob_state {
537         TALLOC_CTX *mem_ctx;
538         DATA_BLOB *blob;
539         time_t timeout;
540         bool result;
541 };
542
543 static void gencache_get_data_blob_parser(time_t timeout, DATA_BLOB blob,
544                                           void *private_data)
545 {
546         struct gencache_get_data_blob_state *state =
547                 (struct gencache_get_data_blob_state *)private_data;
548
549         if (timeout == 0) {
550                 state->result = false;
551                 return;
552         }
553         state->timeout = timeout;
554
555         if (state->blob == NULL) {
556                 state->result = true;
557                 return;
558         }
559
560         *state->blob = data_blob_talloc(state->mem_ctx, blob.data,
561                                         blob.length);
562         if (state->blob->data == NULL) {
563                 state->result = false;
564                 return;
565         }
566         state->result = true;
567 }
568
569 /**
570  * Get existing entry from the cache file.
571  *
572  * @param keystr string that represents a key of this entry
573  * @param blob DATA_BLOB that is filled with entry's blob
574  * @param timeout pointer to a time_t that is filled with entry's
575  *        timeout
576  *
577  * @retval true when entry is successfuly fetched
578  * @retval false for failure
579  **/
580
581 bool gencache_get_data_blob(const char *keystr, TALLOC_CTX *mem_ctx,
582                             DATA_BLOB *blob,
583                             time_t *timeout, bool *was_expired)
584 {
585         struct gencache_get_data_blob_state state;
586         bool expired = false;
587
588         state.result = false;
589         state.mem_ctx = mem_ctx;
590         state.blob = blob;
591
592         if (!gencache_parse(keystr, gencache_get_data_blob_parser, &state)) {
593                 goto fail;
594         }
595         if (!state.result) {
596                 goto fail;
597         }
598         if (state.timeout <= time(NULL)) {
599                 /*
600                  * We're expired, delete the entry. We can't use gencache_del
601                  * here, because that uses gencache_get_data_blob for checking
602                  * the existence of a record. We know the thing exists and
603                  * directly store an empty value with 0 timeout.
604                  */
605                 gencache_set(keystr, "", 0);
606                 expired = true;
607                 goto fail;
608         }
609         if (timeout) {
610                 *timeout = state.timeout;
611         }
612
613         return true;
614
615 fail:
616         if (was_expired != NULL) {
617                 *was_expired = expired;
618         }
619         if (state.result && state.blob) {
620                 data_blob_free(state.blob);
621         }
622         return false;
623
624
625 struct stabilize_state {
626         bool written;
627 };
628 static int stabilize_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA val,
629                         void *priv);
630
631 static int wipe_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA val,
632                    void *priv);
633
634 /**
635  * Stabilize gencache
636  *
637  * Migrate the clear-if-first gencache data to the stable,
638  * transaction-based gencache.tdb
639  */
640
641 bool gencache_stabilize(void)
642 {
643         struct stabilize_state state;
644         int res;
645         char *now;
646
647         if (!gencache_init()) {
648                 return false;
649         }
650
651         res = tdb_transaction_start_nonblock(cache->tdb);
652         if (res != 0) {
653                 if (tdb_error(cache->tdb) == TDB_ERR_NOLOCK)
654                 {
655                         /*
656                          * Someone else already does the stabilize,
657                          * this does not have to be done twice
658                          */
659                         return true;
660                 }
661
662                 DEBUG(10, ("Could not start transaction on gencache.tdb: "
663                            "%s\n", tdb_errorstr(cache->tdb)));
664                 return false;
665         }
666
667         res = tdb_lockall(cache_notrans->tdb);
668         if (res != 0) {
669                 tdb_transaction_cancel(cache->tdb);
670                 DEBUG(10, ("Could not get allrecord lock on "
671                            "gencache_notrans.tdb: %s\n",
672                            tdb_errorstr(cache_notrans->tdb)));
673                 return false;
674         }
675
676         state.written = false;
677
678         res = tdb_traverse(cache_notrans->tdb, stabilize_fn, &state);
679         if (res < 0) {
680                 tdb_unlockall(cache_notrans->tdb);
681                 tdb_transaction_cancel(cache->tdb);
682                 return false;
683         }
684
685         if (!state.written) {
686                 tdb_unlockall(cache_notrans->tdb);
687                 tdb_transaction_cancel(cache->tdb);
688                 return true;
689         }
690
691         res = tdb_transaction_commit(cache->tdb);
692         if (res != 0) {
693                 DEBUG(10, ("tdb_transaction_commit on gencache.tdb failed: "
694                            "%s\n", tdb_errorstr(cache->tdb)));
695                 tdb_unlockall(cache_notrans->tdb);
696                 return false;
697         }
698
699         res = tdb_traverse(cache_notrans->tdb, wipe_fn, NULL);
700         if (res < 0) {
701                 DEBUG(10, ("tdb_traverse with wipe_fn on gencache_notrans.tdb "
702                           "failed: %s\n",
703                            tdb_errorstr(cache_notrans->tdb)));
704                 tdb_unlockall(cache_notrans->tdb);
705                 return false;
706         }
707
708         res = tdb_unlockall(cache_notrans->tdb);
709         if (res != 0) {
710                 DEBUG(10, ("tdb_unlockall on gencache.tdb failed: "
711                            "%s\n", tdb_errorstr(cache->tdb)));
712                 return false;
713         }
714
715         now = talloc_asprintf(talloc_tos(), "%d", (int)time(NULL));
716         if (now != NULL) {
717                 tdb_store(cache_notrans->tdb, last_stabilize_key(),
718                           string_term_tdb_data(now), 0);
719                 TALLOC_FREE(now);
720         }
721
722         return true;
723 }
724
725 static int stabilize_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA val,
726                         void *priv)
727 {
728         struct stabilize_state *state = (struct stabilize_state *)priv;
729         int res;
730         time_t timeout;
731
732         if (tdb_data_cmp(key, last_stabilize_key()) == 0) {
733                 return 0;
734         }
735
736         if (!gencache_pull_timeout((char *)val.dptr, &timeout, NULL)) {
737                 DEBUG(10, ("Ignoring invalid entry\n"));
738                 return 0;
739         }
740         if ((timeout < time(NULL)) || (val.dsize == 0)) {
741                 res = tdb_delete(cache->tdb, key);
742                 if (res == 0) {
743                         state->written = true;
744                 } else if (tdb_error(cache->tdb) == TDB_ERR_NOEXIST) {
745                         res = 0;
746                 }
747         } else {
748                 res = tdb_store(cache->tdb, key, val, 0);
749                 if (res == 0) {
750                         state->written = true;
751                 }
752         }
753
754         if (res != 0) {
755                 DEBUG(10, ("Transfer to gencache.tdb failed: %s\n",
756                            tdb_errorstr(cache->tdb)));
757                 return -1;
758         }
759
760         return 0;
761 }
762
763 static int wipe_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA val,
764                    void *priv)
765 {
766         int res;
767         bool ok;
768         time_t timeout;
769
770         res = tdb_data_cmp(key, last_stabilize_key());
771         if (res == 0) {
772                 return 0;
773         }
774
775         ok = gencache_pull_timeout((char *)val.dptr, &timeout, NULL);
776         if (!ok) {
777                 DEBUG(10, ("Ignoring invalid entry\n"));
778                 return 0;
779         }
780
781         res = tdb_delete(tdb, key);
782         if (res != 0) {
783                 DEBUG(10, ("tdb_delete from gencache_notrans.tdb failed: "
784                            "%s\n", tdb_errorstr(cache_notrans->tdb)));
785                 return -1;
786         }
787
788         return 0;
789 }
790
791
792 /**
793  * Get existing entry from the cache file.
794  *
795  * @param keystr string that represents a key of this entry
796  * @param valstr buffer that is allocated and filled with the entry value
797  *        buffer's disposing must be done outside
798  * @param timeout pointer to a time_t that is filled with entry's
799  *        timeout
800  *
801  * @retval true when entry is successfuly fetched
802  * @retval false for failure
803  **/
804
805 bool gencache_get(const char *keystr, TALLOC_CTX *mem_ctx, char **value,
806                   time_t *ptimeout)
807 {
808         DATA_BLOB blob;
809         bool ret = false;
810
811         ret = gencache_get_data_blob(keystr, mem_ctx, &blob, ptimeout, NULL);
812         if (!ret) {
813                 return false;
814         }
815         if ((blob.data == NULL) || (blob.length == 0)) {
816                 data_blob_free(&blob);
817                 return false;
818         }
819         if (blob.data[blob.length-1] != '\0') {
820                 /* Not NULL terminated, can't be a string */
821                 data_blob_free(&blob);
822                 return false;
823         }
824         if (value) {
825                 /*
826                  * talloc_move generates a type-punned warning here. As we
827                  * leave the function immediately, do a simple talloc_steal.
828                  */
829                 *value = (char *)talloc_steal(mem_ctx, blob.data);
830                 return true;
831         }
832         data_blob_free(&blob);
833         return true;
834 }
835
836 /**
837  * Set an entry in the cache file. If there's no such
838  * one, then add it.
839  *
840  * @param keystr string that represents a key of this entry
841  * @param value text representation value being cached
842  * @param timeout time when the value is expired
843  *
844  * @retval true when entry is successfuly stored
845  * @retval false on failure
846  **/
847
848 bool gencache_set(const char *keystr, const char *value, time_t timeout)
849 {
850         DATA_BLOB blob = data_blob_const(value, strlen(value)+1);
851         return gencache_set_data_blob(keystr, &blob, timeout);
852 }
853
854 struct gencache_iterate_blobs_state {
855         void (*fn)(const char *key, DATA_BLOB value,
856                    time_t timeout, void *private_data);
857         const char *pattern;
858         void *private_data;
859         bool in_persistent;
860 };
861
862 static int gencache_iterate_blobs_fn(struct tdb_context *tdb, TDB_DATA key,
863                                      TDB_DATA data, void *priv)
864 {
865         struct gencache_iterate_blobs_state *state =
866                 (struct gencache_iterate_blobs_state *)priv;
867         char *keystr;
868         char *free_key = NULL;
869         time_t timeout;
870         char *endptr;
871
872         if (tdb_data_cmp(key, last_stabilize_key()) == 0) {
873                 return 0;
874         }
875         if (state->in_persistent && tdb_exists(cache_notrans->tdb, key)) {
876                 return 0;
877         }
878
879         if (key.dptr[key.dsize-1] == '\0') {
880                 keystr = (char *)key.dptr;
881         } else {
882                 /* ensure 0-termination */
883                 keystr = talloc_strndup(talloc_tos(), (char *)key.dptr, key.dsize);
884                 free_key = keystr;
885                 if (keystr == NULL) {
886                         goto done;
887                 }
888         }
889
890         if (!gencache_pull_timeout((char *)data.dptr, &timeout, &endptr)) {
891                 goto done;
892         }
893         endptr += 1;
894
895         if (fnmatch(state->pattern, keystr, 0) != 0) {
896                 goto done;
897         }
898
899         DEBUG(10, ("Calling function with arguments "
900                    "(key=[%s], timeout=[%s])\n",
901                    keystr, timestring(talloc_tos(), timeout)));
902
903         state->fn(keystr,
904                   data_blob_const(endptr,
905                                   data.dsize - PTR_DIFF(endptr, data.dptr)),
906                   timeout, state->private_data);
907
908  done:
909         TALLOC_FREE(free_key);
910         return 0;
911 }
912
913 void gencache_iterate_blobs(void (*fn)(const char *key, DATA_BLOB value,
914                                        time_t timeout, void *private_data),
915                             void *private_data, const char *pattern)
916 {
917         struct gencache_iterate_blobs_state state;
918
919         if ((fn == NULL) || (pattern == NULL) || !gencache_init()) {
920                 return;
921         }
922
923         DEBUG(5, ("Searching cache keys with pattern %s\n", pattern));
924
925         state.fn = fn;
926         state.pattern = pattern;
927         state.private_data = private_data;
928
929         state.in_persistent = false;
930         tdb_traverse(cache_notrans->tdb, gencache_iterate_blobs_fn, &state);
931
932         state.in_persistent = true;
933         tdb_traverse(cache->tdb, gencache_iterate_blobs_fn, &state);
934 }
935
936 /**
937  * Iterate through all entries which key matches to specified pattern
938  *
939  * @param fn pointer to the function that will be supplied with each single
940  *        matching cache entry (key, value and timeout) as an arguments
941  * @param data void pointer to an arbitrary data that is passed directly to the fn
942  *        function on each call
943  * @param keystr_pattern pattern the existing entries' keys are matched to
944  *
945  **/
946
947 struct gencache_iterate_state {
948         void (*fn)(const char *key, const char *value, time_t timeout,
949                    void *priv);
950         void *private_data;
951 };
952
953 static void gencache_iterate_fn(const char *key, DATA_BLOB value,
954                                 time_t timeout, void *private_data)
955 {
956         struct gencache_iterate_state *state =
957                 (struct gencache_iterate_state *)private_data;
958         char *valstr;
959         char *free_val = NULL;
960
961         if (value.data[value.length-1] == '\0') {
962                 valstr = (char *)value.data;
963         } else {
964                 /* ensure 0-termination */
965                 valstr = talloc_strndup(talloc_tos(), (char *)value.data, value.length);
966                 free_val = valstr;
967                 if (valstr == NULL) {
968                         goto done;
969                 }
970         }
971
972         DEBUG(10, ("Calling function with arguments "
973                    "(key=[%s], value=[%s], timeout=[%s])\n",
974                    key, valstr, timestring(talloc_tos(), timeout)));
975
976         state->fn(key, valstr, timeout, state->private_data);
977
978   done:
979
980         TALLOC_FREE(free_val);
981 }
982
983 void gencache_iterate(void (*fn)(const char *key, const char *value,
984                                  time_t timeout, void *dptr),
985                       void *private_data, const char *pattern)
986 {
987         struct gencache_iterate_state state;
988
989         if (fn == NULL) {
990                 return;
991         }
992         state.fn = fn;
993         state.private_data = private_data;
994         gencache_iterate_blobs(gencache_iterate_fn, &state, pattern);
995 }