1 /* $NetBSD: tools.c,v 1.2 2021/08/14 16:15:02 christos Exp $ */
2
3 /* OpenLDAP WiredTiger backend */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2002-2021 The OpenLDAP Foundation.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18 /* ACKNOWLEDGEMENTS:
19 * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
20 * based on back-bdb for inclusion in OpenLDAP Software.
21 * WiredTiger is a product of MongoDB Inc.
22 */
23
24 #include <sys/cdefs.h>
25 __RCSID("$NetBSD: tools.c,v 1.2 2021/08/14 16:15:02 christos Exp $");
26
27 #include "portable.h"
28
29 #include <stdio.h>
30 #include <ac/string.h>
31 #include "back-wt.h"
32 #include "slap-config.h"
33
34 typedef struct dn_id {
35 ID id;
36 struct berval dn;
37 } dn_id;
38
39 #define HOLE_SIZE 4096
40 static dn_id hbuf[HOLE_SIZE], *holes = hbuf;
41 static unsigned nhmax = HOLE_SIZE;
42 static unsigned nholes;
43
44 static int index_nattrs;
45
46 static struct berval *tool_base;
47 static int tool_scope;
48 static Filter *tool_filter;
49 static Entry *tool_next_entry;
50
51 static wt_ctx *wc;
52 static WT_CURSOR *reader;
53 static WT_ITEM item;
54
55 int
wt_tool_entry_open(BackendDB * be,int mode)56 wt_tool_entry_open( BackendDB *be, int mode )
57 {
58 struct wt_info *wi = (struct wt_info *) be->be_private;
59 WT_CONNECTION *conn = wi->wi_conn;
60 int rc;
61
62 wc = wt_ctx_init(wi);
63 if( !wc ){
64 Debug( LDAP_DEBUG_ANY,
65 LDAP_XSTRING(wt_tool_entry_open)
66 ": wt_ctx_get failed\n" );
67 return -1;
68 }
69
70 rc = wc->session->open_cursor(wc->session, WT_TABLE_ID2ENTRY"(entry)"
71 ,NULL, NULL, &reader);
72 if ( rc ) {
73 Debug( LDAP_DEBUG_ANY,
74 LDAP_XSTRING(wt_tool_entry_open)
75 ": cursor open failed: %s (%d)\n",
76 wiredtiger_strerror(rc), rc );
77 return -1;
78 }
79
80 return 0;
81 }
82
83 int
wt_tool_entry_close(BackendDB * be)84 wt_tool_entry_close( BackendDB *be )
85 {
86 int rc;
87
88 if( reader ) {
89 reader->close(reader);
90 reader = NULL;
91 }
92
93 wt_ctx_free(NULL, wc);
94
95 if( nholes ) {
96 unsigned i;
97 fprintf( stderr, "Error, entries missing!\n");
98 for (i=0; i<nholes; i++) {
99 fprintf(stderr, " entry %ld: %s\n",
100 holes[i].id, holes[i].dn.bv_val);
101 }
102 return -1;
103 }
104
105 return 0;
106 }
107
108 ID
wt_tool_entry_first_x(BackendDB * be,struct berval * base,int scope,Filter * f)109 wt_tool_entry_first_x( BackendDB *be,
110 struct berval *base,
111 int scope,
112 Filter *f )
113 {
114 tool_base = base;
115 tool_scope = scope;
116 tool_filter = f;
117
118 return wt_tool_entry_next( be );
119 }
120
121 ID
wt_tool_entry_next(BackendDB * be)122 wt_tool_entry_next( BackendDB *be )
123 {
124 int rc;
125 ID id;
126
127 rc = reader->next(reader);
128 switch( rc ){
129 case 0:
130 break;
131 case WT_NOTFOUND:
132 return NOID;
133 default:
134 Debug( LDAP_DEBUG_ANY,
135 LDAP_XSTRING(wt_tool_entry_next)
136 ": next failed: %s (%d)\n",
137 wiredtiger_strerror(rc), rc );
138 return NOID;
139 }
140
141 rc = reader->get_key(reader, &id);
142 if( rc ){
143 Debug( LDAP_DEBUG_ANY,
144 LDAP_XSTRING(wt_tool_entry_next)
145 ": get_key failed: %s (%d)\n",
146 wiredtiger_strerror(rc), rc );
147 }
148
149 rc = reader->get_value(reader, &item);
150 if( rc ){
151 Debug( LDAP_DEBUG_ANY,
152 LDAP_XSTRING(wt_tool_entry_next)
153 ": get_value failed: %s (%d)\n",
154 wiredtiger_strerror(rc), rc );
155 }
156 return id;
157 }
158
159 static ber_len_t
entry_getlen(unsigned char ** buf)160 entry_getlen(unsigned char **buf)
161 {
162 ber_len_t len;
163 int i;
164
165 len = *(*buf)++;
166 if (len <= 0x7f)
167 return len;
168 i = len & 0x7f;
169 len = 0;
170 for (;i > 0; i--) {
171 len <<= 8;
172 len |= *(*buf)++;
173 }
174 return len;
175 }
176
wt_entry_header(WT_ITEM * item,EntryHeader * eh)177 int wt_entry_header(WT_ITEM *item, EntryHeader *eh){
178 unsigned char *ptr = (unsigned char *)item->data;
179
180 /* Some overlays can create empty entries
181 * so don't check for zeros here.
182 */
183 eh->nattrs = entry_getlen(&ptr);
184 eh->nvals = entry_getlen(&ptr);
185 eh->data = (char *)ptr;
186 return LDAP_SUCCESS;
187 }
188
189 Entry *
wt_tool_entry_get(BackendDB * be,ID id)190 wt_tool_entry_get( BackendDB *be, ID id )
191 {
192 Entry *e = NULL;
193 static EntryHeader eh;
194 int rc, eoff;
195
196 assert( be != NULL );
197 assert( slapMode & SLAP_TOOL_MODE );
198
199 rc = wt_entry_header( &item, &eh );
200 assert( rc == 0 );
201 eoff = eh.data - (char *)item.data;
202
203 eh.bv.bv_len = eh.nvals * sizeof( struct berval ) + item.size;
204 eh.bv.bv_val = ch_realloc( eh.bv.bv_val, eh.bv.bv_len );
205 memset(eh.bv.bv_val, 0xff, eh.bv.bv_len);
206 eh.data = eh.bv.bv_val + eh.nvals * sizeof( struct berval );
207 memcpy(eh.data, item.data, item.size);
208 eh.data += eoff;
209
210 rc = entry_decode( &eh, &e );
211 assert( rc == 0 );
212
213 if( rc == LDAP_SUCCESS ) {
214 e->e_id = id;
215 }
216
217 return e;
218 }
219
wt_tool_next_id(Operation * op,Entry * e,struct berval * text,int hole)220 static int wt_tool_next_id(
221 Operation *op,
222 Entry *e,
223 struct berval *text,
224 int hole )
225 {
226 struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
227 struct berval dn = e->e_name;
228 struct berval ndn = e->e_nname;
229 struct berval pdn, npdn;
230 int rc;
231 ID id = 0;
232 ID pid = 0;
233
234 if(ndn.bv_len == 0){
235 e->e_id = 0;
236 return 0;
237 }
238
239 rc = wt_dn2id(op, wc->session, &ndn, &id);
240 if(rc == 0){
241 e->e_id = id;
242 }else if( rc == WT_NOTFOUND ){
243 if ( !be_issuffix( op->o_bd, &ndn ) ) {
244 ID eid = e->e_id;
245 dnParent( &dn, &pdn );
246 dnParent( &ndn, &npdn );
247 e->e_name = pdn;
248 e->e_nname = npdn;
249 rc = wt_tool_next_id( op, e, text, 1 );
250 e->e_name = dn;
251 e->e_nname = ndn;
252 if ( rc ) {
253 return rc;
254 }
255 /* If parent didn't exist, it was created just now
256 * and its ID is now in e->e_id. Make sure the current
257 * entry gets added under the new parent ID.
258 */
259 if ( eid != e->e_id ) {
260 pid = e->e_id;
261 }
262 }else{
263 pid = id;
264 }
265 wt_next_id( op->o_bd, &e->e_id );
266 rc = wt_dn2id_add(op, wc->session, pid, e);
267 if( rc ){
268 snprintf( text->bv_val, text->bv_len,
269 "wt_dn2id_add failed: %s (%d)",
270 wiredtiger_strerror(rc), rc );
271 Debug( LDAP_DEBUG_ANY,
272 "=> wt_tool_next_id: %s\n", text->bv_val );
273 }
274
275 }else if ( !hole ) {
276 unsigned i, j;
277 e->e_id = id;
278
279 for ( i=0; i<nholes; i++) {
280 if ( holes[i].id == e->e_id ) {
281 free(holes[i].dn.bv_val);
282 for (j=i;j<nholes;j++) holes[j] = holes[j+1];
283 holes[j].id = 0;
284 nholes--;
285 break;
286 } else if ( holes[i].id > e->e_id ) {
287 break;
288 }
289 }
290 }
291 return rc;
292 }
293
294 static int
wt_tool_index_add(Operation * op,wt_ctx * wc,Entry * e)295 wt_tool_index_add(
296 Operation *op,
297 wt_ctx *wc,
298 Entry *e )
299 {
300 return wt_index_entry_add( op, wc, e );
301 }
302
303 ID
wt_tool_entry_put(BackendDB * be,Entry * e,struct berval * text)304 wt_tool_entry_put( BackendDB *be, Entry *e, struct berval *text )
305 {
306 struct wt_info *wi = (struct wt_info *) be->be_private;
307 int rc;
308
309 Operation op = {0};
310 Opheader ohdr = {0};
311
312 assert( slapMode & SLAP_TOOL_MODE );
313 assert( text != NULL );
314 assert( text->bv_val != NULL );
315 assert( text->bv_val[0] == '\0' ); /* overconservative? */
316
317 Debug( LDAP_DEBUG_TRACE,
318 "=> " LDAP_XSTRING(wt_tool_entry_put)
319 ": ( \"%s\" )\n", e->e_dn );
320
321 rc = wc->session->begin_transaction(wc->session, NULL);
322 if( rc ){
323 Debug( LDAP_DEBUG_ANY,
324 LDAP_XSTRING(wt_dn2id_add)
325 ": begin_transaction failed: %s (%d)\n",
326 wiredtiger_strerror(rc), rc );
327 return NOID;
328 }
329
330 op.o_hdr = &ohdr;
331 op.o_bd = be;
332 op.o_tmpmemctx = NULL;
333 op.o_tmpmfuncs = &ch_mfuncs;
334
335 rc = wt_tool_next_id( &op, e, text, 0 );
336 if( rc != 0 ) {
337 snprintf( text->bv_val, text->bv_len,
338 "wt_tool_next_id failed: %s (%d)",
339 wiredtiger_strerror(rc), rc );
340 Debug( LDAP_DEBUG_ANY,
341 "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
342 text->bv_val );
343 goto done;
344 }
345
346 rc = wt_id2entry_add( &op, wc->session, e );
347 if( rc != 0 ) {
348 snprintf( text->bv_val, text->bv_len,
349 "id2entry_add failed: %s (%d)",
350 wiredtiger_strerror(rc), rc );
351 Debug( LDAP_DEBUG_ANY,
352 "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
353 text->bv_val );
354 goto done;
355 }
356
357 rc = wt_tool_index_add( &op, wc, e );
358 if( rc != 0 ) {
359 snprintf( text->bv_val, text->bv_len,
360 "index_entry_add failed: %s (%d)",
361 rc == LDAP_OTHER ? "Internal error" :
362 wiredtiger_strerror(rc), rc );
363 Debug( LDAP_DEBUG_ANY,
364 "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
365 text->bv_val );
366 goto done;
367 }
368
369 done:
370 if ( rc == 0 ){
371 rc = wc->session->commit_transaction(wc->session, NULL);
372 if( rc != 0 ) {
373 snprintf( text->bv_val, text->bv_len,
374 "txn_commit failed: %s (%d)",
375 wiredtiger_strerror(rc), rc );
376 Debug( LDAP_DEBUG_ANY,
377 "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
378 text->bv_val );
379 e->e_id = NOID;
380 }
381 }else{
382 rc = wc->session->rollback_transaction(wc->session, NULL);
383 snprintf( text->bv_val, text->bv_len,
384 "txn_aborted! %s (%d)",
385 rc == LDAP_OTHER ? "Internal error" :
386 wiredtiger_strerror(rc), rc );
387 Debug( LDAP_DEBUG_ANY,
388 "=> " LDAP_XSTRING(wt_tool_entry_put) ": %s\n",
389 text->bv_val );
390 e->e_id = NOID;
391 }
392
393 return e->e_id;
394 }
395
wt_tool_entry_reindex(BackendDB * be,ID id,AttributeDescription ** adv)396 int wt_tool_entry_reindex(
397 BackendDB *be,
398 ID id,
399 AttributeDescription **adv )
400 {
401 struct wt_info *wi = (struct wt_info *) be->be_private;
402 int rc;
403 Entry *e;
404 Operation op = {0};
405 Opheader ohdr = {0};
406
407 Debug( LDAP_DEBUG_ARGS,
408 "=> " LDAP_XSTRING(wt_tool_entry_reindex) "( %ld )\n",
409 (long) id );
410 assert( tool_base == NULL );
411 assert( tool_filter == NULL );
412
413 /* No indexes configured, nothing to do. Could return an
414 * error here to shortcut things.
415 */
416 if (!wi->wi_attrs) {
417 return 0;
418 }
419
420 /* Check for explicit list of attrs to index */
421 if ( adv ) {
422 int i, j, n;
423
424 if ( wi->wi_attrs[0]->ai_desc != adv[0] ) {
425 /* count */
426 for ( n = 0; adv[n]; n++ ) ;
427
428 /* insertion sort */
429 for ( i = 0; i < n; i++ ) {
430 AttributeDescription *ad = adv[i];
431 for ( j = i-1; j>=0; j--) {
432 if ( SLAP_PTRCMP( adv[j], ad ) <= 0 ) break;
433 adv[j+1] = adv[j];
434 }
435 adv[j+1] = ad;
436 }
437 }
438
439 for ( i = 0; adv[i]; i++ ) {
440 if ( wi->wi_attrs[i]->ai_desc != adv[i] ) {
441 for ( j = i+1; j < wi->wi_nattrs; j++ ) {
442 if ( wi->wi_attrs[j]->ai_desc == adv[i] ) {
443 AttrInfo *ai = wi->wi_attrs[i];
444 wi->wi_attrs[i] = wi->wi_attrs[j];
445 wi->wi_attrs[j] = ai;
446 break;
447 }
448 }
449 if ( j == wi->wi_nattrs ) {
450 Debug( LDAP_DEBUG_ANY,
451 LDAP_XSTRING(wt_tool_entry_reindex)
452 ": no index configured for %s\n",
453 adv[i]->ad_cname.bv_val );
454 return -1;
455 }
456 }
457 }
458 wi->wi_nattrs = i;
459 }
460
461 e = wt_tool_entry_get( be, id );
462
463 if( e == NULL ) {
464 Debug( LDAP_DEBUG_ANY,
465 LDAP_XSTRING(wt_tool_entry_reindex)
466 ": could not locate id=%ld\n",
467 (long) id );
468 return -1;
469 }
470
471 op.o_hdr = &ohdr;
472 op.o_bd = be;
473 op.o_tmpmemctx = NULL;
474 op.o_tmpmfuncs = &ch_mfuncs;
475
476 rc = wc->session->begin_transaction(wc->session, NULL);
477 if( rc ){
478 Debug( LDAP_DEBUG_ANY,
479 LDAP_XSTRING(wt_dn2id_add)
480 ": begin_transaction failed: %s (%d)\n",
481 wiredtiger_strerror(rc), rc );
482 goto done;
483 }
484 Debug( LDAP_DEBUG_TRACE,
485 "=> " LDAP_XSTRING(wt_tool_entry_reindex) "( %ld, \"%s\" )\n",
486 (long) id, e->e_dn );
487
488 rc = wt_tool_index_add( &op, wc, e );
489
490 done:
491 if ( rc == 0 ){
492 rc = wc->session->commit_transaction(wc->session, NULL);
493 if( rc ) {
494 Debug( LDAP_DEBUG_ANY,
495 "=> " LDAP_XSTRING(wt_tool_entry_reindex)
496 "commit_transaction failed: %s (%d)\n",
497 wiredtiger_strerror(rc), rc );
498 }
499 }else{
500 rc = wc->session->rollback_transaction(wc->session, NULL);
501 Debug( LDAP_DEBUG_ANY,
502 "=> " LDAP_XSTRING(wt_tool_entry_reindex)
503 ": rollback transaction %s (%d)\n",
504 wiredtiger_strerror(rc), rc );
505 }
506
507 wt_entry_release( &op, e, 0 );
508
509 return rc;
510 }
511
512 /*
513 * Local variables:
514 * indent-tabs-mode: t
515 * tab-width: 4
516 * c-basic-offset: 4
517 * End:
518 */
519