source: trunk/samba/source/lib/util_tdb.c @ 26

Last change on this file since 26 was 26, checked in by Paul Smedley, 14 years ago

Updated source to 3.0.25rc1

File size: 24.3 KB
Line 
1/*
2   Unix SMB/CIFS implementation.
3   tdb utility functions
4   Copyright (C) Andrew Tridgell   1992-1998
5   Copyright (C) Rafal Szczesniak  2002
6   
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11   
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16   
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include "includes.h"
23#undef malloc
24#undef realloc
25#undef calloc
26#undef strdup
27
28/* these are little tdb utility functions that are meant to make
29   dealing with a tdb database a little less cumbersome in Samba */
30
31static SIG_ATOMIC_T gotalarm;
32
33/***************************************************************
34 Signal function to tell us we timed out.
35****************************************************************/
36
37static void gotalarm_sig(void)
38{
39        gotalarm = 1;
40}
41
42/***************************************************************
43 Make a TDB_DATA and keep the const warning in one place
44****************************************************************/
45
46TDB_DATA make_tdb_data(const char *dptr, size_t dsize)
47{
48        TDB_DATA ret;
49        ret.dptr = CONST_DISCARD(char *, dptr);
50        ret.dsize = dsize;
51        return ret;
52}
53
54TDB_DATA string_tdb_data(const char *string)
55{
56        return make_tdb_data(string, strlen(string));
57}
58
59/****************************************************************************
60 Lock a chain with timeout (in seconds).
61****************************************************************************/
62
63static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type)
64{
65        /* Allow tdb_chainlock to be interrupted by an alarm. */
66        int ret;
67        gotalarm = 0;
68
69        if (timeout) {
70                CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
71                alarm(timeout);
72        }
73
74        if (rw_type == F_RDLCK)
75                ret = tdb_chainlock_read(tdb, key);
76        else
77                ret = tdb_chainlock(tdb, key);
78
79        if (timeout) {
80                alarm(0);
81                CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
82                if (gotalarm) {
83                        DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
84                                timeout, key.dptr, tdb_name(tdb)));
85                        /* TODO: If we time out waiting for a lock, it might
86                         * be nice to use F_GETLK to get the pid of the
87                         * process currently holding the lock and print that
88                         * as part of the debugging message. -- mbp */
89                        return -1;
90                }
91        }
92
93        return ret;
94}
95
96/****************************************************************************
97 Write lock a chain. Return -1 if timeout or lock failed.
98****************************************************************************/
99
100int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout)
101{
102        return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
103}
104
105/****************************************************************************
106 Lock a chain by string. Return -1 if timeout or lock failed.
107****************************************************************************/
108
109int tdb_lock_bystring(TDB_CONTEXT *tdb, const char *keyval)
110{
111        TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
112       
113        return tdb_chainlock(tdb, key);
114}
115
116int tdb_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval,
117                                   int timeout)
118{
119        TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
120       
121        return tdb_chainlock_with_timeout(tdb, key, timeout);
122}
123
124/****************************************************************************
125 Unlock a chain by string.
126****************************************************************************/
127
128void tdb_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
129{
130        TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
131
132        tdb_chainunlock(tdb, key);
133}
134
135/****************************************************************************
136 Read lock a chain by string. Return -1 if timeout or lock failed.
137****************************************************************************/
138
139int tdb_read_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout)
140{
141        TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
142       
143        return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
144}
145
146/****************************************************************************
147 Read unlock a chain by string.
148****************************************************************************/
149
150void tdb_read_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
151{
152        TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
153       
154        tdb_chainunlock_read(tdb, key);
155}
156
157
158/****************************************************************************
159 Fetch a int32 value by a arbitrary blob key, return -1 if not found.
160 Output is int32 in native byte order.
161****************************************************************************/
162
163int32 tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, const char *keyval, size_t len)
164{
165        TDB_DATA key = make_tdb_data(keyval, len);
166        TDB_DATA data;
167        int32 ret;
168
169        data = tdb_fetch(tdb, key);
170        if (!data.dptr || data.dsize != sizeof(int32)) {
171                SAFE_FREE(data.dptr);
172                return -1;
173        }
174
175        ret = IVAL(data.dptr,0);
176        SAFE_FREE(data.dptr);
177        return ret;
178}
179
180/****************************************************************************
181 Fetch a int32 value by string key, return -1 if not found.
182 Output is int32 in native byte order.
183****************************************************************************/
184
185int32 tdb_fetch_int32(TDB_CONTEXT *tdb, const char *keystr)
186{
187        return tdb_fetch_int32_byblob(tdb, keystr, strlen(keystr) + 1);
188}
189
190/****************************************************************************
191 Store a int32 value by an arbitary blob key, return 0 on success, -1 on failure.
192 Input is int32 in native byte order. Output in tdb is in little-endian.
193****************************************************************************/
194
195int tdb_store_int32_byblob(TDB_CONTEXT *tdb, const char *keystr, size_t len, int32 v)
196{
197        TDB_DATA key = make_tdb_data(keystr, len);
198        TDB_DATA data;
199        int32 v_store;
200
201        SIVAL(&v_store,0,v);
202        data.dptr = (char *)&v_store;
203        data.dsize = sizeof(int32);
204
205        return tdb_store(tdb, key, data, TDB_REPLACE);
206}
207
208/****************************************************************************
209 Store a int32 value by string key, return 0 on success, -1 on failure.
210 Input is int32 in native byte order. Output in tdb is in little-endian.
211****************************************************************************/
212
213int tdb_store_int32(TDB_CONTEXT *tdb, const char *keystr, int32 v)
214{
215        return tdb_store_int32_byblob(tdb, keystr, strlen(keystr) + 1, v);
216}
217
218/****************************************************************************
219 Fetch a uint32 value by a arbitrary blob key, return -1 if not found.
220 Output is uint32 in native byte order.
221****************************************************************************/
222
223BOOL tdb_fetch_uint32_byblob(TDB_CONTEXT *tdb, const char *keyval, size_t len, uint32 *value)
224{
225        TDB_DATA key = make_tdb_data(keyval, len);
226        TDB_DATA data;
227
228        data = tdb_fetch(tdb, key);
229        if (!data.dptr || data.dsize != sizeof(uint32)) {
230                SAFE_FREE(data.dptr);
231                return False;
232        }
233
234        *value = IVAL(data.dptr,0);
235        SAFE_FREE(data.dptr);
236        return True;
237}
238
239/****************************************************************************
240 Fetch a uint32 value by string key, return -1 if not found.
241 Output is uint32 in native byte order.
242****************************************************************************/
243
244BOOL tdb_fetch_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32 *value)
245{
246        return tdb_fetch_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
247}
248
249/****************************************************************************
250 Store a uint32 value by an arbitary blob key, return 0 on success, -1 on failure.
251 Input is uint32 in native byte order. Output in tdb is in little-endian.
252****************************************************************************/
253
254BOOL tdb_store_uint32_byblob(TDB_CONTEXT *tdb, const char *keystr, size_t len, uint32 value)
255{
256        TDB_DATA key = make_tdb_data(keystr, len);
257        TDB_DATA data;
258        uint32 v_store;
259        BOOL ret = True;
260
261        SIVAL(&v_store, 0, value);
262        data.dptr = (char *)&v_store;
263        data.dsize = sizeof(uint32);
264
265        if (tdb_store(tdb, key, data, TDB_REPLACE) == -1)
266                ret = False;
267
268        return ret;
269}
270
271/****************************************************************************
272 Store a uint32 value by string key, return 0 on success, -1 on failure.
273 Input is uint32 in native byte order. Output in tdb is in little-endian.
274****************************************************************************/
275
276BOOL tdb_store_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32 value)
277{
278        return tdb_store_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
279}
280/****************************************************************************
281 Store a buffer by a null terminated string key.  Return 0 on success, -1
282 on failure.
283****************************************************************************/
284
285int tdb_store_bystring(TDB_CONTEXT *tdb, const char *keystr, TDB_DATA data, int flags)
286{
287        TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
288       
289        return tdb_store(tdb, key, data, flags);
290}
291
292/****************************************************************************
293 Fetch a buffer using a null terminated string key.  Don't forget to call
294 free() on the result dptr.
295****************************************************************************/
296
297TDB_DATA tdb_fetch_bystring(TDB_CONTEXT *tdb, const char *keystr)
298{
299        TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
300
301        return tdb_fetch(tdb, key);
302}
303
304/****************************************************************************
305 Delete an entry using a null terminated string key.
306****************************************************************************/
307
308int tdb_delete_bystring(TDB_CONTEXT *tdb, const char *keystr)
309{
310        TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
311
312        return tdb_delete(tdb, key);
313}
314
315/****************************************************************************
316 Atomic integer change. Returns old value. To create, set initial value in *oldval.
317****************************************************************************/
318
319int32 tdb_change_int32_atomic(TDB_CONTEXT *tdb, const char *keystr, int32 *oldval, int32 change_val)
320{
321        int32 val;
322        int32 ret = -1;
323
324        if (tdb_lock_bystring(tdb, keystr) == -1)
325                return -1;
326
327        if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
328                /* The lookup failed */
329                if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
330                        /* but not because it didn't exist */
331                        goto err_out;
332                }
333               
334                /* Start with 'old' value */
335                val = *oldval;
336
337        } else {
338                /* It worked, set return value (oldval) to tdb data */
339                *oldval = val;
340        }
341
342        /* Increment value for storage and return next time */
343        val += change_val;
344               
345        if (tdb_store_int32(tdb, keystr, val) == -1)
346                goto err_out;
347
348        ret = 0;
349
350  err_out:
351
352        tdb_unlock_bystring(tdb, keystr);
353        return ret;
354}
355
356/****************************************************************************
357 Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
358****************************************************************************/
359
360BOOL tdb_change_uint32_atomic(TDB_CONTEXT *tdb, const char *keystr, uint32 *oldval, uint32 change_val)
361{
362        uint32 val;
363        BOOL ret = False;
364
365        if (tdb_lock_bystring(tdb, keystr) == -1)
366                return False;
367
368        if (!tdb_fetch_uint32(tdb, keystr, &val)) {
369                /* It failed */
370                if (tdb_error(tdb) != TDB_ERR_NOEXIST) { 
371                        /* and not because it didn't exist */
372                        goto err_out;
373                }
374
375                /* Start with 'old' value */
376                val = *oldval;
377
378        } else {
379                /* it worked, set return value (oldval) to tdb data */
380                *oldval = val;
381
382        }
383
384        /* get a new value to store */
385        val += change_val;
386               
387        if (!tdb_store_uint32(tdb, keystr, val))
388                goto err_out;
389
390        ret = True;
391
392  err_out:
393
394        tdb_unlock_bystring(tdb, keystr);
395        return ret;
396}
397
398/****************************************************************************
399 Useful pair of routines for packing/unpacking data consisting of
400 integers and strings.
401****************************************************************************/
402
403size_t tdb_pack_va(char *buf, int bufsize, const char *fmt, va_list ap)
404{
405        uint8 bt;
406        uint16 w;
407        uint32 d;
408        int i;
409        void *p;
410        int len;
411        char *s;
412        char c;
413        char *buf0 = buf;
414        const char *fmt0 = fmt;
415        int bufsize0 = bufsize;
416
417        while (*fmt) {
418                switch ((c = *fmt++)) {
419                case 'b': /* unsigned 8-bit integer */
420                        len = 1;
421                        bt = (uint8)va_arg(ap, int);
422                        if (bufsize && bufsize >= len)
423                                SSVAL(buf, 0, bt);
424                        break;
425                case 'w': /* unsigned 16-bit integer */
426                        len = 2;
427                        w = (uint16)va_arg(ap, int);
428                        if (bufsize && bufsize >= len)
429                                SSVAL(buf, 0, w);
430                        break;
431                case 'd': /* signed 32-bit integer (standard int in most systems) */
432                        len = 4;
433                        d = va_arg(ap, uint32);
434                        if (bufsize && bufsize >= len)
435                                SIVAL(buf, 0, d);
436                        break;
437                case 'p': /* pointer */
438                        len = 4;
439                        p = va_arg(ap, void *);
440                        d = p?1:0;
441                        if (bufsize && bufsize >= len)
442                                SIVAL(buf, 0, d);
443                        break;
444                case 'P': /* null-terminated string */
445                        s = va_arg(ap,char *);
446                        w = strlen(s);
447                        len = w + 1;
448                        if (bufsize && bufsize >= len)
449                                memcpy(buf, s, len);
450                        break;
451                case 'f': /* null-terminated string */
452                        s = va_arg(ap,char *);
453                        w = strlen(s);
454                        len = w + 1;
455                        if (bufsize && bufsize >= len)
456                                memcpy(buf, s, len);
457                        break;
458                case 'B': /* fixed-length string */
459                        i = va_arg(ap, int);
460                        s = va_arg(ap, char *);
461                        len = 4+i;
462                        if (bufsize && bufsize >= len) {
463                                SIVAL(buf, 0, i);
464                                memcpy(buf+4, s, i);
465                        }
466                        break;
467                default:
468                        DEBUG(0,("Unknown tdb_pack format %c in %s\n", 
469                                 c, fmt));
470                        len = 0;
471                        break;
472                }
473
474                buf += len;
475                if (bufsize)
476                        bufsize -= len;
477                if (bufsize < 0)
478                        bufsize = 0;
479        }
480
481        DEBUG(18,("tdb_pack_va(%s, %d) -> %d\n", 
482                 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
483       
484        return PTR_DIFF(buf, buf0);
485}
486
487size_t tdb_pack(char *buf, int bufsize, const char *fmt, ...)
488{
489        va_list ap;
490        size_t result;
491
492        va_start(ap, fmt);
493        result = tdb_pack_va(buf, bufsize, fmt, ap);
494        va_end(ap);
495        return result;
496}
497
498BOOL tdb_pack_append(TALLOC_CTX *mem_ctx, uint8 **buf, size_t *len,
499                     const char *fmt, ...)
500{
501        va_list ap;
502        size_t len1, len2;
503
504        va_start(ap, fmt);
505        len1 = tdb_pack_va(NULL, 0, fmt, ap);
506        va_end(ap);
507
508        if (mem_ctx != NULL) {
509                *buf = TALLOC_REALLOC_ARRAY(mem_ctx, *buf, uint8,
510                                            (*len) + len1);
511        } else {
512                *buf = SMB_REALLOC_ARRAY(*buf, uint8, (*len) + len1);
513        }
514
515        if (*buf == NULL) {
516                return False;
517        }
518
519        va_start(ap, fmt);
520        len2 = tdb_pack_va((char *)(*buf)+(*len), len1, fmt, ap);
521        va_end(ap);
522
523        if (len1 != len2) {
524                return False;
525        }
526
527        *len += len2;
528
529        return True;
530}
531
532/****************************************************************************
533 Useful pair of routines for packing/unpacking data consisting of
534 integers and strings.
535****************************************************************************/
536
537int tdb_unpack(char *buf, int bufsize, const char *fmt, ...)
538{
539        va_list ap;
540        uint8 *bt;
541        uint16 *w;
542        uint32 *d;
543        int len;
544        int *i;
545        void **p;
546        char *s, **b;
547        char c;
548        char *buf0 = buf;
549        const char *fmt0 = fmt;
550        int bufsize0 = bufsize;
551
552        va_start(ap, fmt);
553       
554        while (*fmt) {
555                switch ((c=*fmt++)) {
556                case 'b':
557                        len = 1;
558                        bt = va_arg(ap, uint8 *);
559                        if (bufsize < len)
560                                goto no_space;
561                        *bt = SVAL(buf, 0);
562                        break;
563                case 'w':
564                        len = 2;
565                        w = va_arg(ap, uint16 *);
566                        if (bufsize < len)
567                                goto no_space;
568                        *w = SVAL(buf, 0);
569                        break;
570                case 'd':
571                        len = 4;
572                        d = va_arg(ap, uint32 *);
573                        if (bufsize < len)
574                                goto no_space;
575                        *d = IVAL(buf, 0);
576                        break;
577                case 'p':
578                        len = 4;
579                        p = va_arg(ap, void **);
580                        if (bufsize < len)
581                                goto no_space;
582                        /*
583                         * This isn't a real pointer - only a token (1 or 0)
584                         * to mark the fact a pointer is present.
585                         */
586
587                        *p = (void *)(IVAL(buf, 0) ? (void *)1 : NULL);
588                        break;
589                case 'P':
590                        s = va_arg(ap,char *);
591                        len = strlen(buf) + 1;
592                        if (bufsize < len || len > sizeof(pstring))
593                                goto no_space;
594                        memcpy(s, buf, len);
595                        break;
596                case 'f':
597                        s = va_arg(ap,char *);
598                        len = strlen(buf) + 1;
599                        if (bufsize < len || len > sizeof(fstring))
600                                goto no_space;
601                        memcpy(s, buf, len);
602                        break;
603                case 'B':
604                        i = va_arg(ap, int *);
605                        b = va_arg(ap, char **);
606                        len = 4;
607                        if (bufsize < len)
608                                goto no_space;
609                        *i = IVAL(buf, 0);
610                        if (! *i) {
611                                *b = NULL;
612                                break;
613                        }
614                        len += *i;
615                        if (bufsize < len)
616                                goto no_space;
617                        *b = (char *)SMB_MALLOC(*i);
618                        if (! *b)
619                                goto no_space;
620                        memcpy(*b, buf+4, *i);
621                        break;
622                default:
623                        DEBUG(0,("Unknown tdb_unpack format %c in %s\n", 
624                                 c, fmt));
625
626                        len = 0;
627                        break;
628                }
629
630                buf += len;
631                bufsize -= len;
632        }
633
634        va_end(ap);
635
636        DEBUG(18,("tdb_unpack(%s, %d) -> %d\n", 
637                 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
638
639        return PTR_DIFF(buf, buf0);
640
641 no_space:
642        return -1;
643}
644
645
646/****************************************************************************
647 Log tdb messages via DEBUG().
648****************************************************************************/
649
650static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...)
651{
652        va_list ap;
653        char *ptr = NULL;
654
655        va_start(ap, format);
656        vasprintf(&ptr, format, ap);
657        va_end(ap);
658       
659        if (!ptr || !*ptr)
660                return;
661
662        DEBUG((int)level, ("tdb(%s): %s", tdb_name(tdb) ? tdb_name(tdb) : "unnamed", ptr));
663        SAFE_FREE(ptr);
664}
665
666/****************************************************************************
667 Like tdb_open() but also setup a logging function that redirects to
668 the samba DEBUG() system.
669****************************************************************************/
670
671TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
672                          int open_flags, mode_t mode)
673{
674        TDB_CONTEXT *tdb;
675        struct tdb_logging_context log_ctx;
676
677        if (!lp_use_mmap())
678                tdb_flags |= TDB_NOMMAP;
679
680        log_ctx.log_fn = tdb_log;
681        log_ctx.log_private = NULL;
682
683        tdb = tdb_open_ex(name, hash_size, tdb_flags, 
684                          open_flags, mode, &log_ctx, NULL);
685        if (!tdb)
686                return NULL;
687
688        return tdb;
689}
690
691/****************************************************************************
692 Allow tdb_delete to be used as a tdb_traversal_fn.
693****************************************************************************/
694
695int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
696                     void *state)
697{
698    return tdb_delete(the_tdb, key);
699}
700
701
702
703/**
704 * Search across the whole tdb for keys that match the given pattern
705 * return the result as a list of keys
706 *
707 * @param tdb pointer to opened tdb file context
708 * @param pattern searching pattern used by fnmatch(3) functions
709 *
710 * @return list of keys found by looking up with given pattern
711 **/
712TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern)
713{
714        TDB_DATA key, next;
715        TDB_LIST_NODE *list = NULL;
716        TDB_LIST_NODE *rec = NULL;
717       
718        for (key = tdb_firstkey(tdb); key.dptr; key = next) {
719                /* duplicate key string to ensure null-termination */
720                char *key_str = (char*) SMB_STRNDUP(key.dptr, key.dsize);
721                if (!key_str) {
722                        DEBUG(0, ("tdb_search_keys: strndup() failed!\n"));
723                        smb_panic("strndup failed!\n");
724                }
725               
726                DEBUG(18, ("checking %s for match to pattern %s\n", key_str, pattern));
727               
728                next = tdb_nextkey(tdb, key);
729
730                /* do the pattern checking */
731                if (fnmatch(pattern, key_str, 0) == 0) {
732                        rec = SMB_MALLOC_P(TDB_LIST_NODE);
733                        ZERO_STRUCTP(rec);
734
735                        rec->node_key = key;
736       
737                        DLIST_ADD_END(list, rec, TDB_LIST_NODE *);
738               
739                        DEBUG(18, ("checking %s matched pattern %s\n", key_str, pattern));
740                } else {
741                        free(key.dptr);
742                }
743               
744                /* free duplicated key string */
745                free(key_str);
746        }
747       
748        return list;
749
750}
751
752
753/**
754 * Free the list returned by tdb_search_keys
755 *
756 * @param node list of results found by tdb_search_keys
757 **/
758void tdb_search_list_free(TDB_LIST_NODE* node)
759{
760        TDB_LIST_NODE *next_node;
761       
762        while (node) {
763                next_node = node->next;
764                SAFE_FREE(node->node_key.dptr);
765                SAFE_FREE(node);
766                node = next_node;
767        };
768}
769
770/****************************************************************************
771 tdb_store, wrapped in a transaction. This way we make sure that a process
772 that dies within writing does not leave a corrupt tdb behind.
773****************************************************************************/
774
775int tdb_trans_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
776                    int flag)
777{
778        int res;
779
780        if ((res = tdb_transaction_start(tdb)) != 0) {
781                DEBUG(5, ("tdb_transaction_start failed\n"));
782                return res;
783        }
784
785        if ((res = tdb_store(tdb, key, dbuf, flag)) != 0) {
786                DEBUG(10, ("tdb_store failed\n"));
787                if (tdb_transaction_cancel(tdb) != 0) {
788                        smb_panic("Cancelling transaction failed\n");
789                }
790                return res;
791        }
792
793        if ((res = tdb_transaction_commit(tdb)) != 0) {
794                DEBUG(5, ("tdb_transaction_commit failed\n"));
795        }
796
797        return res;
798}
799
800/****************************************************************************
801 tdb_delete, wrapped in a transaction. This way we make sure that a process
802 that dies within deleting does not leave a corrupt tdb behind.
803****************************************************************************/
804
805int tdb_trans_delete(struct tdb_context *tdb, TDB_DATA key)
806{
807        int res;
808
809        if ((res = tdb_transaction_start(tdb)) != 0) {
810                DEBUG(5, ("tdb_transaction_start failed\n"));
811                return res;
812        }
813
814        if ((res = tdb_delete(tdb, key)) != 0) {
815                DEBUG(10, ("tdb_delete failed\n"));
816                if (tdb_transaction_cancel(tdb) != 0) {
817                        smb_panic("Cancelling transaction failed\n");
818                }
819                return res;
820        }
821
822        if ((res = tdb_transaction_commit(tdb)) != 0) {
823                DEBUG(5, ("tdb_transaction_commit failed\n"));
824        }
825
826        return res;
827}
828
829/*
830 Log tdb messages via DEBUG().
831*/
832static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, 
833                         const char *format, ...) PRINTF_ATTRIBUTE(3,4);
834
835static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, 
836                         const char *format, ...)
837{
838        va_list ap;
839        char *ptr = NULL;
840        int debuglevel = 0;
841
842        va_start(ap, format);
843        vasprintf(&ptr, format, ap);
844        va_end(ap);
845       
846        switch (level) {
847        case TDB_DEBUG_FATAL:
848                debug_level = 0;
849                break;
850        case TDB_DEBUG_ERROR:
851                debuglevel = 1;
852                break;
853        case TDB_DEBUG_WARNING:
854                debuglevel = 2;
855                break;
856        case TDB_DEBUG_TRACE:
857                debuglevel = 5;
858                break;
859        default:
860                debuglevel = 0;
861        }               
862
863        if (ptr != NULL) {
864                const char *name = tdb_name(tdb);
865                DEBUG(debuglevel, ("tdb(%s): %s", name ? name : "unnamed", ptr));
866                free(ptr);
867        }
868}
869
870static struct tdb_wrap *tdb_list;
871
872/* destroy the last connection to a tdb */
873static int tdb_wrap_destructor(struct tdb_wrap *w)
874{
875        tdb_close(w->tdb);
876        DLIST_REMOVE(tdb_list, w);
877        return 0;
878}                               
879
880/*
881  wrapped connection to a tdb database
882  to close just talloc_free() the tdb_wrap pointer
883 */
884struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
885                               const char *name, int hash_size, int tdb_flags,
886                               int open_flags, mode_t mode)
887{
888        struct tdb_wrap *w;
889        struct tdb_logging_context log_ctx;
890        log_ctx.log_fn = tdb_wrap_log;
891
892        for (w=tdb_list;w;w=w->next) {
893                if (strcmp(name, w->name) == 0) {
894                        /*
895                         * Yes, talloc_reference is exactly what we want
896                         * here. Otherwise we would have to implement our own
897                         * reference counting.
898                         */
899                        return talloc_reference(mem_ctx, w);
900                }
901        }
902
903        w = talloc(mem_ctx, struct tdb_wrap);
904        if (w == NULL) {
905                return NULL;
906        }
907
908        if (!(w->name = talloc_strdup(w, name))) {
909                talloc_free(w);
910                return NULL;
911        }
912
913        w->tdb = tdb_open_ex(name, hash_size, tdb_flags, 
914                             open_flags, mode, &log_ctx, NULL);
915        if (w->tdb == NULL) {
916                talloc_free(w);
917                return NULL;
918        }
919
920        talloc_set_destructor(w, tdb_wrap_destructor);
921
922        DLIST_ADD(tdb_list, w);
923
924        return w;
925}
Note: See TracBrowser for help on using the repository browser.