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 380388 : TDB_DATA dbwrap_record_get_key(const struct db_record *rec)
76 : {
77 380388 : return rec->key;
78 : }
79 :
80 8238206 : TDB_DATA dbwrap_record_get_value(const struct db_record *rec)
81 : {
82 8238206 : SMB_ASSERT(rec->value_valid);
83 8238206 : return rec->value;
84 : }
85 :
86 1936167 : NTSTATUS dbwrap_record_storev(struct db_record *rec,
87 : const TDB_DATA *dbufs, int num_dbufs, int flags)
88 : {
89 : NTSTATUS status;
90 :
91 : /*
92 : * Invalidate before rec->storev() is called, give
93 : * rec->storev() the chance to re-validate rec->value.
94 : */
95 1936167 : rec->value_valid = false;
96 :
97 1936167 : status = rec->storev(rec, dbufs, num_dbufs, flags);
98 1936167 : if (!NT_STATUS_IS_OK(status)) {
99 0 : return status;
100 : }
101 1936167 : return NT_STATUS_OK;
102 : }
103 :
104 1735066 : NTSTATUS dbwrap_record_store(struct db_record *rec, TDB_DATA data, int flags)
105 : {
106 1735066 : return dbwrap_record_storev(rec, &data, 1, flags);
107 : }
108 :
109 360967 : NTSTATUS dbwrap_record_delete(struct db_record *rec)
110 : {
111 : NTSTATUS status;
112 :
113 360967 : status = rec->delete_rec(rec);
114 360967 : if (!NT_STATUS_IS_OK(status)) {
115 35684 : return status;
116 : }
117 :
118 325283 : rec->value = tdb_null;
119 :
120 325283 : return NT_STATUS_OK;
121 : }
122 :
123 : const char *locked_dbs[DBWRAP_LOCK_ORDER_MAX];
124 :
125 137812 : static void debug_lock_order(int level)
126 : {
127 : int i;
128 137812 : DEBUG(level, ("lock order: "));
129 689060 : for (i=0; i<DBWRAP_LOCK_ORDER_MAX; i++) {
130 551248 : DEBUGADD(level,
131 : (" %d:%s",
132 : i + 1,
133 : locked_dbs[i] ? locked_dbs[i] : "<none>"));
134 : }
135 137812 : DEBUGADD(level, ("\n"));
136 137812 : }
137 :
138 137812 : void dbwrap_lock_order_lock(const char *db_name,
139 : enum dbwrap_lock_order lock_order)
140 : {
141 : int idx;
142 :
143 137812 : DBG_INFO("check lock order %d for %s\n",
144 : (int)lock_order,
145 : db_name);
146 :
147 137812 : if (!DBWRAP_LOCK_ORDER_VALID(lock_order)) {
148 0 : DBG_ERR("Invalid lock order %d of %s\n",
149 : lock_order,
150 : db_name);
151 0 : smb_panic("lock order violation");
152 : }
153 :
154 674906 : for (idx=lock_order-1; idx<DBWRAP_LOCK_ORDER_MAX; idx++) {
155 537094 : if (locked_dbs[idx] != NULL) {
156 0 : DBG_ERR("Lock order violation: Trying %s at %d while "
157 : "%s at %d is locked\n",
158 : db_name,
159 : (int)lock_order,
160 : locked_dbs[idx],
161 : idx + 1);
162 0 : debug_lock_order(0);
163 0 : smb_panic("lock order violation");
164 : }
165 : }
166 :
167 137812 : locked_dbs[lock_order-1] = db_name;
168 :
169 137812 : debug_lock_order(10);
170 137812 : }
171 :
172 137812 : void dbwrap_lock_order_unlock(const char *db_name,
173 : enum dbwrap_lock_order lock_order)
174 : {
175 137812 : DBG_INFO("release lock order %d for %s\n",
176 : (int)lock_order,
177 : db_name);
178 :
179 137812 : if (!DBWRAP_LOCK_ORDER_VALID(lock_order)) {
180 0 : DBG_ERR("Invalid lock order %d of %s\n",
181 : lock_order,
182 : db_name);
183 0 : smb_panic("lock order violation");
184 : }
185 :
186 137812 : if (locked_dbs[lock_order-1] == NULL) {
187 0 : DBG_ERR("db %s at order %d unlocked\n",
188 : db_name,
189 : (int)lock_order);
190 0 : smb_panic("lock order violation");
191 : }
192 :
193 137812 : if (locked_dbs[lock_order-1] != db_name) {
194 0 : DBG_ERR("locked db at lock order %d is %s, expected %s\n",
195 : (int)lock_order,
196 : locked_dbs[lock_order-1],
197 : db_name);
198 0 : smb_panic("lock order violation");
199 : }
200 :
201 137812 : locked_dbs[lock_order-1] = NULL;
202 137812 : }
203 :
204 : struct dbwrap_lock_order_state {
205 : struct db_context *db;
206 : };
207 :
208 101145 : static int dbwrap_lock_order_state_destructor(
209 : struct dbwrap_lock_order_state *s)
210 : {
211 101145 : struct db_context *db = s->db;
212 101145 : dbwrap_lock_order_unlock(db->name, db->lock_order);
213 101145 : return 0;
214 : }
215 :
216 101145 : static struct dbwrap_lock_order_state *dbwrap_check_lock_order(
217 : struct db_context *db, TALLOC_CTX *mem_ctx)
218 : {
219 : struct dbwrap_lock_order_state *state;
220 :
221 101145 : state = talloc(mem_ctx, struct dbwrap_lock_order_state);
222 101145 : if (state == NULL) {
223 0 : DBG_WARNING("talloc failed\n");
224 0 : return NULL;
225 : }
226 101145 : state->db = db;
227 :
228 101145 : dbwrap_lock_order_lock(db->name, db->lock_order);
229 101145 : talloc_set_destructor(state, dbwrap_lock_order_state_destructor);
230 :
231 101145 : return state;
232 : }
233 :
234 9668428 : static struct db_record *dbwrap_fetch_locked_internal(
235 : struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key,
236 : struct db_record *(*db_fn)(struct db_context *db, TALLOC_CTX *mem_ctx,
237 : TDB_DATA key))
238 : {
239 : struct db_record *rec;
240 9668428 : struct dbwrap_lock_order_state *lock_order = NULL;
241 :
242 9668428 : if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
243 101145 : lock_order = dbwrap_check_lock_order(db, mem_ctx);
244 101145 : if (lock_order == NULL) {
245 0 : return NULL;
246 : }
247 : }
248 9668428 : rec = db_fn(db, mem_ctx, key);
249 9668428 : if (rec == NULL) {
250 0 : TALLOC_FREE(lock_order);
251 0 : return NULL;
252 : }
253 9668428 : (void)talloc_steal(rec, lock_order);
254 9668428 : rec->db = db;
255 9668428 : return rec;
256 : }
257 :
258 9668428 : struct db_record *dbwrap_fetch_locked(struct db_context *db,
259 : TALLOC_CTX *mem_ctx,
260 : TDB_DATA key)
261 : {
262 9668428 : return dbwrap_fetch_locked_internal(db, mem_ctx, key,
263 : db->fetch_locked);
264 : }
265 :
266 135060 : struct db_context *dbwrap_record_get_db(struct db_record *rec)
267 : {
268 135060 : return rec->db;
269 : }
270 :
271 : struct dbwrap_fetch_state {
272 : TALLOC_CTX *mem_ctx;
273 : TDB_DATA data;
274 : };
275 :
276 619705 : static void dbwrap_fetch_parser(TDB_DATA key, TDB_DATA data,
277 : void *private_data)
278 : {
279 619705 : struct dbwrap_fetch_state *state =
280 : (struct dbwrap_fetch_state *)private_data;
281 :
282 619705 : state->data.dsize = data.dsize;
283 619705 : state->data.dptr = (uint8_t *)talloc_memdup(state->mem_ctx, data.dptr,
284 : data.dsize);
285 619705 : }
286 :
287 1418367 : NTSTATUS dbwrap_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
288 : TDB_DATA key, TDB_DATA *value)
289 : {
290 : struct dbwrap_fetch_state state;
291 : NTSTATUS status;
292 :
293 1418367 : if (value == NULL) {
294 0 : return NT_STATUS_INVALID_PARAMETER;
295 : }
296 :
297 1418367 : state.mem_ctx = mem_ctx;
298 :
299 1418367 : status = dbwrap_parse_record(db, key, dbwrap_fetch_parser, &state);
300 1418367 : if (!NT_STATUS_IS_OK(status)) {
301 798662 : return status;
302 : }
303 619705 : if ((state.data.dsize != 0) && (state.data.dptr == NULL)) {
304 0 : return NT_STATUS_NO_MEMORY;
305 : }
306 619705 : *value = state.data;
307 619705 : return NT_STATUS_OK;
308 : }
309 :
310 790706 : bool dbwrap_exists(struct db_context *db, TDB_DATA key)
311 : {
312 : int result;
313 790706 : if (db->exists != NULL) {
314 790706 : result = db->exists(db, key);
315 : } else {
316 0 : result = dbwrap_fallback_exists(db,key);
317 : }
318 790706 : return (result == 1);
319 : }
320 :
321 : struct dbwrap_store_state {
322 : TDB_DATA data;
323 : int flags;
324 : NTSTATUS status;
325 : };
326 :
327 1409864 : static void dbwrap_store_fn(
328 : struct db_record *rec,
329 : TDB_DATA value,
330 : void *private_data)
331 : {
332 1409864 : struct dbwrap_store_state *state = private_data;
333 1409864 : state->status = dbwrap_record_store(rec, state->data, state->flags);
334 1409864 : }
335 :
336 1409864 : NTSTATUS dbwrap_store(struct db_context *db, TDB_DATA key,
337 : TDB_DATA data, int flags)
338 : {
339 1409864 : struct dbwrap_store_state state = { .data = data, .flags = flags };
340 : NTSTATUS status;
341 :
342 1409864 : status = dbwrap_do_locked(db, key, dbwrap_store_fn, &state);
343 1409864 : if (!NT_STATUS_IS_OK(status)) {
344 0 : return status;
345 : }
346 :
347 1409864 : return state.status;
348 : }
349 :
350 : struct dbwrap_delete_state {
351 : NTSTATUS status;
352 : };
353 :
354 65507 : static void dbwrap_delete_fn(
355 : struct db_record *rec,
356 : TDB_DATA value,
357 : void *private_data)
358 : {
359 65507 : struct dbwrap_delete_state *state = private_data;
360 65507 : state->status = dbwrap_record_delete(rec);
361 65507 : }
362 :
363 65507 : NTSTATUS dbwrap_delete(struct db_context *db, TDB_DATA key)
364 : {
365 65507 : struct dbwrap_delete_state state = { .status = NT_STATUS_NOT_FOUND };
366 : NTSTATUS status;
367 :
368 65507 : status = dbwrap_do_locked(db, key, dbwrap_delete_fn, &state);
369 65507 : if (!NT_STATUS_IS_OK(status)) {
370 0 : return status;
371 : }
372 :
373 65507 : return state.status;
374 : }
375 :
376 16048 : NTSTATUS dbwrap_traverse(struct db_context *db,
377 : int (*f)(struct db_record*, void*),
378 : void *private_data,
379 : int *count)
380 : {
381 16048 : int ret = db->traverse(db, f, private_data);
382 :
383 16048 : if (ret < 0) {
384 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
385 : }
386 :
387 16048 : if (count != NULL) {
388 15852 : *count = ret;
389 : }
390 :
391 16048 : return NT_STATUS_OK;
392 : }
393 :
394 3310 : NTSTATUS dbwrap_traverse_read(struct db_context *db,
395 : int (*f)(struct db_record*, void*),
396 : void *private_data,
397 : int *count)
398 : {
399 3310 : int ret = db->traverse_read(db, f, private_data);
400 :
401 3310 : if (ret < 0) {
402 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
403 : }
404 :
405 3310 : if (count != NULL) {
406 277 : *count = ret;
407 : }
408 :
409 3310 : return NT_STATUS_OK;
410 : }
411 :
412 0 : static void dbwrap_null_parser(TDB_DATA key, TDB_DATA val, void* data)
413 : {
414 0 : return;
415 : }
416 :
417 4293040 : NTSTATUS dbwrap_parse_record(struct db_context *db, TDB_DATA key,
418 : void (*parser)(TDB_DATA key, TDB_DATA data,
419 : void *private_data),
420 : void *private_data)
421 : {
422 4293040 : if (parser == NULL) {
423 0 : parser = dbwrap_null_parser;
424 : }
425 4293040 : return db->parse_record(db, key, parser, private_data);
426 : }
427 :
428 : struct dbwrap_parse_record_state {
429 : struct db_context *db;
430 : TDB_DATA key;
431 : uint8_t _keybuf[64];
432 : };
433 :
434 : static void dbwrap_parse_record_done(struct tevent_req *subreq);
435 :
436 0 : struct tevent_req *dbwrap_parse_record_send(
437 : TALLOC_CTX *mem_ctx,
438 : struct tevent_context *ev,
439 : struct db_context *db,
440 : TDB_DATA key,
441 : void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data),
442 : void *private_data,
443 : enum dbwrap_req_state *req_state)
444 : {
445 0 : struct tevent_req *req = NULL;
446 0 : struct tevent_req *subreq = NULL;
447 0 : struct dbwrap_parse_record_state *state = NULL;
448 : NTSTATUS status;
449 :
450 0 : req = tevent_req_create(mem_ctx, &state, struct dbwrap_parse_record_state);
451 0 : if (req == NULL) {
452 0 : *req_state = DBWRAP_REQ_ERROR;
453 0 : return NULL;
454 : }
455 :
456 0 : *state = (struct dbwrap_parse_record_state) {
457 : .db = db,
458 : };
459 :
460 0 : if (parser == NULL) {
461 0 : parser = dbwrap_null_parser;
462 : }
463 :
464 0 : *req_state = DBWRAP_REQ_INIT;
465 :
466 0 : if (db->parse_record_send == NULL) {
467 : /*
468 : * Backend doesn't implement async version, call sync one
469 : */
470 0 : status = db->parse_record(db, key, parser, private_data);
471 0 : if (tevent_req_nterror(req, status)) {
472 0 : *req_state = DBWRAP_REQ_DONE;
473 0 : return tevent_req_post(req, ev);
474 : }
475 :
476 0 : *req_state = DBWRAP_REQ_DONE;
477 0 : tevent_req_done(req);
478 0 : return tevent_req_post(req, ev);
479 : }
480 :
481 : /*
482 : * Copy the key into our state ensuring the key data buffer is always
483 : * available to all the dbwrap backends over the entire lifetime of the
484 : * async request. Otherwise the caller might have free'd the key buffer.
485 : */
486 0 : if (key.dsize > sizeof(state->_keybuf)) {
487 0 : state->key.dptr = talloc_memdup(state, key.dptr, key.dsize);
488 0 : if (tevent_req_nomem(state->key.dptr, req)) {
489 0 : return tevent_req_post(req, ev);
490 : }
491 : } else {
492 0 : memcpy(state->_keybuf, key.dptr, key.dsize);
493 0 : state->key.dptr = state->_keybuf;
494 : }
495 0 : state->key.dsize = key.dsize;
496 :
497 0 : subreq = db->parse_record_send(state,
498 : ev,
499 : db,
500 0 : state->key,
501 : parser,
502 : private_data,
503 : req_state);
504 0 : if (tevent_req_nomem(subreq, req)) {
505 0 : *req_state = DBWRAP_REQ_ERROR;
506 0 : return tevent_req_post(req, ev);
507 : }
508 :
509 0 : tevent_req_set_callback(subreq,
510 : dbwrap_parse_record_done,
511 : req);
512 0 : return req;
513 : }
514 :
515 0 : static void dbwrap_parse_record_done(struct tevent_req *subreq)
516 : {
517 0 : struct tevent_req *req = tevent_req_callback_data(
518 : subreq, struct tevent_req);
519 0 : struct dbwrap_parse_record_state *state = tevent_req_data(
520 : req, struct dbwrap_parse_record_state);
521 : NTSTATUS status;
522 :
523 0 : status = state->db->parse_record_recv(subreq);
524 0 : TALLOC_FREE(subreq);
525 0 : if (!NT_STATUS_IS_OK(status)) {
526 0 : tevent_req_nterror(req, status);
527 0 : return;
528 : }
529 :
530 0 : tevent_req_done(req);
531 : }
532 :
533 0 : NTSTATUS dbwrap_parse_record_recv(struct tevent_req *req)
534 : {
535 0 : return tevent_req_simple_recv_ntstatus(req);
536 : }
537 :
538 1669950 : NTSTATUS dbwrap_do_locked(struct db_context *db, TDB_DATA key,
539 : void (*fn)(struct db_record *rec,
540 : TDB_DATA value,
541 : void *private_data),
542 : void *private_data)
543 : {
544 : struct db_record *rec;
545 :
546 1669950 : if (db->do_locked != NULL) {
547 : NTSTATUS status;
548 :
549 254053 : if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
550 10781 : dbwrap_lock_order_lock(db->name, db->lock_order);
551 : }
552 :
553 254053 : status = db->do_locked(db, key, fn, private_data);
554 :
555 254053 : if (db->lock_order != DBWRAP_LOCK_ORDER_NONE) {
556 10781 : dbwrap_lock_order_unlock(db->name, db->lock_order);
557 : }
558 :
559 254053 : return status;
560 : }
561 :
562 1415897 : rec = dbwrap_fetch_locked(db, db, key);
563 1415897 : if (rec == NULL) {
564 0 : return NT_STATUS_NO_MEMORY;
565 : }
566 :
567 : /*
568 : * Invalidate rec->value, nobody shall assume it's set from
569 : * within dbwrap_do_locked().
570 : */
571 1415897 : rec->value_valid = false;
572 :
573 1415897 : fn(rec, rec->value, private_data);
574 :
575 1415897 : TALLOC_FREE(rec);
576 :
577 1415897 : return NT_STATUS_OK;
578 : }
579 :
580 0 : int dbwrap_wipe(struct db_context *db)
581 : {
582 0 : if (db->wipe == NULL) {
583 0 : return dbwrap_fallback_wipe(db);
584 : }
585 0 : return db->wipe(db);
586 : }
587 :
588 0 : int dbwrap_check(struct db_context *db)
589 : {
590 0 : if (db->check == NULL) {
591 0 : return dbwrap_fallback_check(db);
592 : }
593 0 : return db->check(db);
594 : }
595 :
596 241690 : int dbwrap_get_seqnum(struct db_context *db)
597 : {
598 241690 : return db->get_seqnum(db);
599 : }
600 :
601 17191 : int dbwrap_transaction_start(struct db_context *db)
602 : {
603 17191 : if (!db->persistent) {
604 : /*
605 : * dbwrap_ctdb has two different data models for persistent
606 : * and non-persistent databases. Transactions are supported
607 : * only for the persistent databases. This check is here to
608 : * prevent breakages of the cluster case, autobuild at this
609 : * point only tests non-clustered Samba. Before removing this
610 : * check, please make sure that this facility has also been
611 : * added to dbwrap_ctdb.
612 : *
613 : * Thanks, vl
614 : */
615 0 : DEBUG(1, ("transactions not supported on non-persistent "
616 : "database %s\n", db->name));
617 0 : return -1;
618 : }
619 17191 : return db->transaction_start(db);
620 : }
621 :
622 0 : NTSTATUS dbwrap_transaction_start_nonblock(struct db_context *db)
623 : {
624 0 : if (db->transaction_start_nonblock) {
625 0 : return db->transaction_start_nonblock(db);
626 : } else {
627 0 : return dbwrap_transaction_start(db) == 0 ? NT_STATUS_OK
628 0 : : NT_STATUS_UNSUCCESSFUL;
629 : }
630 : }
631 :
632 17172 : int dbwrap_transaction_commit(struct db_context *db)
633 : {
634 17172 : return db->transaction_commit(db);
635 : }
636 :
637 19 : int dbwrap_transaction_cancel(struct db_context *db)
638 : {
639 19 : return db->transaction_cancel(db);
640 : }
641 :
642 0 : size_t dbwrap_db_id(struct db_context *db, uint8_t *id, size_t idlen)
643 : {
644 0 : return db->id(db, id, idlen);
645 : }
646 :
647 0 : bool dbwrap_is_persistent(struct db_context *db)
648 : {
649 0 : return db->persistent;
650 : }
651 :
652 52015 : const char *dbwrap_name(struct db_context *db)
653 : {
654 52015 : return db->name;
655 : }
656 :
657 0 : static ssize_t tdb_data_buf(const TDB_DATA *dbufs, int num_dbufs,
658 : uint8_t *buf, size_t buflen)
659 : {
660 0 : size_t needed = 0;
661 0 : uint8_t *p = buf;
662 : int i;
663 :
664 0 : for (i=0; i<num_dbufs; i++) {
665 0 : size_t thislen = dbufs[i].dsize;
666 :
667 0 : needed += thislen;
668 0 : if (needed < thislen) {
669 : /* wrap */
670 0 : return -1;
671 : }
672 :
673 0 : if (p != NULL && (thislen != 0) && (needed <= buflen)) {
674 0 : memcpy(p, dbufs[i].dptr, thislen);
675 0 : p += thislen;
676 : }
677 : }
678 :
679 0 : return needed;
680 : }
681 :
682 :
683 0 : TDB_DATA dbwrap_merge_dbufs(TALLOC_CTX *mem_ctx,
684 : const TDB_DATA *dbufs, int num_dbufs)
685 : {
686 0 : ssize_t len = tdb_data_buf(dbufs, num_dbufs, NULL, 0);
687 : uint8_t *buf;
688 :
689 0 : if (len == -1) {
690 0 : return (TDB_DATA) {0};
691 : }
692 :
693 0 : buf = talloc_array(mem_ctx, uint8_t, len);
694 0 : if (buf == NULL) {
695 0 : return (TDB_DATA) {0};
696 : }
697 :
698 0 : tdb_data_buf(dbufs, num_dbufs, buf, len);
699 :
700 0 : return (TDB_DATA) { .dptr = buf, .dsize = len };
701 : }
|