tdb_wrap: Remove tdb_wrap_open_ again
[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 "ccan/str/str.h"
28 #include "lib/param/param.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_store(struct db_record *rec, TDB_DATA data, 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 = talloc_reference(state.result, ctx);
141         state.result->store = db_tdb_store;
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
178 static int db_tdb_exists(struct db_context *db, TDB_DATA key)
179 {
180         struct db_tdb_ctx *ctx = talloc_get_type_abort(
181                 db->private_data, struct db_tdb_ctx);
182         return tdb_exists(ctx->wtdb->tdb, key);
183 }
184
185 static int db_tdb_wipe(struct db_context *db)
186 {
187         struct db_tdb_ctx *ctx = talloc_get_type_abort(
188                 db->private_data, struct db_tdb_ctx);
189         return tdb_wipe_all(ctx->wtdb->tdb);
190 }
191
192 static int db_tdb_check(struct db_context *db)
193 {
194         struct db_tdb_ctx *ctx = talloc_get_type_abort(
195                 db->private_data, struct db_tdb_ctx);
196         return tdb_check(ctx->wtdb->tdb, NULL, NULL);
197 }
198
199 struct db_tdb_parse_state {
200         void (*parser)(TDB_DATA key, TDB_DATA data,
201                        void *private_data);
202         void *private_data;
203 };
204
205 /*
206  * tdb_parse_record expects a parser returning int, mixing up tdb and
207  * parser errors. Wrap around that by always returning 0 and have
208  * dbwrap_parse_record expect a parser returning void.
209  */
210
211 static int db_tdb_parser(TDB_DATA key, TDB_DATA data, void *private_data)
212 {
213         struct db_tdb_parse_state *state =
214                 (struct db_tdb_parse_state *)private_data;
215         state->parser(key, data, state->private_data);
216         return 0;
217 }
218
219 static NTSTATUS db_tdb_parse(struct db_context *db, TDB_DATA key,
220                              void (*parser)(TDB_DATA key, TDB_DATA data,
221                                            void *private_data),
222                              void *private_data)
223 {
224         struct db_tdb_ctx *ctx = talloc_get_type_abort(
225                 db->private_data, struct db_tdb_ctx);
226         struct db_tdb_parse_state state;
227         int ret;
228
229         state.parser = parser;
230         state.private_data = private_data;
231
232         ret = tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_parser, &state);
233
234         if (ret != 0) {
235                 return map_nt_error_from_tdb(tdb_error(ctx->wtdb->tdb));
236         }
237         return NT_STATUS_OK;
238 }
239
240 static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag)
241 {
242         struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
243                                                        struct db_tdb_ctx);
244
245         /*
246          * This has a bug: We need to replace rec->value for correct
247          * operation, but right now brlock and locking don't use the value
248          * anymore after it was stored.
249          */
250
251         return (tdb_store(ctx->wtdb->tdb, rec->key, data, flag) == 0) ?
252                 NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
253 }
254
255 static NTSTATUS db_tdb_delete(struct db_record *rec)
256 {
257         struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
258                                                        struct db_tdb_ctx);
259
260         if (tdb_delete(ctx->wtdb->tdb, rec->key) == 0) {
261                 return NT_STATUS_OK;
262         }
263
264         if (tdb_error(ctx->wtdb->tdb) == TDB_ERR_NOEXIST) {
265                 return NT_STATUS_NOT_FOUND;
266         }
267
268         return NT_STATUS_UNSUCCESSFUL;
269 }
270
271 struct db_tdb_traverse_ctx {
272         struct db_context *db;
273         int (*f)(struct db_record *rec, void *private_data);
274         void *private_data;
275 };
276
277 static int db_tdb_traverse_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
278                                 void *private_data)
279 {
280         struct db_tdb_traverse_ctx *ctx =
281                 (struct db_tdb_traverse_ctx *)private_data;
282         struct db_record rec;
283
284         rec.key = kbuf;
285         rec.value = dbuf;
286         rec.store = db_tdb_store;
287         rec.delete_rec = db_tdb_delete;
288         rec.private_data = ctx->db->private_data;
289         rec.db = ctx->db;
290
291         return ctx->f(&rec, ctx->private_data);
292 }
293
294 static int db_tdb_traverse(struct db_context *db,
295                            int (*f)(struct db_record *rec, void *private_data),
296                            void *private_data)
297 {
298         struct db_tdb_ctx *db_ctx =
299                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
300         struct db_tdb_traverse_ctx ctx;
301
302         ctx.db = db;
303         ctx.f = f;
304         ctx.private_data = private_data;
305         return tdb_traverse(db_ctx->wtdb->tdb, db_tdb_traverse_func, &ctx);
306 }
307
308 static NTSTATUS db_tdb_store_deny(struct db_record *rec, TDB_DATA data, int flag)
309 {
310         return NT_STATUS_MEDIA_WRITE_PROTECTED;
311 }
312
313 static NTSTATUS db_tdb_delete_deny(struct db_record *rec)
314 {
315         return NT_STATUS_MEDIA_WRITE_PROTECTED;
316 }
317
318 static int db_tdb_traverse_read_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
319                                 void *private_data)
320 {
321         struct db_tdb_traverse_ctx *ctx =
322                 (struct db_tdb_traverse_ctx *)private_data;
323         struct db_record rec;
324
325         rec.key = kbuf;
326         rec.value = dbuf;
327         rec.store = db_tdb_store_deny;
328         rec.delete_rec = db_tdb_delete_deny;
329         rec.private_data = ctx->db->private_data;
330         rec.db = ctx->db;
331
332         return ctx->f(&rec, ctx->private_data);
333 }
334
335 static int db_tdb_traverse_read(struct db_context *db,
336                            int (*f)(struct db_record *rec, void *private_data),
337                            void *private_data)
338 {
339         struct db_tdb_ctx *db_ctx =
340                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
341         struct db_tdb_traverse_ctx ctx;
342
343         ctx.db = db;
344         ctx.f = f;
345         ctx.private_data = private_data;
346         return tdb_traverse_read(db_ctx->wtdb->tdb, db_tdb_traverse_read_func, &ctx);
347 }
348
349 static int db_tdb_get_seqnum(struct db_context *db)
350
351 {
352         struct db_tdb_ctx *db_ctx =
353                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
354         return tdb_get_seqnum(db_ctx->wtdb->tdb);
355 }
356
357 static int db_tdb_transaction_start(struct db_context *db)
358 {
359         struct db_tdb_ctx *db_ctx =
360                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
361         return tdb_transaction_start(db_ctx->wtdb->tdb) ? -1 : 0;
362 }
363
364 static NTSTATUS db_tdb_transaction_start_nonblock(struct db_context *db)
365 {
366         struct db_tdb_ctx *db_ctx =
367                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
368         int ret;
369
370         ret = tdb_transaction_start_nonblock(db_ctx->wtdb->tdb);
371         if (ret != 0) {
372                 return map_nt_error_from_tdb(tdb_error(db_ctx->wtdb->tdb));
373         }
374         return NT_STATUS_OK;
375 }
376
377 static int db_tdb_transaction_commit(struct db_context *db)
378 {
379         struct db_tdb_ctx *db_ctx =
380                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
381         return tdb_transaction_commit(db_ctx->wtdb->tdb) ? -1 : 0;
382 }
383
384 static int db_tdb_transaction_cancel(struct db_context *db)
385 {
386         struct db_tdb_ctx *db_ctx =
387                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
388         tdb_transaction_cancel(db_ctx->wtdb->tdb);
389         return 0;
390 }
391
392 static void db_tdb_id(struct db_context *db, const uint8_t **id, size_t *idlen)
393 {
394         struct db_tdb_ctx *db_ctx =
395                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
396         *id = (uint8_t *)&db_ctx->id;
397         *idlen = sizeof(db_ctx->id);
398 }
399
400 struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
401                                struct loadparm_context *lp_ctx,
402                                const char *name,
403                                int hash_size, int tdb_flags,
404                                int open_flags, mode_t mode,
405                                enum dbwrap_lock_order lock_order,
406                                uint64_t dbrwap_flags)
407 {
408         struct db_context *result = NULL;
409         struct db_tdb_ctx *db_tdb;
410         struct stat st;
411
412         /* Extra paranoia. */
413         if (name && strends(name, ".ntdb")) {
414                 DEBUG(0, ("can't try to open %s with tdb!\n", name));
415                 return NULL;
416         }
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         if (hash_size == 0) {
432                 hash_size = lpcfg_tdb_hash_size(lp_ctx, name);
433         }
434
435         db_tdb->wtdb = tdb_wrap_open(db_tdb, name, hash_size,
436                                      lpcfg_tdb_flags(lp_ctx, tdb_flags),
437                                      open_flags, mode);
438         if (db_tdb->wtdb == NULL) {
439                 DEBUG(3, ("Could not open tdb: %s\n", strerror(errno)));
440                 goto fail;
441         }
442
443         ZERO_STRUCT(db_tdb->id);
444
445         if (fstat(tdb_fd(db_tdb->wtdb->tdb), &st) == -1) {
446                 DEBUG(3, ("fstat failed: %s\n", strerror(errno)));
447                 goto fail;
448         }
449         db_tdb->id.dev = st.st_dev;
450         db_tdb->id.ino = st.st_ino;
451
452         result->fetch_locked = db_tdb_fetch_locked;
453         result->try_fetch_locked = db_tdb_try_fetch_locked;
454         result->traverse = db_tdb_traverse;
455         result->traverse_read = db_tdb_traverse_read;
456         result->parse_record = db_tdb_parse;
457         result->get_seqnum = db_tdb_get_seqnum;
458         result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
459         result->transaction_start = db_tdb_transaction_start;
460         result->transaction_start_nonblock = db_tdb_transaction_start_nonblock;
461         result->transaction_commit = db_tdb_transaction_commit;
462         result->transaction_cancel = db_tdb_transaction_cancel;
463         result->exists = db_tdb_exists;
464         result->wipe = db_tdb_wipe;
465         result->id = db_tdb_id;
466         result->check = db_tdb_check;
467         result->name = tdb_name(db_tdb->wtdb->tdb);
468         result->hash_size = hash_size;
469         return result;
470
471  fail:
472         TALLOC_FREE(result);
473         return NULL;
474 }