Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Database interface wrapper
4 : Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2006
5 :
6 : Major code contributions from Aleksey Fedoseev (fedoseev@ru.ibm.com)
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "replace.h"
23 : #include "lib/util/debug.h"
24 : #include "lib/util/fault.h"
25 : #include "lib/util/talloc_stack.h"
26 : #include "dbwrap/dbwrap.h"
27 : #include "dbwrap/dbwrap_private.h"
28 : #include "lib/util/util_tdb.h"
29 : #include "lib/util/tevent_ntstatus.h"
30 :
31 : /*
32 : * Fall back using fetch if no genuine exists operation is provided
33 : */
34 :
35 0 : static int dbwrap_fallback_exists(struct db_context *db, TDB_DATA key)
36 : {
37 0 : NTSTATUS status = dbwrap_parse_record(db, key, NULL, NULL);
38 0 : return NT_STATUS_IS_OK(status) ? 1 : 0;
39 : }
40 :
41 0 : static int delete_record(struct db_record *rec, void *data)
42 : {
43 0 : NTSTATUS status = dbwrap_record_delete(rec);
44 0 : return NT_STATUS_IS_OK(status) ? 0 : -1;
45 : }
46 :
47 : /*
48 : * Fallback wipe implementation using traverse and delete if no genuine
49 : * wipe operation is provided
50 : */
51 0 : static int dbwrap_fallback_wipe(struct db_context *db)
52 : {
53 0 : NTSTATUS status = dbwrap_trans_traverse(db, delete_record, NULL);
54 0 : return NT_STATUS_IS_OK(status) ? 0 : -1;
55 : }
56 :
57 0 : static int do_nothing(struct db_record *rec, void *unused)
58 : {
59 0 : return 0;
60 : }
61 :
62 : /*
63 : * Fallback check operation: just traverse.
64 : */
65 0 : static int dbwrap_fallback_check(struct db_context *db)
66 : {
67 0 : NTSTATUS status = dbwrap_traverse_read(db, do_nothing, NULL, NULL);
68 0 : return NT_STATUS_IS_OK(status) ? 0 : -1;
69 : }
70 :
71 : /*
72 : * Wrapper functions for the backend methods
73 : */
74 :
75 8738221 : TDB_DATA dbwrap_record_get_key(const struct db_record *rec)
76 : {
77 8738221 : return rec->key;
78 : }
79 :
80 22940026 : TDB_DATA dbwrap_record_get_value(const struct db_record *rec)
81 : {
82 22940026 : SMB_ASSERT(rec->value_valid);
83 22940026 : return rec->value;
84 : }
85 :
86 8100446 : NTSTATUS dbwrap_record_storev(struct db_record *rec,
87 : const TDB_DATA *dbufs, int num_dbufs, int flags)
88 : {
89 66848 : NTSTATUS status;
90 :
91 : /*
92 : * Invalidate before rec->storev() is called, give
93 : * rec->storev() the chance to re-validate rec->value.
94 : */
95 8100446 : rec->value_valid = false;
96 :
97 8100446 : status = rec->storev(rec, dbufs, num_dbufs, flags);
98 8100446 : if (!NT_STATUS_IS_OK(status)) {
99 2 : return status;
100 : }
101 8100444 : return NT_STATUS_OK;
102 : }
103 :
104 5532063 : NTSTATUS dbwrap_record_store(struct db_record *rec, TDB_DATA data, int flags)
105 : {
106 5532063 : return dbwrap_record_storev(rec, &data, 1, flags);
107 : }
108 :
109 2383712 : NTSTATUS dbwrap_record_delete(struct db_record *rec)
110 : {
111 13860 : NTSTATUS status;
112 :
113 2383712 : status = rec->delete_rec(rec);
114 2383712 : if (!NT_STATUS_IS_OK(status)) {
115 217317 : return status;
116 : }
117 :
118 2166395 : rec->value = tdb_null;
119 :
120 2166395 : return NT_STATUS_OK;
121 : }
122 :
123 : struct dbwrap_merge_dbs_state {
124 : struct db_context *to;
125 : int flags;
126 : };
127 :
128 : /* Copy a single record to the db_context passed in private_data */
129 4 : static int dbwrap_merge_dbs_copy_record(struct db_record *rec,
130 : void *private_data)
131 : {
132 4 : struct dbwrap_merge_dbs_state *state = private_data;
133 :
134 4 : TDB_DATA data = dbwrap_record_get_value(rec);
135 4 : TDB_DATA key = dbwrap_record_get_key(rec);
136 4 : NTSTATUS status = dbwrap_store(state->to, key, data, state->flags);
137 :
138 4 : return NT_STATUS_IS_OK(status) ? 0 : 1;
139 : }
140 :
141 : NTSTATUS
142 2 : dbwrap_merge_dbs(struct db_context *to, struct db_context *from, int flags)
143 : {
144 2 : struct dbwrap_merge_dbs_state state = {.to = to, .flags = flags};
145 :
146 2 : return dbwrap_traverse(from,
147 : dbwrap_merge_dbs_copy_record,
148 : &state,
149 : NULL);
150 : }
151 :
152 : const char *locked_dbs[DBWRAP_LOCK_ORDER_MAX];
153 :
154 4126355 : static void debug_lock_order(int level)
155 : {
156 19387 : int i;
157 4126355 : DEBUG(level, ("lock order:"));
158 20631775 : for (i=0; i<DBWRAP_LOCK_ORDER_MAX; i++) {
159 16505420 : DEBUGADD(level,
160 : (" %d:%s",
161 : i + 1,
162 : locked_dbs[i] ? locked_dbs[i] : "<none>"));
163 : }
164 4126355 : DEBUGADD(level, ("\n"));
165 4126355 : }
166 :
167 4126355 : void dbwrap_lock_order_lock(const char *db_name,
168 : enum dbwrap_lock_order lock_order)
169 : {
170 19387 : int idx;
171 :
172 4126355 : DBG_INFO("check lock order %d for %s\n",
173 : (int)lock_order,
174 : db_name);
175 :
176 4126355 : if (!DBWRAP_LOCK_ORDER_VALID(lock_order)) {
177 0 : DBG_ERR("Invalid lock order %d of %s\n",
178 : lock_order,
179 : db_name);
180 0 : smb_panic("lock order violation");
181 : }
182 :
183 19500497 : for (idx=lock_order-1; idx<DBWRAP_LOCK_ORDER_MAX; idx++) {
184 15374142 : if (locked_dbs[idx] != NULL) {
185 0 : DBG_ERR("Lock order violation: Trying %s at %d while "
186 : "%s at %d is locked\n",
187 : db_name,
188 : (int)lock_order,
189 : locked_dbs[idx],
190 : idx + 1);
191 0 : debug_lock_order(0);
192 0 : smb_panic("lock order violation");
193 : }
194 : }
195 :
196 4126355 : locked_dbs[lock_order-1] = db_name;
197 :
198 4126355 : debug_lock_order(10);
199 4126355 : }
200 :
201 4126354 : void dbwrap_lock_order_unlock(const char *db_name,
202 : enum dbwrap_lock_order lock_order)
203 : {
204 4126354 : DBG_INFO("release lock order %d for %s\n",
205 : (int)lock_order,
206 : db_name);
207 :
208 4126354 : if (!DBWRAP_LOCK_ORDER_VALID(lock_order)) {
209 0 : DBG_ERR("Invalid lock order %d of %s\n",
210 : lock_order,
211 : db_name);
212 0 : smb_panic("lock order violation");
213 : }
214 :
215 4126354 : if (locked_dbs[lock_order-1] == NULL) {
216 0 : DBG_ERR("db %s at order %d unlocked\n",
217 : db_name,
218 : (int)lock_order);
219 0 : smb_panic("lock order violation");
220 : }
221 :
222 4126354 : if (locked_dbs[lock_order-1] != db_name) {
223 0 : DBG_ERR("locked db at lock order %d is %s, expected %s\n",
224 : (int)lock_order,
225 : locked_dbs[lock_order-1],
226 : db_name);
227 0 : smb_panic("lock order violation");
228 : }
229 :
230 4126354 : locked_dbs[lock_order-1] = NULL;
231 4126354 : }
232 :
233 : struct dbwrap_lock_order_state {
234 : struct db_context *db;
235 : };
236 :
237 1515420 : static int dbwrap_lock_order_state_destructor(
238 : struct dbwrap_lock_order_state *s)
239 : {
240 1515420 : struct db_context *db = s->db;
241 1515420 : dbwrap_lock_order_unlock(db->name, db->lock_order);
242 1515420 : return 0;
243 : }
244 :
245 1515421 : static struct dbwrap_lock_order_state *dbwrap_check_lock_order(
246 : struct db_context *db, TALLOC_CTX *mem_ctx)
247 : {
248 11387 : struct dbwrap_lock_order_state *state;
249 :
250 1515421 : state = talloc(mem_ctx, struct dbwrap_lock_order_state);
251 1515421 : if (state == NULL) {
252 0 : DBG_WARNING("talloc failed\n");
253 0 : return NULL;
254 : }
255 1515421 : state->db = db;
256 :
257 1515421 : dbwrap_lock_order_lock(db->name, db->lock_order);
258 1515421 : talloc_set_destructor(state, dbwrap_lock_order_state_destructor);
259 :
260 1515421 : return state;
261 : }
262 :
263 23493573 : static struct db_record *dbwrap_fetch_locked_internal(
264 : struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key,
265 : struct db_record *(*db_fn)(struct db_context *db, TALLOC_CTX *mem_ctx,
266 : TDB_DATA key))
267 : {
268 70501 : struct db_record *rec;
269 23493573 : struct dbwrap_lock_order_state *lock_order = NULL;
270 :
271 23493573 : if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
272 1515421 : lock_order = dbwrap_check_lock_order(db, mem_ctx);
273 1515421 : if (lock_order == NULL) {
274 0 : return NULL;
275 : }
276 : }
277 23493573 : rec = db_fn(db, mem_ctx, key);
278 23493573 : if (rec == NULL) {
279 0 : TALLOC_FREE(lock_order);
280 0 : return NULL;
281 : }
282 23493573 : (void)talloc_steal(rec, lock_order);
283 23493573 : rec->db = db;
284 23493573 : return rec;
285 : }
286 :
287 23493573 : struct db_record *dbwrap_fetch_locked(struct db_context *db,
288 : TALLOC_CTX *mem_ctx,
289 : TDB_DATA key)
290 : {
291 23493573 : return dbwrap_fetch_locked_internal(db, mem_ctx, key,
292 : db->fetch_locked);
293 : }
294 :
295 1868472 : struct db_context *dbwrap_record_get_db(struct db_record *rec)
296 : {
297 1868472 : return rec->db;
298 : }
299 :
300 : struct dbwrap_fetch_state {
301 : TALLOC_CTX *mem_ctx;
302 : TDB_DATA data;
303 : };
304 :
305 25479023 : static void dbwrap_fetch_parser(TDB_DATA key, TDB_DATA data,
306 : void *private_data)
307 : {
308 25479023 : struct dbwrap_fetch_state *state =
309 : (struct dbwrap_fetch_state *)private_data;
310 :
311 25479023 : state->data.dsize = data.dsize;
312 25479023 : state->data.dptr = (uint8_t *)talloc_memdup(state->mem_ctx, data.dptr,
313 : data.dsize);
314 25479023 : }
315 :
316 34668723 : NTSTATUS dbwrap_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
317 : TDB_DATA key, TDB_DATA *value)
318 : {
319 106194 : struct dbwrap_fetch_state state;
320 106194 : NTSTATUS status;
321 :
322 34668723 : if (value == NULL) {
323 0 : return NT_STATUS_INVALID_PARAMETER;
324 : }
325 :
326 34668723 : state.mem_ctx = mem_ctx;
327 :
328 34668723 : status = dbwrap_parse_record(db, key, dbwrap_fetch_parser, &state);
329 34668723 : if (!NT_STATUS_IS_OK(status)) {
330 9189700 : return status;
331 : }
332 25479023 : if ((state.data.dsize != 0) && (state.data.dptr == NULL)) {
333 0 : return NT_STATUS_NO_MEMORY;
334 : }
335 25479023 : *value = state.data;
336 25479023 : return NT_STATUS_OK;
337 : }
338 :
339 966203 : bool dbwrap_exists(struct db_context *db, TDB_DATA key)
340 : {
341 2594 : int result;
342 966203 : if (db->exists != NULL) {
343 966203 : result = db->exists(db, key);
344 : } else {
345 0 : result = dbwrap_fallback_exists(db,key);
346 : }
347 966203 : return (result == 1);
348 : }
349 :
350 : struct dbwrap_store_state {
351 : TDB_DATA data;
352 : int flags;
353 : NTSTATUS status;
354 : };
355 :
356 3550492 : static void dbwrap_store_fn(
357 : struct db_record *rec,
358 : TDB_DATA value,
359 : void *private_data)
360 : {
361 3550492 : struct dbwrap_store_state *state = private_data;
362 3550492 : state->status = dbwrap_record_store(rec, state->data, state->flags);
363 3550492 : }
364 :
365 3550492 : NTSTATUS dbwrap_store(struct db_context *db, TDB_DATA key,
366 : TDB_DATA data, int flags)
367 : {
368 3550492 : struct dbwrap_store_state state = { .data = data, .flags = flags };
369 43571 : NTSTATUS status;
370 :
371 3550492 : status = dbwrap_do_locked(db, key, dbwrap_store_fn, &state);
372 3550492 : if (!NT_STATUS_IS_OK(status)) {
373 0 : return status;
374 : }
375 :
376 3550492 : return state.status;
377 : }
378 :
379 : struct dbwrap_delete_state {
380 : NTSTATUS status;
381 : };
382 :
383 221390 : static void dbwrap_delete_fn(
384 : struct db_record *rec,
385 : TDB_DATA value,
386 : void *private_data)
387 : {
388 221390 : struct dbwrap_delete_state *state = private_data;
389 221390 : state->status = dbwrap_record_delete(rec);
390 221390 : }
391 :
392 221390 : NTSTATUS dbwrap_delete(struct db_context *db, TDB_DATA key)
393 : {
394 221390 : struct dbwrap_delete_state state = { .status = NT_STATUS_NOT_FOUND };
395 3033 : NTSTATUS status;
396 :
397 221390 : status = dbwrap_do_locked(db, key, dbwrap_delete_fn, &state);
398 221390 : if (!NT_STATUS_IS_OK(status)) {
399 0 : return status;
400 : }
401 :
402 221390 : return state.status;
403 : }
404 :
405 74748 : NTSTATUS dbwrap_traverse(struct db_context *db,
406 : int (*f)(struct db_record*, void*),
407 : void *private_data,
408 : int *count)
409 : {
410 74748 : int ret = db->traverse(db, f, private_data);
411 :
412 74748 : if (ret < 0) {
413 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
414 : }
415 :
416 74748 : if (count != NULL) {
417 74372 : *count = ret;
418 : }
419 :
420 74748 : return NT_STATUS_OK;
421 : }
422 :
423 238111 : NTSTATUS dbwrap_traverse_read(struct db_context *db,
424 : int (*f)(struct db_record*, void*),
425 : void *private_data,
426 : int *count)
427 : {
428 238111 : int ret = db->traverse_read(db, f, private_data);
429 :
430 238111 : if (ret < 0) {
431 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
432 : }
433 :
434 238111 : if (count != NULL) {
435 12824 : *count = ret;
436 : }
437 :
438 238111 : return NT_STATUS_OK;
439 : }
440 :
441 0 : static void dbwrap_null_parser(TDB_DATA key, TDB_DATA val, void* data)
442 : {
443 0 : return;
444 : }
445 :
446 46508877 : NTSTATUS dbwrap_parse_record(struct db_context *db, TDB_DATA key,
447 : void (*parser)(TDB_DATA key, TDB_DATA data,
448 : void *private_data),
449 : void *private_data)
450 : {
451 46508877 : if (parser == NULL) {
452 1 : parser = dbwrap_null_parser;
453 : }
454 46508877 : return db->parse_record(db, key, parser, private_data);
455 : }
456 :
457 : struct dbwrap_parse_record_state {
458 : struct db_context *db;
459 : TDB_DATA key;
460 : uint8_t _keybuf[64];
461 : };
462 :
463 : static void dbwrap_parse_record_done(struct tevent_req *subreq);
464 :
465 0 : struct tevent_req *dbwrap_parse_record_send(
466 : TALLOC_CTX *mem_ctx,
467 : struct tevent_context *ev,
468 : struct db_context *db,
469 : TDB_DATA key,
470 : void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data),
471 : void *private_data,
472 : enum dbwrap_req_state *req_state)
473 : {
474 0 : struct tevent_req *req = NULL;
475 0 : struct tevent_req *subreq = NULL;
476 0 : struct dbwrap_parse_record_state *state = NULL;
477 0 : NTSTATUS status;
478 :
479 0 : req = tevent_req_create(mem_ctx, &state, struct dbwrap_parse_record_state);
480 0 : if (req == NULL) {
481 0 : *req_state = DBWRAP_REQ_ERROR;
482 0 : return NULL;
483 : }
484 :
485 0 : *state = (struct dbwrap_parse_record_state) {
486 : .db = db,
487 : };
488 :
489 0 : if (parser == NULL) {
490 0 : parser = dbwrap_null_parser;
491 : }
492 :
493 0 : *req_state = DBWRAP_REQ_INIT;
494 :
495 0 : if (db->parse_record_send == NULL) {
496 : /*
497 : * Backend doesn't implement async version, call sync one
498 : */
499 0 : status = db->parse_record(db, key, parser, private_data);
500 0 : if (tevent_req_nterror(req, status)) {
501 0 : *req_state = DBWRAP_REQ_DONE;
502 0 : return tevent_req_post(req, ev);
503 : }
504 :
505 0 : *req_state = DBWRAP_REQ_DONE;
506 0 : tevent_req_done(req);
507 0 : return tevent_req_post(req, ev);
508 : }
509 :
510 : /*
511 : * Copy the key into our state ensuring the key data buffer is always
512 : * available to all the dbwrap backends over the entire lifetime of the
513 : * async request. Otherwise the caller might have free'd the key buffer.
514 : */
515 0 : if (key.dsize > sizeof(state->_keybuf)) {
516 0 : state->key.dptr = talloc_memdup(state, key.dptr, key.dsize);
517 0 : if (tevent_req_nomem(state->key.dptr, req)) {
518 0 : return tevent_req_post(req, ev);
519 : }
520 : } else {
521 0 : memcpy(state->_keybuf, key.dptr, key.dsize);
522 0 : state->key.dptr = state->_keybuf;
523 : }
524 0 : state->key.dsize = key.dsize;
525 :
526 0 : subreq = db->parse_record_send(state,
527 : ev,
528 : db,
529 0 : state->key,
530 : parser,
531 : private_data,
532 : req_state);
533 0 : if (tevent_req_nomem(subreq, req)) {
534 0 : *req_state = DBWRAP_REQ_ERROR;
535 0 : return tevent_req_post(req, ev);
536 : }
537 :
538 0 : tevent_req_set_callback(subreq,
539 : dbwrap_parse_record_done,
540 : req);
541 0 : return req;
542 : }
543 :
544 0 : static void dbwrap_parse_record_done(struct tevent_req *subreq)
545 : {
546 0 : struct tevent_req *req = tevent_req_callback_data(
547 : subreq, struct tevent_req);
548 0 : struct dbwrap_parse_record_state *state = tevent_req_data(
549 : req, struct dbwrap_parse_record_state);
550 0 : NTSTATUS status;
551 :
552 0 : status = state->db->parse_record_recv(subreq);
553 0 : TALLOC_FREE(subreq);
554 0 : if (!NT_STATUS_IS_OK(status)) {
555 0 : tevent_req_nterror(req, status);
556 0 : return;
557 : }
558 :
559 0 : tevent_req_done(req);
560 : }
561 :
562 0 : NTSTATUS dbwrap_parse_record_recv(struct tevent_req *req)
563 : {
564 0 : return tevent_req_simple_recv_ntstatus(req);
565 : }
566 :
567 8158271 : NTSTATUS dbwrap_do_locked(struct db_context *db, TDB_DATA key,
568 : void (*fn)(struct db_record *rec,
569 : TDB_DATA value,
570 : void *private_data),
571 : void *private_data)
572 : {
573 58282 : struct db_record *rec;
574 :
575 8158271 : if (db->do_locked != NULL) {
576 16732 : NTSTATUS status;
577 :
578 4498234 : if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
579 1183127 : dbwrap_lock_order_lock(db->name, db->lock_order);
580 : }
581 :
582 4498234 : status = db->do_locked(db, key, fn, private_data);
583 :
584 4498234 : if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
585 1183127 : dbwrap_lock_order_unlock(db->name, db->lock_order);
586 : }
587 :
588 4498234 : return status;
589 : }
590 :
591 3660037 : rec = dbwrap_fetch_locked(db, db, key);
592 3660037 : if (rec == NULL) {
593 0 : return NT_STATUS_NO_MEMORY;
594 : }
595 :
596 : /*
597 : * Invalidate rec->value, nobody shall assume it's set from
598 : * within dbwrap_do_locked().
599 : */
600 3660037 : rec->value_valid = false;
601 :
602 3660037 : fn(rec, rec->value, private_data);
603 :
604 3660037 : TALLOC_FREE(rec);
605 :
606 3660037 : return NT_STATUS_OK;
607 : }
608 :
609 45 : int dbwrap_wipe(struct db_context *db)
610 : {
611 45 : if (db->wipe == NULL) {
612 0 : return dbwrap_fallback_wipe(db);
613 : }
614 45 : return db->wipe(db);
615 : }
616 :
617 0 : int dbwrap_check(struct db_context *db)
618 : {
619 0 : if (db->check == NULL) {
620 0 : return dbwrap_fallback_check(db);
621 : }
622 0 : return db->check(db);
623 : }
624 :
625 2670237 : int dbwrap_get_seqnum(struct db_context *db)
626 : {
627 2670237 : return db->get_seqnum(db);
628 : }
629 :
630 117485 : int dbwrap_transaction_start(struct db_context *db)
631 : {
632 117485 : if (!db->persistent) {
633 : /*
634 : * dbwrap_ctdb has two different data models for persistent
635 : * and non-persistent databases. Transactions are supported
636 : * only for the persistent databases. This check is here to
637 : * prevent breakages of the cluster case, autobuild at this
638 : * point only tests non-clustered Samba. Before removing this
639 : * check, please make sure that this facility has also been
640 : * added to dbwrap_ctdb.
641 : *
642 : * Thanks, vl
643 : */
644 0 : DEBUG(1, ("transactions not supported on non-persistent "
645 : "database %s\n", db->name));
646 0 : return -1;
647 : }
648 117485 : return db->transaction_start(db);
649 : }
650 :
651 0 : NTSTATUS dbwrap_transaction_start_nonblock(struct db_context *db)
652 : {
653 0 : if (db->transaction_start_nonblock) {
654 0 : return db->transaction_start_nonblock(db);
655 : } else {
656 0 : return dbwrap_transaction_start(db) == 0 ? NT_STATUS_OK
657 0 : : NT_STATUS_UNSUCCESSFUL;
658 : }
659 : }
660 :
661 117257 : int dbwrap_transaction_commit(struct db_context *db)
662 : {
663 117257 : return db->transaction_commit(db);
664 : }
665 :
666 227 : int dbwrap_transaction_cancel(struct db_context *db)
667 : {
668 227 : return db->transaction_cancel(db);
669 : }
670 :
671 0 : size_t dbwrap_db_id(struct db_context *db, uint8_t *id, size_t idlen)
672 : {
673 0 : return db->id(db, id, idlen);
674 : }
675 :
676 10 : bool dbwrap_is_persistent(struct db_context *db)
677 : {
678 10 : return db->persistent;
679 : }
680 :
681 2856021 : const char *dbwrap_name(struct db_context *db)
682 : {
683 2856021 : return db->name;
684 : }
685 :
686 1513224 : static ssize_t tdb_data_buf(const TDB_DATA *dbufs, int num_dbufs,
687 : uint8_t *buf, size_t buflen)
688 : {
689 1513224 : size_t needed = 0;
690 1513224 : uint8_t *p = buf;
691 3830 : int i;
692 :
693 5538882 : for (i=0; i<num_dbufs; i++) {
694 4025658 : size_t thislen = dbufs[i].dsize;
695 :
696 4025658 : needed += thislen;
697 4025658 : if (needed < thislen) {
698 : /* wrap */
699 0 : return -1;
700 : }
701 :
702 4025658 : if (p != NULL && (thislen != 0) && (needed <= buflen)) {
703 1570550 : memcpy(p, dbufs[i].dptr, thislen);
704 1570550 : p += thislen;
705 : }
706 : }
707 :
708 1513224 : return needed;
709 : }
710 :
711 :
712 756612 : NTSTATUS dbwrap_merge_dbufs(TDB_DATA *buf, TALLOC_CTX *mem_ctx,
713 : const TDB_DATA *dbufs, int num_dbufs)
714 : {
715 756612 : ssize_t len = tdb_data_buf(dbufs, num_dbufs, NULL, 0);
716 :
717 756612 : if (len == -1) {
718 0 : return NT_STATUS_INVALID_PARAMETER;
719 : }
720 :
721 756612 : if (buf->dsize != len) {
722 1375 : uint8_t *tmp;
723 :
724 514217 : tmp = talloc_realloc(mem_ctx, buf->dptr, uint8_t, len);
725 514217 : if (tmp == NULL && len != 0) {
726 0 : return NT_STATUS_NO_MEMORY;
727 : }
728 :
729 514217 : buf->dptr = tmp;
730 514217 : buf->dsize = len;
731 : }
732 :
733 756612 : tdb_data_buf(dbufs, num_dbufs, buf->dptr, buf->dsize);
734 :
735 756612 : return NT_STATUS_OK;
736 : }
|