f83840d8b7a16ada93866977fdd20668b2658829
[metze/samba/wip.git] / source3 / lib / 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    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 int32_t dbwrap_fetch_int32(struct db_context *db, const char *keystr)
25 {
26         TDB_DATA dbuf;
27         int32 ret;
28
29         if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
30                 return -1;
31         }
32
33         if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(int32_t))) {
34                 TALLOC_FREE(dbuf.dptr);
35                 return -1;
36         }
37
38         ret = IVAL(dbuf.dptr, 0);
39         TALLOC_FREE(dbuf.dptr);
40         return ret;
41 }
42
43 int dbwrap_store_int32(struct db_context *db, const char *keystr, int32_t v)
44 {
45         struct db_record *rec;
46         int32 v_store;
47         NTSTATUS status;
48
49         rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
50         if (rec == NULL) {
51                 return -1;
52         }
53
54         SIVAL(&v_store, 0, v);
55
56         status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
57                                                sizeof(v_store)),
58                             TDB_REPLACE);
59         TALLOC_FREE(rec);
60         return NT_STATUS_IS_OK(status) ? 0 : -1;
61 }
62
63 bool dbwrap_fetch_uint32(struct db_context *db, const char *keystr,
64                          uint32_t *val)
65 {
66         TDB_DATA dbuf;
67
68         if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
69                 return false;
70         }
71
72         if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(uint32_t))) {
73                 TALLOC_FREE(dbuf.dptr);
74                 return false;
75         }
76
77         *val = IVAL(dbuf.dptr, 0);
78         TALLOC_FREE(dbuf.dptr);
79         return true;
80 }
81
82 int dbwrap_store_uint32(struct db_context *db, const char *keystr, uint32_t v)
83 {
84         struct db_record *rec;
85         uint32 v_store;
86         NTSTATUS status;
87
88         rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
89         if (rec == NULL) {
90                 return -1;
91         }
92
93         SIVAL(&v_store, 0, v);
94
95         status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
96                                                sizeof(v_store)),
97                             TDB_REPLACE);
98         TALLOC_FREE(rec);
99         return NT_STATUS_IS_OK(status) ? 0 : -1;
100 }
101
102 /**
103  * Atomic unsigned integer change (addition):
104  *
105  * if value does not exist yet in the db, use *oldval as initial old value.
106  * return old value in *oldval.
107  * store *oldval + change_val to db.
108  */
109 NTSTATUS dbwrap_change_uint32_atomic(struct db_context *db, const char *keystr,
110                                      uint32_t *oldval, uint32_t change_val)
111 {
112         struct db_record *rec;
113         uint32 val = -1;
114         TDB_DATA data;
115         NTSTATUS ret;
116
117         rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
118         if (!rec) {
119                 return NT_STATUS_UNSUCCESSFUL;
120         }
121
122         if (rec->value.dptr == NULL) {
123                 val = *oldval;
124         } else if (rec->value.dsize == sizeof(val)) {
125                 val = IVAL(rec->value.dptr, 0);
126                 *oldval = val;
127         } else {
128                 ret = NT_STATUS_UNSUCCESSFUL;
129                 goto done;
130         }
131
132         val += change_val;
133
134         data.dsize = sizeof(val);
135         data.dptr = (uint8 *)&val;
136
137         ret = rec->store(rec, data, TDB_REPLACE);
138
139 done:
140         TALLOC_FREE(rec);
141         return ret;
142 }
143
144 /**
145  * Atomic integer change (addition):
146  *
147  * if value does not exist yet in the db, use *oldval as initial old value.
148  * return old value in *oldval.
149  * store *oldval + change_val to db.
150  */
151 NTSTATUS dbwrap_change_int32_atomic(struct db_context *db, const char *keystr,
152                                     int32 *oldval, int32 change_val)
153 {
154         struct db_record *rec;
155         int32 val = -1;
156         TDB_DATA data;
157         NTSTATUS ret;
158
159         if (!(rec = db->fetch_locked(db, NULL,
160                                      string_term_tdb_data(keystr)))) {
161                 return NT_STATUS_UNSUCCESSFUL;
162         }
163
164         if (rec->value.dptr == NULL) {
165                 val = *oldval;
166         } else if (rec->value.dsize == sizeof(val)) {
167                 val = IVAL(rec->value.dptr, 0);
168                 *oldval = val;
169         } else {
170                 ret = NT_STATUS_UNSUCCESSFUL;
171                 goto done;
172         }
173
174         val += change_val;
175
176         data.dsize = sizeof(val);
177         data.dptr = (uint8 *)&val;
178
179         ret = rec->store(rec, data, TDB_REPLACE);
180
181 done:
182         TALLOC_FREE(rec);
183         return ret;
184 }
185
186 struct dbwrap_store_context {
187         TDB_DATA *key;
188         TDB_DATA *dbuf;
189         int flag;
190 };
191
192 static NTSTATUS dbwrap_store_action(struct db_context *db, void *private_data)
193 {
194         struct db_record *rec = NULL;
195         NTSTATUS status;
196         struct dbwrap_store_context *store_ctx;
197
198         store_ctx = (struct dbwrap_store_context *)private_data;
199
200         rec = db->fetch_locked(db, talloc_tos(), *(store_ctx->key));
201         if (rec == NULL) {
202                 DEBUG(5, ("fetch_locked failed\n"));
203                 return NT_STATUS_NO_MEMORY;
204         }
205
206         status = rec->store(rec, *(store_ctx->dbuf), store_ctx->flag);
207         if (!NT_STATUS_IS_OK(status)) {
208                 DEBUG(5, ("store returned %s\n", nt_errstr(status)));
209         }
210
211         TALLOC_FREE(rec);
212         return status;
213 }
214
215 NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
216                             int flag)
217 {
218         NTSTATUS status;
219         struct dbwrap_store_context store_ctx;
220
221         store_ctx.key = &key;
222         store_ctx.dbuf = &dbuf;
223         store_ctx.flag = flag;
224
225         status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx);
226
227         return status;
228 }
229
230 static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
231 {
232         NTSTATUS status;
233         struct db_record *rec;
234         TDB_DATA *key = (TDB_DATA *)private_data;
235
236         rec = db->fetch_locked(db, talloc_tos(), *key);
237         if (rec == NULL) {
238                 DEBUG(5, ("fetch_locked failed\n"));
239                 return NT_STATUS_NO_MEMORY;
240         }
241
242         status = rec->delete_rec(rec);
243         if (!NT_STATUS_IS_OK(status)) {
244                 DEBUG(5, ("delete_rec returned %s\n", nt_errstr(status)));
245         }
246
247         talloc_free(rec);
248         return  status;
249 }
250
251 NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
252 {
253         NTSTATUS status;
254
255         status = dbwrap_trans_do(db, dbwrap_delete_action, &key);
256
257         return status;
258 }
259
260 NTSTATUS dbwrap_trans_store_int32(struct db_context *db, const char *keystr,
261                                   int32_t v)
262 {
263         int32 v_store;
264
265         SIVAL(&v_store, 0, v);
266
267         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
268                                   make_tdb_data((const uint8 *)&v_store,
269                                                 sizeof(v_store)),
270                                   TDB_REPLACE);
271 }
272
273 NTSTATUS dbwrap_trans_store_uint32(struct db_context *db, const char *keystr,
274                                    uint32_t v)
275 {
276         uint32 v_store;
277
278         SIVAL(&v_store, 0, v);
279
280         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
281                                   make_tdb_data((const uint8 *)&v_store,
282                                                 sizeof(v_store)),
283                                   TDB_REPLACE);
284 }
285
286 NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
287                                      TDB_DATA data, int flags)
288 {
289         return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
290 }
291
292 NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
293 {
294         return dbwrap_trans_delete(db, string_term_tdb_data(key));
295 }
296
297 /**
298  * Wrap db action(s) into a transaction.
299  */
300 NTSTATUS dbwrap_trans_do(struct db_context *db,
301                          NTSTATUS (*action)(struct db_context *, void *),
302                          void *private_data)
303 {
304         int res;
305         NTSTATUS status;
306
307         res = db->transaction_start(db);
308         if (res != 0) {
309                 DEBUG(5, ("transaction_start failed\n"));
310                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
311         }
312
313         status = action(db, private_data);
314         if (!NT_STATUS_IS_OK(status)) {
315                 if (db->transaction_cancel(db) != 0) {
316                         smb_panic("Cancelling transaction failed");
317                 }
318                 return status;
319         }
320
321         res = db->transaction_commit(db);
322         if (res == 0) {
323                 return NT_STATUS_OK;
324         }
325
326         DEBUG(2, ("transaction_commit failed\n"));
327         return NT_STATUS_INTERNAL_DB_CORRUPTION;
328 }
329
330 NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
331 {
332         char *key_upper;
333         NTSTATUS status;
334
335         key_upper = talloc_strdup_upper(talloc_tos(), key);
336         if (key_upper == NULL) {
337                 return NT_STATUS_NO_MEMORY;
338         }
339
340         status = dbwrap_delete_bystring(db, key_upper);
341
342         talloc_free(key_upper);
343         return status;
344 }
345
346 NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
347                                      TDB_DATA data, int flags)
348 {
349         char *key_upper;
350         NTSTATUS status;
351
352         key_upper = talloc_strdup_upper(talloc_tos(), key);
353         if (key_upper == NULL) {
354                 return NT_STATUS_NO_MEMORY;
355         }
356
357         status = dbwrap_store_bystring(db, key_upper, data, flags);
358
359         talloc_free(key_upper);
360         return status;
361 }
362
363 TDB_DATA dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
364                                      const char *key)
365 {
366         char *key_upper;
367         TDB_DATA result;
368
369         key_upper = talloc_strdup_upper(talloc_tos(), key);
370         if (key_upper == NULL) {
371                 return make_tdb_data(NULL, 0);
372         }
373
374         result = dbwrap_fetch_bystring(db, mem_ctx, key_upper);
375
376         talloc_free(key_upper);
377         return result;
378 }