source: branches/samba-3.0/source/lib/util_tdb.c

Last change on this file was 165, checked in by Paul Smedley, 16 years ago

Add 'missing' 3.0.34 diffs

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