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