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