]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/tools.c
Import ITS#3267 fix from HEAD
[openldap] / servers / slapd / back-bdb / tools.c
1 /* tools.c - tools for slap tools */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2005 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #include <ac/string.h>
21
22 #include "back-bdb.h"
23 #include "external.h"
24
25 static DBC *cursor = NULL;
26 static DBT key, data;
27
28 typedef struct dn_id {
29         ID id;
30         struct berval dn;
31 } dn_id;
32
33 #define HOLE_SIZE       4096
34 static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
35 static unsigned nhmax = HOLE_SIZE;
36 static unsigned nholes;
37
38 int bdb_tool_entry_open(
39         BackendDB *be, int mode )
40 {
41         /* initialize key and data thangs */
42         DBTzero( &key );
43         DBTzero( &data );
44         key.flags = DB_DBT_REALLOC;
45         data.flags = DB_DBT_REALLOC;
46
47         return 0;
48 }
49
50 int bdb_tool_entry_close(
51         BackendDB *be )
52 {
53         assert( be != NULL );
54
55         if( key.data ) {
56                 ch_free( key.data );
57                 key.data = NULL;
58         }
59         if( data.data ) {
60                 ch_free( data.data );
61                 data.data = NULL;
62         }
63
64         if( cursor ) {
65                 cursor->c_close( cursor );
66                 cursor = NULL;
67         }
68
69         if( nholes ) {
70                 unsigned i;
71                 fprintf( stderr, "Error, entries missing!\n");
72                 for (i=0; i<nholes; i++) {
73                         fprintf(stderr, "  entry %ld: %s\n",
74                                 holes[i].id, holes[i].dn.bv_val);
75                 }
76                 return -1;
77         }
78                         
79         return 0;
80 }
81
82 ID bdb_tool_entry_next(
83         BackendDB *be )
84 {
85         int rc;
86         ID id;
87         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
88
89         assert( be != NULL );
90         assert( slapMode & SLAP_TOOL_MODE );
91         assert( bdb != NULL );
92         
93         if (cursor == NULL) {
94                 rc = bdb->bi_id2entry->bdi_db->cursor(
95                         bdb->bi_id2entry->bdi_db, NULL, &cursor,
96                         bdb->bi_db_opflags );
97                 if( rc != 0 ) {
98                         return NOID;
99                 }
100         }
101
102         rc = cursor->c_get( cursor, &key, &data, DB_NEXT );
103
104         if( rc != 0 ) {
105                 return NOID;
106         }
107
108         if( data.data == NULL ) {
109                 return NOID;
110         }
111
112         AC_MEMCPY( &id, key.data, key.size );
113         return id;
114 }
115
116 ID bdb_tool_dn2id_get(
117         Backend *be,
118         struct berval *dn
119 )
120 {
121         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
122         DB *db = bdb->bi_dn2id->bdi_db;
123         int rc;
124         DBT     key, data;
125         ID      id;
126
127         DBTzero( &key );
128         key.size = dn->bv_len + 2;
129         key.data = ch_malloc( key.size );
130         ((char*)key.data)[0] = DN_BASE_PREFIX;
131         AC_MEMCPY( &((char*)key.data)[1], dn->bv_val, key.size - 1 );
132
133         DBTzero( &data );
134         data.data = &id;
135         data.ulen = sizeof(ID);
136         data.flags = DB_DBT_USERMEM;
137
138         rc = db->get( db, NULL, &key, &data, bdb->bi_db_opflags );
139
140     if( rc != 0 ) {
141                 Debug( LDAP_DEBUG_TRACE, LDAP_XSTRING(bdb_tool_dn2id_get)
142                                 ": get failed: %s (%d)\n",
143                                 db_strerror( rc ), rc, 0 );
144                 id = NOID;
145         }
146
147         ch_free( key.data );
148         return id;
149 }
150
151 int bdb_tool_id2entry_get(
152         Backend *be,
153         ID id,
154         Entry **e
155 )
156 {
157         return bdb_id2entry( be, NULL, id, e );
158 }
159
160 Entry* bdb_tool_entry_get( BackendDB *be, ID id )
161 {
162         int rc;
163         Entry *e = NULL;
164         struct berval bv;
165
166         assert( be != NULL );
167         assert( slapMode & SLAP_TOOL_MODE );
168         assert( data.data != NULL );
169
170 #ifndef BDB_HIER
171         DBT2bv( &data, &bv );
172
173         rc = entry_decode( &bv, &e );
174
175         if( rc == LDAP_SUCCESS ) {
176                 e->e_id = id;
177         }
178 #else
179         {
180                 EntryInfo *ei = NULL;
181                 Operation op = {0};
182
183                 op.o_bd = be;
184                 op.o_tmpmemctx = NULL;
185                 op.o_tmpmfuncs = &ch_mfuncs;
186
187                 rc = bdb_cache_find_id( &op, NULL, id, &ei, 0, 0, NULL );
188                 if ( rc == LDAP_SUCCESS )
189                         e = ei->bei_e;
190         }
191 #endif
192         return e;
193 }
194
195 static int bdb_tool_next_id(
196         Operation *op,
197         DB_TXN *tid,
198         Entry *e,
199         struct berval *text,
200         int hole )
201 {
202         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
203         struct berval dn = e->e_name;
204         struct berval ndn = e->e_nname;
205         struct berval pdn, npdn;
206         EntryInfo *ei = NULL, eidummy;
207         int rc;
208
209         if (ndn.bv_len == 0) return 0;
210
211         rc = bdb_cache_find_ndn( op, tid, &ndn, &ei );
212         if ( ei ) bdb_cache_entryinfo_unlock( ei );
213         if ( rc == DB_NOTFOUND ) {
214                 if ( !be_issuffix( op->o_bd, &ndn ) ) {
215                         ID eid = e->e_id;
216                         dnParent( &dn, &pdn );
217                         dnParent( &ndn, &npdn );
218                         e->e_name = pdn;
219                         e->e_nname = npdn;
220                         rc = bdb_tool_next_id( op, tid, e, text, 1 );
221                         e->e_name = dn;
222                         e->e_nname = ndn;
223                         if ( rc ) {
224                                 return rc;
225                         }
226                         /* If parent didn't exist, it was created just now
227                          * and its ID is now in e->e_id. Make sure the current
228                          * entry gets added under the new parent ID.
229                          */
230                         if ( eid != e->e_id ) {
231                                 eidummy.bei_id = e->e_id;
232                                 ei = &eidummy;
233                         }
234                 }
235                 rc = bdb_next_id( op->o_bd, tid, &e->e_id );
236                 if ( rc ) {
237                         snprintf( text->bv_val, text->bv_len,
238                                 "next_id failed: %s (%d)",
239                                 db_strerror(rc), rc );
240                 Debug( LDAP_DEBUG_ANY,
241                         "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
242                         return rc;
243                 }
244                 rc = bdb_dn2id_add( op, tid, ei, e );
245                 if ( rc ) {
246                         snprintf( text->bv_val, text->bv_len, 
247                                 "dn2id_add failed: %s (%d)",
248                                 db_strerror(rc), rc );
249                 Debug( LDAP_DEBUG_ANY,
250                         "=> bdb_tool_next_id: %s\n", text->bv_val, 0, 0 );
251                 } else if ( hole ) {
252                         if ( nholes == nhmax - 1 ) {
253                                 if ( holes == hbuf ) {
254                                         holes = ch_malloc( nhmax * sizeof(dn_id) * 2 );
255                                         AC_MEMCPY( holes, hbuf, sizeof(hbuf) );
256                                 } else {
257                                         holes = ch_realloc( holes, nhmax * sizeof(dn_id) * 2 );
258                                 }
259                                 nhmax *= 2;
260                         }
261                         ber_dupbv( &holes[nholes].dn, &ndn );
262                         holes[nholes++].id = e->e_id;
263                 }
264         } else if ( !hole ) {
265                 unsigned i;
266
267                 e->e_id = ei->bei_id;
268
269                 for ( i=0; i<nholes; i++) {
270                         if ( holes[i].id == e->e_id ) {
271                                 int j;
272                                 free(holes[i].dn.bv_val);
273                                 for (j=i;j<nholes;j++) holes[j] = holes[j+1];
274                                 holes[j].id = 0;
275                                 nholes--;
276                                 break;
277                         } else if ( holes[i].id > e->e_id ) {
278                                 break;
279                         }
280                 }
281         }
282         return rc;
283 }
284
285 ID bdb_tool_entry_put(
286         BackendDB *be,
287         Entry *e,
288         struct berval *text )
289 {
290         int rc;
291         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
292         DB_TXN *tid = NULL;
293         Operation op = {0};
294
295         assert( be != NULL );
296         assert( slapMode & SLAP_TOOL_MODE );
297
298         assert( text );
299         assert( text->bv_val );
300         assert( text->bv_val[0] == '\0' );      /* overconservative? */
301
302         Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(bdb_tool_entry_put)
303                 "( %ld, \"%s\" )\n", (long) e->e_id, e->e_dn, 0 );
304
305         rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid, 
306                 bdb->bi_db_opflags );
307         if( rc != 0 ) {
308                 snprintf( text->bv_val, text->bv_len,
309                         "txn_begin failed: %s (%d)",
310                         db_strerror(rc), rc );
311                 Debug( LDAP_DEBUG_ANY,
312                         "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
313                          text->bv_val, 0, 0 );
314                 return NOID;
315         }
316
317         op.o_bd = be;
318         op.o_tmpmemctx = NULL;
319         op.o_tmpmfuncs = &ch_mfuncs;
320
321         /* add dn2id indices */
322         rc = bdb_tool_next_id( &op, tid, e, text, 0 );
323         if( rc != 0 ) {
324                 goto done;
325         }
326
327         /* id2entry index */
328         rc = bdb_id2entry_add( be, tid, e );
329         if( rc != 0 ) {
330                 snprintf( text->bv_val, text->bv_len,
331                                 "id2entry_add failed: %s (%d)",
332                                 db_strerror(rc), rc );
333                 Debug( LDAP_DEBUG_ANY,
334                         "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
335                         text->bv_val, 0, 0 );
336                 goto done;
337         }
338
339         rc = bdb_index_entry_add( &op, tid, e );
340         if( rc != 0 ) {
341                 snprintf( text->bv_val, text->bv_len,
342                                 "index_entry_add failed: %s (%d)",
343                                 db_strerror(rc), rc );
344                 Debug( LDAP_DEBUG_ANY,
345                         "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
346                         text->bv_val, 0, 0 );
347                 goto done;
348         }
349
350 done:
351         if( rc == 0 ) {
352                 rc = TXN_COMMIT( tid, 0 );
353                 if( rc != 0 ) {
354                         snprintf( text->bv_val, text->bv_len,
355                                         "txn_commit failed: %s (%d)",
356                                         db_strerror(rc), rc );
357                         Debug( LDAP_DEBUG_ANY,
358                                 "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
359                                 text->bv_val, 0, 0 );
360                         e->e_id = NOID;
361                 }
362
363         } else {
364                 TXN_ABORT( tid );
365                 snprintf( text->bv_val, text->bv_len,
366                         "txn_aborted! %s (%d)",
367                         db_strerror(rc), rc );
368                 Debug( LDAP_DEBUG_ANY,
369                         "=> " LDAP_XSTRING(bdb_tool_entry_put) ": %s\n",
370                         text->bv_val, 0, 0 );
371                 e->e_id = NOID;
372         }
373
374         return e->e_id;
375 }
376
377 int bdb_tool_entry_reindex(
378         BackendDB *be,
379         ID id )
380 {
381         struct bdb_info *bi = (struct bdb_info *) be->be_private;
382         int rc;
383         Entry *e;
384         DB_TXN *tid = NULL;
385         Operation op = {0};
386
387         Debug( LDAP_DEBUG_ARGS,
388                 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld )\n",
389                 (long) id, 0, 0 );
390
391         e = bdb_tool_entry_get( be, id );
392
393         if( e == NULL ) {
394                 Debug( LDAP_DEBUG_ANY,
395                         LDAP_XSTRING(bdb_tool_entry_reindex)
396                         ": could not locate id=%ld\n",
397                         (long) id, 0, 0 );
398                 return -1;
399         }
400
401         rc = TXN_BEGIN( bi->bi_dbenv, NULL, &tid, bi->bi_db_opflags );
402         if( rc != 0 ) {
403                 Debug( LDAP_DEBUG_ANY,
404                         "=> " LDAP_XSTRING(bdb_tool_entry_reindex) ": "
405                         "txn_begin failed: %s (%d)\n",
406                         db_strerror(rc), rc, 0 );
407                 goto done;
408         }
409         
410         /*
411          * just (re)add them for now
412          * assume that some other routine (not yet implemented)
413          * will zap index databases
414          *
415          */
416
417         Debug( LDAP_DEBUG_TRACE,
418                 "=> " LDAP_XSTRING(bdb_tool_entry_reindex) "( %ld, \"%s\" )\n",
419                 (long) id, e->e_dn, 0 );
420
421         op.o_bd = be;
422         op.o_tmpmemctx = NULL;
423         op.o_tmpmfuncs = &ch_mfuncs;
424
425 #ifndef BDB_HIER
426         /* add dn2id indices */
427         rc = bdb_dn2id_add( &op, tid, NULL, e );
428         if( rc != 0 && rc != DB_KEYEXIST ) {
429                 Debug( LDAP_DEBUG_ANY,
430                         "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
431                         ": dn2id_add failed: %s (%d)\n",
432                         db_strerror(rc), rc, 0 );
433                 goto done;
434         }
435 #endif
436
437         rc = bdb_index_entry_add( &op, tid, e );
438
439 done:
440         if( rc == 0 ) {
441                 rc = TXN_COMMIT( tid, 0 );
442                 if( rc != 0 ) {
443                         Debug( LDAP_DEBUG_ANY,
444                                 "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
445                                 ": txn_commit failed: %s (%d)\n",
446                                 db_strerror(rc), rc, 0 );
447                         e->e_id = NOID;
448                 }
449
450         } else {
451                 TXN_ABORT( tid );
452                 Debug( LDAP_DEBUG_ANY,
453                         "=> " LDAP_XSTRING(bdb_tool_entry_reindex)
454                         ": txn_aborted! %s (%d)\n",
455                         db_strerror(rc), rc, 0 );
456                 e->e_id = NOID;
457         }
458         bdb_entry_release( &op, e, 0 );
459
460         return rc;
461 }
462
463 ID bdb_tool_entry_modify(
464         BackendDB *be,
465         Entry *e,
466         struct berval *text )
467 {
468         int rc;
469         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
470         DB_TXN *tid = NULL;
471         Operation op = {0};
472
473         assert( be != NULL );
474         assert( slapMode & SLAP_TOOL_MODE );
475
476         assert( text );
477         assert( text->bv_val );
478         assert( text->bv_val[0] == '\0' );      /* overconservative? */
479
480         assert ( e->e_id != NOID );
481         assert ( e->e_id != 0 );
482
483         Debug( LDAP_DEBUG_TRACE,
484                 "=> " LDAP_XSTRING(bdb_tool_entry_modify) "( %ld, \"%s\" )\n",
485                 (long) e->e_id, e->e_dn, 0 );
486
487         rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &tid, 
488                 bdb->bi_db_opflags );
489         if( rc != 0 ) {
490                 snprintf( text->bv_val, text->bv_len,
491                         "txn_begin failed: %s (%d)",
492                         db_strerror(rc), rc );
493                 Debug( LDAP_DEBUG_ANY,
494                         "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
495                          text->bv_val, 0, 0 );
496                 return NOID;
497         }
498
499         op.o_bd = be;
500         op.o_tmpmemctx = NULL;
501         op.o_tmpmfuncs = &ch_mfuncs;
502
503         /* id2entry index */
504         rc = bdb_id2entry_update( be, tid, e );
505         if( rc != 0 ) {
506                 snprintf( text->bv_val, text->bv_len,
507                                 "id2entry_add failed: %s (%d)",
508                                 db_strerror(rc), rc );
509                 Debug( LDAP_DEBUG_ANY,
510                         "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
511                         text->bv_val, 0, 0 );
512                 goto done;
513         }
514
515         rc = bdb_index_entry_del( &op, tid, e );
516         if( rc != 0 ) {
517                 snprintf( text->bv_val, text->bv_len,
518                                 "index_entry_del failed: %s (%d)",
519                                 db_strerror(rc), rc );
520                 Debug( LDAP_DEBUG_ANY,
521                         "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
522                         text->bv_val, 0, 0 );
523                 goto done;
524         }
525
526         rc = bdb_index_entry_add( &op, tid, e );
527         if( rc != 0 ) {
528                 snprintf( text->bv_val, text->bv_len,
529                                 "index_entry_add failed: %s (%d)",
530                                 db_strerror(rc), rc );
531                 Debug( LDAP_DEBUG_ANY,
532                         "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
533                         text->bv_val, 0, 0 );
534                 goto done;
535         }
536
537 done:
538         if( rc == 0 ) {
539                 rc = TXN_COMMIT( tid, 0 );
540                 if( rc != 0 ) {
541                         snprintf( text->bv_val, text->bv_len,
542                                         "txn_commit failed: %s (%d)",
543                                         db_strerror(rc), rc );
544                         Debug( LDAP_DEBUG_ANY,
545                                 "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": "
546                                 "%s\n", text->bv_val, 0, 0 );
547                         e->e_id = NOID;
548                 }
549
550         } else {
551                 TXN_ABORT( tid );
552                 snprintf( text->bv_val, text->bv_len,
553                         "txn_aborted! %s (%d)",
554                         db_strerror(rc), rc );
555                 Debug( LDAP_DEBUG_ANY,
556                         "=> " LDAP_XSTRING(bdb_tool_entry_modify) ": %s\n",
557                         text->bv_val, 0, 0 );
558                 e->e_id = NOID;
559         }
560
561         return e->e_id;
562 }