WHATSNEW: Add changes since 3.6.13.
[Samba.git] / source3 / lib / dbwrap_util.c
blob1e28f844b23f9a80d2c2b56b860eabe21425ff37
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
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
23 #include "dbwrap.h"
24 #include "util_tdb.h"
26 int32_t dbwrap_fetch_int32(struct db_context *db, const char *keystr)
28 TDB_DATA dbuf;
29 int32 ret;
31 if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
32 return -1;
35 if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(int32_t))) {
36 TALLOC_FREE(dbuf.dptr);
37 return -1;
40 ret = IVAL(dbuf.dptr, 0);
41 TALLOC_FREE(dbuf.dptr);
42 return ret;
45 int dbwrap_store_int32(struct db_context *db, const char *keystr, int32_t v)
47 struct db_record *rec;
48 int32 v_store;
49 NTSTATUS status;
51 rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
52 if (rec == NULL) {
53 return -1;
56 SIVAL(&v_store, 0, v);
58 status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
59 sizeof(v_store)),
60 TDB_REPLACE);
61 TALLOC_FREE(rec);
62 return NT_STATUS_IS_OK(status) ? 0 : -1;
65 bool dbwrap_fetch_uint32(struct db_context *db, const char *keystr,
66 uint32_t *val)
68 TDB_DATA dbuf;
70 if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
71 return false;
74 if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(uint32_t))) {
75 TALLOC_FREE(dbuf.dptr);
76 return false;
79 *val = IVAL(dbuf.dptr, 0);
80 TALLOC_FREE(dbuf.dptr);
81 return true;
84 int dbwrap_store_uint32(struct db_context *db, const char *keystr, uint32_t v)
86 struct db_record *rec;
87 uint32 v_store;
88 NTSTATUS status;
90 rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
91 if (rec == NULL) {
92 return -1;
95 SIVAL(&v_store, 0, v);
97 status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
98 sizeof(v_store)),
99 TDB_REPLACE);
100 TALLOC_FREE(rec);
101 return NT_STATUS_IS_OK(status) ? 0 : -1;
105 * Atomic unsigned integer change (addition):
107 * if value does not exist yet in the db, use *oldval as initial old value.
108 * return old value in *oldval.
109 * store *oldval + change_val to db.
112 struct dbwrap_change_uint32_atomic_context {
113 const char *keystr;
114 uint32_t *oldval;
115 uint32_t change_val;
118 static NTSTATUS dbwrap_change_uint32_atomic_action(struct db_context *db,
119 void *private_data)
121 struct db_record *rec;
122 uint32_t val = (uint32_t)-1;
123 uint32_t v_store;
124 NTSTATUS ret;
125 struct dbwrap_change_uint32_atomic_context *state;
127 state = (struct dbwrap_change_uint32_atomic_context *)private_data;
129 rec = db->fetch_locked(db, NULL, string_term_tdb_data(state->keystr));
130 if (!rec) {
131 return NT_STATUS_UNSUCCESSFUL;
134 if (rec->value.dptr == NULL) {
135 val = *(state->oldval);
136 } else if (rec->value.dsize == sizeof(val)) {
137 val = IVAL(rec->value.dptr, 0);
138 *(state->oldval) = val;
139 } else {
140 ret = NT_STATUS_UNSUCCESSFUL;
141 goto done;
144 val += state->change_val;
146 SIVAL(&v_store, 0, val);
148 ret = rec->store(rec,
149 make_tdb_data((const uint8 *)&v_store,
150 sizeof(v_store)),
151 TDB_REPLACE);
153 done:
154 TALLOC_FREE(rec);
155 return ret;
158 NTSTATUS dbwrap_change_uint32_atomic(struct db_context *db, const char *keystr,
159 uint32_t *oldval, uint32_t change_val)
161 NTSTATUS ret;
162 struct dbwrap_change_uint32_atomic_context state;
164 state.keystr = keystr;
165 state.oldval = oldval;
166 state.change_val = change_val;
168 ret = dbwrap_change_uint32_atomic_action(db, &state);
170 return ret;
173 NTSTATUS dbwrap_trans_change_uint32_atomic(struct db_context *db,
174 const char *keystr,
175 uint32_t *oldval,
176 uint32_t change_val)
178 NTSTATUS ret;
179 struct dbwrap_change_uint32_atomic_context state;
181 state.keystr = keystr;
182 state.oldval = oldval;
183 state.change_val = change_val;
185 ret = dbwrap_trans_do(db, dbwrap_change_uint32_atomic_action, &state);
187 return ret;
191 * Atomic integer change (addition):
193 * if value does not exist yet in the db, use *oldval as initial old value.
194 * return old value in *oldval.
195 * store *oldval + change_val to db.
198 struct dbwrap_change_int32_atomic_context {
199 const char *keystr;
200 int32_t *oldval;
201 int32_t change_val;
204 static NTSTATUS dbwrap_change_int32_atomic_action(struct db_context *db,
205 void *private_data)
207 struct db_record *rec;
208 int32_t val = -1;
209 int32_t v_store;
210 NTSTATUS ret;
211 struct dbwrap_change_int32_atomic_context *state;
213 state = (struct dbwrap_change_int32_atomic_context *)private_data;
215 rec = db->fetch_locked(db, NULL, string_term_tdb_data(state->keystr));
216 if (!rec) {
217 return NT_STATUS_UNSUCCESSFUL;
220 if (rec->value.dptr == NULL) {
221 val = *(state->oldval);
222 } else if (rec->value.dsize == sizeof(val)) {
223 val = IVAL(rec->value.dptr, 0);
224 *(state->oldval) = val;
225 } else {
226 ret = NT_STATUS_UNSUCCESSFUL;
227 goto done;
230 val += state->change_val;
232 SIVAL(&v_store, 0, val);
234 ret = rec->store(rec,
235 make_tdb_data((const uint8_t *)&v_store,
236 sizeof(v_store)),
237 TDB_REPLACE);
239 done:
240 TALLOC_FREE(rec);
241 return ret;
244 NTSTATUS dbwrap_change_int32_atomic(struct db_context *db, const char *keystr,
245 int32_t *oldval, int32_t change_val)
247 NTSTATUS ret;
248 struct dbwrap_change_int32_atomic_context state;
250 state.keystr = keystr;
251 state.oldval = oldval;
252 state.change_val = change_val;
254 ret = dbwrap_change_int32_atomic_action(db, &state);
256 return ret;
259 NTSTATUS dbwrap_trans_change_int32_atomic(struct db_context *db,
260 const char *keystr,
261 int32_t *oldval,
262 int32_t change_val)
264 NTSTATUS ret;
265 struct dbwrap_change_int32_atomic_context state;
267 state.keystr = keystr;
268 state.oldval = oldval;
269 state.change_val = change_val;
271 ret = dbwrap_trans_do(db, dbwrap_change_int32_atomic_action, &state);
273 return ret;
276 struct dbwrap_store_context {
277 TDB_DATA *key;
278 TDB_DATA *dbuf;
279 int flag;
282 static NTSTATUS dbwrap_store_action(struct db_context *db, void *private_data)
284 struct db_record *rec = NULL;
285 NTSTATUS status;
286 struct dbwrap_store_context *store_ctx;
288 store_ctx = (struct dbwrap_store_context *)private_data;
290 rec = db->fetch_locked(db, talloc_tos(), *(store_ctx->key));
291 if (rec == NULL) {
292 DEBUG(5, ("fetch_locked failed\n"));
293 return NT_STATUS_NO_MEMORY;
296 status = rec->store(rec, *(store_ctx->dbuf), store_ctx->flag);
297 if (!NT_STATUS_IS_OK(status)) {
298 DEBUG(5, ("store returned %s\n", nt_errstr(status)));
301 TALLOC_FREE(rec);
302 return status;
305 NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
306 int flag)
308 NTSTATUS status;
309 struct dbwrap_store_context store_ctx;
311 store_ctx.key = &key;
312 store_ctx.dbuf = &dbuf;
313 store_ctx.flag = flag;
315 status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx);
317 return status;
320 static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
322 NTSTATUS status;
323 struct db_record *rec;
324 TDB_DATA *key = (TDB_DATA *)private_data;
326 rec = db->fetch_locked(db, talloc_tos(), *key);
327 if (rec == NULL) {
328 DEBUG(5, ("fetch_locked failed\n"));
329 return NT_STATUS_NO_MEMORY;
332 status = rec->delete_rec(rec);
333 if (!NT_STATUS_IS_OK(status)) {
334 DEBUG(5, ("delete_rec returned %s\n", nt_errstr(status)));
337 talloc_free(rec);
338 return status;
341 NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
343 NTSTATUS status;
345 status = dbwrap_trans_do(db, dbwrap_delete_action, &key);
347 return status;
350 NTSTATUS dbwrap_trans_store_int32(struct db_context *db, const char *keystr,
351 int32_t v)
353 int32 v_store;
355 SIVAL(&v_store, 0, v);
357 return dbwrap_trans_store(db, string_term_tdb_data(keystr),
358 make_tdb_data((const uint8 *)&v_store,
359 sizeof(v_store)),
360 TDB_REPLACE);
363 NTSTATUS dbwrap_trans_store_uint32(struct db_context *db, const char *keystr,
364 uint32_t v)
366 uint32 v_store;
368 SIVAL(&v_store, 0, v);
370 return dbwrap_trans_store(db, string_term_tdb_data(keystr),
371 make_tdb_data((const uint8 *)&v_store,
372 sizeof(v_store)),
373 TDB_REPLACE);
376 NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
377 TDB_DATA data, int flags)
379 return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
382 NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
384 return dbwrap_trans_delete(db, string_term_tdb_data(key));
388 * Wrap db action(s) into a transaction.
390 NTSTATUS dbwrap_trans_do(struct db_context *db,
391 NTSTATUS (*action)(struct db_context *, void *),
392 void *private_data)
394 int res;
395 NTSTATUS status;
397 res = db->transaction_start(db);
398 if (res != 0) {
399 DEBUG(5, ("transaction_start failed\n"));
400 return NT_STATUS_INTERNAL_DB_CORRUPTION;
403 status = action(db, private_data);
404 if (!NT_STATUS_IS_OK(status)) {
405 if (db->transaction_cancel(db) != 0) {
406 smb_panic("Cancelling transaction failed");
408 return status;
411 res = db->transaction_commit(db);
412 if (res == 0) {
413 return NT_STATUS_OK;
416 DEBUG(2, ("transaction_commit failed\n"));
417 return NT_STATUS_INTERNAL_DB_CORRUPTION;
420 struct dbwrap_trans_traverse_action_ctx {
421 int (*f)(struct db_record* rec, void* private_data);
422 void* private_data;
426 static NTSTATUS dbwrap_trans_traverse_action(struct db_context* db, void* private_data)
428 struct dbwrap_trans_traverse_action_ctx* ctx =
429 (struct dbwrap_trans_traverse_action_ctx*)private_data;
431 int ret = db->traverse(db, ctx->f, ctx->private_data);
433 return (ret == -1) ? NT_STATUS_INTERNAL_DB_CORRUPTION : NT_STATUS_OK;
436 NTSTATUS dbwrap_trans_traverse(struct db_context *db,
437 int (*f)(struct db_record*, void*),
438 void *private_data)
440 struct dbwrap_trans_traverse_action_ctx ctx = {
441 .f = f,
442 .private_data = private_data,
444 return dbwrap_trans_do(db, dbwrap_trans_traverse_action, &ctx);
447 NTSTATUS dbwrap_traverse(struct db_context *db,
448 int (*f)(struct db_record*, void*),
449 void *private_data,
450 int *count)
452 int ret = db->traverse(db, f, private_data);
454 if (ret < 0) {
455 return NT_STATUS_INTERNAL_DB_CORRUPTION;
458 if (count != NULL) {
459 *count = ret;
462 return NT_STATUS_OK;
465 NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
467 char *key_upper;
468 NTSTATUS status;
470 key_upper = talloc_strdup_upper(talloc_tos(), key);
471 if (key_upper == NULL) {
472 return NT_STATUS_NO_MEMORY;
475 status = dbwrap_delete_bystring(db, key_upper);
477 talloc_free(key_upper);
478 return status;
481 NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
482 TDB_DATA data, int flags)
484 char *key_upper;
485 NTSTATUS status;
487 key_upper = talloc_strdup_upper(talloc_tos(), key);
488 if (key_upper == NULL) {
489 return NT_STATUS_NO_MEMORY;
492 status = dbwrap_store_bystring(db, key_upper, data, flags);
494 talloc_free(key_upper);
495 return status;
498 TDB_DATA dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
499 const char *key)
501 char *key_upper;
502 TDB_DATA result;
504 key_upper = talloc_strdup_upper(talloc_tos(), key);
505 if (key_upper == NULL) {
506 return make_tdb_data(NULL, 0);
509 result = dbwrap_fetch_bystring(db, mem_ctx, key_upper);
511 talloc_free(key_upper);
512 return result;