Ejemplo n.º 1
0
static void
remove_storage_ref_info(struct mailengine * engine,
                        struct mailstorage * storage)
{
    chashdatum key;
    chashdatum data;
    struct storage_ref_info * ref_info;

    key.data = &storage;
    key.len = sizeof(storage);

#ifdef LIBETPAN_REENTRANT
    pthread_mutex_lock(&engine->storage_hash_lock);
#endif

    chash_get(engine->storage_hash, &key, &data);
    ref_info = data.data;

    if (ref_info != NULL) {
        storage_ref_info_free(ref_info);

        chash_delete(engine->storage_hash, &key, NULL);
    }

#ifdef LIBETPAN_REENTRANT
    pthread_mutex_unlock(&engine->storage_hash_lock);
#endif
}
Ejemplo n.º 2
0
void mailprivacy_smime_encryption_id_list_clear(struct mailprivacy * privacy,
    mailmessage * msg)
{
  clist * encryption_id_list;
  clistiter * iter;
  
  LOCK();
  encryption_id_list = get_list(privacy, msg);
  if (encryption_id_list != NULL) {
    chashdatum key;
    
    for(iter = clist_begin(encryption_id_list) ;
        iter != NULL ; iter = clist_next(iter)) {
      char * str;
      
      str = clist_content(iter);
      free(str);
    }
    clist_free(encryption_id_list);
    
    key.data = &msg;
    key.len = sizeof(msg);
    chash_delete(encryption_id_hash, &key, NULL);
    
    if (chash_count(encryption_id_hash) == 0) {
      chash_free(encryption_id_hash);
      encryption_id_hash = NULL;
    }
  }
  UNLOCK();
}
Ejemplo n.º 3
0
static void unregister_message(struct mailprivacy * privacy,
    mailmessage * msg)
{
  chashdatum key;
  
  key.data = &msg;
  key.len = sizeof(msg);
  
  chash_delete(privacy->msg_ref, &key, NULL);
}
Ejemplo n.º 4
0
static void unregister_mime(struct mailprivacy * privacy,
    struct mailmime * mime)
{
  chashdatum key;
  
  key.data = &mime;
  key.len = sizeof(mime);
  
