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