/* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 2011-2021 Free Software Foundation, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include #include "mudbm.h" #if defined(WITH_NDBM) #include static int _ndbm_file_safety (mu_dbm_file_t db, int mode, uid_t owner) { int rc; char *name; rc = mu_asprintf (&name, "%s.pag", db->db_name); if (rc) return rc; rc = mu_file_safety_check (name, mode, owner, NULL); if (rc) { free (name); return rc; } strcpy (name + strlen (name) - 3, "dir"); rc = mu_file_safety_check (name, mode, owner, NULL); free (name); return rc; } #ifndef HAVE_DBM_PAGFNO # ifdef HAVE_DBM_DIRFNO # undef dbm_pagfno # define dbm_pagfno dbm_dirfno # else # error "neither dbm_pagfno nor dbm_dirfno available" # endif #endif #ifndef HAVE_DBM_DIRFNO # ifdef HAVE_DBM_PAGFNO # undef dbm_dirfno # define dbm_dirfno dbm_pagfno # else # error "neither dbm_pagfno nor dbm_dirfno available" # endif #endif int _ndbm_get_fd (mu_dbm_file_t db, int *pag, int *dir) { DBM *dbm = db->db_descr; *pag = dbm_pagfno (dbm); if (dir) *dir = dbm_dirfno (dbm); return 0; } static int _ndbm_open (mu_dbm_file_t db, int flags, int mode) { int f; DBM *dbm; 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; } dbm = dbm_open (db->db_name, f, mode); if (!dbm) return MU_ERR_FAILURE; db->db_descr = dbm; return 0; } static int _ndbm_close (mu_dbm_file_t db) { if (db->db_descr) { dbm_close ((DBM *) db->db_descr); db->db_descr = NULL; } return 0; } static int _ndbm_conv_datum (mu_dbm_file_t db, struct mu_dbm_datum *ret, datum content) { ret->mu_dptr = malloc (content.dsize); if (!ret->mu_dptr) return errno; memcpy (ret->mu_dptr, content.dptr, content.dsize); ret->mu_dsize = content.dsize; ret->mu_sys = db->db_sys; return 0; } static int _ndbm_fetch (mu_dbm_file_t db, struct mu_dbm_datum const *key, struct mu_dbm_datum *ret) { datum keydat, content; keydat.dptr = key->mu_dptr; keydat.dsize = key->mu_dsize; errno = 0; content = dbm_fetch (db->db_descr, keydat); mu_dbm_datum_free (ret); if (content.dptr == NULL) return MU_ERR_NOENT; return _ndbm_conv_datum (db, ret, content); } static int _ndbm_store (mu_dbm_file_t db, struct mu_dbm_datum const *key, struct mu_dbm_datum const *contents, int replace) { DBM *dbm = db->db_descr; datum keydat, condat; keydat.dptr = key->mu_dptr; keydat.dsize = key->mu_dsize; condat.dptr = contents->mu_dptr; condat.dsize = contents->mu_dsize; errno = 0; switch (dbm_store (dbm, keydat, condat, replace ? DBM_REPLACE : DBM_INSERT)) { case 0: break; case 1: return MU_ERR_EXISTS; case -1: db->db_errno.n = errno; return MU_ERR_FAILURE; } return 0; } static int _ndbm_delete (mu_dbm_file_t db, struct mu_dbm_datum const *key) { DBM *dbm = db->db_descr; datum keydat; keydat.dptr = key->mu_dptr; keydat.dsize = key->mu_dsize; errno = 0; switch (dbm_delete (dbm, keydat)) { case 0: break; case 1: return MU_ERR_NOENT; case -1: db->db_errno.n = errno; return MU_ERR_FAILURE; } return 0; } static int _ndbm_firstkey (mu_dbm_file_t db, struct mu_dbm_datum *ret) { DBM *dbm = db->db_descr; datum keydat; errno = 0; keydat = dbm_firstkey (dbm); if (keydat.dptr == NULL) return MU_ERR_NOENT; return _ndbm_conv_datum (db, ret, keydat); } static int _ndbm_nextkey (mu_dbm_file_t db, struct mu_dbm_datum *ret) { DBM *dbm = db->db_descr; datum keydat; keydat = dbm_nextkey (dbm); if (keydat.dptr == NULL) return MU_ERR_NOENT; return _ndbm_conv_datum (db, ret, keydat); } static void _ndbm_datum_free (struct mu_dbm_datum *datum) { free (datum->mu_dptr); } static char const * _ndbm_strerror (mu_dbm_file_t db) { return strerror (db->db_errno.n); } struct mu_dbm_impl _mu_dbm_ndbm = { "ndbm", _ndbm_file_safety, _ndbm_get_fd, _ndbm_open, _ndbm_close, _ndbm_fetch, _ndbm_store, _ndbm_delete, _ndbm_firstkey, _ndbm_nextkey, _ndbm_datum_free, _ndbm_strerror }; #endif