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