view src/lib-dict/dict-cdb.c @ 22325:e01bc3015b2f

lib-index: Check .log.2 rotation only when syncing Instead of also whenever appending transactions to .log file. This shouldn't change the behavior much, and it's needed for the following change to work correctly.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Tue, 11 Jul 2017 15:33:56 +0300
parents af8d96508fad
children cb108f786fb4
line wrap: on
line source

/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */

#include "lib.h"

#ifdef BUILD_CDB
#include "dict-private.h"

#include <string.h>
#include <cdb.h>
#include <unistd.h>
#include <fcntl.h>

#define CDB_WITH_NULL 1
#define CDB_WITHOUT_NULL 2

struct cdb_dict {
	struct dict dict;
	struct cdb cdb;
	char *path;
	int fd, flag;
};

static void cdb_dict_deinit(struct dict *_dict);

static int
cdb_dict_init(struct dict *driver, const char *uri,
	      const struct dict_settings *set ATTR_UNUSED,
	      struct dict **dict_r, const char **error_r)
{
	struct cdb_dict *dict;

	dict = i_new(struct cdb_dict, 1);
	dict->dict = *driver;
	dict->path = i_strdup(uri);
	dict->flag = CDB_WITH_NULL | CDB_WITHOUT_NULL;

	/* initialize cdb to 0 (unallocated) */
	memset(&dict->cdb, 0, sizeof(struct cdb));

	dict->fd = open(dict->path, O_RDONLY);
	if (dict->fd == -1) {
		*error_r = t_strdup_printf("open(%s) failed: %m", dict->path);
		cdb_dict_deinit(&dict->dict);
		return -1;
	}

#ifdef TINYCDB_VERSION
	if (cdb_init(&dict->cdb, dict->fd) < 0) {
		*error_r = t_strdup_printf("cdb_init(%s) failed: %m", dict->path);
		cdb_dict_deinit(&dict->dict);
		return -1;
	}
#else
	cdb_init(&dict->cdb, dict->fd);
#endif

	*dict_r = &dict->dict;
	return 0;
}

static void cdb_dict_deinit(struct dict *_dict)
{
	struct cdb_dict *dict = (struct cdb_dict *)_dict;

	/* we can safely deinit unallocated cdb */
	cdb_free(&dict->cdb);

	if (dict->fd != -1) {
		if (close(dict->fd) < 0)
			i_error("close(%s) failed: %m", dict->path);
	}

	i_free(dict->path);
	i_free(dict);
}

static int cdb_dict_lookup(struct dict *_dict, pool_t pool,
			   const char *key, const char **value_r)
{
	struct cdb_dict *dict = (struct cdb_dict *)_dict;
	unsigned datalen;
	int ret = 0;
	char *data;

	/* keys and values may be null terminated... */
	if ((dict->flag & CDB_WITH_NULL) != 0) {
		ret = cdb_find(&dict->cdb, key, (unsigned)strlen(key)+1);
		if (ret > 0)
			dict->flag &= ~CDB_WITHOUT_NULL;
	}

	/* ...or not */
	if (ret == 0 && (dict->flag & CDB_WITHOUT_NULL) != 0) {
		ret = cdb_find(&dict->cdb, key, (unsigned)strlen(key));
		if (ret > 0)
			dict->flag &= ~CDB_WITH_NULL;
	}

	if (ret <= 0) {
		*value_r = NULL;
		/* something bad with db */
		if (ret < 0) {
			i_error("cdb_find(%s) failed: %m", dict->path);
			return -1;
		}
		/* found nothing */
		return 0;
	}

	datalen = cdb_datalen(&dict->cdb);
	data = p_malloc(pool, datalen + 1);
	if (cdb_read(&dict->cdb, data, datalen, cdb_datapos(&dict->cdb)) < 0) {
		i_error("cdb_read(%s) failed: %m", dict->path);
		return -1;
	}
	*value_r = data;
	return 1;
}

struct dict dict_driver_cdb = {
	.name = "cdb",
	{
		.init = cdb_dict_init,
		.deinit = cdb_dict_deinit,
		.lookup = cdb_dict_lookup,
	}
};
#endif