  chash_delete(privacy->mime_ref, &key, NULL);
}
Ejemplo n.º 5
0
static void folder_message_remove(struct folder_ref_info * ref_info,
                                  mailmessage * msg)
{
    chashdatum key;
    struct message_ref_elt * msg_ref;

    if (msg->msg_uid != NULL) {
        key.data = msg->msg_uid;
        key.len = strlen(msg->msg_uid);

        chash_delete(ref_info->uid_hash, &key, NULL);
    }

    msg_ref = folder_info_get_msg_ref(ref_info, msg);
    message_ref_elt_free(msg_ref);

    key.data = &msg;
    key.len = sizeof(msg);

    chash_delete(ref_info->msg_hash, &key, NULL);
}
Ejemplo n.º 6
0
static void unregister_result_mmapstr(struct mailprivacy * privacy,
    char * str)
{
  chashdatum key;
  
  mmap_string_unref(str);
  
  key.data = &str;
  key.len = sizeof(str);
  
  chash_delete(privacy->mmapstr, &key, NULL);
}
Ejemplo n.º 7
0
void stem_cache_delete(struct stem_cache *cache) {
    unsigned int i;

    for (i = 0; i < cache->size; i++) {
        free(cache->arr[i]->src);
        free(cache->arr[i]->dst);
        free(cache->arr[i]);
    }

    chash_delete(cache->lookup);
    free(cache->arr);
    free(cache);
}
Ejemplo n.º 8
0
int mmap_string_unref(char * str)
{
  MMAPString * string;
  chash * ht;
  chashdatum key;
  chashdatum data;
  int r;

  if (str == NULL)
    return -1;
  
  MUTEX_LOCK(&mmapstring_lock);

  ht = mmapstring_hashtable;
  
  if (ht == NULL) {

	MUTEX_UNLOCK(&mmapstring_lock);
    return -1;
  }
  
  key.data = &str;
  key.len = sizeof(str);

  r = chash_get(ht, &key, &data);
  if (r < 0)
    string = NULL;
  else
    string = data.data;
  
  if (string != NULL) {
    chash_delete(ht, &key, NULL);
    if (chash_count(ht) == 0) {
      chash_free(ht);
      mmapstring_hashtable = NULL;
    }
  }
  
  MUTEX_UNLOCK(&mmapstring_lock);

  if (string != NULL) {
    mmap_string_free(string);
    return 0;
  }
  else
    return -1;
}
Ejemplo n.º 9
0
static void delete_nntp(Folder *folder, newsnntp *nntp)
{
	chashdatum key;

	key.data = &folder;
	key.len = sizeof(folder);
	chash_delete(session_hash, &key, NULL);
	
	key.data = &nntp;
	key.len = sizeof(nntp);
	if (nntp && nntp->nntp_stream) {
		/* we don't want libetpan to logout */
		mailstream_close(nntp->nntp_stream);
		nntp->nntp_stream = NULL;
	}
	debug_print("removing newsnntp %p\n", nntp);
	newsnntp_free(nntp);	
}
Ejemplo n.º 10
0
void mail_flags_store_clear(struct mail_flags_store * flags_store)
{
  unsigned int i;

  for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) {
    chashdatum key;
    mailmessage * msg;

    msg = carray_get(flags_store->fls_tab, i);

    key.data = &msg->msg_index;
    key.len = sizeof(msg->msg_index);
    chash_delete(flags_store->fls_hash, &key, NULL);

    mailmessage_free(msg);
  }
  carray_set_size(flags_store->fls_tab, 0);
}
Ejemplo n.º 11
0
static int folder_message_add(struct folder_ref_info * ref_info,
                              mailmessage * msg)
{
    chashdatum key;
    chashdatum data;
    struct message_ref_elt * msg_ref;
    int r;

    msg_ref = message_ref_elt_new(ref_info->folder, msg);
    if (msg_ref == NULL)
        goto err;

    key.data = &msg;
    key.len = sizeof(msg);
    data.data = msg_ref;
    data.len = 0;

    r = chash_set(ref_info->msg_hash, &key, &data, NULL);
    if (r < 0)
        goto free_msg_ref;

    if (msg->msg_uid != NULL) {
        key.data = msg->msg_uid;
        key.len = strlen(msg->msg_uid);
        data.data = msg;
        data.len = 0;

        r = chash_set(ref_info->uid_hash, &key, &data, NULL);
        if (r < 0)
            goto remove_msg_ref;
    }

    return MAIL_NO_ERROR;

remove_msg_ref:
    key.data = &msg;
    key.len = sizeof(msg);
    chash_delete(ref_info->msg_hash, &key, NULL);
free_msg_ref:
    message_ref_elt_free(msg_ref);
err:
    return MAIL_ERROR_MEMORY;
}
Ejemplo n.º 12
0
/* WARNING: This does not sync!!! */
void remove_element(cache_t *c, struct ce_t *o, int locked)
{
	if(!o) return;
	if(o->dirty)
		panic(PANIC_NOSYNC, "tried to remove non-sync'd element");
	
	if(!locked) rwlock_acquire(c->rwl, RWL_WRITER);
	if(o->dirty)
		set_dirty(c, o, 0);
	assert(c->count);
	sub_atomic(&c->count, 1);
	ll_remove(&c->primary_ll, o->list_node);
	if(c->hash) chash_delete(c->hash, o->id, o->key);
	if(o->data)
		kfree(o->data);
	rwlock_destroy(o->rwl);
	kfree(o);
	if(!locked) rwlock_release(c->rwl, RWL_WRITER);
}
Ejemplo n.º 13
0
void nntp_done(Folder * folder)
{
	struct etpan_thread * thread;
	chashdatum key;
	chashdatum value;
	int r;
	
	key.data = &folder;
	key.len = sizeof(folder);
	
	r = chash_get(nntp_hash, &key, &value);
	if (r < 0)
		return;
	
	thread = value.data;
	
	etpan_thread_unbind(thread);
	
	chash_delete(nntp_hash, &key, NULL);
	
	debug_print("remove thread");
}
Ejemplo n.º 14
0
int mailmh_folder_remove_message(struct mailmh_folder * folder,
				 uint32_t indx)
{
  char * filename;
  struct mailmh_msg_info * msg_info;
  int res;
  int r;
  chashdatum key;
  chashdatum data;

  r = mailmh_folder_get_message_filename(folder, indx, &filename);
  if (filename == NULL) {
    res = r;
    goto err;
  }

  if (unlink(filename) == -1) {
    res = MAILMH_ERROR_FILE;
    goto free;
  }

  key.data = &indx;
  key.len = sizeof(indx);
  r = chash_get(folder->fl_msgs_hash, &key, &data);
  if (r == 0) {
    msg_info = data.data;

    carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index);
    chash_delete(folder->fl_msgs_hash, &key, NULL);
  }

  return MAILMH_NO_ERROR;

 free:
  free(filename);
 err:
  return res;
}
Ejemplo n.º 15
0
static void storage_folder_remove_ref(struct storage_ref_info * ref_info,
                                      struct mailfolder * folder)
{
    struct folder_ref_info * folder_ref;
    chashdatum key;
    chashdatum value;
    int r;

