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