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 128
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)
61 /* the body of the database is made of one list_struct for the free space
62 plus a separate data list for each hash value */
64 tdb_len rec_len; /* total byte length of record */
65 tdb_off next; /* offset of the next record in the list */
66 tdb_len key_len; /* byte length of key */
67 tdb_len data_len; /* byte length of data */
68 unsigned full_hash; /* the full 32 bit hash of the key */
69 unsigned magic; /* try to catch errors */
71 the following union is implied
82 /* a null data record - useful for error returns */
83 static TDB_DATA null_data;
85 /* a byte range locking function - return 0 on success
86 this functions locks/unlocks 1 byte at the specified offset */
87 static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
88 int set, int rw_type, int lck_type)
95 if (tdb->read_only) return -1;
97 fl.l_type = set==LOCK_SET?rw_type:F_UNLCK;
98 fl.l_whence = SEEK_SET;
103 if (fcntl(tdb->fd, lck_type, &fl) != 0) {
105 if (lck_type == F_SETLKW) {
106 printf("lock %d failed at %d (%s)\n",
107 set, offset, strerror(errno));
110 tdb->ecode = TDB_ERR_LOCK;
117 /* lock a list in the database. list -1 is the alloc list */
118 static int tdb_lock(TDB_CONTEXT *tdb, int list)
120 if (list < -1 || list >= (int)tdb->header.hash_size) {
122 printf("bad list %d\n", list);
126 if (tdb->locked[list+1] == 0) {
127 if (tdb_brlock(tdb, LIST_LOCK_BASE + 4*list, LOCK_SET,
128 F_WRLCK, F_SETLKW) != 0) {
132 tdb->locked[list+1]++;
136 /* unlock the database. */
137 static int tdb_unlock(TDB_CONTEXT *tdb, int list)
139 if (list < -1 || list >= (int)tdb->header.hash_size) {
141 printf("bad unlock list %d\n", list);
146 if (tdb->locked[list+1] == 0) {
148 printf("not locked %d\n", list);
150 tdb->ecode = TDB_ERR_LOCK;
153 if (tdb->locked[list+1] == 1) {
154 if (tdb_brlock(tdb, LIST_LOCK_BASE + 4*list, LOCK_CLEAR,
155 F_WRLCK, F_SETLKW) != 0) {
159 tdb->locked[list+1]--;
163 /* the hash algorithm - turn a key into an integer
164 This is based on the hash agorithm from gdbm */
165 static unsigned tdb_hash(TDB_DATA *key)
167 unsigned value; /* Used to compute the hash value. */
168 unsigned i; /* Used to cycle through random values. */
170 /* Set the initial value from the key size. */
171 value = 0x238F13AF * key->dsize;
172 for (i=0; i < key->dsize; i++) {
173 value = (value + (key->dptr[i] << (i*5 % 24)));
176 value = (1103515243 * value + 12345);
181 /* find the top of the hash chain for an open database */
182 static tdb_off tdb_hash_top(TDB_CONTEXT *tdb, unsigned hash)
186 ret = FREELIST_TOP + (hash+1)*sizeof(tdb_off);
191 /* check for an out of bounds access - if it is out of bounds then
192 see if the database has been expanded by someone else and expand
194 static int tdb_oob(TDB_CONTEXT *tdb, tdb_off offset)
197 if (offset <= tdb->map_size) return 0;
200 if (st.st_size <= (ssize_t)offset) {
201 tdb->ecode = TDB_ERR_IO;
207 munmap(tdb->map_ptr, tdb->map_size);
212 tdb->map_size = st.st_size;
214 tdb->map_ptr = (void *)mmap(NULL, tdb->map_size,
215 tdb->read_only?PROT_READ:PROT_READ|PROT_WRITE,
216 MAP_SHARED | MAP_FILE, tdb->fd, 0);
222 /* write a lump of data at a specified offset */
223 static int tdb_write(TDB_CONTEXT *tdb, tdb_off offset, const char *buf, tdb_len len)
225 if (tdb_oob(tdb, offset + len) != 0) {
226 /* oops - trying to write beyond the end of the database! */
231 memcpy(offset + (char *)tdb->map_ptr, buf, len);
233 if (lseek(tdb->fd, offset, SEEK_SET) != offset ||
234 write(tdb->fd, buf, len) != (ssize_t)len) {
235 tdb->ecode = TDB_ERR_IO;
242 /* read a lump of data at a specified offset */
243 static int tdb_read(TDB_CONTEXT *tdb, tdb_off offset, char *buf, tdb_len len)
245 if (tdb_oob(tdb, offset + len) != 0) {
246 /* oops - trying to read beyond the end of the database! */
251 memcpy(buf, offset + (char *)tdb->map_ptr, len);
253 if (lseek(tdb->fd, offset, SEEK_SET) != offset ||
254 read(tdb->fd, buf, len) != (ssize_t)len) {
255 tdb->ecode = TDB_ERR_IO;
263 /* read a lump of data, allocating the space for it */
264 static char *tdb_alloc_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_len len)
268 buf = (char *)malloc(len);
271 tdb->ecode = TDB_ERR_OOM;
275 if (tdb_read(tdb, offset, buf, len) == -1) {
283 /* convenience routine for writing a record */
284 static int rec_write(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
286 return tdb_write(tdb, offset, (char *)rec, sizeof(*rec));
289 /* convenience routine for writing a tdb_off */
290 static int ofs_write(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
292 return tdb_write(tdb, offset, (char *)d, sizeof(*d));
295 /* read a tdb_off from the store */
296 static int ofs_read(TDB_CONTEXT *tdb, tdb_off offset, tdb_off *d)
298 return tdb_read(tdb, offset, (char *)d, sizeof(*d));
301 /* read a record and check for simple errors */
302 static int rec_read(TDB_CONTEXT *tdb, tdb_off offset, struct list_struct *rec)
304 if (tdb_read(tdb, offset, (char *)rec, sizeof(*rec)) == -1) return -1;
305 if (rec->magic != TDB_MAGIC) {
307 printf("bad magic 0x%08x at offset %d\n",
310 tdb->ecode = TDB_ERR_CORRUPT;
313 if (tdb_oob(tdb, rec->next) != 0) {
319 /* expand the database at least length bytes by expanding the
320 underlying file and doing the mmap again if necessary */
321 static int tdb_expand(TDB_CONTEXT *tdb, tdb_off length)
323 struct list_struct rec;
329 /* make sure we know about any previous expansions by another
331 tdb_oob(tdb,tdb->map_size + 1);
333 /* always make room for at least 10 more records */
334 length *= TDB_LEN_MULTIPLIER;
336 /* and round the database up to a multiple of TDB_PAGE_SIZE */
337 length = ((tdb->map_size + length + TDB_PAGE_SIZE) & ~(TDB_PAGE_SIZE - 1)) - tdb->map_size;
339 /* expand the file itself */
340 lseek(tdb->fd, tdb->map_size + length - 1, SEEK_SET);
341 if (write(tdb->fd, &b, 1) != 1) goto fail;
343 /* form a new freelist record */
344 offset = FREELIST_TOP;
345 rec.rec_len = length - sizeof(rec);
346 rec.magic = TDB_FREE_MAGIC;
347 if (ofs_read(tdb, offset, &rec.next) == -1) {
353 munmap(tdb->map_ptr, tdb->map_size);
358 tdb->map_size += length;
361 if (rec_write(tdb, tdb->map_size - length, &rec) == -1) {
365 /* link it into the free list */
366 ptr = tdb->map_size - length;
367 if (ofs_write(tdb, offset, &ptr) == -1) goto fail;
370 tdb->map_ptr = (void *)mmap(NULL, tdb->map_size,
371 PROT_READ|PROT_WRITE,
372 MAP_SHARED | MAP_FILE, tdb->fd, 0);
382 /* allocate some space from the free list. The offset returned points
383 to a unconnected list_struct within the database with room for at
384 least length bytes of total data
386 0 is returned if the space could not be allocated
388 static tdb_off tdb_allocate(TDB_CONTEXT *tdb, tdb_len length)
390 tdb_off offset, rec_ptr, last_ptr;
391 struct list_struct rec, lastrec, newrec;
397 offset = FREELIST_TOP;
399 /* read in the freelist top */
400 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
404 /* keep looking until we find a freelist record that is big
407 if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec)) == -1) {
411 if (rec.magic != TDB_FREE_MAGIC) {
413 printf("bad magic 0x%08x in free list\n", rec.magic);
418 if (rec.rec_len >= length) {
419 /* found it - now possibly split it up */
420 if (rec.rec_len > length + MIN_REC_SIZE) {
421 length = (length + TDB_ALIGN) & ~(TDB_ALIGN-1);
423 newrec.rec_len = rec.rec_len - (sizeof(rec) + length);
424 newrec.next = rec.next;
425 newrec.magic = TDB_FREE_MAGIC;
427 rec.rec_len = length;
428 rec.next = rec_ptr + sizeof(rec) + rec.rec_len;
430 if (rec_write(tdb, rec.next, &newrec) == -1) {
434 if (rec_write(tdb, rec_ptr, &rec) == -1) {
439 /* remove it from the list */
441 offset = FREELIST_TOP;
443 if (ofs_write(tdb, offset, &rec.next) == -1) {
447 lastrec.next = rec.next;
448 if (rec_write(tdb, last_ptr, &lastrec) == -1) {
453 /* all done - return the new record offset */
458 /* move to the next record */
464 /* we didn't find enough space. See if we can expand the
465 database and if we can then try again */
466 if (tdb_expand(tdb, length + sizeof(rec)) == 0) goto again;
470 printf("tdb_allocate failed for size %u\n", length);
476 /* initialise a new database with a specified hash size */
477 static int tdb_new_database(TDB_CONTEXT *tdb, int hash_size)
479 struct tdb_header header;
484 /* create the header */
485 memset(&header, 0, sizeof(header));
486 memcpy(header.magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1);
487 header.version = TDB_VERSION;
488 header.hash_size = hash_size;
489 lseek(tdb->fd, 0, SEEK_SET);
490 ftruncate(tdb->fd, 0);
492 if (write(tdb->fd, &header, sizeof(header)) != sizeof(header)) {
493 tdb->ecode = TDB_ERR_IO;
497 /* the freelist and hash pointers */
499 memset(buf, 0, sizeof(buf));
500 for (i=0;(hash_size+1)-i >= 16; i += 16) {
501 if (write(tdb->fd, buf, sizeof(buf)) != sizeof(buf)) {
502 tdb->ecode = TDB_ERR_IO;
506 for (;i<hash_size+1; i++) {
507 if (write(tdb->fd, buf, sizeof(tdb_off)) != sizeof(tdb_off)) {
508 tdb->ecode = TDB_ERR_IO;
514 printf("initialised database of hash_size %u\n",
520 /* Returns 0 on fail. On success, return offset of record, and fills
522 static tdb_off tdb_find(TDB_CONTEXT *tdb, TDB_DATA key, unsigned int hash,
523 struct list_struct *rec)
525 tdb_off offset, rec_ptr;
527 /* find the top of the hash chain */
528 offset = tdb_hash_top(tdb, hash);
530 /* read in the hash top */
531 if (ofs_read(tdb, offset, &rec_ptr) == -1)
534 /* keep looking until we find the right record */
536 if (rec_read(tdb, rec_ptr, rec) == -1)
539 if (hash == rec->full_hash && key.dsize == rec->key_len) {
541 /* a very likely hit - read the key */
542 k = tdb_alloc_read(tdb, rec_ptr + sizeof(*rec),
548 if (memcmp(key.dptr, k, key.dsize) == 0) {
555 /* move to the next record */
562 return an error string for the last tdb error
564 char *tdb_error(TDB_CONTEXT *tdb)
568 enum TDB_ERROR ecode;
571 {TDB_SUCCESS, "Success"},
572 {TDB_ERR_CORRUPT, "Corrupt database"},
573 {TDB_ERR_IO, "IO Error"},
574 {TDB_ERR_LOCK, "Locking error"},
575 {TDB_ERR_OOM, "Out of memory"},
576 {TDB_ERR_EXISTS, "Record exists"},
579 for (i=0;emap[i].estring;i++) {
580 if (tdb->ecode == emap[i].ecode) return emap[i].estring;
583 return "Invalid tdb context";
585 return "Invalid error code";
589 /* update an entry in place - this only works if the new data size
590 is <= the old data size and the key exists.
593 int tdb_update(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf)
596 struct list_struct rec;
600 /* find which hash bucket it is in */
601 hash = tdb_hash(&key);
603 tdb_lock(tdb, BUCKET(hash));
604 rec_ptr = tdb_find(tdb, key, hash, &rec);
609 /* must be long enough */
610 if (rec.rec_len < key.dsize + dbuf.dsize)
613 if (tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
614 dbuf.dptr, dbuf.dsize) == -1)
617 if (dbuf.dsize != rec.data_len) {
619 rec.data_len = dbuf.dsize;
620 ret = rec_write(tdb, rec_ptr, &rec);
625 tdb_unlock(tdb, BUCKET(hash));
629 /* find an entry in the database given a key */
630 TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key)
634 struct list_struct rec;
635 TDB_DATA ret = null_data;
637 /* find which hash bucket it is in */
638 hash = tdb_hash(&key);
640 tdb_lock(tdb, BUCKET(hash));
641 rec_ptr = tdb_find(tdb, key, hash, &rec);
644 ret.dptr = tdb_alloc_read(tdb,
645 rec_ptr + sizeof(rec) + rec.key_len,
647 ret.dsize = rec.data_len;
650 tdb_unlock(tdb, BUCKET(hash));
654 /* check if an entry in the database exists
656 note that 1 is returned if the key is found and 0 is returned if not found
657 this doesn't match the conventions in the rest of this module, but is
660 int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key)
664 struct list_struct rec;
666 /* find which hash bucket it is in */
667 hash = tdb_hash(&key);
669 tdb_lock(tdb, BUCKET(hash));
670 rec_ptr = tdb_find(tdb, key, hash, &rec);
671 tdb_unlock(tdb, BUCKET(hash));
676 /* traverse the entire database - calling fn(tdb, key, data) on each element.
677 return -1 on error or the record count traversed
678 if fn is NULL then it is not called
679 a non-zero return value from fn() indicates that the traversal should stop
681 int tdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void* state), void* state)
685 tdb_off offset, rec_ptr;
686 struct list_struct rec;
690 /* loop over all hash chains */
691 for (h = 0; h < tdb->header.hash_size; h++) {
692 tdb_lock(tdb, BUCKET(h));
694 /* read in the hash top */
695 offset = tdb_hash_top(tdb, h);
696 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
700 /* traverse all records for this hash */
702 if (rec_read(tdb, rec_ptr, &rec) == -1) {
706 /* now read the full record */
707 data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
708 rec.key_len + rec.data_len);
714 key.dsize = rec.key_len;
715 dbuf.dptr = data + rec.key_len;
716 dbuf.dsize = rec.data_len;
719 if (fn && fn(tdb, key, dbuf, state) != 0) {
720 /* they want us to stop traversing */
722 tdb_unlock(tdb, BUCKET(h));
729 /* move to the next record */
732 tdb_unlock(tdb, BUCKET(h));
735 /* return the number traversed */
739 tdb_unlock(tdb, BUCKET(h));
744 /* find the first entry in the database and return its key */
745 TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb)
747 tdb_off offset, rec_ptr;
748 struct list_struct rec;
752 /* look for a non-empty hash chain */
753 for (hash = 0, rec_ptr = 0;
754 hash < tdb->header.hash_size;
756 /* find the top of the hash chain */
757 offset = tdb_hash_top(tdb, hash);
759 tdb_lock(tdb, BUCKET(hash));
761 /* read in the hash top */
762 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
768 tdb_unlock(tdb, BUCKET(hash));
771 if (rec_ptr == 0) return null_data;
773 /* we've found a non-empty chain, now read the record */
774 if (rec_read(tdb, rec_ptr, &rec) == -1) {
778 /* allocate and read the key space */
779 ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec), rec.key_len);
780 ret.dsize = rec.key_len;
781 tdb_unlock(tdb, BUCKET(hash));
785 tdb_unlock(tdb, BUCKET(hash));
789 /* find the next entry in the database, returning its key */
790 TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key)
792 unsigned hash, hbucket;
793 tdb_off rec_ptr, offset;
794 struct list_struct rec;
797 /* find which hash bucket it is in */
798 hash = tdb_hash(&key);
799 hbucket = BUCKET(hash);
801 tdb_lock(tdb, hbucket);
802 rec_ptr = tdb_find(tdb, key, hash, &rec);
804 /* we want the next record after this one */
808 /* not found or last in hash: look for next non-empty hash chain */
809 while (rec_ptr == 0) {
810 tdb_unlock(tdb, hbucket);
812 if (++hbucket >= tdb->header.hash_size - 1)
815 offset = tdb_hash_top(tdb, hbucket);
816 tdb_lock(tdb, hbucket);
817 /* read in the hash top */
818 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
819 tdb_unlock(tdb, hbucket);
824 /* Read the record. */
825 if (rec_read(tdb, rec_ptr, &rec) == -1) {
826 tdb_unlock(tdb, hbucket);
829 /* allocate and read the key */
830 ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec), rec.key_len);
831 ret.dsize = rec.key_len;
832 tdb_unlock(tdb, hbucket);
837 /* delete an entry in the database given a key */
838 int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key)
841 tdb_off offset, rec_ptr, last_ptr;
842 struct list_struct rec, lastrec;
845 /* find which hash bucket it is in */
846 hash = tdb_hash(&key);
848 tdb_lock(tdb, BUCKET(hash));
850 /* find the top of the hash chain */
851 offset = tdb_hash_top(tdb, hash);
853 /* read in the hash top */
854 if (ofs_read(tdb, offset, &rec_ptr) == -1) {
860 /* keep looking until we find the right record */
862 if (rec_read(tdb, rec_ptr, &rec) == -1) {
866 if (hash == rec.full_hash && key.dsize == rec.key_len) {
867 /* a very likely hit - read the record and full key */
868 data = tdb_alloc_read(tdb, rec_ptr + sizeof(rec),
874 if (memcmp(key.dptr, data, key.dsize) == 0) {
875 /* a definite match - delete it */
877 offset = tdb_hash_top(tdb, hash);
878 if (ofs_write(tdb, offset, &rec.next) == -1) {
882 lastrec.next = rec.next;
883 if (rec_write(tdb, last_ptr, &lastrec) == -1) {
887 tdb_unlock(tdb, BUCKET(hash));
889 /* and recover the space */
890 offset = FREELIST_TOP;
891 if (ofs_read(tdb, offset, &rec.next) == -1) {
894 rec.magic = TDB_FREE_MAGIC;
895 if (rec_write(tdb, rec_ptr, &rec) == -1) {
898 if (ofs_write(tdb, offset, &rec_ptr) == -1) {
902 /* yipee - all done */
913 /* move to the next record */
920 if (data) free(data);
921 tdb_unlock(tdb, BUCKET(hash));
925 if (data) free(data);
931 /* store an element in the database, replacing any existing element
934 return 0 on success, -1 on failure
936 int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
938 struct list_struct rec;
940 tdb_off rec_ptr, offset;
943 /* find which hash bucket it is in */
944 hash = tdb_hash(&key);
946 /* check for it existing */
947 if (flag == TDB_INSERT && tdb_exists(tdb, key)) {
948 tdb->ecode = TDB_ERR_EXISTS;
952 /* first try in-place update */
953 if (flag != TDB_INSERT && tdb_update(tdb, key, dbuf) == 0) {
957 rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize);
962 tdb_lock(tdb, BUCKET(hash));
964 /* delete any existing record - if it doesn't exist we don't care */
965 if (flag != TDB_INSERT) {
966 tdb_delete(tdb, key);
969 /* read the newly created record */
970 if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec)) == -1) {
974 if (rec.magic != TDB_FREE_MAGIC) goto fail;
976 /* find the top of the hash chain */
977 offset = tdb_hash_top(tdb, hash);
979 /* read in the hash top diretcly into our next pointer */
980 if (ofs_read(tdb, offset, &rec.next) == -1) {
984 rec.key_len = key.dsize;
985 rec.data_len = dbuf.dsize;
986 rec.full_hash = hash;
987 rec.magic = TDB_MAGIC;
989 p = (char *)malloc(sizeof(rec) + key.dsize + dbuf.dsize);
991 tdb->ecode = TDB_ERR_OOM;
995 memcpy(p, &rec, sizeof(rec));
996 memcpy(p+sizeof(rec), key.dptr, key.dsize);
997 memcpy(p+sizeof(rec)+key.dsize, dbuf.dptr, dbuf.dsize);
999 if (tdb_write(tdb, rec_ptr, p, sizeof(rec)+key.dsize+dbuf.dsize) == -1)
1005 /* and point the top of the hash chain at it */
1006 if (ofs_write(tdb, offset, &rec_ptr) == -1) goto fail;
1008 tdb_unlock(tdb, BUCKET(hash));
1013 printf("store failed for hash 0x%08x in bucket %u\n", hash, BUCKET(hash));
1016 tdb_unlock(tdb, BUCKET(hash));
1021 /* open the database, creating it if necessary
1023 The open_flags and mode are passed straight to the open call on the database
1024 file. A flags value of O_WRONLY is invalid
1026 The hash size is advisory, use zero for a default value.
1028 return is NULL on error
1030 TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
1031 int open_flags, mode_t mode)
1033 TDB_CONTEXT tdb, *ret;
1040 if ((open_flags & O_ACCMODE) == O_WRONLY) {
1044 if (hash_size == 0) hash_size = DEFAULT_HASH_SIZE;
1046 memset(&tdb, 0, sizeof(tdb));
1048 tdb.read_only = ((open_flags & O_ACCMODE) == O_RDONLY);
1050 tdb.fd = open(name, open_flags, mode);
1055 /* ensure there is only one process initialising at once */
1056 tdb_brlock(&tdb, GLOBAL_LOCK, LOCK_SET, F_WRLCK, F_SETLKW);
1058 if (tdb_flags & TDB_CLEAR_IF_FIRST) {
1059 /* we need to zero the database if we are the only
1061 if (tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_SET, F_WRLCK, F_SETLK) == 0) {
1062 ftruncate(tdb.fd, 0);
1063 tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_CLEAR, F_WRLCK, F_SETLK);
1067 /* leave this lock in place */
1068 tdb_brlock(&tdb, ACTIVE_LOCK, LOCK_SET, F_RDLCK, F_SETLKW);
1070 if (read(tdb.fd, &tdb.header, sizeof(tdb.header)) != sizeof(tdb.header) ||
1071 strcmp(tdb.header.magic_food, TDB_MAGIC_FOOD) != 0 ||
1072 tdb.header.version != TDB_VERSION) {
1073 /* its not a valid database - possibly initialise it */
1074 if (!(open_flags & O_CREAT)) {
1077 if (tdb_new_database(&tdb, hash_size) == -1) goto fail;
1079 lseek(tdb.fd, 0, SEEK_SET);
1080 if (read(tdb.fd, &tdb.header, sizeof(tdb.header)) != sizeof(tdb.header)) goto fail;
1085 /* map the database and fill in the return structure */
1086 tdb.name = (char *)strdup(name);
1087 tdb.locked = (int *)calloc(tdb.header.hash_size+1,
1088 sizeof(tdb.locked[0]));
1092 tdb.map_size = st.st_size;
1094 tdb.map_ptr = (void *)mmap(NULL, st.st_size,
1095 tdb.read_only? PROT_READ : PROT_READ|PROT_WRITE,
1096 MAP_SHARED | MAP_FILE, tdb.fd, 0);
1099 ret = (TDB_CONTEXT *)malloc(sizeof(tdb));
1100 if (!ret) goto fail;
1105 printf("mapped database of hash_size %u map_size=%u\n",
1106 hash_size, tdb.map_size);
1109 tdb_brlock(&tdb, GLOBAL_LOCK, LOCK_CLEAR, F_WRLCK, F_SETLKW);
1113 if (tdb.name) free(tdb.name);
1114 if (tdb.fd != -1) close(tdb.fd);
1115 if (tdb.map_ptr) munmap(tdb.map_ptr, tdb.map_size);
1120 /* close a database */
1121 int tdb_close(TDB_CONTEXT *tdb)
1123 if (!tdb) return -1;
1125 if (tdb->name) free(tdb->name);
1126 if (tdb->fd != -1) close(tdb->fd);
1127 if (tdb->map_ptr) munmap(tdb->map_ptr, tdb->map_size);
1128 if (tdb->locked) free(tdb->locked);
1130 memset(tdb, 0, sizeof(*tdb));
1136 /* lock the database. If we already have it locked then don't do anything */
1137 int tdb_writelock(TDB_CONTEXT *tdb)
1139 return tdb_lock(tdb, -1);
1142 /* unlock the database. */
1143 int tdb_writeunlock(TDB_CONTEXT *tdb)
1145 return tdb_unlock(tdb, -1);
1148 /* lock one hash chain. This is meant to be used to reduce locking
1149 contention - it cannot guarantee how many records will be locked */
1150 int tdb_lockchain(TDB_CONTEXT *tdb, TDB_DATA key)
1152 return tdb_lock(tdb, BUCKET(tdb_hash(&key)));
1156 /* unlock one hash chain */
1157 int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key)
1159 return tdb_unlock(tdb, BUCKET(tdb_hash(&key)));