    key.data = &folder;
    key.len = sizeof(folder);
    r = chash_get(ref_info->folder_ref_info, &key, &value);
    if (r < 0)
        return;

    folder_ref = value.data;

    if (folder_ref == NULL)
        return;

    folder_ref_info_free(folder_ref);

    chash_delete(ref_info->folder_ref_info, &key, &value);
}
Ejemplo n.º 16
0
int mailmh_folder_remove_subfolder(struct mailmh_folder * folder)
{
  struct mailmh_folder * parent;
  chashdatum key;
  chashdatum data;
  int r;
  
  parent = folder->fl_parent;

  key.data = folder->fl_filename;
  key.len = strlen(folder->fl_filename);
  
  r = chash_get(parent->fl_subfolders_hash, &key, &data);
  if (r < 0)
    return MAILMH_ERROR_FOLDER;

  chash_delete(parent->fl_subfolders_hash, &key, NULL);
  carray_delete_fast(parent->fl_subfolders_tab, folder->fl_array_index);
  
  mailmh_folder_free(folder);
      
  return MAILMH_NO_ERROR;

}
Ejemplo n.º 17
0
int mailmh_folder_update(struct mailmh_folder * folder)
{
  DIR * d;
  struct dirent * ent;
  struct stat buf;
  char * mh_seq;
  char filename[PATH_MAX];
  int res;
  int r;
  uint32_t max_index;
  unsigned int i;

  if (stat(folder->fl_filename, &buf) == -1) {
    res = MAILMH_ERROR_FOLDER;
    goto err;
  }

  if (folder->fl_mtime == buf.st_mtime) {
    res = MAILMH_NO_ERROR;
    goto err;
  }

  folder->fl_mtime = buf.st_mtime;

  d = opendir(folder->fl_filename);
  if (d == NULL) {
    res = MAILMH_ERROR_FOLDER;
    goto err;
  }

  max_index = 0;

  /* clear the message list */

  for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++) {
    struct mailmh_msg_info * msg_info;
    chashdatum key;
    
    msg_info = carray_get(folder->fl_msgs_tab, i);
    if (msg_info == NULL)
      continue;

    key.data = &msg_info->msg_index;
    key.len = sizeof(msg_info->msg_index);
    chash_delete(folder->fl_msgs_hash, &key, NULL);
    
    mailmh_msg_info_free(msg_info);
  }

  carray_set_size(folder->fl_msgs_tab, 0);

  do {
    uint32_t indx;

    ent = readdir(d);

    if (ent != NULL) {

      snprintf(filename, PATH_MAX,
	       "%s%c%s", folder->fl_filename, MAIL_DIR_SEPARATOR, ent->d_name);

      if (stat(filename, &buf) == -1)
	continue;

      if (S_ISREG(buf.st_mode)) {
	indx = strtoul(ent->d_name, NULL, 10);
	if (indx != 0) {
	  struct mailmh_msg_info * msg_info;
	  unsigned int array_index;
          chashdatum key;
          chashdatum data;

	  msg_info = mailmh_msg_info_new(indx, buf.st_size, buf.st_mtime);
	  if (msg_info == NULL) {
	    res = MAILMH_ERROR_MEMORY;
	    goto closedir;
	  }
	  
	  r = carray_add(folder->fl_msgs_tab, msg_info, &array_index);
	  if (r < 0) {
	    mailmh_msg_info_free(msg_info);
	    res = MAILMH_ERROR_MEMORY;
	    goto closedir;
	  }
	  msg_info->msg_array_index = array_index;

	  if (indx > max_index)
	    max_index = indx;

          key.data = &msg_info->msg_index;
          key.len = sizeof(msg_info->msg_index);
          data.data = msg_info;
          data.len = 0;
          
          r = chash_set(folder->fl_msgs_hash, &key, &data, NULL);
	  if (r < 0) {
	    carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index);
	    mailmh_msg_info_free(msg_info);
	    res = MAILMH_ERROR_MEMORY;
	    goto closedir;
	  }
	}
      }
      else if (S_ISDIR(buf.st_mode)) {
	struct mailmh_folder * subfolder;
	unsigned int array_index;
	chashdatum key;
	chashdatum data;

	if (ent->d_name[0] == '.') {
	  if (ent->d_name[1] == 0)
	    continue;
	  if ((ent->d_name[1] == '.') && (ent->d_name[2] == 0))
	    continue;
	}

	key.data = ent->d_name;
	key.len = strlen(ent->d_name);
	r = chash_get(folder->fl_subfolders_hash, &key, &data);
	if (r < 0) {
	  subfolder = mailmh_folder_new(folder, ent->d_name);
	  if (subfolder == NULL) {
	    res = MAILMH_ERROR_MEMORY;
	    goto closedir;
	  }
	  
	  r = carray_add(folder->fl_subfolders_tab, subfolder, &array_index);
	  if (r < 0) {
	    mailmh_folder_free(subfolder);
	    res = MAILMH_ERROR_MEMORY;
	    goto closedir;
	  }
	  subfolder->fl_array_index = array_index;
	  
	  key.data = subfolder->fl_filename;
	  key.len = strlen(subfolder->fl_filename);
	  data.data = subfolder;
	  data.len = 0;
	  r = chash_set(folder->fl_subfolders_hash, &key, &data, NULL);
	  if (r < 0) {
	    carray_delete_fast(folder->fl_subfolders_tab, subfolder->fl_array_index);
	    mailmh_folder_free(subfolder);
	    res = MAILMH_ERROR_MEMORY;
	    goto closedir;
	  }
	}
      }
    }
  }
  while (ent != NULL);

  folder->fl_max_index = max_index;

  mh_seq = malloc(strlen(folder->fl_filename) + 2 + sizeof(".mh_sequences"));
  if (mh_seq == NULL) {
    res = MAILMH_ERROR_MEMORY;
    goto closedir;
  }
  strcpy(mh_seq, folder->fl_filename);
  strcat(mh_seq, MAIL_DIR_SEPARATOR_S);
  strcat(mh_seq, ".mh_sequences");

  if (stat(mh_seq, &buf) == -1) {
    int fd;

    fd = creat(mh_seq, S_IRUSR | S_IWUSR);
    if (fd != -1)
      close(fd);
  }
  free(mh_seq);

  closedir(d);

  return MAILMH_NO_ERROR;

 closedir:
  closedir(d);
 err:
  return res;
}
Ejemplo n.º 18
0
int test_file(FILE *fp, int argc, char **argv) {
    char buf[65535 + 1];
    char *pos;
    unsigned int strategy = 0;  /* what bucketing strategy we're 
                                          using */
    void *ptr = NULL;
    unsigned int bucketsize = 0;
    struct params params = {0};
    struct chash *hash = NULL;
    char name[256];

    if (!parse_params(argc, argv, &params)) {
        fprintf(stderr, "failed to parse params\n");
        return 0;
    }

    while (fgets((char *) buf, 65535, fp)) {
        str_rtrim(buf);
        pos = (char *) str_ltrim(buf);

        if (!str_casecmp(pos, "new")) {

            /* creating a new bucket */
            unsigned int size = -1;

            if (ptr) {
                chash_delete(hash);
                free(ptr);
            }

            /* read parameters */
            if ((fscanf(fp, "%255s %u %u", name, &strategy, &size) == 3)
              && (size <= 65535) 
              && (bucketsize = size)
              && (ptr = malloc(size))
              && (hash = chash_ptr_new(1, 2.0, 
                /* some fn pointer casting dodginess */
                (unsigned int (*)(const void *)) str_len, 
                (int (*)(const void *, const void *)) str_cmp))
              && (bucket_new(ptr, bucketsize, strategy))) {
                /* succeeded, do nothing */
                if (params.verbose) {
                    printf("%s: new bucket with size %u strategy %u\n", name, 
                      size, strategy);
                }
            } else {
                fprintf(stderr, "%s: failed to create bucket\n", name);
                return 0;
            }
        } else if (!str_casecmp(pos, "add")) {
            /* adding a term to the bucket */
            void *ret;
            unsigned int veclen,
                         succeed,
                         len;
            int toobig;

            if (!ptr) { return 0; }

            /* read parameters */
            if ((fscanf(fp, "%65535s %u %u", buf, &veclen, &succeed) == 3) 
              && (veclen <= 65535)) {

                len = str_len(buf);
                if ((((ret = bucket_alloc(ptr, bucketsize, strategy, buf, len, 
                        veclen, &toobig, NULL))
                      && succeed)
                    || (!ret && !succeed))) {
                    /* do nothing */
                    if (params.verbose) {
                        printf("%s: added term '%s'\n", name, buf);
                    }
                } else if (succeed) {
                    fprintf(stderr, "%s: failed to add '%s' to bucket\n", 
                      name, buf);
                    return 0;
                } else if (!succeed) {
                    fprintf(stderr, "%s: add '%s' succeeded but shouldn't "
                      "have\n", name, buf);
                    return 0;
                }
            } else {
                fprintf(stderr, "%s: failed to add\n", name);
                return 0;
            }
        } else if (!str_casecmp(pos, "ls")) {
            /* matching stuff in the bucket */
            unsigned int numterms,
                         i,
                         len,
                         veclen,
                         veclen2,
                         state;
            void *addr;
            struct chash *tmphash;
            const char *term;
            void **tmpptr,
                  *tmp;

            if (!ptr) { return 0; }

            if (!(tmphash = chash_ptr_new(1, 2.0, 
              /* some fn pointer casting dodginess */
              (unsigned int (*)(const void *)) str_len, 
              (int (*)(const void *, const void *)) str_cmp))) {
                fprintf(stderr, "%s: failed to init hashtable\n", name);
                return 0;
            }

            /* first, fill hashtable with all terms from bucket */
            state = 0;
            while ((term 
              = bucket_next_term(ptr, bucketsize, strategy,
                  &state, &len, &addr, &veclen))) {

                if (!((term = str_ndup(term, len)) 
                  && (chash_ptr_ptr_insert(tmphash, term, (void*) term) 
                      == CHASH_OK))) {

                    fprintf(stderr, "%s: failed to init hashtable\n", name);
                    return 0;
                }
            }

            /* now, take terms from file, comparing them with hashtable 
             * entries */
            if (fscanf(fp, "%u", &numterms)) {
                for (i = 0; i < numterms; i++) {
                    if (fscanf(fp, "%65535s %u ", buf, &veclen)) {
                        if (params.verbose) {
                            printf("%s: ls checking %s\n", name, buf);
                        }
                        
                        if ((addr = bucket_find(ptr, bucketsize, strategy,
                            buf, str_len(buf), &veclen2, NULL))
                          /* remove it from hashtable */
                          && chash_ptr_ptr_find(tmphash, buf, &tmpptr) 
                            == CHASH_OK
                          && chash_ptr_ptr_remove(tmphash, *tmpptr, &tmp) 
                            == CHASH_OK
                          && (free(tmp), 1)
                          && (veclen <= 65535)
                          && (veclen2 == veclen)
                          && fread(buf, veclen, 1, fp)
                          && ((buf[veclen] = '\0'), 1)
                          && (!params.verbose 
                            || printf("%s: ls check read '%s'\n", name, buf))
                          && !memcmp(buf, addr, veclen)) {
                            /* do nothing */
                        } else {
                            unsigned int j;

                            fprintf(stderr, "%s: ls failed cmp '%s' with '", 
                              name, buf);
                            for (j = 0; j < veclen; j++) {
                                putc(((char *) addr)[j], stderr);
                            }
                            fprintf(stderr, "'\n");
                            return 0;
                        }
                    } else {
                        fprintf(stderr, "%s: ls failed\n", name);
                        return 0;
                    }
                }

                if (chash_size(tmphash)) {
                    fprintf(stderr, "%s: ls failed\n", name);
                    return 0;
                }
            } else {
                fprintf(stderr, "%s: ls failed\n", name);
                return 0;
            }

            chash_delete(tmphash);

            if (params.verbose) {
                printf("%s: matched all (%u) entries\n", name, numterms);
            }
        } else if (!str_casecmp(pos, "set")) {
            /* setting the vector for a term in the bucket */
            unsigned int veclen,
                        reallen;
            void *addr;

            if (!ptr) { return 0; }

            /* read parameters */
            if ((fscanf(fp, "%65535s %u ", buf, &veclen) == 2) 
              && (veclen <= 65535)) {

                addr = bucket_find(ptr, bucketsize, strategy, buf, 
                  str_len(buf), &reallen, NULL);

                if (addr && (reallen == veclen) 
                  && fread(addr, 1, veclen, fp)) {
                    /* do nothing */
                    if (params.verbose) {
                        unsigned int j;

                        printf("%s: set term '%s' to '", name, buf);
                        for (j = 0; j < reallen; j++) {
                            putc(((char *) addr)[j], stdout);
                        }
                        printf("'\n");
                    }
                } else {
                    fprintf(stderr, "%s: failed to set!\n", name);
                    return 0;
                }
            } else {
                fprintf(stderr, "%s: failed to set\n", name);
                return 0;
            }
        } else if (!str_casecmp(pos, "realloc")) {
            /* reallocating a term in the bucket */
            unsigned int veclen,
                         succeed;
            int toobig;

            if (!ptr) { return 0; }

            /* read parameters */
            if ((fscanf(fp, "%65535s %u %u", buf, &veclen, &succeed) == 3) 
              && (veclen <= 65535)) {

                if (!bucket_realloc(ptr, bucketsize, strategy, buf, 
                  str_len(buf), veclen, &toobig)) {
                    fprintf(stderr, "%s: failed to realloc!\n", name);
                    return 0;
                }
            } else {
                fprintf(stderr, "%s: failed to realloc\n", name);
                return 0;
            }

            if (params.verbose) {
                printf("%s: realloc'd term '%s'\n", name, buf);
            }
        } else if (!str_casecmp(pos, "rm")) {
            /* removing something from the bucket */
            unsigned int succeed;

            if (!ptr) { return 0; }

            if (fscanf(fp, "%65535s %u", buf, &succeed) == 2) {
                if (succeed) {

                    if (!(bucket_remove(ptr, bucketsize, strategy, buf, 
                      str_len(buf)))) {
                        fprintf(stderr, "%s: failed to rm '%s'\n", name, 
                          buf);
                        return 0;
                    } else if (params.verbose) {
                        printf("%s: rm term '%s'\n", name, buf);
                    }
                } else if (succeed) {
                    fprintf(stderr, "%s: failed to rm\n", name);
                    return 0;
                }
            } else {
                fprintf(stderr, "%s: failed to rm\n", name);
                return 0;
            }
        } else if (!str_casecmp(pos, "print")) {
            /* printing out the bucket contents */
            unsigned int state = 0,
                         len,
                         veclen;
            const char *term;
            char format[100];
            void *addr;

            if (!ptr) { 
                printf("can't print, no bucket\n");
            } else {
                do {
                    term 
                      = bucket_next_term(ptr, bucketsize, strategy, &state, 
                        &len, &addr, &veclen);
                } while (term 
                  && memcpy(buf, term, len)
                  && ((buf[len] = '\0') || 1)
                  && snprintf(format, 100, "%%.%us (%%u): '%%.%us' (%%u) "
                    "(off %%u)\n", len, veclen) 
                  && printf(format, term, len, (char*) addr, veclen, 
                    ((char *) addr) - (char *) ptr));

                if (!state) {
                    printf("(empty)\n");
                }

                printf("%u entries, %u data, %u string, %u overhead, %u free\n", 
                  bucket_entries(ptr, bucketsize, strategy), 
                  bucket_utilised(ptr, bucketsize, strategy), 
                  bucket_string(ptr, bucketsize, strategy), 
                  bucket_overhead(ptr, bucketsize, strategy),
                  bucket_unused(ptr, bucketsize, strategy));
            }
        } else if (!str_casecmp(pos, "match")) {
            unsigned int veclen,
                         veclen2;
            void *addr;

            if (fscanf(fp, "%65535s %u ", buf, &veclen)) {
                if ((addr = bucket_find(ptr, bucketsize, strategy,
                    buf, str_len(buf), &veclen2, NULL))
                  && (veclen <= 65535)
                  && (veclen2 >= veclen)
                  && (!params.verbose 
                    || printf("%s: match on '%s' ", name, buf))
                  && fread(buf, veclen, 1, fp)
                  && !memcmp(buf, addr, veclen)) {
                    if (params.verbose) {
                        printf("content succeeded\n");
                    }
                } else {
                    fprintf(stderr, "%s: match failed (%s vs %s)\n", name, buf,
                      (char *) addr);
                    return 0;
                }
            } else {
                fprintf(stderr, "%s: match failed\n", name);
                return 0;
            }
        } else if ((*pos != '#') && str_len(pos)) {
            fprintf(stderr, "%s: unknown command '%s'\n", name, pos);
            return 0;
        }
    }

    if (ptr) {
        chash_delete(hash);
        free(ptr);
    }

    return 1;
}