diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-04-12 11:50:38 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-04-12 11:50:38 +0000 |
commit | 7f8a5835e41a0032769daec4865484680b332d6c (patch) | |
tree | 542e64a854fb882b814b571fc0cab4e1a82570b5 | |
parent | b9859b7dcd488df71ed18deeb2e034063b5bc8bd (diff) | |
download | mailfromd-7f8a5835e41a0032769daec4865484680b332d6c.tar.gz mailfromd-7f8a5835e41a0032769daec4865484680b332d6c.tar.bz2 |
Re-implement database locking for Berkeley DB
git-svn-id: file:///svnroot/mailfromd/trunk@1352 7a8a7f39-df28-0410-adc6-e0d955640f24
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | src/mu_dbm.c | 144 |
2 files changed, 127 insertions, 19 deletions
@@ -1,5 +1,7 @@ 2007-04-12 Sergey Poznyakoff <gray@gnu.org.ua> + * src/mu_dbm.c: Re-implement database locking for Berkeley DB + * src/mu_dbm.c, src/mu_dbm.h (mu_dbm_strerror): New function (mu_dbm_firstkey, mu_dbm_nextkey): Change signature * src/dnscache.c, src/db.c, src/cache.c, src/rate.c, diff --git a/src/mu_dbm.c b/src/mu_dbm.c index 421a846c..461731e7 100644 --- a/src/mu_dbm.c +++ b/src/mu_dbm.c @@ -46,15 +46,12 @@ mu_fcheck_perm (int fd, int mode) if (fstat (fd, &st) == -1) { if (errno == ENOENT) - return 0; + return ENOENT; else - return 1; + return MU_ERR_FAILURE; } if ((st.st_mode & 0777) != mode) - { - errno = MU_ERR_UNSAFE_PERMS; - return 1; - } + return errno = MU_ERR_UNSAFE_PERMS; return 0; } @@ -68,25 +65,18 @@ mu_check_perm (const char *name, int mode) if (stat (name, &st) == -1) { if (errno == ENOENT) - return 0; + return ENOENT; else - return 1; + return MU_ERR_FAILURE; } if ((st.st_mode & 0777) != mode) - { - errno = MU_ERR_UNSAFE_PERMS; - return 1; - } + return errno = MU_ERR_UNSAFE_PERMS; + return 0; } #if defined(WITH_GDBM) -void -mu_dbm_finish () -{ -} - int mu_dbm_open (char *name, DBM_FILE *db, int flags, int mode, int *ro) { @@ -216,6 +206,8 @@ mu_dbm_datum_free (DBM_DATUM *datum) const char * mu_dbm_strerror () { + if (errno == MU_ERR_UNSAFE_PERMS) + return mu_strerror (errno); return gdbm_strerror (gdbm_errno); } @@ -223,6 +215,68 @@ mu_dbm_strerror () int mu_dbm_errno; +static int +lock_file (int fd, int type) +{ + int i; + struct flock fl; + int rc = 0; + + memset(&fl, 0, sizeof fl); + fl.l_whence = SEEK_SET; + fl.l_type = type; + + for (i = 0; i < lock_retry_count_option; i++) + { + if (fcntl(fd, F_SETLK, &fl) == 0) + { + rc = 0; + break; + } + rc = errno; + if (!(errno == EAGAIN || errno == EACCES)) + break; + sleep (lock_retry_timeout_option); + } + return rc; +} + +#define LOCK_SUFFIX ".lock" + +static int +make_lockfile (char *name, int *pfd, char **plockname) +{ + int rc; + int fd; + char *lockname; + size_t size; + + size = strlen (name) + sizeof LOCK_SUFFIX; + lockname = malloc (size); + if (!lockname) + return errno; + strcpy (lockname, name); + strcat (lockname, LOCK_SUFFIX); + fd = open (lockname, O_CREAT|O_RDWR, 0600); + if (!fd) + { + free (lockname); + return errno; + } + + rc = lock_file (fd, F_WRLCK); + if (rc) + { + free (lockname); + return rc; + } + + *plockname = lockname; + *pfd = fd; + return 0; +} + + static void mu_dbm_errcall_fcn (const char *errpfx, char *msg) { @@ -235,10 +289,14 @@ mu_dbm_errcall_fcn (const char *errpfx, char *msg) int mu_dbm_open (char *name, DBM_FILE *dbm, int flags, int mode, int *ro) { - int f, rc; + int f; DB *db = NULL; + int lockfd = -1; + char *lockname; + int fd; - if (mu_check_perm (name, mode)) + mu_dbm_errno = mu_check_perm (name, mode); + if (mu_dbm_errno && mu_dbm_errno != ENOENT) return MU_ERR_UNSAFE_PERMS; if (ro) @@ -251,6 +309,8 @@ mu_dbm_open (char *name, DBM_FILE *dbm, int flags, int mode, int *ro) break; case MU_STREAM_READ: + if (mu_dbm_errno == ENOENT) + return MU_ERR_FAILURE; f = DB_RDONLY; break; @@ -263,6 +323,17 @@ mu_dbm_open (char *name, DBM_FILE *dbm, int flags, int mode, int *ro) return -1; } + if (mu_dbm_errno == ENOENT) + { + mu_dbm_errno = make_lockfile (name, &lockfd, &lockname); + if (mu_dbm_errno) + { + mu_error ("Cannot lock file %s: %s", + name, mu_strerror (mu_dbm_errno)); + return MU_ERR_FAILURE; + } + } + #if DB_VERSION_MAJOR == 2 mu_dbm_errno = db_open (name, DB_HASH, f, mode, NULL, NULL, &db); #else @@ -277,10 +348,39 @@ mu_dbm_open (char *name, DBM_FILE *dbm, int flags, int mode, int *ro) #endif if (mu_dbm_errno) return MU_ERR_FAILURE; + + if (mu_dbm_errno = db->fd (db, &fd)) + { + mu_error("Cannot get file descriptor for the database: %s", + mu_dbm_strerror ()); + db->close (db, 0); + if (lockfd != -1) + { + unlink (lockname); + free (lockname); + close (lockfd); + } + return MU_ERR_FAILURE; + } + + mu_dbm_errno = lock_file (fd, (flags == MU_STREAM_READ) ? F_RDLCK : F_WRLCK); + if (lockfd != -1) + { + unlink (lockname); + free (lockname); + close (lockfd); + } + + if (mu_dbm_errno) + { + db->close (db, 0); + return MU_ERR_FAILURE; + } dbm->name = strdup (name); dbm->db = db; dbm->dbc = NULL; + return 0; } @@ -413,7 +513,13 @@ mu_dbm_datum_free(DBM_DATUM *datum) const char * mu_dbm_strerror () { + if (errno == MU_ERR_UNSAFE_PERMS) + return mu_strerror (errno); +#if DB_VERSION_MAJOR > 2 return db_strerror (mu_dbm_errno); +#else + return mu_strerror (mu_dbm_errno); +#endif } #endif |