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