merge from 2.2
[samba.git] / source / tdb / tdbutil.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    tdb utility functions
5    Copyright (C) Andrew Tridgell 1992-1998
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 /* these are little tdb utility functions that are meant to make
25    dealing with a tdb database a little less cumbersome in Samba */
26
27 /* lock a chain by string */
28 int tdb_lock_bystring(TDB_CONTEXT *tdb, char *keyval)
29 {
30         TDB_DATA key;
31
32         key.dptr = keyval;
33         key.dsize = strlen(keyval)+1;
34         
35         return tdb_chainlock(tdb, key);
36 }
37
38 /* unlock a chain by string */
39 void tdb_unlock_bystring(TDB_CONTEXT *tdb, char *keyval)
40 {
41         TDB_DATA key;
42
43         key.dptr = keyval;
44         key.dsize = strlen(keyval)+1;
45         
46         tdb_chainunlock(tdb, key);
47 }
48
49 /* lock a chain by string key */
50
51
52 /* fetch a value by a arbitrary blob key, return -1 if not found */
53 int tdb_fetch_int_byblob(TDB_CONTEXT *tdb, char *keyval, size_t len)
54 {
55         TDB_DATA key, data;
56         int ret;
57
58         key.dptr = keyval;
59         key.dsize = len;
60         data = tdb_fetch(tdb, key);
61         if (!data.dptr || data.dsize != sizeof(int)) return -1;
62         
63         memcpy(&ret, data.dptr, sizeof(int));
64         free(data.dptr);
65         return ret;
66 }
67
68 /* fetch a value by string key, return -1 if not found */
69 int tdb_fetch_int(TDB_CONTEXT *tdb, char *keystr)
70 {
71         return tdb_fetch_int_byblob(tdb, keystr, strlen(keystr) + 1);
72 }
73
74 /* store a value by an arbitary blob key, return 0 on success, -1 on failure */
75 int tdb_store_int_byblob(TDB_CONTEXT *tdb, char *keystr, size_t len, int v)
76 {
77         TDB_DATA key, data;
78
79         key.dptr = keystr;
80         key.dsize = len;
81         data.dptr = (void *)&v;
82         data.dsize = sizeof(int);
83
84         return tdb_store(tdb, key, data, TDB_REPLACE);
85 }
86
87 /* store a value by string key, return 0 on success, -1 on failure */
88 int tdb_store_int(TDB_CONTEXT *tdb, char *keystr, int v)
89 {
90         return tdb_store_int_byblob(tdb, keystr, strlen(keystr) + 1, v);
91 }
92
93 /* Store a buffer by a null terminated string key.  Return 0 on success, -1
94    on failure */
95 int tdb_store_by_string(TDB_CONTEXT *tdb, char *keystr, void *buffer, int len)
96 {
97     TDB_DATA key, data;
98
99     key.dptr = keystr;
100     key.dsize = strlen(keystr) + 1;
101
102     data.dptr = buffer;
103     data.dsize = len;
104
105     return tdb_store(tdb, key, data, TDB_REPLACE);
106 }
107
108 /* Fetch a buffer using a null terminated string key.  Don't forget to call
109    free() on the result dptr. */
110 TDB_DATA tdb_fetch_by_string(TDB_CONTEXT *tdb, char *keystr)
111 {
112     TDB_DATA key;
113
114     key.dptr = keystr;
115     key.dsize = strlen(keystr) + 1;
116
117     return tdb_fetch(tdb, key);
118 }
119
120
121 /* useful pair of routines for packing/unpacking data consisting of
122    integers and strings */
123 size_t tdb_pack(char *buf, int bufsize, char *fmt, ...)
124 {
125         va_list ap;
126         uint16 w;
127         uint32 d;
128         int i;
129         void *p;
130         int len=0;
131         char *s;
132         char c;
133         char *buf0 = buf;
134         char *fmt0 = fmt;
135         int bufsize0 = bufsize;
136
137         va_start(ap, fmt);
138
139         while (*fmt) {
140                 switch ((c = *fmt++)) {
141                 case 'w':
142                         len = 2;
143                         w = (uint16)va_arg(ap, int);
144                         if (bufsize >= len) {
145                                 SSVAL(buf, 0, w);
146                         }
147                         break;
148                 case 'd':
149                         len = 4;
150                         d = va_arg(ap, uint32);
151                         if (bufsize >= len) {
152                                 SIVAL(buf, 0, d);
153                         }
154                         break;
155                 case 'p':
156                         len = 4;
157                         p = va_arg(ap, void *);
158                         d = p?1:0;
159                         if (bufsize >= len) {
160                                 SIVAL(buf, 0, d);
161                         }
162                         break;
163                 case 'P':
164                         s = va_arg(ap,char *);
165                         w = strlen(s);
166                         len = w + 1;
167                         if (bufsize >= len) {
168                                 memcpy(buf, s, len);
169                         }
170                         break;
171                 case 'f':
172                         s = va_arg(ap,char *);
173                         w = strlen(s);
174                         len = w + 1;
175                         if (bufsize >= len) {
176                                 memcpy(buf, s, len);
177                         }
178                         break;
179                 case 'B':
180                         i = va_arg(ap, int);
181                         s = va_arg(ap, char *);
182                         len = 4+i;
183                         if (bufsize >= len) {
184                                 SIVAL(buf, 0, i);
185                                 memcpy(buf+4, s, i);
186                         }
187                         break;
188                 default:
189                         DEBUG(0,("Unknown tdb_pack format %c in %s\n", 
190                                  c, fmt));
191                         break;
192                 }
193
194                 buf += len;
195                 bufsize -= len;
196         }
197
198         va_end(ap);
199
200         DEBUG(8,("tdb_pack(%s, %d) -> %d\n", 
201                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
202         
203         return PTR_DIFF(buf, buf0);
204 }
205
206
207
208 /* useful pair of routines for packing/unpacking data consisting of
209    integers and strings */
210
211 int tdb_unpack(char *buf, int bufsize, char *fmt, ...)
212 {
213         va_list ap;
214         uint16 *w;
215         uint32 *d;
216         int len=0;
217         int *i;
218         void **p;
219         char *s, **b;
220         char c;
221         char *buf0 = buf;
222         char *fmt0 = fmt;
223         int bufsize0 = bufsize;
224
225         va_start(ap, fmt);
226         
227         while (*fmt) {
228                 switch ((c=*fmt++)) {
229                 case 'w':
230                         len = 2;
231                         w = va_arg(ap, uint16 *);
232                         if (bufsize < len) goto no_space;
233                         *w = SVAL(buf, 0);
234                         break;
235                 case 'd':
236                         len = 4;
237                         d = va_arg(ap, uint32 *);
238                         if (bufsize < len) goto no_space;
239                         *d = IVAL(buf, 0);
240                         break;
241                 case 'p':
242                         len = 4;
243                         p = va_arg(ap, void **);
244                         if (bufsize < len) goto no_space;
245                         *p = (void *)IVAL(buf, 0);
246                         break;
247                 case 'P':
248                         s = va_arg(ap,char *);
249                         len = strlen(buf) + 1;
250                         if (bufsize < len || len > sizeof(pstring)) goto no_space;
251                         memcpy(s, buf, len);
252                         break;
253                 case 'f':
254                         s = va_arg(ap,char *);
255                         len = strlen(buf) + 1;
256                         if (bufsize < len || len > sizeof(fstring)) goto no_space;
257                         memcpy(s, buf, len);
258                         break;
259                 case 'B':
260                         i = va_arg(ap, int *);
261                         b = va_arg(ap, char **);
262                         len = 4;
263                         if (bufsize < len) goto no_space;
264                         *i = IVAL(buf, 0);
265                         if (! *i) break;
266                         len += *i;
267                         if (bufsize < len) goto no_space;
268                         *b = (char *)malloc(*i);
269                         if (! *b) goto no_space;
270                         memcpy(*b, buf+4, *i);
271                         break;
272                 default:
273                         DEBUG(0,("Unknown tdb_unpack format %c in %s\n", 
274                                  c, fmt));
275                         break;
276                 }
277
278                 buf += len;
279                 bufsize -= len;
280         }
281
282         va_end(ap);
283
284         DEBUG(8,("tdb_unpack(%s, %d) -> %d\n", 
285                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
286
287         return PTR_DIFF(buf, buf0);
288
289  no_space:
290         return -1;
291 }