/* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. GNU Mailutils 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 2, or (at your option) any later version. GNU Mailutils 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 GNU Mailutils; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #ifdef HAVE_STRINGS_H # include #endif #include #include #include #include int mu_fcheck_perm (int fd, int mode) { struct stat st; if (fstat (fd, &st) == -1) { if (errno == ENOENT) return 0; else return 1; } if ((st.st_mode & 0777) != mode) { errno = MU_ERR_UNSAFE_PERMS; return 1; } return 0; } int mu_check_perm (const char *name, int mode) { struct stat st; if (mode == 0) return 0; if (stat (name, &st) == -1) { if (errno == ENOENT) return 0; else return 1; } if ((st.st_mode & 0777) != mode) { errno = MU_ERR_UNSAFE_PERMS; return 1; } return 0; } #if defined(WITH_GDBM) #define DB_SUFFIX ".db" int mu_dbm_stat (char *name, struct stat *sb) { int rc; char *pfname = xmalloc (strlen (name) + sizeof DB_SUFFIX); strcat (strcpy (pfname, name), DB_SUFFIX); rc = stat (pfname, sb); free (pfname); return rc; } int mu_dbm_open (char *name, DBM_FILE *db, int flags, int mode) { int f; char *pfname; pfname = xmalloc (strlen (name) + sizeof DB_SUFFIX); strcat (strcpy (pfname, name), DB_SUFFIX); if (mu_check_perm (pfname, mode)) { free (pfname); return -1; } 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: free (pfname); errno = EINVAL; return 1; } *db = gdbm_open(pfname, 512, f, mode, NULL); free (pfname); return *db == NULL; } int mu_dbm_close (DBM_FILE db) { gdbm_close(db); return 0; } int mu_dbm_fetch (DBM_FILE db, DBM_DATUM key, DBM_DATUM *ret) { *ret = gdbm_fetch(db, key); return ret->dptr == NULL; } int mu_dbm_delete (DBM_FILE db, DBM_DATUM key) { return gdbm_delete (db, key); } int mu_dbm_insert (DBM_FILE db, DBM_DATUM key, DBM_DATUM contents, int replace) { return gdbm_store(db, key, contents, replace ? GDBM_REPLACE : GDBM_INSERT); } DBM_DATUM mu_dbm_firstkey (DBM_FILE db) { return gdbm_firstkey (db); } DBM_DATUM mu_dbm_nextkey (DBM_FILE db, DBM_DATUM key) { return gdbm_nextkey (db, key); } #elif defined(WITH_BDB2) #define DB_SUFFIX ".db" int mu_dbm_stat (char *name, struct stat *sb) { int rc; char *pfname = xmalloc (strlen (name) + sizeof DB_SUFFIX); strcat (strcpy (pfname, name), DB_SUFFIX); rc = stat (pfname, sb); free (pfname); return rc; } int mu_dbm_open (char *name, DBM_FILE *dbm, int flags, int mode) { int f, rc; DB *db; char *pfname; pfname = xmalloc (strlen (name) + sizeof DB_SUFFIX); strcat (strcpy (pfname, name), DB_SUFFIX); if (mu_check_perm (pfname, mode)) { free (pfname); return -1; } switch (flags) { case MU_STREAM_CREAT: f = DB_CREATE|DB_TRUNCATE; break; case MU_STREAM_READ: f = DB_RDONLY; break; case MU_STREAM_RDWR: f = DB_CREATE; break; default: free (pfname); errno = EINVAL; return -1; } rc = db_open (pfname, DB_HASH, f, mode, NULL, NULL, &db); free (pfname); if (rc) return -1; *dbm = malloc (sizeof **dbm); if (!*dbm) { db->close (db, 0); errno = ENOMEM; return -1; } (*dbm)->db = db; (*dbm)->dbc = NULL; return 0; } int mu_dbm_close (DBM_FILE db) { db->db->close (db->db, 0); free (db); return 0; } int mu_dbm_fetch (DBM_FILE db, DBM_DATUM key, DBM_DATUM *ret) { return db->db->get (db->db, NULL, &key, ret, 0); } int mu_dbm_delete (DBM_FILE db, DBM_DATUM key) { return db->db->del (db->db, NULL, &key, 0); } int mu_dbm_insert (DBM_FILE db, DBM_DATUM key, DBM_DATUM contents, int replace) { /*FIXME: replace unused*/ return db->db->put (db->db, NULL, &key, &contents, 0); } DBM_DATUM mu_dbm_firstkey (DBM_FILE db) { DBT key, data; int ret; memset(&key, 0, sizeof key); memset(&data, 0, sizeof data); if (!db->dbc) { if (db->db->cursor(db->db, NULL, &db->dbc BDB2_CURSOR_LASTARG) != 0) return key; } if ((ret = db->dbc->c_get(db->dbc, &key, &data, DB_FIRST)) != 0) { key.data = NULL; key.size = 0; if (ret == DB_NOTFOUND) errno = MU_ERR_NOENT; else errno = ret; } return key; } DBM_DATUM mu_dbm_nextkey (DBM_FILE db, DBM_DATUM pkey /*unused*/) { DBT key, data; int ret; memset(&key, 0, sizeof key); memset(&data, 0, sizeof data); if (!db->dbc) return key; if ((ret = db->dbc->c_get(db->dbc, &key, &data, DB_NEXT)) != 0) { key.data = NULL; key.size = 0; if (ret == DB_NOTFOUND) errno = MU_ERR_NOENT; else errno = ret; } return key; } #elif defined(WITH_NDBM) #define DB_SUFFIX ".pag" int mu_dbm_stat (char *name, struct stat *sb) { int rc; char *pfname = xmalloc (strlen (name) + sizeof DB_SUFFIX); strcat (strcpy (pfname, name), DB_SUFFIX); rc = stat (pfname, sb); free (pfname); return rc; } int mu_dbm_open (char *name, DBM_FILE *db, int flags, int mode) { int f; switch (flags) { case MU_STREAM_CREAT: f = O_CREAT|O_TRUNC|O_RDWR; break; case MU_STREAM_READ: f = O_RDONLY; break; case MU_STREAM_RDWR: f = O_CREAT|O_RDWR; break; default: errno = EINVAL; return -1; } *db = dbm_open (name, f, mode); if (!*db) return -1; if (mu_fcheck_perm (dbm_dirfno (*db), mode) || mu_fcheck_perm (dbm_pagfno (*db), mode)) { dbm_close (*db); return 1; } return 0; } int mu_dbm_close (DBM_FILE db) { dbm_close(db); return 0; } int mu_dbm_fetch (DBM_FILE db, DBM_DATUM key, DBM_DATUM *ret) { *ret = dbm_fetch(db, key); return ret->dptr == NULL; } int mu_dbm_delete (DBM_FILE db, DBM_DATUM key) { return dbm_delete (db, key); } int mu_dbm_insert (DBM_FILE db, DBM_DATUM key, DBM_DATUM contents, int replace) { return dbm_store(db, key, contents, replace ? DBM_REPLACE : DBM_INSERT); } DBM_DATUM mu_dbm_firstkey (DBM_FILE db) { return dbm_firstkey (db); } DBM_DATUM mu_dbm_nextkey (DBM_FILE db, DBM_DATUM key) { return dbm_nextkey (db, key); } #elif defined(WITH_OLD_DBM) #define DB_SUFFIX ".pag" int mu_dbm_stat (char *name, struct stat *sb) { int rc; char *pfname = xmalloc (strlen (name) + sizeof DB_SUFFIX); strcat (strcpy (pfname, name), DB_SUFFIX); rc = stat (pfname, sb); free (pfname); return rc; } /*ARGSUSED*/ int mu_dbm_open (char *name, DBM_FILE *db, int flags, int mode) { int f; switch (flags) { case MU_STREAM_CREAT: f = O_CREAT|O_TRUNC|O_RDWR; break; case MU_STREAM_READ: f = O_RDONLY; break; case MU_STREAM_RDWR: f = O_CREAT|O_RDWR; break; default: return -1; } if (f & O_CREAT) { char *p; int fd; p = xmalloc(strlen(name)+5); strcat(strcpy(p, name), ".pag"); fd = open(p, f, mode); free(p); if (fd < 0) return -1; close(fd); p = xmalloc(strlen(name)+5); strcat(strcpy(p, name), ".dir"); fd = open(p, f, mode); free(p); if (fd < 0) return -1; close(fd); } return dbminit(name); } /*ARGSUSED*/ int mu_dbm_close (DBM_FILE db) { dbmclose(); return 0; } /*ARGSUSED*/ int mu_dbm_fetch (DBM_FILE db, DBM_DATUM key, DBM_DATUM *ret) { *ret = fetch(key); return ret->dptr == NULL; } int mu_dbm_delete (DBM_FILE db, DBM_DATUM key) { return delete (key); } int mu_dbm_insert (DBM_FILE db, DBM_DATUM key, DBM_DATUM contents, int replace) { return store(key, contents); } DBM_DATUM mu_dbm_firstkey (DBM_FILE db) { return firstkey (); } DBM_DATUM mu_dbm_nextkey (DBM_FILE db, DBM_DATUM key) { return nextkey (key); } #endif