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