lib/tdb: TDB_TRACE support (for developers)
[samba.git] / lib / tdb / common / tdb.c
1  /* 
2    Unix SMB/CIFS implementation.
3
4    trivial database library
5
6    Copyright (C) Andrew Tridgell              1999-2005
7    Copyright (C) Paul `Rusty' Russell              2000
8    Copyright (C) Jeremy Allison                    2000-2003
9    
10      ** NOTE! The following LGPL license applies to the tdb
11      ** library. This does NOT imply that all of Samba is released
12      ** under the LGPL
13    
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.
18
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.
23
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/>.
26 */
27
28 #include "tdb_private.h"
29
30 TDB_DATA tdb_null;
31
32 /*
33   non-blocking increment of the tdb sequence number if the tdb has been opened using
34   the TDB_SEQNUM flag
35 */
36 void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)
37 {
38         tdb_off_t seqnum=0;
39         
40         if (!(tdb->flags & TDB_SEQNUM)) {
41                 return;
42         }
43
44         /* we ignore errors from this, as we have no sane way of
45            dealing with them.
46         */
47         tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
48         seqnum++;
49         tdb_ofs_write(tdb, TDB_SEQNUM_OFS, &seqnum);
50 }
51
52 /*
53   increment the tdb sequence number if the tdb has been opened using
54   the TDB_SEQNUM flag
55 */
56 static void tdb_increment_seqnum(struct tdb_context *tdb)
57 {
58         if (!(tdb->flags & TDB_SEQNUM)) {
59                 return;
60         }
61
62         if (tdb_brlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, F_SETLKW, 1, 1) != 0) {
63                 return;
64         }
65
66         tdb_increment_seqnum_nonblock(tdb);
67
68         tdb_brlock(tdb, TDB_SEQNUM_OFS, F_UNLCK, F_SETLKW, 1, 1);
69 }
70
71 static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data)
72 {
73         return memcmp(data.dptr, key.dptr, data.dsize);
74 }
75
76 /* Returns 0 on fail.  On success, return offset of record, and fills
77    in rec */
78 static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
79                         struct list_struct *r)
80 {
81         tdb_off_t rec_ptr;
82         
83         /* read in the hash top */
84         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
85                 return 0;
86
87         /* keep looking until we find the right record */
88         while (rec_ptr) {
89                 if (tdb_rec_read(tdb, rec_ptr, r) == -1)
90                         return 0;
91
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,
96                                       NULL) == 0) {
97                         return rec_ptr;
98                 }
99                 /* detect tight infinite loop */
100                 if (rec_ptr == r->next) {
101                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_find: loop detected.\n"));
102                         return TDB_ERRCODE(TDB_ERR_CORRUPT, 0);
103                 }
104                 rec_ptr = r->next;
105         }
106         return TDB_ERRCODE(TDB_ERR_NOEXIST, 0);
107 }
108
109 /* As tdb_find, but if you succeed, keep the lock */
110 tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
111                            struct list_struct *rec)
112 {
113         uint32_t rec_ptr;
114
115         if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)
116                 return 0;
117         if (!(rec_ptr = tdb_find(tdb, key, hash, rec)))
118                 tdb_unlock(tdb, BUCKET(hash), locktype);
119         return rec_ptr;
120 }
121
122
123 /* update an entry in place - this only works if the new data size
124    is <= the old data size and the key exists.
125    on failure return -1.
126 */
127 static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, TDB_DATA dbuf)
128 {
129         struct list_struct rec;
130         tdb_off_t rec_ptr;
131
132         /* find entry */
133         if (!(rec_ptr = tdb_find(tdb, key, hash, &rec)))
134                 return -1;
135
136         /* must be long enough key, data and tailer */
137         if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off_t)) {
138                 tdb->ecode = TDB_SUCCESS; /* Not really an error */
139                 return -1;
140         }
141
142         if (tdb->methods->tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
143                       dbuf.dptr, dbuf.dsize) == -1)
144                 return -1;
145
146         if (dbuf.dsize != rec.data_len) {
147                 /* update size */
148                 rec.data_len = dbuf.dsize;
149                 return tdb_rec_write(tdb, rec_ptr, &rec);
150         }
151  
152         return 0;
153 }
154
155 /* find an entry in the database given a key */
156 /* If an entry doesn't exist tdb_err will be set to
157  * TDB_ERR_NOEXIST. If a key has no data attached
158  * then the TDB_DATA will have zero length but
159  * a non-zero pointer
160  */
161 static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
162 {
163         tdb_off_t rec_ptr;
164         struct list_struct rec;
165         TDB_DATA ret;
166         uint32_t hash;
167
168         /* find which hash bucket it is in */
169         hash = tdb->hash_fn(&key);
170         if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec)))
171                 return tdb_null;
172
173         ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
174                                   rec.data_len);
175         ret.dsize = rec.data_len;
176         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
177         return ret;
178 }
179
180 TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
181 {
182         TDB_DATA ret = _tdb_fetch(tdb, key);
183
184         tdb_trace_1rec_retrec(tdb, "tdb_fetch", key, ret);
185         return ret;
186 }
187
188 /*
189  * Find an entry in the database and hand the record's data to a parsing
190  * function. The parsing function is executed under the chain read lock, so it
191  * should be fast and should not block on other syscalls.
192  *
193  * DONT CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS.
194  *
195  * For mmapped tdb's that do not have a transaction open it points the parsing
196  * function directly at the mmap area, it avoids the malloc/memcpy in this
197  * case. If a transaction is open or no mmap is available, it has to do
198  * malloc/read/parse/free.
199  *
200  * This is interesting for all readers of potentially large data structures in
201  * the tdb records, ldb indexes being one example.
202  */
203
204 int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
205                      int (*parser)(TDB_DATA key, TDB_DATA data,
206                                    void *private_data),
207                      void *private_data)
208 {
209         tdb_off_t rec_ptr;
210         struct list_struct rec;
211         int ret;
212         uint32_t hash;
213
214         /* find which hash bucket it is in */
215         hash = tdb->hash_fn(&key);
216
217         if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
218                 tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, -1);
219                 return TDB_ERRCODE(TDB_ERR_NOEXIST, 0);
220         }
221         tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0);
222
223         ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len,
224                              rec.data_len, parser, private_data);
225
226         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
227
228         return ret;
229 }
230
231 /* check if an entry in the database exists 
232
233    note that 1 is returned if the key is found and 0 is returned if not found
234    this doesn't match the conventions in the rest of this module, but is
235    compatible with gdbm
236 */
237 static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
238 {
239         struct list_struct rec;
240         
241         if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
242                 return 0;
243         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
244         return 1;
245 }
246
247 int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
248 {
249         uint32_t hash = tdb->hash_fn(&key);
250         int ret;
251
252         ret = tdb_exists_hash(tdb, key, hash);
253         tdb_trace_1rec_ret(tdb, "tdb_exists", key, ret);
254         return ret;
255 }
256
257 /* actually delete an entry in the database given the offset */
258 int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct list_struct *rec)
259 {
260         tdb_off_t last_ptr, i;
261         struct list_struct lastrec;
262
263         if (tdb->read_only || tdb->traverse_read) return -1;
264
265         if (((tdb->traverse_write != 0) && (!TDB_DEAD(rec))) ||
266             tdb_write_lock_record(tdb, rec_ptr) == -1) {
267                 /* Someone traversing here: mark it as dead */
268                 rec->magic = TDB_DEAD_MAGIC;
269                 return tdb_rec_write(tdb, rec_ptr, rec);
270         }
271         if (tdb_write_unlock_record(tdb, rec_ptr) != 0)
272                 return -1;
273
274         /* find previous record in hash chain */
275         if (tdb_ofs_read(tdb, TDB_HASH_TOP(rec->full_hash), &i) == -1)
276                 return -1;
277         for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next)
278                 if (tdb_rec_read(tdb, i, &lastrec) == -1)
279                         return -1;
280
281         /* unlink it: next ptr is at start of record. */
282         if (last_ptr == 0)
283                 last_ptr = TDB_HASH_TOP(rec->full_hash);
284         if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1)
285                 return -1;
286
287         /* recover the space */
288         if (tdb_free(tdb, rec_ptr, rec) == -1)
289                 return -1;
290         return 0;
291 }
292
293 static int tdb_count_dead(struct tdb_context *tdb, uint32_t hash)
294 {
295         int res = 0;
296         tdb_off_t rec_ptr;
297         struct list_struct rec;
298         
299         /* read in the hash top */
300         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
301                 return 0;
302
303         while (rec_ptr) {
304                 if (tdb_rec_read(tdb, rec_ptr, &rec) == -1)
305                         return 0;
306
307                 if (rec.magic == TDB_DEAD_MAGIC) {
308                         res += 1;
309                 }
310                 rec_ptr = rec.next;
311         }
312         return res;
313 }
314
315 /*
316  * Purge all DEAD records from a hash chain
317  */
318 static int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash)
319 {
320         int res = -1;
321         struct list_struct rec;
322         tdb_off_t rec_ptr;
323
324         if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
325                 return -1;
326         }
327         
328         /* read in the hash top */
329         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
330                 goto fail;
331
332         while (rec_ptr) {
333                 tdb_off_t next;
334
335                 if (tdb_rec_read(tdb, rec_ptr, &rec) == -1) {
336                         goto fail;
337                 }
338
339                 next = rec.next;
340
341                 if (rec.magic == TDB_DEAD_MAGIC
342                     && tdb_do_delete(tdb, rec_ptr, &rec) == -1) {
343                         goto fail;
344                 }
345                 rec_ptr = next;
346         }
347         res = 0;
348  fail:
349         tdb_unlock(tdb, -1, F_WRLCK);
350         return res;
351 }
352
353 /* delete an entry in the database given a key */
354 static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
355 {
356         tdb_off_t rec_ptr;
357         struct list_struct rec;
358         int ret;
359
360         if (tdb->max_dead_records != 0) {
361
362                 /*
363                  * Allow for some dead records per hash chain, mainly for
364                  * tdb's with a very high create/delete rate like locking.tdb.
365                  */
366
367                 if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
368                         return -1;
369
370                 if (tdb_count_dead(tdb, hash) >= tdb->max_dead_records) {
371                         /*
372                          * Don't let the per-chain freelist grow too large,
373                          * delete all existing dead records
374                          */
375                         tdb_purge_dead(tdb, hash);
376                 }
377
378                 if (!(rec_ptr = tdb_find(tdb, key, hash, &rec))) {
379                         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
380                         return -1;
381                 }
382
383                 /*
384                  * Just mark the record as dead.
385                  */
386                 rec.magic = TDB_DEAD_MAGIC;
387                 ret = tdb_rec_write(tdb, rec_ptr, &rec);
388         }
389         else {
390                 if (!(rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK,
391                                                    &rec)))
392                         return -1;
393
394                 ret = tdb_do_delete(tdb, rec_ptr, &rec);
395         }
396
397         if (ret == 0) {
398                 tdb_increment_seqnum(tdb);
399         }
400
401         if (tdb_unlock(tdb, BUCKET(rec.full_hash), F_WRLCK) != 0)
402                 TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_delete: WARNING tdb_unlock failed!\n"));
403         return ret;
404 }
405
406 int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
407 {
408         uint32_t hash = tdb->hash_fn(&key);
409         int ret;
410
411         ret = tdb_delete_hash(tdb, key, hash);
412         tdb_trace_1rec_ret(tdb, "tdb_delete", key, ret);
413         return ret;
414 }
415
416 /*
417  * See if we have a dead record around with enough space
418  */
419 static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
420                                struct list_struct *r, tdb_len_t length)
421 {
422         tdb_off_t rec_ptr;
423         
424         /* read in the hash top */
425         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
426                 return 0;
427
428         /* keep looking until we find the right record */
429         while (rec_ptr) {
430                 if (tdb_rec_read(tdb, rec_ptr, r) == -1)
431                         return 0;
432
433                 if (TDB_DEAD(r) && r->rec_len >= length) {
434                         /*
435                          * First fit for simple coding, TODO: change to best
436                          * fit
437                          */
438                         return rec_ptr;
439                 }
440                 rec_ptr = r->next;
441         }
442         return 0;
443 }
444
445 static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
446                        TDB_DATA dbuf, int flag, uint32_t hash)
447 {
448         struct list_struct rec;
449         tdb_off_t rec_ptr;
450         char *p = NULL;
451         int ret = -1;
452
453         /* check for it existing, on insert. */
454         if (flag == TDB_INSERT) {
455                 if (tdb_exists_hash(tdb, key, hash)) {
456                         tdb->ecode = TDB_ERR_EXISTS;
457                         goto fail;
458                 }
459         } else {
460                 /* first try in-place update, on modify or replace. */
461                 if (tdb_update_hash(tdb, key, hash, dbuf) == 0) {
462                         goto done;
463                 }
464                 if (tdb->ecode == TDB_ERR_NOEXIST &&
465                     flag == TDB_MODIFY) {
466                         /* if the record doesn't exist and we are in TDB_MODIFY mode then
467                          we should fail the store */
468                         goto fail;
469                 }
470         }
471         /* reset the error code potentially set by the tdb_update() */
472         tdb->ecode = TDB_SUCCESS;
473
474         /* delete any existing record - if it doesn't exist we don't
475            care.  Doing this first reduces fragmentation, and avoids
476            coalescing with `allocated' block before it's updated. */
477         if (flag != TDB_INSERT)
478                 tdb_delete_hash(tdb, key, hash);
479
480         /* Copy key+value *before* allocating free space in case malloc
481            fails and we are left with a dead spot in the tdb. */
482
483         if (!(p = (char *)malloc(key.dsize + dbuf.dsize))) {
484                 tdb->ecode = TDB_ERR_OOM;
485                 goto fail;
486         }
487
488         memcpy(p, key.dptr, key.dsize);
489         if (dbuf.dsize)
490                 memcpy(p+key.dsize, dbuf.dptr, dbuf.dsize);
491
492         if (tdb->max_dead_records != 0) {
493                 /*
494                  * Allow for some dead records per hash chain, look if we can
495                  * find one that can hold the new record. We need enough space
496                  * for key, data and tailer. If we find one, we don't have to
497                  * consult the central freelist.
498                  */
499                 rec_ptr = tdb_find_dead(
500                         tdb, hash, &rec,
501                         key.dsize + dbuf.dsize + sizeof(tdb_off_t));
502
503                 if (rec_ptr != 0) {
504                         rec.key_len = key.dsize;
505                         rec.data_len = dbuf.dsize;
506                         rec.full_hash = hash;
507                         rec.magic = TDB_MAGIC;
508                         if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
509                             || tdb->methods->tdb_write(
510                                     tdb, rec_ptr + sizeof(rec),
511                                     p, key.dsize + dbuf.dsize) == -1) {
512                                 goto fail;
513                         }
514                         goto done;
515                 }
516         }
517
518         /*
519          * We have to allocate some space from the freelist, so this means we
520          * have to lock it. Use the chance to purge all the DEAD records from
521          * the hash chain under the freelist lock.
522          */
523
524         if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
525                 goto fail;
526         }
527
528         if ((tdb->max_dead_records != 0)
529             && (tdb_purge_dead(tdb, hash) == -1)) {
530                 tdb_unlock(tdb, -1, F_WRLCK);
531                 goto fail;
532         }
533
534         /* we have to allocate some space */
535         rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec);
536
537         tdb_unlock(tdb, -1, F_WRLCK);
538
539         if (rec_ptr == 0) {
540                 goto fail;
541         }
542
543         /* Read hash top into next ptr */
544         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
545                 goto fail;
546
547         rec.key_len = key.dsize;
548         rec.data_len = dbuf.dsize;
549         rec.full_hash = hash;
550         rec.magic = TDB_MAGIC;
551
552         /* write out and point the top of the hash chain at it */
553         if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
554             || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec), p, key.dsize+dbuf.dsize)==-1
555             || tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
556                 /* Need to tdb_unallocate() here */
557                 goto fail;
558         }
559
560  done:
561         ret = 0;
562  fail:
563         if (ret == 0) {
564                 tdb_increment_seqnum(tdb);
565         }
566
567         SAFE_FREE(p); 
568         return ret;
569 }
570
571 /* store an element in the database, replacing any existing element
572    with the same key
573
574    return 0 on success, -1 on failure
575 */
576 int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
577 {
578         uint32_t hash;
579         int ret;
580
581         if (tdb->read_only || tdb->traverse_read) {
582                 tdb->ecode = TDB_ERR_RDONLY;
583                 tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, -1);
584                 return -1;
585         }
586
587         /* find which hash bucket it is in */
588         hash = tdb->hash_fn(&key);
589         if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
590                 return -1;
591
592         ret = _tdb_store(tdb, key, dbuf, flag, hash);
593         tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, ret);
594         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
595         return ret;
596 }
597
598 /* Append to an entry. Create if not exist. */
599 int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
600 {
601         uint32_t hash;
602         TDB_DATA dbuf;
603         int ret = -1;
604
605         /* find which hash bucket it is in */
606         hash = tdb->hash_fn(&key);
607         if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
608                 return -1;
609
610         dbuf = _tdb_fetch(tdb, key);
611
612         if (dbuf.dptr == NULL) {
613                 dbuf.dptr = (unsigned char *)malloc(new_dbuf.dsize);
614         } else {
615                 unsigned int new_len = dbuf.dsize + new_dbuf.dsize;
616                 unsigned char *new_dptr;
617
618                 /* realloc '0' is special: don't do that. */
619                 if (new_len == 0)
620                         new_len = 1;
621                 new_dptr = (unsigned char *)realloc(dbuf.dptr, new_len);
622                 if (new_dptr == NULL) {
623                         free(dbuf.dptr);
624                 }
625                 dbuf.dptr = new_dptr;
626         }
627
628         if (dbuf.dptr == NULL) {
629                 tdb->ecode = TDB_ERR_OOM;
630                 goto failed;
631         }
632
633         memcpy(dbuf.dptr + dbuf.dsize, new_dbuf.dptr, new_dbuf.dsize);
634         dbuf.dsize += new_dbuf.dsize;
635
636         ret = _tdb_store(tdb, key, dbuf, 0, hash);
637         tdb_trace_2rec_retrec(tdb, "tdb_append", key, new_dbuf, dbuf);
638         
639 failed:
640         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
641         SAFE_FREE(dbuf.dptr);
642         return ret;
643 }
644
645
646 /*
647   return the name of the current tdb file
648   useful for external logging functions
649 */
650 const char *tdb_name(struct tdb_context *tdb)
651 {
652         return tdb->name;
653 }
654
655 /*
656   return the underlying file descriptor being used by tdb, or -1
657   useful for external routines that want to check the device/inode
658   of the fd
659 */
660 int tdb_fd(struct tdb_context *tdb)
661 {
662         return tdb->fd;
663 }
664
665 /*
666   return the current logging function
667   useful for external tdb routines that wish to log tdb errors
668 */
669 tdb_log_func tdb_log_fn(struct tdb_context *tdb)
670 {
671         return tdb->log.log_fn;
672 }
673
674
675 /*
676   get the tdb sequence number. Only makes sense if the writers opened
677   with TDB_SEQNUM set. Note that this sequence number will wrap quite
678   quickly, so it should only be used for a 'has something changed'
679   test, not for code that relies on the count of the number of changes
680   made. If you want a counter then use a tdb record.
681
682   The aim of this sequence number is to allow for a very lightweight
683   test of a possible tdb change.
684 */
685 int tdb_get_seqnum(struct tdb_context *tdb)
686 {
687         tdb_off_t seqnum=0;
688
689         tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
690         return seqnum;
691 }
692
693 int tdb_hash_size(struct tdb_context *tdb)
694 {
695         return tdb->header.hash_size;
696 }
697
698 size_t tdb_map_size(struct tdb_context *tdb)
699 {
700         return tdb->map_size;
701 }
702
703 int tdb_get_flags(struct tdb_context *tdb)
704 {
705         return tdb->flags;
706 }
707
708 void tdb_add_flags(struct tdb_context *tdb, unsigned flags)
709 {
710         tdb->flags |= flags;
711 }
712
713 void tdb_remove_flags(struct tdb_context *tdb, unsigned flags)
714 {
715         tdb->flags &= ~flags;
716 }
717
718
719 /*
720   enable sequence number handling on an open tdb
721 */
722 void tdb_enable_seqnum(struct tdb_context *tdb)
723 {
724         tdb->flags |= TDB_SEQNUM;
725 }
726
727
728 /*
729   add a region of the file to the freelist. Length is the size of the region in bytes, 
730   which includes the free list header that needs to be added
731  */
732 static int tdb_free_region(struct tdb_context *tdb, tdb_off_t offset, ssize_t length)
733 {
734         struct list_struct rec;
735         if (length <= sizeof(rec)) {
736                 /* the region is not worth adding */
737                 return 0;
738         }
739         if (length + offset > tdb->map_size) {
740                 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: adding region beyond end of file\n"));
741                 return -1;              
742         }
743         memset(&rec,'\0',sizeof(rec));
744         rec.rec_len = length - sizeof(rec);
745         if (tdb_free(tdb, offset, &rec) == -1) {
746                 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: failed to add free record\n"));
747                 return -1;
748         }
749         return 0;
750 }
751
752 /*
753   wipe the entire database, deleting all records. This can be done
754   very fast by using a global lock. The entire data portion of the
755   file becomes a single entry in the freelist.
756
757   This code carefully steps around the recovery area, leaving it alone
758  */
759 int tdb_wipe_all(struct tdb_context *tdb)
760 {
761         int i;
762         tdb_off_t offset = 0;
763         ssize_t data_len;
764         tdb_off_t recovery_head;
765         tdb_len_t recovery_size = 0;
766
767         if (tdb_lockall(tdb) != 0) {
768                 return -1;
769         }
770
771         tdb_trace(tdb, "tdb_wipe_all");
772
773         /* see if the tdb has a recovery area, and remember its size
774            if so. We don't want to lose this as otherwise each
775            tdb_wipe_all() in a transaction will increase the size of
776            the tdb by the size of the recovery area */
777         if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
778                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery head\n"));
779                 goto failed;
780         }
781
782         if (recovery_head != 0) {
783                 struct list_struct rec;
784                 if (tdb->methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
785                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery record\n"));
786                         return -1;
787                 }       
788                 recovery_size = rec.rec_len + sizeof(rec);
789         }
790
791         /* wipe the hashes */
792         for (i=0;i<tdb->header.hash_size;i++) {
793                 if (tdb_ofs_write(tdb, TDB_HASH_TOP(i), &offset) == -1) {
794                         TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write hash %d\n", i));
795                         goto failed;
796                 }
797         }
798
799         /* wipe the freelist */
800         if (tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
801                 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write freelist\n"));
802                 goto failed;
803         }
804
805         /* add all the rest of the file to the freelist, possibly leaving a gap 
806            for the recovery area */
807         if (recovery_size == 0) {
808                 /* the simple case - the whole file can be used as a freelist */
809                 data_len = (tdb->map_size - TDB_DATA_START(tdb->header.hash_size));
810                 if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) {
811                         goto failed;
812                 }
813         } else {
814                 /* we need to add two freelist entries - one on either
815                    side of the recovery area 
816
817                    Note that we cannot shift the recovery area during
818                    this operation. Only the transaction.c code may
819                    move the recovery area or we risk subtle data
820                    corruption
821                 */
822                 data_len = (recovery_head - TDB_DATA_START(tdb->header.hash_size));
823                 if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) {
824                         goto failed;
825                 }
826                 /* and the 2nd free list entry after the recovery area - if any */
827                 data_len = tdb->map_size - (recovery_head+recovery_size);
828                 if (tdb_free_region(tdb, recovery_head+recovery_size, data_len) != 0) {
829                         goto failed;
830                 }
831         }
832
833         if (tdb_unlockall(tdb) != 0) {
834                 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to unlock\n"));
835                 goto failed;
836         }
837
838         return 0;
839
840 failed:
841         tdb_unlockall(tdb);
842         return -1;
843 }
844
845 struct traverse_state {
846         bool error;
847         struct tdb_context *dest_db;
848 };
849
850 /*
851   traverse function for repacking
852  */
853 static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data)
854 {
855         struct traverse_state *state = (struct traverse_state *)private_data;
856         if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) {
857                 state->error = true;
858                 return -1;
859         }
860         return 0;
861 }
862
863 /*
864   repack a tdb
865  */
866 int tdb_repack(struct tdb_context *tdb)
867 {
868         struct tdb_context *tmp_db;
869         struct traverse_state state;
870
871         tdb_trace(tdb, "tdb_repack");
872
873         if (tdb_transaction_start(tdb) != 0) {
874                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to start transaction\n"));
875                 return -1;
876         }
877
878         tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb), TDB_INTERNAL, O_RDWR|O_CREAT, 0);
879         if (tmp_db == NULL) {
880                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to create tmp_db\n"));
881                 tdb_transaction_cancel(tdb);
882                 return -1;
883         }
884
885         state.error = false;
886         state.dest_db = tmp_db;
887
888         if (tdb_traverse_read(tdb, repack_traverse, &state) == -1) {
889                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying out\n"));
890                 tdb_transaction_cancel(tdb);
891                 tdb_close(tmp_db);
892                 return -1;              
893         }
894
895         if (state.error) {
896                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during traversal\n"));
897                 tdb_transaction_cancel(tdb);
898                 tdb_close(tmp_db);
899                 return -1;
900         }
901
902         if (tdb_wipe_all(tdb) != 0) {
903                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to wipe database\n"));
904                 tdb_transaction_cancel(tdb);
905                 tdb_close(tmp_db);
906                 return -1;
907         }
908
909         state.error = false;
910         state.dest_db = tdb;
911
912         if (tdb_traverse_read(tmp_db, repack_traverse, &state) == -1) {
913                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying back\n"));
914                 tdb_transaction_cancel(tdb);
915                 tdb_close(tmp_db);
916                 return -1;              
917         }
918
919         if (state.error) {
920                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during second traversal\n"));
921                 tdb_transaction_cancel(tdb);
922                 tdb_close(tmp_db);
923                 return -1;
924         }
925
926         tdb_close(tmp_db);
927
928         if (tdb_transaction_commit(tdb) != 0) {
929                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to commit\n"));
930                 return -1;
931         }
932
933         return 0;
934 }
935
936 #ifdef TDB_TRACE
937 static void tdb_trace_write(struct tdb_context *tdb, const char *str)
938 {
939         if (write(tdb->tracefd, str, strlen(str)) != strlen(str)) {
940                 close(tdb->tracefd);
941                 tdb->tracefd = -1;
942         }
943 }
944
945 static void tdb_trace_start(struct tdb_context *tdb)
946 {
947         tdb_off_t seqnum=0;
948         char msg[sizeof(tdb_off_t) * 4 + 1];
949
950         tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
951         snprintf(msg, sizeof(msg), "%u ", seqnum);
952         tdb_trace_write(tdb, msg);
953 }
954
955 static void tdb_trace_end(struct tdb_context *tdb)
956 {
957         tdb_trace_write(tdb, "\n");
958 }
959
960 static void tdb_trace_end_ret(struct tdb_context *tdb, int ret)
961 {
962         char msg[sizeof(ret) * 4 + 4];
963         snprintf(msg, sizeof(msg), " = %i\n", ret);
964         tdb_trace_write(tdb, msg);
965 }
966
967 static void tdb_trace_record(struct tdb_context *tdb, TDB_DATA rec)
968 {
969         char msg[20 + rec.dsize*2], *p;
970         unsigned int i;
971
972         /* We differentiate zero-length records from non-existent ones. */
973         if (rec.dptr == NULL) {
974                 tdb_trace_write(tdb, " NULL");
975                 return;
976         }
977
978         /* snprintf here is purely cargo-cult programming. */
979         p = msg;
980         p += snprintf(p, sizeof(msg), " %zu:", rec.dsize);
981         for (i = 0; i < rec.dsize; i++)
982                 p += snprintf(p, 2, "%02x", rec.dptr[i]);
983
984         tdb_trace_write(tdb, msg);
985 }
986
987 void tdb_trace(struct tdb_context *tdb, const char *op)
988 {
989         tdb_trace_start(tdb);
990         tdb_trace_write(tdb, op);
991         tdb_trace_end(tdb);
992 }
993
994 void tdb_trace_seqnum(struct tdb_context *tdb, uint32_t seqnum, const char *op)
995 {
996         char msg[sizeof(tdb_off_t) * 4 + 1];
997
998         snprintf(msg, sizeof(msg), "%u ", seqnum);
999         tdb_trace_write(tdb, msg);
1000         tdb_trace_write(tdb, op);
1001         tdb_trace_end(tdb);
1002 }
1003
1004 void tdb_trace_open(struct tdb_context *tdb, const char *op,
1005                     unsigned hash_size, unsigned tdb_flags, unsigned open_flags)
1006 {
1007         char msg[128];
1008
1009         snprintf(msg, sizeof(msg),
1010                  "%s %u 0x%x 0x%x", op, hash_size, tdb_flags, open_flags);
1011         tdb_trace_start(tdb);
1012         tdb_trace_write(tdb, msg);
1013         tdb_trace_end(tdb);
1014 }
1015
1016 void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret)
1017 {
1018         tdb_trace_start(tdb);
1019         tdb_trace_write(tdb, op);
1020         tdb_trace_end_ret(tdb, ret);
1021 }
1022
1023 void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret)
1024 {
1025         tdb_trace_start(tdb);
1026         tdb_trace_write(tdb, op);
1027         tdb_trace_write(tdb, " =");
1028         tdb_trace_record(tdb, ret);
1029         tdb_trace_end(tdb);
1030 }
1031
1032 void tdb_trace_1rec(struct tdb_context *tdb, const char *op,
1033                     TDB_DATA rec)
1034 {
1035         tdb_trace_start(tdb);
1036         tdb_trace_write(tdb, op);
1037         tdb_trace_record(tdb, rec);
1038         tdb_trace_end(tdb);
1039 }
1040
1041 void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op,
1042                         TDB_DATA rec, int ret)
1043 {
1044         tdb_trace_start(tdb);
1045         tdb_trace_write(tdb, op);
1046         tdb_trace_record(tdb, rec);
1047         tdb_trace_end_ret(tdb, ret);
1048 }
1049
1050 void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op,
1051                            TDB_DATA rec, TDB_DATA ret)
1052 {
1053         tdb_trace_start(tdb);
1054         tdb_trace_write(tdb, op);
1055         tdb_trace_record(tdb, rec);
1056         tdb_trace_write(tdb, " =");
1057         tdb_trace_record(tdb, ret);
1058         tdb_trace_end(tdb);
1059 }
1060
1061 void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op,
1062                              TDB_DATA rec1, TDB_DATA rec2, unsigned flag,
1063                              int ret)
1064 {
1065         char msg[1 + sizeof(ret) * 4];
1066
1067         snprintf(msg, sizeof(msg), " %#x", flag);
1068         tdb_trace_start(tdb);
1069         tdb_trace_write(tdb, op);
1070         tdb_trace_record(tdb, rec1);
1071         tdb_trace_record(tdb, rec2);
1072         tdb_trace_write(tdb, msg);
1073         tdb_trace_end_ret(tdb, ret);
1074 }
1075
1076 void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
1077                            TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret)
1078 {
1079         tdb_trace_start(tdb);
1080         tdb_trace_write(tdb, op);
1081         tdb_trace_record(tdb, rec1);
1082         tdb_trace_record(tdb, rec2);
1083         tdb_trace_write(tdb, " =");
1084         tdb_trace_record(tdb, ret);
1085         tdb_trace_end(tdb);
1086 }
1087 #endif