68 #ifndef TINYCDB_VERSION
72 #define cdb_fileno(c) ((c)->fd)
76 #define CDB_SUFFIX ".cdb"
78 #ifndef CDB_TMP_SUFFIX
79 #define CDB_TMP_SUFFIX CDB_SUFFIX ".tmp"
98 static const char *dict_cdbq_lookup(
DICT *dict,
const char *name)
100 DICT_CDBQ *dict_cdbq = (DICT_CDBQ *) dict;
105 const char *result = 0;
126 status = cdb_find(&dict_cdbq->cdb, name, strlen(name) + 1);
136 status = cdb_find(&dict_cdbq->cdb, name, strlen(name));
144 vlen = cdb_datalen(&dict_cdbq->cdb);
152 if (cdb_read(&dict_cdbq->cdb, buf, vlen,
153 cdb_datapos(&dict_cdbq->cdb)) < 0)
165 static void dict_cdbq_close(
DICT *dict)
167 DICT_CDBQ *dict_cdbq = (DICT_CDBQ *) dict;
169 cdb_free(&dict_cdbq->cdb);
178 static DICT *dict_cdbq_open(
const char *path,
int dict_flags)
180 DICT_CDBQ *dict_cdbq;
188 #define DICT_CDBQ_OPEN_RETURN(d) do { \
194 cdb_path =
concatenate(path, CDB_SUFFIX, (
char *) 0);
196 if ((fd = open(cdb_path, O_RDONLY)) < 0)
198 O_RDONLY, dict_flags,
199 "open database %s: %m", cdb_path));
202 cdb_path,
sizeof(*dict_cdbq));
203 #if defined(TINYCDB_VERSION)
204 if (cdb_init(&(dict_cdbq->cdb), fd) != 0)
205 msg_fatal(
"dict_cdbq_open: unable to init %s: %m", cdb_path);
207 cdb_init(&(dict_cdbq->cdb), fd);
209 dict_cdbq->dict.lookup = dict_cdbq_lookup;
210 dict_cdbq->dict.close = dict_cdbq_close;
211 dict_cdbq->dict.stat_fd = fd;
212 if (
fstat(fd, &st) < 0)
214 dict_cdbq->dict.mtime = st.st_mtime;
215 dict_cdbq->dict.owner.uid = st.st_uid;
216 dict_cdbq->dict.owner.status = (st.st_uid != 0);
223 if (
stat(path, &st) == 0
224 && st.st_mtime > dict_cdbq->dict.mtime
225 && st.st_mtime < time((time_t *) 0) - 100)
226 msg_warn(
"database %s is older than source file %s", cdb_path, path);
238 DICT_CDBQ_OPEN_RETURN(
DICT_DEBUG (&dict_cdbq->dict));
243 static int dict_cdbm_update(
DICT *dict,
const char *name,
const char *value)
245 DICT_CDBM *dict_cdbm = (DICT_CDBM *) dict;
246 unsigned ksize, vsize;
254 if (dict->
flags & DICT_FLAG_FOLD_FIX) {
260 ksize = strlen(name);
261 vsize = strlen(value);
274 #ifdef TINYCDB_VERSION
276 #error please upgrate tinycdb to at least 0.5 version
284 r = cdb_make_put(&dict_cdbm->cdbm, name, ksize, value, vsize, r);
286 msg_fatal(
"error writing %s: %m", dict_cdbm->tmp_path);
291 msg_warn(
"%s: duplicate entry: \"%s\"",
292 dict_cdbm->dict.name, name);
295 dict_cdbm->dict.name, name);
299 if (cdb_make_add(&dict_cdbm->cdbm, name, ksize, value, vsize) < 0)
300 msg_fatal(
"error writing %s: %m", dict_cdbm->tmp_path);
307 static void dict_cdbm_close(
DICT *dict)
309 DICT_CDBM *dict_cdbm = (DICT_CDBM *) dict;
310 int fd = cdb_fileno(&dict_cdbm->cdbm);
318 if (cdb_make_finish(&dict_cdbm->cdbm) < 0)
319 msg_fatal(
"finish database %s: %m", dict_cdbm->tmp_path);
320 if (rename(dict_cdbm->tmp_path, dict_cdbm->cdb_path) < 0)
321 msg_fatal(
"rename database from %s to %s: %m",
322 dict_cdbm->tmp_path, dict_cdbm->cdb_path);
324 msg_fatal(
"close database %s: %m", dict_cdbm->cdb_path);
325 myfree(dict_cdbm->cdb_path);
326 myfree(dict_cdbm->tmp_path);
334 static DICT *dict_cdbm_open(
const char *path,
int dict_flags)
336 DICT_CDBM *dict_cdbm;
340 struct stat st0, st1;
345 #define DICT_CDBM_OPEN_RETURN(d) do { \
354 cdb_path =
concatenate(path, CDB_SUFFIX, (
char *) 0);
355 tmp_path =
concatenate(path, CDB_TMP_SUFFIX, (
char *) 0);
365 if ((fd = open(tmp_path, O_RDWR | O_CREAT, 0644)) < 0)
368 "open database %s: %m",
370 if (
fstat(fd, &st0) < 0)
380 if (
stat(tmp_path, &st1) < 0)
387 if (st0.st_ino == st1.st_ino && st0.st_dev == st1.st_dev
388 && st0.st_rdev == st1.st_rdev && st0.st_nlink == st1.st_nlink
403 if (cdb_make_start(&dict_cdbm->cdbm, fd) < 0)
404 msg_fatal(
"initialize database %s: %m", tmp_path);
405 dict_cdbm->dict.close = dict_cdbm_close;
406 dict_cdbm->dict.update = dict_cdbm_update;
407 dict_cdbm->cdb_path = cdb_path;
408 dict_cdbm->tmp_path = tmp_path;
409 cdb_path = tmp_path = 0;
410 dict_cdbm->dict.owner.uid = st1.st_uid;
411 dict_cdbm->dict.owner.status = (st1.st_uid != 0);
422 dict_flags &= ~DICT_FLAG_TRY0NULL;
424 if (dict_flags & DICT_FLAG_FOLD_FIX)
427 DICT_CDBM_OPEN_RETURN(
DICT_DEBUG (&dict_cdbm->dict));
434 switch (open_flags & (O_RDONLY | O_RDWR | O_WRONLY | O_CREAT | O_TRUNC)) {
436 return dict_cdbq_open(path, dict_flags);
437 case O_WRONLY | O_CREAT | O_TRUNC:
438 case O_RDWR | O_CREAT | O_TRUNC:
439 return dict_cdbm_open(path, dict_flags);
441 msg_fatal(
"dict_cdb_open: inappropriate open flags for cdb database"
442 " - specify O_RDONLY or O_WRONLY|O_CREAT|O_TRUNC");
#define DICT_FLAG_DUP_IGNORE
void * myrealloc(void *ptr, ssize_t len)
#define MYFLOCK_OP_EXCLUSIVE
#define DICT_FLAG_FOLD_FIX
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
#define DICT_FLAG_DUP_REPLACE
#define DICT_FLAG_TRY1NULL
void msg_warn(const char *fmt,...)
VSTRING * vstring_alloc(ssize_t len)
int myflock(int fd, int lock_style, int operation)
char * lowercase(char *string)
#define DICT_FLAG_DUP_WARN
NORETURN msg_fatal(const char *fmt,...)
char * concatenate(const char *arg0,...)
VSTRING * vstring_free(VSTRING *vp)
DICT * dict_alloc(const char *, const char *, ssize_t)
#define DICT_FLAG_TRY0NULL
int close_on_exec(int fd, int on)
DICT * dict_cdb_open(const char *, int, int)
DICT * dict_surrogate(const char *dict_type, const char *dict_name, int open_flags, int dict_flags, const char *fmt,...)
void * mymalloc(ssize_t len)