s3: smbd: Cleanup. smb2_file_rename_information() can never have a @GMT path in the...
[Samba.git] / lib / dbwrap / dbwrap_util.c
blobdf6dea40097df145199a07c6596633bf91c95276
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;
161 static NTSTATUS dbwrap_change_uint32_atomic_action(struct db_context *db,
162 void *private_data)
164 struct db_record *rec;
165 uint32_t val = (uint32_t)-1;
166 uint32_t v_store;
167 NTSTATUS ret;
168 struct dbwrap_change_uint32_atomic_context *state;
169 TDB_DATA value;
171 state = (struct dbwrap_change_uint32_atomic_context *)private_data;
173 rec = dbwrap_fetch_locked(db, talloc_tos(),
174 string_term_tdb_data(state->keystr));
175 if (!rec) {
176 return NT_STATUS_UNSUCCESSFUL;
179 value = dbwrap_record_get_value(rec);
181 if (value.dptr == NULL) {
182 val = *(state->oldval);
183 } else if (value.dsize == sizeof(val)) {
184 val = IVAL(value.dptr, 0);
185 *(state->oldval) = val;
186 } else {
187 ret = NT_STATUS_UNSUCCESSFUL;
188 goto done;
191 val += state->change_val;
193 SIVAL(&v_store, 0, val);
195 ret = dbwrap_record_store(rec,
196 make_tdb_data((const uint8_t *)&v_store,
197 sizeof(v_store)),
198 TDB_REPLACE);
200 done:
201 TALLOC_FREE(rec);
202 return ret;
205 NTSTATUS dbwrap_change_uint32_atomic_bystring(struct db_context *db,
206 const char *keystr,
207 uint32_t *oldval,
208 uint32_t change_val)
210 NTSTATUS ret;
211 struct dbwrap_change_uint32_atomic_context state;
213 state.keystr = keystr;
214 state.oldval = oldval;
215 state.change_val = change_val;
217 ret = dbwrap_change_uint32_atomic_action(db, &state);
219 return ret;
222 NTSTATUS dbwrap_trans_change_uint32_atomic_bystring(struct db_context *db,
223 const char *keystr,
224 uint32_t *oldval,
225 uint32_t change_val)
227 NTSTATUS ret;
228 struct dbwrap_change_uint32_atomic_context state;
230 state.keystr = keystr;
231 state.oldval = oldval;
232 state.change_val = change_val;
234 ret = dbwrap_trans_do(db, dbwrap_change_uint32_atomic_action, &state);
236 return ret;
240 * Atomic integer change (addition):
242 * if value does not exist yet in the db, use *oldval as initial old value.
243 * return old value in *oldval.
244 * store *oldval + change_val to db.
247 struct dbwrap_change_int32_atomic_context {
248 TDB_DATA key;
249 int32_t *oldval;
250 int32_t change_val;
253 static NTSTATUS dbwrap_change_int32_atomic_action(struct db_context *db,
254 void *private_data)
256 struct db_record *rec;
257 int32_t val = -1;
258 int32_t v_store;
259 NTSTATUS ret;
260 struct dbwrap_change_int32_atomic_context *state;
261 TDB_DATA value;
263 state = (struct dbwrap_change_int32_atomic_context *)private_data;
265 rec = dbwrap_fetch_locked(db, talloc_tos(), state->key);
266 if (!rec) {
267 return NT_STATUS_UNSUCCESSFUL;
270 value = dbwrap_record_get_value(rec);
272 if (value.dptr == NULL) {
273 val = *(state->oldval);
274 } else if (value.dsize == sizeof(val)) {
275 val = IVAL(value.dptr, 0);
276 *(state->oldval) = val;
277 } else {
278 ret = NT_STATUS_UNSUCCESSFUL;
279 goto done;
282 val += state->change_val;
284 SIVAL(&v_store, 0, val);
286 ret = dbwrap_record_store(rec,
287 make_tdb_data((const uint8_t *)&v_store,
288 sizeof(v_store)),
289 TDB_REPLACE);
291 done:
292 TALLOC_FREE(rec);
293 return ret;
296 NTSTATUS dbwrap_change_int32_atomic(struct db_context *db,
297 TDB_DATA key,
298 int32_t *oldval,
299 int32_t change_val)
301 NTSTATUS ret;
302 struct dbwrap_change_int32_atomic_context state;
304 state.key = key;
305 state.oldval = oldval;
306 state.change_val = change_val;
308 ret = dbwrap_change_int32_atomic_action(db, &state);
310 return ret;
313 NTSTATUS dbwrap_change_int32_atomic_bystring(struct db_context *db,
314 const char *keystr,
315 int32_t *oldval,
316 int32_t change_val)
318 return dbwrap_change_int32_atomic(db, string_term_tdb_data(keystr),
319 oldval, change_val);
322 NTSTATUS dbwrap_trans_change_int32_atomic_bystring(struct db_context *db,
323 const char *keystr,
324 int32_t *oldval,
325 int32_t change_val)
327 NTSTATUS ret;
328 struct dbwrap_change_int32_atomic_context state;
330 state.key = string_term_tdb_data(keystr);
331 state.oldval = oldval;
332 state.change_val = change_val;
334 ret = dbwrap_trans_do(db, dbwrap_change_int32_atomic_action, &state);
336 return ret;
339 struct dbwrap_store_context {
340 TDB_DATA *key;
341 TDB_DATA *dbuf;
342 int flag;
345 static NTSTATUS dbwrap_store_action(struct db_context *db, void *private_data)
347 NTSTATUS status;
348 struct dbwrap_store_context *store_ctx;
350 store_ctx = (struct dbwrap_store_context *)private_data;
352 status = dbwrap_store(db, *(store_ctx->key), *(store_ctx->dbuf),
353 store_ctx->flag);
354 if (!NT_STATUS_IS_OK(status)) {
355 DEBUG(5, ("store returned %s\n", nt_errstr(status)));
358 return status;
361 NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
362 int flag)
364 NTSTATUS status;
365 struct dbwrap_store_context store_ctx;
367 store_ctx.key = &key;
368 store_ctx.dbuf = &dbuf;
369 store_ctx.flag = flag;
371 status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx);
373 return status;
376 static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
378 NTSTATUS status;
379 TDB_DATA *key = (TDB_DATA *)private_data;
381 status = dbwrap_delete(db, *key);
382 if (!NT_STATUS_IS_OK(status)) {
383 DBG_INFO("dbwrap_record_delete returned %s\n",
384 nt_errstr(status));
386 return status;
389 NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
391 NTSTATUS status;
393 status = dbwrap_trans_do(db, dbwrap_delete_action, &key);
395 return status;
398 NTSTATUS dbwrap_trans_store_int32_bystring(struct db_context *db,
399 const char *keystr,
400 int32_t v)
402 int32_t v_store;
404 SIVAL(&v_store, 0, v);
406 return dbwrap_trans_store(db, string_term_tdb_data(keystr),
407 make_tdb_data((const uint8_t *)&v_store,
408 sizeof(v_store)),
409 TDB_REPLACE);
412 NTSTATUS dbwrap_trans_store_uint32_bystring(struct db_context *db,
413 const char *keystr,
414 uint32_t v)
416 uint32_t v_store;
418 SIVAL(&v_store, 0, v);
420 return dbwrap_trans_store(db, string_term_tdb_data(keystr),
421 make_tdb_data((const uint8_t *)&v_store,
422 sizeof(v_store)),
423 TDB_REPLACE);
426 NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
427 TDB_DATA data, int flags)
429 return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
432 NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
434 return dbwrap_trans_delete(db, string_term_tdb_data(key));
438 * Wrap db action(s) into a transaction.
440 NTSTATUS dbwrap_trans_do(struct db_context *db,
441 NTSTATUS (*action)(struct db_context *, void *),
442 void *private_data)
444 int res;
445 NTSTATUS status;
447 res = dbwrap_transaction_start(db);
448 if (res != 0) {
449 DEBUG(5, ("transaction_start failed\n"));
450 return NT_STATUS_INTERNAL_DB_CORRUPTION;
453 status = action(db, private_data);
454 if (!NT_STATUS_IS_OK(status)) {
455 if (dbwrap_transaction_cancel(db) != 0) {
456 smb_panic("Cancelling transaction failed");
458 return status;
461 res = dbwrap_transaction_commit(db);
462 if (res == 0) {
463 return NT_STATUS_OK;
466 DEBUG(2, ("transaction_commit failed\n"));
467 return NT_STATUS_INTERNAL_DB_CORRUPTION;
470 struct dbwrap_trans_traverse_action_ctx {
471 int (*f)(struct db_record* rec, void* private_data);
472 void* private_data;
476 static NTSTATUS dbwrap_trans_traverse_action(struct db_context* db, void* private_data)
478 struct dbwrap_trans_traverse_action_ctx* ctx =
479 (struct dbwrap_trans_traverse_action_ctx*)private_data;
481 NTSTATUS status = dbwrap_traverse(db, ctx->f, ctx->private_data, NULL);
483 return status;
486 NTSTATUS dbwrap_trans_traverse(struct db_context *db,
487 int (*f)(struct db_record*, void*),
488 void *private_data)
490 struct dbwrap_trans_traverse_action_ctx ctx = {
491 .f = f,
492 .private_data = private_data,
494 return dbwrap_trans_do(db, dbwrap_trans_traverse_action, &ctx);
497 NTSTATUS dbwrap_purge(struct db_context *db, TDB_DATA key)
499 NTSTATUS status;
501 status = dbwrap_delete(db, key);
502 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
503 status = NT_STATUS_OK;
506 return status;
509 NTSTATUS dbwrap_purge_bystring(struct db_context *db, const char *key)
511 return dbwrap_purge(db, string_term_tdb_data(key));
514 NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key)
516 return dbwrap_delete(db, string_term_tdb_data(key));
519 NTSTATUS dbwrap_store_bystring(struct db_context *db, const char *key,
520 TDB_DATA data, int flags)
522 return dbwrap_store(db, string_term_tdb_data(key), data, flags);
525 NTSTATUS dbwrap_fetch_bystring(struct db_context *db, TALLOC_CTX *mem_ctx,
526 const char *key, TDB_DATA *value)
528 return dbwrap_fetch(db, mem_ctx, string_term_tdb_data(key), value);
533 NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
535 char *key_upper;
536 NTSTATUS status;
538 key_upper = talloc_strdup_upper(talloc_tos(), key);
539 if (key_upper == NULL) {
540 return NT_STATUS_NO_MEMORY;
543 status = dbwrap_delete_bystring(db, key_upper);
545 talloc_free(key_upper);
546 return status;
549 NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
550 TDB_DATA data, int flags)
552 char *key_upper;
553 NTSTATUS status;
555 key_upper = talloc_strdup_upper(talloc_tos(), key);
556 if (key_upper == NULL) {
557 return NT_STATUS_NO_MEMORY;
560 status = dbwrap_store_bystring(db, key_upper, data, flags);
562 talloc_free(key_upper);
563 return status;
566 NTSTATUS dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
567 const char *key, TDB_DATA *value)
569 char *key_upper;
570 NTSTATUS status;
572 key_upper = talloc_strdup_upper(talloc_tos(), key);
573 if (key_upper == NULL) {
574 return NT_STATUS_NO_MEMORY;
577 status = dbwrap_fetch_bystring(db, mem_ctx, key_upper, value);
579 talloc_free(key_upper);
580 return status;
583 struct dbwrap_marshall_state {
584 uint8_t *buf;
585 size_t bufsize;
586 size_t dbsize;
589 static int dbwrap_marshall_fn(struct db_record *rec, void *private_data)
591 struct dbwrap_marshall_state *state = private_data;
592 TDB_DATA key, value;
593 size_t new_dbsize;
595 key = dbwrap_record_get_key(rec);
596 value = dbwrap_record_get_value(rec);
598 new_dbsize = state->dbsize;
599 new_dbsize += 8 + key.dsize;
600 new_dbsize += 8 + value.dsize;
602 if (new_dbsize <= state->bufsize) {
603 uint8_t *p = state->buf + state->dbsize;
605 SBVAL(p, 0, key.dsize);
606 p += 8;
607 memcpy(p, key.dptr, key.dsize);
608 p += key.dsize;
610 SBVAL(p, 0, value.dsize);
611 p += 8;
612 memcpy(p, value.dptr, value.dsize);
614 state->dbsize = new_dbsize;
615 return 0;
618 size_t dbwrap_marshall(struct db_context *db, uint8_t *buf, size_t bufsize)
620 struct dbwrap_marshall_state state;
622 state.bufsize = bufsize;
623 state.buf = buf;
624 state.dbsize = 0;
626 dbwrap_traverse_read(db, dbwrap_marshall_fn, &state, NULL);
628 return state.dbsize;
631 static ssize_t dbwrap_unmarshall_get_data(const uint8_t *buf, size_t buflen,
632 size_t ofs, TDB_DATA *pdata)
634 uint64_t space, len;
635 const uint8_t *p;
637 if (ofs == buflen) {
638 return 0;
640 if (ofs > buflen) {
641 return -1;
644 space = buflen - ofs;
645 if (space < 8) {
646 return -1;
649 p = buf + ofs;
650 len = BVAL(p, 0);
652 p += 8;
653 space -= 8;
655 if (len > space) {
656 return -1;
659 *pdata = (TDB_DATA) { .dptr = discard_const_p(uint8_t, p),
660 .dsize = len };
661 return len + 8;
664 NTSTATUS dbwrap_parse_marshall_buf(const uint8_t *buf, size_t buflen,
665 bool (*fn)(TDB_DATA key, TDB_DATA value,
666 void *private_data),
667 void *private_data)
669 size_t ofs = 0;
671 while (true) {
672 ssize_t len;
673 TDB_DATA key, value;
674 bool ok;
676 len = dbwrap_unmarshall_get_data(buf, buflen, ofs, &key);
677 if (len == 0) {
678 break;
680 if (len == -1) {
681 return NT_STATUS_INVALID_PARAMETER;
683 ofs += len;
685 len = dbwrap_unmarshall_get_data(buf, buflen, ofs, &value);
686 if (len == 0) {
687 break;
689 if (len == -1) {
690 return NT_STATUS_INVALID_PARAMETER;
692 ofs += len;
694 ok = fn(key, value, private_data);
695 if (!ok) {
696 break;
700 return NT_STATUS_OK;
703 struct dbwrap_unmarshall_state {
704 struct db_context *db;
705 NTSTATUS ret;
708 static bool dbwrap_unmarshall_fn(TDB_DATA key, TDB_DATA value,
709 void *private_data)
711 struct dbwrap_unmarshall_state *state = private_data;
712 NTSTATUS status;
714 status = dbwrap_store(state->db, key, value, 0);
715 if (!NT_STATUS_IS_OK(status)) {
716 DBG_DEBUG("dbwrap_record_store failed: %s\n",
717 nt_errstr(status));
718 state->ret = status;
719 return false;
722 return true;
725 NTSTATUS dbwrap_unmarshall(struct db_context *db, const uint8_t *buf,
726 size_t buflen)
728 struct dbwrap_unmarshall_state state = { .db = db };
729 NTSTATUS status;
731 status = dbwrap_parse_marshall_buf(buf, buflen,
732 dbwrap_unmarshall_fn, &state);
733 if (!NT_STATUS_IS_OK(status)) {
734 return status;
736 return state.ret;