NeoMutt  2023-05-17-56-ga67199
Teaching an old dog new tricks
DOXYGEN
bdb.c
Go to the documentation of this file.
1
33#include "config.h"
34#include <db.h>
35#include <errno.h>
36#include <fcntl.h>
37#include <stdbool.h>
38#include <stdint.h>
39#include <sys/stat.h>
40#include <unistd.h>
41#include "mutt/lib.h"
42#include "lib.h"
43
48{
49 DB_ENV *env;
50 DB *db;
51 int fd;
53};
54
61static void dbt_init(DBT *dbt, void *data, size_t len)
62{
63 dbt->data = data;
64 dbt->size = len;
65 dbt->ulen = len;
66 dbt->dlen = 0;
67 dbt->doff = 0;
68 dbt->flags = DB_DBT_USERMEM;
69}
70
75static void dbt_empty_init(DBT *dbt)
76{
77 dbt->data = NULL;
78 dbt->size = 0;
79 dbt->ulen = 0;
80 dbt->dlen = 0;
81 dbt->doff = 0;
82 dbt->flags = 0;
83}
84
88static void *store_bdb_open(const char *path)
89{
90 if (!path)
91 return NULL;
92
93 struct stat st = { 0 };
94 int rc;
95 uint32_t createflags = DB_CREATE;
96
97 struct StoreDbCtx *ctx = mutt_mem_malloc(sizeof(struct StoreDbCtx));
98
99 const int pagesize = 512;
100
101 ctx->lockfile = buf_make(128);
102 buf_printf(&ctx->lockfile, "%s-lock-hack", path);
103
104 ctx->fd = open(buf_string(&ctx->lockfile), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
105 if (ctx->fd < 0)
106 {
107 FREE(&ctx);
108 return NULL;
109 }
110
111 if (mutt_file_lock(ctx->fd, true, true))
112 goto fail_close;
113
114 rc = db_env_create(&ctx->env, 0);
115 if (rc)
116 goto fail_unlock;
117
118 rc = (*ctx->env->open)(ctx->env, NULL, DB_INIT_MPOOL | DB_CREATE | DB_PRIVATE, 0600);
119 if (rc)
120 goto fail_env;
121
122 ctx->db = NULL;
123 rc = db_create(&ctx->db, ctx->env, 0);
124 if (rc)
125 goto fail_env;
126
127 if ((stat(path, &st) != 0) && (errno == ENOENT))
128 {
129 createflags |= DB_EXCL;
130 ctx->db->set_pagesize(ctx->db, pagesize);
131 }
132
133 rc = (*ctx->db->open)(ctx->db, NULL, path, NULL, DB_BTREE, createflags, 0600);
134 if (rc)
135 goto fail_db;
136
137 return ctx;
138
139fail_db:
140 ctx->db->close(ctx->db, 0);
141fail_env:
142 ctx->env->close(ctx->env, 0);
143fail_unlock:
144 mutt_file_unlock(ctx->fd);
145fail_close:
146 close(ctx->fd);
147 unlink(buf_string(&ctx->lockfile));
148 buf_dealloc(&ctx->lockfile);
149 FREE(&ctx);
150
151 return NULL;
152}
153
157static void *store_bdb_fetch(void *store, const char *key, size_t klen, size_t *vlen)
158{
159 if (!store)
160 return NULL;
161
162 DBT dkey;
163 DBT data;
164
165 struct StoreDbCtx *ctx = store;
166
167 dbt_init(&dkey, (void *) key, klen);
168 dbt_empty_init(&data);
169 data.flags = DB_DBT_MALLOC;
170
171 ctx->db->get(ctx->db, NULL, &dkey, &data, 0);
172
173 *vlen = data.size;
174 return data.data;
175}
176
180static void store_bdb_free(void *store, void **ptr)
181{
182 FREE(ptr);
183}
184
188static int store_bdb_store(void *store, const char *key, size_t klen, void *value, size_t vlen)
189{
190 if (!store)
191 return -1;
192
193 DBT dkey;
194 DBT databuf;
195
196 struct StoreDbCtx *ctx = store;
197
198 dbt_init(&dkey, (void *) key, klen);
199 dbt_empty_init(&databuf);
200 databuf.flags = DB_DBT_USERMEM;
201 databuf.data = value;
202 databuf.size = vlen;
203 databuf.ulen = vlen;
204
205 return ctx->db->put(ctx->db, NULL, &dkey, &databuf, 0);
206}
207
211static int store_bdb_delete_record(void *store, const char *key, size_t klen)
212{
213 if (!store)
214 return -1;
215
216 DBT dkey;
217
218 struct StoreDbCtx *ctx = store;
219
220 dbt_init(&dkey, (void *) key, klen);
221 return ctx->db->del(ctx->db, NULL, &dkey, 0);
222}
223
227static void store_bdb_close(void **ptr)
228{
229 if (!ptr || !*ptr)
230 return;
231
232 struct StoreDbCtx *db = *ptr;
233
234 db->db->close(db->db, 0);
235 db->env->close(db->env, 0);
236 mutt_file_unlock(db->fd);
237 close(db->fd);
238 unlink(buf_string(&db->lockfile));
239 buf_dealloc(&db->lockfile);
240 FREE(ptr);
241}
242
246static const char *store_bdb_version(void)
247{
248 return DB_VERSION_STRING;
249}
250
static void dbt_empty_init(DBT *dbt)
Initialise an empty BDB context.
Definition: bdb.c:75
static void dbt_init(DBT *dbt, void *data, size_t len)
Initialise a BDB context.
Definition: bdb.c:61
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:173
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:383
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:70
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:90
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition: file.c:1218
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition: file.c:1266
static void store_bdb_close(void **ptr)
Implements StoreOps::close() -.
Definition: bdb.c:227
static int store_bdb_delete_record(void *store, const char *key, size_t klen)
Implements StoreOps::delete_record() -.
Definition: bdb.c:211
static void * store_bdb_fetch(void *store, const char *key, size_t klen, size_t *vlen)
Implements StoreOps::fetch() -.
Definition: bdb.c:157
static void store_bdb_free(void *store, void **ptr)
Implements StoreOps::free() -.
Definition: bdb.c:180
static void * store_bdb_open(const char *path)
Implements StoreOps::open() -.
Definition: bdb.c:88
static int store_bdb_store(void *store, const char *key, size_t klen, void *value, size_t vlen)
Implements StoreOps::store() -.
Definition: bdb.c:188
static const char * store_bdb_version(void)
Implements StoreOps::version() -.
Definition: bdb.c:246
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:43
Convenience wrapper for the library headers.
Key value store.
#define STORE_BACKEND_OPS(_name)
Definition: lib.h:159
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
Berkeley DB context.
Definition: bdb.c:48
DB * db
Definition: bdb.c:50
int fd
Definition: bdb.c:51
struct Buffer lockfile
Definition: bdb.c:52
DB_ENV * env
Definition: bdb.c:49