diff options
Diffstat (limited to 'lib/mf-dbm.c')
-rw-r--r-- | lib/mf-dbm.c | 658 |
1 files changed, 0 insertions, 658 deletions
diff --git a/lib/mf-dbm.c b/lib/mf-dbm.c deleted file mode 100644 index a42c96ff..00000000 --- a/lib/mf-dbm.c +++ /dev/null @@ -1,658 +0,0 @@ -/* This file is part of Mailfromd. - Copyright (C) 1999, 2000, 2001, 2002, 2005, 2006, 2007, 2008, 2009, - 2010 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <signal.h> -#include <string.h> -#ifdef HAVE_STRINGS_H -# include <strings.h> -#endif -#include <errno.h> -#include <mailutils/error.h> -#include <mailutils/errno.h> -#include <mf-dbm.h> -#include "libmf.h" - -#ifndef MU_ERR_EXISTS -# define MU_ERR_EXISTS EEXIST -#endif - -size_t lock_retry_count_option = 3; -time_t lock_retry_timeout_option = 1; -static mu_debug_handle_t debug_handle; - -void -libdbm_init() -{ - debug_handle = mu_debug_register_category("dbm"); -} - -int -mf_fcheck_perm(int fd, int mode) -{ - struct stat st; - - if (fstat (fd, &st) == -1) { - if (errno == ENOENT) - return ENOENT; - else - return MU_ERR_FAILURE; - } - if ((st.st_mode & 0777) != mode) - return errno = EACCES; - return 0; -} - -int -mf_check_perm(const char *name, int mode) -{ - struct stat st; - - if (mode == 0) - return 0; - if (stat(name, &st) == -1) { - if (errno == ENOENT) - return ENOENT; - else - return MU_ERR_FAILURE; - } - if ((st.st_mode & 0777) != mode) - return errno = EACCES; - - return 0; -} - -#if defined(WITH_GDBM) - -int -mf_dbm_open(char *name, MF_DBM_FILE *db, int flags, int mode, int *ro) -{ - int rc; - int f; - size_t i; - GDBM_FILE gdbm; - - rc = mf_check_perm(name, mode); - if (rc && rc != ENOENT) - return MU_ERR_UNSAFE_PERMS; - - if (ro) - *ro = 0; - - switch (flags) { - case MU_STREAM_CREAT: - f = GDBM_NEWDB; - break; - - case MU_STREAM_READ: - f = GDBM_READER; - break; - - case MU_STREAM_RDWR: - f = GDBM_WRCREAT; - break; - - default: - errno = EINVAL; - return 1; - } - - for (i = 0; i < lock_retry_count_option; i++) { - gdbm = gdbm_open(name, 512, f, mode, NULL); - if (gdbm || errno != EAGAIN) - break; - sleep(lock_retry_timeout_option); - } - - if (!gdbm) { - if (ro) { - gdbm = gdbm_open(name, 512, GDBM_READER, mode, NULL); - if (gdbm) - *ro = 1; - } - } - - rc = (gdbm == NULL) ? MU_ERR_FAILURE : 0; - - if (rc == 0) { - db->db = gdbm; - db->name = strdup(name); - } - - return rc; -} - -int -mf_dbm_close(MF_DBM_FILE *db) -{ - gdbm_close(db->db); - free(db->name); - return 0; -} - -int -mf_dbm_fetch(MF_DBM_FILE *db, MF_DBM_DATUM key, MF_DBM_DATUM *ret) -{ - *ret = gdbm_fetch(db->db, key); - if (ret->dptr == NULL) - return MU_ERR_NOENT; - return 0; -} - -int -mf_dbm_delete(MF_DBM_FILE *db, MF_DBM_DATUM key) -{ - return gdbm_delete(db->db, key) ? MU_ERR_FAILURE : 0; -} - -int -mf_dbm_insert(MF_DBM_FILE *db, MF_DBM_DATUM key, MF_DBM_DATUM contents, int replace) -{ - switch (gdbm_store(db->db, key, contents, - replace ? GDBM_REPLACE : GDBM_INSERT)) { - case -1: - return MU_ERR_FAILURE; - - case 0: - return 0; - - case 1: - return MU_ERR_EXISTS; - } - return MU_ERR_FAILURE; -} - -int -mf_dbm_firstkey(MF_DBM_FILE *db, MF_DBM_DATUM *pkey) -{ - *pkey = gdbm_firstkey(db->db); - return (pkey->dptr == NULL) ? MU_ERR_NOENT : 0; -} - -int -mf_dbm_nextkey(MF_DBM_FILE *db, MF_DBM_DATUM prevkey, MF_DBM_DATUM *pkey) -{ - *pkey = gdbm_nextkey(db->db, prevkey); - return (pkey->dptr == NULL) ? MU_ERR_NOENT : 0; -} - -void -mf_dbm_datum_free(MF_DBM_DATUM *datum) -{ - void *ptr = MF_DATUM_PTR(*datum); - if (ptr) - free(ptr); - MF_DATUM_PTR(*datum) = 0; -} - -const char * -mf_dbm_strerror() -{ - if (errno == MU_ERR_UNSAFE_PERMS) - return mu_strerror(errno); - return gdbm_strerror(gdbm_errno); -} - -#elif defined(WITH_BDB) - -int mf_dbm_errno; - -static int -try_lock(int fd, int type, struct flock *fl) -{ - int i, rc; - - for (i = 0; i < lock_retry_count_option; i++) { - alarm(lock_retry_timeout_option); - rc = fcntl(fd, F_SETLKW, fl); - alarm(0); - if (rc == 0) - return 0; - } - return errno; -} - -static int -lock_file(const char *name, int fd, int type) -{ - int rc = 0; - struct flock fl; - - if (type == F_UNLCK) - mu_debug(debug_handle, MU_DEBUG_TRACE1, - ("unlocking %s", name)); - else - mu_debug(debug_handle, MU_DEBUG_TRACE1, - ("locking %s for %s", - name, - (type == F_RDLCK) ? "reading" : "writing")); - - memset(&fl, 0, sizeof fl); - fl.l_whence = SEEK_SET; - fl.l_type = type; - - rc = try_lock(fd, type, &fl); - if (!rc) - return 0; - - fl.l_pid = 0; - if (fcntl(fd, F_GETLK, &fl) != -1) { - if (fl.l_type == F_UNLCK) { - memset (&fl, 0, sizeof fl); - fl.l_whence = SEEK_SET; - fl.l_type = type; - rc = try_lock (fd, type, &fl); - if (rc) - mu_error(_("%s: cannot acquire lock: %s"), - name, mu_strerror (rc)); - } else if (fl.l_pid) { - if (kill(fl.l_pid, 0) == 0) - mu_error(_("%s is locked (%d) " - "by process ID %lu"), - name, - fl.l_type, - (unsigned long) fl.l_pid); - else if (errno == ESRCH) { - mu_error (_("%s is locked by " - "nonexisting process " - "ID %lu; " - "retrying"), - name, - (unsigned long) fl.l_pid); - if (unlink(name)) - mu_error (_("cannot unlink " - "file %s: %s"), - name, - mu_strerror(errno)); - else { - rc = try_lock(fd, type, &fl); - if (rc) - mu_error (_("%s: cannot acquire lock: %s"), - name, - mu_strerror(rc)); - } - } else - mu_error (_("%s seems locked " - "by process ID %lu, " - "but its validity cannot " - "be verified: %s"), - name, - (unsigned long) fl.l_pid, - mu_strerror(errno)); - } else - mu_error (_("%s: cannot acquire lock: %s"), - name, mu_strerror(rc)); - } else - mu_error (_("cannot obtain locker info for %s: %s"), - name, mu_strerror (errno)); - return rc; -} - -#ifndef DB_FCNTL_LOCKING -#define LOCK_SUFFIX ".lock" - -static int -make_lockfile(char *name, int lktype, int *pfd, char **plockname) -{ - int rc; - int fd; - char *p, *lockname; - size_t size, namesize; - - size = strlen(mailfromd_state_dir); - if (strlen(name) > size - && memcmp(name, mailfromd_state_dir, size) == 0 - && name[size] == '/') - p = name + size + 1; - else - p = name; - - namesize = size + 1 + strlen(p) + sizeof LOCK_SUFFIX; - lockname = malloc(namesize); - if (!lockname) - return errno; - strcpy(lockname, mailfromd_state_dir); - strcat(lockname, "/"); - strcat(lockname, p); - strcat(lockname, LOCK_SUFFIX); - for (p = lockname + size + 1; *p; p++) - if (*p == '/') - *p = '-'; - - fd = open(lockname, O_CREAT|O_RDWR, 0600); - if (fd == -1) { - free(lockname); - return errno; - } - - rc = lock_file(lockname, fd, lktype); - if (rc) { - free(lockname); - return rc; - } - - *plockname = lockname; - *pfd = fd; - return 0; -} -#endif - -static void -mf_dbm_errcall_fcn -#if DB_VERSION_MAJOR == 3 - (const char *errpfx, char *msg) -#elif DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 2 - (const char *errpfx, char *msg) -#else - (const DB_ENV *env, const char *errpfx, const char *msg) -#endif -{ - if (errpfx) - mu_error("%s: %s: %s", errpfx, _("Berkeley DB error"), msg); - else - mu_error("%s: %s", _("Berkeley DB error"), msg); -} - -#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1 -# define DB_TXN_NULL NULL, -#else -# define DB_TXN_NULL -#endif - -int -mf_dbm_open(char *name, MF_DBM_FILE *dbm, int flags, int mode, int *ro) -{ - int f = 0; - DB *db = NULL; - int oflags; -# define LKTYPE(o) (((o) & O_RDWR) ? F_WRLCK : F_RDLCK) - - mu_debug(debug_handle, MU_DEBUG_TRACE2, ("opening database %s", name)); - mf_dbm_errno = mf_check_perm(name, mode); - - if (mf_dbm_errno && mf_dbm_errno != ENOENT) - return EACCES; - - if (ro) - *ro = 0; - - switch (flags) { - case MU_STREAM_CREAT: - f = DB_CREATE | DB_TRUNCATE; - oflags = O_CREAT | O_TRUNC | O_RDWR; - break; - - case MU_STREAM_READ: - if (mf_dbm_errno == ENOENT) - return MU_ERR_FAILURE; - f = DB_RDONLY; - oflags = O_RDONLY; - break; - - case MU_STREAM_RDWR: - f = DB_CREATE; - oflags = O_CREAT | O_RDWR; - if (mf_dbm_errno == ENOENT) - f |= DB_TRUNCATE; - break; - - default: - mf_dbm_errno = EINVAL; - return MU_ERR_FAILURE; - } - - dbm->lockname = NULL; -#ifdef DB_FCNTL_LOCKING - f |= DB_FCNTL_LOCKING; - - dbm->lockfd = open(name, oflags, mode); - if (dbm->lockfd == -1) { - mf_dbm_errno = errno; - return MU_ERR_FAILURE; - } - mf_dbm_errno = lock_file(name, dbm->lockfd, LKTYPE(oflags)); - if (mf_dbm_errno) { - mu_error(_("cannot lock file %s: %s"), - name, mu_strerror(mf_dbm_errno)); - close(dbm->lockfd); - return MU_ERR_FAILURE; - } -#else - mf_dbm_errno = make_lockfile(name, LKTYPE(oflags), &dbm->lockfd, - &dbm->lockname); - if (mf_dbm_errno) { - mu_error(_("cannot lock file %s: %s"), - name, mu_strerror(mf_dbm_errno)); - return MU_ERR_FAILURE; - } -#endif - -#if DB_VERSION_MAJOR == 2 - mf_dbm_errno = db_open(name, DB_HASH, f, mode, NULL, NULL, &db); -#else - mf_dbm_errno = db_create(&db, NULL, 0); - if (mf_dbm_errno != 0 || db == NULL) - return MU_ERR_FAILURE; -# if DB_VERSION_MAJOR == 3 - mf_dbm_errno = db->open(db, name, NULL, DB_HASH, f, mode); -# else - mf_dbm_errno = db->open(db, DB_TXN_NULL name, NULL, DB_HASH, f, mode); -# endif -#endif - if (mf_dbm_errno) { - if (dbm->lockname) { - unlink(dbm->lockname); - free(dbm->lockname); - } - close(dbm->lockfd); - return MU_ERR_FAILURE; - } - - db->sync(db, 0); - -#if DB_VERSION_MAJOR > 2 - if (mu_debug_level_p(debug_handle, MU_DEBUG_TRACE0)) - db->set_errcall (db, mf_dbm_errcall_fcn); -#endif - - dbm->name = strdup(name); - dbm->db = db; - dbm->dbc = NULL; - - return 0; -} - -int -mf_dbm_close(MF_DBM_FILE *db) -{ - mu_debug(debug_handle, MU_DEBUG_TRACE2, - ("closing database %s", db->name)); - if (db->dbc) { - mf_dbm_errno = db->dbc->c_close(db->dbc); - db->dbc = NULL; - if (mf_dbm_errno) - return MU_ERR_FAILURE; - } - - db->db->sync(db->db, 0); - mf_dbm_errno = db->db->close(db->db, 0); - if (db->lockname) { - mu_debug(debug_handle, MU_DEBUG_TRACE2, - ("removing lock file %s", db->lockname)); - unlink(db->lockname); - free(db->lockname); - } - close(db->lockfd); - - free(db->name); - return (mf_dbm_errno == 0) ? 0 : MU_ERR_FAILURE; -} - -int -mf_dbm_fetch(MF_DBM_FILE *db, MF_DBM_DATUM key, MF_DBM_DATUM *ret) -{ - mf_dbm_errno = db->db->get(db->db, NULL, &key, ret, 0); - switch (mf_dbm_errno) { - case 0: - return 0; - - case DB_NOTFOUND: - return MU_ERR_NOENT; - - default: - return MU_ERR_FAILURE; - } -} - -int -mf_dbm_delete(MF_DBM_FILE *dbm, MF_DBM_DATUM key) -{ - mf_dbm_errno = dbm->db->del(dbm->db, NULL, &key, 0); - return mf_dbm_errno ? MU_ERR_FAILURE : 0; -} - -int -mf_dbm_insert(MF_DBM_FILE *dbm, MF_DBM_DATUM key, MF_DBM_DATUM contents, int replace) -{ - int flags = replace ? 0 : DB_NOOVERWRITE; - int rc = 0; - - mf_dbm_errno = dbm->db->put(dbm->db, NULL, &key, &contents, flags); - switch (mf_dbm_errno) { - case 0: - break; - - case DB_KEYEXIST: - rc = MU_ERR_EXISTS; - break; - - default: - rc = MU_ERR_FAILURE; - } - return rc; -} - -int -mf_dbm_firstkey(MF_DBM_FILE *db, MF_DBM_DATUM *pkey) -{ - DBT data; - - memset(pkey, 0, sizeof *pkey); - memset(&data, 0, sizeof data); - - if (!db->dbc) { - mf_dbm_errno = db->db->cursor(db->db, NULL, &db->dbc - BDB2_CURSOR_LASTARG); - if (mf_dbm_errno) - return MU_ERR_FAILURE; - } - - mf_dbm_errno = db->dbc->c_get(db->dbc, pkey, &data, DB_FIRST); - switch (mf_dbm_errno) { - case 0: - return 0; - - case DB_NOTFOUND: - return MU_ERR_NOENT; - - default: - return MU_ERR_FAILURE; - } -} - -int -mf_dbm_nextkey(MF_DBM_FILE *db, MF_DBM_DATUM prevkey /*unused*/, - MF_DBM_DATUM *pkey) -{ - DBT data; - - memset(pkey, 0, sizeof *pkey); - memset(&data, 0, sizeof data); - - if (!db->dbc) { - mf_dbm_errno = EINVAL; - return MU_ERR_FAILURE; - } - - mf_dbm_errno = db->dbc->c_get(db->dbc, pkey, &data, DB_NEXT); - - switch (mf_dbm_errno) { - case 0: - return 0; - - case DB_NOTFOUND: - return MU_ERR_NOENT; - - default: - return MU_ERR_FAILURE; - } -} - -void -mf_dbm_datum_free(MF_DBM_DATUM *datum) -{ - /* empty */ -} - -const char * -mf_dbm_strerror() -{ -#if DB_VERSION_MAJOR == 2 - switch (mf_dbm_errno) { - case DB_INCOMPLETE: - return "Sync didn't finish"; - - case DB_KEYEMPTY: - return "The key/data pair was deleted or " - "was never created by the user"; - break; - - case DB_KEYEXIST: - return "The key/data pair already exists"; - - case DB_LOCK_DEADLOCK: - return "Locker killed to resolve deadlock"; - - case DB_LOCK_NOTGRANTED: - return "Lock unavailable, no-wait set"; - - case DB_LOCK_NOTHELD: - return "Lock not held by locker"; - - case DB_NOTFOUND: - return "Key/data pair not found (EOF)"; - - default: - return mu_strerror(mf_dbm_errno); - } -#else - if (mf_dbm_errno < 0) - return db_strerror(mf_dbm_errno); - else - return mu_strerror(mf_dbm_errno); -#endif -} - -#endif |