vfs_ceph: Disable the module on unsupported Ceph versions
[Samba.git] / lib / dbwrap / dbwrap_util.c
blob312fb4187542a1eab22db7340ddcfa22ea24afd2
1 /*
2 Unix SMB/CIFS implementation.
3 Utility functions for the dbwrap API
4 Copyright (C) Volker Lendecke 2007
5 Copyright (C) Michael Adam 2009
6 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2006
8 Major code contributions from Aleksey Fedoseev (fedoseev@ru.ibm.com)
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "includes.h"
26 #include "dbwrap.h"
27 #include "lib/util/util_tdb.h"
29 struct dbwrap_fetch_int32_state {
30 NTSTATUS status;
31 int32_t result;
34 static void dbwrap_fetch_int32_parser(TDB_DATA key, TDB_DATA data,
35 void *private_data)
37 struct dbwrap_fetch_int32_state *state =
38 (struct dbwrap_fetch_int32_state *)private_data;
40 if (data.dsize != sizeof(state->result)) {
41 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
42 return;
44 state->result = IVAL(data.dptr, 0);
45 state->status = NT_STATUS_OK;
48 NTSTATUS dbwrap_fetch_int32(struct db_context *db, TDB_DATA key,
49 int32_t *result)
51 struct dbwrap_fetch_int32_state state;
52 NTSTATUS status;
54 if (result == NULL) {
55 return NT_STATUS_INVALID_PARAMETER;
58 state.status = NT_STATUS_INTERNAL_ERROR;
60 status = dbwrap_parse_record(db, key, dbwrap_fetch_int32_parser, &state);
61 if (!NT_STATUS_IS_OK(status)) {
62 return status;
65 if (NT_STATUS_IS_OK(state.status)) {
66 *result = state.result;
68 return state.status;
71 NTSTATUS dbwrap_fetch_int32_bystring(struct db_context *db, const char *keystr,
72 int32_t *result)
74 return dbwrap_fetch_int32(db, string_term_tdb_data(keystr), result);
77 NTSTATUS dbwrap_store_int32_bystring(struct db_context *db, const char *keystr,
78 int32_t v)
80 uint8_t v_store[sizeof(int32_t)];
81 TDB_DATA data = { .dptr = v_store, .dsize = sizeof(v_store) };
82 NTSTATUS status;
84 SIVAL(v_store, 0, v);
86 status = dbwrap_store(db, string_term_tdb_data(keystr), data,
87 TDB_REPLACE);
88 return status;
91 struct dbwrap_fetch_uint32_state {
92 NTSTATUS status;
93 uint32_t result;
96 static void dbwrap_fetch_uint32_parser(TDB_DATA key, TDB_DATA data,
97 void *private_data)
99 struct dbwrap_fetch_uint32_state *state =
100 (struct dbwrap_fetch_uint32_state *)private_data;
102 if (data.dsize != sizeof(state->result)) {
103 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
104 return;
106 state->result = IVAL(data.dptr, 0);
107 state->status = NT_STATUS_OK;
110 NTSTATUS dbwrap_fetch_uint32_bystring(struct db_context *db,
111 const char *keystr, uint32_t *val)
113 struct dbwrap_fetch_uint32_state state;
114 NTSTATUS status;
116 if (val == NULL) {
117 return NT_STATUS_INVALID_PARAMETER;
120 state.status = NT_STATUS_INTERNAL_ERROR;
122 status = dbwrap_parse_record(db, string_term_tdb_data(keystr),
123 dbwrap_fetch_uint32_parser, &state);
124 if (!NT_STATUS_IS_OK(status)) {
125 return status;
127 if (NT_STATUS_IS_OK(state.status)) {
128 *val = state.result;
130 return state.status;
133 NTSTATUS dbwrap_store_uint32_bystring(struct db_context *db,
134 const char *keystr, uint32_t v)
136 uint8_t v_store[sizeof(uint32_t)];
137 TDB_DATA data = { .dptr = v_store, .dsize = sizeof(v_store) };
138 NTSTATUS status;
140 SIVAL(v_store, 0, v);
142 status = dbwrap_store(db, string_term_tdb_data(keystr), data,
143 TDB_REPLACE);
144 return status;
148 * Atomic unsigned integer change (addition):
150 * if value does not exist yet in the db, use *oldval as initial old value.
151 * return old value in *oldval.
152 * store *oldval + change_val to db.
155 struct dbwrap_change_uint32_atomic_context {
156 const char *keystr;
157 uint32_t *oldval;
158 uint32_t change_val;
159 NTSTATUS status;
162 static void dbwrap_change_uint32_atomic_action_fn(struct db_record *rec,
163 TDB_DATA value,
164 void *private_data)
166 struct dbwrap_change_uint32_atomic_context *state = private_data;
167 uint8_t v_store[4];
168 TDB_DATA data = {
169 .dptr = v_store,
170 .dsize = sizeof(v_store),
172 uint32_t val = UINT32_MAX;
174 if (value.dptr == NULL) {
175 val = *(state->oldval);
176 } else if (value.dsize == sizeof(val)) {
177 val = PULL_LE_U32(value.dptr, 0);
178 *(state->oldval) = val;
179 } else {
180 state->status = NT_STATUS_UNSUCCESSFUL;
181 return;
184 val += state->change_val;
185 PUSH_LE_U32(v_store, 0, val);
187 state->status = dbwrap_record_store(rec, data, TDB_REPLACE);
190 static NTSTATUS dbwrap_change_uint32_atomic_action(struct db_context *db,
191 void *private_data)
193 struct dbwrap_change_uint32_atomic_context *state = private_data;
194 NTSTATUS status;
196 status = dbwrap_do_locked(db,
197 string_term_tdb_data(state->keystr),
198 dbwrap_change_uint32_atomic_action_fn,
199 state);
200 if (!NT_STATUS_IS_OK(status)) {
201 DBG_DEBUG("dbwrap_do_locked() failed: %s\n",
202 nt_errstr(status));
203 return status;
205 if (!NT_STATUS_IS_OK(state->status)) {
206 DBG_DEBUG("dbwrap_change_uint32_atomic_action_fn() "
207 "failed: %s\n",
208 nt_errstr(status));
209 return status;
211 return NT_STATUS_OK;
214 NTSTATUS dbwrap_change_uint32_atomic_bystring(struct db_context *db,
215 const char *keystr,
216 uint32_t *oldval,
217 uint32_t change_val)
219 NTSTATUS ret;
220 struct dbwrap_change_uint32_atomic_context state;
222 state.keystr = keystr;
223 state.oldval = oldval;
224 state.change_val = change_val;
226 ret = dbwrap_change_uint32_atomic_action(db, &state);
228 return ret;
231 NTSTATUS dbwrap_trans_change_uint32_atomic_bystring(struct db_context *db,
232 const char *keystr,
233 uint32_t *oldval,
234 uint32_t change_val)
236 NTSTATUS ret;
237 struct dbwrap_change_uint32_atomic_context state;
239 state.keystr = keystr;
240 state.oldval = oldval;
241 state.change_val = change_val;
243 ret = dbwrap_trans_do(db, dbwrap_change_uint32_atomic_action, &state);
245 return ret;
249 * Atomic integer change (addition):
251 * if value does not exist yet in the db, use *oldval as initial old value.
252 * return old value in *oldval.
253 * store *oldval + change_val to db.
256 struct dbwrap_change_int32_atomic_context {
257 TDB_DATA key;
258 int32_t *oldval;
259 int32_t change_val;
260 NTSTATUS status;
263 static void dbwrap_change_int32_atomic_action_fn(struct db_record *rec,
264 TDB_DATA value,
265 void *private_data)
267 struct dbwrap_change_int32_atomic_context *state = private_data;
268 uint8_t v_store[4];
269 TDB_DATA data = {
270 .dptr = v_store,
271 .dsize = sizeof(v_store),
273 int32_t val = -1;
275 if (value.dptr == NULL) {
276 val = *(state->oldval);
277 } else if (value.dsize == sizeof(val)) {
278 val = PULL_LE_U32(value.dptr, 0);
279 *(state->oldval) = val;
280 } else {
281 state->status = NT_STATUS_UNSUCCESSFUL;
282 return;
285 val += state->change_val;
286 PUSH_LE_U32(v_store, 0, val);
288 state->status = dbwrap_record_store(rec, data, TDB_REPLACE);
291 static NTSTATUS dbwrap_change_int32_atomic_action(struct db_context *db,
292 void *private_data)
294 struct dbwrap_change_int32_atomic_context *state = private_data;
295 NTSTATUS status;
297 status = dbwrap_do_locked(db,
298 state->key,
299 dbwrap_change_int32_atomic_action_fn,
300 state);
301 if (!NT_STATUS_IS_OK(status)) {
302 DBG_DEBUG("dbwrap_do_locked() failed: %s\n",
303 nt_errstr(status));
304 return status;
306 if (!NT_STATUS_IS_OK(state->status)) {
307 DBG_DEBUG("dbwrap_change_int32_atomic_action_fn() "
308 "failed: %s\n",
309 nt_errstr(status));
310 return status;
312 return NT_STATUS_OK;
315 NTSTATUS dbwrap_change_int32_atomic(struct db_context *db,
316 TDB_DATA key,
317 int32_t *oldval,
318 int32_t change_val)
320 NTSTATUS ret;
321 struct dbwrap_change_int32_atomic_context state;
323 state.key = key;
324 state.oldval = oldval;
325 state.change_val = change_val;
327 ret = dbwrap_change_int32_atomic_action(db, &state);
329 return ret;
332 NTSTATUS dbwrap_change_int32_atomic_bystring(struct db_context *db,
333 const char *keystr,
334 int32_t *oldval,
335 int32_t change_val)
337 return dbwrap_change_int32_atomic(db, string_term_tdb_data(keystr),
338 oldval, change_val);
341 NTSTATUS dbwrap_trans_change_int32_atomic_bystring(struct db_context *db,
342 const char *keystr,
343 int32_t *oldval,
344 int32_t change_val)
346 NTSTATUS ret;
347 struct dbwrap_change_int32_atomic_context state;
349 state.key = string_term_tdb_data(keystr);
350 state.oldval = oldval;
351 state.change_val = change_val;
353 ret = dbwrap_trans_do(db, dbwrap_change_int32_atomic_action, &state);
355 return ret;
358 struct dbwrap_store_context {
359 TDB_DATA *key;
360 TDB_DATA *dbuf;
361 int flag;
364 static NTSTATUS dbwrap_store_action(struct db_context *db, void *private_data)
366 NTSTATUS status;
367 struct dbwrap_store_context *store_ctx;
369 store_ctx = (struct dbwrap_store_context *)private_data;
371 status = dbwrap_store(db, *(store_ctx->key), *(store_ctx->dbuf),
372 store_ctx->flag);
373 if (!NT_STATUS_IS_OK(status)) {
374 DEBUG(5, ("store returned %s\n", nt_errstr(status)));
377 return status;
380 NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
381 int flag)
383 NTSTATUS status;
384 struct dbwrap_store_context store_ctx;
386 store_ctx.key = &key;
387 store_ctx.dbuf = &dbuf;
388 store_ctx.flag = flag;
390 status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx);
392 return status;
395 static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
397 NTSTATUS status;
398 TDB_DATA *key = (TDB_DATA *)private_data;
400 status = dbwrap_delete(db, *key);
401 if (!NT_STATUS_IS_OK(status)) {
402 DBG_INFO("dbwrap_record_delete returned %s\n",
403 nt_errstr(status));
405 return status;
408 NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
410 NTSTATUS status;
412 status = dbwrap_trans_do(db, dbwrap_delete_action, &key);
414 return status;
417 NTSTATUS dbwrap_trans_store_int32_bystring(struct db_context *db,
418 const char *keystr,
419 int32_t v)
421 int32_t v_store;
423 SIVAL(&v_store, 0, v);
425 return dbwrap_trans_store(db, string_term_tdb_data(keystr),
426 make_tdb_data((const uint8_t *)&v_store,
427 sizeof(v_store)),
428 TDB_REPLACE);
431 NTSTATUS dbwrap_trans_store_uint32_bystring(struct db_context *db,
432 const char *keystr,
433 uint32_t v)
435 uint32_t v_store;
437 SIVAL(&v_store, 0, v);
439 return dbwrap_trans_store(db, string_term_tdb_data(keystr),
440 make_tdb_data((const uint8_t *)&v_store,
441 sizeof(v_store)),
442 TDB_REPLACE);
445 NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
446 TDB_DATA data, int flags)
448 return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
451 NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
453 return dbwrap_trans_delete(db, string_term_tdb_data(key));
457 * Wrap db action(s) into a transaction.
459 NTSTATUS dbwrap_trans_do(struct db_context *db,
460 NTSTATUS (*action)(struct db_context *, void *),
461 void *private_data)
463 int res;
464 NTSTATUS status;
466 res = dbwrap_transaction_start(db);
467 if (res != 0) {
468 DEBUG(5, ("transaction_start failed\n"));
469 return NT_STATUS_INTERNAL_DB_CORRUPTION;
472 status = action(db, private_data);
473 if (!NT_STATUS_IS_OK(status)) {
474 if (dbwrap_transaction_cancel(db) != 0) {
475 smb_panic("Cancelling transaction failed");
477 return status;
480 res = dbwrap_transaction_commit(db);
481 if (res == 0) {
482 return NT_STATUS_OK;
485 DEBUG(2, ("transaction_commit failed\n"));
486 return NT_STATUS_INTERNAL_DB_CORRUPTION;
489 struct dbwrap_trans_traverse_action_ctx {
490 int (*f)(struct db_record* rec, void* private_data);
491 void* private_data;
495 static NTSTATUS dbwrap_trans_traverse_action(struct db_context* db, void* private_data)
497 struct dbwrap_trans_traverse_action_ctx* ctx =
498 (struct dbwrap_trans_traverse_action_ctx*)private_data;
500 NTSTATUS status = dbwrap_traverse(db, ctx->f, ctx->private_data, NULL);
502 return status;
505 NTSTATUS dbwrap_trans_traverse(struct db_context *db,
506 int (*f)(struct db_record*, void*),
507 void *private_data)
509 struct dbwrap_trans_traverse_action_ctx ctx = {
510 .f = f,
511 .private_data = private_data,
513 return dbwrap_trans_do(db, dbwrap_trans_traverse_action, &ctx);
516 NTSTATUS dbwrap_purge(struct db_context *db, TDB_DATA key)
518 NTSTATUS status;
520 status = dbwrap_delete(db, key);
521 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
522 status = NT_STATUS_OK;
525 return status;
528 NTSTATUS dbwrap_purge_bystring(struct db_context *db, const char *key)
530 return dbwrap_purge(db, string_term_tdb_data(key));
533 NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key)
535 return dbwrap_delete(db, string_term_tdb_data(key));
538 NTSTATUS dbwrap_store_bystring(struct db_context *db, const char *key,
539 TDB_DATA data, int flags)
541 return dbwrap_store(db, string_term_tdb_data(key), data, flags);
544 NTSTATUS dbwrap_fetch_bystring(struct db_context *db, TALLOC_CTX *mem_ctx,
545 const char *key, TDB_DATA *value)
547 return dbwrap_fetch(db, mem_ctx, string_term_tdb_data(key), value);
552 NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
554 char *key_upper;
555 NTSTATUS status;
557 key_upper = talloc_strdup_upper(talloc_tos(), key);
558 if (key_upper == NULL) {
559 return NT_STATUS_NO_MEMORY;
562 status = dbwrap_delete_bystring(db, key_upper);
564 talloc_free(key_upper);
565 return status;
568 NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
569 TDB_DATA data, int flags)
571 char *key_upper;
572 NTSTATUS status;
574 key_upper = talloc_strdup_upper(talloc_tos(), key);
575 if (key_upper == NULL) {
576 return NT_STATUS_NO_MEMORY;
579 status = dbwrap_store_bystring(db, key_upper, data, flags);
581 talloc_free(key_upper);
582 return status;
585 NTSTATUS dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
586 const char *key, TDB_DATA *value)
588 char *key_upper;
589 NTSTATUS status;
591 key_upper = talloc_strdup_upper(talloc_tos(), key);
592 if (key_upper == NULL) {
593 return NT_STATUS_NO_MEMORY;
596 status = dbwrap_fetch_bystring(db, mem_ctx, key_upper, value);
598 talloc_free(key_upper);
599 return status;
602 struct dbwrap_marshall_state {
603 uint8_t *buf;
604 size_t bufsize;
605 size_t dbsize;
608 static int dbwrap_marshall_fn(struct db_record *rec, void *private_data)
610 struct dbwrap_marshall_state *state = private_data;
611 TDB_DATA key, value;
612 size_t new_dbsize;
614 key = dbwrap_record_get_key(rec);
615 value = dbwrap_record_get_value(rec);
617 new_dbsize = state->dbsize;
618 new_dbsize += 8 + key.dsize;
619 new_dbsize += 8 + value.dsize;
621 if (new_dbsize <= state->bufsize) {
622 uint8_t *p = state->buf + state->dbsize;
624 SBVAL(p, 0, key.dsize);
625 p += 8;
626 memcpy(p, key.dptr, key.dsize);
627 p += key.dsize;
629 SBVAL(p, 0, value.dsize);
630 p += 8;
631 memcpy(p, value.dptr, value.dsize);
633 state->dbsize = new_dbsize;
634 return 0;
637 size_t dbwrap_marshall(struct db_context *db, uint8_t *buf, size_t bufsize)
639 struct dbwrap_marshall_state state;
641 state.bufsize = bufsize;
642 state.buf = buf;
643 state.dbsize = 0;
645 dbwrap_traverse_read(db, dbwrap_marshall_fn, &state, NULL);
647 return state.dbsize;
650 static ssize_t dbwrap_unmarshall_get_data(const uint8_t *buf, size_t buflen,
651 size_t ofs, TDB_DATA *pdata)
653 uint64_t space, len;
654 const uint8_t *p;
656 if (ofs == buflen) {
657 return 0;
659 if (ofs > buflen) {
660 return -1;
663 space = buflen - ofs;
664 if (space < 8) {
665 return -1;
668 p = buf + ofs;
669 len = BVAL(p, 0);
671 p += 8;
672 space -= 8;
674 if (len > space) {
675 return -1;
678 *pdata = (TDB_DATA) { .dptr = discard_const_p(uint8_t, p),
679 .dsize = len };
680 return len + 8;
683 NTSTATUS dbwrap_parse_marshall_buf(const uint8_t *buf, size_t buflen,
684 bool (*fn)(TDB_DATA key, TDB_DATA value,
685 void *private_data),
686 void *private_data)
688 size_t ofs = 0;
690 while (true) {
691 ssize_t len;
692 TDB_DATA key, value;
693 bool ok;
695 len = dbwrap_unmarshall_get_data(buf, buflen, ofs, &key);
696 if (len == 0) {
697 break;
699 if (len == -1) {
700 return NT_STATUS_INVALID_PARAMETER;
702 ofs += len;
704 len = dbwrap_unmarshall_get_data(buf, buflen, ofs, &value);
705 if (len == 0) {
706 break;
708 if (len == -1) {
709 return NT_STATUS_INVALID_PARAMETER;
711 ofs += len;
713 ok = fn(key, value, private_data);
714 if (!ok) {
715 break;
719 return NT_STATUS_OK;
722 struct dbwrap_unmarshall_state {
723 struct db_context *db;
724 NTSTATUS ret;
727 static bool dbwrap_unmarshall_fn(TDB_DATA key, TDB_DATA value,
728 void *private_data)
730 struct dbwrap_unmarshall_state *state = private_data;
731 NTSTATUS status;
733 status = dbwrap_store(state->db, key, value, 0);
734 if (!NT_STATUS_IS_OK(status)) {
735 DBG_DEBUG("dbwrap_record_store failed: %s\n",
736 nt_errstr(status));
737 state->ret = status;
738 return false;
741 return true;
744 NTSTATUS dbwrap_unmarshall(struct db_context *db, const uint8_t *buf,
745 size_t buflen)
747 struct dbwrap_unmarshall_state state = { .db = db };
748 NTSTATUS status;
750 status = dbwrap_parse_marshall_buf(buf, buflen,
751 dbwrap_unmarshall_fn, &state);
752 if (!NT_STATUS_IS_OK(status)) {
753 return status;
755 return state.ret;