]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/delete.c
misc cleanup
[openldap] / servers / slapd / back-bdb / delete.c
1 /* delete.c - bdb backend delete routine */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2003 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 #include "external.h"
15
16 int
17 bdb_delete( Operation *op, SlapReply *rs )
18 {
19         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
20         Entry   *matched = NULL;
21         struct berval   pdn = {0, NULL};
22         Entry   *e = NULL;
23         Entry   *p = NULL;
24         EntryInfo       *ei = NULL, *eip = NULL;
25         int             manageDSAit = get_manageDSAit( op );
26         AttributeDescription *children = slap_schema.si_ad_children;
27         AttributeDescription *entry = slap_schema.si_ad_entry;
28         DB_TXN          *ltid = NULL, *lt2;
29         struct bdb_op_info opinfo;
30
31         u_int32_t       locker = 0;
32         DB_LOCK         lock, plock;
33
34         int             noop = 0;
35
36         int             num_retries = 0;
37
38 #ifdef LDAP_SYNC
39         Operation* ps_list;
40         int     rc;
41         EntryInfo   *suffix_ei;
42         Entry       *ctxcsn_e;
43         int         ctxcsn_added = 0;
44 #endif
45
46 #ifdef NEW_LOGGING
47         LDAP_LOG ( OPERATION, ARGS,  "==> bdb_delete: %s\n", op->o_req_dn.bv_val, 0, 0 );
48 #else
49         Debug( LDAP_DEBUG_ARGS, "==> bdb_delete: %s\n",
50                 op->o_req_dn.bv_val, 0, 0 );
51 #endif
52
53         if( 0 ) {
54 retry:  /* transaction retry */
55                 if( e != NULL ) {
56                         bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
57                         e = NULL;
58                 }
59 #ifdef NEW_LOGGING
60                 LDAP_LOG ( OPERATION, DETAIL1, 
61                         "==> bdb_delete: retrying...\n", 0, 0, 0 );
62 #else
63                 Debug( LDAP_DEBUG_TRACE, "==> bdb_delete: retrying...\n",
64                         0, 0, 0 );
65 #endif
66                 rs->sr_err = TXN_ABORT( ltid );
67                 ltid = NULL;
68                 op->o_private = NULL;
69                 op->o_do_not_cache = opinfo.boi_acl_cache;
70                 if( rs->sr_err != 0 ) {
71                         rs->sr_err = LDAP_OTHER;
72                         rs->sr_text = "internal error";
73                         goto return_results;
74                 }
75                 bdb_trans_backoff( ++num_retries );
76                 ldap_pvt_thread_yield();
77         }
78
79         /* begin transaction */
80         rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
81                 bdb->bi_db_opflags );
82         rs->sr_text = NULL;
83         if( rs->sr_err != 0 ) {
84 #ifdef NEW_LOGGING
85                 LDAP_LOG ( OPERATION, ERR, 
86                         "==> bdb_delete: txn_begin failed: %s (%d)\n",
87                         db_strerror(rs->sr_err), rs->sr_err, 0 );
88 #else
89                 Debug( LDAP_DEBUG_TRACE,
90                         "bdb_delete: txn_begin failed: %s (%d)\n",
91                         db_strerror(rs->sr_err), rs->sr_err, 0 );
92 #endif
93                 rs->sr_err = LDAP_OTHER;
94                 rs->sr_text = "internal error";
95                 goto return_results;
96         }
97
98         locker = TXN_ID ( ltid );
99
100         opinfo.boi_bdb = op->o_bd;
101         opinfo.boi_txn = ltid;
102         opinfo.boi_locker = locker;
103         opinfo.boi_err = 0;
104         opinfo.boi_acl_cache = op->o_do_not_cache;
105         op->o_private = &opinfo;
106
107         if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
108                 dnParent( &op->o_req_ndn, &pdn );
109         }
110
111         /* get entry */
112         rs->sr_err = bdb_dn2entry( op, ltid, &op->o_req_ndn, &ei, 1,
113                 locker, &lock );
114
115         switch( rs->sr_err ) {
116         case 0:
117         case DB_NOTFOUND:
118                 break;
119         case DB_LOCK_DEADLOCK:
120         case DB_LOCK_NOTGRANTED:
121                 goto retry;
122         case LDAP_BUSY:
123                 rs->sr_text = "ldap server busy";
124                 goto return_results;
125         default:
126                 rs->sr_err = LDAP_OTHER;
127                 rs->sr_text = "internal error";
128                 goto return_results;
129         }
130
131         if ( rs->sr_err == 0 ) {
132                 e = ei->bei_e;
133                 eip = ei->bei_parent;
134                 bdb_cache_find_id( op, ltid, eip->bei_id, &eip,
135                         0, locker, &plock );
136         } else {
137                 matched = ei->bei_e;
138         }
139         if ( eip ) {
140                 p = eip->bei_e;
141         }
142
143         if ( pdn.bv_len != 0 ) {
144                 if( p == NULL || !bvmatch( &pdn, &p->e_nname )) {
145 #ifdef NEW_LOGGING
146                         LDAP_LOG ( OPERATION, DETAIL1, 
147                                 "<=- bdb_delete: parent does not exist\n", 0, 0, 0 );
148 #else
149                         Debug( LDAP_DEBUG_TRACE,
150                                 "<=- bdb_delete: parent does not exist\n",
151                                 0, 0, 0);
152 #endif
153                         rs->sr_err = LDAP_OTHER;
154                         rs->sr_text = "could not locate parent of entry";
155                         goto return_results;
156                 }
157
158                 /* check parent for "children" acl */
159                 rs->sr_err = access_allowed( op, p,
160                         children, NULL, ACL_WRITE, NULL );
161
162                 bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, p);
163                 p = NULL;
164
165                 if ( !rs->sr_err  ) {
166                         switch( opinfo.boi_err ) {
167                         case DB_LOCK_DEADLOCK:
168                         case DB_LOCK_NOTGRANTED:
169                                 goto retry;
170                         }
171
172 #ifdef NEW_LOGGING
173                         LDAP_LOG ( OPERATION, DETAIL1, 
174                                 "<=- bdb_delete: no write access to parent\n", 0, 0, 0 );
175 #else
176                         Debug( LDAP_DEBUG_TRACE,
177                                 "<=- bdb_delete: no write access to parent\n",
178                                 0, 0, 0 );
179 #endif
180                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
181                         rs->sr_text = "no write access to parent";
182                         goto return_results;
183                 }
184
185         } else {
186                 /* no parent, must be root to delete */
187                 if( ! be_isroot( op->o_bd, &op->o_ndn ) ) {
188                         if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
189                                 || be_isupdate( op->o_bd, &op->o_ndn ) ) {
190                                 p = (Entry *)&slap_entry_root;
191
192                                 /* check parent for "children" acl */
193                                 rs->sr_err = access_allowed( op, p,
194                                         children, NULL, ACL_WRITE, NULL );
195
196                                 p = NULL;
197
198                                 if ( !rs->sr_err  ) {
199                                         switch( opinfo.boi_err ) {
200                                         case DB_LOCK_DEADLOCK:
201                                         case DB_LOCK_NOTGRANTED:
202                                                 goto retry;
203                                         }
204
205 #ifdef NEW_LOGGING
206                                         LDAP_LOG ( OPERATION, DETAIL1, 
207                                                 "<=- bdb_delete: no access to parent\n", 0, 0, 0 );
208 #else
209                                         Debug( LDAP_DEBUG_TRACE,
210                                                 "<=- bdb_delete: no access "
211                                                 "to parent\n", 0, 0, 0 );
212 #endif
213                                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
214                                         rs->sr_text = "no write access to parent";
215                                         goto return_results;
216                                 }
217
218                         } else {
219 #ifdef NEW_LOGGING
220                                 LDAP_LOG ( OPERATION, DETAIL1, 
221                                         "<=- bdb_delete: no parent and not root\n", 0, 0, 0 );
222 #else
223                                 Debug( LDAP_DEBUG_TRACE,
224                                         "<=- bdb_delete: no parent "
225                                         "and not root\n", 0, 0, 0);
226 #endif
227                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
228                                 goto return_results;
229                         }
230                 }
231         }
232
233 #ifdef LDAP_SYNCREPL /* FIXME : dn2entry() should return non-glue entry */
234         if ( e == NULL || ( !manageDSAit && is_entry_glue( e ))) {
235 #else
236         if ( e == NULL ) {
237 #endif
238 #ifdef NEW_LOGGING
239                 LDAP_LOG ( OPERATION, ARGS, 
240                         "<=- bdb_delete: no such object %s\n", op->o_req_dn.bv_val, 0, 0);
241 #else
242                 Debug( LDAP_DEBUG_ARGS,
243                         "<=- bdb_delete: no such object %s\n",
244                         op->o_req_dn.bv_val, 0, 0);
245 #endif
246
247                 if ( matched != NULL ) {
248                         rs->sr_matched = ch_strdup( matched->e_dn );
249                         rs->sr_ref = is_entry_referral( matched )
250                                 ? get_entry_referrals( op, matched )
251                                 : NULL;
252                         bdb_unlocked_cache_return_entry_r(&bdb->bi_cache, matched);
253                         matched = NULL;
254
255                 } else {
256 #ifdef LDAP_SYNCREPL
257                         BerVarray deref = op->o_bd->syncinfo ?
258                                                           op->o_bd->syncinfo->provideruri_bv : default_referral;
259 #else
260                         BerVarray deref = default_referral;
261 #endif
262                         rs->sr_ref = referral_rewrite( deref, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
263                 }
264
265                 rs->sr_err = LDAP_REFERRAL;
266                 send_ldap_result( op, rs );
267
268                 ber_bvarray_free( rs->sr_ref );
269                 free( (char *)rs->sr_matched );
270                 rs->sr_ref = NULL;
271                 rs->sr_matched = NULL;
272
273                 rs->sr_err = -1;
274                 goto done;
275         }
276
277         if ( get_assert( op ) &&
278                 ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
279         {
280                 rs->sr_err = LDAP_ASSERTION_FAILED;
281                 goto return_results;
282         }
283
284         rs->sr_err = access_allowed( op, e,
285                 entry, NULL, ACL_WRITE, NULL );
286
287         if ( !rs->sr_err  ) {
288                 switch( opinfo.boi_err ) {
289                 case DB_LOCK_DEADLOCK:
290                 case DB_LOCK_NOTGRANTED:
291                         goto retry;
292                 }
293
294 #ifdef NEW_LOGGING
295                 LDAP_LOG ( OPERATION, DETAIL1, 
296                         "<=- bdb_delete: no write access to entry\n", 0, 0, 0 );
297 #else
298                 Debug( LDAP_DEBUG_TRACE,
299                         "<=- bdb_delete: no write access to entry\n",
300                         0, 0, 0 );
301 #endif
302                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
303                 rs->sr_text = "no write access to entry";
304                 goto return_results;
305         }
306
307         if ( !manageDSAit && is_entry_referral( e ) ) {
308                 /* entry is a referral, don't allow delete */
309                 rs->sr_ref = get_entry_referrals( op, e );
310
311 #ifdef NEW_LOGGING
312                 LDAP_LOG ( OPERATION, DETAIL1, 
313                         "<=- bdb_delete: entry is referral\n", 0, 0, 0 );
314 #else
315                 Debug( LDAP_DEBUG_TRACE,
316                         "bdb_delete: entry is referral\n", 0, 0, 0 );
317 #endif
318
319                 rs->sr_err = LDAP_REFERRAL;
320                 rs->sr_matched = e->e_name.bv_val;
321                 send_ldap_result( op, rs );
322
323                 ber_bvarray_free( rs->sr_ref );
324                 rs->sr_ref = NULL;
325                 rs->sr_matched = NULL;
326
327                 rs->sr_err = 1;
328                 goto done;
329         }
330
331         /* nested transaction */
332         rs->sr_err = TXN_BEGIN( bdb->bi_dbenv, ltid, &lt2, 
333                 bdb->bi_db_opflags );
334         rs->sr_text = NULL;
335         if( rs->sr_err != 0 ) {
336 #ifdef NEW_LOGGING
337                 LDAP_LOG ( OPERATION, ERR, 
338                         "bdb_delete: txn_begin(2) failed: %s (%d)\n", db_strerror(rs->sr_err), rs->sr_err, 0 );
339 #else
340                 Debug( LDAP_DEBUG_TRACE,
341                         "bdb_delete: txn_begin(2) failed: %s (%d)\n",
342                         db_strerror(rs->sr_err), rs->sr_err, 0 );
343 #endif
344                 rs->sr_err = LDAP_OTHER;
345                 rs->sr_text = "internal error";
346                 goto return_results;
347         }
348
349         /* Can't do it if we have kids */
350         rs->sr_err = bdb_cache_children( op, lt2, e );
351         if( rs->sr_err != DB_NOTFOUND ) {
352                 switch( rs->sr_err ) {
353                 case DB_LOCK_DEADLOCK:
354                 case DB_LOCK_NOTGRANTED:
355                         goto retry;
356                 case 0:
357 #ifdef NEW_LOGGING
358                         LDAP_LOG ( OPERATION, DETAIL1, 
359                                 "<=- bdb_delete: non-leaf %s\n", op->o_req_dn.bv_val, 0, 0 );
360 #else
361                         Debug(LDAP_DEBUG_ARGS,
362                                 "<=- bdb_delete: non-leaf %s\n",
363                                 op->o_req_dn.bv_val, 0, 0);
364 #endif
365                         rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
366                         rs->sr_text = "subtree delete not supported";
367                         break;
368                 default:
369 #ifdef NEW_LOGGING
370                         LDAP_LOG ( OPERATION, ERR, 
371                                 "<=- bdb_delete: has_children failed %s (%d)\n",
372                                 db_strerror(rs->sr_err), rs->sr_err, 0 );
373 #else
374                         Debug(LDAP_DEBUG_ARGS,
375                                 "<=- bdb_delete: has_children failed: %s (%d)\n",
376                                 db_strerror(rs->sr_err), rs->sr_err, 0 );
377 #endif
378                         rs->sr_err = LDAP_OTHER;
379                         rs->sr_text = "internal error";
380                 }
381                 goto return_results;
382         }
383
384         /* delete from dn2id */
385         rs->sr_err = bdb_dn2id_delete( op, lt2, eip, e );
386         if ( rs->sr_err != 0 ) {
387 #ifdef NEW_LOGGING
388                 LDAP_LOG ( OPERATION, ERR, 
389                         "<=- bdb_delete: dn2id failed: %s (%d)\n",
390                         db_strerror(rs->sr_err), rs->sr_err, 0 );
391 #else
392                 Debug(LDAP_DEBUG_TRACE,
393                         "<=- bdb_delete: dn2id failed: %s (%d)\n",
394                         db_strerror(rs->sr_err), rs->sr_err, 0 );
395 #endif
396                 switch( rs->sr_err ) {
397                 case DB_LOCK_DEADLOCK:
398                 case DB_LOCK_NOTGRANTED:
399                         goto retry;
400                 }
401                 rs->sr_text = "DN index delete failed";
402                 rs->sr_err = LDAP_OTHER;
403                 goto return_results;
404         }
405
406         /* delete from id2entry */
407         rs->sr_err = bdb_id2entry_delete( op->o_bd, lt2, e );
408         if ( rs->sr_err != 0 ) {
409 #ifdef NEW_LOGGING
410                 LDAP_LOG ( OPERATION, ERR, 
411                         "<=- bdb_delete: id2entry failed: %s (%d)\n", 
412                         db_strerror(rs->sr_err), rs->sr_err, 0 );
413 #else
414                 Debug(LDAP_DEBUG_TRACE,
415                         "<=- bdb_delete: id2entry failed: %s (%d)\n",
416                         db_strerror(rs->sr_err), rs->sr_err, 0 );
417 #endif
418                 switch( rs->sr_err ) {
419                 case DB_LOCK_DEADLOCK:
420                 case DB_LOCK_NOTGRANTED:
421                         goto retry;
422                 }
423                 rs->sr_text = "entry delete failed";
424                 rs->sr_err = LDAP_OTHER;
425                 goto return_results;
426         }
427
428         /* delete indices for old attributes */
429         rs->sr_err = bdb_index_entry_del( op, lt2, e );
430         if ( rs->sr_err != LDAP_SUCCESS ) {
431 #ifdef NEW_LOGGING
432                 LDAP_LOG ( OPERATION, ERR, 
433                         "<=- bdb_delete: index failed: %s (%d)\n", 
434                         db_strerror(rs->sr_err), rs->sr_err, 0 );
435 #else
436                 Debug( LDAP_DEBUG_TRACE,
437                         "<=- bdb_delete: index failed: %s (%d)\n", 
438                         db_strerror(rs->sr_err), rs->sr_err, 0 );
439 #endif
440                 switch( rs->sr_err ) {
441                 case DB_LOCK_DEADLOCK:
442                 case DB_LOCK_NOTGRANTED:
443                         goto retry;
444                 }
445                 rs->sr_text = "entry index delete failed";
446                 rs->sr_err = LDAP_OTHER;
447                 goto return_results;
448         }
449         if ( TXN_COMMIT( lt2, 0 ) != 0 ) {
450                 rs->sr_err = LDAP_OTHER;
451                 rs->sr_text = "txn_commit(2) failed";
452                 goto return_results;
453         }
454
455 #if 0   /* Do we want to reclaim deleted IDs? */
456         ldap_pvt_thread_mutex_lock( &bdb->bi_lastid_mutex );
457         if ( e->e_id == bdb->bi_lastid ) {
458                 bdb_last_id( op->o_bd, ltid );
459         }
460         ldap_pvt_thread_mutex_unlock( &bdb->bi_lastid_mutex );
461 #endif
462
463 #ifdef LDAP_SYNC
464         rc = bdb_csn_commit( op, rs, ltid, ei, &suffix_ei, &ctxcsn_e, &ctxcsn_added, locker );
465         switch ( rc ) {
466         case BDB_CSN_ABORT :
467                 goto return_results;
468         case BDB_CSN_RETRY :
469                 goto retry;
470         }
471 #endif
472
473         if( op->o_noop ) {
474                 if ( ( rs->sr_err = TXN_ABORT( ltid ) ) != 0 ) {
475                         rs->sr_text = "txn_abort (no-op) failed";
476                 } else {
477                         noop = 1;
478                         rs->sr_err = LDAP_SUCCESS;
479                 }
480         } else {
481 #ifdef LDAP_SYNC
482                 struct berval ctx_nrdn;
483 #endif
484
485                 bdb_cache_delete( &bdb->bi_cache, e, bdb->bi_dbenv,
486                         locker, &lock );
487
488 #ifdef LDAP_SYNC
489                 if ( ctxcsn_added ) {
490                         ctx_nrdn.bv_val = "cn=ldapsync";
491                         ctx_nrdn.bv_len = strlen( ctx_nrdn.bv_val );
492                         bdb_cache_add( bdb, suffix_ei, ctxcsn_e, &ctx_nrdn, locker );
493                 }
494 #endif
495
496                 rs->sr_err = TXN_COMMIT( ltid, 0 );
497         }
498         ltid = NULL;
499         op->o_private = NULL;
500
501         if( rs->sr_err != 0 ) {
502 #ifdef NEW_LOGGING
503                 LDAP_LOG ( OPERATION, ERR, 
504                         "bdb_delete: txn_%s failed: %s (%d)\n",
505                         op->o_noop ? "abort (no-op)" : "commit", db_strerror(rs->sr_err), rs->sr_err );
506 #else
507                 Debug( LDAP_DEBUG_TRACE,
508                         "bdb_delete: txn_%s failed: %s (%d)\n",
509                         op->o_noop ? "abort (no-op)" : "commit",
510                         db_strerror(rs->sr_err), rs->sr_err );
511 #endif
512                 rs->sr_err = LDAP_OTHER;
513                 rs->sr_text = "commit failed";
514
515         } else {
516 #ifdef NEW_LOGGING
517                 LDAP_LOG ( OPERATION, RESULTS, 
518                         "bdb_delete: deleted%s id=%08lx db=\"%s\"\n",
519                         op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn );
520 #else
521                 Debug( LDAP_DEBUG_TRACE,
522                         "bdb_delete: deleted%s id=%08lx dn=\"%s\"\n",
523                         op->o_noop ? " (no-op)" : "",
524                         e->e_id, e->e_dn );
525 #endif
526                 rs->sr_err = LDAP_SUCCESS;
527                 rs->sr_text = NULL;
528         }
529
530 return_results:
531         send_ldap_result( op, rs );
532
533 #ifdef LDAP_SYNC
534         if ( rs->sr_err == LDAP_SUCCESS && !noop ) {
535                 LDAP_LIST_FOREACH( ps_list, &bdb->bi_psearch_list, o_ps_link ) {
536                         bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_DELETE );
537                 }
538         }
539 #endif
540
541         if(rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp ) {
542                 ldap_pvt_thread_yield();
543                 TXN_CHECKPOINT( bdb->bi_dbenv,
544                         bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
545         }
546
547 done:
548         /* free entry */
549         if( e != NULL ) {
550                 if ( rs->sr_err == LDAP_SUCCESS ) {
551                         /* Free the EntryInfo and the Entry */
552                         bdb_cache_delete_cleanup( e );
553                 } else {
554                         bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e);
555                 }
556         }
557
558         if( ltid != NULL ) {
559                 TXN_ABORT( ltid );
560                 op->o_private = NULL;
561         }
562
563         return ( ( rs->sr_err == LDAP_SUCCESS ) ? noop : rs->sr_err );
564 }