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