2 Unix SMB/Netbios implementation.
4 Samba database functions
5 Copyright (C) Andrew Tridgell 1999
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
37 #define TDB_VERSION (0x26011967 + 1)
38 #define TDB_MAGIC (0x26011999U)
39 #define TDB_FREE_MAGIC (~TDB_MAGIC)
41 #define MIN_REC_SIZE (2*sizeof(struct list_struct) + TDB_ALIGN)
42 #define DEFAULT_HASH_SIZE 512
43 #define TDB_PAGE_SIZE 0x2000
44 #define TDB_LEN_MULTIPLIER 10
45 #define FREELIST_TOP (sizeof(struct tdb_header))
47 #define BUCKET(hash) ((hash) % tdb->header.hash_size)
49 /* the body of the database is made of one list_struct for the free space
50 plus a separate data list for each hash value */
52 tdb_len rec_len; /* total byte length of record */
53 tdb_off next; /* offset of the next record in the list */
54 tdb_len key_len; /* byte length of key */
55 tdb_len data_len; /* byte length of data */
56 unsigned full_hash; /* the full 32 bit hash of the key */
57 unsigned magic; /* try to catch errors */
59 the following union is implied
70 /* a null data record - useful for error returns */
71 static TDB_DATA null_data;
74 /* like strdup but for memory */
75 static char *memdup(char *d, int size)
78 ret = (char *)malloc(size);
79 if (!ret) return NULL;
86 /* a byte range locking function - return 0 on success
87 this functions locks/unlocks 1 byte at the specified offset */
88 static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset, int set)
95 if (tdb->read_only) return -1;
97 fl.l_type = set?F_WRLCK:F_UNLCK;
98 fl.l_whence = SEEK_SET;
103 if (fcntl(tdb->fd, F_SETLKW, &fl) != 0) {
105 printf("lock %d failed at %d (%s)\n",
106 set, offset, strerror(errno));
114 /* lock a list in the database. list -1 is the alloc list */
115 static int tdb_lock(TDB_CONTEXT *tdb, int list)
117 if (list < -1 || list >= (int)tdb->header.hash_size) {
119 printf("bad list %d\n", list);
123 if (tdb->locked[list+1] == 0) {
124 if (tdb_brlock(tdb, 4*(list+1), 1) != 0) {
128 tdb->locked[list+1]++;
132 /* unlock the database. */
133 static int tdb_unlock(TDB_CONTEXT *tdb, int list)
135 if (list < -1 || list >= (int)tdb->header.hash_size) {
137 printf("bad unlock list %d\n", list);
142 if (tdb->locked[list+1] == 0) {
144 printf("not locked %d\n", list);
148 if (tdb->locked[list+1] == 1) {
149 if (tdb_brlock(tdb, 4*(list+1), 0) != 0) {
153 tdb->locked[list+1]--;
157 /* the hash algorithm - turn a key into an integer
158 This is based on the hash agorithm from gdbm */
159 static unsigned tdb_hash(TDB_DATA *key)
161 unsigned value; /* Used to compute the hash value. */
162 unsigned i; /* Used to cycle through random values. */
164 /* Set the initial value from the key size. */
165 value = 0x238F13AF * key->dsize;
166 for (i=0; i < key->dsize; i++) {
167 value = (value + (key->dptr[i] << (i*5 % 24)));
170 value = (1103515243 * value + 12345);
175 /* find the top of the hash chain for an open database */
176 static tdb_off tdb_hash_top(TDB_CONTEXT *tdb, unsigned hash)
180 ret = FREELIST_TOP + (hash+1)*sizeof(tdb_off);
185 /* check for an out of bounds access - if it is out of bounds then
186 see if the database has been expanded by someone else and expand
188 static int tdb_oob(TDB_CONTEXT *tdb, tdb_off offset)
191 if (offset <= tdb->map_size) return 0;
194 if (st.st_size <= (ssize_t)tdb->map_size) return -1;
198 munmap(tdb->map_ptr, tdb->map_size);
203 tdb->map_size = st.st_size;
205 tdb->map_ptr = (void *)mmap(NULL, tdb->map_size,
206 tdb->read_only?PROT_READ:PROT_READ|PROT_WRITE,
207 MAP_SHARED | MAP_FILE, tdb->fd, 0);
213 /* write a lump of data at a specified offset */
214 static int tdb_write(TDB_CONTEXT *tdb, tdb_off offset, char *buf, tdb_len len)
216 if (tdb_oob(tdb, offset + len) != 0) {
217 /* oops - trying to write beyond the end of the database! */
219 printf("write error of length %u at offset %u (max %u)\n",
220 len, offset, tdb->map_size);
226 memcpy(offset + (char *)tdb->map_ptr, buf, len);
228 lseek(tdb->fd, offset, SEEK_SET);
229 if (write(tdb->fd, buf, len) != (ssize_t)len) {
236 /* read a lump of data at a specified offset */
237 static int tdb_read(TDB_CONTEXT *tdb, tdb_off offset, char *buf, tdb_len len)
239 if (tdb_oob(tdb, offset + len) != 0) {
240 /* oops - trying to read beyond the end of the database! */
242 printf("read error of length %u at offset %u (max %u)\n",
243 len, offset, tdb->map_size);
249 memcpy(buf, offset + (char *)tdb->map_ptr, len);
251 lseek(tdb->fd, offset, SEEK_SET);
252 if (read(tdb->fd, buf, len) != (ssize_t)len) {
260 /* read a lump of data, allocating the space for it */
261 static char *tdb_alloc_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_len len)
265 buf = (char *)malloc(len);
267 if (tdb_read(tdb, offset, buf, len) == -1) {
275 /* convenience routine for writing a record */
276 static int rec_write(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
278 return tdb_write(tdb, offset, (char *)rec, sizeof(*rec));
281 /* convenience routine for writing a tdb_off */
282 static int ofs_write(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
284 return tdb_write(tdb, offset, (char *)d, sizeof(*d));
287 /* read a tdb_off from the store */
288 static int ofs_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
290 return tdb_read(tdb, offset, (char *)d, sizeof(*d));
293 /* read a record and check for simple errors */
294 static int rec_read(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
296 if (tdb_read(tdb, offset, (char *)rec, sizeof(*rec)) == -1) return -1;
297 if (rec->magic != TDB_MAGIC) {
299 printf("bad magic 0x%08x at offset %d\n",
304 if (tdb_oob(tdb, rec->next) != 0) {
306 printf("bad next %d at offset %d\n",
314 /* expand the database at least length bytes by expanding the
315 underlying file and doing the mmap again if necessary */
316 static int tdb_expand(TDB_CONTEXT *tdb, tdb_off length)
318 struct list_struct rec;
324 /* make sure we know about any previous expansions by another
326 tdb_oob(tdb,tdb->map_size + 1);
328 /* always make room for at least 10 more records */
329 length *= TDB_LEN_MULTIPLIER;
331 /* and round the database up to a multiple of TDB_PAGE_SIZE */
332 length = ((tdb->map_size + length + TDB_PAGE_SIZE) & ~(TDB_PAGE_SIZE - 1)) - tdb->map_size;
334 /* expand the file itself */
335 lseek(tdb->fd, tdb->map_size + length - 1, SEEK_SET);
336 if (write(tdb->fd, &b, 1) != 1) goto fail;
338 /* form a new freelist record */
339 offset = FREELIST_TOP;
340 rec.rec_len = length - sizeof(rec);
341 rec.magic = TDB_FREE_MAGIC;
342 if (ofs_read(tdb, offset, &rec.next) == -1) {
348 munmap(tdb->map_ptr, tdb->map_size);
353 tdb->map_size += length;
356 if (rec_write(tdb, tdb->map_size - length, &rec) == -1) {
360 /* link it into the free list */
361 ptr = tdb->map_size - length;
362 if (ofs_write(tdb, offset, &ptr) == -1) goto fail;
365 tdb->map_ptr = (void *)mmap(NULL, tdb->map_size,
366 PROT_READ|PROT_WRITE,
367 MAP_SHARED | MAP_FILE, tdb->fd, 0);
377 /* allocate some space from the free list. The offset returned points
378 to a unconnected list_struct within the database with room for at
379 least length bytes of total data
381 0 is returned if the space could not be allocated
383 static tdb_off tdb_allocate(TDB_CONTEXT *tdb, tdb_len length)
385 tdb_off offset, rec_ptr, last_ptr;
386 struct list_struct rec, lastrec, newrec;
392 offset = FREELIST_TOP;
394 /* read in the freelist top */
395 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
399 /* keep looking until we find a freelist record that is big
402 if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec)) == -1) {
406 if (rec.magic != TDB_FREE_MAGIC) {
408 printf("bad magic 0x%08x in free list\n", rec.magic);
413 if (rec.rec_len >= length) {
414 /* found it - now possibly split it up */
415 if (rec.rec_len > length + MIN_REC_SIZE) {
416 length = (length + TDB_ALIGN) & ~(TDB_ALIGN-1);
418 newrec.rec_len = rec.rec_len - (sizeof(rec) + length);
419 newrec.next = rec.next;
420 newrec.magic = TDB_FREE_MAGIC;
422 rec.rec_len = length;
423 rec.next = rec_ptr + sizeof(rec) + rec.rec_len;
425 if (rec_write(tdb, rec.next, &newrec) == -1) {
429 if (rec_write(tdb, rec_ptr, &rec) == -1) {
434 /* remove it from the list */
436 offset = FREELIST_TOP;
438 if (ofs_write(tdb, offset, &rec.next) == -1) {
442 lastrec.next = rec.next;
443 if (rec_write(tdb, last_ptr, &lastrec) == -1) {
448 /* all done - return the new record offset */
453 /* move to the next record */
459 /* we didn't find enough space. See if we can expand the
460 database and if we can then try again */
461 if (tdb_expand(tdb, length + sizeof(rec)) == 0) goto again;
465 printf("tdb_allocate failed for size %u\n", length);
471 /* initialise a new database with a specified hash size */
472 static int tdb_new_database(TDB_CONTEXT *tdb, int hash_size)
474 struct tdb_header header;
478 /* create the header */
479 header.version = TDB_VERSION;
480 header.hash_size = hash_size;
481 lseek(tdb->fd, 0, SEEK_SET);
482 ftruncate(tdb->fd, 0);
484 if (write(tdb->fd, &header, sizeof(header)) != sizeof(header)) return -1;
486 /* the freelist and hash pointers */
488 for (i=0;i<hash_size+1;i++) {
489 if (write(tdb->fd, &offset, sizeof(tdb_off)) != sizeof(tdb_off)) return -1;
493 printf("initialised database of hash_size %u\n",
500 /* update an entry in place - this only works if the new data size
501 is <= the old data size and the key exists.
504 int tdb_update(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf)
507 tdb_off offset, rec_ptr;
508 struct list_struct rec;
511 /* find which hash bucket it is in */
512 hash = tdb_hash(&key);
514 tdb_lock(tdb, BUCKET(hash));
516 /* find the top of the hash chain */
517 offset = tdb_hash_top(tdb, hash);
519 /* read in the hash top */
520 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
524 /* keep looking until we find the right record */
526 if (rec_read(tdb, rec_ptr, &rec) == -1) {
530 if (hash == rec.full_hash && key.dsize == rec.key_len) {
531 /* a very likely hit - read the full key */
532 data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
534 if (!data) goto fail;
536 if (memcmp(key.dptr, data, key.dsize) == 0) {
538 if (rec.rec_len < key.dsize + dbuf.dsize) {
539 /* the update won't fit! */
542 if (tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
543 dbuf.dptr, dbuf.dsize) == -1) {
546 if (dbuf.dsize != rec.data_len) {
547 rec.data_len = dbuf.dsize;
548 if (rec_write(tdb, rec_ptr, &rec) == -1) {
553 tdb_unlock(tdb, BUCKET(hash));
562 /* move to the next record */
566 /* we didn't find it */
568 tdb_unlock(tdb, BUCKET(hash));
569 if (data) free(data);
574 /* find an entry in the database given a key */
575 TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key)
578 tdb_off offset, rec_ptr;
579 struct list_struct rec;
583 /* find which hash bucket it is in */
584 hash = tdb_hash(&key);
586 tdb_lock(tdb, BUCKET(hash));
588 /* find the top of the hash chain */
589 offset = tdb_hash_top(tdb, hash);
591 /* read in the hash top */
592 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
596 /* keep looking until we find the right record */
598 if (rec_read(tdb, rec_ptr, &rec) == -1) {
602 if (hash == rec.full_hash && key.dsize == rec.key_len) {
603 /* a very likely hit - read the full record */
604 data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
605 rec.key_len + rec.data_len);
610 if (memcmp(key.dptr, data, key.dsize) == 0) {
611 /* a definate match */
612 ret.dptr = (char *)memdup(data + rec.key_len, rec.data_len);
613 ret.dsize = rec.data_len;
615 tdb_unlock(tdb, BUCKET(hash));
623 /* move to the next record */
627 /* we didn't find it */
629 tdb_unlock(tdb, BUCKET(hash));
633 /* check if an entry in the database exists
635 note that 1 is returned if the key is found and 0 is returned if not found
636 this doesn't match the conventions in the rest of this module, but is
639 int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key)
642 tdb_off offset, rec_ptr;
643 struct list_struct rec;
646 /* find which hash bucket it is in */
647 hash = tdb_hash(&key);
649 tdb_lock(tdb, BUCKET(hash));
651 /* find the top of the hash chain */
652 offset = tdb_hash_top(tdb, hash);
654 /* read in the hash top */
655 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
659 /* keep looking until we find the right record */
661 if (rec_read(tdb, rec_ptr, &rec) == -1) {
665 if (hash == rec.full_hash && key.dsize == rec.key_len) {
666 /* a very likely hit - read the full record */
667 data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
668 rec.key_len + rec.data_len);
673 if (memcmp(key.dptr, data, key.dsize) == 0) {
674 /* a definate match */
676 tdb_unlock(tdb, BUCKET(hash));
684 /* move to the next record */
688 /* we didn't find it */
690 tdb_unlock(tdb, BUCKET(hash));
695 /* traverse the entire database - calling fn(tdb, key, data) on each element.
696 return -1 on error or the record count traversed
697 if fn is NULL then it is not called
698 a non-zero return value from fn() indicates that the traversal should stop
700 int tdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf))
704 tdb_off offset, rec_ptr;
705 struct list_struct rec;
709 /* loop over all hash chains */
710 for (h = 0; h < tdb->header.hash_size; h++) {
711 tdb_lock(tdb, BUCKET(h));
713 /* read in the hash top */
714 offset = tdb_hash_top(tdb, h);
715 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
719 /* traverse all records for this hash */
721 if (rec_read(tdb, rec_ptr, &rec) == -1) {
725 /* now read the full record */
726 data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
727 rec.key_len + rec.data_len);
733 key.dsize = rec.key_len;
734 dbuf.dptr = data + rec.key_len;
735 dbuf.dsize = rec.data_len;
738 if (fn && fn(tdb, key, dbuf) != 0) {
739 /* they want us to stop traversing */
741 tdb_unlock(tdb, BUCKET(h));
748 /* move to the next record */
751 tdb_unlock(tdb, BUCKET(h));
754 /* return the number traversed */
758 tdb_unlock(tdb, BUCKET(h));
763 /* find the first entry in the database and return its key */
764 TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb)
766 tdb_off offset, rec_ptr;
767 struct list_struct rec;
771 /* look for a non-empty hash chain */
772 for (hash = 0, rec_ptr = 0;
773 hash < tdb->header.hash_size;
775 /* find the top of the hash chain */
776 offset = tdb_hash_top(tdb, hash);
778 tdb_lock(tdb, BUCKET(hash));
780 /* read in the hash top */
781 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
787 tdb_unlock(tdb, BUCKET(hash));
790 if (rec_ptr == 0) return null_data;
792 /* we've found a non-empty chain, now read the record */
793 if (rec_read(tdb, rec_ptr, &rec) == -1) {
797 /* allocate and read the key space */
798 ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec), rec.key_len);
799 ret.dsize = rec.key_len;
800 tdb_unlock(tdb, BUCKET(hash));
804 tdb_unlock(tdb, BUCKET(hash));
808 /* find the next entry in the database, returning its key */
809 TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key)
812 tdb_off offset, rec_ptr;
813 struct list_struct rec;
817 /* find which hash bucket it is in */
818 hash = tdb_hash(&key);
820 tdb_lock(tdb, BUCKET(hash));
822 /* find the top of the hash chain */
823 offset = tdb_hash_top(tdb, hash);
825 /* read in the hash top */
826 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
830 /* look until we find the right record */
832 if (rec_read(tdb, rec_ptr, &rec) == -1) {
836 if (hash == rec.full_hash && key.dsize == rec.key_len) {
837 /* a very likely hit - read the full key */
838 data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
844 if (memcmp(key.dptr, data, key.dsize) == 0) {
845 /* a definate match - we want the next
846 record after this one */
849 if (rec_ptr == 0) goto next_hash;
857 /* move to the next record */
862 tdb_unlock(tdb, BUCKET(hash));
865 if (h == tdb->header.hash_size - 1) return null_data;
867 /* look for a non-empty hash chain */
868 for (hash = h+1, rec_ptr = 0;
869 hash < tdb->header.hash_size;
871 /* find the top of the hash chain */
872 offset = tdb_hash_top(tdb, hash);
874 tdb_lock(tdb, BUCKET(hash));
875 /* read in the hash top */
876 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
882 tdb_unlock(tdb, BUCKET(hash));
885 if (rec_ptr == 0) return null_data;
889 /* we've found a non-empty chain, now read the record */
890 if (rec_read(tdb, rec_ptr, &rec) == -1) {
894 /* allocate and read the key space */
895 ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec), rec.key_len);
896 ret.dsize = rec.key_len;
897 tdb_unlock(tdb, BUCKET(hash));
901 tdb_unlock(tdb, BUCKET(hash));
905 /* delete an entry in the database given a key */
906 int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key)
909 tdb_off offset, rec_ptr, last_ptr;
910 struct list_struct rec, lastrec;
913 /* find which hash bucket it is in */
914 hash = tdb_hash(&key);
916 tdb_lock(tdb, BUCKET(hash));
918 /* find the top of the hash chain */
919 offset = tdb_hash_top(tdb, hash);
921 /* read in the hash top */
922 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
928 /* keep looking until we find the right record */
930 if (rec_read(tdb, rec_ptr, &rec) == -1) {
934 if (hash == rec.full_hash && key.dsize == rec.key_len) {
935 /* a very likely hit - read the record and full key */
936 data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
942 if (memcmp(key.dptr, data, key.dsize) == 0) {
943 /* a definate match - delete it */
945 offset = tdb_hash_top(tdb, hash);
946 if (ofs_write(tdb, offset, &rec.next) == -1) {
950 lastrec.next = rec.next;
951 if (rec_write(tdb, last_ptr, &lastrec) == -1) {
955 tdb_unlock(tdb, BUCKET(hash));
957 /* and recover the space */
958 offset = FREELIST_TOP;
959 if (ofs_read(tdb, offset, &rec.next) == -1) {
962 rec.magic = TDB_FREE_MAGIC;
963 if (rec_write(tdb, rec_ptr, &rec) == -1) {
966 if (ofs_write(tdb, offset, &rec_ptr) == -1) {
970 /* yipee - all done */
981 /* move to the next record */
988 if (data) free(data);
989 tdb_unlock(tdb, BUCKET(hash));
993 if (data) free(data);
999 /* store an element in the database, replacing any existing element
1002 return 0 on success, -1 on failure
1004 int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
1006 struct list_struct rec;
1008 tdb_off rec_ptr, offset;
1011 /* find which hash bucket it is in */
1012 hash = tdb_hash(&key);
1014 /* check for it existing */
1015 if (flag == TDB_INSERT && tdb_exists(tdb, key)) {
1019 /* first try in-place update */
1020 if (flag != TDB_INSERT && tdb_update(tdb, key, dbuf) == 0) {
1024 rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize);
1029 tdb_lock(tdb, BUCKET(hash));
1031 /* delete any existing record - if it doesn't exist we don't care */
1032 if (flag != TDB_INSERT) {
1033 tdb_delete(tdb, key);
1036 /* read the newly created record */
1037 if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec)) == -1) {
1041 if (rec.magic != TDB_FREE_MAGIC) goto fail;
1043 /* find the top of the hash chain */
1044 offset = tdb_hash_top(tdb, hash);
1046 /* read in the hash top diretcly into our next pointer */
1047 if (ofs_read(tdb, offset, &rec.next) == -1) {
1051 rec.key_len = key.dsize;
1052 rec.data_len = dbuf.dsize;
1053 rec.full_hash = hash;
1054 rec.magic = TDB_MAGIC;
1056 p = (char *)malloc(sizeof(rec) + key.dsize + dbuf.dsize);
1059 memcpy(p, &rec, sizeof(rec));
1060 memcpy(p+sizeof(rec), key.dptr, key.dsize);
1061 memcpy(p+sizeof(rec)+key.dsize, dbuf.dptr, dbuf.dsize);
1063 if (tdb_write(tdb, rec_ptr, p, sizeof(rec)+key.dsize+dbuf.dsize) == -1)
1069 /* and point the top of the hash chain at it */
1070 if (ofs_write(tdb, offset, &rec_ptr) == -1) goto fail;
1072 tdb_unlock(tdb, BUCKET(hash));
1077 printf("store failed for hash 0x%08x in bucket %u\n", hash, BUCKET(hash));
1080 tdb_unlock(tdb, BUCKET(hash));
1085 /* open the database, creating it if necessary
1087 The flags and mode are passed straight to the open call on the database
1088 file. A flags value of O_WRONLY is invalid
1090 The hash size is advisory, use zero for a default value.
1092 return is NULL on error
1094 TDB_CONTEXT *tdb_open(char *name, int hash_size, int flags, mode_t mode)
1096 TDB_CONTEXT tdb, *ret;
1103 if ((flags & O_ACCMODE) == O_WRONLY) goto fail;
1105 if (hash_size == 0) hash_size = DEFAULT_HASH_SIZE;
1107 memset(&tdb, 0, sizeof(tdb));
1109 tdb.fd = open(name, flags, mode);
1110 if (tdb.fd == -1) goto fail;
1112 tdb_brlock(&tdb, 0, 1);
1114 if (read(tdb.fd, &tdb.header, sizeof(tdb.header)) != sizeof(tdb.header) ||
1115 tdb.header.version != TDB_VERSION) {
1116 /* its not a valid database - possibly initialise it */
1117 if (!(flags & O_CREAT)) {
1120 if (tdb_new_database(&tdb, hash_size) == -1) goto fail;
1122 lseek(tdb.fd, 0, SEEK_SET);
1123 if (read(tdb.fd, &tdb.header, sizeof(tdb.header)) != sizeof(tdb.header)) goto fail;
1128 /* map the database and fill in the return structure */
1129 tdb.name = (char *)strdup(name);
1130 tdb.locked = (int *)calloc(tdb.header.hash_size+1,
1131 sizeof(tdb.locked[0]));
1132 if (!tdb.locked) goto fail;
1133 tdb.map_size = st.st_size;
1134 tdb.read_only = ((flags & O_ACCMODE) == O_RDONLY);
1136 tdb.map_ptr = (void *)mmap(NULL, st.st_size,
1137 tdb.read_only? PROT_READ : PROT_READ|PROT_WRITE,
1138 MAP_SHARED | MAP_FILE, tdb.fd, 0);
1141 ret = (TDB_CONTEXT *)malloc(sizeof(tdb));
1142 if (!ret) goto fail;
1147 printf("mapped database of hash_size %u map_size=%u\n",
1148 hash_size, tdb.map_size);
1151 tdb_brlock(&tdb, 0, 0);
1155 tdb_brlock(&tdb, 0, 0);
1156 if (tdb.name) free(tdb.name);
1157 if (tdb.fd != -1) close(tdb.fd);
1158 if (tdb.map_ptr) munmap(tdb.map_ptr, tdb.map_size);
1163 /* close a database */
1164 int tdb_close(TDB_CONTEXT *tdb)
1166 if (!tdb) return -1;
1168 if (tdb->name) free(tdb->name);
1169 if (tdb->fd != -1) close(tdb->fd);
1170 if (tdb->map_ptr) munmap(tdb->map_ptr, tdb->map_size);
1171 if (tdb->locked) free(tdb->locked);
1173 memset(tdb, 0, sizeof(*tdb));
1179 /* lock the database. If we already have it locked then don't do anything */
1180 int tdb_writelock(TDB_CONTEXT *tdb)
1182 return tdb_lock(tdb, -1);
1185 /* unlock the database. */
1186 int tdb_writeunlock(TDB_CONTEXT *tdb)
1188 return tdb_unlock(tdb, -1);
1191 /* lock one hash chain. This is meant to be used to reduce locking
1192 contention - it cannot guarantee how many records will be locked */
1193 int tdb_lockchain(TDB_CONTEXT *tdb, TDB_DATA key)
1195 return tdb_lock(tdb, BUCKET(tdb_hash(&key)));
1199 /* unlock one hash chain */
1200 int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key)
1202 return tdb_unlock(tdb, BUCKET(tdb_hash(&key)));