/* 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