s3: Add dbwrap_try_fetch_locked
[Samba/gebeck_regimport.git] / source3 / lib / dbwrap / dbwrap_tdb.c
blobffad39bed8bfb0f78765a12a029d3cce6031f240
1 /*
2 Unix SMB/CIFS implementation.
3 Database interface wrapper around tdb
4 Copyright (C) Volker Lendecke 2005-2007
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.
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.
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/>.
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/param/param.h"
26 #include "util_tdb.h"
28 struct db_tdb_ctx {
29 struct tdb_wrap *wtdb;
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);
35 static void db_tdb_log_key(const char *prefix, TDB_DATA key)
37 size_t len;
38 char *keystr;
40 if (DEBUGLEVEL < 10) {
41 return;
43 len = key.dsize;
44 if (DEBUGLEVEL == 10) {
46 * Only fully spam at debuglevel > 10
48 len = MIN(10, key.dsize);
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);
56 static int db_tdb_record_destr(struct db_record* data)
58 struct db_tdb_ctx *ctx =
59 talloc_get_type_abort(data->private_data, struct db_tdb_ctx);
61 db_tdb_log_key("Unlocking", data->key);
62 tdb_chainunlock(ctx->wtdb->tdb, data->key);
63 return 0;
66 struct tdb_fetch_locked_state {
67 TALLOC_CTX *mem_ctx;
68 struct db_record *result;
71 static int db_tdb_fetchlock_parse(TDB_DATA key, TDB_DATA data,
72 void *private_data)
74 struct tdb_fetch_locked_state *state =
75 (struct tdb_fetch_locked_state *)private_data;
76 struct db_record *result;
78 result = (struct db_record *)talloc_size(
79 state->mem_ctx,
80 sizeof(struct db_record) + key.dsize + data.dsize);
82 if (result == NULL) {
83 return 0;
85 state->result = result;
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);
91 result->value.dsize = data.dsize;
93 if (data.dsize > 0) {
94 result->value.dptr = result->key.dptr+key.dsize;
95 memcpy(result->value.dptr, data.dptr, data.dsize);
97 else {
98 result->value.dptr = NULL;
101 return 0;
104 static struct db_record *db_tdb_fetch_locked_internal(
105 struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
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;
111 state.mem_ctx = mem_ctx;
112 state.result = NULL;
114 tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_fetchlock_parse, &state);
116 if (state.result == NULL) {
117 db_tdb_fetchlock_parse(key, tdb_null, &state);
120 if (state.result == NULL) {
121 tdb_chainunlock(ctx->wtdb->tdb, key);
122 return NULL;
125 talloc_set_destructor(state.result, db_tdb_record_destr);
127 state.result->private_data = talloc_reference(state.result, ctx);
128 state.result->store = db_tdb_store;
129 state.result->delete_rec = db_tdb_delete;
131 DEBUG(10, ("Allocated locked data 0x%p\n", state.result));
133 return state.result;
136 static struct db_record *db_tdb_fetch_locked(
137 struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
139 struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
140 struct db_tdb_ctx);
142 db_tdb_log_key("Locking", key);
143 if (tdb_chainlock(ctx->wtdb->tdb, key) != 0) {
144 DEBUG(3, ("tdb_chainlock failed\n"));
145 return NULL;
147 return db_tdb_fetch_locked_internal(db, mem_ctx, key);
150 static struct db_record *db_tdb_try_fetch_locked(
151 struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
153 struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
154 struct db_tdb_ctx);
156 db_tdb_log_key("Trying to lock", key);
157 if (tdb_chainlock_nonblock(ctx->wtdb->tdb, key) != 0) {
158 DEBUG(3, ("tdb_chainlock_nonblock failed\n"));
159 return NULL;
161 return db_tdb_fetch_locked_internal(db, mem_ctx, key);
165 static int db_tdb_exists(struct db_context *db, TDB_DATA key)
167 struct db_tdb_ctx *ctx = talloc_get_type_abort(
168 db->private_data, struct db_tdb_ctx);
169 return tdb_exists(ctx->wtdb->tdb, key);
172 static int db_tdb_wipe(struct db_context *db)
174 struct db_tdb_ctx *ctx = talloc_get_type_abort(
175 db->private_data, struct db_tdb_ctx);
176 return tdb_wipe_all(ctx->wtdb->tdb);
179 struct db_tdb_parse_state {
180 void (*parser)(TDB_DATA key, TDB_DATA data,
181 void *private_data);
182 void *private_data;
186 * tdb_parse_record expects a parser returning int, mixing up tdb and
187 * parser errors. Wrap around that by always returning 0 and have
188 * dbwrap_parse_record expect a parser returning void.
191 static int db_tdb_parser(TDB_DATA key, TDB_DATA data, void *private_data)
193 struct db_tdb_parse_state *state =
194 (struct db_tdb_parse_state *)private_data;
195 state->parser(key, data, state->private_data);
196 return 0;
199 static NTSTATUS db_tdb_parse(struct db_context *db, TDB_DATA key,
200 void (*parser)(TDB_DATA key, TDB_DATA data,
201 void *private_data),
202 void *private_data)
204 struct db_tdb_ctx *ctx = talloc_get_type_abort(
205 db->private_data, struct db_tdb_ctx);
206 struct db_tdb_parse_state state;
207 int ret;
209 state.parser = parser;
210 state.private_data = private_data;
212 ret = tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_parser, &state);
214 if (ret != 0) {
215 return map_nt_error_from_tdb(tdb_error(ctx->wtdb->tdb));
217 return NT_STATUS_OK;
220 static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag)
222 struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
223 struct db_tdb_ctx);
226 * This has a bug: We need to replace rec->value for correct
227 * operation, but right now brlock and locking don't use the value
228 * anymore after it was stored.
231 return (tdb_store(ctx->wtdb->tdb, rec->key, data, flag) == 0) ?
232 NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
235 static NTSTATUS db_tdb_delete(struct db_record *rec)
237 struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
238 struct db_tdb_ctx);
240 if (tdb_delete(ctx->wtdb->tdb, rec->key) == 0) {
241 return NT_STATUS_OK;
244 if (tdb_error(ctx->wtdb->tdb) == TDB_ERR_NOEXIST) {
245 return NT_STATUS_NOT_FOUND;
248 return NT_STATUS_UNSUCCESSFUL;
251 struct db_tdb_traverse_ctx {
252 struct db_context *db;
253 int (*f)(struct db_record *rec, void *private_data);
254 void *private_data;
257 static int db_tdb_traverse_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
258 void *private_data)
260 struct db_tdb_traverse_ctx *ctx =
261 (struct db_tdb_traverse_ctx *)private_data;
262 struct db_record rec;
264 rec.key = kbuf;
265 rec.value = dbuf;
266 rec.store = db_tdb_store;
267 rec.delete_rec = db_tdb_delete;
268 rec.private_data = ctx->db->private_data;
270 return ctx->f(&rec, ctx->private_data);
273 static int db_tdb_traverse(struct db_context *db,
274 int (*f)(struct db_record *rec, void *private_data),
275 void *private_data)
277 struct db_tdb_ctx *db_ctx =
278 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
279 struct db_tdb_traverse_ctx ctx;
281 ctx.db = db;
282 ctx.f = f;
283 ctx.private_data = private_data;
284 return tdb_traverse(db_ctx->wtdb->tdb, db_tdb_traverse_func, &ctx);
287 static NTSTATUS db_tdb_store_deny(struct db_record *rec, TDB_DATA data, int flag)
289 return NT_STATUS_MEDIA_WRITE_PROTECTED;
292 static NTSTATUS db_tdb_delete_deny(struct db_record *rec)
294 return NT_STATUS_MEDIA_WRITE_PROTECTED;
297 static int db_tdb_traverse_read_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
298 void *private_data)
300 struct db_tdb_traverse_ctx *ctx =
301 (struct db_tdb_traverse_ctx *)private_data;
302 struct db_record rec;
304 rec.key = kbuf;
305 rec.value = dbuf;
306 rec.store = db_tdb_store_deny;
307 rec.delete_rec = db_tdb_delete_deny;
308 rec.private_data = ctx->db->private_data;
310 return ctx->f(&rec, ctx->private_data);
313 static int db_tdb_traverse_read(struct db_context *db,
314 int (*f)(struct db_record *rec, void *private_data),
315 void *private_data)
317 struct db_tdb_ctx *db_ctx =
318 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
319 struct db_tdb_traverse_ctx ctx;
321 ctx.db = db;
322 ctx.f = f;
323 ctx.private_data = private_data;
324 return tdb_traverse_read(db_ctx->wtdb->tdb, db_tdb_traverse_read_func, &ctx);
327 static int db_tdb_get_seqnum(struct db_context *db)
330 struct db_tdb_ctx *db_ctx =
331 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
332 return tdb_get_seqnum(db_ctx->wtdb->tdb);
335 static int db_tdb_get_flags(struct db_context *db)
338 struct db_tdb_ctx *db_ctx =
339 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
340 return tdb_get_flags(db_ctx->wtdb->tdb);
343 static int db_tdb_transaction_start(struct db_context *db)
345 struct db_tdb_ctx *db_ctx =
346 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
347 return tdb_transaction_start(db_ctx->wtdb->tdb) ? -1 : 0;
350 static int db_tdb_transaction_commit(struct db_context *db)
352 struct db_tdb_ctx *db_ctx =
353 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
354 return tdb_transaction_commit(db_ctx->wtdb->tdb) ? -1 : 0;
357 static int db_tdb_transaction_cancel(struct db_context *db)
359 struct db_tdb_ctx *db_ctx =
360 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
361 tdb_transaction_cancel(db_ctx->wtdb->tdb);
362 return 0;
365 struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
366 const char *name,
367 int hash_size, int tdb_flags,
368 int open_flags, mode_t mode,
369 enum dbwrap_lock_order lock_order)
371 struct db_context *result = NULL;
372 struct db_tdb_ctx *db_tdb;
373 struct loadparm_context *lp_ctx;
375 result = talloc_zero(mem_ctx, struct db_context);
376 if (result == NULL) {
377 DEBUG(0, ("talloc failed\n"));
378 goto fail;
380 lp_ctx = loadparm_init_s3(result, loadparm_s3_context());
382 result->private_data = db_tdb = talloc(result, struct db_tdb_ctx);
383 if (db_tdb == NULL) {
384 DEBUG(0, ("talloc failed\n"));
385 goto fail;
387 result->lock_order = lock_order;
389 db_tdb->wtdb = tdb_wrap_open(db_tdb, name, hash_size, tdb_flags,
390 open_flags, mode, lp_ctx);
391 talloc_unlink(result, lp_ctx);
392 if (db_tdb->wtdb == NULL) {
393 DEBUG(3, ("Could not open tdb: %s\n", strerror(errno)));
394 goto fail;
397 result->fetch_locked = db_tdb_fetch_locked;
398 result->try_fetch_locked = db_tdb_try_fetch_locked;
399 result->traverse = db_tdb_traverse;
400 result->traverse_read = db_tdb_traverse_read;
401 result->parse_record = db_tdb_parse;
402 result->get_seqnum = db_tdb_get_seqnum;
403 result->get_flags = db_tdb_get_flags;
404 result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
405 result->transaction_start = db_tdb_transaction_start;
406 result->transaction_commit = db_tdb_transaction_commit;
407 result->transaction_cancel = db_tdb_transaction_cancel;
408 result->exists = db_tdb_exists;
409 result->wipe = db_tdb_wipe;
410 return result;
412 fail:
413 if (result != NULL) {
414 TALLOC_FREE(result);
416 return NULL;