dbwrap: Convert backend store to storev
[kai/samba-autobuild/.git] / lib / dbwrap / dbwrap_tdb.c
1 /*
2    Unix SMB/CIFS implementation.
3    Database interface wrapper around tdb
4    Copyright (C) Volker Lendecke 2005-2007
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "dbwrap/dbwrap.h"
22 #include "dbwrap/dbwrap_private.h"
23 #include "dbwrap/dbwrap_tdb.h"
24 #include "lib/tdb_wrap/tdb_wrap.h"
25 #include "lib/util/util_tdb.h"
26 #include "system/filesys.h"
27 #include "lib/param/param.h"
28
29 struct db_tdb_ctx {
30         struct tdb_wrap *wtdb;
31
32         struct {
33                 dev_t dev;
34                 ino_t ino;
35         } id;
36 };
37
38 static NTSTATUS db_tdb_storev(struct db_record *rec,
39                               const TDB_DATA *dbufs, int num_dbufs, int flag);
40 static NTSTATUS db_tdb_delete(struct db_record *rec);
41
42 static void db_tdb_log_key(const char *prefix, TDB_DATA key)
43 {
44         size_t len;
45         char *keystr;
46         TALLOC_CTX *frame;
47         if (DEBUGLEVEL < 10) {
48                 return;
49         }
50         frame = talloc_stackframe();
51         len = key.dsize;
52         if (DEBUGLEVEL == 10) {
53                 /*
54                  * Only fully spam at debuglevel > 10
55                  */
56                 len = MIN(10, key.dsize);
57         }
58         keystr = hex_encode_talloc(frame, (unsigned char *)(key.dptr),
59                                    len);
60         DEBUG(10, ("%s key %s\n", prefix, keystr));
61         TALLOC_FREE(frame);
62 }
63
64 static int db_tdb_record_destr(struct db_record* data)
65 {
66         struct db_tdb_ctx *ctx =
67                 talloc_get_type_abort(data->private_data, struct db_tdb_ctx);
68
69         db_tdb_log_key("Unlocking", data->key);
70         tdb_chainunlock(ctx->wtdb->tdb, data->key);
71         return 0;
72 }
73
74 struct tdb_fetch_locked_state {
75         TALLOC_CTX *mem_ctx;
76         struct db_record *result;
77 };
78
79 static int db_tdb_fetchlock_parse(TDB_DATA key, TDB_DATA data,
80                                   void *private_data)
81 {
82         struct tdb_fetch_locked_state *state =
83                 (struct tdb_fetch_locked_state *)private_data;
84         struct db_record *result;
85
86         result = (struct db_record *)talloc_size(
87                 state->mem_ctx,
88                 sizeof(struct db_record) + key.dsize + data.dsize);
89
90         if (result == NULL) {
91                 return 0;
92         }
93         state->result = result;
94
95         result->key.dsize = key.dsize;
96         result->key.dptr = ((uint8_t *)result) + sizeof(struct db_record);
97         memcpy(result->key.dptr, key.dptr, key.dsize);
98
99         result->value.dsize = data.dsize;
100
101         if (data.dsize > 0) {
102                 result->value.dptr = result->key.dptr+key.dsize;
103                 memcpy(result->value.dptr, data.dptr, data.dsize);
104         }
105         else {
106                 result->value.dptr = NULL;
107         }
108
109         return 0;
110 }
111
112 static struct db_record *db_tdb_fetch_locked_internal(
113         struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
114 {
115         struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
116                                                        struct db_tdb_ctx);
117         struct tdb_fetch_locked_state state;
118
119         state.mem_ctx = mem_ctx;
120         state.result = NULL;
121
122         if ((tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_fetchlock_parse,
123                               &state) < 0) &&
124             (tdb_error(ctx->wtdb->tdb) != TDB_ERR_NOEXIST)) {
125                 tdb_chainunlock(ctx->wtdb->tdb, key);
126                 return NULL;
127         }
128
129         if (state.result == NULL) {
130                 db_tdb_fetchlock_parse(key, tdb_null, &state);
131         }
132
133         if (state.result == NULL) {
134                 tdb_chainunlock(ctx->wtdb->tdb, key);
135                 return NULL;
136         }
137
138         talloc_set_destructor(state.result, db_tdb_record_destr);
139
140         state.result->private_data = ctx;
141         state.result->storev = db_tdb_storev;
142         state.result->delete_rec = db_tdb_delete;
143
144         DEBUG(10, ("Allocated locked data 0x%p\n", state.result));
145
146         return state.result;
147 }
148
149 static struct db_record *db_tdb_fetch_locked(
150         struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
151 {
152         struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
153                                                        struct db_tdb_ctx);
154
155         db_tdb_log_key("Locking", key);
156         if (tdb_chainlock(ctx->wtdb->tdb, key) != 0) {
157                 DEBUG(3, ("tdb_chainlock failed\n"));
158                 return NULL;
159         }
160         return db_tdb_fetch_locked_internal(db, mem_ctx, key);
161 }
162
163 static struct db_record *db_tdb_try_fetch_locked(
164         struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
165 {
166         struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
167                                                        struct db_tdb_ctx);
168
169         db_tdb_log_key("Trying to lock", key);
170         if (tdb_chainlock_nonblock(ctx->wtdb->tdb, key) != 0) {
171                 DEBUG(3, ("tdb_chainlock_nonblock failed\n"));
172                 return NULL;
173         }
174         return db_tdb_fetch_locked_internal(db, mem_ctx, key);
175 }
176
177 static int db_tdb_exists(struct db_context *db, TDB_DATA key)
178 {
179         struct db_tdb_ctx *ctx = talloc_get_type_abort(
180                 db->private_data, struct db_tdb_ctx);
181         return tdb_exists(ctx->wtdb->tdb, key);
182 }
183
184 static int db_tdb_wipe(struct db_context *db)
185 {
186         struct db_tdb_ctx *ctx = talloc_get_type_abort(
187                 db->private_data, struct db_tdb_ctx);
188         return tdb_wipe_all(ctx->wtdb->tdb);
189 }
190
191 static int db_tdb_check(struct db_context *db)
192 {
193         struct db_tdb_ctx *ctx = talloc_get_type_abort(
194                 db->private_data, struct db_tdb_ctx);
195         return tdb_check(ctx->wtdb->tdb, NULL, NULL);
196 }
197
198 struct db_tdb_parse_state {
199         void (*parser)(TDB_DATA key, TDB_DATA data,
200                        void *private_data);
201         void *private_data;
202 };
203
204 /*
205  * tdb_parse_record expects a parser returning int, mixing up tdb and
206  * parser errors. Wrap around that by always returning 0 and have
207  * dbwrap_parse_record expect a parser returning void.
208  */
209
210 static int db_tdb_parser(TDB_DATA key, TDB_DATA data, void *private_data)
211 {
212         struct db_tdb_parse_state *state =
213                 (struct db_tdb_parse_state *)private_data;
214         state->parser(key, data, state->private_data);
215         return 0;
216 }
217
218 static NTSTATUS db_tdb_parse(struct db_context *db, TDB_DATA key,
219                              void (*parser)(TDB_DATA key, TDB_DATA data,
220                                            void *private_data),
221                              void *private_data)
222 {
223         struct db_tdb_ctx *ctx = talloc_get_type_abort(
224                 db->private_data, struct db_tdb_ctx);
225         struct db_tdb_parse_state state;
226         int ret;
227
228         state.parser = parser;
229         state.private_data = private_data;
230
231         ret = tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_parser, &state);
232
233         if (ret != 0) {
234                 return map_nt_error_from_tdb(tdb_error(ctx->wtdb->tdb));
235         }
236         return NT_STATUS_OK;
237 }
238
239 static NTSTATUS db_tdb_storev(struct db_record *rec,
240                               const TDB_DATA *dbufs, int num_dbufs, int flag)
241 {
242         struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
243                                                        struct db_tdb_ctx);
244         int ret;
245
246         /*
247          * This has a bug: We need to replace rec->value for correct
248          * operation, but right now brlock and locking don't use the value
249          * anymore after it was stored.
250          */
251
252         ret = tdb_storev(ctx->wtdb->tdb, rec->key, dbufs, num_dbufs, flag);
253         return (ret == 0) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
254 }
255
256 static NTSTATUS db_tdb_delete(struct db_record *rec)
257 {
258         struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
259                                                        struct db_tdb_ctx);
260
261         if (tdb_delete(ctx->wtdb->tdb, rec->key) == 0) {
262                 return NT_STATUS_OK;
263         }
264
265         if (tdb_error(ctx->wtdb->tdb) == TDB_ERR_NOEXIST) {
266                 return NT_STATUS_NOT_FOUND;
267         }
268
269         return NT_STATUS_UNSUCCESSFUL;
270 }
271
272 struct db_tdb_traverse_ctx {
273         struct db_context *db;
274         int (*f)(struct db_record *rec, void *private_data);
275         void *private_data;
276 };
277
278 static int db_tdb_traverse_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
279                                 void *private_data)
280 {
281         struct db_tdb_traverse_ctx *ctx =
282                 (struct db_tdb_traverse_ctx *)private_data;
283         struct db_record rec;
284
285         rec.key = kbuf;
286         rec.value = dbuf;
287         rec.storev = db_tdb_storev;
288         rec.delete_rec = db_tdb_delete;
289         rec.private_data = ctx->db->private_data;
290         rec.db = ctx->db;
291
292         return ctx->f(&rec, ctx->private_data);
293 }
294
295 static int db_tdb_traverse(struct db_context *db,
296                            int (*f)(struct db_record *rec, void *private_data),
297                            void *private_data)
298 {
299         struct db_tdb_ctx *db_ctx =
300                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
301         struct db_tdb_traverse_ctx ctx;
302
303         ctx.db = db;
304         ctx.f = f;
305         ctx.private_data = private_data;
306         return tdb_traverse(db_ctx->wtdb->tdb, db_tdb_traverse_func, &ctx);
307 }
308
309 static NTSTATUS db_tdb_storev_deny(struct db_record *rec,
310                                    const TDB_DATA *dbufs, int num_dbufs,
311                                    int flag)
312 {
313         return NT_STATUS_MEDIA_WRITE_PROTECTED;
314 }
315
316 static NTSTATUS db_tdb_delete_deny(struct db_record *rec)
317 {
318         return NT_STATUS_MEDIA_WRITE_PROTECTED;
319 }
320
321 static int db_tdb_traverse_read_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
322                                 void *private_data)
323 {
324         struct db_tdb_traverse_ctx *ctx =
325                 (struct db_tdb_traverse_ctx *)private_data;
326         struct db_record rec;
327
328         rec.key = kbuf;
329         rec.value = dbuf;
330         rec.storev = db_tdb_storev_deny;
331         rec.delete_rec = db_tdb_delete_deny;
332         rec.private_data = ctx->db->private_data;
333         rec.db = ctx->db;
334
335         return ctx->f(&rec, ctx->private_data);
336 }
337
338 static int db_tdb_traverse_read(struct db_context *db,
339                            int (*f)(struct db_record *rec, void *private_data),
340                            void *private_data)
341 {
342         struct db_tdb_ctx *db_ctx =
343                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
344         struct db_tdb_traverse_ctx ctx;
345
346         ctx.db = db;
347         ctx.f = f;
348         ctx.private_data = private_data;
349         return tdb_traverse_read(db_ctx->wtdb->tdb, db_tdb_traverse_read_func, &ctx);
350 }
351
352 static int db_tdb_get_seqnum(struct db_context *db)
353
354 {
355         struct db_tdb_ctx *db_ctx =
356                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
357         return tdb_get_seqnum(db_ctx->wtdb->tdb);
358 }
359
360 static int db_tdb_transaction_start(struct db_context *db)
361 {
362         struct db_tdb_ctx *db_ctx =
363                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
364         return tdb_transaction_start(db_ctx->wtdb->tdb) ? -1 : 0;
365 }
366
367 static NTSTATUS db_tdb_transaction_start_nonblock(struct db_context *db)
368 {
369         struct db_tdb_ctx *db_ctx =
370                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
371         int ret;
372
373         ret = tdb_transaction_start_nonblock(db_ctx->wtdb->tdb);
374         if (ret != 0) {
375                 return map_nt_error_from_tdb(tdb_error(db_ctx->wtdb->tdb));
376         }
377         return NT_STATUS_OK;
378 }
379
380 static int db_tdb_transaction_commit(struct db_context *db)
381 {
382         struct db_tdb_ctx *db_ctx =
383                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
384         return tdb_transaction_commit(db_ctx->wtdb->tdb) ? -1 : 0;
385 }
386
387 static int db_tdb_transaction_cancel(struct db_context *db)
388 {
389         struct db_tdb_ctx *db_ctx =
390                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
391         tdb_transaction_cancel(db_ctx->wtdb->tdb);
392         return 0;
393 }
394
395 static size_t db_tdb_id(struct db_context *db, uint8_t *id, size_t idlen)
396 {
397         struct db_tdb_ctx *db_ctx =
398                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
399
400         if (idlen >= sizeof(db_ctx->id)) {
401                 memcpy(id, &db_ctx->id, sizeof(db_ctx->id));
402         }
403
404         return sizeof(db_ctx->id);
405 }
406
407 struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
408                                const char *name,
409                                int hash_size, int tdb_flags,
410                                int open_flags, mode_t mode,
411                                enum dbwrap_lock_order lock_order,
412                                uint64_t dbwrap_flags)
413 {
414         struct db_context *result = NULL;
415         struct db_tdb_ctx *db_tdb;
416         struct stat st;
417
418         result = talloc_zero(mem_ctx, struct db_context);
419         if (result == NULL) {
420                 DEBUG(0, ("talloc failed\n"));
421                 goto fail;
422         }
423
424         result->private_data = db_tdb = talloc(result, struct db_tdb_ctx);
425         if (db_tdb == NULL) {
426                 DEBUG(0, ("talloc failed\n"));
427                 goto fail;
428         }
429         result->lock_order = lock_order;
430
431         db_tdb->wtdb = tdb_wrap_open(db_tdb, name, hash_size, tdb_flags,
432                                      open_flags, mode);
433         if (db_tdb->wtdb == NULL) {
434                 DEBUG(3, ("Could not open tdb: %s\n", strerror(errno)));
435                 goto fail;
436         }
437
438         ZERO_STRUCT(db_tdb->id);
439
440         if (fstat(tdb_fd(db_tdb->wtdb->tdb), &st) == -1) {
441                 DEBUG(3, ("fstat failed: %s\n", strerror(errno)));
442                 goto fail;
443         }
444         db_tdb->id.dev = st.st_dev;
445         db_tdb->id.ino = st.st_ino;
446
447         result->fetch_locked = db_tdb_fetch_locked;
448         result->try_fetch_locked = db_tdb_try_fetch_locked;
449         result->traverse = db_tdb_traverse;
450         result->traverse_read = db_tdb_traverse_read;
451         result->parse_record = db_tdb_parse;
452         result->get_seqnum = db_tdb_get_seqnum;
453         result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
454         result->transaction_start = db_tdb_transaction_start;
455         result->transaction_start_nonblock = db_tdb_transaction_start_nonblock;
456         result->transaction_commit = db_tdb_transaction_commit;
457         result->transaction_cancel = db_tdb_transaction_cancel;
458         result->exists = db_tdb_exists;
459         result->wipe = db_tdb_wipe;
460         result->id = db_tdb_id;
461         result->check = db_tdb_check;
462         result->name = tdb_name(db_tdb->wtdb->tdb);
463         return result;
464
465  fail:
466         TALLOC_FREE(result);
467         return NULL;
468 }