]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/id2entry.c
Patches for modify/modrdn to work with BDB_USE_BINARY_RW.
[openldap] / servers / slapd / back-bdb / id2entry.c
1 /* id2entry.c - routines to deal with the id2entry database */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #include <ac/string.h>
12
13 #include "back-bdb.h"
14
15 #ifdef BDB_USE_BINARY_RW
16
17 /* A cache of every AttributeDescription we ever see. We don't want
18  * to churn thru malloc/free on them all the time since most will be
19  * encountered repeatedly.
20  */
21 static Avlnode *adcache;
22
23 static int
24 ad_type_cmp(
25         char *desc,
26         AttributeDescription *ad
27 )
28 {
29         return strcasecmp(desc, ad->ad_cname->bv_val);
30 }
31
32 static int
33 ad_info_cmp(
34         AttributeDescription *a1,
35         AttributeDescription *a2
36 )
37 {
38         return strcasecmp(a1->ad_cname->bv_val, a2->ad_cname->bv_val);
39 }
40
41 AttributeDescription *
42 bdb_str2ad(const char *desc)
43 {
44         AttributeDescription *a;
45
46         a = (AttributeDescription *) avl_find(adcache, desc,
47                 (AVL_CMP) ad_type_cmp);
48         if (!a) {
49                 int rc;
50                 const char *text;
51
52                 rc = slap_str2ad(desc, &a, &text);
53                 if (rc != LDAP_SUCCESS) {
54                         return NULL;
55                 }
56                 rc = avl_insert(&adcache, (caddr_t)a, (AVL_CMP) ad_info_cmp,
57                         (AVL_DUP) avl_dup_error);
58         }
59         return a;
60 }
61
62 /* Flatten an Entry into a buffer. The buffer contents become a direct
63  * copy of the entry, with all pointers converted to offsets from the
64  * beginning of the buffer. We do this by first walking through all
65  * the fields of the Entry, adding up their sizes. Then a single chunk
66  * of memory is malloc'd and the entry is copied. We differentiate between
67  * fixed size fields and variable-length content when tallying up the
68  * entry size, so that we can stick all of the variable-length stuff
69  * into the back half of the buffer.
70  */
71 int bdb_encode(Entry *e, struct berval **bv)
72 {
73         int siz = sizeof(Entry);
74         int len, dnlen;
75         int i, j;
76         Entry *f;
77         Attribute *a, *b;
78         struct berval **bvl, *bz;
79         char *ptr, *base, *data;
80
81         *bv = ch_malloc(sizeof(struct berval));
82         /* Compress any white space in the DN */
83         dn_validate(e->e_dn);
84         dnlen = strlen(e->e_dn);
85         /* The dn and ndn are always the same length */
86         len = dnlen + dnlen + 2;        /* two trailing NUL bytes */
87         for (a=e->e_attrs; a; a=a->a_next) {
88                 /* For AttributeDesc, we only store the attr name */
89                 siz += sizeof(Attribute);
90                 len += a->a_desc->ad_cname->bv_len+1;
91                 for (i=0; a->a_vals[i]; i++) {
92                         siz += sizeof(struct berval *);
93                         siz += sizeof(struct berval);
94                         len += a->a_vals[i]->bv_len + 1;
95                 }
96                 siz += sizeof(struct berval *); /* NULL pointer at end */
97         }
98         (*bv)->bv_len = siz + len;
99         (*bv)->bv_val = ch_malloc(siz+len);
100         base = (*bv)->bv_val;
101         ptr = base + siz;
102         f = (Entry *)base;
103         data = (char *)(f+1);
104         f->e_id = e->e_id;
105         f->e_dn = (char *)(ptr-base);
106         memcpy(ptr, e->e_dn, dnlen);
107         ptr += dnlen;
108         *ptr++ = '\0';
109         f->e_ndn = (char *)(ptr-base);
110         memcpy(ptr, e->e_ndn, dnlen);
111         ptr += dnlen;
112         *ptr++ = '\0';
113         f->e_attrs = e->e_attrs ? (Attribute *)sizeof(Entry) : NULL;
114         f->e_private = NULL;
115         for (a=e->e_attrs; a; a=a->a_next) {
116                 b = (Attribute *)data;
117                 data = (char *)(b+1);
118                 b->a_desc = (AttributeDescription *)(ptr-base);
119                 memcpy(ptr, a->a_desc->ad_cname->bv_val,
120                         a->a_desc->ad_cname->bv_len);
121                 ptr += a->a_desc->ad_cname->bv_len;
122                 *ptr++ = '\0';
123                 if (a->a_vals) {
124                     bvl = (struct berval **)data;
125                     b->a_vals = (struct berval **)(data-base);
126                     for (i=0; a->a_vals[i]; i++);
127                     data = (char *)(bvl+i+1);
128                     bz = (struct berval *)data;
129                     for (j=0; j<i; j++) {
130                             bz->bv_len = a->a_vals[j]->bv_len;
131                             if (a->a_vals[j]->bv_val) {
132                                 bz->bv_val = (char *)(ptr-base);
133                                 memcpy(ptr, a->a_vals[j]->bv_val, bz->bv_len);
134                             } else {
135                                 bz->bv_val = NULL;
136                             }
137                             ptr += bz->bv_len;
138                             *ptr++ = '\0';
139                             bvl[j] = (struct berval *)(data-base);
140                             bz++;
141                             data = (char *)bz;
142                     }
143                     bvl[j] = NULL;
144                 } else {
145                     b->a_vals = NULL;
146                 }
147
148                 if (a->a_next)
149                     b->a_next = (Attribute *)(data-base);
150                 else
151                     b->a_next = NULL;
152         }
153         return 0;
154 }
155
156 /* Retrieve an Entry that was stored using bdb_encode above.
157  * All we have to do is add the buffer address to all of the
158  * stored offsets. We also use the stored attribute names to
159  * pull AttributeDescriptions from our ad_cache. To detect if
160  * the attributes of an Entry are later modified, we also store
161  * the address of the end of this block in e_private. Since
162  * modify_internal always allocs a new list of attrs to work
163  * with, we need to free that separately.
164  */
165 int bdb_decode(struct berval *bv, Entry **e)
166 {
167         int i;
168         long base;
169         Attribute *a;
170         Entry *x = (Entry *)bv->bv_val;
171
172         base = (long)bv->bv_val;
173         x->e_dn += base;
174         x->e_ndn += base;
175         x->e_private = bv->bv_val + bv->bv_len;
176         if (x->e_attrs)
177                 x->e_attrs = (Attribute *)((long)x->e_attrs+base);
178         for (a=x->e_attrs; a; a=a->a_next) {
179                 if (a->a_next)
180                         a->a_next = (Attribute *)((long)a->a_next+base);
181                 a->a_desc=bdb_str2ad((char *)a->a_desc+base);
182                 if (!a->a_desc) return -1;
183                 if (a->a_vals) {
184                         a->a_vals = (struct berval **)((long)a->a_vals+base);
185                         for (i=0; a->a_vals[i]; i++) {
186                                 a->a_vals[i] = (struct berval *)
187                                         ((long)a->a_vals[i]+base);
188                                 if (a->a_vals[i]->bv_val)
189                                     a->a_vals[i]->bv_val += base;
190                         }
191                 }
192         }
193         *e = x;
194         return 0;
195 }
196
197 #define entry_encode(a, b)      bdb_encode(a,b)
198 #define entry_decode(a, b)      bdb_decode(a,b)
199
200 #endif  /* BDB_USE_BINARY_RW */
201
202 int bdb_id2entry_add(
203         BackendDB *be,
204         DB_TXN *tid,
205         Entry *e )
206 {
207         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
208         DB *db = bdb->bi_id2entry->bdi_db;
209         DBT key, data;
210         struct berval *bv;
211         int rc;
212
213         DBTzero( &key );
214         key.data = (char *) &e->e_id;
215         key.size = sizeof(ID);
216
217         rc = entry_encode( e, &bv );
218         if( rc != LDAP_SUCCESS ) {
219                 return -1;
220         }
221
222         DBTzero( &data );
223         bv2DBT( bv, &data );
224
225         rc = db->put( db, tid, &key, &data, DB_NOOVERWRITE );
226
227         ber_bvfree( bv );
228         return rc;
229 }
230
231 int bdb_id2entry_update(
232         BackendDB *be,
233         DB_TXN *tid,
234         Entry *e )
235 {
236         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
237         DB *db = bdb->bi_id2entry->bdi_db;
238         DBT key, data;
239         struct berval *bv;
240         int rc;
241
242         DBTzero( &key );
243         key.data = (char *) &e->e_id;
244         key.size = sizeof(ID);
245
246         rc = entry_encode( e, &bv );
247         if( rc != LDAP_SUCCESS ) {
248                 return -1;
249         }
250
251         DBTzero( &data );
252         bv2DBT( bv, &data );
253
254         rc = db->put( db, tid, &key, &data, 0 );
255
256         ber_bvfree( bv );
257         return rc;
258 }
259
260 int bdb_id2entry(
261         BackendDB *be,
262         DB_TXN *tid,
263         ID id,
264         Entry **e )
265 {
266         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
267         DB *db = bdb->bi_id2entry->bdi_db;
268         DBT key, data;
269         struct berval bv;
270         int rc;
271
272         *e = NULL;
273
274         DBTzero( &key );
275         key.data = (char *) &id;
276         key.size = sizeof(ID);
277
278         DBTzero( &data );
279         data.flags = DB_DBT_MALLOC;
280
281         /* fetch it */
282         rc = db->get( db, tid, &key, &data, 0 );
283
284         if( rc != 0 ) {
285                 return rc;
286         }
287
288         DBT2bv( &data, &bv );
289
290         rc = entry_decode( &bv, e );
291
292         if( rc == 0 ) {
293                 (*e)->e_id = id;
294         }
295
296 #ifndef BDB_USE_BINARY_RW
297         ch_free( data.data );
298 #endif
299         return rc;
300 }
301
302 int bdb_id2entry_delete(
303         BackendDB *be,
304         DB_TXN *tid,
305         ID id )
306 {
307         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
308         DB *db = bdb->bi_id2entry->bdi_db;
309         DBT key;
310         struct berval *bv;
311         int rc;
312
313         DBTzero( &key );
314         key.data = (char *) &id;
315         key.size = sizeof(ID);
316
317         rc = db->del( db, tid, &key, 0 );
318
319         ber_bvfree( bv );
320         return rc;
321 }
322
323 int bdb_entry_return(
324         BackendDB *be,
325         Entry *e )
326 {
327 #ifdef BDB_USE_BINARY_RW
328         /* bdb_modify_internal always operates on a dup'd set of attrs. */
329         if ((void *)e->e_attrs < (void *)e  ||
330                 (void *)e->e_attrs > e->e_private)
331             attrs_free(e->e_attrs);
332         ch_free(e);
333 #else
334         entry_free( e );
335 #endif
336         return 0;
337 }