source: vendor/3.6.23/source3/lib/dbwrap_util.c

Last change on this file was 746, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated vendor to 3.6.9

File size: 11.9 KB
Line 
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
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.
11
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.
16
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.
20*/
21
22#include "includes.h"
23#include "dbwrap.h"
24#include "util_tdb.h"
25
26int32_t dbwrap_fetch_int32(struct db_context *db, const char *keystr)
27{
28 TDB_DATA dbuf;
29 int32 ret;
30
31 if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
32 return -1;
33 }
34
35 if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(int32_t))) {
36 TALLOC_FREE(dbuf.dptr);
37 return -1;
38 }
39
40 ret = IVAL(dbuf.dptr, 0);
41 TALLOC_FREE(dbuf.dptr);
42 return ret;
43}
44
45int dbwrap_store_int32(struct db_context *db, const char *keystr, int32_t v)
46{
47 struct db_record *rec;
48 int32 v_store;
49 NTSTATUS status;
50
51 rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
52 if (rec == NULL) {
53 return -1;
54 }
55
56 SIVAL(&v_store, 0, v);
57
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;
63}
64
65bool dbwrap_fetch_uint32(struct db_context *db, const char *keystr,
66 uint32_t *val)
67{
68 TDB_DATA dbuf;
69
70 if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
71 return false;
72 }
73
74 if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(uint32_t))) {
75 TALLOC_FREE(dbuf.dptr);
76 return false;
77 }
78
79 *val = IVAL(dbuf.dptr, 0);
80 TALLOC_FREE(dbuf.dptr);
81 return true;
82}
83
84int dbwrap_store_uint32(struct db_context *db, const char *keystr, uint32_t v)
85{
86 struct db_record *rec;
87 uint32 v_store;
88 NTSTATUS status;
89
90 rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
91 if (rec == NULL) {
92 return -1;
93 }
94
95 SIVAL(&v_store, 0, v);
96
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;
102}
103
104/**
105 * Atomic unsigned integer change (addition):
106 *
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.
110 */
111
112struct dbwrap_change_uint32_atomic_context {
113 const char *keystr;
114 uint32_t *oldval;
115 uint32_t change_val;
116};
117
118static NTSTATUS dbwrap_change_uint32_atomic_action(struct db_context *db,
119 void *private_data)
120{
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;
126
127 state = (struct dbwrap_change_uint32_atomic_context *)private_data;
128
129 rec = db->fetch_locked(db, NULL, string_term_tdb_data(state->keystr));
130 if (!rec) {
131 return NT_STATUS_UNSUCCESSFUL;
132 }
133
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;
142 }
143
144 val += state->change_val;
145
146 SIVAL(&v_store, 0, val);
147
148 ret = rec->store(rec,
149 make_tdb_data((const uint8 *)&v_store,
150 sizeof(v_store)),
151 TDB_REPLACE);
152
153done:
154 TALLOC_FREE(rec);
155 return ret;
156}
157
158NTSTATUS dbwrap_change_uint32_atomic(struct db_context *db, const char *keystr,
159 uint32_t *oldval, uint32_t change_val)
160{
161 NTSTATUS ret;
162 struct dbwrap_change_uint32_atomic_context state;
163
164 state.keystr = keystr;
165 state.oldval = oldval;
166 state.change_val = change_val;
167
168 ret = dbwrap_change_uint32_atomic_action(db, &state);
169
170 return ret;
171}
172
173NTSTATUS dbwrap_trans_change_uint32_atomic(struct db_context *db,
174 const char *keystr,
175 uint32_t *oldval,
176 uint32_t change_val)
177{
178 NTSTATUS ret;
179 struct dbwrap_change_uint32_atomic_context state;
180
181 state.keystr = keystr;
182 state.oldval = oldval;
183 state.change_val = change_val;
184
185 ret = dbwrap_trans_do(db, dbwrap_change_uint32_atomic_action, &state);
186
187 return ret;
188}
189
190/**
191 * Atomic integer change (addition):
192 *
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.
196 */
197
198struct dbwrap_change_int32_atomic_context {
199 const char *keystr;
200 int32_t *oldval;
201 int32_t change_val;
202};
203
204static NTSTATUS dbwrap_change_int32_atomic_action(struct db_context *db,
205 void *private_data)
206{
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;
212
213 state = (struct dbwrap_change_int32_atomic_context *)private_data;
214
215 rec = db->fetch_locked(db, NULL, string_term_tdb_data(state->keystr));
216 if (!rec) {
217 return NT_STATUS_UNSUCCESSFUL;
218 }
219
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;
228 }
229
230 val += state->change_val;
231
232 SIVAL(&v_store, 0, val);
233
234 ret = rec->store(rec,
235 make_tdb_data((const uint8_t *)&v_store,
236 sizeof(v_store)),
237 TDB_REPLACE);
238
239done:
240 TALLOC_FREE(rec);
241 return ret;
242}
243
244NTSTATUS dbwrap_change_int32_atomic(struct db_context *db, const char *keystr,
245 int32_t *oldval, int32_t change_val)
246{
247 NTSTATUS ret;
248 struct dbwrap_change_int32_atomic_context state;
249
250 state.keystr = keystr;
251 state.oldval = oldval;
252 state.change_val = change_val;
253
254 ret = dbwrap_change_int32_atomic_action(db, &state);
255
256 return ret;
257}
258
259NTSTATUS dbwrap_trans_change_int32_atomic(struct db_context *db,
260 const char *keystr,
261 int32_t *oldval,
262 int32_t change_val)
263{
264 NTSTATUS ret;
265 struct dbwrap_change_int32_atomic_context state;
266
267 state.keystr = keystr;
268 state.oldval = oldval;
269 state.change_val = change_val;
270
271 ret = dbwrap_trans_do(db, dbwrap_change_int32_atomic_action, &state);
272
273 return ret;
274}
275
276struct dbwrap_store_context {
277 TDB_DATA *key;
278 TDB_DATA *dbuf;
279 int flag;
280};
281
282static NTSTATUS dbwrap_store_action(struct db_context *db, void *private_data)
283{
284 struct db_record *rec = NULL;
285 NTSTATUS status;
286 struct dbwrap_store_context *store_ctx;
287
288 store_ctx = (struct dbwrap_store_context *)private_data;
289
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;
294 }
295
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)));
299 }
300
301 TALLOC_FREE(rec);
302 return status;
303}
304
305NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
306 int flag)
307{
308 NTSTATUS status;
309 struct dbwrap_store_context store_ctx;
310
311 store_ctx.key = &key;
312 store_ctx.dbuf = &dbuf;
313 store_ctx.flag = flag;
314
315 status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx);
316
317 return status;
318}
319
320static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
321{
322 NTSTATUS status;
323 struct db_record *rec;
324 TDB_DATA *key = (TDB_DATA *)private_data;
325
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;
330 }
331
332 status = rec->delete_rec(rec);
333 if (!NT_STATUS_IS_OK(status)) {
334 DEBUG(5, ("delete_rec returned %s\n", nt_errstr(status)));
335 }
336
337 talloc_free(rec);
338 return status;
339}
340
341NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
342{
343 NTSTATUS status;
344
345 status = dbwrap_trans_do(db, dbwrap_delete_action, &key);
346
347 return status;
348}
349
350NTSTATUS dbwrap_trans_store_int32(struct db_context *db, const char *keystr,
351 int32_t v)
352{
353 int32 v_store;
354
355 SIVAL(&v_store, 0, v);
356
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);
361}
362
363NTSTATUS dbwrap_trans_store_uint32(struct db_context *db, const char *keystr,
364 uint32_t v)
365{
366 uint32 v_store;
367
368 SIVAL(&v_store, 0, v);
369
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);
374}
375
376NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
377 TDB_DATA data, int flags)
378{
379 return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
380}
381
382NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
383{
384 return dbwrap_trans_delete(db, string_term_tdb_data(key));
385}
386
387/**
388 * Wrap db action(s) into a transaction.
389 */
390NTSTATUS dbwrap_trans_do(struct db_context *db,
391 NTSTATUS (*action)(struct db_context *, void *),
392 void *private_data)
393{
394 int res;
395 NTSTATUS status;
396
397 res = db->transaction_start(db);
398 if (res != 0) {
399 DEBUG(5, ("transaction_start failed\n"));
400 return NT_STATUS_INTERNAL_DB_CORRUPTION;
401 }
402
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");
407 }
408 return status;
409 }
410
411 res = db->transaction_commit(db);
412 if (res == 0) {
413 return NT_STATUS_OK;
414 }
415
416 DEBUG(2, ("transaction_commit failed\n"));
417 return NT_STATUS_INTERNAL_DB_CORRUPTION;
418}
419
420struct dbwrap_trans_traverse_action_ctx {
421 int (*f)(struct db_record* rec, void* private_data);
422 void* private_data;
423};
424
425
426static NTSTATUS dbwrap_trans_traverse_action(struct db_context* db, void* private_data)
427{
428 struct dbwrap_trans_traverse_action_ctx* ctx =
429 (struct dbwrap_trans_traverse_action_ctx*)private_data;
430
431 int ret = db->traverse(db, ctx->f, ctx->private_data);
432
433 return (ret == -1) ? NT_STATUS_INTERNAL_DB_CORRUPTION : NT_STATUS_OK;
434}
435
436NTSTATUS dbwrap_trans_traverse(struct db_context *db,
437 int (*f)(struct db_record*, void*),
438 void *private_data)
439{
440 struct dbwrap_trans_traverse_action_ctx ctx = {
441 .f = f,
442 .private_data = private_data,
443 };
444 return dbwrap_trans_do(db, dbwrap_trans_traverse_action, &ctx);
445}
446
447NTSTATUS dbwrap_traverse(struct db_context *db,
448 int (*f)(struct db_record*, void*),
449 void *private_data,
450 int *count)
451{
452 int ret = db->traverse(db, f, private_data);
453
454 if (ret < 0) {
455 return NT_STATUS_INTERNAL_DB_CORRUPTION;
456 }
457
458 if (count != NULL) {
459 *count = ret;
460 }
461
462 return NT_STATUS_OK;
463}
464
465NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
466{
467 char *key_upper;
468 NTSTATUS status;
469
470 key_upper = talloc_strdup_upper(talloc_tos(), key);
471 if (key_upper == NULL) {
472 return NT_STATUS_NO_MEMORY;
473 }
474
475 status = dbwrap_delete_bystring(db, key_upper);
476
477 talloc_free(key_upper);
478 return status;
479}
480
481NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
482 TDB_DATA data, int flags)
483{
484 char *key_upper;
485 NTSTATUS status;
486
487 key_upper = talloc_strdup_upper(talloc_tos(), key);
488 if (key_upper == NULL) {
489 return NT_STATUS_NO_MEMORY;
490 }
491
492 status = dbwrap_store_bystring(db, key_upper, data, flags);
493
494 talloc_free(key_upper);
495 return status;
496}
497
498TDB_DATA dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
499 const char *key)
500{
501 char *key_upper;
502 TDB_DATA result;
503
504 key_upper = talloc_strdup_upper(talloc_tos(), key);
505 if (key_upper == NULL) {
506 return make_tdb_data(NULL, 0);
507 }
508
509 result = dbwrap_fetch_bystring(db, mem_ctx, key_upper);
510
511 talloc_free(key_upper);
512 return result;
513}
Note: See TracBrowser for help on using the repository browser.