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/util/tdb_wrap.h"
25 #include "lib/param/param.h"
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
)
40 if (DEBUGLEVEL
< 10) {
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
),
52 DEBUG(10, ("%s key %s\n", prefix
, 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
);
66 struct tdb_fetch_locked_state
{
68 struct db_record
*result
;
71 static int db_tdb_fetchlock_parse(TDB_DATA key
, TDB_DATA data
,
74 struct tdb_fetch_locked_state
*state
=
75 (struct tdb_fetch_locked_state
*)private_data
;
77 state
->result
= (struct db_record
*)talloc_size(
79 sizeof(struct db_record
) + key
.dsize
+ data
.dsize
);
81 if (state
->result
== NULL
) {
85 state
->result
->key
.dsize
= key
.dsize
;
86 state
->result
->key
.dptr
= ((uint8
*)state
->result
)
87 + sizeof(struct db_record
);
88 memcpy(state
->result
->key
.dptr
, key
.dptr
, key
.dsize
);
90 state
->result
->value
.dsize
= data
.dsize
;
93 state
->result
->value
.dptr
= state
->result
->key
.dptr
+key
.dsize
;
94 memcpy(state
->result
->value
.dptr
, data
.dptr
, data
.dsize
);
97 state
->result
->value
.dptr
= NULL
;
103 static struct db_record
*db_tdb_fetch_locked(struct db_context
*db
,
104 TALLOC_CTX
*mem_ctx
, TDB_DATA key
)
106 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(db
->private_data
,
108 struct tdb_fetch_locked_state state
;
110 db_tdb_log_key("Locking", key
);
112 if (tdb_chainlock(ctx
->wtdb
->tdb
, key
) != 0) {
113 DEBUG(3, ("tdb_chainlock failed\n"));
117 state
.mem_ctx
= mem_ctx
;
120 tdb_parse_record(ctx
->wtdb
->tdb
, key
, db_tdb_fetchlock_parse
, &state
);
122 if (state
.result
== NULL
) {
123 db_tdb_fetchlock_parse(key
, tdb_null
, &state
);
126 if (state
.result
== NULL
) {
127 tdb_chainunlock(ctx
->wtdb
->tdb
, key
);
131 talloc_set_destructor(state
.result
, db_tdb_record_destr
);
133 state
.result
->private_data
= talloc_reference(state
.result
, ctx
);
134 state
.result
->store
= db_tdb_store
;
135 state
.result
->delete_rec
= db_tdb_delete
;
137 DEBUG(10, ("Allocated locked data 0x%p\n", state
.result
));
142 struct tdb_fetch_state
{
148 static int db_tdb_fetch_parse(TDB_DATA key
, TDB_DATA data
,
151 struct tdb_fetch_state
*state
=
152 (struct tdb_fetch_state
*)private_data
;
154 if (data
.dptr
== NULL
) {
155 /* should not happen */
156 state
->result
= NT_STATUS_INTERNAL_DB_ERROR
;
160 state
->data
.dptr
= (uint8
*)talloc_memdup(state
->mem_ctx
, data
.dptr
,
162 if (state
->data
.dptr
== NULL
) {
163 state
->result
= NT_STATUS_NO_MEMORY
;
167 state
->data
.dsize
= data
.dsize
;
171 static NTSTATUS
db_tdb_fetch(struct db_context
*db
, TALLOC_CTX
*mem_ctx
,
172 TDB_DATA key
, TDB_DATA
*pdata
)
174 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(
175 db
->private_data
, struct db_tdb_ctx
);
177 struct tdb_fetch_state state
;
180 state
.mem_ctx
= mem_ctx
;
181 state
.result
= NT_STATUS_OK
;
182 state
.data
= tdb_null
;
184 ret
= tdb_parse_record(ctx
->wtdb
->tdb
, key
, db_tdb_fetch_parse
, &state
);
189 if (!NT_STATUS_IS_OK(state
.result
)) {
190 /* the parser has set an error code. return it */
194 status
= map_nt_error_from_tdb(tdb_error(ctx
->wtdb
->tdb
));
198 if (!NT_STATUS_IS_OK(state
.result
)) {
206 static int db_tdb_exists(struct db_context
*db
, TDB_DATA key
)
208 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(
209 db
->private_data
, struct db_tdb_ctx
);
210 return tdb_exists(ctx
->wtdb
->tdb
, key
);
213 static int db_tdb_wipe(struct db_context
*db
)
215 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(
216 db
->private_data
, struct db_tdb_ctx
);
217 return tdb_wipe_all(ctx
->wtdb
->tdb
);
220 static int db_tdb_parse(struct db_context
*db
, TDB_DATA key
,
221 int (*parser
)(TDB_DATA key
, TDB_DATA data
,
225 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(
226 db
->private_data
, struct db_tdb_ctx
);
228 return tdb_parse_record(ctx
->wtdb
->tdb
, key
, parser
, private_data
) ? -1 : 0;
231 static NTSTATUS
db_tdb_store(struct db_record
*rec
, TDB_DATA data
, int flag
)
233 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(rec
->private_data
,
237 * This has a bug: We need to replace rec->value for correct
238 * operation, but right now brlock and locking don't use the value
239 * anymore after it was stored.
242 return (tdb_store(ctx
->wtdb
->tdb
, rec
->key
, data
, flag
) == 0) ?
243 NT_STATUS_OK
: NT_STATUS_UNSUCCESSFUL
;
246 static NTSTATUS
db_tdb_delete(struct db_record
*rec
)
248 struct db_tdb_ctx
*ctx
= talloc_get_type_abort(rec
->private_data
,
251 if (tdb_delete(ctx
->wtdb
->tdb
, rec
->key
) == 0) {
255 if (tdb_error(ctx
->wtdb
->tdb
) == TDB_ERR_NOEXIST
) {
256 return NT_STATUS_NOT_FOUND
;
259 return NT_STATUS_UNSUCCESSFUL
;
262 struct db_tdb_traverse_ctx
{
263 struct db_context
*db
;
264 int (*f
)(struct db_record
*rec
, void *private_data
);
268 static int db_tdb_traverse_func(TDB_CONTEXT
*tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
271 struct db_tdb_traverse_ctx
*ctx
=
272 (struct db_tdb_traverse_ctx
*)private_data
;
273 struct db_record rec
;
277 rec
.store
= db_tdb_store
;
278 rec
.delete_rec
= db_tdb_delete
;
279 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
;
321 return ctx
->f(&rec
, ctx
->private_data
);
324 static int db_tdb_traverse_read(struct db_context
*db
,
325 int (*f
)(struct db_record
*rec
, void *private_data
),
328 struct db_tdb_ctx
*db_ctx
=
329 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
330 struct db_tdb_traverse_ctx ctx
;
334 ctx
.private_data
= private_data
;
335 return tdb_traverse_read(db_ctx
->wtdb
->tdb
, db_tdb_traverse_read_func
, &ctx
);
338 static int db_tdb_get_seqnum(struct db_context
*db
)
341 struct db_tdb_ctx
*db_ctx
=
342 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
343 return tdb_get_seqnum(db_ctx
->wtdb
->tdb
);
346 static int db_tdb_get_flags(struct db_context
*db
)
349 struct db_tdb_ctx
*db_ctx
=
350 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
351 return tdb_get_flags(db_ctx
->wtdb
->tdb
);
354 static int db_tdb_transaction_start(struct db_context
*db
)
356 struct db_tdb_ctx
*db_ctx
=
357 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
358 return tdb_transaction_start(db_ctx
->wtdb
->tdb
) ? -1 : 0;
361 static int db_tdb_transaction_commit(struct db_context
*db
)
363 struct db_tdb_ctx
*db_ctx
=
364 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
365 return tdb_transaction_commit(db_ctx
->wtdb
->tdb
) ? -1 : 0;
368 static int db_tdb_transaction_cancel(struct db_context
*db
)
370 struct db_tdb_ctx
*db_ctx
=
371 talloc_get_type_abort(db
->private_data
, struct db_tdb_ctx
);
372 tdb_transaction_cancel(db_ctx
->wtdb
->tdb
);
376 struct db_context
*db_open_tdb(TALLOC_CTX
*mem_ctx
,
378 int hash_size
, int tdb_flags
,
379 int open_flags
, mode_t mode
)
381 struct db_context
*result
= NULL
;
382 struct db_tdb_ctx
*db_tdb
;
383 struct loadparm_context
*lp_ctx
;
385 result
= talloc_zero(mem_ctx
, struct db_context
);
386 if (result
== NULL
) {
387 DEBUG(0, ("talloc failed\n"));
390 lp_ctx
= loadparm_init_s3(result
, loadparm_s3_context());
392 result
->private_data
= db_tdb
= talloc(result
, struct db_tdb_ctx
);
393 if (db_tdb
== NULL
) {
394 DEBUG(0, ("talloc failed\n"));
398 db_tdb
->wtdb
= tdb_wrap_open(db_tdb
, name
, hash_size
, tdb_flags
,
399 open_flags
, mode
, lp_ctx
);
400 talloc_unlink(result
, lp_ctx
);
401 if (db_tdb
->wtdb
== NULL
) {
402 DEBUG(3, ("Could not open tdb: %s\n", strerror(errno
)));
406 result
->fetch_locked
= db_tdb_fetch_locked
;
407 result
->fetch
= db_tdb_fetch
;
408 result
->traverse
= db_tdb_traverse
;
409 result
->traverse_read
= db_tdb_traverse_read
;
410 result
->parse_record
= db_tdb_parse
;
411 result
->get_seqnum
= db_tdb_get_seqnum
;
412 result
->get_flags
= db_tdb_get_flags
;
413 result
->persistent
= ((tdb_flags
& TDB_CLEAR_IF_FIRST
) == 0);
414 result
->transaction_start
= db_tdb_transaction_start
;
415 result
->transaction_commit
= db_tdb_transaction_commit
;
416 result
->transaction_cancel
= db_tdb_transaction_cancel
;
417 result
->exists
= db_tdb_exists
;
418 result
->wipe
= db_tdb_wipe
;
422 if (result
!= NULL
) {