diff options
author | cvsadm <cvsadm> | 2005-01-21 00:44:34 +0000 |
---|---|---|
committer | cvsadm <cvsadm> | 2005-01-21 00:44:34 +0000 |
commit | b2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch) | |
tree | cf58939393a9032182c4fbc4441164a9456e82f8 /ldap/servers/plugins/retrocl/retrocl_po.c | |
download | ds-ldapserver7x.tar.gz ds-ldapserver7x.tar.xz ds-ldapserver7x.zip |
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'ldap/servers/plugins/retrocl/retrocl_po.c')
-rw-r--r-- | ldap/servers/plugins/retrocl/retrocl_po.c | 529 |
1 files changed, 529 insertions, 0 deletions
diff --git a/ldap/servers/plugins/retrocl/retrocl_po.c b/ldap/servers/plugins/retrocl/retrocl_po.c new file mode 100644 index 00000000..96512a51 --- /dev/null +++ b/ldap/servers/plugins/retrocl/retrocl_po.c @@ -0,0 +1,529 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#include "retrocl.h" + +static int +entry2reple( Slapi_Entry *e, Slapi_Entry *oe ); + +static int +mods2reple( Slapi_Entry *e, LDAPMod **ldm ); + +static int +modrdn2reple( Slapi_Entry *e, const char *newrdn, int deloldrdn, + LDAPMod **ldm, const char *newsup ); + +/******************************/ + +const char *attr_changenumber = "changenumber"; +const char *attr_targetdn = "targetdn"; +const char *attr_changetype = "changetype"; +const char *attr_newrdn = "newrdn"; +const char *attr_deleteoldrdn = "deleteoldrdn"; +const char *attr_changes = "changes"; +const char *attr_newsuperior = "newsuperior"; +const char *attr_changetime = "changetime"; +const char *attr_objectclass = "objectclass"; + +/* + * Function: make_changes_string + * + * Returns: + * + * Arguments: + * + * Description: + * loop through the LDAPMod struct and construct the changes attribute/ + * + */ + +static lenstr *make_changes_string(LDAPMod **ldm, const char **includeattrs) +{ + lenstr *l; + int i, j, len; + int skip; + + l = lenstr_new(); + + for ( i = 0; ldm[ i ] != NULL; i++ ) { + /* If a list of explicit attributes was given, only add those */ + if ( NULL != includeattrs ) { + skip = 1; + for ( j = 0; includeattrs[ j ] != NULL; j++ ) { + if ( strcasecmp( includeattrs[ j ], ldm[ i ]->mod_type ) == 0 ) { + skip = 0; + break; + } + } + if ( skip ) { + continue; + } + } + switch ( ldm[ i ]->mod_op & ~LDAP_MOD_BVALUES ) { + case LDAP_MOD_ADD: + addlenstr( l, "add: " ); + addlenstr( l, ldm[ i ]->mod_type ); + addlenstr( l, "\n" ); + break; + case LDAP_MOD_DELETE: + addlenstr( l, "delete: " ); + addlenstr( l, ldm[ i ]->mod_type ); + addlenstr( l, "\n" ); + break; + case LDAP_MOD_REPLACE: + addlenstr( l, "replace: " ); + addlenstr( l, ldm[ i ]->mod_type ); + addlenstr( l, "\n" ); + break; + } + for ( j = 0; ldm[ i ]->mod_bvalues != NULL && + ldm[ i ]->mod_bvalues[ j ] != NULL; j++ ) { + char *buf = NULL; + char *bufp = NULL; + + len = strlen( ldm[ i ]->mod_type ); + len = LDIF_SIZE_NEEDED( len, + ldm[ i ]->mod_bvalues[ j ]->bv_len ) + 1; + buf = slapi_ch_malloc( len ); + bufp = buf; + ldif_put_type_and_value( &bufp, ldm[ i ]->mod_type, + ldm[ i ]->mod_bvalues[ j ]->bv_val, + ldm[ i ]->mod_bvalues[ j ]->bv_len ); + *bufp = '\0'; + + addlenstr( l, buf ); + + free( buf ); + } + addlenstr( l, "-\n" ); + } + return l; +} + +/* + * Function: write_replog_db + * Arguments: be - backend to which this change is being applied + * optype - type of LDAP operation being logged + * dn - distinguished name of entry being changed + * log_m - pointer to the actual change operation on a modify + * flag - only used by modrdn operations - value of deleteoldrdn + * curtime - the current time + * Returns: nothing + * Description: Given a change, construct an entry which is to be added to the + * changelog database. + */ +static void +write_replog_db( + int optype, + char *dn, + LDAPMod **log_m, + int flag, + time_t curtime, + Slapi_Entry *log_e, + const char *newrdn, + LDAPMod **modrdn_mods, + const char *newsuperior +) +{ + char *pat, *edn; + struct berval *vals[ 2 ]; + struct berval val; + Slapi_Entry *e; + char chnobuf[ 20 ]; + int err; + Slapi_PBlock *pb = NULL; + changeNumber changenum; + + PR_Lock(retrocl_internal_lock); + changenum = retrocl_assign_changenumber(); + + PR_ASSERT( changenum > 0UL ); + slapi_log_error( SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, + "write_replog_db: write change record %d for dn: \"%s\"\n", + changenum, ( dn == NULL ) ? "NULL" : dn ); + + /* Construct the dn of this change record */ + pat = "%s=%lu,%s"; + edn = slapi_ch_malloc( strlen( pat ) + strlen( RETROCL_CHANGELOG_DN) + 20 ); + sprintf( edn, pat, attr_changenumber, changenum, RETROCL_CHANGELOG_DN); + + /* + * Create the entry struct, and fill in fields common to all types + * of change records. + */ + vals[ 0 ] = &val; + vals[ 1 ] = NULL; + + e = slapi_entry_alloc(); + slapi_entry_set_dn( e, slapi_ch_strdup( edn )); + + /* Set the objectclass attribute */ + val.bv_val = "top"; + val.bv_len = 3; + slapi_entry_add_values( e, "objectclass", vals ); + + val.bv_val = "changelogentry"; + val.bv_len = 14; + slapi_entry_add_values( e, "objectclass", vals ); + + /* Set the changeNumber attribute */ + sprintf( chnobuf, "%lu", changenum ); + val.bv_val = chnobuf; + val.bv_len = strlen( chnobuf ); + slapi_entry_add_values( e, attr_changenumber, vals ); + + /* Set the targetentrydn attribute */ + val.bv_val = dn; + val.bv_len = strlen( dn ); + slapi_entry_add_values( e, attr_targetdn, vals ); + + /* Set the changeTime attribute */ + val.bv_val = format_genTime (curtime); + val.bv_len = strlen( val.bv_val ); + slapi_entry_add_values( e, attr_changetime, vals ); + free( val.bv_val ); + + /* + * Finish constructing the entry. How to do it depends on the type + * of modification being logged. + */ + err = 0; + switch ( optype ) { + case OP_ADD: + if ( entry2reple( e, log_e ) != 0 ) { + err = 1; + } + break; + + case OP_MODIFY: + if ( mods2reple( e, log_m ) != 0 ) { + err = 1; + } + break; + + case OP_MODRDN: + if ( modrdn2reple( e, newrdn, flag, modrdn_mods, newsuperior ) != 0 ) { + err = 1; + } + break; + + case OP_DELETE: + /* Set the changetype attribute */ + val.bv_val = "delete"; + val.bv_len = 6; + slapi_entry_add_values( e, attr_changetype, vals ); + break; + default: + slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "replog: Unknown LDAP operation type " + "%d.\n", optype ); + err = 1; + } + + /* Call the repl backend to add this entry */ + if ( 0 == err ) { + int rc; + + pb = slapi_pblock_new (); + slapi_add_entry_internal_set_pb( pb, e, NULL /* controls */, + g_plg_identity[PLUGIN_RETROCL], + 0 /* actions */ ); + slapi_add_internal_pb (pb); + slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rc ); + slapi_pblock_destroy(pb); + if ( 0 != rc ) { + slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, + "replog: an error occured while adding change " + "number %d, dn = %s: %s. \n", + changenum, edn, ldap_err2string( rc )); + retrocl_release_changenumber(); + } else { + /* Tell the change numbering system this one's committed to disk */ + retrocl_commit_changenumber( ); + } + } else { + slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, + "An error occurred while constructing " + "change record number %ld.\n", changenum ); + retrocl_release_changenumber(); + } + PR_Unlock(retrocl_internal_lock); + if ( NULL != edn ) { + slapi_ch_free((void **) &edn); + } + +} + + +/* + * Function: entry2reple + * Arguments: e - a partially-constructed Slapi_Entry structure + * oe - the original entry (an entry being added by a client). + * Returns: 0 on success. + * Description: Given an Slapi_Entry struct, construct a changelog entry which will be + * added to the replication database. It is assumed that e points + * to an entry obtained from slapi_entry_alloc(). + */ +static int +entry2reple( Slapi_Entry *e, Slapi_Entry *oe ) +{ + char *p, *estr; + struct berval *vals[ 2 ]; + struct berval val; + int len; + + vals[ 0 ] = &val; + vals[ 1 ] = NULL; + + /* Set the changetype attribute */ + val.bv_val = "add"; + val.bv_len = 3; + slapi_entry_add_values( e, attr_changetype, vals ); + + estr = slapi_entry2str( oe, &len ); + p = estr; + /* Skip over the dn: line */ + while (( p = strchr( p, '\n' )) != NULL ) { + p++; + if ( !ldap_utf8isspace( p )) { + break; + } + } + val.bv_val = p; + val.bv_len = len - ( p - estr ); /* length + terminating \0 */ + slapi_entry_add_values( e, attr_changes, vals ); + free( estr ); + return 0; +} + +/* + * Function: mods2reple + * Arguments: e - a partially-constructed Slapi_Entry structure + * ldm - an array of pointers to LDAPMod structures describing the + * change applied. + * Returns: 0 on success. + * Description: Given a pointer to an LDAPMod struct and a dn, construct + * a new entry which will be added to the replication database. + * It is assumed that e points to an entry obtained from + * slapi_entry_alloc(). + */ +static int +mods2reple( Slapi_Entry *e, LDAPMod **ldm ) +{ + struct berval val; + struct berval *vals[ 2 ]; + lenstr *l; + + vals[ 0 ] = &val; + vals[ 1 ] = NULL; + + /* Set the changetype attribute */ + val.bv_val = "modify"; + val.bv_len = 6; + slapi_entry_add_values( e, "changetype", vals ); + + if (NULL != ldm) { + l = make_changes_string( ldm, NULL ); + if ( NULL != l ) { + val.bv_val = l->ls_buf; + val.bv_len = l->ls_len + 1; /* string + terminating \0 */ + slapi_entry_add_values( e, attr_changes, vals ); + lenstr_free( &l ); + } + } + return 0; +} + + +/* + * Function: modrdn2reple + * Arguments: e - a partially-constructed Slapi_Entry structure + * newrdn - the new relative distinguished name for the entry + * deloldrdn - the "deleteoldrdn" flag provided by the client + * ldm - any modifications applied as a side-effect of the modrdn + * Returns: 0 on success + * Description: Given a dn, a new rdn, and a deleteoldrdn flag, construct + * a new entry which will be added to the replication database reflecting a + * completed modrdn operation. The entry has the same form as above. + * It is assumed that e points to an entry obtained from slapi_entry_alloc(). + */ +static int +modrdn2reple( + Slapi_Entry *e, + const char *newrdn, + int deloldrdn, + LDAPMod **ldm, + const char *newsuperior +) +{ + struct berval val; + struct berval *vals[ 2 ]; + lenstr *l; + static const char *lastmodattrs[] = {"modifiersname", "modifytimestamp", + "creatorsname", "createtimestamp", + NULL }; + + vals[ 0 ] = &val; + vals[ 1 ] = NULL; + + val.bv_val = "modrdn"; + val.bv_len = 6; + slapi_entry_add_values( e, attr_changetype, vals ); + + if (newrdn) { + val.bv_val = (char *)newrdn; /* cast away const */ + val.bv_len = strlen( newrdn ); + slapi_entry_add_values( e, attr_newrdn, vals ); + } + + if ( deloldrdn == 0 ) { + val.bv_val = "FALSE"; + val.bv_len = 5; + } else { + val.bv_val = "TRUE"; + val.bv_len = 4; + } + slapi_entry_add_values( e, attr_deleteoldrdn, vals ); + + if (newsuperior) { + val.bv_val = (char *)newsuperior; /* cast away const */ + val.bv_len = strlen(newsuperior); + slapi_entry_add_values(e, attr_newsuperior,vals); + } + + if (NULL != ldm) { + l = make_changes_string( ldm, lastmodattrs ); + if ( NULL != l ) { + val.bv_val = l->ls_buf; + val.bv_len = l->ls_len + 1; /* string + terminating \0 */ + slapi_entry_add_values( e, attr_changes, vals ); + lenstr_free( &l ); + } + } + + return 0; +} + +/* + * Function: retrocl_postob + * + * Returns: 0 on success + * + * Arguments: pblock, optype (add, del, modify etc) + * + * Description: called from retrocl.c op-specific plugins. + * + * Please be aware that operation threads may be scheduled out between their + * being performed inside of the LDBM database and the changelog plugin + * running. For example, suppose MA and MB are two modify operations on the + * same entry. MA may be performed on the LDBM database, and then block + * before the changelog runs. MB then runs against the LDBM database and then + * is written to the changelog. MA starts running. In the changelog, MB will + * appear to have been performed before MA, but in the LDBM database the + * opposite will have occured. + * + * + */ + +int retrocl_postob (Slapi_PBlock *pb,int optype) +{ + char *dn; + LDAPMod **log_m = NULL; + int flag = 0; + Slapi_Entry *te = NULL; + Slapi_Operation *op = NULL; + LDAPMod **modrdn_mods = NULL; + char *newrdn = NULL; + char *newsuperior = NULL; + Slapi_Backend *be = NULL; + time_t curtime; + int rc; + + /* + * Check to see if the change was made to the replication backend db. + * If so, don't try to log it to the db (otherwise, we'd get in a loop). + */ + + (void)slapi_pblock_get( pb, SLAPI_BACKEND, &be ); + + if (slapi_be_logchanges(be) == 0) { + LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if not logging\n", + 0,0,0); + return 0; + } + + if (retrocl_be_changelog == NULL || be == retrocl_be_changelog) { + LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if no/cl be\n",0,0,0); + return 0; + } + + slapi_pblock_get(pb, SLAPI_RESULT_CODE, &rc); + + if (rc != LDAP_SUCCESS) { + LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if op failed %d\n",rc, + 0,0); + return 0; + } + + if (slapi_op_abandoned(pb)) { + LDAPDebug(LDAP_DEBUG_PLUGIN,"not applying change if op abandoned\n", + 0,0,0); + return 0; + } + + curtime = current_time(); + + (void)slapi_pblock_get( pb, SLAPI_ORIGINAL_TARGET_DN, &dn ); + + /* change number could be retrieved from Operation extension stored in + * the pblock, or else it needs to be made dynamically. */ + + /* get the operation extension and retrieve the change number */ + slapi_pblock_get( pb, SLAPI_OPERATION, &op ); + + if (op == NULL) { + LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if no op\n",0,0,0); + return 0; + } + + if (operation_is_flag_set(op, OP_FLAG_TOMBSTONE_ENTRY)){ + LDAPDebug(LDAP_DEBUG_TRACE,"not applying change for nsTombstone entries\n",0,0,0); + return 0; + } + + switch ( optype ) { + case OP_MODIFY: + (void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &log_m ); + break; + case OP_ADD: + /* + * For adds, we want the unnormalized dn, so we can preserve + * spacing, case, when replicating it. + */ + (void)slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &te ); + if ( NULL != te ) { + dn = slapi_entry_get_dn( te ); + } + break; + case OP_DELETE: + break; + case OP_MODRDN: + (void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn ); + (void)slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &flag ); + (void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &modrdn_mods ); + (void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR, &newsuperior); + break; + } + + + /* check if we should log change to retro changelog, and + * if so, do it here */ + write_replog_db( optype, dn, log_m, flag, curtime, te, + newrdn, modrdn_mods, newsuperior ); + + return 0; +} + + |