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