[GLUE] Rsync SAMBA_3_0 SVN r25598 in order to create the v3-0-test branch.
[Samba.git] / source / lib / util_tdb.c
bloba1b5bf5bb16d1bcbb4ead4ea28939f0d6762c4ca
1 /*
2 Unix SMB/CIFS implementation.
3 tdb utility functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Rafal Szczesniak 2002
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.
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.
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.
22 #include "includes.h"
23 #undef malloc
24 #undef realloc
25 #undef calloc
26 #undef strdup
28 /* these are little tdb utility functions that are meant to make
29 dealing with a tdb database a little less cumbersome in Samba */
31 static SIG_ATOMIC_T gotalarm;
33 /***************************************************************
34 Signal function to tell us we timed out.
35 ****************************************************************/
37 static void gotalarm_sig(void)
39 gotalarm = 1;
42 /***************************************************************
43 Make a TDB_DATA and keep the const warning in one place
44 ****************************************************************/
46 TDB_DATA make_tdb_data(const char *dptr, size_t dsize)
48 TDB_DATA ret;
49 ret.dptr = CONST_DISCARD(char *, dptr);
50 ret.dsize = dsize;
51 return ret;
54 TDB_DATA string_tdb_data(const char *string)
56 return make_tdb_data(string, strlen(string));
59 /****************************************************************************
60 Lock a chain with timeout (in seconds).
61 ****************************************************************************/
63 static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type)
65 /* Allow tdb_chainlock to be interrupted by an alarm. */
66 int ret;
67 gotalarm = 0;
69 if (timeout) {
70 CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
71 alarm(timeout);
74 if (rw_type == F_RDLCK)
75 ret = tdb_chainlock_read(tdb, key);
76 else
77 ret = tdb_chainlock(tdb, key);
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;
93 return ret;
96 /****************************************************************************
97 Write lock a chain. Return -1 if timeout or lock failed.
98 ****************************************************************************/
100 int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout)
102 return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
105 /****************************************************************************
106 Lock a chain by string. Return -1 if timeout or lock failed.
107 ****************************************************************************/
109 int tdb_lock_bystring(TDB_CONTEXT *tdb, const char *keyval)
111 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
113 return tdb_chainlock(tdb, key);
116 int tdb_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval,
117 int timeout)
119 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
121 return tdb_chainlock_with_timeout(tdb, key, timeout);
124 /****************************************************************************
125 Unlock a chain by string.
126 ****************************************************************************/
128 void tdb_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
130 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
132 tdb_chainunlock(tdb, key);
135 /****************************************************************************
136 Read lock a chain by string. Return -1 if timeout or lock failed.
137 ****************************************************************************/
139 int tdb_read_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout)
141 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
143 return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
146 /****************************************************************************
147 Read unlock a chain by string.
148 ****************************************************************************/
150 void tdb_read_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
152 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
154 tdb_chainunlock_read(tdb, key);
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 ****************************************************************************/
163 int32 tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, const char *keyval, size_t len)
165 TDB_DATA key = make_tdb_data(keyval, len);
166 TDB_DATA data;
167 int32 ret;
169 data = tdb_fetch(tdb, key);
170 if (!data.dptr || data.dsize != sizeof(int32)) {
171 SAFE_FREE(data.dptr);
172 return -1;
175 ret = IVAL(data.dptr,0);
176 SAFE_FREE(data.dptr);
177 return ret;
180 /****************************************************************************
181 Fetch a int32 value by string key, return -1 if not found.
182 Output is int32 in native byte order.
183 ****************************************************************************/
185 int32 tdb_fetch_int32(TDB_CONTEXT *tdb, const char *keystr)
187 return tdb_fetch_int32_byblob(tdb, keystr, strlen(keystr) + 1);
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 ****************************************************************************/
195 int tdb_store_int32_byblob(TDB_CONTEXT *tdb, const char *keystr, size_t len, int32 v)
197 TDB_DATA key = make_tdb_data(keystr, len);
198 TDB_DATA data;
199 int32 v_store;
201 SIVAL(&v_store,0,v);
202 data.dptr = (char *)&v_store;
203 data.dsize = sizeof(int32);
205 return tdb_store(tdb, key, data, TDB_REPLACE);
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 ****************************************************************************/
213 int tdb_store_int32(TDB_CONTEXT *tdb, const char *keystr, int32 v)
215 return tdb_store_int32_byblob(tdb, keystr, strlen(keystr) + 1, v);
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 ****************************************************************************/
223 BOOL tdb_fetch_uint32_byblob(TDB_CONTEXT *tdb, const char *keyval, size_t len, uint32 *value)
225 TDB_DATA key = make_tdb_data(keyval, len);
226 TDB_DATA data;
228 data = tdb_fetch(tdb, key);
229 if (!data.dptr || data.dsize != sizeof(uint32)) {
230 SAFE_FREE(data.dptr);
231 return False;
234 *value = IVAL(data.dptr,0);
235 SAFE_FREE(data.dptr);
236 return True;
239 /****************************************************************************
240 Fetch a uint32 value by string key, return -1 if not found.
241 Output is uint32 in native byte order.
242 ****************************************************************************/
244 BOOL tdb_fetch_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32 *value)
246 return tdb_fetch_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
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 ****************************************************************************/
254 BOOL tdb_store_uint32_byblob(TDB_CONTEXT *tdb, const char *keystr, size_t len, uint32 value)
256 TDB_DATA key = make_tdb_data(keystr, len);
257 TDB_DATA data;
258 uint32 v_store;
259 BOOL ret = True;
261 SIVAL(&v_store, 0, value);
262 data.dptr = (char *)&v_store;
263 data.dsize = sizeof(uint32);
265 if (tdb_store(tdb, key, data, TDB_REPLACE) == -1)
266 ret = False;
268 return ret;
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 ****************************************************************************/
276 BOOL tdb_store_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32 value)
278 return tdb_store_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
280 /****************************************************************************
281 Store a buffer by a null terminated string key. Return 0 on success, -1
282 on failure.
283 ****************************************************************************/
285 int tdb_store_bystring(TDB_CONTEXT *tdb, const char *keystr, TDB_DATA data, int flags)
287 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
289 return tdb_store(tdb, key, data, flags);
292 /****************************************************************************
293 Fetch a buffer using a null terminated string key. Don't forget to call
294 free() on the result dptr.
295 ****************************************************************************/
297 TDB_DATA tdb_fetch_bystring(TDB_CONTEXT *tdb, const char *keystr)
299 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
301 return tdb_fetch(tdb, key);
304 /****************************************************************************
305 Delete an entry using a null terminated string key.
306 ****************************************************************************/
308 int tdb_delete_bystring(TDB_CONTEXT *tdb, const char *keystr)
310 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
312 return tdb_delete(tdb, key);
315 /****************************************************************************
316 Atomic integer change. Returns old value. To create, set initial value in *oldval.
317 ****************************************************************************/
319 int32 tdb_change_int32_atomic(TDB_CONTEXT *tdb, const char *keystr, int32 *oldval, int32 change_val)
321 int32 val;
322 int32 ret = -1;
324 if (tdb_lock_bystring(tdb, keystr) == -1)
325 return -1;
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;
334 /* Start with 'old' value */
335 val = *oldval;
337 } else {
338 /* It worked, set return value (oldval) to tdb data */
339 *oldval = val;
342 /* Increment value for storage and return next time */
343 val += change_val;
345 if (tdb_store_int32(tdb, keystr, val) == -1)
346 goto err_out;
348 ret = 0;
350 err_out:
352 tdb_unlock_bystring(tdb, keystr);
353 return ret;
356 /****************************************************************************
357 Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
358 ****************************************************************************/
360 BOOL tdb_change_uint32_atomic(TDB_CONTEXT *tdb, const char *keystr, uint32 *oldval, uint32 change_val)
362 uint32 val;
363 BOOL ret = False;
365 if (tdb_lock_bystring(tdb, keystr) == -1)
366 return False;
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;
375 /* Start with 'old' value */
376 val = *oldval;
378 } else {
379 /* it worked, set return value (oldval) to tdb data */
380 *oldval = val;
384 /* get a new value to store */
385 val += change_val;
387 if (!tdb_store_uint32(tdb, keystr, val))
388 goto err_out;
390 ret = True;
392 err_out:
394 tdb_unlock_bystring(tdb, keystr);
395 return ret;
398 /****************************************************************************
399 Useful pair of routines for packing/unpacking data consisting of
400 integers and strings.
401 ****************************************************************************/
403 size_t tdb_pack_va(char *buf, int bufsize, const char *fmt, va_list ap)
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;
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);
466 break;
467 default:
468 DEBUG(0,("Unknown tdb_pack format %c in %s\n",
469 c, fmt));
470 len = 0;
471 break;
474 buf += len;
475 if (bufsize)
476 bufsize -= len;
477 if (bufsize < 0)
478 bufsize = 0;
481 DEBUG(18,("tdb_pack_va(%s, %d) -> %d\n",
482 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
484 return PTR_DIFF(buf, buf0);
487 size_t tdb_pack(char *buf, int bufsize, const char *fmt, ...)
489 va_list ap;
490 size_t result;
492 va_start(ap, fmt);
493 result = tdb_pack_va(buf, bufsize, fmt, ap);
494 va_end(ap);
495 return result;
498 BOOL tdb_pack_append(TALLOC_CTX *mem_ctx, uint8 **buf, size_t *len,
499 const char *fmt, ...)
501 va_list ap;
502 size_t len1, len2;
504 va_start(ap, fmt);
505 len1 = tdb_pack_va(NULL, 0, fmt, ap);
506 va_end(ap);
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);
515 if (*buf == NULL) {
516 return False;
519 va_start(ap, fmt);
520 len2 = tdb_pack_va((char *)(*buf)+(*len), len1, fmt, ap);
521 va_end(ap);
523 if (len1 != len2) {
524 return False;
527 *len += len2;
529 return True;
532 /****************************************************************************
533 Useful pair of routines for packing/unpacking data consisting of
534 integers and strings.
535 ****************************************************************************/
537 int tdb_unpack(char *buf, int bufsize, const char *fmt, ...)
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;
552 va_start(ap, fmt);
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;
583 * This isn't a real pointer - only a token (1 or 0)
584 * to mark the fact a pointer is present.
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;
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));
626 len = 0;
627 break;
630 buf += len;
631 bufsize -= len;
634 va_end(ap);
636 DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
637 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
639 return PTR_DIFF(buf, buf0);
641 no_space:
642 return -1;
646 /****************************************************************************
647 Log tdb messages via DEBUG().
648 ****************************************************************************/
650 static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...)
652 va_list ap;
653 char *ptr = NULL;
655 va_start(ap, format);
656 vasprintf(&ptr, format, ap);
657 va_end(ap);
659 if (!ptr || !*ptr)
660 return;
662 DEBUG((int)level, ("tdb(%s): %s", tdb_name(tdb) ? tdb_name(tdb) : "unnamed", ptr));
663 SAFE_FREE(ptr);
666 /****************************************************************************
667 Like tdb_open() but also setup a logging function that redirects to
668 the samba DEBUG() system.
669 ****************************************************************************/
671 TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
672 int open_flags, mode_t mode)
674 TDB_CONTEXT *tdb;
675 struct tdb_logging_context log_ctx;
677 if (!lp_use_mmap())
678 tdb_flags |= TDB_NOMMAP;
680 log_ctx.log_fn = tdb_log;
681 log_ctx.log_private = NULL;
683 tdb = tdb_open_ex(name, hash_size, tdb_flags,
684 open_flags, mode, &log_ctx, NULL);
685 if (!tdb)
686 return NULL;
688 return tdb;
691 /****************************************************************************
692 Allow tdb_delete to be used as a tdb_traversal_fn.
693 ****************************************************************************/
695 int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
696 void *state)
698 return tdb_delete(the_tdb, key);
704 * Search across the whole tdb for keys that match the given pattern
705 * return the result as a list of keys
707 * @param tdb pointer to opened tdb file context
708 * @param pattern searching pattern used by fnmatch(3) functions
710 * @return list of keys found by looking up with given pattern
712 TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern)
714 TDB_DATA key, next;
715 TDB_LIST_NODE *list = NULL;
716 TDB_LIST_NODE *rec = NULL;
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");
726 DEBUG(18, ("checking %s for match to pattern %s\n", key_str, pattern));
728 next = tdb_nextkey(tdb, key);
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);
735 rec->node_key = key;
737 DLIST_ADD_END(list, rec, TDB_LIST_NODE *);
739 DEBUG(18, ("checking %s matched pattern %s\n", key_str, pattern));
740 } else {
741 free(key.dptr);
744 /* free duplicated key string */
745 free(key_str);
748 return list;
754 * Free the list returned by tdb_search_keys
756 * @param node list of results found by tdb_search_keys
758 void tdb_search_list_free(TDB_LIST_NODE* node)
760 TDB_LIST_NODE *next_node;
762 while (node) {
763 next_node = node->next;
764 SAFE_FREE(node->node_key.dptr);
765 SAFE_FREE(node);
766 node = next_node;
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 ****************************************************************************/
775 int tdb_trans_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
776 int flag)
778 int res;
780 if ((res = tdb_transaction_start(tdb)) != 0) {
781 DEBUG(5, ("tdb_transaction_start failed\n"));
782 return res;
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");
790 return res;
793 if ((res = tdb_transaction_commit(tdb)) != 0) {
794 DEBUG(5, ("tdb_transaction_commit failed\n"));
797 return res;
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 ****************************************************************************/
805 int tdb_trans_delete(struct tdb_context *tdb, TDB_DATA key)
807 int res;
809 if ((res = tdb_transaction_start(tdb)) != 0) {
810 DEBUG(5, ("tdb_transaction_start failed\n"));
811 return res;
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");
819 return res;
822 if ((res = tdb_transaction_commit(tdb)) != 0) {
823 DEBUG(5, ("tdb_transaction_commit failed\n"));
826 return res;
830 Log tdb messages via DEBUG().
832 static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level,
833 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
835 static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level,
836 const char *format, ...)
838 va_list ap;
839 char *ptr = NULL;
840 int debuglevel = 0;
842 va_start(ap, format);
843 vasprintf(&ptr, format, ap);
844 va_end(ap);
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;
863 if (ptr != NULL) {
864 const char *name = tdb_name(tdb);
865 DEBUG(debuglevel, ("tdb(%s): %s", name ? name : "unnamed", ptr));
866 free(ptr);
870 static struct tdb_wrap *tdb_list;
872 /* destroy the last connection to a tdb */
873 static int tdb_wrap_destructor(struct tdb_wrap *w)
875 tdb_close(w->tdb);
876 DLIST_REMOVE(tdb_list, w);
877 return 0;
881 wrapped connection to a tdb database
882 to close just talloc_free() the tdb_wrap pointer
884 struct 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)
888 struct tdb_wrap *w;
889 struct tdb_logging_context log_ctx;
890 log_ctx.log_fn = tdb_wrap_log;
892 for (w=tdb_list;w;w=w->next) {
893 if (strcmp(name, w->name) == 0) {
895 * Yes, talloc_reference is exactly what we want
896 * here. Otherwise we would have to implement our own
897 * reference counting.
899 return talloc_reference(mem_ctx, w);
903 w = talloc(mem_ctx, struct tdb_wrap);
904 if (w == NULL) {
905 return NULL;
908 if (!(w->name = talloc_strdup(w, name))) {
909 talloc_free(w);
910 return NULL;
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;
920 talloc_set_destructor(w, tdb_wrap_destructor);
922 DLIST_ADD(tdb_list, w);
924 return w;