struct bdb_info *bdb = (struct bdb_info *) be->be_private;
char *pdn = NULL;
Entry *p = NULL;
- int rootlock = 0;
int rc;
const char *text = NULL;
AttributeDescription *children = slap_schema.si_ad_children;
DB_TXN *ltid = NULL;
-
Debug(LDAP_DEBUG_ARGS, "==> bdb_add: %s\n", e->e_dn, 0, 0);
/* check entry's schema */
goto return_results;
}
+ if (0) {
+retry: rc = txn_abort( ltid );
+ ltid = NULL;
+ op->o_private = NULL;
+ if( rc != 0 ) {
+ rc = LDAP_OTHER;
+ text = "internal error";
+ goto return_results;
+ }
+ }
+
/* begin transaction */
rc = txn_begin( bdb->bi_dbenv, NULL, <id, 0 );
if( rc != 0 ) {
text = "internal error";
goto return_results;
}
+
+ op->o_private = ltid;
/*
* Get the parent dn and see if the corresponding entry exists.
Entry *matched = NULL;
/* get parent with reader lock */
- p = dn2entry_r( be, ltid, pdn, &matched );
+ rc = dn2entry_r( be, ltid, pdn, &p, &matched );
+ ch_free( pdn );
+
+ switch( rc ) {
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
+ default:
+ rc = LDAP_OTHER;
+ text = "internal error";
+ goto return_results;
+ }
+
if ( p == NULL ) {
char *matched_dn;
struct berval **refs;
- ch_free( pdn );
-
if ( matched != NULL ) {
matched_dn = ch_strdup( matched->e_dn );
refs = is_entry_referral( matched )
goto done;
}
- ch_free(pdn);
-
if ( ! access_allowed( be, conn, op, p,
children, NULL, ACL_WRITE ) )
{
goto done;
}
+ /* free parent and writer lock */
+ bdb_entry_return( be, p );
+ p = NULL;
+
} else {
if( pdn != NULL ) {
free(pdn);
if ( rc != 0 ) {
Debug( LDAP_DEBUG_TRACE, "bdb_add: dn2id_add failed: %s (%d)\n",
db_strerror(rc), rc, 0 );
- if( rc == DB_KEYEXIST ) {
+
+ switch( rc ) {
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
+ case DB_KEYEXIST:
rc = LDAP_ALREADY_EXISTS;
- } else {
+ break;
+ default:
rc = LDAP_OTHER;
}
goto return_results;
rc = txn_commit( ltid, 0 );
ltid = NULL;
+ op->o_private = NULL;
if( rc == 0 ) {
Debug( LDAP_DEBUG_TRACE,
return_results:
send_ldap_result( conn, op, rc,
- NULL, text, NULL, NULL );
-
+ NULL, text, NULL, NULL );
done:
if (p != NULL) {
if( ltid != NULL ) {
txn_abort( ltid );
+ op->o_private = NULL;
}
return rc;
--- /dev/null
+/* delete.c - ldbm backend delete routine */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "back-bdb.h"
+
+int
+bdb_delete(
+ Backend *be,
+ Connection *conn,
+ Operation *op,
+ const char *dn,
+ const char *ndn
+)
+{
+ struct bdb_info *bdb = (struct bdb_info *) be->be_private;
+ Entry *matched;
+ char *pdn = NULL;
+ Entry *e, *p = NULL;
+ int rc;
+ const char *text = NULL;
+ int manageDSAit = get_manageDSAit( op );
+ AttributeDescription *children = slap_schema.si_ad_children;
+ DB_TXN *ltid = NULL;
+
+ Debug(LDAP_DEBUG_ARGS, "==> bdb_delete: %s\n", dn, 0, 0);
+
+ if (0) {
+retry: rc = txn_abort( ltid );
+ ltid = NULL;
+ op->o_private = NULL;
+ if( rc != 0 ) {
+ rc = LDAP_OTHER;
+ text = "internal error";
+ goto return_results;
+ }
+ }
+
+ /* begin transaction */
+ rc = txn_begin( bdb->bi_dbenv, NULL, <id, 0 );
+ if( rc != 0 ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_delete: txn_begin failed: %s (%d)\n",
+ db_strerror(rc), rc, 0 );
+ rc = LDAP_OTHER;
+ text = "internal error";
+ goto return_results;
+ }
+
+ op->o_private = ltid;
+
+ pdn = dn_parent( be, e->e_ndn );
+
+ if( pdn != NULL && *pdn != '\0' ) {
+ /* get parent with reader lock */
+ rc = dn2entry_r( be, ltid, pdn, &p, NULL );
+
+ ch_free( pdn );
+
+ switch( rc ) {
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
+ default:
+ rc = LDAP_OTHER;
+ text = "internal error";
+ goto return_results;
+ }
+
+ if( p == NULL) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<=- bdb_delete: parent does not exist\n",
+ 0, 0, 0);
+ rc = LDAP_OTHER;
+ text = "could not locate parent of entry";
+ goto return_results;
+ }
+
+ /* check parent for "children" acl */
+ rc = access_allowed( be, conn, op, p,
+ children, NULL, ACL_WRITE );
+
+ bdb_entry_return( be, p );
+
+ if ( !rc ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<=- bdb_delete: no access to parent\n",
+ 0, 0, 0 );
+ rc = LDAP_INSUFFICIENT_ACCESS;
+ goto return_results;
+ }
+
+ } else {
+ ch_free( pdn );
+
+ /* no parent, must be root to delete */
+ if( ! be_isroot( be, op->o_ndn ) ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<=- bdb_delete: no parent and not root\n",
+ 0, 0, 0);
+ rc = LDAP_INSUFFICIENT_ACCESS;
+ goto return_results;
+ }
+ }
+
+ /* get entry */
+ rc = dn2entry_w( be, ltid, ndn, &e, &matched );
+
+ switch( rc ) {
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
+ default:
+ rc = LDAP_OTHER;
+ text = "internal error";
+ goto return_results;
+ }
+
+ if ( e == NULL ) {
+ char *matched_dn = NULL;
+ struct berval **refs = NULL;
+
+ Debug( LDAP_DEBUG_ARGS,
+ "<=- bdb_delete: no such object %s\n",
+ dn, 0, 0);
+
+ if ( matched != NULL ) {
+ matched_dn = ch_strdup( matched->e_dn );
+ refs = is_entry_referral( matched )
+ ? get_entry_referrals( be, conn, op, matched )
+ : NULL;
+ bdb_entry_return( be, matched );
+ } else {
+ refs = default_referral;
+ }
+
+ send_ldap_result( conn, op, LDAP_REFERRAL,
+ matched_dn, NULL, refs, NULL );
+
+ if ( matched != NULL ) {
+ ber_bvecfree( refs );
+ free( matched_dn );
+ }
+
+ rc = -1;
+ goto done;
+ }
+
+ if ( !manageDSAit && is_entry_referral( e ) ) {
+ /* parent is a referral, don't allow add */
+ /* parent is an alias, don't allow add */
+ struct berval **refs = get_entry_referrals( be,
+ conn, op, e );
+
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_delete: entry is referral\n",
+ 0, 0, 0 );
+
+ send_ldap_result( conn, op, LDAP_REFERRAL,
+ e->e_dn, NULL, refs, NULL );
+
+ ber_bvecfree( refs );
+
+ rc = 1;
+ goto done;
+ }
+
+
+ if ( bdb_has_children( be, e ) ) {
+ Debug(LDAP_DEBUG_ARGS,
+ "<=- bdb_delete: non leaf %s\n",
+ dn, 0, 0);
+ rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
+ text = "subtree delete not supported";
+ goto return_results;
+ }
+
+ /* delete from dn2id mapping */
+ if ( bdb_dn2id_delete( be, e->e_ndn, e->e_id ) != 0 ) {
+ Debug(LDAP_DEBUG_ARGS,
+ "<=- ldbm_back_delete: operations error %s\n",
+ dn, 0, 0);
+ rc = LDAP_OTHER;
+ text = "DN index delete failed";
+ goto return_results;
+ }
+
+ /* delete from disk and cache */
+ if ( bdb_id2entry_delete( be, e ) != 0 ) {
+ Debug(LDAP_DEBUG_ARGS,
+ "<=- bdb_delete: operations error %s\n",
+ dn, 0, 0);
+ rc = LDAP_OTHER;
+ text = "entry delete failed";
+ goto return_results;
+ }
+
+ rc = txn_commit( ltid, 0 );
+ ltid = NULL;
+ op->o_private = NULL;
+
+ if( rc == 0 ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_add: txn_commit failed: %s (%d)\n",
+ db_strerror(rc), rc, 0 );
+ rc = LDAP_OTHER;
+ text = "commit failed";
+ } else {
+ Debug( LDAP_DEBUG_TRACE,
+ "bdb_add: added id=%08x dn=\"%s\"\n",
+ e->e_id, e->e_dn, 0 );
+ rc = LDAP_SUCCESS;
+ text = NULL;
+ }
+
+return_results:
+ send_ldap_result( conn, op, LDAP_SUCCESS,
+ NULL, text, NULL, NULL );
+
+done:
+ /* free entry and writer lock */
+ bdb_entry_return( be, e );
+
+ if( ltid != NULL ) {
+ txn_abort( ltid );
+ op->o_private = NULL;
+ }
+
+ return rc;
+}
DBT key, data;
DB_TXN *ltid;
- rc = txn_begin( bdb->bi_dbenv, tid, <id, 0 );
- if( rc != 0 ) {
- return rc;
- }
-
DBTzero( &key );
key.data = (char *) &kid;
key.size = sizeof( kid );
data.ulen = sizeof( id );
data.flags = DB_DBT_USERMEM;
- /* get exiting value (with write lock) */
+ if( 0 ) {
+retry: if( tid != NULL ) {
+ /* nested transaction, abort and return */
+ (void) txn_abort( ltid );
+ return rc;
+ }
+ rc = txn_abort( ltid );
+ if( rc != 0 ) {
+ return rc;
+ }
+ }
+
+ rc = txn_begin( bdb->bi_dbenv, tid, <id, 0 );
+ if( rc != 0 ) {
+ return rc;
+ }
+
+ /* get existing value for read/modify/write */
rc = bdb->bi_nextid->bdi_db->get( bdb->bi_nextid->bdi_db,
ltid, &key, &data, DB_RMW );
- if( rc == DB_NOTFOUND ) {
- /* must be first add */
+ switch(rc) {
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
+
+ case DB_NOTFOUND:
id = NOID;
+ break;
- } else if( rc != 0 ) {
- goto done;
+ case 0:
+ if ( data.size != sizeof(ID) ) {
+ /* size mismatch! */
+ rc = -1;
+ goto done;
+ }
+ break;
- } else if ( data.size != sizeof(ID) ) {
- /* size mismatch! */
- rc = -1;
+ default:
goto done;
}
id++;
- /* store new value */
+ /* put new value */
rc = bdb->bi_nextid->bdi_db->put( bdb->bi_nextid->bdi_db,
ltid, &key, &data, 0 );
- *out = id;
+ switch(rc) {
+ case DB_LOCK_DEADLOCK:
+ case DB_LOCK_NOTGRANTED:
+ goto retry;
-done:
- if( rc != 0 ) {
- (void) txn_abort( ltid );
- } else {
+ case 0:
+ *out = id;
rc = txn_commit( ltid, 0 );
+ break;
+
+ default:
+done: (void) txn_abort( ltid );
}
return rc;
const char *dn,
ID id );
-Entry * bdb_dn2entry_rw LDAP_P(( Backend *be, DB_TXN *tid,
- const char *dn, Entry **matched, int rw ));
+int bdb_dn2entry_rw LDAP_P(( Backend *be, DB_TXN *tid,
+ const char *dn, Entry **e, Entry **matched, int rw ));
-#define dn2entry_r(be, tid, dn, m) bdb_dn2entry_rw((be), (tid), (dn), (m), 0)
-#define dn2entry_w(be, tid, dn, m) bdb_dn2entry_rw((be), (tid), (dn), (m), 1)
+#define dn2entry_r(be, tid, dn, p, m) bdb_dn2entry_rw((be), (tid), (dn), (p), (m), 0)
+#define dn2entry_w(be, tid, dn, p, m) bdb_dn2entry_rw((be), (tid), (dn), (p), (m), 1)
/*
* entry.c