dbwrap: dbwrap_trans_change_int32_atomic->dbwrap_trans_change_int32_atomic_bystring
[ddiss/samba.git] / lib / dbwrap / dbwrap_util.c
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
7
8    Major code contributions from Aleksey Fedoseev (fedoseev@ru.ibm.com)
9
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.
14
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.
19
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.
23 */
24
25 #include "includes.h"
26 #include "dbwrap.h"
27 #include "lib/util/util_tdb.h"
28
29 NTSTATUS dbwrap_fetch_int32_bystring(struct db_context *db, const char *keystr,
30                                      int32_t *result)
31 {
32         TDB_DATA dbuf;
33         NTSTATUS status;
34
35         if (result == NULL) {
36                 return NT_STATUS_INVALID_PARAMETER;
37         }
38
39         status = dbwrap_fetch_bystring(db, talloc_tos(), keystr, &dbuf);
40         if (!NT_STATUS_IS_OK(status)) {
41                 return status;
42         }
43
44         if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(int32_t))) {
45                 TALLOC_FREE(dbuf.dptr);
46                 return NT_STATUS_NOT_FOUND;
47         }
48
49         *result = IVAL(dbuf.dptr, 0);
50         TALLOC_FREE(dbuf.dptr);
51         return NT_STATUS_OK;
52 }
53
54 NTSTATUS dbwrap_store_int32_bystring(struct db_context *db, const char *keystr,
55                                      int32_t v)
56 {
57         struct db_record *rec;
58         int32_t v_store;
59         NTSTATUS status;
60
61         rec = dbwrap_fetch_locked(db, talloc_tos(),
62                                   string_term_tdb_data(keystr));
63         if (rec == NULL) {
64                 return NT_STATUS_UNSUCCESSFUL;
65         }
66
67         SIVAL(&v_store, 0, v);
68
69         status = dbwrap_record_store(rec,
70                                      make_tdb_data((const uint8_t *)&v_store,
71                                                    sizeof(v_store)),
72                                      TDB_REPLACE);
73         TALLOC_FREE(rec);
74         return status;
75 }
76
77 NTSTATUS dbwrap_fetch_uint32_bystring(struct db_context *db,
78                                       const char *keystr, uint32_t *val)
79 {
80         TDB_DATA dbuf;
81         NTSTATUS status;
82
83         if (val == NULL) {
84                 return NT_STATUS_INVALID_PARAMETER;
85         }
86
87         status = dbwrap_fetch_bystring(db, talloc_tos(), keystr, &dbuf);
88         if (!NT_STATUS_IS_OK(status)) {
89                 return status;
90         }
91
92         if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(uint32_t))) {
93                 TALLOC_FREE(dbuf.dptr);
94                 return NT_STATUS_NOT_FOUND;
95         }
96
97         *val = IVAL(dbuf.dptr, 0);
98         TALLOC_FREE(dbuf.dptr);
99         return NT_STATUS_OK;
100 }
101
102 NTSTATUS dbwrap_store_uint32_bystring(struct db_context *db,
103                                       const char *keystr, uint32_t v)
104 {
105         struct db_record *rec;
106         uint32_t v_store;
107         NTSTATUS status;
108
109         rec = dbwrap_fetch_locked(db, talloc_tos(),
110                                   string_term_tdb_data(keystr));
111         if (rec == NULL) {
112                 return NT_STATUS_INVALID_PARAMETER;
113         }
114
115         SIVAL(&v_store, 0, v);
116
117         status = dbwrap_record_store(rec,
118                                      make_tdb_data((const uint8_t *)&v_store,
119                                                    sizeof(v_store)),
120                                      TDB_REPLACE);
121         TALLOC_FREE(rec);
122         return status;
123 }
124
125 /**
126  * Atomic unsigned integer change (addition):
127  *
128  * if value does not exist yet in the db, use *oldval as initial old value.
129  * return old value in *oldval.
130  * store *oldval + change_val to db.
131  */
132
133 struct dbwrap_change_uint32_atomic_context {
134         const char *keystr;
135         uint32_t *oldval;
136         uint32_t change_val;
137 };
138
139 static NTSTATUS dbwrap_change_uint32_atomic_action(struct db_context *db,
140                                                    void *private_data)
141 {
142         struct db_record *rec;
143         uint32_t val = (uint32_t)-1;
144         uint32_t v_store;
145         NTSTATUS ret;
146         struct dbwrap_change_uint32_atomic_context *state;
147         TDB_DATA value;
148
149         state = (struct dbwrap_change_uint32_atomic_context *)private_data;
150
151         rec = dbwrap_fetch_locked(db, talloc_tos(),
152                                   string_term_tdb_data(state->keystr));
153         if (!rec) {
154                 return NT_STATUS_UNSUCCESSFUL;
155         }
156
157         value = dbwrap_record_get_value(rec);
158
159         if (value.dptr == NULL) {
160                 val = *(state->oldval);
161         } else if (value.dsize == sizeof(val)) {
162                 val = IVAL(value.dptr, 0);
163                 *(state->oldval) = val;
164         } else {
165                 ret = NT_STATUS_UNSUCCESSFUL;
166                 goto done;
167         }
168
169         val += state->change_val;
170
171         SIVAL(&v_store, 0, val);
172
173         ret = dbwrap_record_store(rec,
174                                   make_tdb_data((const uint8_t *)&v_store,
175                                                 sizeof(v_store)),
176                                   TDB_REPLACE);
177
178 done:
179         TALLOC_FREE(rec);
180         return ret;
181 }
182
183 NTSTATUS dbwrap_change_uint32_atomic_bystring(struct db_context *db,
184                                               const char *keystr,
185                                               uint32_t *oldval,
186                                               uint32_t change_val)
187 {
188         NTSTATUS ret;
189         struct dbwrap_change_uint32_atomic_context state;
190
191         state.keystr = keystr;
192         state.oldval = oldval;
193         state.change_val = change_val;
194
195         ret = dbwrap_change_uint32_atomic_action(db, &state);
196
197         return ret;
198 }
199
200 NTSTATUS dbwrap_trans_change_uint32_atomic_bystring(struct db_context *db,
201                                                     const char *keystr,
202                                                     uint32_t *oldval,
203                                                     uint32_t change_val)
204 {
205         NTSTATUS ret;
206         struct dbwrap_change_uint32_atomic_context state;
207
208         state.keystr = keystr;
209         state.oldval = oldval;
210         state.change_val = change_val;
211
212         ret = dbwrap_trans_do(db, dbwrap_change_uint32_atomic_action, &state);
213
214         return ret;
215 }
216
217 /**
218  * Atomic integer change (addition):
219  *
220  * if value does not exist yet in the db, use *oldval as initial old value.
221  * return old value in *oldval.
222  * store *oldval + change_val to db.
223  */
224
225 struct dbwrap_change_int32_atomic_context {
226         const char *keystr;
227         int32_t *oldval;
228         int32_t change_val;
229 };
230
231 static NTSTATUS dbwrap_change_int32_atomic_action(struct db_context *db,
232                                                   void *private_data)
233 {
234         struct db_record *rec;
235         int32_t val = -1;
236         int32_t v_store;
237         NTSTATUS ret;
238         struct dbwrap_change_int32_atomic_context *state;
239         TDB_DATA value;
240
241         state = (struct dbwrap_change_int32_atomic_context *)private_data;
242
243         rec = dbwrap_fetch_locked(db, talloc_tos(),
244                                   string_term_tdb_data(state->keystr));
245         if (!rec) {
246                 return NT_STATUS_UNSUCCESSFUL;
247         }
248
249         value = dbwrap_record_get_value(rec);
250
251         if (value.dptr == NULL) {
252                 val = *(state->oldval);
253         } else if (value.dsize == sizeof(val)) {
254                 val = IVAL(value.dptr, 0);
255                 *(state->oldval) = val;
256         } else {
257                 ret = NT_STATUS_UNSUCCESSFUL;
258                 goto done;
259         }
260
261         val += state->change_val;
262
263         SIVAL(&v_store, 0, val);
264
265         ret = dbwrap_record_store(rec,
266                                   make_tdb_data((const uint8_t *)&v_store,
267                                                 sizeof(v_store)),
268                                   TDB_REPLACE);
269
270 done:
271         TALLOC_FREE(rec);
272         return ret;
273 }
274
275 NTSTATUS dbwrap_change_int32_atomic_bystring(struct db_context *db,
276                                              const char *keystr,
277                                              int32_t *oldval,
278                                              int32_t change_val)
279 {
280         NTSTATUS ret;
281         struct dbwrap_change_int32_atomic_context state;
282
283         state.keystr = keystr;
284         state.oldval = oldval;
285         state.change_val = change_val;
286
287         ret = dbwrap_change_int32_atomic_action(db, &state);
288
289         return ret;
290 }
291
292 NTSTATUS dbwrap_trans_change_int32_atomic_bystring(struct db_context *db,
293                                                    const char *keystr,
294                                                    int32_t *oldval,
295                                                    int32_t change_val)
296 {
297         NTSTATUS ret;
298         struct dbwrap_change_int32_atomic_context state;
299
300         state.keystr = keystr;
301         state.oldval = oldval;
302         state.change_val = change_val;
303
304         ret = dbwrap_trans_do(db, dbwrap_change_int32_atomic_action, &state);
305
306         return ret;
307 }
308
309 struct dbwrap_store_context {
310         TDB_DATA *key;
311         TDB_DATA *dbuf;
312         int flag;
313 };
314
315 static NTSTATUS dbwrap_store_action(struct db_context *db, void *private_data)
316 {
317         struct db_record *rec = NULL;
318         NTSTATUS status;
319         struct dbwrap_store_context *store_ctx;
320
321         store_ctx = (struct dbwrap_store_context *)private_data;
322
323         rec = dbwrap_fetch_locked(db, talloc_tos(), *(store_ctx->key));
324         if (rec == NULL) {
325                 DEBUG(5, ("fetch_locked failed\n"));
326                 return NT_STATUS_NO_MEMORY;
327         }
328
329         status = dbwrap_record_store(rec, *(store_ctx->dbuf), store_ctx->flag);
330         if (!NT_STATUS_IS_OK(status)) {
331                 DEBUG(5, ("store returned %s\n", nt_errstr(status)));
332         }
333
334         TALLOC_FREE(rec);
335         return status;
336 }
337
338 NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
339                             int flag)
340 {
341         NTSTATUS status;
342         struct dbwrap_store_context store_ctx;
343
344         store_ctx.key = &key;
345         store_ctx.dbuf = &dbuf;
346         store_ctx.flag = flag;
347
348         status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx);
349
350         return status;
351 }
352
353 static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
354 {
355         NTSTATUS status;
356         struct db_record *rec;
357         TDB_DATA *key = (TDB_DATA *)private_data;
358
359         rec = dbwrap_fetch_locked(db, talloc_tos(), *key);
360         if (rec == NULL) {
361                 DEBUG(5, ("fetch_locked failed\n"));
362                 return NT_STATUS_NO_MEMORY;
363         }
364
365         status = dbwrap_record_delete(rec);
366         if (!NT_STATUS_IS_OK(status)) {
367                 DEBUG(5, ("delete_rec returned %s\n", nt_errstr(status)));
368         }
369
370         talloc_free(rec);
371         return  status;
372 }
373
374 NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
375 {
376         NTSTATUS status;
377
378         status = dbwrap_trans_do(db, dbwrap_delete_action, &key);
379
380         return status;
381 }
382
383 NTSTATUS dbwrap_trans_store_int32(struct db_context *db, const char *keystr,
384                                   int32_t v)
385 {
386         int32_t v_store;
387
388         SIVAL(&v_store, 0, v);
389
390         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
391                                   make_tdb_data((const uint8_t *)&v_store,
392                                                 sizeof(v_store)),
393                                   TDB_REPLACE);
394 }
395
396 NTSTATUS dbwrap_trans_store_uint32(struct db_context *db, const char *keystr,
397                                    uint32_t v)
398 {
399         uint32_t v_store;
400
401         SIVAL(&v_store, 0, v);
402
403         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
404                                   make_tdb_data((const uint8_t *)&v_store,
405                                                 sizeof(v_store)),
406                                   TDB_REPLACE);
407 }
408
409 NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
410                                      TDB_DATA data, int flags)
411 {
412         return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
413 }
414
415 NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
416 {
417         return dbwrap_trans_delete(db, string_term_tdb_data(key));
418 }
419
420 /**
421  * Wrap db action(s) into a transaction.
422  */
423 NTSTATUS dbwrap_trans_do(struct db_context *db,
424                          NTSTATUS (*action)(struct db_context *, void *),
425                          void *private_data)
426 {
427         int res;
428         NTSTATUS status;
429
430         res = dbwrap_transaction_start(db);
431         if (res != 0) {
432                 DEBUG(5, ("transaction_start failed\n"));
433                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
434         }
435
436         status = action(db, private_data);
437         if (!NT_STATUS_IS_OK(status)) {
438                 if (dbwrap_transaction_cancel(db) != 0) {
439                         smb_panic("Cancelling transaction failed");
440                 }
441                 return status;
442         }
443
444         res = dbwrap_transaction_commit(db);
445         if (res == 0) {
446                 return NT_STATUS_OK;
447         }
448
449         DEBUG(2, ("transaction_commit failed\n"));
450         return NT_STATUS_INTERNAL_DB_CORRUPTION;
451 }
452
453 struct dbwrap_trans_traverse_action_ctx {
454         int (*f)(struct db_record* rec, void* private_data);
455         void* private_data;
456 };
457
458
459 static NTSTATUS dbwrap_trans_traverse_action(struct db_context* db, void* private_data)
460 {
461         struct dbwrap_trans_traverse_action_ctx* ctx =
462                 (struct dbwrap_trans_traverse_action_ctx*)private_data;
463
464         NTSTATUS status = dbwrap_traverse(db, ctx->f, ctx->private_data, NULL);
465
466         return status;
467 }
468
469 NTSTATUS dbwrap_trans_traverse(struct db_context *db,
470                                int (*f)(struct db_record*, void*),
471                                void *private_data)
472 {
473         struct dbwrap_trans_traverse_action_ctx ctx = {
474                 .f = f,
475                 .private_data = private_data,
476         };
477         return dbwrap_trans_do(db, dbwrap_trans_traverse_action, &ctx);
478 }
479
480 NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key)
481 {
482         return dbwrap_delete(db, string_term_tdb_data(key));
483 }
484
485 NTSTATUS dbwrap_store_bystring(struct db_context *db, const char *key,
486                                TDB_DATA data, int flags)
487 {
488         return dbwrap_store(db, string_term_tdb_data(key), data, flags);
489 }
490
491 NTSTATUS dbwrap_fetch_bystring(struct db_context *db, TALLOC_CTX *mem_ctx,
492                                const char *key, TDB_DATA *value)
493 {
494         return dbwrap_fetch(db, mem_ctx, string_term_tdb_data(key), value);
495 }
496
497
498
499 NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
500 {
501         char *key_upper;
502         NTSTATUS status;
503
504         key_upper = talloc_strdup_upper(talloc_tos(), key);
505         if (key_upper == NULL) {
506                 return NT_STATUS_NO_MEMORY;
507         }
508
509         status = dbwrap_delete_bystring(db, key_upper);
510
511         talloc_free(key_upper);
512         return status;
513 }
514
515 NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
516                                      TDB_DATA data, int flags)
517 {
518         char *key_upper;
519         NTSTATUS status;
520
521         key_upper = talloc_strdup_upper(talloc_tos(), key);
522         if (key_upper == NULL) {
523                 return NT_STATUS_NO_MEMORY;
524         }
525
526         status = dbwrap_store_bystring(db, key_upper, data, flags);
527
528         talloc_free(key_upper);
529         return status;
530 }
531
532 NTSTATUS dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
533                                      const char *key, TDB_DATA *value)
534 {
535         char *key_upper;
536         NTSTATUS status;
537
538         key_upper = talloc_strdup_upper(talloc_tos(), key);
539         if (key_upper == NULL) {
540                 return NT_STATUS_NO_MEMORY;
541         }
542
543         status = dbwrap_fetch_bystring(db, mem_ctx, key_upper, value);
544
545         talloc_free(key_upper);
546         return status;
547 }