]> git.sur5r.net Git - openldap/blob - servers/slapd/back-wt/delete.c
ITS#8605 - spelling fixes
[openldap] / servers / slapd / back-wt / delete.c
1 /* OpenLDAP WiredTiger backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2002-2017 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 /* ACKNOWLEDGEMENTS:
17  * This work was developed by HAMANO Tsukasa <hamano@osstech.co.jp>
18  * based on back-bdb for inclusion in OpenLDAP Software.
19  * WiredTiger is a product of MongoDB Inc.
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25 #include <ac/string.h>
26
27 #include "back-wt.h"
28 #include "config.h"
29
30 int
31 wt_delete( Operation *op, SlapReply *rs )
32 {
33     struct wt_info *wi = (struct wt_info *) op->o_bd->be_private;
34         struct berval   pdn = {0, NULL};
35         Entry *e = NULL;
36         Entry *p = NULL;
37         int manageDSAit = get_manageDSAit( op );
38         AttributeDescription *children = slap_schema.si_ad_children;
39         AttributeDescription *entry = slap_schema.si_ad_entry;
40
41         LDAPControl **preread_ctrl = NULL;
42         LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS];
43         int num_ctrls = 0;
44
45         wt_ctx *wc;
46         int rc;
47         WT_CURSOR *cursor = NULL;
48
49         int parent_is_glue = 0;
50         int parent_is_leaf = 0;
51
52         Debug( LDAP_DEBUG_ARGS, "==> " LDAP_XSTRING(wt_delete) ": %s\n",
53                    op->o_req_dn.bv_val, 0, 0 );
54
55 #ifdef LDAP_X_TXN
56         if( op->o_txnSpec && txn_preop( op, rs ))
57                 return rs->sr_err;
58 #endif
59
60         ctrls[num_ctrls] = 0;
61         rs->sr_text = NULL;
62
63         wc = wt_ctx_get(op, wi);
64         if( !wc ){
65         Debug( LDAP_DEBUG_TRACE,
66                            LDAP_XSTRING(wt_delete)
67                            ": wt_ctx_get failed\n",
68                            0, 0, 0 );
69                 rs->sr_err = LDAP_OTHER;
70                 rs->sr_text = "internal error";
71                 goto return_results;
72         }
73
74 /* allocate CSN */
75         if ( BER_BVISNULL( &op->o_csn ) ) {
76                 struct berval csn;
77                 char csnbuf[LDAP_PVT_CSNSTR_BUFSIZE];
78
79                 csn.bv_val = csnbuf;
80                 csn.bv_len = sizeof(csnbuf);
81                 slap_get_csn( op, &csn, 1 );
82         }
83
84         if ( !be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
85                 dnParent( &op->o_req_ndn, &pdn );
86         }
87
88         /* get parent */
89         rc = wt_dn2entry(op->o_bd, wc, &pdn, &p);
90         switch( rc ) {
91         case 0:
92         case WT_NOTFOUND:
93                 break;
94         default:
95                 /* TODO: error handling */
96                 rs->sr_err = LDAP_OTHER;
97                 rs->sr_text = "internal error";
98                 Debug( LDAP_DEBUG_ANY,
99                            LDAP_XSTRING(wt_delete)
100                            ": error at wt_dn2entry() rc=%d\n",
101                            rc, 0, 0 );
102                 goto return_results;
103         }
104
105         if ( rc == WT_NOTFOUND && pdn.bv_len != 0 ) {
106                 Debug( LDAP_DEBUG_ARGS,
107                            "<== " LDAP_XSTRING(wt_delete) ": no such object %s\n",
108                            op->o_req_dn.bv_val, 0, 0);
109
110                 if ( p && !BER_BVISEMPTY( &p->e_name )) {
111                         rs->sr_matched = ch_strdup( p->e_name.bv_val );
112                         if ( is_entry_referral( p )) {
113                                 BerVarray ref = get_entry_referrals( op, p );
114                                 rs->sr_ref = referral_rewrite( ref, &p->e_name,
115                                                                                            &op->o_req_dn, LDAP_SCOPE_DEFAULT );
116                                 ber_bvarray_free( ref );
117                         } else {
118                                 rs->sr_ref = NULL;
119                         }
120                 } else {
121                         rs->sr_ref = referral_rewrite( default_referral, NULL,
122                                                                                    &op->o_req_dn, LDAP_SCOPE_DEFAULT );
123                 }
124
125                 rs->sr_err = LDAP_REFERRAL;
126                 rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
127                 goto return_results;
128         }
129
130         /* get entry */
131         rc = wt_dn2entry(op->o_bd, wc, &op->o_req_ndn, &e);
132         switch( rc ) {
133         case 0:
134                 break;
135         case WT_NOTFOUND:
136                 Debug( LDAP_DEBUG_ARGS,
137                            "<== " LDAP_XSTRING(wt_delete)
138                            ": no such object %s\n",
139                            op->o_req_dn.bv_val, 0, 0);
140                 rs->sr_err = LDAP_REFERRAL;
141                 rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
142                 goto return_results;
143         default:
144                 /* TODO: error handling */
145                 rs->sr_err = LDAP_OTHER;
146                 rs->sr_text = "internal error";
147                 Debug( LDAP_DEBUG_ANY,
148                            LDAP_XSTRING(wt_delete)
149                            ": error at wt_dn2entry() rc=%d\n",
150                            rc, 0, 0 );
151                 goto return_results;
152         }
153
154         /* FIXME : dn2entry() should return non-glue entry */
155         if ( !manageDSAit && is_entry_glue( e ) ) {
156                 Debug( LDAP_DEBUG_ARGS,
157                            "<== " LDAP_XSTRING(wt_delete)
158                            ": glue entry %s\n",
159                            op->o_req_dn.bv_val, 0, 0);
160
161                 rs->sr_matched = ch_strdup( e->e_dn );
162                 if ( is_entry_referral( e )) {
163                         BerVarray ref = get_entry_referrals( op, e );
164                         rs->sr_ref = referral_rewrite( ref, &e->e_name,
165                                                                                    &op->o_req_dn, LDAP_SCOPE_DEFAULT );
166                         ber_bvarray_free( ref );
167                 } else {
168                         rs->sr_ref = NULL;
169                 }
170
171                 rs->sr_err = LDAP_REFERRAL;
172                 rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
173                 goto return_results;
174         }
175
176         if ( pdn.bv_len != 0 ) {
177                 /* check parent for "children" acl */
178                 rs->sr_err = access_allowed( op, p,
179                                                                          children, NULL, ACL_WDEL, NULL );
180
181                 if ( !rs->sr_err  ) {
182                         Debug( LDAP_DEBUG_TRACE,
183                                    "<== " LDAP_XSTRING(wt_delete) ": no write "
184                                    "access to parent\n", 0, 0, 0 );
185                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
186                         rs->sr_text = "no write access to parent";
187                         goto return_results;
188                 }
189
190         } else {
191                 /* no parent, must be root to delete */
192                 if( ! be_isroot( op ) ) {
193                         if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv )
194                                  || be_shadow_update( op ) ) {
195                                 p = (Entry *)&slap_entry_root;
196
197                                 /* check parent for "children" acl */
198                                 rs->sr_err = access_allowed( op, p,
199                                                                                          children, NULL, ACL_WDEL, NULL );
200
201                                 p = NULL;
202
203                                 if ( !rs->sr_err  ) {
204                                         Debug( LDAP_DEBUG_TRACE,
205                                                    "<== " LDAP_XSTRING(wt_delete)
206                                                    ": no access to parent\n",
207                                                    0, 0, 0 );
208                                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
209                                         rs->sr_text = "no write access to parent";
210                                         goto return_results;
211                                 }
212
213                         } else {
214                                 Debug( LDAP_DEBUG_TRACE,
215                                            "<== " LDAP_XSTRING(wt_delete)
216                                            ": no parent and not root\n", 0, 0, 0 );
217                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
218                                 goto return_results;
219                         }
220                 }
221         }
222
223         if ( get_assert( op ) &&
224                  ( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
225         {
226                 rs->sr_err = LDAP_ASSERTION_FAILED;
227                 goto return_results;
228         }
229
230         rs->sr_err = access_allowed( op, e,
231                                                                  entry, NULL, ACL_WDEL, NULL );
232         if ( !rs->sr_err  ) {
233                 Debug( LDAP_DEBUG_TRACE,
234                            "<== " LDAP_XSTRING(wt_delete) ": no write access "
235                            "to entry\n", 0, 0, 0 );
236                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
237                 rs->sr_text = "no write access to entry";
238                 goto return_results;
239         }
240
241         if ( !manageDSAit && is_entry_referral( e ) ) {
242                 /* entry is a referral, don't allow delete */
243                 rs->sr_ref = get_entry_referrals( op, e );
244
245                 Debug( LDAP_DEBUG_TRACE,
246                            LDAP_XSTRING(tw_delete) ": entry is referral\n",
247                            0, 0, 0 );
248
249                 rs->sr_err = LDAP_REFERRAL;
250                 rs->sr_matched = ch_strdup( e->e_name.bv_val );
251                 rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
252                 goto return_results;
253         }
254
255         /* pre-read */
256         if( op->o_preread ) {
257                 if( preread_ctrl == NULL ) {
258                         preread_ctrl = &ctrls[num_ctrls++];
259                         ctrls[num_ctrls] = NULL;
260                 }
261                 if( slap_read_controls( op, rs, e,
262                                                                 &slap_pre_read_bv, preread_ctrl ) )
263                 {
264                         Debug( LDAP_DEBUG_TRACE,
265                                    "<== " LDAP_XSTRING(wt_delete) ": pre-read "
266                                    "failed!\n", 0, 0, 0 );
267                         if ( op->o_preread & SLAP_CONTROL_CRITICAL ) {
268                                 /* FIXME: is it correct to abort
269                  * operation if control fails? */
270                                 goto return_results;
271                         }
272                 }
273         }
274
275     /* Can't do it if we have kids */
276         rc = wt_dn2id_has_children( op, wc->session, e->e_id );
277         if( rc != WT_NOTFOUND ) {
278                 switch( rc ) {
279                 case 0:
280                         Debug(LDAP_DEBUG_ARGS,
281                                   "<== " LDAP_XSTRING(wt_delete)
282                                   ": non-leaf %s\n",
283                                   op->o_req_dn.bv_val, 0, 0);
284                         rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF;
285                         rs->sr_text = "subordinate objects must be deleted first";
286                         break;
287                 default:
288                         Debug(LDAP_DEBUG_ARGS,
289                                   "<== " LDAP_XSTRING(wt_delete)
290                                   ": has_children failed: %s (%d)\n",
291                                   wiredtiger_strerror(rc), rc, 0 );
292                         rs->sr_err = LDAP_OTHER;
293                         rs->sr_text = "internal error";
294                 }
295                 goto return_results;
296         }
297
298         /* begin transaction */
299         rc = wc->session->begin_transaction(wc->session, NULL);
300         if( rc ) {
301                 Debug( LDAP_DEBUG_TRACE,
302                            LDAP_XSTRING(wt_add) ": begin_transaction failed: %s (%d)\n",
303                            wiredtiger_strerror(rc), rc, 0 );
304                 rs->sr_err = LDAP_OTHER;
305                 rs->sr_text = "begin_transaction failed";
306                 goto return_results;
307         }
308
309         /* delete from dn2id */
310         rc = wt_dn2id_delete( op, wc->session, &e->e_nname);
311         if ( rc ) {
312                 Debug(LDAP_DEBUG_TRACE,
313                           "<== " LDAP_XSTRING(wt_delete)
314                           ": dn2id failed: %s (%d)\n",
315                           wiredtiger_strerror(rc), rc, 0 );
316                 rs->sr_err = LDAP_OTHER;
317                 rs->sr_text = "dn2id delete failed";
318                 wc->session->rollback_transaction(wc->session, NULL);
319                 goto return_results;
320         }
321
322         /* delete indices for old attributes */
323         rc = wt_index_entry_del( op, wc, e );
324         if ( rc ) {
325                 Debug(LDAP_DEBUG_TRACE,
326                           "<== " LDAP_XSTRING(wt_delete)
327                           ": index delete failed: %s (%d)\n",
328                           wiredtiger_strerror(rc), rc, 0 );
329                 rs->sr_err = LDAP_OTHER;
330                 rs->sr_text = "index delete failed";
331                 wc->session->rollback_transaction(wc->session, NULL);
332                 goto return_results;
333         }
334
335         /* fixup delete CSN */
336         if ( !SLAP_SHADOW( op->o_bd )) {
337                 struct berval vals[2];
338
339                 assert( !BER_BVISNULL( &op->o_csn ) );
340                 vals[0] = op->o_csn;
341                 BER_BVZERO( &vals[1] );
342                 rs->sr_err = wt_index_values( op, wc->session, slap_schema.si_ad_entryCSN,
343                                                                           vals, 0, SLAP_INDEX_ADD_OP );
344                 if ( rs->sr_err != LDAP_SUCCESS ) {
345                         rs->sr_text = "entryCSN index update failed";
346                         rs->sr_err = LDAP_OTHER;
347                         wc->session->rollback_transaction(wc->session, NULL);
348                         goto return_results;
349                 }
350         }
351
352         /* delete from id2entry */
353         rc = wt_id2entry_delete( op, wc->session, e );
354         if ( rc ) {
355                 Debug( LDAP_DEBUG_TRACE,
356                            "<== " LDAP_XSTRING(wt_delete)
357                            ": id2entry failed: %s (%d)\n",
358                            wiredtiger_strerror(rc), rc, 0 );
359                 rs->sr_err = LDAP_OTHER;
360                 rs->sr_text = "entry delete failed";
361                 wc->session->rollback_transaction(wc->session, NULL);
362                 goto return_results;
363         }
364
365         if ( pdn.bv_len != 0 ) {
366                 // TODO: glue entry
367         }
368
369         rc = wc->session->commit_transaction(wc->session, NULL);
370         if( rc ) {
371                 Debug( LDAP_DEBUG_TRACE,
372                            "<== " LDAP_XSTRING(wt_delete)
373                            ": commit_transaction failed: %s (%d)\n",
374                            wiredtiger_strerror(rc), rc, 0 );
375                 rs->sr_err = LDAP_OTHER;
376                 rs->sr_text = "commit_transaction failed";
377                 goto return_results;
378         }
379
380         Debug( LDAP_DEBUG_TRACE,
381                    LDAP_XSTRING(wt_delete)
382                    ": deleted%s id=%08lx dn=\"%s\"\n",
383                    op->o_noop ? " (no-op)" : "", e->e_id, op->o_req_dn.bv_val );
384
385         rs->sr_err = LDAP_SUCCESS;
386         rs->sr_text = NULL;
387         if( num_ctrls ) {
388                 rs->sr_ctrls = ctrls;
389         }
390
391 return_results:
392         if ( rs->sr_err == LDAP_SUCCESS && parent_is_glue && parent_is_leaf ) {
393                 op->o_delete_glue_parent = 1;
394         }
395
396         if ( p != NULL ) {
397                 wt_entry_return( p );
398         }
399
400         /* free entry */
401         if( e != NULL ) {
402                 wt_entry_return( e );
403         }
404
405         send_ldap_result( op, rs );
406         slap_graduate_commit_csn( op );
407
408         if( preread_ctrl != NULL && (*preread_ctrl) != NULL ) {
409                 slap_sl_free( (*preread_ctrl)->ldctl_value.bv_val, op->o_tmpmemctx );
410                 slap_sl_free( *preread_ctrl, op->o_tmpmemctx );
411         }
412
413         /* TODO: checkpoint */
414
415         return rs->sr_err;
416 }
417
418 /*
419  * Local variables:
420  * indent-tabs-mode: t
421  * tab-width: 4
422  * c-basic-offset: 4
423  * End:
424  */