source: trunk-3.0/source/lib/util_tdb.c@ 102

Last change on this file since 102 was 26, checked in by Paul Smedley, 18 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.