2 Unix SMB/CIFS implementation.
4 trivial database library
6 Copyright (C) Andrew Tridgell 1999-2005
7 Copyright (C) Paul `Rusty' Russell 2000
8 Copyright (C) Jeremy Allison 2000-2003
10 ** NOTE! The following LGPL license applies to the tdb
11 ** library. This does NOT imply that all of Samba is released
14 This library is free software; you can redistribute it and/or
15 modify it under the terms of the GNU Lesser General Public
16 License as published by the Free Software Foundation; either
17 version 3 of the License, or (at your option) any later version.
19 This library is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 Lesser General Public License for more details.
24 You should have received a copy of the GNU Lesser General Public
25 License along with this library; if not, see <http://www.gnu.org/licenses/>.
28 #include "tdb_private.h"
33 non-blocking increment of the tdb sequence number if the tdb has been opened using
36 void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)
40 if (!(tdb->flags & TDB_SEQNUM)) {
44 /* we ignore errors from this, as we have no sane way of
47 tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
49 tdb_ofs_write(tdb, TDB_SEQNUM_OFS, &seqnum);
53 increment the tdb sequence number if the tdb has been opened using
56 static void tdb_increment_seqnum(struct tdb_context *tdb)
58 if (!(tdb->flags & TDB_SEQNUM)) {
62 if (tdb_brlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, F_SETLKW, 1, 1) != 0) {
66 tdb_increment_seqnum_nonblock(tdb);
68 tdb_brlock(tdb, TDB_SEQNUM_OFS, F_UNLCK, F_SETLKW, 1, 1);
71 static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data)
73 return memcmp(data.dptr, key.dptr, data.dsize);
76 /* Returns 0 on fail. On success, return offset of record, and fills
78 static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
79 struct list_struct *r)
83 /* read in the hash top */
84 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
87 /* keep looking until we find the right record */
89 if (tdb_rec_read(tdb, rec_ptr, r) == -1)
92 if (!TDB_DEAD(r) && hash==r->full_hash
93 && key.dsize==r->key_len
94 && tdb_parse_data(tdb, key, rec_ptr + sizeof(*r),
95 r->key_len, tdb_key_compare,
101 return TDB_ERRCODE(TDB_ERR_NOEXIST, 0);
104 /* As tdb_find, but if you succeed, keep the lock */
105 tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
106 struct list_struct *rec)
110 if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)
112 if (!(rec_ptr = tdb_find(tdb, key, hash, rec)))
113 tdb_unlock(tdb, BUCKET(hash), locktype);
118 /* update an entry in place - this only works if the new data size
119 is <= the old data size and the key exists.
120 on failure return -1.
122 static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, TDB_DATA dbuf)
124 struct list_struct rec;
128 if (!(rec_ptr = tdb_find(tdb, key, hash, &rec)))
131 /* must be long enough key, data and tailer */
132 if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off_t)) {
133 tdb->ecode = TDB_SUCCESS; /* Not really an error */
137 if (tdb->methods->tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
138 dbuf.dptr, dbuf.dsize) == -1)
141 if (dbuf.dsize != rec.data_len) {
143 rec.data_len = dbuf.dsize;
144 return tdb_rec_write(tdb, rec_ptr, &rec);
150 /* find an entry in the database given a key */
151 /* If an entry doesn't exist tdb_err will be set to
152 * TDB_ERR_NOEXIST. If a key has no data attached
153 * then the TDB_DATA will have zero length but
156 static TDB_DATA do_tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
159 struct list_struct rec;
163 /* find which hash bucket it is in */
164 hash = tdb->hash_fn(&key);
165 if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
168 ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
170 ret.dsize = rec.data_len;
171 tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
175 TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
177 TDB_DATA ret = do_tdb_fetch(tdb, key);
179 tdb_trace_1rec_retrec(tdb, "tdb_fetch", key, ret);
184 * Find an entry in the database and hand the record's data to a parsing
185 * function. The parsing function is executed under the chain read lock, so it
186 * should be fast and should not block on other syscalls.
188 * DONT CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS.
190 * For mmapped tdb's that do not have a transaction open it points the parsing
191 * function directly at the mmap area, it avoids the malloc/memcpy in this
192 * case. If a transaction is open or no mmap is available, it has to do
193 * malloc/read/parse/free.
195 * This is interesting for all readers of potentially large data structures in
196 * the tdb records, ldb indexes being one example.
199 int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
200 int (*parser)(TDB_DATA key, TDB_DATA data,
205 struct list_struct rec;
209 /* find which hash bucket it is in */
210 hash = tdb->hash_fn(&key);
212 if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
213 tdb_trace_1rec_ret(tdb, "tdb_parse_record", key,
215 return TDB_ERRCODE(TDB_ERR_NOEXIST, 0);
217 tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0);
219 ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len,
220 rec.data_len, parser, private_data);
222 tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
227 /* check if an entry in the database exists
229 note that 1 is returned if the key is found and 0 is returned if not found
230 this doesn't match the conventions in the rest of this module, but is
233 static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
235 struct list_struct rec;
237 if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
239 tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
243 int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
245 uint32_t hash = tdb->hash_fn(&key);
248 ret = tdb_exists_hash(tdb, key, hash);
249 tdb_trace_1rec_ret(tdb, "tdb_exists", key, ret);
253 /* actually delete an entry in the database given the offset */
254 int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct list_struct *rec)
256 tdb_off_t last_ptr, i;
257 struct list_struct lastrec;
259 if (tdb->read_only || tdb->traverse_read) return -1;
261 if (tdb->traverse_write != 0 ||
262 tdb_write_lock_record(tdb, rec_ptr) == -1) {
263 /* Someone traversing here: mark it as dead */
264 rec->magic = TDB_DEAD_MAGIC;
265 return tdb_rec_write(tdb, rec_ptr, rec);
267 if (tdb_write_unlock_record(tdb, rec_ptr) != 0)
270 /* find previous record in hash chain */
271 if (tdb_ofs_read(tdb, TDB_HASH_TOP(rec->full_hash), &i) == -1)
273 for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next)
274 if (tdb_rec_read(tdb, i, &lastrec) == -1)
277 /* unlink it: next ptr is at start of record. */
279 last_ptr = TDB_HASH_TOP(rec->full_hash);
280 if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1)
283 /* recover the space */
284 if (tdb_free(tdb, rec_ptr, rec) == -1)
289 static int tdb_count_dead(struct tdb_context *tdb, uint32_t hash)
293 struct list_struct rec;
295 /* read in the hash top */
296 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
300 if (tdb_rec_read(tdb, rec_ptr, &rec) == -1)
303 if (rec.magic == TDB_DEAD_MAGIC) {
312 * Purge all DEAD records from a hash chain
314 static int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash)
317 struct list_struct rec;
320 if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
324 /* read in the hash top */
325 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
331 if (tdb_rec_read(tdb, rec_ptr, &rec) == -1) {
337 if (rec.magic == TDB_DEAD_MAGIC
338 && tdb_do_delete(tdb, rec_ptr, &rec) == -1) {
345 tdb_unlock(tdb, -1, F_WRLCK);
349 /* delete an entry in the database given a key */
350 static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
353 struct list_struct rec;
356 if (tdb->max_dead_records != 0) {
359 * Allow for some dead records per hash chain, mainly for
360 * tdb's with a very high create/delete rate like locking.tdb.
363 if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
366 if (tdb_count_dead(tdb, hash) >= tdb->max_dead_records) {
368 * Don't let the per-chain freelist grow too large,
369 * delete all existing dead records
371 tdb_purge_dead(tdb, hash);
374 if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) {
375 tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
380 * Just mark the record as dead.
382 rec.magic = TDB_DEAD_MAGIC;
383 ret = tdb_rec_write(tdb, rec_ptr, &rec);
386 if (!(rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK,
390 ret = tdb_do_delete(tdb, rec_ptr, &rec);
394 tdb_increment_seqnum(tdb);
397 if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0)
398 TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_delete: WARNING tdb_unlock failed!\n"));
402 int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
404 uint32_t hash = tdb->hash_fn(&key);
407 ret = tdb_delete_hash(tdb, key, hash);
408 tdb_trace_1rec_ret(tdb, "tdb_delete", key, ret);
413 * See if we have a dead record around with enough space
415 static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
416 struct list_struct *r, tdb_len_t length)
420 /* read in the hash top */
421 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
424 /* keep looking until we find the right record */
426 if (tdb_rec_read(tdb, rec_ptr, r) == -1)
429 if (TDB_DEAD(r) && r->rec_len >= length) {
431 * First fit for simple coding, TODO: change to best
441 static int _tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
442 int flag, uint32_t hash)
444 struct list_struct rec;
449 /* check for it existing, on insert. */
450 if (flag == TDB_INSERT) {
451 if (tdb_exists_hash(tdb, key, hash)) {
452 tdb->ecode = TDB_ERR_EXISTS;
456 /* first try in-place update, on modify or replace. */
457 if (tdb_update_hash(tdb, key, hash, dbuf) == 0) {
460 if (tdb->ecode == TDB_ERR_NOEXIST &&
461 flag == TDB_MODIFY) {
462 /* if the record doesn't exist and we are in TDB_MODIFY mode then
463 we should fail the store */
467 /* reset the error code potentially set by the tdb_update() */
468 tdb->ecode = TDB_SUCCESS;
470 /* delete any existing record - if it doesn't exist we don't
471 care. Doing this first reduces fragmentation, and avoids
472 coalescing with `allocated' block before it's updated. */
473 if (flag != TDB_INSERT)
474 tdb_delete_hash(tdb, key, hash);
476 /* Copy key+value *before* allocating free space in case malloc
477 fails and we are left with a dead spot in the tdb. */
479 if (!(p = (char *)malloc(key.dsize + dbuf.dsize))) {
480 tdb->ecode = TDB_ERR_OOM;
484 memcpy(p, key.dptr, key.dsize);
486 memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize);
488 if (tdb->max_dead_records != 0) {
490 * Allow for some dead records per hash chain, look if we can
491 * find one that can hold the new record. We need enough space
492 * for key, data and tailer. If we find one, we don't have to
493 * consult the central freelist.
495 rec_ptr = tdb_find_dead(
497 key.dsize + dbuf.dsize + sizeof(tdb_off_t));
500 rec.key_len = key.dsize;
501 rec.data_len = dbuf.dsize;
502 rec.full_hash = hash;
503 rec.magic = TDB_MAGIC;
504 if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
505 || tdb->methods->tdb_write(
506 tdb, rec_ptr + sizeof(rec),
507 p, key.dsize + dbuf.dsize) == -1) {
515 * We have to allocate some space from the freelist, so this means we
516 * have to lock it. Use the chance to purge all the DEAD records from
517 * the hash chain under the freelist lock.
520 if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
524 if ((tdb->max_dead_records != 0)
525 && (tdb_purge_dead(tdb, hash) == -1)) {
526 tdb_unlock(tdb, -1, F_WRLCK);
530 /* we have to allocate some space */
531 rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec);
533 tdb_unlock(tdb, -1, F_WRLCK);
539 /* Read hash top into next ptr */
540 if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
543 rec.key_len = key.dsize;
544 rec.data_len = dbuf.dsize;
545 rec.full_hash = hash;
546 rec.magic = TDB_MAGIC;
548 /* write out and point the top of the hash chain at it */
549 if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
550 || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1
551 || tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
552 /* Need to tdb_unallocate() here */
560 tdb_increment_seqnum(tdb);
567 /* store an element in the database, replacing any existing element
570 return 0 on success, -1 on failure
572 int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
577 if (tdb->read_only || tdb->traverse_read) {
578 tdb->ecode = TDB_ERR_RDONLY;
579 tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag,
584 /* find which hash bucket it is in */
585 hash = tdb->hash_fn(&key);
586 if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
589 ret = _tdb_store(tdb, key, dbuf, flag, hash);
590 tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, ret);
591 tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
596 /* Append to an entry. Create if not exist. */
597 int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
603 /* find which hash bucket it is in */
604 hash = tdb->hash_fn(&key);
605 if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
608 dbuf = do_tdb_fetch(tdb, key);
610 if (dbuf.dptr == NULL) {
611 dbuf.dptr = (unsigned char *)malloc(new_dbuf.dsize);
613 unsigned int new_len = dbuf.dsize + new_dbuf.dsize;
614 unsigned char *new_dptr;
616 /* realloc '0' is special: don't do that. */
619 new_dptr = (unsigned char *)realloc(dbuf.dptr, new_len);
620 if (new_dptr == NULL) {
623 dbuf.dptr = new_dptr;
626 if (dbuf.dptr == NULL) {
627 tdb->ecode = TDB_ERR_OOM;
631 memcpy(dbuf.dptr + dbuf.dsize, new_dbuf.dptr, new_dbuf.dsize);
632 dbuf.dsize += new_dbuf.dsize;
634 ret = _tdb_store(tdb, key, dbuf, 0, hash);
635 tdb_trace_2rec_retrec(tdb, "tdb_append", key, new_dbuf, dbuf);
638 tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
639 SAFE_FREE(dbuf.dptr);
645 return the name of the current tdb file
646 useful for external logging functions
648 const char *tdb_name(struct tdb_context *tdb)
654 return the underlying file descriptor being used by tdb, or -1
655 useful for external routines that want to check the device/inode
658 int tdb_fd(struct tdb_context *tdb)
664 return the current logging function
665 useful for external tdb routines that wish to log tdb errors
667 tdb_log_func tdb_log_fn(struct tdb_context *tdb)
669 return tdb->log.log_fn;
674 get the tdb sequence number. Only makes sense if the writers opened
675 with TDB_SEQNUM set. Note that this sequence number will wrap quite
676 quickly, so it should only be used for a 'has something changed'
677 test, not for code that relies on the count of the number of changes
678 made. If you want a counter then use a tdb record.
680 The aim of this sequence number is to allow for a very lightweight
681 test of a possible tdb change.
683 int tdb_get_seqnum(struct tdb_context *tdb)
687 tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
688 tdb_trace_ret(tdb, "tdb_get_seqnum", seqnum);
692 int tdb_hash_size(struct tdb_context *tdb)
694 return tdb->header.hash_size;
697 size_t tdb_map_size(struct tdb_context *tdb)
699 return tdb->map_size;
702 int tdb_get_flags(struct tdb_context *tdb)
707 void tdb_add_flags(struct tdb_context *tdb, unsigned flags)
712 void tdb_remove_flags(struct tdb_context *tdb, unsigned flags)
714 tdb->flags &= ~flags;
719 enable sequence number handling on an open tdb
721 void tdb_enable_seqnum(struct tdb_context *tdb)
723 tdb->flags |= TDB_SEQNUM;
728 add a region of the file to the freelist. Length is the size of the region in bytes,
729 which includes the free list header that needs to be added
731 static int tdb_free_region(struct tdb_context *tdb, tdb_off_t offset, ssize_t length)
733 struct list_struct rec;
734 if (length <= sizeof(rec)) {
735 /* the region is not worth adding */
738 if (length + offset > tdb->map_size) {
739 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: adding region beyond end of file\n"));
742 memset(&rec,'\0',sizeof(rec));
743 rec.rec_len = length - sizeof(rec);
744 if (tdb_free(tdb, offset, &rec) == -1) {
745 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: failed to add free record\n"));
752 wipe the entire database, deleting all records. This can be done
753 very fast by using a global lock. The entire data portion of the
754 file becomes a single entry in the freelist.
756 This code carefully steps around the recovery area, leaving it alone
758 int tdb_wipe_all(struct tdb_context *tdb)
761 tdb_off_t offset = 0;
763 tdb_off_t recovery_head;
764 tdb_len_t recovery_size = 0;
766 if (tdb_lockall(tdb) != 0) {
770 tdb_trace(tdb, "tdb_wipe_all");
772 /* see if the tdb has a recovery area, and remember its size
773 if so. We don't want to lose this as otherwise each
774 tdb_wipe_all() in a transaction will increase the size of
775 the tdb by the size of the recovery area */
776 if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
777 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery head\n"));
781 if (recovery_head != 0) {
782 struct list_struct rec;
783 if (tdb->methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
784 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery record\n"));
787 recovery_size = rec.rec_len + sizeof(rec);
790 /* wipe the hashes */
791 for (i=0;i<tdb->header.hash_size;i++) {
792 if (tdb_ofs_write(tdb, TDB_HASH_TOP(i), &offset) == -1) {
793 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write hash %d\n", i));
798 /* wipe the freelist */
799 if (tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
800 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write freelist\n"));
804 /* add all the rest of the file to the freelist, possibly leaving a gap
805 for the recovery area */
806 if (recovery_size == 0) {
807 /* the simple case - the whole file can be used as a freelist */
808 data_len = (tdb->map_size - TDB_DATA_START(tdb->header.hash_size));
809 if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) {
813 /* we need to add two freelist entries - one on either
814 side of the recovery area
816 Note that we cannot shift the recovery area during
817 this operation. Only the transaction.c code may
818 move the recovery area or we risk subtle data
821 data_len = (recovery_head - TDB_DATA_START(tdb->header.hash_size));
822 if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) {
825 /* and the 2nd free list entry after the recovery area - if any */
826 data_len = tdb->map_size - (recovery_head+recovery_size);
827 if (tdb_free_region(tdb, recovery_head+recovery_size, data_len) != 0) {
832 if (tdb_unlockall(tdb) != 0) {
833 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to unlock\n"));
845 static void tdb_trace_write(struct tdb_context *tdb, const char *str)
847 if (write(tdb->tracefd, str, strlen(str)) != strlen(str)) {
853 static void tdb_trace_start(struct tdb_context *tdb)
856 char msg[sizeof(tdb_off_t) * 4];
858 tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
859 sprintf(msg, "%u ", seqnum);
860 tdb_trace_write(tdb, msg);
863 static void tdb_trace_end(struct tdb_context *tdb)
865 tdb_trace_write(tdb, "\n");
868 static void tdb_trace_end_ret(struct tdb_context *tdb, int ret)
870 char msg[sizeof(ret) * 4];
871 sprintf(msg, " = %i\n", ret);
872 tdb_trace_write(tdb, msg);
875 static void tdb_trace_record(struct tdb_context *tdb, TDB_DATA rec)
880 /* We differentiate zero-length records from non-existent ones. */
881 if (rec.dptr == NULL) {
882 tdb_trace_write(tdb, " NULL");
885 sprintf(msg, " %zu:", rec.dsize);
886 tdb_trace_write(tdb, msg);
887 for (i = 0; i < rec.dsize; i++) {
888 sprintf(msg, "%02x", rec.dptr[i]);
889 tdb_trace_write(tdb, msg);
893 void tdb_trace(struct tdb_context *tdb, const char *op)
895 tdb_trace_start(tdb);
896 tdb_trace_write(tdb, op);
900 void tdb_trace_open(struct tdb_context *tdb, const char *op,
901 unsigned hash_size, unsigned tdb_flags, unsigned open_flags)
905 sprintf(msg, "%s %u %#x %#x", op, hash_size, tdb_flags, open_flags);
906 tdb_trace_start(tdb);
907 tdb_trace_write(tdb, msg);
911 void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret)
913 tdb_trace_start(tdb);
914 tdb_trace_write(tdb, op);
915 tdb_trace_end_ret(tdb, ret);
918 void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret)
920 tdb_trace_start(tdb);
921 tdb_trace_write(tdb, op);
922 tdb_trace_write(tdb, " =");
923 tdb_trace_record(tdb, ret);
927 void tdb_trace_1rec(struct tdb_context *tdb, const char *op,
930 tdb_trace_start(tdb);
931 tdb_trace_write(tdb, op);
932 tdb_trace_record(tdb, rec);
936 void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op,
937 TDB_DATA rec, int ret)
939 tdb_trace_start(tdb);
940 tdb_trace_write(tdb, op);
941 tdb_trace_record(tdb, rec);
942 tdb_trace_end_ret(tdb, ret);
945 void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op,
946 TDB_DATA rec, TDB_DATA ret)
948 tdb_trace_start(tdb);
949 tdb_trace_write(tdb, op);
950 tdb_trace_record(tdb, rec);
951 tdb_trace_write(tdb, " =");
952 tdb_trace_record(tdb, ret);
956 void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op,
957 TDB_DATA rec1, TDB_DATA rec2, unsigned flag,
960 char msg[sizeof(ret) * 4];
962 sprintf(msg, " %#x", flag);
963 tdb_trace_start(tdb);
964 tdb_trace_write(tdb, op);
965 tdb_trace_record(tdb, rec1);
966 tdb_trace_record(tdb, rec2);
967 tdb_trace_write(tdb, msg);
968 tdb_trace_end_ret(tdb, ret);
971 void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
972 TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret)
974 tdb_trace_start(tdb);
975 tdb_trace_write(tdb, op);
976 tdb_trace_record(tdb, rec1);
977 tdb_trace_record(tdb, rec2);
978 tdb_trace_write(tdb, " =");
979 tdb_trace_record(tdb, ret);