s3-includes: only include system/glob.h when needed.
[kai/samba-autobuild/.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/glob.h"
26
27 #undef  DBGC_CLASS
28 #define DBGC_CLASS DBGC_TDB
29
30 #define TIMEOUT_LEN 12
31 #define CACHE_DATA_FMT  "%12u/"
32 #define READ_CACHE_DATA_FMT_TEMPLATE "%%12u/%%%us"
33 #define BLOB_TYPE "DATA_BLOB"
34 #define BLOB_TYPE_LEN 9
35
36 static struct tdb_context *cache;
37 static struct tdb_context *cache_notrans;
38
39 /**
40  * @file gencache.c
41  * @brief Generic, persistent and shared between processes cache mechanism
42  *        for use by various parts of the Samba code
43  *
44  **/
45
46
47 /**
48  * Cache initialisation function. Opens cache tdb file or creates
49  * it if does not exist.
50  *
51  * @return true on successful initialisation of the cache or
52  *         false on failure
53  **/
54
55 static bool gencache_init(void)
56 {
57         char* cache_fname = NULL;
58         int open_flags = O_RDWR|O_CREAT;
59         bool first_try = true;
60
61         /* skip file open if it's already opened */
62         if (cache) return True;
63
64         cache_fname = lock_path("gencache.tdb");
65
66         DEBUG(5, ("Opening cache file at %s\n", cache_fname));
67
68 again:
69         cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT|TDB_INCOMPATIBLE_HASH, open_flags, 0644);
70         if (cache) {
71                 int ret;
72                 ret = tdb_check(cache, NULL, NULL);
73                 if (ret != 0) {
74                         tdb_close(cache);
75                         cache = NULL;
76                         if (!first_try) {
77                                 DEBUG(0, ("gencache_init: tdb_check(%s) failed\n",
78                                           cache_fname));
79                                 return false;
80                         }
81                         first_try = false;
82                         DEBUG(0, ("gencache_init: tdb_check(%s) failed - retry after CLEAR_IF_FIRST\n",
83                                   cache_fname));
84                         cache = tdb_open_log(cache_fname, 0, TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, open_flags, 0644);
85                         if (cache) {
86                                 tdb_close(cache);
87                                 cache = NULL;
88                                 goto again;
89                         }
90                 }
91         }
92
93         if (!cache && (errno == EACCES)) {
94                 open_flags = O_RDONLY;
95                 cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT|TDB_INCOMPATIBLE_HASH, open_flags,
96                                      0644);
97                 if (cache) {
98                         DEBUG(5, ("gencache_init: Opening cache file %s read-only.\n", cache_fname));
99                 }
100         }
101
102         if (!cache) {
103                 DEBUG(5, ("Attempt to open gencache.tdb has failed.\n"));
104                 return False;
105         }
106
107         cache_fname = lock_path("gencache_notrans.tdb");
108
109         DEBUG(5, ("Opening cache file at %s\n", cache_fname));
110
111         cache_notrans = tdb_open_log(cache_fname, 0, TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
112                                      open_flags, 0644);
113         if (cache_notrans == NULL) {
114                 DEBUG(5, ("Opening %s failed: %s\n", cache_fname,
115                           strerror(errno)));
116                 tdb_close(cache);
117                 cache = NULL;
118                 return false;
119         }
120
121         return True;
122 }
123
124 static TDB_DATA last_stabilize_key(void)
125 {
126         TDB_DATA result;
127         result.dptr = (uint8_t *)"@LAST_STABILIZED";
128         result.dsize = 17;
129         return result;
130 }
131
132 /**
133  * Set an entry in the cache file. If there's no such
134  * one, then add it.
135  *
136  * @param keystr string that represents a key of this entry
137  * @param blob DATA_BLOB value being cached
138  * @param timeout time when the value is expired
139  *
140  * @retval true when entry is successfuly stored
141  * @retval false on failure
142  **/
143
144 bool gencache_set_data_blob(const char *keystr, const DATA_BLOB *blob,
145                             time_t timeout)
146 {
147         int ret;
148         TDB_DATA databuf;
149         char* val;
150         time_t last_stabilize;
151         static int writecount;
152
153         if (tdb_data_cmp(string_term_tdb_data(keystr),
154                          last_stabilize_key()) == 0) {
155                 DEBUG(10, ("Can't store %s as a key\n", keystr));
156                 return false;
157         }
158
159         if ((keystr == NULL) || (blob == NULL)) {
160                 return false;
161         }
162
163         if (!gencache_init()) return False;
164
165         val = talloc_asprintf(talloc_tos(), CACHE_DATA_FMT, (int)timeout);
166         if (val == NULL) {
167                 return False;
168         }
169         val = talloc_realloc(NULL, val, char, talloc_array_length(val)-1);
170         if (val == NULL) {
171                 return false;
172         }
173         val = (char *)talloc_append_blob(NULL, val, *blob);
174         if (val == NULL) {
175                 return false;
176         }
177
178         DEBUG(10, ("Adding cache entry with key = %s and timeout ="
179                    " %s (%d seconds %s)\n", keystr, ctime(&timeout),
180                    (int)(timeout - time(NULL)), 
181                    timeout > time(NULL) ? "ahead" : "in the past"));
182
183         ret = tdb_store_bystring(
184                 cache_notrans, keystr,
185                 make_tdb_data((uint8_t *)val, talloc_array_length(val)),
186                 0);
187         TALLOC_FREE(val);
188
189         if (ret != 0) {
190                 return false;
191         }
192
193         /*
194          * Every 100 writes within a single process, stabilize the cache with
195          * a transaction. This is done to prevent a single transaction to
196          * become huge and chew lots of memory.
197          */
198         writecount += 1;
199         if (writecount > lp_parm_int(-1, "gencache", "stabilize_count", 100)) {
200                 gencache_stabilize();
201                 writecount = 0;
202                 goto done;
203         }
204
205         /*
206          * Every 5 minutes, call gencache_stabilize() to not let grow
207          * gencache_notrans.tdb too large.
208          */
209
210         last_stabilize = 0;
211         databuf = tdb_fetch(cache_notrans, last_stabilize_key());
212         if ((databuf.dptr != NULL)
213             && (databuf.dptr[databuf.dsize-1] == '\0')) {
214                 last_stabilize = atoi((char *)databuf.dptr);
215                 SAFE_FREE(databuf.dptr);
216         }
217         if ((last_stabilize
218              + lp_parm_int(-1, "gencache", "stabilize_interval", 300))
219             < time(NULL)) {
220                 gencache_stabilize();
221         }
222
223 done:
224         return ret == 0;
225 }
226
227 /**
228  * Delete one entry from the cache file.
229  *
230  * @param keystr string that represents a key of this entry
231  *
232  * @retval true upon successful deletion
233  * @retval false in case of failure
234  **/
235
236 bool gencache_del(const char *keystr)
237 {
238         bool exists, was_expired;
239         bool ret = false;
240         DATA_BLOB value;
241
242         if (keystr == NULL) {
243                 return false;
244         }
245
246         if (!gencache_init()) return False;     
247
248         DEBUG(10, ("Deleting cache entry (key = %s)\n", keystr));
249
250         /*
251          * We delete an element by setting its timeout to 0. This way we don't
252          * have to do a transaction on gencache.tdb every time we delete an
253          * element.
254          */
255
256         exists = gencache_get_data_blob(keystr, &value, NULL, &was_expired);
257
258         if (!exists && was_expired) {
259                 /*
260                  * gencache_get_data_blob has implicitly deleted this
261                  * entry, so we have to return success here.
262                  */
263                 return true;
264         }
265
266         if (exists) {
267                 data_blob_free(&value);
268                 ret = gencache_set(keystr, "", 0);
269         }
270         return ret;
271 }
272
273 static bool gencache_pull_timeout(char *val, time_t *pres, char **pendptr)
274 {
275         time_t res;
276         char *endptr;
277
278         if (val == NULL) {
279                 return false;
280         }
281
282         res = strtol(val, &endptr, 10);
283
284         if ((endptr == NULL) || (*endptr != '/')) {
285                 DEBUG(2, ("Invalid gencache data format: %s\n", val));
286                 return false;
287         }
288         if (pres != NULL) {
289                 *pres = res;
290         }
291         if (pendptr != NULL) {
292                 *pendptr = endptr;
293         }
294         return true;
295 }
296
297 struct gencache_parse_state {
298         void (*parser)(time_t timeout, DATA_BLOB blob, void *private_data);
299         void *private_data;
300 };
301
302 static int gencache_parse_fn(TDB_DATA key, TDB_DATA data, void *private_data)
303 {
304         struct gencache_parse_state *state;
305         DATA_BLOB blob;
306         time_t t;
307         char *endptr;
308         bool ret;
309
310         if (data.dptr == NULL) {
311                 return -1;
312         }
313         ret = gencache_pull_timeout((char *)data.dptr, &t, &endptr);
314         if (!ret) {
315                 return -1;
316         }
317         state = (struct gencache_parse_state *)private_data;
318         blob = data_blob_const(
319                 endptr+1, data.dsize - PTR_DIFF(endptr+1, data.dptr));
320         state->parser(t, blob, state->private_data);
321         return 0;
322 }
323
324 bool gencache_parse(const char *keystr,
325                     void (*parser)(time_t timeout, DATA_BLOB blob,
326                                    void *private_data),
327                     void *private_data)
328 {
329         struct gencache_parse_state state;
330         TDB_DATA key;
331         int ret;
332
333         if (keystr == NULL) {
334                 return false;
335         }
336         if (tdb_data_cmp(string_term_tdb_data(keystr),
337                          last_stabilize_key()) == 0) {
338                 return false;
339         }
340         if (!gencache_init()) {
341                 return false;
342         }
343
344         key = string_term_tdb_data(keystr);
345         state.parser = parser;
346         state.private_data = private_data;
347
348         ret = tdb_parse_record(cache_notrans, key, gencache_parse_fn, &state);
349         if (ret != -1) {
350                 return true;
351         }
352         ret = tdb_parse_record(cache, key, gencache_parse_fn, &state);
353         return (ret != -1);
354 }
355
356 struct gencache_get_data_blob_state {
357         DATA_BLOB *blob;
358         time_t timeout;
359         bool result;
360 };
361
362 static void gencache_get_data_blob_parser(time_t timeout, DATA_BLOB blob,
363                                           void *private_data)
364 {
365         struct gencache_get_data_blob_state *state =
366                 (struct gencache_get_data_blob_state *)private_data;
367
368         if (timeout == 0) {
369                 state->result = false;
370                 return;
371         }
372         state->timeout = timeout;
373
374         if (state->blob == NULL) {
375                 state->result = true;
376                 return;
377         }
378
379         *state->blob = data_blob(blob.data, blob.length);
380         if (state->blob->data == NULL) {
381                 state->result = false;
382                 return;
383         }
384         state->result = true;
385 }
386
387 /**
388  * Get existing entry from the cache file.
389  *
390  * @param keystr string that represents a key of this entry
391  * @param blob DATA_BLOB that is filled with entry's blob
392  * @param timeout pointer to a time_t that is filled with entry's
393  *        timeout
394  *
395  * @retval true when entry is successfuly fetched
396  * @retval False for failure
397  **/
398
399 bool gencache_get_data_blob(const char *keystr, DATA_BLOB *blob,
400                             time_t *timeout, bool *was_expired)
401 {
402         struct gencache_get_data_blob_state state;
403         bool expired = false;
404
405         state.result = false;
406         state.blob = blob;
407
408         if (!gencache_parse(keystr, gencache_get_data_blob_parser, &state)) {
409                 goto fail;
410         }
411         if (!state.result) {
412                 goto fail;
413         }
414         if (state.timeout <= time(NULL)) {
415                 /*
416                  * We're expired, delete the entry. We can't use gencache_del
417                  * here, because that uses gencache_get_data_blob for checking
418                  * the existence of a record. We know the thing exists and
419                  * directly store an empty value with 0 timeout.
420                  */
421                 gencache_set(keystr, "", 0);
422                 expired = true;
423                 goto fail;
424         }
425         if (timeout) {
426                 *timeout = state.timeout;
427         }
428
429         return True;
430
431 fail:
432         if (was_expired != NULL) {
433                 *was_expired = expired;
434         }
435         if (state.result && state.blob) {
436                 data_blob_free(state.blob);
437         }
438         return false;
439
440
441 struct stabilize_state {
442         bool written;
443         bool error;
444 };
445 static int stabilize_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA val,
446                         void *priv);
447
448 /**
449  * Stabilize gencache
450  *
451  * Migrate the clear-if-first gencache data to the stable,
452  * transaction-based gencache.tdb
453  */
454
455 bool gencache_stabilize(void)
456 {
457         struct stabilize_state state;
458         int res;
459         char *now;
460
461         if (!gencache_init()) {
462                 return false;
463         }
464
465         res = tdb_transaction_start_nonblock(cache);
466         if (res == -1) {
467
468                 if (tdb_error(cache) == TDB_ERR_NOLOCK) {
469                         /*
470                          * Someone else already does the stabilize,
471                          * this does not have to be done twice
472                          */
473                         return true;
474                 }
475
476                 DEBUG(10, ("Could not start transaction on gencache.tdb: "
477                            "%s\n", tdb_errorstr(cache)));
478                 return false;
479         }
480         res = tdb_transaction_start(cache_notrans);
481         if (res == -1) {
482                 tdb_transaction_cancel(cache);
483                 DEBUG(10, ("Could not start transaction on "
484                            "gencache_notrans.tdb: %s\n",
485                            tdb_errorstr(cache_notrans)));
486                 return false;
487         }
488
489         state.error = false;
490         state.written = false;
491
492         res = tdb_traverse(cache_notrans, stabilize_fn, &state);
493         if ((res == -1) || state.error) {
494                 if ((tdb_transaction_cancel(cache_notrans) == -1)
495                     || (tdb_transaction_cancel(cache) == -1)) {
496                         smb_panic("tdb_transaction_cancel failed\n");
497                 }
498                 return false;
499         }
500
501         if (!state.written) {
502                 if ((tdb_transaction_cancel(cache_notrans) == -1)
503                     || (tdb_transaction_cancel(cache) == -1)) {
504                         smb_panic("tdb_transaction_cancel failed\n");
505                 }
506                 return true;
507         }
508
509         res = tdb_transaction_commit(cache);
510         if (res == -1) {
511                 DEBUG(10, ("tdb_transaction_commit on gencache.tdb failed: "
512                            "%s\n", tdb_errorstr(cache)));
513                 if (tdb_transaction_cancel(cache_notrans) == -1) {
514                         smb_panic("tdb_transaction_cancel failed\n");
515                 }
516                 return false;
517         }
518
519         res = tdb_transaction_commit(cache_notrans);
520         if (res == -1) {
521                 DEBUG(10, ("tdb_transaction_commit on gencache.tdb failed: "
522                            "%s\n", tdb_errorstr(cache)));
523                 return false;
524         }
525
526         now = talloc_asprintf(talloc_tos(), "%d", (int)time(NULL));
527         if (now != NULL) {
528                 tdb_store(cache_notrans, last_stabilize_key(),
529                           string_term_tdb_data(now), 0);
530                 TALLOC_FREE(now);
531         }
532
533         return true;
534 }
535
536 static int stabilize_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA val,
537                         void *priv)
538 {
539         struct stabilize_state *state = (struct stabilize_state *)priv;
540         int res;
541         time_t timeout;
542
543         if (tdb_data_cmp(key, last_stabilize_key()) == 0) {
544                 return 0;
545         }
546
547         if (!gencache_pull_timeout((char *)val.dptr, &timeout, NULL)) {
548                 DEBUG(10, ("Ignoring invalid entry\n"));
549                 return 0;
550         }
551         if ((timeout < time(NULL)) || (val.dsize == 0)) {
552                 res = tdb_delete(cache, key);
553                 if ((res == -1) && (tdb_error(cache) == TDB_ERR_NOEXIST)) {
554                         res = 0;
555                 } else {
556                         state->written = true;
557                 }
558         } else {
559                 res = tdb_store(cache, key, val, 0);
560                 if (res == 0) {
561                         state->written = true;
562                 }
563         }
564
565         if (res == -1) {
566                 DEBUG(10, ("Transfer to gencache.tdb failed: %s\n",
567                            tdb_errorstr(cache)));
568                 state->error = true;
569                 return -1;
570         }
571
572         if (tdb_delete(cache_notrans, key) == -1) {
573                 DEBUG(10, ("tdb_delete from gencache_notrans.tdb failed: "
574                            "%s\n", tdb_errorstr(cache_notrans)));
575                 state->error = true;
576                 return -1;
577         }
578         return 0;
579 }
580
581 /**
582  * Get existing entry from the cache file.
583  *
584  * @param keystr string that represents a key of this entry
585  * @param valstr buffer that is allocated and filled with the entry value
586  *        buffer's disposing must be done outside
587  * @param timeout pointer to a time_t that is filled with entry's
588  *        timeout
589  *
590  * @retval true when entry is successfuly fetched
591  * @retval False for failure
592  **/
593
594 bool gencache_get(const char *keystr, char **value, time_t *ptimeout)
595 {
596         DATA_BLOB blob;
597         bool ret = False;
598
599         ret = gencache_get_data_blob(keystr, &blob, ptimeout, NULL);
600         if (!ret) {
601                 return false;
602         }
603         if ((blob.data == NULL) || (blob.length == 0)) {
604                 SAFE_FREE(blob.data);
605                 return false;
606         }
607         if (blob.data[blob.length-1] != '\0') {
608                 /* Not NULL terminated, can't be a string */
609                 SAFE_FREE(blob.data);
610                 return false;
611         }
612         if (value) {
613                 *value = SMB_STRDUP((char *)blob.data);
614                 data_blob_free(&blob);
615                 if (*value == NULL) {
616                         return false;
617                 }
618                 return true;
619         }
620         data_blob_free(&blob);
621         return true;
622 }
623
624 /**
625  * Set an entry in the cache file. If there's no such
626  * one, then add it.
627  *
628  * @param keystr string that represents a key of this entry
629  * @param value text representation value being cached
630  * @param timeout time when the value is expired
631  *
632  * @retval true when entry is successfuly stored
633  * @retval false on failure
634  **/
635
636 bool gencache_set(const char *keystr, const char *value, time_t timeout)
637 {
638         DATA_BLOB blob = data_blob_const(value, strlen(value)+1);
639         return gencache_set_data_blob(keystr, &blob, timeout);
640 }
641
642 struct gencache_iterate_blobs_state {
643         void (*fn)(const char *key, DATA_BLOB value,
644                    time_t timeout, void *private_data);
645         const char *pattern;
646         void *private_data;
647         bool in_persistent;
648 };
649
650 static int gencache_iterate_blobs_fn(struct tdb_context *tdb, TDB_DATA key,
651                                      TDB_DATA data, void *priv)
652 {
653         struct gencache_iterate_blobs_state *state =
654                 (struct gencache_iterate_blobs_state *)priv;
655         char *keystr;
656         char *free_key = NULL;
657         time_t timeout;
658         char *endptr;
659
660         if (tdb_data_cmp(key, last_stabilize_key()) == 0) {
661                 return 0;
662         }
663         if (state->in_persistent && tdb_exists(cache_notrans, key)) {
664                 return 0;
665         }
666
667         if (key.dptr[key.dsize-1] == '\0') {
668                 keystr = (char *)key.dptr;
669         } else {
670                 /* ensure 0-termination */
671                 keystr = SMB_STRNDUP((char *)key.dptr, key.dsize);
672                 free_key = keystr;
673         }
674
675         if (!gencache_pull_timeout((char *)data.dptr, &timeout, &endptr)) {
676                 goto done;
677         }
678         endptr += 1;
679
680         if (fnmatch(state->pattern, keystr, 0) != 0) {
681                 goto done;
682         }
683
684         DEBUG(10, ("Calling function with arguments (key=%s, timeout=%s)\n",
685                    keystr, ctime(&timeout)));
686
687         state->fn(keystr,
688                   data_blob_const(endptr,
689                                   data.dsize - PTR_DIFF(endptr, data.dptr)),
690                   timeout, state->private_data);
691
692  done:
693         SAFE_FREE(free_key);
694         return 0;
695 }
696
697 void gencache_iterate_blobs(void (*fn)(const char *key, DATA_BLOB value,
698                                        time_t timeout, void *private_data),
699                             void *private_data, const char *pattern)
700 {
701         struct gencache_iterate_blobs_state state;
702
703         if ((fn == NULL) || (pattern == NULL) || !gencache_init()) {
704                 return;
705         }
706
707         DEBUG(5, ("Searching cache keys with pattern %s\n", pattern));
708
709         state.fn = fn;
710         state.pattern = pattern;
711         state.private_data = private_data;
712
713         state.in_persistent = false;
714         tdb_traverse(cache_notrans, gencache_iterate_blobs_fn, &state);
715
716         state.in_persistent = true;
717         tdb_traverse(cache, gencache_iterate_blobs_fn, &state);
718 }
719
720 /**
721  * Iterate through all entries which key matches to specified pattern
722  *
723  * @param fn pointer to the function that will be supplied with each single
724  *        matching cache entry (key, value and timeout) as an arguments
725  * @param data void pointer to an arbitrary data that is passed directly to the fn
726  *        function on each call
727  * @param keystr_pattern pattern the existing entries' keys are matched to
728  *
729  **/
730
731 struct gencache_iterate_state {
732         void (*fn)(const char *key, const char *value, time_t timeout,
733                    void *priv);
734         void *private_data;
735 };
736
737 static void gencache_iterate_fn(const char *key, DATA_BLOB value,
738                                 time_t timeout, void *private_data)
739 {
740         struct gencache_iterate_state *state =
741                 (struct gencache_iterate_state *)private_data;
742         char *valstr;
743         char *free_val = NULL;
744
745         if (value.data[value.length-1] == '\0') {
746                 valstr = (char *)value.data;
747         } else {
748                 /* ensure 0-termination */
749                 valstr = SMB_STRNDUP((char *)value.data, value.length);
750                 free_val = valstr;
751         }
752
753         DEBUG(10, ("Calling function with arguments "
754                    "(key = %s, value = %s, timeout = %s)\n",
755                    key, valstr, ctime(&timeout)));
756
757         state->fn(key, valstr, timeout, state->private_data);
758
759         SAFE_FREE(free_val);
760 }
761
762 void gencache_iterate(void (*fn)(const char *key, const char *value,
763                                  time_t timeout, void *dptr),
764                       void *private_data, const char *pattern)
765 {
766         struct gencache_iterate_state state;
767
768         if (fn == NULL) {
769                 return;
770         }
771         state.fn = fn;
772         state.private_data = private_data;
773         gencache_iterate_blobs(gencache_iterate_fn, &state, pattern);
774 }