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 "lib/util/debug.h"
27 #include "lib/util/samba_util.h"
28 #include "system/filesys.h"
29 #include "lib/param/param.h"
30 #include "libcli/util/error.h"
33 struct tdb_wrap
*wtdb
;
41 static NTSTATUS
db_tdb_storev(struct db_record
*rec
,
42 const TDB_DATA
*dbufs
, int num_dbufs
, int flag
);
43 static NTSTATUS
db_tdb_delete(struct db_record
*rec
);
45 static void db_tdb_log_key(const char *prefix
, TDB_DATA key
)
47 if (DEBUGLEVEL
< 10) {
50 if (DEBUGLEVEL
== 10) {
52 * Only fully spam at debuglevel > 10
54 key
.dsize
= MIN(10, key
.dsize
);
57 if (key
.dsize
< 1024) {
58 char keystr
[key
.dsize
*2+1];
59 hex_encode_buf(keystr
, key
.dptr
, key
.dsize
);
60 DBG_DEBUG("%s key %s\n", prefix
, keystr
);
64 dump_data(DEBUGLEVEL
, key
.dptr
, key
.dsize
);
67 static int db_tdb_record_destr(struct db_record
* data
)
69 struct db_tdb_ctx
*ctx
=
70 talloc_get_type_abort(data
->private_data
, struct db_tdb_ctx
);
72 db_tdb_log_key("Unlocking", data
->key
);
73 tdb_chainunlock(ctx
->wtdb
->tdb
, data
->key
);
77 struct tdb_fetch_locked_state
{
79 struct db_record
*result
;
82 static int db_tdb_fetchlock_parse(TDB_DATA key
, TDB_DATA data
,
85 struct tdb_fetch_locked_state
*state
=
86 (struct tdb_fetch_locked_state
*)private_data
;
87 struct db_record
*result
;
89 result
= (struct db_record
*)talloc_size(
91 sizeof(struct db_record
) + key
.dsize
+ data
.dsize
);
96 state
->result
= result
;
98 result
->key
.dsize
= key
.dsize
;
99 result
->key
.dptr
= ((uint8_t *)result
) + sizeof(struct db_record
);
100 memcpy(result
->key
.dptr
, key
.dptr
, key
.dsize
);
102 result
->value
.dsize
= data
.dsize
;
104 if (data
.dsize
> 0) {
105 result
->value
.dptr
= result
->key
.dptr
+key
.dsize
;
106 memcpy(result
->value
.dptr
, data
.dptr
, data
.dsize
);
109 result
->value
.dptr
= NULL
;
111 result
->value_valid
= true;
116 static struct db_record
*db_tdb_fetch_locked_internal(
117 struct db_context
*db
,
118 struct db_tdb_ctx
*ctx
,
122 struct tdb_fetch_locked_state state
;
125 state
= (struct tdb_fetch_locked_state
) {
129 ret
= tdb_parse_record(ctx
->wtdb
->tdb
,
131 db_tdb_fetchlock_parse
,
133 if ((ret
< 0) && (tdb_error(ctx
->wtdb
->tdb
) != TDB_ERR_NOEXIST
)) {
134 tdb_chainunlock(ctx
->wtdb
->tdb
, key
);
138 if (state
.result
== NULL
) {
139 db_tdb_fetchlock_parse(key
, tdb_null
, &state
);
142 if (state
.result
== NULL
) {
143 tdb_chainunlock(ctx
->wtdb
->tdb
, key
);
147 talloc_set_destructor(state
.result
, db_tdb_record_destr
);
149 state
.result
->private_data
= ctx
;
150 state
.result
->storev
= db_tdb_storev
;
151 state
.result
->delete_rec
= db_tdb_delete
;
153 DBG_DEBUG("Allocated locked data %p\n", state
.result
);
158 static struct db_record
*db_tdb_fetch_locked(
159 struct db_context
*db
, TALLOC_CTX
*mem_ctx
, TDB_DATA key
)
161 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
164 db_tdb_log_key("Locking", key
);
165 if (tdb_chainlock(ctx
->wtdb
->tdb
, key
) != 0) {
166 DEBUG(3, ("tdb_chainlock failed\n"));
169 return db_tdb_fetch_locked_internal(db
, ctx
, mem_ctx
, key
);
172 static struct db_record
*db_tdb_try_fetch_locked(
173 struct db_context
*db
, TALLOC_CTX
*mem_ctx
, TDB_DATA key
)
175 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
178 db_tdb_log_key("Trying to lock", key
);
179 if (tdb_chainlock_nonblock(ctx
->wtdb
->tdb
, key
) != 0) {
180 DEBUG(3, ("tdb_chainlock_nonblock failed\n"));
183 return db_tdb_fetch_locked_internal(db
, ctx
, mem_ctx
, key
);
186 static NTSTATUS
db_tdb_do_locked(struct db_context
*db
, TDB_DATA key
,
187 void (*fn
)(struct db_record
*rec
,
192 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(
193 db
->private_data
, struct db_tdb_ctx
);
195 struct db_record rec
;
198 ret
= tdb_chainlock(ctx
->wtdb
->tdb
, key
);
200 enum TDB_ERROR err
= tdb_error(ctx
->wtdb
->tdb
);
201 DBG_DEBUG("tdb_chainlock failed: %s\n",
202 tdb_errorstr(ctx
->wtdb
->tdb
));
203 return map_nt_error_from_tdb(err
);
206 ret
= tdb_fetch_talloc(ctx
->wtdb
->tdb
, key
, ctx
, &buf
);
208 if ((ret
!= 0) && (ret
!= ENOENT
)) {
209 DBG_DEBUG("tdb_fetch_talloc failed: %s\n",
211 tdb_chainunlock(ctx
->wtdb
->tdb
, key
);
212 return map_nt_error_from_unix_common(ret
);
215 rec
= (struct db_record
) {
216 .db
= db
, .key
= key
,
217 .value_valid
= false,
218 .storev
= db_tdb_storev
, .delete_rec
= db_tdb_delete
,
223 (TDB_DATA
) { .dptr
= buf
, .dsize
= talloc_get_size(buf
) },
226 tdb_chainunlock(ctx
->wtdb
->tdb
, key
);
233 static int db_tdb_exists(struct db_context
*db
, TDB_DATA key
)
235 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(
236 db
->private_data
, struct db_tdb_ctx
);
237 return tdb_exists(ctx
->wtdb
->tdb
, key
);
240 static int db_tdb_wipe(struct db_context
*db
)
242 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(
243 db
->private_data
, struct db_tdb_ctx
);
244 return tdb_wipe_all(ctx
->wtdb
->tdb
);
247 static int db_tdb_check(struct db_context
*db
)
249 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(
250 db
->private_data
, struct db_tdb_ctx
);
251 return tdb_check(ctx
->wtdb
->tdb
, NULL
, NULL
);
254 struct db_tdb_parse_state
{
255 void (*parser
)(TDB_DATA key
, TDB_DATA data
,
261 * tdb_parse_record expects a parser returning int, mixing up tdb and
262 * parser errors. Wrap around that by always returning 0 and have
263 * dbwrap_parse_record expect a parser returning void.
266 static int db_tdb_parser(TDB_DATA key
, TDB_DATA data
, void *private_data
)
268 struct db_tdb_parse_state
*state
=
269 (struct db_tdb_parse_state
*)private_data
;
270 state
->parser(key
, data
, state
->private_data
);
274 static NTSTATUS
db_tdb_parse(struct db_context
*db
, TDB_DATA key
,
275 void (*parser
)(TDB_DATA key
, TDB_DATA data
,
279 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(
280 db
->private_data
, struct db_tdb_ctx
);
281 struct db_tdb_parse_state state
;
284 state
.parser
= parser
;
285 state
.private_data
= private_data
;
287 ret
= tdb_parse_record(ctx
->wtdb
->tdb
, key
, db_tdb_parser
, &state
);
290 return map_nt_error_from_tdb(tdb_error(ctx
->wtdb
->tdb
));
295 static NTSTATUS
db_tdb_storev(struct db_record
*rec
,
296 const TDB_DATA
*dbufs
, int num_dbufs
, int flag
)
298 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(rec
->private_data
,
300 struct tdb_context
*tdb
= ctx
->wtdb
->tdb
;
301 NTSTATUS status
= NT_STATUS_OK
;
305 * This has a bug: We need to replace rec->value for correct
306 * operation, but right now brlock and locking don't use the value
307 * anymore after it was stored.
310 ret
= tdb_storev(tdb
, rec
->key
, dbufs
, num_dbufs
, flag
);
312 enum TDB_ERROR err
= tdb_error(tdb
);
313 status
= map_nt_error_from_tdb(err
);
318 static NTSTATUS
db_tdb_delete(struct db_record
*rec
)
320 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(rec
->private_data
,
323 if (tdb_delete(ctx
->wtdb
->tdb
, rec
->key
) == 0) {
327 if (tdb_error(ctx
->wtdb
->tdb
) == TDB_ERR_NOEXIST
) {
328 return NT_STATUS_NOT_FOUND
;
331 return NT_STATUS_UNSUCCESSFUL
;
334 struct db_tdb_traverse_ctx
{
335 struct db_context
*db
;
336 int (*f
)(struct db_record
*rec
, void *private_data
);
340 static int db_tdb_traverse_func(TDB_CONTEXT
*tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
343 struct db_tdb_traverse_ctx
*ctx
=
344 (struct db_tdb_traverse_ctx
*)private_data
;
345 struct db_record rec
;
349 rec
.value_valid
= true;
350 rec
.storev
= db_tdb_storev
;
351 rec
.delete_rec
= db_tdb_delete
;
352 rec
.private_data
= ctx
->db
->private_data
;
355 return ctx
->f(&rec
, ctx
->private_data
);
358 static int db_tdb_traverse(struct db_context
*db
,
359 int (*f
)(struct db_record
*rec
, void *private_data
),
362 struct db_tdb_ctx
*db_ctx
=
363 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
364 struct db_tdb_traverse_ctx ctx
;
368 ctx
.private_data
= private_data
;
369 return tdb_traverse(db_ctx
->wtdb
->tdb
, db_tdb_traverse_func
, &ctx
);
372 static NTSTATUS
db_tdb_storev_deny(struct db_record
*rec
,
373 const TDB_DATA
*dbufs
, int num_dbufs
,
376 return NT_STATUS_MEDIA_WRITE_PROTECTED
;
379 static NTSTATUS
db_tdb_delete_deny(struct db_record
*rec
)
381 return NT_STATUS_MEDIA_WRITE_PROTECTED
;
384 static int db_tdb_traverse_read_func(TDB_CONTEXT
*tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
387 struct db_tdb_traverse_ctx
*ctx
=
388 (struct db_tdb_traverse_ctx
*)private_data
;
389 struct db_record rec
;
393 rec
.value_valid
= true;
394 rec
.storev
= db_tdb_storev_deny
;
395 rec
.delete_rec
= db_tdb_delete_deny
;
396 rec
.private_data
= ctx
->db
->private_data
;
399 return ctx
->f(&rec
, ctx
->private_data
);
402 static int db_tdb_traverse_read(struct db_context
*db
,
403 int (*f
)(struct db_record
*rec
, void *private_data
),
406 struct db_tdb_ctx
*db_ctx
=
407 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
408 struct db_tdb_traverse_ctx ctx
;
412 ctx
.private_data
= private_data
;
413 return tdb_traverse_read(db_ctx
->wtdb
->tdb
, db_tdb_traverse_read_func
, &ctx
);
416 static int db_tdb_get_seqnum(struct db_context
*db
)
419 struct db_tdb_ctx
*db_ctx
=
420 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
421 return tdb_get_seqnum(db_ctx
->wtdb
->tdb
);
424 static int db_tdb_transaction_start(struct db_context
*db
)
426 struct db_tdb_ctx
*db_ctx
=
427 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
428 return tdb_transaction_start(db_ctx
->wtdb
->tdb
) ? -1 : 0;
431 static NTSTATUS
db_tdb_transaction_start_nonblock(struct db_context
*db
)
433 struct db_tdb_ctx
*db_ctx
=
434 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
437 ret
= tdb_transaction_start_nonblock(db_ctx
->wtdb
->tdb
);
439 return map_nt_error_from_tdb(tdb_error(db_ctx
->wtdb
->tdb
));
444 static int db_tdb_transaction_commit(struct db_context
*db
)
446 struct db_tdb_ctx
*db_ctx
=
447 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
448 return tdb_transaction_commit(db_ctx
->wtdb
->tdb
) ? -1 : 0;
451 static int db_tdb_transaction_cancel(struct db_context
*db
)
453 struct db_tdb_ctx
*db_ctx
=
454 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
455 tdb_transaction_cancel(db_ctx
->wtdb
->tdb
);
459 static size_t db_tdb_id(struct db_context
*db
, uint8_t *id
, size_t idlen
)
461 struct db_tdb_ctx
*db_ctx
=
462 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
464 if (idlen
>= sizeof(db_ctx
->id
)) {
465 memcpy(id
, &db_ctx
->id
, sizeof(db_ctx
->id
));
468 return sizeof(db_ctx
->id
);
471 struct db_context
*db_open_tdb(TALLOC_CTX
*mem_ctx
,
473 int hash_size
, int tdb_flags
,
474 int open_flags
, mode_t mode
,
475 enum dbwrap_lock_order lock_order
,
476 uint64_t dbwrap_flags
)
478 struct db_context
*result
= NULL
;
479 struct db_tdb_ctx
*db_tdb
;
482 result
= talloc_zero(mem_ctx
, struct db_context
);
483 if (result
== NULL
) {
484 DEBUG(0, ("talloc failed\n"));
488 result
->private_data
= db_tdb
= talloc(result
, struct db_tdb_ctx
);
489 if (db_tdb
== NULL
) {
490 DEBUG(0, ("talloc failed\n"));
493 result
->lock_order
= lock_order
;
495 db_tdb
->wtdb
= tdb_wrap_open(db_tdb
, name
, hash_size
, tdb_flags
,
497 if (db_tdb
->wtdb
== NULL
) {
498 DEBUG(3, ("Could not open tdb: %s\n", strerror(errno
)));
502 ZERO_STRUCT(db_tdb
->id
);
504 if (fstat(tdb_fd(db_tdb
->wtdb
->tdb
), &st
) == -1) {
505 DEBUG(3, ("fstat failed: %s\n", strerror(errno
)));
508 db_tdb
->id
.dev
= st
.st_dev
;
509 db_tdb
->id
.ino
= st
.st_ino
;
511 result
->fetch_locked
= db_tdb_fetch_locked
;
512 result
->try_fetch_locked
= db_tdb_try_fetch_locked
;
513 result
->do_locked
= db_tdb_do_locked
;
514 result
->traverse
= db_tdb_traverse
;
515 result
->traverse_read
= db_tdb_traverse_read
;
516 result
->parse_record
= db_tdb_parse
;
517 result
->get_seqnum
= db_tdb_get_seqnum
;
518 result
->persistent
= ((tdb_flags
& TDB_CLEAR_IF_FIRST
) == 0);
519 result
->transaction_start
= db_tdb_transaction_start
;
520 result
->transaction_start_nonblock
= db_tdb_transaction_start_nonblock
;
521 result
->transaction_commit
= db_tdb_transaction_commit
;
522 result
->transaction_cancel
= db_tdb_transaction_cancel
;
523 result
->exists
= db_tdb_exists
;
524 result
->wipe
= db_tdb_wipe
;
525 result
->id
= db_tdb_id
;
526 result
->check
= db_tdb_check
;
527 result
->name
= tdb_name(db_tdb
->wtdb
->tdb
);