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"
27 #include "ccan/str/str.h"
30 struct tdb_wrap
*wtdb
;
38 static NTSTATUS
db_tdb_store(struct db_record
*rec
, TDB_DATA data
, int flag
);
39 static NTSTATUS
db_tdb_delete(struct db_record
*rec
);
41 static void db_tdb_log_key(const char *prefix
, TDB_DATA key
)
46 if (DEBUGLEVEL
< 10) {
49 frame
= talloc_stackframe();
51 if (DEBUGLEVEL
== 10) {
53 * Only fully spam at debuglevel > 10
55 len
= MIN(10, key
.dsize
);
57 keystr
= hex_encode_talloc(frame
, (unsigned char *)(key
.dptr
),
59 DEBUG(10, ("%s key %s\n", prefix
, keystr
));
63 static int db_tdb_record_destr(struct db_record
* data
)
65 struct db_tdb_ctx
*ctx
=
66 talloc_get_type_abort(data
->private_data
, struct db_tdb_ctx
);
68 db_tdb_log_key("Unlocking", data
->key
);
69 tdb_chainunlock(ctx
->wtdb
->tdb
, data
->key
);
73 struct tdb_fetch_locked_state
{
75 struct db_record
*result
;
78 static int db_tdb_fetchlock_parse(TDB_DATA key
, TDB_DATA data
,
81 struct tdb_fetch_locked_state
*state
=
82 (struct tdb_fetch_locked_state
*)private_data
;
83 struct db_record
*result
;
85 result
= (struct db_record
*)talloc_size(
87 sizeof(struct db_record
) + key
.dsize
+ data
.dsize
);
92 state
->result
= result
;
94 result
->key
.dsize
= key
.dsize
;
95 result
->key
.dptr
= ((uint8_t *)result
) + sizeof(struct db_record
);
96 memcpy(result
->key
.dptr
, key
.dptr
, key
.dsize
);
98 result
->value
.dsize
= data
.dsize
;
100 if (data
.dsize
> 0) {
101 result
->value
.dptr
= result
->key
.dptr
+key
.dsize
;
102 memcpy(result
->value
.dptr
, data
.dptr
, data
.dsize
);
105 result
->value
.dptr
= NULL
;
111 static struct db_record
*db_tdb_fetch_locked_internal(
112 struct db_context
*db
, TALLOC_CTX
*mem_ctx
, TDB_DATA key
)
114 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
116 struct tdb_fetch_locked_state state
;
118 state
.mem_ctx
= mem_ctx
;
121 if ((tdb_parse_record(ctx
->wtdb
->tdb
, key
, db_tdb_fetchlock_parse
,
123 (tdb_error(ctx
->wtdb
->tdb
) != TDB_ERR_NOEXIST
)) {
124 tdb_chainunlock(ctx
->wtdb
->tdb
, key
);
128 if (state
.result
== NULL
) {
129 db_tdb_fetchlock_parse(key
, tdb_null
, &state
);
132 if (state
.result
== NULL
) {
133 tdb_chainunlock(ctx
->wtdb
->tdb
, key
);
137 talloc_set_destructor(state
.result
, db_tdb_record_destr
);
139 state
.result
->private_data
= talloc_reference(state
.result
, ctx
);
140 state
.result
->store
= db_tdb_store
;
141 state
.result
->delete_rec
= db_tdb_delete
;
143 DEBUG(10, ("Allocated locked data 0x%p\n", state
.result
));
148 static struct db_record
*db_tdb_fetch_locked(
149 struct db_context
*db
, TALLOC_CTX
*mem_ctx
, TDB_DATA key
)
151 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
154 db_tdb_log_key("Locking", key
);
155 if (tdb_chainlock(ctx
->wtdb
->tdb
, key
) != 0) {
156 DEBUG(3, ("tdb_chainlock failed\n"));
159 return db_tdb_fetch_locked_internal(db
, mem_ctx
, key
);
162 static struct db_record
*db_tdb_fetch_locked_timeout(
163 struct db_context
*db
, TALLOC_CTX
*mem_ctx
, TDB_DATA key
,
164 unsigned int timeout
)
166 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
169 db_tdb_log_key("Locking with timeout ", key
);
170 if (tdb_chainlock_with_timeout(ctx
->wtdb
->tdb
, key
, timeout
) != 0) {
171 DEBUG(3, ("tdb_chainlock_with_timeout failed\n"));
174 return db_tdb_fetch_locked_internal(db
, mem_ctx
, key
);
177 static struct db_record
*db_tdb_try_fetch_locked(
178 struct db_context
*db
, TALLOC_CTX
*mem_ctx
, TDB_DATA key
)
180 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
183 db_tdb_log_key("Trying to lock", key
);
184 if (tdb_chainlock_nonblock(ctx
->wtdb
->tdb
, key
) != 0) {
185 DEBUG(3, ("tdb_chainlock_nonblock failed\n"));
188 return db_tdb_fetch_locked_internal(db
, mem_ctx
, key
);
192 static int db_tdb_exists(struct db_context
*db
, TDB_DATA key
)
194 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(
195 db
->private_data
, struct db_tdb_ctx
);
196 return tdb_exists(ctx
->wtdb
->tdb
, key
);
199 static int db_tdb_wipe(struct db_context
*db
)
201 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(
202 db
->private_data
, struct db_tdb_ctx
);
203 return tdb_wipe_all(ctx
->wtdb
->tdb
);
206 static int db_tdb_check(struct db_context
*db
)
208 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(
209 db
->private_data
, struct db_tdb_ctx
);
210 return tdb_check(ctx
->wtdb
->tdb
, NULL
, NULL
);
213 struct db_tdb_parse_state
{
214 void (*parser
)(TDB_DATA key
, TDB_DATA data
,
220 * tdb_parse_record expects a parser returning int, mixing up tdb and
221 * parser errors. Wrap around that by always returning 0 and have
222 * dbwrap_parse_record expect a parser returning void.
225 static int db_tdb_parser(TDB_DATA key
, TDB_DATA data
, void *private_data
)
227 struct db_tdb_parse_state
*state
=
228 (struct db_tdb_parse_state
*)private_data
;
229 state
->parser(key
, data
, state
->private_data
);
233 static NTSTATUS
db_tdb_parse(struct db_context
*db
, TDB_DATA key
,
234 void (*parser
)(TDB_DATA key
, TDB_DATA data
,
238 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(
239 db
->private_data
, struct db_tdb_ctx
);
240 struct db_tdb_parse_state state
;
243 state
.parser
= parser
;
244 state
.private_data
= private_data
;
246 ret
= tdb_parse_record(ctx
->wtdb
->tdb
, key
, db_tdb_parser
, &state
);
249 return map_nt_error_from_tdb(tdb_error(ctx
->wtdb
->tdb
));
254 static NTSTATUS
db_tdb_store(struct db_record
*rec
, TDB_DATA data
, int flag
)
256 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(rec
->private_data
,
260 * This has a bug: We need to replace rec->value for correct
261 * operation, but right now brlock and locking don't use the value
262 * anymore after it was stored.
265 return (tdb_store(ctx
->wtdb
->tdb
, rec
->key
, data
, flag
) == 0) ?
266 NT_STATUS_OK
: NT_STATUS_UNSUCCESSFUL
;
269 static NTSTATUS
db_tdb_delete(struct db_record
*rec
)
271 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(rec
->private_data
,
274 if (tdb_delete(ctx
->wtdb
->tdb
, rec
->key
) == 0) {
278 if (tdb_error(ctx
->wtdb
->tdb
) == TDB_ERR_NOEXIST
) {
279 return NT_STATUS_NOT_FOUND
;
282 return NT_STATUS_UNSUCCESSFUL
;
285 struct db_tdb_traverse_ctx
{
286 struct db_context
*db
;
287 int (*f
)(struct db_record
*rec
, void *private_data
);
291 static int db_tdb_traverse_func(TDB_CONTEXT
*tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
294 struct db_tdb_traverse_ctx
*ctx
=
295 (struct db_tdb_traverse_ctx
*)private_data
;
296 struct db_record rec
;
300 rec
.store
= db_tdb_store
;
301 rec
.delete_rec
= db_tdb_delete
;
302 rec
.private_data
= ctx
->db
->private_data
;
305 return ctx
->f(&rec
, ctx
->private_data
);
308 static int db_tdb_traverse(struct db_context
*db
,
309 int (*f
)(struct db_record
*rec
, void *private_data
),
312 struct db_tdb_ctx
*db_ctx
=
313 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
314 struct db_tdb_traverse_ctx ctx
;
318 ctx
.private_data
= private_data
;
319 return tdb_traverse(db_ctx
->wtdb
->tdb
, db_tdb_traverse_func
, &ctx
);
322 static NTSTATUS
db_tdb_store_deny(struct db_record
*rec
, TDB_DATA data
, int flag
)
324 return NT_STATUS_MEDIA_WRITE_PROTECTED
;
327 static NTSTATUS
db_tdb_delete_deny(struct db_record
*rec
)
329 return NT_STATUS_MEDIA_WRITE_PROTECTED
;
332 static int db_tdb_traverse_read_func(TDB_CONTEXT
*tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
335 struct db_tdb_traverse_ctx
*ctx
=
336 (struct db_tdb_traverse_ctx
*)private_data
;
337 struct db_record rec
;
341 rec
.store
= db_tdb_store_deny
;
342 rec
.delete_rec
= db_tdb_delete_deny
;
343 rec
.private_data
= ctx
->db
->private_data
;
346 return ctx
->f(&rec
, ctx
->private_data
);
349 static int db_tdb_traverse_read(struct db_context
*db
,
350 int (*f
)(struct db_record
*rec
, void *private_data
),
353 struct db_tdb_ctx
*db_ctx
=
354 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
355 struct db_tdb_traverse_ctx ctx
;
359 ctx
.private_data
= private_data
;
360 return tdb_traverse_read(db_ctx
->wtdb
->tdb
, db_tdb_traverse_read_func
, &ctx
);
363 static int db_tdb_get_seqnum(struct db_context
*db
)
366 struct db_tdb_ctx
*db_ctx
=
367 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
368 return tdb_get_seqnum(db_ctx
->wtdb
->tdb
);
371 static int db_tdb_transaction_start(struct db_context
*db
)
373 struct db_tdb_ctx
*db_ctx
=
374 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
375 return tdb_transaction_start(db_ctx
->wtdb
->tdb
) ? -1 : 0;
378 static NTSTATUS
db_tdb_transaction_start_nonblock(struct db_context
*db
)
380 struct db_tdb_ctx
*db_ctx
=
381 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
384 ret
= tdb_transaction_start_nonblock(db_ctx
->wtdb
->tdb
);
386 return map_nt_error_from_tdb(tdb_error(db_ctx
->wtdb
->tdb
));
391 static int db_tdb_transaction_commit(struct db_context
*db
)
393 struct db_tdb_ctx
*db_ctx
=
394 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
395 return tdb_transaction_commit(db_ctx
->wtdb
->tdb
) ? -1 : 0;
398 static int db_tdb_transaction_cancel(struct db_context
*db
)
400 struct db_tdb_ctx
*db_ctx
=
401 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
402 tdb_transaction_cancel(db_ctx
->wtdb
->tdb
);
406 static void db_tdb_id(struct db_context
*db
, const uint8_t **id
, size_t *idlen
)
408 struct db_tdb_ctx
*db_ctx
=
409 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
410 *id
= (uint8_t *)&db_ctx
->id
;
411 *idlen
= sizeof(db_ctx
->id
);
414 struct db_context
*db_open_tdb(TALLOC_CTX
*mem_ctx
,
415 struct loadparm_context
*lp_ctx
,
417 int hash_size
, int tdb_flags
,
418 int open_flags
, mode_t mode
,
419 enum dbwrap_lock_order lock_order
)
421 struct db_context
*result
= NULL
;
422 struct db_tdb_ctx
*db_tdb
;
425 /* Extra paranoia. */
426 if (name
&& strends(name
, ".ntdb")) {
427 DEBUG(0, ("can't try to open %s with tdb!\n", name
));
431 result
= talloc_zero(mem_ctx
, struct db_context
);
432 if (result
== NULL
) {
433 DEBUG(0, ("talloc failed\n"));
437 result
->private_data
= db_tdb
= talloc(result
, struct db_tdb_ctx
);
438 if (db_tdb
== NULL
) {
439 DEBUG(0, ("talloc failed\n"));
442 result
->lock_order
= lock_order
;
444 db_tdb
->wtdb
= tdb_wrap_open(db_tdb
, name
, hash_size
, tdb_flags
,
445 open_flags
, mode
, lp_ctx
);
446 if (db_tdb
->wtdb
== NULL
) {
447 DEBUG(3, ("Could not open tdb: %s\n", strerror(errno
)));
451 ZERO_STRUCT(db_tdb
->id
);
453 if (fstat(tdb_fd(db_tdb
->wtdb
->tdb
), &st
) == -1) {
454 DEBUG(3, ("fstat failed: %s\n", strerror(errno
)));
457 db_tdb
->id
.dev
= st
.st_dev
;
458 db_tdb
->id
.ino
= st
.st_ino
;
460 result
->fetch_locked
= db_tdb_fetch_locked
;
461 result
->fetch_locked_timeout
= db_tdb_fetch_locked_timeout
;
462 result
->try_fetch_locked
= db_tdb_try_fetch_locked
;
463 result
->traverse
= db_tdb_traverse
;
464 result
->traverse_read
= db_tdb_traverse_read
;
465 result
->parse_record
= db_tdb_parse
;
466 result
->get_seqnum
= db_tdb_get_seqnum
;
467 result
->persistent
= ((tdb_flags
& TDB_CLEAR_IF_FIRST
) == 0);
468 result
->transaction_start
= db_tdb_transaction_start
;
469 result
->transaction_start_nonblock
= db_tdb_transaction_start_nonblock
;
470 result
->transaction_commit
= db_tdb_transaction_commit
;
471 result
->transaction_cancel
= db_tdb_transaction_cancel
;
472 result
->exists
= db_tdb_exists
;
473 result
->wipe
= db_tdb_wipe
;
474 result
->id
= db_tdb_id
;
475 result
->check
= db_tdb_check
;
476 result
->stored_callback
= NULL
;
477 result
->name
= tdb_name(db_tdb
->wtdb
->tdb
);
478 result
->hash_size
= hash_size
;
482 if (result
!= NULL
) {