8e6498d7d0c17320897b8b35ddc37b7faeb65adc
[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_bystring(struct db_context *db,
384                                            const char *keystr,
385                                            int32_t v)
386 {
387         int32_t v_store;
388
389         SIVAL(&v_store, 0, v);
390
391         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
392                                   make_tdb_data((const uint8_t *)&v_store,
393                                                 sizeof(v_store)),
394                                   TDB_REPLACE);
395 }
396
397 NTSTATUS dbwrap_trans_store_uint32_bystring(struct db_context *db,
398                                             const char *keystr,
399                                             uint32_t v)
400 {
401         uint32_t v_store;
402
403         SIVAL(&v_store, 0, v);
404
405         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
406                                   make_tdb_data((const uint8_t *)&v_store,
407                                                 sizeof(v_store)),
408                                   TDB_REPLACE);
409 }
410
411 NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
412                                      TDB_DATA data, int flags)
413 {
414         return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
415 }
416
417 NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
418 {
419         return dbwrap_trans_delete(db, string_term_tdb_data(key));
420 }
421
422 /**
423  * Wrap db action(s) into a transaction.
424  */
425 NTSTATUS dbwrap_trans_do(struct db_context *db,
426                          NTSTATUS (*action)(struct db_context *, void *),
427                          void *private_data)
428 {
429         int res;
430         NTSTATUS status;
431
432         res = dbwrap_transaction_start(db);
433         if (res != 0) {
434                 DEBUG(5, ("transaction_start failed\n"));
435                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
436         }
437
438         status = action(db, private_data);
439         if (!NT_STATUS_IS_OK(status)) {
440                 if (dbwrap_transaction_cancel(db) != 0) {
441                         smb_panic("Cancelling transaction failed");
442                 }
443                 return status;
444         }
445
446         res = dbwrap_transaction_commit(db);
447         if (res == 0) {
448                 return NT_STATUS_OK;
449         }
450
451         DEBUG(2, ("transaction_commit failed\n"));
452         return NT_STATUS_INTERNAL_DB_CORRUPTION;
453 }
454
455 struct dbwrap_trans_traverse_action_ctx {
456         int (*f)(struct db_record* rec, void* private_data);
457         void* private_data;
458 };
459
460
461 static NTSTATUS dbwrap_trans_traverse_action(struct db_context* db, void* private_data)
462 {
463         struct dbwrap_trans_traverse_action_ctx* ctx =
464                 (struct dbwrap_trans_traverse_action_ctx*)private_data;
465
466         NTSTATUS status = dbwrap_traverse(db, ctx->f, ctx->private_data, NULL);
467
468         return status;
469 }
470
471 NTSTATUS dbwrap_trans_traverse(struct db_context *db,
472                                int (*f)(struct db_record*, void*),
473                                void *private_data)
474 {
475         struct dbwrap_trans_traverse_action_ctx ctx = {
476                 .f = f,
477                 .private_data = private_data,
478         };
479         return dbwrap_trans_do(db, dbwrap_trans_traverse_action, &ctx);
480 }
481
482 NTSTATUS dbwrap_delete_bystring(struct db_context *db, const char *key)
483 {
484         return dbwrap_delete(db, string_term_tdb_data(key));
485 }
486
487 NTSTATUS dbwrap_store_bystring(struct db_context *db, const char *key,
488                                TDB_DATA data, int flags)
489 {
490         return dbwrap_store(db, string_term_tdb_data(key), data, flags);
491 }
492
493 NTSTATUS dbwrap_fetch_bystring(struct db_context *db, TALLOC_CTX *mem_ctx,
494                                const char *key, TDB_DATA *value)
495 {
496         return dbwrap_fetch(db, mem_ctx, string_term_tdb_data(key), value);
497 }
498
499
500
501 NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
502 {
503         char *key_upper;
504         NTSTATUS status;
505
506         key_upper = talloc_strdup_upper(talloc_tos(), key);
507         if (key_upper == NULL) {
508                 return NT_STATUS_NO_MEMORY;
509         }
510
511         status = dbwrap_delete_bystring(db, key_upper);
512
513         talloc_free(key_upper);
514         return status;
515 }
516
517 NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
518                                      TDB_DATA data, int flags)
519 {
520         char *key_upper;
521         NTSTATUS status;
522
523         key_upper = talloc_strdup_upper(talloc_tos(), key);
524         if (key_upper == NULL) {
525                 return NT_STATUS_NO_MEMORY;
526         }
527
528         status = dbwrap_store_bystring(db, key_upper, data, flags);
529
530         talloc_free(key_upper);
531         return status;
532 }
533
534 NTSTATUS dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
535                                      const char *key, TDB_DATA *value)
536 {
537         char *key_upper;
538         NTSTATUS status;
539
540         key_upper = talloc_strdup_upper(talloc_tos(), key);
541         if (key_upper == NULL) {
542                 return NT_STATUS_NO_MEMORY;
543         }
544
545         status = dbwrap_fetch_bystring(db, mem_ctx, key_upper, value);
546
547         talloc_free(key_upper);
548         return status;
549 }