diff options
Diffstat (limited to 'ldap/servers/plugins/replication/cl4_api.c')
-rw-r--r-- | ldap/servers/plugins/replication/cl4_api.c | 797 |
1 files changed, 797 insertions, 0 deletions
diff --git a/ldap/servers/plugins/replication/cl4_api.c b/ldap/servers/plugins/replication/cl4_api.c new file mode 100644 index 00000000..135b4a5b --- /dev/null +++ b/ldap/servers/plugins/replication/cl4_api.c @@ -0,0 +1,797 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/* cl4_api.h - implementation of the minimal interface to 4.0 changelog necessary to + link 4.0 changelog to 5.0 replication + */ + +#include "repl.h" +#include "cl4_api.h" +#include "csnpl.h" +#include "cl4.h" + +/*** Data Structures ***/ + +/* changelog internal data */ +typedef struct cl4priv +{ + CSNPL *csnPL; /* csn pending list */ + int regID; /* csn function registration id */ +}CL4Private; + +/* callback data to get result of internal operations */ +typedef struct cl4ret +{ + int err; /* error code */ + Slapi_Entry *e; /* target entry */ +}CL4Ret; + +/* Global Data */ +static CL4Private s_cl4Desc; /* represents changelog state */ + +/*** Helper functions forward declarations ***/ +static int _cl4WriteOperation (const slapi_operation_parameters *op); +static void _cl4AssignCSNCallback (const CSN *csn, void *data); +static void _cl4AbortCSNCallback (const CSN *csn, void *data); +static char* _cl4MakeCSNDN (const CSN* csn); +static int _cl4GetEntry (const CSN *csn, Slapi_Entry **entry); +static void _cl4ResultCallback (int err, void *callback_data); +static int _cl4EntryCallback (Slapi_Entry *e, void *callback_data); +static PRBool _cl4CanAssignChangeNumber (const CSN *csn); +static int _cl4ResolveTargetDN (Slapi_Entry *entry, Slapi_DN **newTargetDN); +static int _cl4GetTargetEntry (Slapi_DN *targetDN, const char *uniqueid, Slapi_Entry **entry); +static int _cl4FindTargetDN (const CSN *csn, const char *uniqueid, + const Slapi_DN *targetSDN, Slapi_DN **newTargetDN); +static int _cl4AssignChangeNumber (changeNumber *cnum); +static int _cl4UpdateEntry (const CSN *csn, const char *changeType, const Slapi_DN *newTargetDN, changeNumber cnum); + +/*** API ***/ +int cl4Init () +{ + s_cl4Desc.csnPL = csnplNew (); + if (s_cl4Desc.csnPL == NULL) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4Init: failed to create CSN pending list\n"); + return CL4_CSNPL_ERROR; + } + + s_cl4Desc.regID = csnRegisterNewCSNCb(_cl4AssignCSNCallback, NULL, + _cl4AbortCSNCallback, NULL); + + return CL4_SUCCESS; +} + +void cl4Cleanup () +{ + if (s_cl4Desc.regID >= 0) + { + csnRemoveNewCSNCb(s_cl4Desc.regID); + s_cl4Desc.regID = -1; + } + + if (s_cl4Desc.csnPL == NULL) + csnplFree (&s_cl4Desc.csnPL); +} + +int cl4WriteOperation (const slapi_operation_parameters *op) +{ + int rc; + ReplicaId rd; + + if (op == NULL || !IsValidOperation (op)) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4WriteEntry: invalid entry\n"); + return CL4_BAD_DATA; + } + + rc = _cl4WriteOperation (op); + if (rc != CL4_SUCCESS) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4WriteEntry: failed to write changelog entry\n"); + return rc; + } + + /* the entry is generated by this server - remove the entry from the pending list */ + rd= csn_get_replicaid(op->csn); + if (rd == slapi_get_replicaid ()) + { + rc = csnplRemove (s_cl4Desc.csnPL, op->csn); + + if (rc != 0) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "cl4WriteEntry: failed to remove CSN from the pending list\n"); + rc = CL4_CSNPL_ERROR; + } + } + + return rc; +} + +int cl4ChangeTargetDN (const CSN *csn, const char *newDN) +{ + Slapi_PBlock *pb; + char *changeEntryDN; + Slapi_Mods smods; + int res; + + if (csn == NULL || newDN == NULL) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4ChangeTargetDN: invalid argument\n"); + return CL4_BAD_DATA; + } + + /* construct dn of the change entry */ + changeEntryDN = _cl4MakeCSNDN (csn); + if (changeEntryDN == NULL) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "cl4ChangeTargetDN: failed to construct change entry dn\n"); + return CL4_MEMORY_ERROR; + } + + pb = slapi_pblock_new (); + + slapi_mods_init(&smods, 1); + slapi_mods_add(&smods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, attr_targetdn, + strlen (newDN), newDN); + slapi_modify_internal_set_pb(pb, changeEntryDN, slapi_mods_get_ldapmods_byref(&smods), + NULL, NULL, repl_get_plugin_identity(PLUGIN_LEGACY_REPLICATION), 0); + slapi_modify_internal_pb (pb); + + slapi_mods_done(&smods); + slapi_ch_free ((void**)&changeEntryDN); + + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res); + slapi_pblock_destroy(pb); + + if (res != LDAP_SUCCESS) + { + char s[CSN_STRSIZE]; + slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, + "cl4ChangeTargetDN: an error occured while modifying change entry with csn %s: %s. " + "Logging of changes is disabled.\n", csn_as_string(csn,PR_FALSE,s), ldap_err2string(res)); + /* GGOODREPL g_set_repl_backend( NULL ); */ + return CL4_LDAP_ERROR; + } + + return CL4_SUCCESS; +} + +void cl4AssignChangeNumbers (time_t when, void *arg) +{ + int rc = CL4_SUCCESS; + Slapi_Entry *entry; + CSN *csn = NULL; + Slapi_DN *newTargetDN; + changeNumber cnum; + char *changetype; + + /* we are looping though the entries ready to be commited updating there target dn + and assigning change numbers */ + while (_cl4GetEntry (csn, &entry) == CL4_SUCCESS) + { + /* ONREPL - I think we need to free previous csn */ + csn = csn_new_by_string(slapi_entry_attr_get_charptr (entry, attr_csn)); + /* all conflicts involving this entry have been resolved */ + if (_cl4CanAssignChangeNumber (csn)) + { + /* figure out the name of the target entry that corresponds to change csn */ + rc = _cl4ResolveTargetDN (entry, &newTargetDN); + slapi_entry_free (entry); + if (rc != CL4_SUCCESS) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4AssignChangeNumbers: failed to resolve target dn\n"); + break; + } + + _cl4AssignChangeNumber (&cnum); + + changetype = slapi_entry_attr_get_charptr (entry, attr_changetype); + + /* update change entry: write change number and remove csn attribute. + Note that we leave uniqueid in the entry to avoid an extra update. + This is ok since uniqueid is an operational attribute not returned + to the client by default. */ + rc = _cl4UpdateEntry (csn, changetype, newTargetDN, cnum); + if (newTargetDN) + { + slapi_sdn_free (&newTargetDN); + } + + slapi_ch_free ((void**)&changetype); + + if (rc != CL4_SUCCESS) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "cl4AssignChangeNumbers: failed to update changelog entry\n"); + break; + } + } + else /* went too far */ + { + slapi_entry_free (entry); + break; + } + } +} + + +/*** Helper Functions ***/ + +/* adds new change record to 4.0 changelog */ +static int _cl4WriteOperation (const slapi_operation_parameters *op) +{ + int rc = CL4_SUCCESS, res; + char *changeEntryDN, *timeStr; + Slapi_Entry *e; + Slapi_PBlock *pb = NULL; + Slapi_Value *values[3]; + char s[CSN_STRSIZE]; + + slapi_log_error (SLAPI_LOG_PLUGIN, repl_plugin_name, + "_cl4WriteEntry: writing change record with csn %s for dn: \"%s\"\n", + csn_as_string(op->csn,PR_FALSE,s), op->target_address.dn); + + /* create change entry dn */ + changeEntryDN = _cl4MakeCSNDN (op->csn); + if (changeEntryDN == NULL) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "_cl4WriteEntry: failed to create entry dn\n"); + return CL4_MEMORY_ERROR; + } + + /* + * Create the entry struct, and fill in fields common to all types + * of change records. + */ + e = slapi_entry_alloc(); + if (e == NULL) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "_cl4WriteEntry: failed to allocate change entry\n"); + return CL4_MEMORY_ERROR; + } + + slapi_entry_set_dn(e, slapi_ch_strdup (changeEntryDN)); + + /* Set the objectclass attribute */ + values [0] = slapi_value_new (NULL); + values [1] = slapi_value_new (NULL); + values [2] = NULL; + slapi_value_set_string(values[0], "top"); + slapi_value_set_string(values[1], "changelogentry"); + slapi_entry_add_values_sv (e, "objectclass", values); + + /* ONREPL - for now we have to free Slapi_Values since api makes copy; + this will change when a new set of api is added */ + slapi_value_free (&(values[0])); + slapi_value_free (&(values[1])); + + /* Set the changeNumber attribute */ + /* Need to set this because it is required by schema */ + slapi_entry_attr_set_charptr (e, attr_changenumber, "0"); + + /* Set the targetentrydn attribute */ + if (op->operation_type == SLAPI_OPERATION_ADD) /* use raw dn */ + slapi_entry_attr_set_charptr (e, attr_targetdn, slapi_entry_get_dn (op->p.p_add.target_entry)); + else /* use normolized dn */ + slapi_entry_attr_set_charptr (e, attr_targetdn, op->target_address.dn); + + /* ONREPL - set dbid attribute */ + + /* Set the changeTime attribute */ + timeStr = format_localTime (current_time()); + slapi_entry_attr_set_charptr (e, attr_changetime, timeStr); + slapi_ch_free((void**)&timeStr); + + /* + * Finish constructing the entry. How to do it depends on the type + * of modification being logged. + */ + switch (op->operation_type) + { + case SLAPI_OPERATION_ADD: if (entry2reple(e, op->p.p_add.target_entry) != 0 ) + { + rc = CL4_INTERNAL_ERROR; + goto done; + } + + break; + + case SLAPI_OPERATION_MODIFY: if (mods2reple(e, op->p.p_modify.modify_mods) != 0) + { + rc = CL4_INTERNAL_ERROR; + goto done; + } + + break; + + case SLAPI_OPERATION_MODDN: if (modrdn2reple(e, op->p.p_modrdn.modrdn_newrdn, + op->p.p_modrdn.modrdn_deloldrdn, op->p.p_modrdn.modrdn_mods) != 0) + { + rc = CL4_INTERNAL_ERROR; + goto done; + } + + break; + + case SLAPI_OPERATION_DELETE: /* Set the changetype attribute */ + slapi_entry_attr_set_charptr (e, attr_changetype, "delete"); + break; + } + + pb = slapi_pblock_new (pb); + slapi_add_entry_internal_set_pb (pb, e, NULL, repl_get_plugin_identity (PLUGIN_LEGACY_REPLICATION), 0); + slapi_add_internal_pb (pb); + + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res); + slapi_pblock_destroy(pb); + + if (res != LDAP_SUCCESS) + { + char s[CSN_STRSIZE]; + slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, + "_cl4WriteEntry: an error occured while adding change entry with csn %s, dn = %s: %s. " + "Logging of changes is disabled.\n", csn_as_string(op->csn,PR_FALSE,s), op->target_address.dn, + ldap_err2string(res)); + /* GGOODREPL g_set_repl_backend( NULL ); */ + rc = CL4_LDAP_ERROR; + } + +done: + if (changeEntryDN) + slapi_ch_free((void **) &changeEntryDN); + + return rc; +} + +static void _cl4AssignCSNCallback (const CSN *csn, void *data) +{ + int rc; + + if (csn == NULL) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4AssignCSNCallback: null csn\n"); + return; + } + + rc = csnplInsert (s_cl4Desc.csnPL, csn); + + if (rc == -1) + { + char s[CSN_STRSIZE]; + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "_cl4AssignCSNCallback: failed to insert csn %s to the pending list\n", + csn_as_string(csn,PR_FALSE,s)); + } +} + +static void _cl4AbortCSNCallback (const CSN *csn, void *data) +{ + int rc; + + if (csn == NULL) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4AbortCSNCallback: null csn\n"); + return; + } + + rc = csnplRemove (s_cl4Desc.csnPL, csn); + if (rc == -1) + { + char s[CSN_STRSIZE]; + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, + "_cl4AbortCSNCallback: failed to remove csn %s from the pending list\n", + csn_as_string(csn,PR_FALSE,s)); + } +} + +/* initial dn format: csn=<csn>,<changelog suffix>. For instance, csn=013744022939465,cn=changelog4 */ +static char* _cl4MakeCSNDN (const CSN* csn) +{ + char *pat, *edn; + char *suffix = changelog4_get_suffix (); + char s[CSN_STRSIZE]; + + if (suffix == NULL) + return NULL; + + /* Construct the dn of this change record */ + pat = "%s=%s,%s"; + edn = slapi_ch_malloc(strlen(pat) + strlen(attr_csn) + strlen(suffix) + CSN_STRSIZE + 1); + if (edn) + sprintf(edn, pat, attr_csn, csn_as_string(csn,PR_FALSE,s), suffix); + slapi_ch_free ((void **)&suffix); + + return edn; +} + +static int _cl4GetEntry (const CSN *csn, Slapi_Entry **entry) +{ + int rc; + char *suffix = changelog4_get_suffix (); + int type; + const char *value; + CL4Ret ret; + char s[CSN_STRSIZE]; + + if (csn == NULL) /* entry with smallest csn */ + { + type = SLAPI_SEQ_FIRST; + value = NULL; + } + else /* entry with next csn */ + { + type = SLAPI_SEQ_NEXT; + value = csn_as_string(csn,PR_FALSE,s); + } + + rc = slapi_seq_callback(suffix, type, attr_csn, (char*)value, NULL, 0, &ret, NULL, + _cl4ResultCallback, _cl4EntryCallback, NULL); + slapi_ch_free ((void**)&suffix); + + if (rc != 0 || ret.err != 0) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4GetEntry: failed to get next changelog entry\n"); + return CL4_INTERNAL_ERROR; + } + + *entry = ret.e; + return CL4_SUCCESS; +} + +static void _cl4ResultCallback (int err, void *callback_data) +{ + CL4Ret *ret = (CL4Ret *)callback_data; + + if (ret) + { + ret->err = err; + } +} + +static int _cl4EntryCallback (Slapi_Entry *e, void *callback_data) +{ + CL4Ret *ret = (CL4Ret *)callback_data; + + if (ret) + { + ret->e = slapi_entry_dup (e); + } + + return 0; +} + +static PRBool _cl4CanAssignChangeNumber (const CSN *csn) +{ + CSN *commitCSN = NULL; + + /* th CSN is withtin region that can be commited */ + if (csn && csn_compare(csn, commitCSN) < 0) + return PR_TRUE; + + return PR_FALSE; +} + +/* ONREPL - describe algorithm */ +static int _cl4ResolveTargetDN (Slapi_Entry *entry, Slapi_DN **newTargetDN) +{ + int rc; + char *csnStr = slapi_entry_attr_get_charptr (entry, attr_csn); + char *targetdn = slapi_entry_attr_get_charptr (entry, attr_targetdn); + const char *uniqueid = slapi_entry_get_uniqueid (entry); + char *changetype = slapi_entry_attr_get_charptr (entry, attr_changetype); + CSN *csn = csn_new_by_string (csnStr); + Slapi_Entry *targetEntry = NULL; + const Slapi_DN *teSDN; + Slapi_DN *targetSDN; + const CSN *teDNCSN = NULL; + + *newTargetDN = NULL; + + targetSDN = slapi_sdn_new(); + if (strcasecmp (changetype, "add") == 0) /* this is add operation - we have rawdn */ + slapi_sdn_set_dn_byref (targetSDN, targetdn); + else + slapi_sdn_set_ndn_byref (targetSDN, targetdn); + + /* read the entry to which the change was applied */ + rc = _cl4GetTargetEntry (targetSDN, uniqueid, &targetEntry); + if (rc != CL4_SUCCESS) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4ResolveTargetDN: failed to get target entry\n"); + goto done; + } + + teDNCSN = entry_get_dncsn(targetEntry); + if (teDNCSN == NULL) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4ResolveTargetDN: failed to get target entry dn\n"); + rc = CL4_BAD_FORMAT; + goto done; + } + + if (csn_compare(teDNCSN, csn) <= 0) + { + /* the change entry target dn should be the same as target entry dn */ + teSDN = slapi_entry_get_sdn_const(targetEntry); + + /* target dn of change entry is not the same as dn of the target entry - update */ + if (slapi_sdn_compare (teSDN, targetSDN) != 0) + { + *newTargetDN = slapi_sdn_dup (targetSDN); + } + } + else /* the target entry was renamed since this change occur - find the right target dn */ + { + rc = _cl4FindTargetDN (csn, uniqueid, targetSDN, newTargetDN); + } + +done:; + if (csnStr) + slapi_ch_free ((void**)&csnStr); + + if (targetdn) + slapi_ch_free ((void**)&targetdn); + + if (uniqueid) + slapi_ch_free ((void**)&uniqueid); + + if (changetype) + slapi_ch_free ((void**)&changetype); + + if (targetEntry) + slapi_entry_free (targetEntry); + + if (targetSDN) + slapi_sdn_free (&targetSDN); + + return rc; +} + +static int _cl4GetTargetEntry (Slapi_DN *sdn, const char *uniqueid, Slapi_Entry **entry) +{ + Slapi_PBlock *pb; + char filter [128]; + int res, rc = CL4_SUCCESS; + Slapi_Entry **entries = NULL; + + /* read corresponding database entry based on its uniqueid */ + sprintf (filter, "uniqueid=%s", uniqueid); + pb = slapi_pblock_new (); + slapi_search_internal_set_pb (pb, (char*)slapi_sdn_get_ndn(sdn), LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL, + repl_get_plugin_identity (PLUGIN_LEGACY_REPLICATION), 0); + slapi_search_internal_pb (pb); + + if (pb == NULL) + { + rc = CL4_LDAP_ERROR; + goto done; + } + + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res); + if (res == LDAP_NO_SUCH_OBJECT) /* entry not found */ + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4GetTargetEntry: entry (%s) not found\n", + slapi_sdn_get_ndn(sdn)); + rc = CL4_NOT_FOUND; + goto done; + } + + if (res != LDAP_SUCCESS) + { + slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, + "_cl4ResolveTargetDN: an error occured while searching for directory entry with uniqueid %s: %s. " + "Logging of changes is disabled.\n", uniqueid, ldap_err2string(res)); + /* GGOODREPL g_set_repl_backend( NULL ); */ + rc = CL4_LDAP_ERROR; + goto done; + } + + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); + if (entries == NULL || entries [0] == NULL) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4GetTargetEntry: entry (%s) not found\n", + slapi_sdn_get_ndn(sdn)); + rc = CL4_NOT_FOUND; + goto done; + } + + *entry = slapi_entry_dup (entries[0]); + +done: + if (pb) + { + slapi_free_search_results_internal(pb); + slapi_pblock_destroy (pb); + } + + return rc; +} + +static int _cl4FindTargetDN (const CSN *csn, const char *uniqueid, + const Slapi_DN *targetSDN, Slapi_DN **newTargetDN) +{ + int rc = CL4_SUCCESS; + int res, i; + Slapi_PBlock *pb; + char *suffix = changelog4_get_suffix (); + char filter [128]; + Slapi_Entry **entries; + int minIndex = 0; + CSN *minCSN = NULL, *curCSN; + char *curType; + const Slapi_DN *sdn; + char s[CSN_STRSIZE]; + + *newTargetDN = NULL; + + /* Look for all modifications to the target entry with csn larger than + this csn. We are only interested in rename operations, but change type + is currently not indexed */ + sprintf (filter, "&(uniqueid=%s)(csn>%s)", uniqueid, csn_as_string(csn,PR_FALSE,s)); + pb = slapi_pblock_new (); + slapi_search_internal_set_pb (pb, suffix, LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL, + repl_get_plugin_identity (PLUGIN_LEGACY_REPLICATION), 0); + slapi_search_internal_pb (pb); + slapi_ch_free ((void**)&suffix); + if (pb == NULL) + { + rc = CL4_LDAP_ERROR; + goto done; + } + + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res); + if (res == LDAP_NO_SUCH_OBJECT) /* entry not found */ + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4FindTargetDN: no entries much filter (%s)\n", + filter); + rc = CL4_NOT_FOUND; + goto done; + } + + if (res != LDAP_SUCCESS) + { + slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, + "_cl4ResolveTargetDN: an error occured while searching change entries matching filter %s: %s. " + "Logging of changes is disabled.\n", filter, ldap_err2string(res)); + /* GGOODREPL g_set_repl_backend( NULL ); */ + rc = CL4_LDAP_ERROR; + goto done; + } + + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); + if (entries == NULL) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4FindTargetDN: no entries much filter (%s)\n", + filter); + rc = CL4_NOT_FOUND; + goto done; + } + + i = 0; + + /* find rename operation with smallest csn - its target dn should be the name + of our change entry */ + while (entries[i]) + { + curType = slapi_entry_attr_get_charptr (entries[i], attr_changetype); + if (curType && strcasecmp (curType, "modrdn") == 0) + { + curCSN = csn_new_by_string (slapi_entry_attr_get_charptr (entries[i], attr_csn)); + if (minCSN == NULL || csn_compare (curCSN, minCSN) < 0) + { + minCSN = curCSN; + minIndex = i; + } + } + + if (curType) + slapi_ch_free ((void**)&curType); + + i ++; + } + + if (curCSN == NULL) + { + rc = CL4_NOT_FOUND; + goto done; + } + + /* update targetDN of our entry if necessary */ + sdn = slapi_entry_get_sdn_const(entries[minIndex]); + + /* target dn does not match to renaming operation - rename change entry */ + if (slapi_sdn_compare (sdn, targetSDN) != 0) + *newTargetDN = slapi_sdn_dup (sdn); + +done: + if (pb) + { + slapi_free_search_results_internal(pb); + slapi_pblock_destroy (pb); + } + + return rc; +} + +static int _cl4AssignChangeNumber (changeNumber *cnum) +{ + *cnum = ldapi_assign_changenumber(); + return CL4_SUCCESS; +} + +static int _cl4UpdateEntry (const CSN *csn, const char *changeType, + const Slapi_DN *newDN, changeNumber cnum) +{ + Slapi_PBlock *pb; + char *dn; + const char *dnTemp; + int res; + Slapi_Mods smods; + char cnumbuf[32]; + + if (csn == NULL || changeType == NULL) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4UpdateEntry: invalid argument\n"); + return CL4_BAD_DATA; + } + + dn = _cl4MakeCSNDN (csn); + if (dn == NULL) + { + slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4UpdateEntry: failed to create entry dn\n"); + return CL4_MEMORY_ERROR; + } + + slapi_mods_init(&smods, 2); + if (newDN) + { + if (strcasecmp (changeType, "add") == 0) + dnTemp = slapi_sdn_get_dn (newDN); + else + dnTemp = slapi_sdn_get_ndn (newDN); + + slapi_mods_add(&smods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, attr_targetdn, + strlen (dnTemp), dnTemp); + } + /* Set the changeNumber attribute */ + sprintf(cnumbuf, "%lu", cnum); + slapi_mods_add (&smods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, attr_changenumber, + strlen (cnumbuf), cnumbuf); + pb = slapi_pblock_new (); + slapi_modify_internal_set_pb (pb, dn, slapi_mods_get_ldapmods_byref(&smods), NULL, NULL, + repl_get_plugin_identity (PLUGIN_LEGACY_REPLICATION), 0); + slapi_modify_internal_pb (pb); + slapi_mods_done(&smods); + slapi_ch_free ((void**)&dn); + + if (pb == NULL) + { + return CL4_LDAP_ERROR; + } + + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res); + slapi_pblock_destroy(pb); + if (res != LDAP_SUCCESS) + { + char s[CSN_STRSIZE]; + slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, + "cl4ChangeTargetDN: an error occured while modifying change entry with csn %s: %s. " + "Logging of changes is disabled.\n", csn_as_string(csn,PR_FALSE,s), ldap_err2string(res)); + /* GGOODREPL g_set_repl_backend( NULL ); */ + return CL4_LDAP_ERROR; + } + + if ( ldapi_get_first_changenumber() == (changeNumber) 0L ) + { + ldapi_set_first_changenumber( cnum ); + } + + ldapi_commit_changenumber(cnum); + return CL4_SUCCESS; +} |