c30bedee77548c54f00433f402da235b578551b9
[metze/samba/wip.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 #include "libcli/util/error.h"
29
30 struct db_tdb_ctx {
31         struct tdb_wrap *wtdb;
32
33         struct {
34                 dev_t dev;
35                 ino_t ino;
36         } id;
37 };
38
39 static NTSTATUS db_tdb_storev(struct db_record *rec,
40                               const TDB_DATA *dbufs, int num_dbufs, int flag);
41 static NTSTATUS db_tdb_delete(struct db_record *rec);
42
43 static void db_tdb_log_key(const char *prefix, TDB_DATA key)
44 {
45         size_t len;
46         char *keystr;
47         TALLOC_CTX *frame;
48         if (DEBUGLEVEL < 10) {
49                 return;
50         }
51         frame = talloc_stackframe();
52         len = key.dsize;
53         if (DEBUGLEVEL == 10) {
54                 /*
55                  * Only fully spam at debuglevel > 10
56                  */
57                 len = MIN(10, key.dsize);
58         }
59         keystr = hex_encode_talloc(frame, (unsigned char *)(key.dptr),
60                                    len);
61         DEBUG(10, ("%s key %s\n", prefix, keystr));
62         TALLOC_FREE(frame);
63 }
64
65 static int db_tdb_record_destr(struct db_record* data)
66 {
67         struct db_tdb_ctx *ctx =
68                 talloc_get_type_abort(data->private_data, struct db_tdb_ctx);
69
70         db_tdb_log_key("Unlocking", data->key);
71         tdb_chainunlock(ctx->wtdb->tdb, data->key);
72         return 0;
73 }
74
75 struct tdb_fetch_locked_state {
76         TALLOC_CTX *mem_ctx;
77         struct db_record *result;
78 };
79
80 static int db_tdb_fetchlock_parse(TDB_DATA key, TDB_DATA data,
81                                   void *private_data)
82 {
83         struct tdb_fetch_locked_state *state =
84                 (struct tdb_fetch_locked_state *)private_data;
85         struct db_record *result;
86
87         result = (struct db_record *)talloc_size(
88                 state->mem_ctx,
89                 sizeof(struct db_record) + key.dsize + data.dsize);
90
91         if (result == NULL) {
92                 return 0;
93         }
94         state->result = result;
95
96         result->key.dsize = key.dsize;
97         result->key.dptr = ((uint8_t *)result) + sizeof(struct db_record);
98         memcpy(result->key.dptr, key.dptr, key.dsize);
99
100         result->value.dsize = data.dsize;
101
102         if (data.dsize > 0) {
103                 result->value.dptr = result->key.dptr+key.dsize;
104                 memcpy(result->value.dptr, data.dptr, data.dsize);
105         }
106         else {
107                 result->value.dptr = NULL;
108         }
109
110         return 0;
111 }
112
113 static struct db_record *db_tdb_fetch_locked_internal(
114         struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
115 {
116         struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
117                                                        struct db_tdb_ctx);
118         struct tdb_fetch_locked_state state;
119
120         state.mem_ctx = mem_ctx;
121         state.result = NULL;
122
123         if ((tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_fetchlock_parse,
124                               &state) < 0) &&
125             (tdb_error(ctx->wtdb->tdb) != TDB_ERR_NOEXIST)) {
126                 tdb_chainunlock(ctx->wtdb->tdb, key);
127                 return NULL;
128         }
129
130         if (state.result == NULL) {
131                 db_tdb_fetchlock_parse(key, tdb_null, &state);
132         }
133
134         if (state.result == NULL) {
135                 tdb_chainunlock(ctx->wtdb->tdb, key);
136                 return NULL;
137         }
138
139         talloc_set_destructor(state.result, db_tdb_record_destr);
140
141         state.result->private_data = ctx;
142         state.result->storev = db_tdb_storev;
143         state.result->delete_rec = db_tdb_delete;
144
145         DEBUG(10, ("Allocated locked data 0x%p\n", state.result));
146
147         return state.result;
148 }
149
150 static struct db_record *db_tdb_fetch_locked(
151         struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
152 {
153         struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
154                                                        struct db_tdb_ctx);
155
156         db_tdb_log_key("Locking", key);
157         if (tdb_chainlock(ctx->wtdb->tdb, key) != 0) {
158                 DEBUG(3, ("tdb_chainlock failed\n"));
159                 return NULL;
160         }
161         return db_tdb_fetch_locked_internal(db, mem_ctx, key);
162 }
163
164 static struct db_record *db_tdb_try_fetch_locked(
165         struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
166 {
167         struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
168                                                        struct db_tdb_ctx);
169
170         db_tdb_log_key("Trying to lock", key);
171         if (tdb_chainlock_nonblock(ctx->wtdb->tdb, key) != 0) {
172                 DEBUG(3, ("tdb_chainlock_nonblock failed\n"));
173                 return NULL;
174         }
175         return db_tdb_fetch_locked_internal(db, mem_ctx, key);
176 }
177
178 static NTSTATUS db_tdb_do_locked(struct db_context *db, TDB_DATA key,
179                                  void (*fn)(struct db_record *rec,
180                                             void *private_data),
181                                  void *private_data)
182 {
183         struct db_tdb_ctx *ctx = talloc_get_type_abort(
184                 db->private_data, struct db_tdb_ctx);
185         uint8_t *buf = NULL;
186         struct db_record rec;
187         int ret;
188
189         ret = tdb_chainlock(ctx->wtdb->tdb, key);
190         if (ret == -1) {
191                 enum TDB_ERROR err = tdb_error(ctx->wtdb->tdb);
192                 DBG_DEBUG("tdb_chainlock failed: %s\n",
193                           tdb_errorstr(ctx->wtdb->tdb));
194                 return map_nt_error_from_tdb(err);
195         }
196
197         ret = tdb_fetch_talloc(ctx->wtdb->tdb, key, ctx, &buf);
198
199         if ((ret != 0) && (ret != ENOENT)) {
200                 DBG_DEBUG("tdb_fetch_talloc failed: %s\n",
201                           strerror(errno));
202                 tdb_chainunlock(ctx->wtdb->tdb, key);
203                 return map_nt_error_from_unix_common(ret);
204         }
205
206         rec = (struct db_record) {
207                 .db = db, .key = key,
208                 .value = (struct TDB_DATA) { .dptr = buf,
209                                              .dsize = talloc_get_size(buf) },
210                 .storev = db_tdb_storev, .delete_rec = db_tdb_delete,
211                 .private_data = ctx
212         };
213
214         fn(&rec, private_data);
215
216         talloc_free(buf);
217
218         tdb_chainunlock(ctx->wtdb->tdb, key);
219
220         return NT_STATUS_OK;
221 }
222
223 static int db_tdb_exists(struct db_context *db, TDB_DATA key)
224 {
225         struct db_tdb_ctx *ctx = talloc_get_type_abort(
226                 db->private_data, struct db_tdb_ctx);
227         return tdb_exists(ctx->wtdb->tdb, key);
228 }
229
230 static int db_tdb_wipe(struct db_context *db)
231 {
232         struct db_tdb_ctx *ctx = talloc_get_type_abort(
233                 db->private_data, struct db_tdb_ctx);
234         return tdb_wipe_all(ctx->wtdb->tdb);
235 }
236
237 static int db_tdb_check(struct db_context *db)
238 {
239         struct db_tdb_ctx *ctx = talloc_get_type_abort(
240                 db->private_data, struct db_tdb_ctx);
241         return tdb_check(ctx->wtdb->tdb, NULL, NULL);
242 }
243
244 struct db_tdb_parse_state {
245         void (*parser)(TDB_DATA key, TDB_DATA data,
246                        void *private_data);
247         void *private_data;
248 };
249
250 /*
251  * tdb_parse_record expects a parser returning int, mixing up tdb and
252  * parser errors. Wrap around that by always returning 0 and have
253  * dbwrap_parse_record expect a parser returning void.
254  */
255
256 static int db_tdb_parser(TDB_DATA key, TDB_DATA data, void *private_data)
257 {
258         struct db_tdb_parse_state *state =
259                 (struct db_tdb_parse_state *)private_data;
260         state->parser(key, data, state->private_data);
261         return 0;
262 }
263
264 static NTSTATUS db_tdb_parse(struct db_context *db, TDB_DATA key,
265                              void (*parser)(TDB_DATA key, TDB_DATA data,
266                                            void *private_data),
267                              void *private_data)
268 {
269         struct db_tdb_ctx *ctx = talloc_get_type_abort(
270                 db->private_data, struct db_tdb_ctx);
271         struct db_tdb_parse_state state;
272         int ret;
273
274         state.parser = parser;
275         state.private_data = private_data;
276
277         ret = tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_parser, &state);
278
279         if (ret != 0) {
280                 return map_nt_error_from_tdb(tdb_error(ctx->wtdb->tdb));
281         }
282         return NT_STATUS_OK;
283 }
284
285 static NTSTATUS db_tdb_storev(struct db_record *rec,
286                               const TDB_DATA *dbufs, int num_dbufs, int flag)
287 {
288         struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
289                                                        struct db_tdb_ctx);
290         int ret;
291
292         /*
293          * This has a bug: We need to replace rec->value for correct
294          * operation, but right now brlock and locking don't use the value
295          * anymore after it was stored.
296          */
297
298         ret = tdb_storev(ctx->wtdb->tdb, rec->key, dbufs, num_dbufs, flag);
299         return (ret == 0) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
300 }
301
302 static NTSTATUS db_tdb_delete(struct db_record *rec)
303 {
304         struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
305                                                        struct db_tdb_ctx);
306
307         if (tdb_delete(ctx->wtdb->tdb, rec->key) == 0) {
308                 return NT_STATUS_OK;
309         }
310
311         if (tdb_error(ctx->wtdb->tdb) == TDB_ERR_NOEXIST) {
312                 return NT_STATUS_NOT_FOUND;
313         }
314
315         return NT_STATUS_UNSUCCESSFUL;
316 }
317
318 struct db_tdb_traverse_ctx {
319         struct db_context *db;
320         int (*f)(struct db_record *rec, void *private_data);
321         void *private_data;
322 };
323
324 static int db_tdb_traverse_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
325                                 void *private_data)
326 {
327         struct db_tdb_traverse_ctx *ctx =
328                 (struct db_tdb_traverse_ctx *)private_data;
329         struct db_record rec;
330
331         rec.key = kbuf;
332         rec.value = dbuf;
333         rec.storev = db_tdb_storev;
334         rec.delete_rec = db_tdb_delete;
335         rec.private_data = ctx->db->private_data;
336         rec.db = ctx->db;
337
338         return ctx->f(&rec, ctx->private_data);
339 }
340
341 static int db_tdb_traverse(struct db_context *db,
342                            int (*f)(struct db_record *rec, void *private_data),
343                            void *private_data)
344 {
345         struct db_tdb_ctx *db_ctx =
346                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
347         struct db_tdb_traverse_ctx ctx;
348
349         ctx.db = db;
350         ctx.f = f;
351         ctx.private_data = private_data;
352         return tdb_traverse(db_ctx->wtdb->tdb, db_tdb_traverse_func, &ctx);
353 }
354
355 static NTSTATUS db_tdb_storev_deny(struct db_record *rec,
356                                    const TDB_DATA *dbufs, int num_dbufs,
357                                    int flag)
358 {
359         return NT_STATUS_MEDIA_WRITE_PROTECTED;
360 }
361
362 static NTSTATUS db_tdb_delete_deny(struct db_record *rec)
363 {
364         return NT_STATUS_MEDIA_WRITE_PROTECTED;
365 }
366
367 static int db_tdb_traverse_read_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
368                                 void *private_data)
369 {
370         struct db_tdb_traverse_ctx *ctx =
371                 (struct db_tdb_traverse_ctx *)private_data;
372         struct db_record rec;
373
374         rec.key = kbuf;
375         rec.value = dbuf;
376         rec.storev = db_tdb_storev_deny;
377         rec.delete_rec = db_tdb_delete_deny;
378         rec.private_data = ctx->db->private_data;
379         rec.db = ctx->db;
380
381         return ctx->f(&rec, ctx->private_data);
382 }
383
384 static int db_tdb_traverse_read(struct db_context *db,
385                            int (*f)(struct db_record *rec, void *private_data),
386                            void *private_data)
387 {
388         struct db_tdb_ctx *db_ctx =
389                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
390         struct db_tdb_traverse_ctx ctx;
391
392         ctx.db = db;
393         ctx.f = f;
394         ctx.private_data = private_data;
395         return tdb_traverse_read(db_ctx->wtdb->tdb, db_tdb_traverse_read_func, &ctx);
396 }
397
398 static int db_tdb_get_seqnum(struct db_context *db)
399
400 {
401         struct db_tdb_ctx *db_ctx =
402                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
403         return tdb_get_seqnum(db_ctx->wtdb->tdb);
404 }
405
406 static int db_tdb_transaction_start(struct db_context *db)
407 {
408         struct db_tdb_ctx *db_ctx =
409                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
410         return tdb_transaction_start(db_ctx->wtdb->tdb) ? -1 : 0;
411 }
412
413 static NTSTATUS db_tdb_transaction_start_nonblock(struct db_context *db)
414 {
415         struct db_tdb_ctx *db_ctx =
416                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
417         int ret;
418
419         ret = tdb_transaction_start_nonblock(db_ctx->wtdb->tdb);
420         if (ret != 0) {
421                 return map_nt_error_from_tdb(tdb_error(db_ctx->wtdb->tdb));
422         }
423         return NT_STATUS_OK;
424 }
425
426 static int db_tdb_transaction_commit(struct db_context *db)
427 {
428         struct db_tdb_ctx *db_ctx =
429                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
430         return tdb_transaction_commit(db_ctx->wtdb->tdb) ? -1 : 0;
431 }
432
433 static int db_tdb_transaction_cancel(struct db_context *db)
434 {
435         struct db_tdb_ctx *db_ctx =
436                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
437         tdb_transaction_cancel(db_ctx->wtdb->tdb);
438         return 0;
439 }
440
441 static size_t db_tdb_id(struct db_context *db, uint8_t *id, size_t idlen)
442 {
443         struct db_tdb_ctx *db_ctx =
444                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
445
446         if (idlen >= sizeof(db_ctx->id)) {
447                 memcpy(id, &db_ctx->id, sizeof(db_ctx->id));
448         }
449
450         return sizeof(db_ctx->id);
451 }
452
453 struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
454                                const char *name,
455                                int hash_size, int tdb_flags,
456                                int open_flags, mode_t mode,
457                                enum dbwrap_lock_order lock_order,
458                                uint64_t dbwrap_flags)
459 {
460         struct db_context *result = NULL;
461         struct db_tdb_ctx *db_tdb;
462         struct stat st;
463
464         result = talloc_zero(mem_ctx, struct db_context);
465         if (result == NULL) {
466                 DEBUG(0, ("talloc failed\n"));
467                 goto fail;
468         }
469
470         result->private_data = db_tdb = talloc(result, struct db_tdb_ctx);
471         if (db_tdb == NULL) {
472                 DEBUG(0, ("talloc failed\n"));
473                 goto fail;
474         }
475         result->lock_order = lock_order;
476
477         db_tdb->wtdb = tdb_wrap_open(db_tdb, name, hash_size, tdb_flags,
478                                      open_flags, mode);
479         if (db_tdb->wtdb == NULL) {
480                 DEBUG(3, ("Could not open tdb: %s\n", strerror(errno)));
481                 goto fail;
482         }
483
484         ZERO_STRUCT(db_tdb->id);
485
486         if (fstat(tdb_fd(db_tdb->wtdb->tdb), &st) == -1) {
487                 DEBUG(3, ("fstat failed: %s\n", strerror(errno)));
488                 goto fail;
489         }
490         db_tdb->id.dev = st.st_dev;
491         db_tdb->id.ino = st.st_ino;
492
493         result->fetch_locked = db_tdb_fetch_locked;
494         result->try_fetch_locked = db_tdb_try_fetch_locked;
495         result->do_locked = db_tdb_do_locked;
496         result->traverse = db_tdb_traverse;
497         result->traverse_read = db_tdb_traverse_read;
498         result->parse_record = db_tdb_parse;
499         result->get_seqnum = db_tdb_get_seqnum;
500         result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
501         result->transaction_start = db_tdb_transaction_start;
502         result->transaction_start_nonblock = db_tdb_transaction_start_nonblock;
503         result->transaction_commit = db_tdb_transaction_commit;
504         result->transaction_cancel = db_tdb_transaction_cancel;
505         result->exists = db_tdb_exists;
506         result->wipe = db_tdb_wipe;
507         result->id = db_tdb_id;
508         result->check = db_tdb_check;
509         result->name = tdb_name(db_tdb->wtdb->tdb);
510         return result;
511
512  fail:
513         TALLOC_FREE(result);
514         return NULL;
515 }