1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2001-2003 Ximian Inc.
5 * Authors: Michael Zucchi <notzed@ximian.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
32 #include <sys/types.h>
35 #include <libedataserver/e-msgport.h>
37 #include "camel-block-file.h"
38 #include "camel-partition-table.h"
40 /* Do we synchronously write table updates - makes the
41 tables consistent after program crash without sync */
42 /*#define SYNC_UPDATES*/
44 #define d(x) /*(printf("%s(%d):%s: ", __FILE__, __LINE__, __PRETTY_FUNCTION__),(x))*/
46 #define k(x) /*(printf("%s(%d):%s: ", __FILE__, __LINE__, __PRETTY_FUNCTION__),(x))*/
49 struct _CamelPartitionTablePrivate {
50 pthread_mutex_t lock; /* for locking partition */
53 #define CAMEL_PARTITION_TABLE_LOCK(kf, lock) (pthread_mutex_lock(&(kf)->priv->lock))
54 #define CAMEL_PARTITION_TABLE_UNLOCK(kf, lock) (pthread_mutex_unlock(&(kf)->priv->lock))
58 camel_partition_table_class_init(CamelPartitionTableClass *klass)
63 camel_partition_table_init(CamelPartitionTable *cpi)
65 struct _CamelPartitionTablePrivate *p;
67 e_dlist_init(&cpi->partition);
69 p = cpi->priv = g_malloc0(sizeof(*cpi->priv));
70 pthread_mutex_init(&p->lock, NULL);
74 camel_partition_table_finalise(CamelPartitionTable *cpi)
77 struct _CamelPartitionTablePrivate *p;
82 while ((bl = (CamelBlock *)e_dlist_remhead(&cpi->partition))) {
83 camel_block_file_sync_block(cpi->blocks, bl);
84 camel_block_file_unref_block(cpi->blocks, bl);
86 camel_block_file_sync(cpi->blocks);
88 camel_object_unref((CamelObject *)cpi->blocks);
91 pthread_mutex_destroy(&p->lock);
98 camel_partition_table_get_type(void)
100 static CamelType type = CAMEL_INVALID_TYPE;
102 if (type == CAMEL_INVALID_TYPE) {
103 type = camel_type_register(camel_object_get_type(), "CamelPartitionTable",
104 sizeof (CamelPartitionTable),
105 sizeof (CamelPartitionTableClass),
106 (CamelObjectClassInitFunc) camel_partition_table_class_init,
108 (CamelObjectInitFunc) camel_partition_table_init,
109 (CamelObjectFinalizeFunc) camel_partition_table_finalise);
115 /* ********************************************************************** */
122 nameid is pointer to name file, includes a bit to say if name is deleted
123 wordid is a pointer to word file, includes pointer to start of word entries
125 delete a name -> set it as deleted, do nothing else though
127 lookup word, if nameid is deleted, mark it in wordlist as unused and mark for write (?)
130 /* ********************************************************************** */
132 /* This simple hash seems to work quite well */
133 static camel_hash_t hash_key(const char *key)
135 camel_hash_t hash = 0xABADF00D;
138 hash = hash * (*key) ^ (*key);
145 /* Call with lock held */
146 static CamelBlock *find_partition(CamelPartitionTable *cpi, camel_hash_t id, int *indexp)
150 CamelPartitionMapBlock *ptb;
151 CamelPartitionMap *part;
153 /* first, find the block this key might be in, then binary search the block */
154 bl = (CamelBlock *)cpi->partition.head;
156 ptb = (CamelPartitionMapBlock *)&bl->data;
157 part = ptb->partition;
158 if (ptb->used > 0 && id <= part[ptb->used-1].hashid) {
166 if (id <= part[index].hashid) {
167 if (index == 0 || id > part[index-1].hashid)
171 if (index >= ptb->used-1)
186 g_warning("could not find a partition that could fit ! partition table corrupt!");
188 /* This should never be reached */
193 CamelPartitionTable *camel_partition_table_new(struct _CamelBlockFile *bs, camel_block_t root)
195 CamelPartitionTable *cpi;
196 CamelPartitionMapBlock *ptb;
197 CamelPartitionKeyBlock *kb;
198 CamelBlock *block, *pblock;
200 cpi = (CamelPartitionTable *)camel_object_new(camel_partition_table_get_type());
203 camel_object_ref((CamelObject *)bs);
205 /* read the partition table into memory */
207 block = camel_block_file_get_block(bs, root);
211 ptb = (CamelPartitionMapBlock *)&block->data;
213 d(printf("Adding partition block, used = %d, hashid = %08x\n", ptb->used, ptb->partition[0].hashid));
215 /* if we have no data, prime initial block */
216 if (ptb->used == 0 && e_dlist_empty(&cpi->partition) && ptb->next == 0) {
217 pblock = camel_block_file_new_block(bs);
218 if (pblock == NULL) {
219 camel_block_file_unref_block(bs, block);
222 kb = (CamelPartitionKeyBlock *)&pblock->data;
225 ptb->partition[0].hashid = 0xffffffff;
226 ptb->partition[0].blockid = pblock->id;
227 camel_block_file_touch_block(bs, pblock);
228 camel_block_file_unref_block(bs, pblock);
229 camel_block_file_touch_block(bs, block);
231 camel_block_file_sync_block(bs, block);
236 camel_block_file_detach_block(bs, block);
237 e_dlist_addtail(&cpi->partition, (EDListNode *)block);
243 camel_object_unref((CamelObject *)cpi);
247 /* sync our blocks, the caller must still sync the blockfile itself */
249 camel_partition_table_sync(CamelPartitionTable *cpi)
254 CAMEL_PARTITION_TABLE_LOCK(cpi, lock);
257 bl = (CamelBlock *)cpi->partition.head;
260 ret = camel_block_file_sync_block(cpi->blocks, bl);
268 CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
273 camel_key_t camel_partition_table_lookup(CamelPartitionTable *cpi, const char *key)
275 CamelPartitionKeyBlock *pkb;
276 CamelPartitionMapBlock *ptb;
277 CamelBlock *block, *ptblock;
279 camel_key_t keyid = 0;
282 hashid = hash_key(key);
284 CAMEL_PARTITION_TABLE_LOCK(cpi, lock);
286 ptblock = find_partition(cpi, hashid, &index);
287 if (ptblock == NULL) {
288 CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
291 ptb = (CamelPartitionMapBlock *)&ptblock->data;
292 block = camel_block_file_get_block(cpi->blocks, ptb->partition[index].blockid);
294 CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
298 pkb = (CamelPartitionKeyBlock *)&block->data;
300 /* What to do about duplicate hash's? */
301 for (i=0;i<pkb->used;i++) {
302 if (pkb->keys[i].hashid == hashid) {
303 /* !! need to: lookup and compare string value */
304 /* get_key() if key == key ... */
305 keyid = pkb->keys[i].keyid;
310 CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
312 camel_block_file_unref_block(cpi->blocks, block);
317 void camel_partition_table_remove(CamelPartitionTable *cpi, const char *key)
319 CamelPartitionKeyBlock *pkb;
320 CamelPartitionMapBlock *ptb;
321 CamelBlock *block, *ptblock;
325 hashid = hash_key(key);
327 CAMEL_PARTITION_TABLE_LOCK(cpi, lock);
329 ptblock = find_partition(cpi, hashid, &index);
330 if (ptblock == NULL) {
331 CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
334 ptb = (CamelPartitionMapBlock *)&ptblock->data;
335 block = camel_block_file_get_block(cpi->blocks, ptb->partition[index].blockid);
337 CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
340 pkb = (CamelPartitionKeyBlock *)&block->data;
342 /* What to do about duplicate hash's? */
343 for (i=0;i<pkb->used;i++) {
344 if (pkb->keys[i].hashid == hashid) {
345 /* !! need to: lookup and compare string value */
346 /* get_key() if key == key ... */
348 /* remove this key */
350 for (;i<pkb->used;i++) {
351 pkb->keys[i].keyid = pkb->keys[i+1].keyid;
352 pkb->keys[i].hashid = pkb->keys[i+1].hashid;
354 camel_block_file_touch_block(cpi->blocks, block);
359 CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
361 camel_block_file_unref_block(cpi->blocks, block);
365 keys_cmp(const void *ap, const void *bp)
367 const CamelPartitionKey *a = ap;
368 const CamelPartitionKey *b = bp;
370 if (a->hashid < b->hashid)
372 else if (a->hashid > b->hashid)
379 camel_partition_table_add(CamelPartitionTable *cpi, const char *key, camel_key_t keyid)
381 camel_hash_t hashid, partid;
382 int index, newindex = 0; /* initialisation of this and pkb/nkb is just to silence compiler */
383 CamelPartitionMapBlock *ptb, *ptn;
384 CamelPartitionKeyBlock *kb, *newkb, *nkb = NULL, *pkb = NULL;
385 CamelBlock *block, *ptblock, *ptnblock;
387 struct _CamelPartitionKey keys[CAMEL_BLOCK_SIZE/4];
390 #define KEY_SIZE (sizeof(kb->keys)/sizeof(kb->keys[0]))
392 hashid = hash_key(key);
394 CAMEL_PARTITION_TABLE_LOCK(cpi, lock);
395 ptblock = find_partition(cpi, hashid, &index);
396 if (ptblock == NULL) {
397 CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
400 ptb = (CamelPartitionMapBlock *)&ptblock->data;
401 block = camel_block_file_get_block(cpi->blocks, ptb->partition[index].blockid);
403 CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
406 kb = (CamelPartitionKeyBlock *)&block->data;
408 /* TODO: Keep the key array in sorted order, cheaper lookups and split operation */
410 if (kb->used < sizeof(kb->keys)/sizeof(kb->keys[0])) {
411 /* Have room, just put it in */
412 kb->keys[kb->used].hashid = hashid;
413 kb->keys[kb->used].keyid = keyid;
416 CamelBlock *newblock = NULL, *nblock = NULL, *pblock = NULL;
418 /* Need to split? See if previous or next has room, then split across that instead */
420 /* TODO: Should look at next/previous partition table block as well ... */
423 pblock = camel_block_file_get_block(cpi->blocks, ptb->partition[index-1].blockid);
426 pkb = (CamelPartitionKeyBlock *)&pblock->data;
428 if (index < (ptb->used-1)) {
429 nblock = camel_block_file_get_block(cpi->blocks, ptb->partition[index+1].blockid);
430 if (nblock == NULL) {
432 camel_block_file_unref_block(cpi->blocks, pblock);
435 nkb = (CamelPartitionKeyBlock *)&nblock->data;
438 if (pblock && pkb->used < KEY_SIZE) {
439 if (nblock && nkb->used < KEY_SIZE) {
440 if (pkb->used < nkb->used) {
452 if (nblock && nkb->used < KEY_SIZE) {
458 /* We had no room, need to split across another block */
459 if (newblock == NULL) {
460 /* See if we have room in the partition table for this block or need to split that too */
461 if (ptb->used >= sizeof(ptb->partition)/sizeof(ptb->partition[0])) {
462 /* TODO: Could check next block to see if it'll fit there first */
463 ptnblock = camel_block_file_new_block(cpi->blocks);
464 if (ptnblock == NULL) {
466 camel_block_file_unref_block(cpi->blocks, nblock);
468 camel_block_file_unref_block(cpi->blocks, pblock);
471 camel_block_file_detach_block(cpi->blocks, ptnblock);
473 /* split block and link on-disk, always sorted */
474 ptn = (CamelPartitionMapBlock *)&ptnblock->data;
475 ptn->next = ptb->next;
476 ptb->next = ptnblock->id;
478 ptn->used = ptb->used - len;
480 memcpy(ptn->partition, &ptb->partition[len], ptn->used * sizeof(ptb->partition[0]));
483 ptnblock->next = ptblock->next;
484 ptblock->next->prev = ptnblock;
485 ptblock->next = ptnblock;
486 ptnblock->prev = ptblock;
488 /* write in right order to ensure structure */
489 camel_block_file_touch_block(cpi->blocks, ptnblock);
491 camel_block_file_sync_block(cpi->blocks, ptnblock);
494 camel_block_file_touch_block(cpi->blocks, ptblock);
496 camel_block_file_sync_block(cpi->blocks, ptblock);
504 /* try get newblock before modifying existing */
505 newblock = camel_block_file_new_block(cpi->blocks);
506 if (newblock == NULL) {
508 camel_block_file_unref_block(cpi->blocks, nblock);
510 camel_block_file_unref_block(cpi->blocks, pblock);
514 for (i=ptb->used-1;i>index;i--) {
515 ptb->partition[i+1].hashid = ptb->partition[i].hashid;
516 ptb->partition[i+1].blockid = ptb->partition[i].blockid;
520 newkb = (CamelPartitionKeyBlock *)&newblock->data;
524 ptb->partition[newindex].hashid = ptb->partition[index].hashid;
525 ptb->partition[newindex].blockid = newblock->id;
528 camel_block_file_unref_block(cpi->blocks, nblock);
530 camel_block_file_unref_block(cpi->blocks, pblock);
532 newkb = (CamelPartitionKeyBlock *)&newblock->data;
534 if (newblock == pblock) {
536 camel_block_file_unref_block(cpi->blocks, nblock);
539 camel_block_file_unref_block(cpi->blocks, pblock);
543 /* sort keys to find midpoint */
545 memcpy(keys, kb->keys, sizeof(kb->keys[0])*len);
546 memcpy(keys+len, newkb->keys, sizeof(newkb->keys[0])*newkb->used);
548 keys[len].hashid = hashid;
549 keys[len].keyid = keyid;
551 qsort(keys, len, sizeof(keys[0]), keys_cmp);
553 /* Split keys, fix partition table */
555 partid = keys[half-1].hashid;
557 if (index < newindex) {
558 memcpy(kb->keys, keys, sizeof(keys[0])*half);
560 memcpy(newkb->keys, keys+half, sizeof(keys[0])*(len-half));
561 newkb->used = len-half;
562 ptb->partition[index].hashid = partid;
564 memcpy(newkb->keys, keys, sizeof(keys[0])*half);
566 memcpy(kb->keys, keys+half, sizeof(keys[0])*(len-half));
568 ptb->partition[newindex].hashid = partid;
571 camel_block_file_touch_block(cpi->blocks, ptblock);
573 camel_block_file_sync_block(cpi->blocks, ptblock);
575 camel_block_file_touch_block(cpi->blocks, newblock);
576 camel_block_file_unref_block(cpi->blocks, newblock);
579 camel_block_file_touch_block(cpi->blocks, block);
580 camel_block_file_unref_block(cpi->blocks, block);
584 CAMEL_PARTITION_TABLE_UNLOCK(cpi, lock);
589 /* ********************************************************************** */
592 struct _CamelKeyTablePrivate {
593 pthread_mutex_t lock; /* for locking key */
596 #define CAMEL_KEY_TABLE_LOCK(kf, lock) (pthread_mutex_lock(&(kf)->priv->lock))
597 #define CAMEL_KEY_TABLE_UNLOCK(kf, lock) (pthread_mutex_unlock(&(kf)->priv->lock))
601 camel_key_table_class_init(CamelKeyTableClass *klass)
606 camel_key_table_init(CamelKeyTable *ki)
608 struct _CamelKeyTablePrivate *p;
610 p = ki->priv = g_malloc0(sizeof(*ki->priv));
611 pthread_mutex_init(&p->lock, NULL);
615 camel_key_table_finalise(CamelKeyTable *ki)
617 struct _CamelKeyTablePrivate *p;
622 if (ki->root_block) {
623 camel_block_file_sync_block(ki->blocks, ki->root_block);
624 camel_block_file_unref_block(ki->blocks, ki->root_block);
626 camel_block_file_sync(ki->blocks);
627 camel_object_unref((CamelObject *)ki->blocks);
630 pthread_mutex_destroy(&p->lock);
637 camel_key_table_get_type(void)
639 static CamelType type = CAMEL_INVALID_TYPE;
641 if (type == CAMEL_INVALID_TYPE) {
642 type = camel_type_register(camel_object_get_type(), "CamelKeyTable",
643 sizeof (CamelKeyTable),
644 sizeof (CamelKeyTableClass),
645 (CamelObjectClassInitFunc) camel_key_table_class_init,
647 (CamelObjectInitFunc) camel_key_table_init,
648 (CamelObjectFinalizeFunc) camel_key_table_finalise);
656 camel_key_table_new(CamelBlockFile *bs, camel_block_t root)
660 ki = (CamelKeyTable *)camel_object_new(camel_key_table_get_type());
663 camel_object_ref((CamelObject *)bs);
666 ki->root_block = camel_block_file_get_block(bs, ki->rootid);
667 if (ki->root_block == NULL) {
668 camel_object_unref((CamelObject *)ki);
671 camel_block_file_detach_block(bs, ki->root_block);
672 ki->root = (CamelKeyRootBlock *)&ki->root_block->data;
674 k(printf("Opening key index\n"));
675 k(printf(" first %u\n last %u\n free %u\n", ki->root->first, ki->root->last, ki->root->free));
682 camel_key_table_sync(CamelKeyTable *ki)
687 return camel_block_file_sync_block(ki->blocks, ki->root_block);
692 camel_key_table_add(CamelKeyTable *ki, const char *key, camel_block_t data, unsigned int flags)
694 CamelBlock *last, *next;
695 CamelKeyBlock *kblast, *kbnext;
698 camel_key_t keyid = 0;
700 /* Maximum key size = 128 chars */
702 if (len > CAMEL_KEY_TABLE_MAX_KEY)
705 CAMEL_KEY_TABLE_LOCK(ki, lock);
707 if (ki->root->last == 0) {
708 last = camel_block_file_new_block(ki->blocks);
711 ki->root->last = ki->root->first = last->id;
712 camel_block_file_touch_block(ki->blocks, ki->root_block);
713 k(printf("adding first block, first = %u\n", ki->root->first));
715 last = camel_block_file_get_block(ki->blocks, ki->root->last);
720 kblast = (CamelKeyBlock *)&last->data;
722 if (kblast->used >= 127)
725 if (kblast->used > 0) {
726 /*left = &kblast->u.keydata[kblast->u.keys[kblast->used-1].offset] - (char *)(&kblast->u.keys[kblast->used+1]);*/
727 left = kblast->u.keys[kblast->used-1].offset - sizeof(kblast->u.keys[0])*(kblast->used+1);
728 d(printf("key '%s' used = %d (%d), filled = %d, left = %d len = %d?\n",
729 key, kblast->used, kblast->used * sizeof(kblast->u.keys[0]),
730 sizeof(kblast->u.keydata) - kblast->u.keys[kblast->used-1].offset,
733 next = camel_block_file_new_block(ki->blocks);
735 camel_block_file_unref_block(ki->blocks, last);
738 kbnext = (CamelKeyBlock *)&next->data;
739 kblast->next = next->id;
740 ki->root->last = next->id;
741 d(printf("adding new block, first = %u, last = %u\n", ki->root->first, ki->root->last));
742 camel_block_file_touch_block(ki->blocks, ki->root_block);
743 camel_block_file_touch_block(ki->blocks, last);
744 camel_block_file_unref_block(ki->blocks, last);
750 if (kblast->used > 0)
751 offset = kblast->u.keys[kblast->used-1].offset - len;
753 offset = sizeof(kblast->u.keydata)-len;
755 kblast->u.keys[kblast->used].flags = flags;
756 kblast->u.keys[kblast->used].data = data;
757 kblast->u.keys[kblast->used].offset = offset;
758 memcpy(kblast->u.keydata + offset, key, len);
760 keyid = (last->id & (~(CAMEL_BLOCK_SIZE-1))) | kblast->used;
764 g_assert(kblast->used < 127);
766 camel_block_file_touch_block(ki->blocks, last);
767 camel_block_file_unref_block(ki->blocks, last);
770 camel_block_file_sync_block(ki->blocks, ki->root_block);
773 CAMEL_KEY_TABLE_UNLOCK(ki, lock);
779 camel_key_table_set_data(CamelKeyTable *ki, camel_key_t keyid, camel_block_t data)
782 camel_block_t blockid;
789 blockid = keyid & (~(CAMEL_BLOCK_SIZE-1));
790 index = keyid & (CAMEL_BLOCK_SIZE-1);
792 bl = camel_block_file_get_block(ki->blocks, blockid);
795 kb = (CamelKeyBlock *)&bl->data;
797 CAMEL_KEY_TABLE_LOCK(ki, lock);
799 if (kb->u.keys[index].data != data) {
800 kb->u.keys[index].data = data;
801 camel_block_file_touch_block(ki->blocks, bl);
804 CAMEL_KEY_TABLE_UNLOCK(ki, lock);
806 camel_block_file_unref_block(ki->blocks, bl);
810 camel_key_table_set_flags(CamelKeyTable *ki, camel_key_t keyid, unsigned int flags, unsigned int set)
813 camel_block_t blockid;
821 blockid = keyid & (~(CAMEL_BLOCK_SIZE-1));
822 index = keyid & (CAMEL_BLOCK_SIZE-1);
824 bl = camel_block_file_get_block(ki->blocks, blockid);
827 kb = (CamelKeyBlock *)&bl->data;
829 g_assert(kb->used < 127);
830 g_assert(index < kb->used);
832 CAMEL_KEY_TABLE_LOCK(ki, lock);
834 old = kb->u.keys[index].flags;
835 if ((old & set) != (flags & set)) {
836 kb->u.keys[index].flags = (old & (~set)) | (flags & set);
837 camel_block_file_touch_block(ki->blocks, bl);
840 CAMEL_KEY_TABLE_UNLOCK(ki, lock);
842 camel_block_file_unref_block(ki->blocks, bl);
846 camel_key_table_lookup(CamelKeyTable *ki, camel_key_t keyid, char **keyp, unsigned int *flags)
849 camel_block_t blockid;
861 blockid = keyid & (~(CAMEL_BLOCK_SIZE-1));
862 index = keyid & (CAMEL_BLOCK_SIZE-1);
864 bl = camel_block_file_get_block(ki->blocks, blockid);
868 kb = (CamelKeyBlock *)&bl->data;
871 g_assert(kb->used < 127); /* this should be more accurate */
872 g_assert(index < kb->used);
874 if (kb->used >=127 || index >= kb->used) {
875 g_warning("Block %x: Invalid index or content: index %d used %d\n", blockid, index, kb->used);
880 CAMEL_KEY_TABLE_LOCK(ki, lock);
882 blockid = kb->u.keys[index].data;
884 *flags = kb->u.keys[index].flags;
887 off = kb->u.keys[index].offset;
889 len = sizeof(kb->u.keydata) - off;
891 len = kb->u.keys[index-1].offset - off;
892 *keyp = key = g_malloc(len+1);
893 memcpy(key, kb->u.keydata + off, len);
897 CAMEL_KEY_TABLE_UNLOCK(ki, lock);
899 camel_block_file_unref_block(ki->blocks, bl);
904 /* iterate through all keys */
906 camel_key_table_next(CamelKeyTable *ki, camel_key_t next, char **keyp, unsigned int *flagsp, camel_block_t *datap)
910 camel_block_t blockid;
920 CAMEL_KEY_TABLE_LOCK(ki, lock);
923 next = ki->root->first;
925 CAMEL_KEY_TABLE_UNLOCK(ki, lock);
932 blockid = next & (~(CAMEL_BLOCK_SIZE-1));
933 index = next & (CAMEL_BLOCK_SIZE-1);
935 bl = camel_block_file_get_block(ki->blocks, blockid);
937 CAMEL_KEY_TABLE_UNLOCK(ki, lock);
941 kb = (CamelKeyBlock *)&bl->data;
943 /* see if we need to goto the next block */
944 if (index >= kb->used) {
945 /* FIXME: check for loops */
947 camel_block_file_unref_block(ki->blocks, bl);
950 } while (bl == NULL);
952 /* invalid block data */
953 if ((kb->u.keys[index].offset >= sizeof(kb->u.keydata)
954 /*|| kb->u.keys[index].offset < kb->u.keydata - (char *)&kb->u.keys[kb->used])*/
955 || kb->u.keys[index].offset < sizeof(kb->u.keys[0]) * kb->used
957 (kb->u.keys[index-1].offset >= sizeof(kb->u.keydata)
958 /*|| kb->u.keys[index-1].offset < kb->u.keydata - (char *)&kb->u.keys[kb->used]))) {*/
959 || kb->u.keys[index-1].offset < sizeof(kb->u.keys[0]) * kb->used)))) {
960 g_warning("Block %u invalid scanning keys", bl->id);
961 camel_block_file_unref_block(ki->blocks, bl);
962 CAMEL_KEY_TABLE_UNLOCK(ki, lock);
967 *datap = kb->u.keys[index].data;
970 *flagsp = kb->u.keys[index].flags;
973 int len, off = kb->u.keys[index].offset;
977 len = sizeof(kb->u.keydata) - off;
979 len = kb->u.keys[index-1].offset - off;
980 *keyp = key = g_malloc(len+1);
981 memcpy(key, kb->u.keydata + off, len);
985 CAMEL_KEY_TABLE_UNLOCK(ki, lock);
987 camel_block_file_unref_block(ki->blocks, bl);
992 /* ********************************************************************** */