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/>.
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"
29 struct tdb_wrap
*wtdb
;
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
);
40 static void db_tdb_log_key(const char *prefix
, TDB_DATA key
)
45 if (DEBUGLEVEL
< 10) {
49 if (DEBUGLEVEL
== 10) {
51 * Only fully spam at debuglevel > 10
53 len
= MIN(10, key
.dsize
);
55 keystr
= hex_encode_talloc(talloc_tos(), (unsigned char *)(key
.dptr
),
57 DEBUG(10, ("%s key %s\n", prefix
, keystr
));
61 static int db_tdb_record_destr(struct db_record
* data
)
63 struct db_tdb_ctx
*ctx
=
64 talloc_get_type_abort(data
->private_data
, struct db_tdb_ctx
);
66 db_tdb_log_key("Unlocking", data
->key
);
67 tdb_chainunlock(ctx
->wtdb
->tdb
, data
->key
);
71 struct tdb_fetch_locked_state
{
73 struct db_record
*result
;
76 static int db_tdb_fetchlock_parse(TDB_DATA key
, TDB_DATA data
,
79 struct tdb_fetch_locked_state
*state
=
80 (struct tdb_fetch_locked_state
*)private_data
;
81 struct db_record
*result
;
83 result
= (struct db_record
*)talloc_size(
85 sizeof(struct db_record
) + key
.dsize
+ data
.dsize
);
90 state
->result
= result
;
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
);
96 result
->value
.dsize
= data
.dsize
;
99 result
->value
.dptr
= result
->key
.dptr
+key
.dsize
;
100 memcpy(result
->value
.dptr
, data
.dptr
, data
.dsize
);
103 result
->value
.dptr
= NULL
;
109 static struct db_record
*db_tdb_fetch_locked_internal(
110 struct db_context
*db
, TALLOC_CTX
*mem_ctx
, TDB_DATA key
)
112 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
114 struct tdb_fetch_locked_state state
;
116 state
.mem_ctx
= mem_ctx
;
119 if ((tdb_parse_record(ctx
->wtdb
->tdb
, key
, db_tdb_fetchlock_parse
,
121 (tdb_error(ctx
->wtdb
->tdb
) != TDB_ERR_NOEXIST
)) {
122 tdb_chainunlock(ctx
->wtdb
->tdb
, key
);
126 if (state
.result
== NULL
) {
127 db_tdb_fetchlock_parse(key
, tdb_null
, &state
);
130 if (state
.result
== NULL
) {
131 tdb_chainunlock(ctx
->wtdb
->tdb
, key
);
135 talloc_set_destructor(state
.result
, db_tdb_record_destr
);
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
;
141 DEBUG(10, ("Allocated locked data 0x%p\n", state
.result
));
146 static struct db_record
*db_tdb_fetch_locked(
147 struct db_context
*db
, TALLOC_CTX
*mem_ctx
, TDB_DATA key
)
149 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
152 db_tdb_log_key("Locking", key
);
153 if (tdb_chainlock(ctx
->wtdb
->tdb
, key
) != 0) {
154 DEBUG(3, ("tdb_chainlock failed\n"));
157 return db_tdb_fetch_locked_internal(db
, mem_ctx
, key
);
160 static struct db_record
*db_tdb_try_fetch_locked(
161 struct db_context
*db
, TALLOC_CTX
*mem_ctx
, TDB_DATA key
)
163 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
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"));
171 return db_tdb_fetch_locked_internal(db
, mem_ctx
, key
);
175 static int db_tdb_exists(struct db_context
*db
, TDB_DATA key
)
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
);
182 static int db_tdb_wipe(struct db_context
*db
)
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
);
189 struct db_tdb_parse_state
{
190 void (*parser
)(TDB_DATA key
, TDB_DATA data
,
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.
201 static int db_tdb_parser(TDB_DATA key
, TDB_DATA data
, void *private_data
)
203 struct db_tdb_parse_state
*state
=
204 (struct db_tdb_parse_state
*)private_data
;
205 state
->parser(key
, data
, state
->private_data
);
209 static NTSTATUS
db_tdb_parse(struct db_context
*db
, TDB_DATA key
,
210 void (*parser
)(TDB_DATA key
, TDB_DATA data
,
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
;
219 state
.parser
= parser
;
220 state
.private_data
= private_data
;
222 ret
= tdb_parse_record(ctx
->wtdb
->tdb
, key
, db_tdb_parser
, &state
);
225 return map_nt_error_from_tdb(tdb_error(ctx
->wtdb
->tdb
));
230 static NTSTATUS
db_tdb_store(struct db_record
*rec
, TDB_DATA data
, int flag
)
232 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(rec
->private_data
,
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.
241 return (tdb_store(ctx
->wtdb
->tdb
, rec
->key
, data
, flag
) == 0) ?
242 NT_STATUS_OK
: NT_STATUS_UNSUCCESSFUL
;
245 static NTSTATUS
db_tdb_delete(struct db_record
*rec
)
247 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(rec
->private_data
,
250 if (tdb_delete(ctx
->wtdb
->tdb
, rec
->key
) == 0) {
254 if (tdb_error(ctx
->wtdb
->tdb
) == TDB_ERR_NOEXIST
) {
255 return NT_STATUS_NOT_FOUND
;
258 return NT_STATUS_UNSUCCESSFUL
;
261 struct db_tdb_traverse_ctx
{
262 struct db_context
*db
;
263 int (*f
)(struct db_record
*rec
, void *private_data
);
267 static int db_tdb_traverse_func(TDB_CONTEXT
*tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
270 struct db_tdb_traverse_ctx
*ctx
=
271 (struct db_tdb_traverse_ctx
*)private_data
;
272 struct db_record rec
;
276 rec
.store
= db_tdb_store
;
277 rec
.delete_rec
= db_tdb_delete
;
278 rec
.private_data
= ctx
->db
->private_data
;
281 return ctx
->f(&rec
, ctx
->private_data
);
284 static int db_tdb_traverse(struct db_context
*db
,
285 int (*f
)(struct db_record
*rec
, void *private_data
),
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
;
294 ctx
.private_data
= private_data
;
295 return tdb_traverse(db_ctx
->wtdb
->tdb
, db_tdb_traverse_func
, &ctx
);
298 static NTSTATUS
db_tdb_store_deny(struct db_record
*rec
, TDB_DATA data
, int flag
)
300 return NT_STATUS_MEDIA_WRITE_PROTECTED
;
303 static NTSTATUS
db_tdb_delete_deny(struct db_record
*rec
)
305 return NT_STATUS_MEDIA_WRITE_PROTECTED
;
308 static int db_tdb_traverse_read_func(TDB_CONTEXT
*tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
311 struct db_tdb_traverse_ctx
*ctx
=
312 (struct db_tdb_traverse_ctx
*)private_data
;
313 struct db_record rec
;
317 rec
.store
= db_tdb_store_deny
;
318 rec
.delete_rec
= db_tdb_delete_deny
;
319 rec
.private_data
= ctx
->db
->private_data
;
322 return ctx
->f(&rec
, ctx
->private_data
);
325 static int db_tdb_traverse_read(struct db_context
*db
,
326 int (*f
)(struct db_record
*rec
, void *private_data
),
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
;
335 ctx
.private_data
= private_data
;
336 return tdb_traverse_read(db_ctx
->wtdb
->tdb
, db_tdb_traverse_read_func
, &ctx
);
339 static int db_tdb_get_seqnum(struct db_context
*db
)
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
);
347 static int db_tdb_get_flags(struct db_context
*db
)
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
);
355 static int db_tdb_transaction_start(struct db_context
*db
)
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;
362 static int db_tdb_transaction_commit(struct db_context
*db
)
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;
369 static int db_tdb_transaction_cancel(struct db_context
*db
)
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
);
377 static void db_tdb_id(struct db_context
*db
, const uint8_t **id
, size_t *idlen
)
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
);
385 struct db_context
*db_open_tdb(TALLOC_CTX
*mem_ctx
,
386 struct loadparm_context
*lp_ctx
,
388 int hash_size
, int tdb_flags
,
389 int open_flags
, mode_t mode
,
390 enum dbwrap_lock_order lock_order
)
392 struct db_context
*result
= NULL
;
393 struct db_tdb_ctx
*db_tdb
;
396 result
= talloc_zero(mem_ctx
, struct db_context
);
397 if (result
== NULL
) {
398 DEBUG(0, ("talloc failed\n"));
402 result
->private_data
= db_tdb
= talloc(result
, struct db_tdb_ctx
);
403 if (db_tdb
== NULL
) {
404 DEBUG(0, ("talloc failed\n"));
407 result
->lock_order
= lock_order
;
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
)));
416 ZERO_STRUCT(db_tdb
->id
);
418 if (fstat(tdb_fd(db_tdb
->wtdb
->tdb
), &st
) == -1) {
419 DEBUG(3, ("fstat failed: %s\n", strerror(errno
)));
422 db_tdb
->id
.dev
= st
.st_dev
;
423 db_tdb
->id
.ino
= st
.st_ino
;
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
;
443 if (result
!= NULL
) {