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))
53 #define LIST_LOCK_BASE 1024
55 #define BUCKET(hash) ((hash) % tdb->header.hash_size)
57 /* the body of the database is made of one list_struct for the free space
58 plus a separate data list for each hash value */
60 tdb_len rec_len; /* total byte length of record */
61 tdb_off next; /* offset of the next record in the list */
62 tdb_len key_len; /* byte length of key */
63 tdb_len data_len; /* byte length of data */
64 unsigned full_hash; /* the full 32 bit hash of the key */
65 unsigned magic; /* try to catch errors */
67 the following union is implied
78 /* a null data record - useful for error returns */
79 static TDB_DATA null_data;
82 /* like strdup but for memory */
83 static char *memdup(char *d, int size)
86 ret = (char *)malloc(size);
87 if (!ret) return NULL;
94 /* a byte range locking function - return 0 on success
95 this functions locks/unlocks 1 byte at the specified offset */
96 static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
97 int set, int rw_type, int lck_type)
104 if (tdb->read_only) return -1;
106 fl.l_type = set==LOCK_SET?rw_type:F_UNLCK;
107 fl.l_whence = SEEK_SET;
112 if (fcntl(tdb->fd, lck_type, &fl) != 0 && lck_type == F_SETLKW) {
114 printf("lock %d failed at %d (%s)\n",
115 set, offset, strerror(errno));
123 /* lock a list in the database. list -1 is the alloc list */
124 static int tdb_lock(TDB_CONTEXT *tdb, int list)
126 if (list < -1 || list >= (int)tdb->header.hash_size) {
128 printf("bad list %d\n", list);
132 if (tdb->locked[list+1] == 0) {
133 if (tdb_brlock(tdb, LIST_LOCK_BASE + 4*list, LOCK_SET,
134 F_WRLCK, F_SETLKW) != 0) {
138 tdb->locked[list+1]++;
142 /* unlock the database. */
143 static int tdb_unlock(TDB_CONTEXT *tdb, int list)
145 if (list < -1 || list >= (int)tdb->header.hash_size) {
147 printf("bad unlock list %d\n", list);
152 if (tdb->locked[list+1] == 0) {
154 printf("not locked %d\n", list);
158 if (tdb->locked[list+1] == 1) {
159 if (tdb_brlock(tdb, LIST_LOCK_BASE + 4*list, LOCK_CLEAR,
160 F_WRLCK, F_SETLKW) != 0) {
164 tdb->locked[list+1]--;
168 /* the hash algorithm - turn a key into an integer
169 This is based on the hash agorithm from gdbm */
170 static unsigned tdb_hash(TDB_DATA *key)
172 unsigned value; /* Used to compute the hash value. */
173 unsigned i; /* Used to cycle through random values. */
175 /* Set the initial value from the key size. */
176 value = 0x238F13AF * key->dsize;
177 for (i=0; i < key->dsize; i++) {
178 value = (value + (key->dptr[i] << (i*5 % 24)));
181 value = (1103515243 * value + 12345);
186 /* find the top of the hash chain for an open database */
187 static tdb_off tdb_hash_top(TDB_CONTEXT *tdb, unsigned hash)
191 ret = FREELIST_TOP + (hash+1)*sizeof(tdb_off);
196 /* check for an out of bounds access - if it is out of bounds then
197 see if the database has been expanded by someone else and expand
199 static int tdb_oob(TDB_CONTEXT *tdb, tdb_off offset)
202 if (offset <= tdb->map_size) return 0;
205 if (st.st_size <= (ssize_t)tdb->map_size) return -1;
209 munmap(tdb->map_ptr, tdb->map_size);
214 tdb->map_size = st.st_size;
216 tdb->map_ptr = (void *)mmap(NULL, tdb->map_size,
217 tdb->read_only?PROT_READ:PROT_READ|PROT_WRITE,
218 MAP_SHARED | MAP_FILE, tdb->fd, 0);
224 /* write a lump of data at a specified offset */
225 static int tdb_write(TDB_CONTEXT *tdb, tdb_off offset, char *buf, tdb_len len)
227 if (tdb_oob(tdb, offset + len) != 0) {
228 /* oops - trying to write beyond the end of the database! */
230 printf("write error of length %u at offset %u (max %u)\n",
231 len, offset, tdb->map_size);
237 memcpy(offset + (char *)tdb->map_ptr, buf, len);
239 lseek(tdb->fd, offset, SEEK_SET);
240 if (write(tdb->fd, buf, len) != (ssize_t)len) {
247 /* read a lump of data at a specified offset */
248 static int tdb_read(TDB_CONTEXT *tdb, tdb_off offset, char *buf, tdb_len len)
250 if (tdb_oob(tdb, offset + len) != 0) {
251 /* oops - trying to read beyond the end of the database! */
253 printf("read error of length %u at offset %u (max %u)\n",
254 len, offset, tdb->map_size);
260 memcpy(buf, offset + (char *)tdb->map_ptr, len);
262 lseek(tdb->fd, offset, SEEK_SET);
263 if (read(tdb->fd, buf, len) != (ssize_t)len) {
271 /* read a lump of data, allocating the space for it */
272 static char *tdb_alloc_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_len len)
276 buf = (char *)malloc(len);
278 if (!buf) return NULL;
280 if (tdb_read(tdb, offset, buf, len) == -1) {
288 /* convenience routine for writing a record */
289 static int rec_write(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
291 return tdb_write(tdb, offset, (char *)rec, sizeof(*rec));
294 /* convenience routine for writing a tdb_off */
295 static int ofs_write(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
297 return tdb_write(tdb, offset, (char *)d, sizeof(*d));
300 /* read a tdb_off from the store */
301 static int ofs_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
303 return tdb_read(tdb, offset, (char *)d, sizeof(*d));
306 /* read a record and check for simple errors */
307 static int rec_read(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
309 if (tdb_read(tdb, offset, (char *)rec, sizeof(*rec)) == -1) return -1;
310 if (rec->magic != TDB_MAGIC) {
312 printf("bad magic 0x%08x at offset %d\n",
317 if (tdb_oob(tdb, rec->next) != 0) {
319 printf("bad next %d at offset %d\n",
327 /* expand the database at least length bytes by expanding the
328 underlying file and doing the mmap again if necessary */
329 static int tdb_expand(TDB_CONTEXT *tdb, tdb_off length)
331 struct list_struct rec;
337 /* make sure we know about any previous expansions by another
339 tdb_oob(tdb,tdb->map_size + 1);
341 /* always make room for at least 10 more records */
342 length *= TDB_LEN_MULTIPLIER;
344 /* and round the database up to a multiple of TDB_PAGE_SIZE */
345 length = ((tdb->map_size + length + TDB_PAGE_SIZE) & ~(TDB_PAGE_SIZE - 1)) - tdb->map_size;
347 /* expand the file itself */
348 lseek(tdb->fd, tdb->map_size + length - 1, SEEK_SET);
349 if (write(tdb->fd, &b, 1) != 1) goto fail;
351 /* form a new freelist record */
352 offset = FREELIST_TOP;
353 rec.rec_len = length - sizeof(rec);
354 rec.magic = TDB_FREE_MAGIC;
355 if (ofs_read(tdb, offset, &rec.next) == -1) {
361 munmap(tdb->map_ptr, tdb->map_size);
366 tdb->map_size += length;
369 if (rec_write(tdb, tdb->map_size - length, &rec) == -1) {
373 /* link it into the free list */
374 ptr = tdb->map_size - length;
375 if (ofs_write(tdb, offset, &ptr) == -1) goto fail;
378 tdb->map_ptr = (void *)mmap(NULL, tdb->map_size,
379 PROT_READ|PROT_WRITE,
380 MAP_SHARED | MAP_FILE, tdb->fd, 0);
390 /* allocate some space from the free list. The offset returned points
391 to a unconnected list_struct within the database with room for at
392 least length bytes of total data
394 0 is returned if the space could not be allocated
396 static tdb_off tdb_allocate(TDB_CONTEXT *tdb, tdb_len length)
398 tdb_off offset, rec_ptr, last_ptr;
399 struct list_struct rec, lastrec, newrec;
405 offset = FREELIST_TOP;
407 /* read in the freelist top */
408 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
412 /* keep looking until we find a freelist record that is big
415 if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec)) == -1) {
419 if (rec.magic != TDB_FREE_MAGIC) {
421 printf("bad magic 0x%08x in free list\n", rec.magic);
426 if (rec.rec_len >= length) {
427 /* found it - now possibly split it up */
428 if (rec.rec_len > length + MIN_REC_SIZE) {
429 length = (length + TDB_ALIGN) & ~(TDB_ALIGN-1);
431 newrec.rec_len = rec.rec_len - (sizeof(rec) + length);
432 newrec.next = rec.next;
433 newrec.magic = TDB_FREE_MAGIC;
435 rec.rec_len = length;
436 rec.next = rec_ptr + sizeof(rec) + rec.rec_len;
438 if (rec_write(tdb, rec.next, &newrec) == -1) {
442 if (rec_write(tdb, rec_ptr, &rec) == -1) {
447 /* remove it from the list */
449 offset = FREELIST_TOP;
451 if (ofs_write(tdb, offset, &rec.next) == -1) {
455 lastrec.next = rec.next;
456 if (rec_write(tdb, last_ptr, &lastrec) == -1) {
461 /* all done - return the new record offset */
466 /* move to the next record */
472 /* we didn't find enough space. See if we can expand the
473 database and if we can then try again */
474 if (tdb_expand(tdb, length + sizeof(rec)) == 0) goto again;
478 printf("tdb_allocate failed for size %u\n", length);
484 /* initialise a new database with a specified hash size */
485 static int tdb_new_database(TDB_CONTEXT *tdb, int hash_size)
487 struct tdb_header header;
491 /* create the header */
492 header.version = TDB_VERSION;
493 header.hash_size = hash_size;
494 lseek(tdb->fd, 0, SEEK_SET);
495 ftruncate(tdb->fd, 0);
497 if (write(tdb->fd, &header, sizeof(header)) != sizeof(header)) return -1;
499 /* the freelist and hash pointers */
501 for (i=0;i<hash_size+1;i++) {
502 if (write(tdb->fd, &offset, sizeof(tdb_off)) != sizeof(tdb_off)) return -1;
506 printf("initialised database of hash_size %u\n",
513 /* update an entry in place - this only works if the new data size
514 is <= the old data size and the key exists.
517 int tdb_update(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf)
520 tdb_off offset, rec_ptr;
521 struct list_struct rec;
524 /* find which hash bucket it is in */
525 hash = tdb_hash(&key);
527 tdb_lock(tdb, BUCKET(hash));
529 /* find the top of the hash chain */
530 offset = tdb_hash_top(tdb, hash);
532 /* read in the hash top */
533 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
537 /* keep looking until we find the right record */
539 if (rec_read(tdb, rec_ptr, &rec) == -1) {
543 if (hash == rec.full_hash && key.dsize == rec.key_len) {
544 /* a very likely hit - read the full key */
545 data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
547 if (!data) goto fail;
549 if (memcmp(key.dptr, data, key.dsize) == 0) {
551 if (rec.rec_len < key.dsize + dbuf.dsize) {
552 /* the update won't fit! */
555 if (tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
556 dbuf.dptr, dbuf.dsize) == -1) {
559 if (dbuf.dsize != rec.data_len) {
560 rec.data_len = dbuf.dsize;
561 if (rec_write(tdb, rec_ptr, &rec) == -1) {
566 tdb_unlock(tdb, BUCKET(hash));
575 /* move to the next record */
579 /* we didn't find it */
581 tdb_unlock(tdb, BUCKET(hash));
582 if (data) free(data);
587 /* find an entry in the database given a key */
588 TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key)
591 tdb_off offset, rec_ptr;
592 struct list_struct rec;
596 /* find which hash bucket it is in */
597 hash = tdb_hash(&key);
599 tdb_lock(tdb, BUCKET(hash));
601 /* find the top of the hash chain */
602 offset = tdb_hash_top(tdb, hash);
604 /* read in the hash top */
605 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
609 /* keep looking until we find the right record */
611 if (rec_read(tdb, rec_ptr, &rec) == -1) {
615 if (hash == rec.full_hash && key.dsize == rec.key_len) {
616 /* a very likely hit - read the full record */
617 data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
618 rec.key_len + rec.data_len);
623 if (memcmp(key.dptr, data, key.dsize) == 0) {
624 /* a definate match */
625 ret.dptr = (char *)memdup(data + rec.key_len, rec.data_len);
626 ret.dsize = rec.data_len;
628 tdb_unlock(tdb, BUCKET(hash));
636 /* move to the next record */
640 /* we didn't find it */
642 tdb_unlock(tdb, BUCKET(hash));
646 /* check if an entry in the database exists
648 note that 1 is returned if the key is found and 0 is returned if not found
649 this doesn't match the conventions in the rest of this module, but is
652 int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key)
655 tdb_off offset, rec_ptr;
656 struct list_struct rec;
659 /* find which hash bucket it is in */
660 hash = tdb_hash(&key);
662 tdb_lock(tdb, BUCKET(hash));
664 /* find the top of the hash chain */
665 offset = tdb_hash_top(tdb, hash);
667 /* read in the hash top */
668 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
672 /* keep looking until we find the right record */
674 if (rec_read(tdb, rec_ptr, &rec) == -1) {
678 if (hash == rec.full_hash && key.dsize == rec.key_len) {
679 /* a very likely hit - read the full record */
680 data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
681 rec.key_len + rec.data_len);
686 if (memcmp(key.dptr, data, key.dsize) == 0) {
687 /* a definate match */
689 tdb_unlock(tdb, BUCKET(hash));
697 /* move to the next record */
701 /* we didn't find it */
703 tdb_unlock(tdb, BUCKET(hash));
708 /* traverse the entire database - calling fn(tdb, key, data) on each element.
709 return -1 on error or the record count traversed
710 if fn is NULL then it is not called
711 a non-zero return value from fn() indicates that the traversal should stop
713 int tdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf))
717 tdb_off offset, rec_ptr;
718 struct list_struct rec;
722 /* loop over all hash chains */
723 for (h = 0; h < tdb->header.hash_size; h++) {
724 tdb_lock(tdb, BUCKET(h));
726 /* read in the hash top */
727 offset = tdb_hash_top(tdb, h);
728 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
732 /* traverse all records for this hash */
734 if (rec_read(tdb, rec_ptr, &rec) == -1) {
738 /* now read the full record */
739 data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
740 rec.key_len + rec.data_len);
746 key.dsize = rec.key_len;
747 dbuf.dptr = data + rec.key_len;
748 dbuf.dsize = rec.data_len;
751 if (fn && fn(tdb, key, dbuf) != 0) {
752 /* they want us to stop traversing */
754 tdb_unlock(tdb, BUCKET(h));
761 /* move to the next record */
764 tdb_unlock(tdb, BUCKET(h));
767 /* return the number traversed */
771 tdb_unlock(tdb, BUCKET(h));
776 /* find the first entry in the database and return its key */
777 TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb)
779 tdb_off offset, rec_ptr;
780 struct list_struct rec;
784 /* look for a non-empty hash chain */
785 for (hash = 0, rec_ptr = 0;
786 hash < tdb->header.hash_size;
788 /* find the top of the hash chain */
789 offset = tdb_hash_top(tdb, hash);
791 tdb_lock(tdb, BUCKET(hash));
793 /* read in the hash top */
794 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
800 tdb_unlock(tdb, BUCKET(hash));
803 if (rec_ptr == 0) return null_data;
805 /* we've found a non-empty chain, now read the record */
806 if (rec_read(tdb, rec_ptr, &rec) == -1) {
810 /* allocate and read the key space */
811 ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec), rec.key_len);
812 ret.dsize = rec.key_len;
813 tdb_unlock(tdb, BUCKET(hash));
817 tdb_unlock(tdb, BUCKET(hash));
821 /* find the next entry in the database, returning its key */
822 TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key)
825 tdb_off offset, rec_ptr;
826 struct list_struct rec;
830 /* find which hash bucket it is in */
831 hash = tdb_hash(&key);
833 tdb_lock(tdb, BUCKET(hash));
835 /* find the top of the hash chain */
836 offset = tdb_hash_top(tdb, hash);
838 /* read in the hash top */
839 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
843 /* look until we find the right record */
845 if (rec_read(tdb, rec_ptr, &rec) == -1) {
849 if (hash == rec.full_hash && key.dsize == rec.key_len) {
850 /* a very likely hit - read the full key */
851 data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
857 if (memcmp(key.dptr, data, key.dsize) == 0) {
858 /* a definate match - we want the next
859 record after this one */
862 if (rec_ptr == 0) goto next_hash;
870 /* move to the next record */
875 tdb_unlock(tdb, BUCKET(hash));
878 if (h == tdb->header.hash_size - 1) return null_data;
880 /* look for a non-empty hash chain */
881 for (hash = h+1, rec_ptr = 0;
882 hash < tdb->header.hash_size;
884 /* find the top of the hash chain */
885 offset = tdb_hash_top(tdb, hash);
887 tdb_lock(tdb, BUCKET(hash));
888 /* read in the hash top */
889 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
895 tdb_unlock(tdb, BUCKET(hash));
898 if (rec_ptr == 0) return null_data;
902 /* we've found a non-empty chain, now read the record */
903 if (rec_read(tdb, rec_ptr, &rec) == -1) {
907 /* allocate and read the key space */
908 ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec), rec.key_len);
909 ret.dsize = rec.key_len;
910 tdb_unlock(tdb, BUCKET(hash));
914 tdb_unlock(tdb, BUCKET(hash));
918 /* delete an entry in the database given a key */
919 int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key)
922 tdb_off offset, rec_ptr, last_ptr;
923 struct list_struct rec, lastrec;
926 /* find which hash bucket it is in */
927 hash = tdb_hash(&key);
929 tdb_lock(tdb, BUCKET(hash));
931 /* find the top of the hash chain */
932 offset = tdb_hash_top(tdb, hash);
934 /* read in the hash top */
935 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
941 /* keep looking until we find the right record */
943 if (rec_read(tdb, rec_ptr, &rec) == -1) {
947 if (hash == rec.full_hash && key.dsize == rec.key_len) {
948 /* a very likely hit - read the record and full key */
949 data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
955 if (memcmp(key.dptr, data, key.dsize) == 0) {
956 /* a definate match - delete it */
958 offset = tdb_hash_top(tdb, hash);
959 if (ofs_write(tdb, offset, &rec.next) == -1) {
963 lastrec.next = rec.next;
964 if (rec_write(tdb, last_ptr, &lastrec) == -1) {
968 tdb_unlock(tdb, BUCKET(hash));
970 /* and recover the space */
971 offset = FREELIST_TOP;
972 if (ofs_read(tdb, offset, &rec.next) == -1) {
975 rec.magic = TDB_FREE_MAGIC;
976 if (rec_write(tdb, rec_ptr, &rec) == -1) {
979 if (ofs_write(tdb, offset, &rec_ptr) == -1) {
983 /* yipee - all done */
994 /* move to the next record */
1001 if (data) free(data);
1002 tdb_unlock(tdb, BUCKET(hash));
1006 if (data) free(data);
1007 tdb_unlock(tdb, -1);
1012 /* store an element in the database, replacing any existing element
1015 return 0 on success, -1 on failure
1017 int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
1019 struct list_struct rec;
1021 tdb_off rec_ptr, offset;
1024 /* find which hash bucket it is in */
1025 hash = tdb_hash(&key);
1027 /* check for it existing */
1028 if (flag == TDB_INSERT && tdb_exists(tdb, key)) {
1032 /* first try in-place update */
1033 if (flag != TDB_INSERT && tdb_update(tdb, key, dbuf) == 0) {
1037 rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize);
1042 tdb_lock(tdb, BUCKET(hash));
1044 /* delete any existing record - if it doesn't exist we don't care */
1045 if (flag != TDB_INSERT) {
1046 tdb_delete(tdb, key);
1049 /* read the newly created record */
1050 if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec)) == -1) {
1054 if (rec.magic != TDB_FREE_MAGIC) goto fail;
1056 /* find the top of the hash chain */
1057 offset = tdb_hash_top(tdb, hash);
1059 /* read in the hash top diretcly into our next pointer */
1060 if (ofs_read(tdb, offset, &rec.next) == -1) {
1064 rec.key_len = key.dsize;
1065 rec.data_len = dbuf.dsize;
1066 rec.full_hash = hash;
1067 rec.magic = TDB_MAGIC;
1069 p = (char *)malloc(sizeof(rec) + key.dsize + dbuf.dsize);
1072 memcpy(p, &rec, sizeof(rec));
1073 memcpy(p+sizeof(rec), key.dptr, key.dsize);
1074 memcpy(p+sizeof(rec)+key.dsize, dbuf.dptr, dbuf.dsize);
1076 if (tdb_write(tdb, rec_ptr, p, sizeof(rec)+key.dsize+dbuf.dsize) == -1)
1082 /* and point the top of the hash chain at it */
1083 if (ofs_write(tdb, offset, &rec_ptr) == -1) goto fail;
1085 tdb_unlock(tdb, BUCKET(hash));
1090 printf("store failed for hash 0x%08x in bucket %u\n", hash, BUCKET(hash));
1093 tdb_unlock(tdb, BUCKET(hash));
1098 /* open the database, creating it if necessary
1100 The open_flags and mode are passed straight to the open call on the database
1101 file. A flags value of O_WRONLY is invalid
1103 The hash size is advisory, use zero for a default value.
1105 return is NULL on error
1107 TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
1108 int open_flags, mode_t mode)
1110 TDB_CONTEXT tdb, *ret;
1117 if ((open_flags & O_ACCMODE) == O_WRONLY) goto fail;
1119 if (hash_size == 0) hash_size = DEFAULT_HASH_SIZE;
1121 memset(&tdb, 0, sizeof(tdb));
1123 tdb.read_only = ((open_flags & O_ACCMODE) == O_RDONLY);
1125 tdb.fd = open(name, open_flags, mode);
1126 if (tdb.fd == -1) goto fail;
1128 /* ensure there is only one process initialising at once */
1129 tdb_brlock(&tdb, GLOBAL_LOCK, LOCK_SET, F_WRLCK, F_SETLKW);
1131 if (tdb_flags & TDB_CLEAR_IF_FIRST) {
1132 /* we need to zero the database if we are the only
1134 if (tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_SET, F_WRLCK, F_SETLK) == 0) {
1135 ftruncate(tdb.fd, 0);
1136 tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_CLEAR, F_WRLCK, F_SETLK);
1140 /* leave this lock in place */
1141 tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_SET, F_RDLCK, F_SETLKW);
1143 if (read(tdb.fd, &tdb.header, sizeof(tdb.header)) != sizeof(tdb.header) ||
1144 tdb.header.version != TDB_VERSION) {
1145 /* its not a valid database - possibly initialise it */
1146 if (!(open_flags & O_CREAT)) {
1149 if (tdb_new_database(&tdb, hash_size) == -1) goto fail;
1151 lseek(tdb.fd, 0, SEEK_SET);
1152 if (read(tdb.fd, &tdb.header, sizeof(tdb.header)) != sizeof(tdb.header)) goto fail;
1157 /* map the database and fill in the return structure */
1158 tdb.name = (char *)strdup(name);
1159 tdb.locked = (int *)calloc(tdb.header.hash_size+1,
1160 sizeof(tdb.locked[0]));
1161 if (!tdb.locked) goto fail;
1162 tdb.map_size = st.st_size;
1164 tdb.map_ptr = (void *)mmap(NULL, st.st_size,
1165 tdb.read_only? PROT_READ : PROT_READ|PROT_WRITE,
1166 MAP_SHARED | MAP_FILE, tdb.fd, 0);
1169 ret = (TDB_CONTEXT *)malloc(sizeof(tdb));
1170 if (!ret) goto fail;
1175 printf("mapped database of hash_size %u map_size=%u\n",
1176 hash_size, tdb.map_size);
1179 tdb_brlock(&tdb, GLOBAL_LOCK, LOCK_CLEAR, F_WRLCK, F_SETLKW);
1183 if (tdb.name) free(tdb.name);
1184 if (tdb.fd != -1) close(tdb.fd);
1185 if (tdb.map_ptr) munmap(tdb.map_ptr, tdb.map_size);
1190 /* close a database */
1191 int tdb_close(TDB_CONTEXT *tdb)
1193 if (!tdb) return -1;
1195 if (tdb->name) free(tdb->name);
1196 if (tdb->fd != -1) close(tdb->fd);
1197 if (tdb->map_ptr) munmap(tdb->map_ptr, tdb->map_size);
1198 if (tdb->locked) free(tdb->locked);
1200 memset(tdb, 0, sizeof(*tdb));
1206 /* lock the database. If we already have it locked then don't do anything */
1207 int tdb_writelock(TDB_CONTEXT *tdb)
1209 return tdb_lock(tdb, -1);
1212 /* unlock the database. */
1213 int tdb_writeunlock(TDB_CONTEXT *tdb)
1215 return tdb_unlock(tdb, -1);
1218 /* lock one hash chain. This is meant to be used to reduce locking
1219 contention - it cannot guarantee how many records will be locked */
1220 int tdb_lockchain(TDB_CONTEXT *tdb, TDB_DATA key)
1222 return tdb_lock(tdb, BUCKET(tdb_hash(&key)));
1226 /* unlock one hash chain */
1227 int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key)
1229 return tdb_unlock(tdb, BUCKET(tdb_hash(&key)));