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