entrywsi.c 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* entrywsi.c - routines for dealing with entries... With State Information */
  42. #include "slap.h"
  43. #include "slapi-plugin.h"
  44. static void resolve_attribute_state(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, int delete_priority);
  45. static int
  46. entry_present_value_to_deleted_value(Slapi_Attr *a, Slapi_Value *v)
  47. {
  48. Slapi_Value *r= valueset_remove_value(a, &a->a_present_values, v);
  49. if(r!=NULL)
  50. {
  51. slapi_valueset_add_value_ext(&a->a_deleted_values, r, SLAPI_VALUE_FLAG_PASSIN);
  52. }
  53. return LDAP_SUCCESS;
  54. }
  55. static int
  56. entry_present_value_to_zapped_value(Slapi_Attr *a, Slapi_Value *v)
  57. {
  58. if(v!=NULL)
  59. {
  60. Slapi_Value *r= valueset_remove_value(a, &a->a_present_values, v);
  61. if(r!=NULL)
  62. {
  63. slapi_value_free(&r);
  64. }
  65. }
  66. return LDAP_SUCCESS;
  67. }
  68. static int
  69. entry_deleted_value_to_present_value(Slapi_Attr *a, Slapi_Value *v)
  70. {
  71. Slapi_Value *r= valueset_remove_value(a, &a->a_deleted_values, v);
  72. if(r!=NULL)
  73. {
  74. slapi_valueset_add_value_ext(&a->a_present_values, r, SLAPI_VALUE_FLAG_PASSIN);
  75. }
  76. return LDAP_SUCCESS;
  77. }
  78. static int
  79. entry_deleted_value_to_zapped_value(Slapi_Attr *a, Slapi_Value *v)
  80. {
  81. if(v!=NULL)
  82. {
  83. Slapi_Value *r= valueset_remove_value(a, &a->a_deleted_values, v);
  84. if(r!=NULL)
  85. {
  86. slapi_value_free(&r);
  87. }
  88. }
  89. return LDAP_SUCCESS;
  90. }
  91. static int
  92. entry_present_attribute_to_deleted_attribute(Slapi_Entry *e, Slapi_Attr *a)
  93. {
  94. attrlist_remove(&e->e_attrs,a->a_type);
  95. attrlist_add(&e->e_deleted_attrs,a);
  96. return LDAP_SUCCESS;
  97. }
  98. static int
  99. entry_deleted_attribute_to_present_attribute(Slapi_Entry *e, Slapi_Attr *a)
  100. {
  101. attrlist_remove(&e->e_deleted_attrs,a->a_type);
  102. attrlist_add(&e->e_attrs,a);
  103. return LDAP_SUCCESS;
  104. }
  105. /*
  106. * Get the first deleted attribute.
  107. *
  108. * Return 0: Return the type and the CSN of the deleted attribute.
  109. * Return -1: There are no deleted attributes.
  110. */
  111. int
  112. entry_first_deleted_attribute( const Slapi_Entry *e, Slapi_Attr **a)
  113. {
  114. *a= e->e_deleted_attrs;
  115. return( *a ? 0 : -1 );
  116. }
  117. /*
  118. * Get the next deleted attribute.
  119. *
  120. * Return 0: the type and the CSN of the deleted attribute.
  121. * Return -1: no deleted attributes.
  122. */
  123. int
  124. entry_next_deleted_attribute( const Slapi_Entry *e, Slapi_Attr **a)
  125. {
  126. *a= (*a)->a_next;
  127. return( *a ? 0 : -1 );
  128. }
  129. const CSN *
  130. entry_get_maxcsn ( const Slapi_Entry *entry )
  131. {
  132. return entry->e_maxcsn;
  133. }
  134. void
  135. entry_set_maxcsn ( Slapi_Entry *entry, const CSN *csn )
  136. {
  137. if ( NULL == entry->e_maxcsn )
  138. {
  139. entry->e_maxcsn = csn_dup ( csn );
  140. }
  141. else if ( csn_compare ( entry->e_maxcsn, csn ) < 0 )
  142. {
  143. csn_init_by_csn ( entry->e_maxcsn, csn );
  144. }
  145. }
  146. /*
  147. * Get the DN CSN of an entry.
  148. */
  149. const CSN *
  150. entry_get_dncsn(const Slapi_Entry *entry)
  151. {
  152. return csnset_get_last_csn(entry->e_dncsnset);
  153. }
  154. /*
  155. * Get the DN CSN set of an entry.
  156. */
  157. const CSNSet *
  158. entry_get_dncsnset(const Slapi_Entry *entry)
  159. {
  160. return entry->e_dncsnset;
  161. }
  162. /*
  163. * Add a DN CSN to an entry.
  164. */
  165. int
  166. entry_add_dncsn(Slapi_Entry *entry, const CSN *csn)
  167. {
  168. PR_ASSERT(entry!=NULL);
  169. csnset_update_csn(&entry->e_dncsnset, CSN_TYPE_VALUE_DISTINGUISHED, csn);
  170. return 0;
  171. }
  172. /*
  173. * Add a DN CSN to an entry, but uses flags to control the behavior
  174. * Using the ENTRY_DNCSN_INCREASING flag makes sure the csnset is in
  175. * order of increasing csn. csnset_insert_csn may not be very fast, so
  176. * we may have to revisit this if it becomes a performance problem.
  177. * In most cases, storing the csn unsorted is ok since the server
  178. * usually makes sure the csn is already in order. However, when doing
  179. * a str2entry, the order is not preserved unless we sort it.
  180. */
  181. int
  182. entry_add_dncsn_ext(Slapi_Entry *entry, const CSN *csn, PRUint32 flags)
  183. {
  184. PR_ASSERT(entry!=NULL);
  185. csnset_update_csn(&entry->e_dncsnset, CSN_TYPE_VALUE_DISTINGUISHED, csn);
  186. return 0;
  187. }
  188. /*
  189. * Set the CSN for all the present values on the entry.
  190. * This is only intended to be used for new entries
  191. * being added.
  192. */
  193. int
  194. entry_set_csn(Slapi_Entry *entry, const CSN *csn)
  195. {
  196. Slapi_Attr *a;
  197. PR_ASSERT(entry!=NULL);
  198. slapi_entry_first_attr( entry, &a );
  199. while(a!=NULL)
  200. {
  201. /*
  202. * JCM - it'd be more efficient if the str2entry code
  203. * set a flag on the attribute structure.
  204. */
  205. if(strcasecmp(a->a_type, SLAPI_ATTR_UNIQUEID)!=0)
  206. {
  207. attr_set_csn(a,csn);
  208. }
  209. slapi_entry_next_attr( entry, a, &a );
  210. }
  211. return 0;
  212. }
  213. /*
  214. * Set the Distinguished CSN for the RDN components of the entry.
  215. */
  216. void
  217. entry_add_rdn_csn(Slapi_Entry *e, const CSN *csn)
  218. {
  219. char *type;
  220. char *value;
  221. int index;
  222. const Slapi_DN *dn= slapi_entry_get_sdn_const(e);
  223. Slapi_RDN *rdn= slapi_rdn_new_sdn(dn);
  224. index= slapi_rdn_get_first(rdn, &type, &value);
  225. while(index!=-1)
  226. {
  227. Slapi_Attr *a= NULL;
  228. Slapi_Value *v= NULL;
  229. if ((entry_attr_find_wsi(e, type, &a) == ATTRIBUTE_PRESENT) && (a!=NULL))
  230. {
  231. struct berval bv;
  232. bv.bv_len= strlen(value);
  233. bv.bv_val= (void*)value;
  234. if (attr_value_find_wsi(a, &bv, &v) == VALUE_DELETED) {
  235. v = NULL;
  236. }
  237. }
  238. if(v!=NULL)
  239. {
  240. value_update_csn(v,CSN_TYPE_VALUE_DISTINGUISHED,csn);
  241. }
  242. else
  243. {
  244. /* JCM RDN component isn't a present value - this is illegal. */
  245. }
  246. index= slapi_rdn_get_next(rdn, index, &type, &value);
  247. }
  248. slapi_rdn_free(&rdn);
  249. }
  250. CSN*
  251. entry_assign_operation_csn ( Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *parententry )
  252. {
  253. Slapi_Operation *op;
  254. const CSN *basecsn = NULL;
  255. const CSN *parententry_dncsn = NULL;
  256. CSN *opcsn = NULL;
  257. slapi_pblock_get ( pb, SLAPI_OPERATION, &op );
  258. /*
  259. * The replication pre-op would have set op->o_csngen_handler for
  260. * user requests that are against a replica.
  261. */
  262. if ( op->o_csngen_handler )
  263. {
  264. /*
  265. * Sync up the CSN generator so that the new csn is greater
  266. * than the entry's maxcsn and/or the parent's max dncsn.
  267. */
  268. if ( e )
  269. {
  270. basecsn = entry_get_maxcsn ( e );
  271. }
  272. if ( parententry )
  273. {
  274. parententry_dncsn = entry_get_dncsn ( parententry );
  275. if ( csn_compare ( parententry_dncsn, basecsn ) > 0 )
  276. {
  277. basecsn = parententry_dncsn;
  278. }
  279. }
  280. opcsn = op->o_csngen_handler ( pb, basecsn );
  281. if (NULL != opcsn)
  282. {
  283. operation_set_csn (op, opcsn);
  284. }
  285. }
  286. return opcsn;
  287. }
  288. /*
  289. * Purge state information from the entry older than csnUpTo
  290. *
  291. * if csnUpTo is NULL, get rid of all the CSN related info.
  292. * if csnUpTo is non-NULL, purge all info older than csnUpTo
  293. */
  294. void
  295. entry_purge_state_information(Slapi_Entry *e, const CSN *csnUpTo)
  296. {
  297. Slapi_Attr *a=NULL;
  298. PR_ASSERT(e!=NULL);
  299. for(a = e->e_attrs; NULL != a; a = a->a_next)
  300. {
  301. /*
  302. * we are passing in the entry so that we may be able to "optimize"
  303. * the csn related information and roll it up higher to the level
  304. * of entry
  305. */
  306. attr_purge_state_information(e, a, csnUpTo);
  307. }
  308. for(a = e->e_deleted_attrs; NULL != a; a = a->a_next)
  309. {
  310. /*
  311. * we are passing in the entry so that we may be able to "optimize"
  312. * the csn related information and roll it up higher to the level
  313. * of entry
  314. */
  315. attr_purge_state_information(e, a, csnUpTo);
  316. }
  317. csnset_purge(&e->e_dncsnset, csnUpTo);
  318. }
  319. /*
  320. * Look for the attribute on the present and deleted attribute lists.
  321. */
  322. int
  323. entry_attr_find_wsi(Slapi_Entry *e, const char *type, Slapi_Attr **a)
  324. {
  325. int retVal= ATTRIBUTE_NOTFOUND;
  326. PR_ASSERT(e!=NULL);
  327. PR_ASSERT(type!=NULL);
  328. PR_ASSERT(a!=NULL);
  329. /* Look on the present attribute list */
  330. *a= attrlist_find(e->e_attrs,type);
  331. if(*a!=NULL)
  332. {
  333. /* The attribute is present */
  334. retVal= ATTRIBUTE_PRESENT;
  335. }
  336. else
  337. {
  338. /* Maybe the attribue was deleted... */
  339. *a= attrlist_find(e->e_deleted_attrs,type);
  340. if(*a!=NULL)
  341. {
  342. /* The attribute is deleted */
  343. retVal= ATTRIBUTE_DELETED;
  344. }
  345. else
  346. {
  347. /* The attribute was not found */
  348. retVal= ATTRIBUTE_NOTFOUND;
  349. }
  350. }
  351. return retVal;
  352. }
  353. /*
  354. * Add the attribute to the deleted attribute list.
  355. *
  356. * Consumes the attribute.
  357. */
  358. int
  359. entry_add_deleted_attribute_wsi(Slapi_Entry *e, Slapi_Attr *a)
  360. {
  361. PR_ASSERT( e!=NULL );
  362. PR_ASSERT( a!=NULL );
  363. attrlist_add(&e->e_deleted_attrs, a);
  364. return 0;
  365. }
  366. /*
  367. * Add the attribute to the present attribute list.
  368. *
  369. * Consumes the attribute.
  370. */
  371. int
  372. entry_add_present_attribute_wsi(Slapi_Entry *e, Slapi_Attr *a)
  373. {
  374. PR_ASSERT( e!=NULL );
  375. PR_ASSERT( a!=NULL );
  376. attrlist_add(&e->e_attrs, a);
  377. return 0;
  378. }
  379. /*
  380. * Add a list of values to the attribute, whilst maintaining state information.
  381. *
  382. * Preserves LDAP Information Model constraints,
  383. * returning an LDAP result code.
  384. */
  385. static int
  386. entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **bervals, const CSN *csn, int urp, long flags)
  387. {
  388. int retVal= LDAP_SUCCESS;
  389. Slapi_Value **valuestoadd = NULL;
  390. valuearray_init_bervalarray(bervals,&valuestoadd); /* JCM SLOW FUNCTION */
  391. if(!valuearray_isempty(valuestoadd))
  392. {
  393. Slapi_Attr *a= NULL;
  394. long a_flags_orig;
  395. int attr_state= entry_attr_find_wsi(e, type, &a);
  396. if (ATTRIBUTE_NOTFOUND == attr_state)
  397. {
  398. /* Create a new attribute */
  399. a = slapi_attr_new();
  400. slapi_attr_init(a, type);
  401. attrlist_add(&e->e_attrs, a);
  402. }
  403. a_flags_orig = a->a_flags;
  404. a->a_flags |= flags;
  405. /* Check if the type of the to-be-added values has DN syntax or not. */
  406. if (slapi_attr_is_dn_syntax_attr(a)) {
  407. valuearray_dn_normalize_value(valuestoadd);
  408. a->a_flags |= SLAPI_ATTR_FLAG_NORMALIZED;
  409. }
  410. if(urp)
  411. {
  412. /*
  413. * Consolidate a->a_present_values and the pending values:
  414. * Delete the pending values from a->a_present_values
  415. * and transfer their csnsets to valuestoadd.
  416. */
  417. valueset_remove_valuearray (&a->a_present_values, a, valuestoadd,
  418. SLAPI_VALUE_FLAG_IGNOREERROR |
  419. SLAPI_VALUE_FLAG_PRESERVECSNSET, NULL);
  420. /*
  421. * Consolidate a->a_deleted_values and the pending values
  422. * similarly.
  423. */
  424. valueset_remove_valuearray (&a->a_deleted_values, a, valuestoadd,
  425. SLAPI_VALUE_FLAG_IGNOREERROR |
  426. SLAPI_VALUE_FLAG_PRESERVECSNSET, NULL);
  427. /* Append the pending values to a->a_present_values */
  428. valuearray_update_csn (valuestoadd,CSN_TYPE_VALUE_UPDATED,csn);
  429. valueset_add_valuearray_ext(&a->a_present_values, valuestoadd, SLAPI_VALUE_FLAG_PASSIN);
  430. slapi_ch_free ( (void **)&valuestoadd );
  431. /*
  432. * Now delete non-RDN values from a->a_present_values; and
  433. * restore possible RDN values from a->a_deleted_values
  434. */
  435. resolve_attribute_state(e, a, attr_state, 0);
  436. retVal= LDAP_SUCCESS;
  437. }
  438. else
  439. {
  440. Slapi_Value **deletedvalues= NULL;
  441. switch(attr_state)
  442. {
  443. case ATTRIBUTE_PRESENT:
  444. /* The attribute is already on the present list */
  445. break;
  446. case ATTRIBUTE_DELETED:
  447. /* Move the deleted attribute onto the present list */
  448. entry_deleted_attribute_to_present_attribute(e, a);
  449. break;
  450. case ATTRIBUTE_NOTFOUND:
  451. /* No-op - attribute was initialized & added to entry above */
  452. break;
  453. }
  454. /* Check if any of the values to be added are on the deleted list */
  455. valueset_remove_valuearray(&a->a_deleted_values,
  456. a, valuestoadd,
  457. SLAPI_VALUE_FLAG_IGNOREERROR|SLAPI_VALUE_FLAG_USENEWVALUE,
  458. &deletedvalues); /* JCM Check return code */
  459. if(deletedvalues!=NULL && deletedvalues[0]!=NULL)
  460. {
  461. /* Some of the values to be added were on the deleted list */
  462. Slapi_Value **v= NULL;
  463. Slapi_ValueSet vs;
  464. /* Add each deleted value to the present list */
  465. valuearray_update_csn(deletedvalues,CSN_TYPE_VALUE_UPDATED,csn);
  466. valueset_add_valuearray_ext(&a->a_present_values, deletedvalues, SLAPI_VALUE_FLAG_PASSIN);
  467. /* Remove the deleted values from the values to add */
  468. valueset_set_valuearray_passin(&vs,valuestoadd);
  469. valueset_remove_valuearray(&vs, a, deletedvalues, SLAPI_VALUE_FLAG_IGNOREERROR, &v);
  470. valuestoadd= valueset_get_valuearray(&vs);
  471. valuearray_free(&v);
  472. slapi_ch_free((void **)&deletedvalues);
  473. }
  474. valuearray_update_csn(valuestoadd,CSN_TYPE_VALUE_UPDATED,csn);
  475. retVal= attr_add_valuearray(a, valuestoadd, slapi_entry_get_dn_const(e));
  476. valuearray_free(&valuestoadd);
  477. }
  478. a->a_flags = a_flags_orig;
  479. }
  480. return(retVal);
  481. }
  482. /*
  483. * Delete a list of values from an attribute, whilst maintaining state information.
  484. *
  485. * Preserves LDAP Information Model constraints,
  486. * returning an LDAP result code.
  487. */
  488. static int
  489. entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **vals, const CSN *csn, int urp, int mod_op, struct berval **replacevals)
  490. {
  491. int retVal= LDAP_SUCCESS;
  492. Slapi_Attr *a= NULL;
  493. int attr_state= entry_attr_find_wsi(e, type, &a);
  494. if(attr_state==ATTRIBUTE_PRESENT || (attr_state==ATTRIBUTE_DELETED && urp))
  495. {
  496. /* The attribute is on the present list, or the deleted list and we're doing URP */
  497. if ( vals == NULL || vals[0] == NULL )
  498. {
  499. /* delete the entire attribute */
  500. LDAPDebug( LDAP_DEBUG_ARGS, "removing entire attribute %s\n", type, 0, 0 );
  501. attr_set_deletion_csn(a,csn);
  502. if(urp)
  503. {
  504. resolve_attribute_state(e, a, attr_state, 1 /* set delete priority */); /* ABSOLVED */
  505. }
  506. else
  507. {
  508. if(!slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE))
  509. {
  510. /* We don't maintain a deleted value list for single valued attributes */
  511. valueset_add_valueset(&a->a_deleted_values, &a->a_present_values); /* JCM Would be better to passin the valuestodelete */
  512. }
  513. slapi_valueset_done(&a->a_present_values);
  514. entry_present_attribute_to_deleted_attribute(e, a);
  515. }
  516. retVal= LDAP_SUCCESS; /* This Operation always succeeds when the attribute is Present */
  517. }
  518. else
  519. {
  520. /* delete some specific values */
  521. Slapi_Value **valuestodelete= NULL;
  522. valuearray_init_bervalarray(vals,&valuestodelete); /* JCM SLOW FUNCTION */
  523. /* Check if the type of the to-be-deleted values has DN syntax
  524. * or not. */
  525. if (slapi_attr_is_dn_syntax_attr(a)) {
  526. valuearray_dn_normalize_value(valuestodelete);
  527. a->a_flags |= SLAPI_ATTR_FLAG_NORMALIZED;
  528. }
  529. if(urp)
  530. {
  531. Slapi_Value **valuesupdated= NULL;
  532. valueset_update_csn_for_valuearray(&a->a_present_values, a, valuestodelete, CSN_TYPE_VALUE_DELETED, csn, &valuesupdated);
  533. /* if we removed the last value, we need to mark the attribute as deleted
  534. the resolve_attribute_state() code will "resurrect" the attribute if
  535. there are present values with a later CSN - otherwise, even though
  536. the value will be updated with a VDCSN which is later than the VUCSN,
  537. the attribute will not be deleted */
  538. if(slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE) && valuesupdated &&
  539. *valuesupdated)
  540. {
  541. attr_set_deletion_csn(a,csn);
  542. }
  543. valuearray_free(&valuesupdated);
  544. valueset_update_csn_for_valuearray(&a->a_deleted_values, a, valuestodelete, CSN_TYPE_VALUE_DELETED, csn, &valuesupdated);
  545. valuearray_free(&valuesupdated);
  546. valuearray_update_csn(valuestodelete,CSN_TYPE_VALUE_DELETED,csn);
  547. valueset_add_valuearray_ext(&a->a_deleted_values, valuestodelete, SLAPI_VALUE_FLAG_PASSIN);
  548. /* all the elements in valuestodelete are passed;
  549. * should free valuestodelete only (don't call valuearray_free)
  550. * [622023] */
  551. slapi_ch_free((void **)&valuestodelete);
  552. resolve_attribute_state(e, a, attr_state, 0);
  553. retVal= LDAP_SUCCESS;
  554. }
  555. else
  556. {
  557. Slapi_Value **deletedvalues= NULL;
  558. retVal= valueset_remove_valuearray(&a->a_present_values, a, valuestodelete, 0 /* Do Not Ignore Errors */,&deletedvalues);
  559. if(retVal==LDAP_SUCCESS && deletedvalues != NULL)
  560. {
  561. if(!slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE))
  562. {
  563. /* We don't maintain a deleted value list for single valued attributes */
  564. /* Add each deleted value to the deleted set */
  565. valuearray_update_csn(deletedvalues,CSN_TYPE_VALUE_DELETED,csn);
  566. valueset_add_valuearray_ext(&a->a_deleted_values, deletedvalues, SLAPI_VALUE_FLAG_PASSIN);
  567. slapi_ch_free((void **)&deletedvalues);
  568. }
  569. else {
  570. valuearray_free(&deletedvalues);
  571. }
  572. if(valueset_isempty(&a->a_present_values))
  573. {
  574. /* There are no present values, so move the
  575. * attribute to the deleted attribute list. */
  576. entry_present_attribute_to_deleted_attribute(e, a);
  577. }
  578. }
  579. else if (retVal != LDAP_SUCCESS)
  580. {
  581. /* Failed
  582. * - Duplicate value
  583. * - Value not found
  584. * - Operations error
  585. */
  586. if ( retVal==LDAP_OPERATIONS_ERROR )
  587. {
  588. LDAPDebug( LDAP_DEBUG_ANY, "Possible existing duplicate "
  589. "value for attribute type %s found in "
  590. "entry %s\n", a->a_type, slapi_entry_get_dn_const(e), 0 );
  591. }
  592. }
  593. valuearray_free(&valuestodelete);
  594. }
  595. }
  596. }
  597. else if (attr_state==ATTRIBUTE_DELETED)
  598. {
  599. /* If the type is in the forbidden attr list (e.g., unhashed password),
  600. * we don't return the reason of the failure to the clients. */
  601. if (is_type_forbidden(type)) {
  602. retVal = LDAP_SUCCESS;
  603. } else {
  604. retVal= LDAP_NO_SUCH_ATTRIBUTE;
  605. }
  606. }
  607. else if (attr_state==ATTRIBUTE_NOTFOUND)
  608. {
  609. /*
  610. * If type is in the protected_attrs_all list, we could ignore the
  611. * failure, as the attribute could only exist in the entry in the
  612. * memory when the add/mod operation is done, while the retried entry
  613. * from the db does not contain the attribute.
  614. * So is in the forbidden_attrs list. We don't return the reason
  615. * of the failure.
  616. */
  617. if (is_type_protected(type) || is_type_forbidden(type)) {
  618. retVal = LDAP_SUCCESS;
  619. } else {
  620. if (!urp) {
  621. /* Only warn if not urping */
  622. LDAPDebug1Arg(LDAP_DEBUG_ARGS, "could not find attribute %s\n",
  623. type);
  624. }
  625. retVal = LDAP_NO_SUCH_ATTRIBUTE;
  626. }
  627. /* NOTE: LDAP says that a MOD REPLACE with no vals of a non-existent
  628. attribute is a no-op - MOD REPLACE with some vals will add the attribute */
  629. /* if we are doing a replace with actual values, meaning the result
  630. of the mod is that the attribute will have some values, we need to create
  631. a dummy attribute for entry_add_present_values_wsi to use, and set
  632. the deletion csn to the csn of the current operation */
  633. /* note that if LDAP_MOD_REPLACE == mod_op then vals is NULL -
  634. see entry_replace_present_values_wsi */
  635. if ((LDAP_MOD_REPLACE == mod_op) && replacevals && replacevals[0])
  636. {
  637. /* Create a new attribute and set the adcsn */
  638. Slapi_Attr *a = slapi_attr_new();
  639. slapi_attr_init(a, type);
  640. attr_set_deletion_csn(a,csn);
  641. /* mark the attribute as deleted - it does not really
  642. exist yet - the code in entry_add_present_values_wsi
  643. will add it back to the present list in the non urp case,
  644. or determine if the attribute needs to be added
  645. or not in the urp case
  646. */
  647. entry_add_deleted_attribute_wsi(e, a);
  648. }
  649. }
  650. return( retVal );
  651. }
  652. /*
  653. * Replace all the values of an attribute with a list of attribute values.
  654. *
  655. * Preserves LDAP Information Model constraints,
  656. * returning an LDAP result code.
  657. */
  658. static int
  659. entry_replace_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **vals, const CSN *csn, int urp)
  660. {
  661. /*
  662. * Remove all existing values.
  663. */
  664. entry_delete_present_values_wsi(e, type, NULL /* Delete all values */, csn, urp, LDAP_MOD_REPLACE, vals);
  665. /*
  666. * Add the new values. If there are no new values,
  667. * slapi_entry_add_values() returns LDAP_SUCCESS and so the
  668. * attribute remains deleted (which is the correct outcome).
  669. */
  670. return( entry_add_present_values_wsi( e, type, vals, csn, urp, SLAPI_ATTR_FLAG_CMP_BITBYBIT ));
  671. }
  672. /*
  673. * Applies the modification to the entry whilst
  674. * maintaining state information.
  675. */
  676. int
  677. entry_apply_mod_wsi(Slapi_Entry *e, const LDAPMod *mod, const CSN *csn, int urp)
  678. {
  679. int retVal= LDAP_SUCCESS;
  680. int i;
  681. switch ( mod->mod_op & ~LDAP_MOD_BVALUES )
  682. {
  683. case LDAP_MOD_ADD:
  684. LDAPDebug( LDAP_DEBUG_ARGS, " add: %s\n", mod->mod_type, 0, 0 );
  685. retVal = entry_add_present_values_wsi( e, mod->mod_type, mod->mod_bvalues, csn, urp, 0 );
  686. break;
  687. case LDAP_MOD_DELETE:
  688. LDAPDebug( LDAP_DEBUG_ARGS, " delete: %s\n", mod->mod_type, 0, 0 );
  689. retVal = entry_delete_present_values_wsi( e, mod->mod_type, mod->mod_bvalues, csn, urp, mod->mod_op, NULL );
  690. break;
  691. case LDAP_MOD_REPLACE:
  692. LDAPDebug( LDAP_DEBUG_ARGS, " replace: %s\n", mod->mod_type, 0, 0 );
  693. retVal = entry_replace_present_values_wsi( e, mod->mod_type, mod->mod_bvalues, csn, urp );
  694. break;
  695. }
  696. if ( LDAPDebugLevelIsSet( LDAP_DEBUG_ARGS )) {
  697. for ( i = 0;
  698. mod->mod_bvalues != NULL && mod->mod_bvalues[i] != NULL;
  699. i++ ) {
  700. LDAPDebug( LDAP_DEBUG_ARGS, " %s: %s\n",
  701. mod->mod_type, mod->mod_bvalues[i]->bv_val, 0 );
  702. }
  703. LDAPDebug( LDAP_DEBUG_ARGS, " -\n", 0, 0, 0 );
  704. }
  705. return retVal;
  706. }
  707. /*
  708. * Applies the set of modifications to the entry whilst
  709. * maintaining state information.
  710. */
  711. int
  712. entry_apply_mods_wsi(Slapi_Entry *e, Slapi_Mods *smods, const CSN *csn, int urp)
  713. {
  714. int retVal= LDAP_SUCCESS;
  715. LDAPMod *mod;
  716. CSN localcsn;
  717. if (csn) {
  718. localcsn = *csn; /* make a copy */
  719. }
  720. LDAPDebug( LDAP_DEBUG_TRACE, "=> entry_apply_mods_wsi\n", 0, 0, 0 );
  721. mod = slapi_mods_get_first_mod(smods);
  722. while(NULL!=mod && retVal==LDAP_SUCCESS)
  723. {
  724. if(csn!=NULL)
  725. {
  726. retVal= entry_apply_mod_wsi(e, mod, &localcsn, urp);
  727. /* use subsequence to guarantee absolute ordering of all of the
  728. mods in a set of mods, if this is a replicated operation,
  729. and the csn doesn't already have a subsequence
  730. if the csn already has a subsequence, assume it was generated
  731. on another replica in the correct order */
  732. if (urp && (csn_get_subseqnum(csn) == 0)) {
  733. csn_increment_subsequence(&localcsn);
  734. }
  735. }
  736. else
  737. {
  738. retVal= entry_apply_mod(e, mod);
  739. }
  740. mod = slapi_mods_get_next_mod(smods);
  741. }
  742. LDAPDebug( LDAP_DEBUG_TRACE, "<= entry_apply_mods_wsi %d\n", retVal, 0, 0 );
  743. return retVal;
  744. }
  745. /*
  746. * This code implements a computed attribute called 'nscpEntryWSI'.
  747. * By specifically asking for this attribute the client will receive
  748. * an LDIF dump of the entry with all its state information.
  749. *
  750. * JCM - Security... Only for the Directory Manager.
  751. */
  752. static const char *nscpEntryWSI= "nscpEntryWSI";
  753. /*
  754. */
  755. static int
  756. entry_compute_nscpentrywsi(computed_attr_context *c,char* type,Slapi_Entry *e,slapi_compute_output_t outputfn)
  757. {
  758. int rc = 0;
  759. if ( strcasecmp(type, nscpEntryWSI ) == 0)
  760. {
  761. /* If not, we return it as zero */
  762. char *es;
  763. char *s;
  764. char *p;
  765. int len;
  766. Slapi_Attr our_attr;
  767. slapi_attr_init(&our_attr, nscpEntryWSI);
  768. our_attr.a_flags = SLAPI_ATTR_FLAG_OPATTR;
  769. es= slapi_entry2str_with_options(e, &len, SLAPI_DUMP_STATEINFO | SLAPI_DUMP_UNIQUEID | SLAPI_DUMP_NOWRAP);
  770. s= es;
  771. p= ldif_getline( &s );
  772. while(p!=NULL)
  773. {
  774. Slapi_Value *v;
  775. char *t, *d;
  776. /* Strip out the Continuation Markers (JCM - I think that NOWRAP means we don't need to do this any more)*/
  777. for ( t = p, d = p; *t; t++ )
  778. {
  779. if ( *t != 0x01 )
  780. *d++ = *t;
  781. }
  782. *d = '\0';
  783. v= slapi_value_new_string(p);
  784. slapi_attr_add_value(&our_attr,v);
  785. slapi_value_free(&v);
  786. p= ldif_getline( &s );
  787. }
  788. slapi_ch_free((void**)&es);
  789. rc = (*outputfn) (c, &our_attr, e);
  790. attr_done(&our_attr);
  791. return (rc);
  792. }
  793. return -1; /* I see no ships */
  794. }
  795. int
  796. entry_computed_attr_init()
  797. {
  798. slapi_compute_add_evaluator(entry_compute_nscpentrywsi);
  799. return 0;
  800. }
  801. static void
  802. purge_attribute_state_multi_valued(const Slapi_Attr *a, Slapi_Value *v)
  803. {
  804. const CSN *vdcsn= value_get_csn(v,CSN_TYPE_VALUE_DELETED);
  805. const CSN *vucsn= value_get_csn(v,CSN_TYPE_VALUE_UPDATED);
  806. if(vdcsn && csn_compare(vdcsn,vucsn)<0)
  807. {
  808. value_remove_csn(v,CSN_TYPE_VALUE_DELETED);
  809. }
  810. }
  811. /*
  812. * utility function for value_distinguished_at_csn...
  813. */
  814. static const CSN *
  815. vdac_sniff_value(Slapi_ValueSet *vs, const Slapi_Value *v, const CSN *csn, const CSN *most_recent_mdcsn)
  816. {
  817. const CSN *mdcsn= value_get_csn(v,CSN_TYPE_VALUE_DISTINGUISHED);
  818. if(mdcsn!=NULL)
  819. {
  820. /* This value was/is distinguished... */
  821. if(csn_compare(csn,most_recent_mdcsn)<0)
  822. {
  823. /* ...and was distinguished before the point in time we're interested in... */
  824. int r= csn_compare(mdcsn,most_recent_mdcsn);
  825. if(r>0)
  826. {
  827. /* ...and is the most recent MDCSN we've seen thus far. */
  828. slapi_valueset_done(vs);
  829. slapi_valueset_add_value(vs,v);
  830. most_recent_mdcsn= mdcsn;
  831. }
  832. else if(r==0)
  833. {
  834. /* ...and is as recent as the last most recent MDCSN we've seen thus far. */
  835. /* Must have been a multi-valued RDN */
  836. slapi_valueset_add_value(vs,v);
  837. }
  838. }
  839. }
  840. return most_recent_mdcsn;
  841. }
  842. /*
  843. * utility function for value_distinguished_at_csn...
  844. */
  845. static const CSN *
  846. vdac_sniff_attribute(Slapi_ValueSet *vs, Slapi_Attr *a, const CSN *csn, const CSN *most_recent_mdcsn)
  847. {
  848. Slapi_Value *v;
  849. int i= slapi_attr_first_value( a, &v );
  850. while(i!=-1)
  851. {
  852. most_recent_mdcsn= vdac_sniff_value( vs, v, csn, most_recent_mdcsn );
  853. i= slapi_attr_next_value( a, i, &v );
  854. }
  855. i= attr_first_deleted_value( a, &v );
  856. while(i!=-1)
  857. {
  858. most_recent_mdcsn= vdac_sniff_value( vs, v, csn, most_recent_mdcsn );
  859. i= attr_next_deleted_value( a, i, &v );
  860. }
  861. return most_recent_mdcsn;
  862. }
  863. /*
  864. * utility function for value_distinguished_at_csn...
  865. *
  866. * Return the set of values that made up the RDN at or before the csn point.
  867. */
  868. static const CSN *
  869. distinguished_values_at_csn(const Slapi_Entry *e, const CSN *csn, Slapi_ValueSet *vs)
  870. {
  871. const CSN *most_recent_mdcsn= NULL;
  872. Slapi_Attr *a;
  873. int i= slapi_entry_first_attr( e, &a );
  874. while(i!=-1)
  875. {
  876. most_recent_mdcsn= vdac_sniff_attribute( vs, a, csn, most_recent_mdcsn);
  877. i= slapi_entry_next_attr( e, a, &a );
  878. }
  879. i= entry_first_deleted_attribute( e, &a );
  880. while(i!=-1)
  881. {
  882. most_recent_mdcsn= vdac_sniff_attribute( vs, a, csn, most_recent_mdcsn);
  883. i= entry_next_deleted_attribute( e, &a );
  884. }
  885. return most_recent_mdcsn;
  886. }
  887. /*
  888. * Work out if the value was distinguished at time csn.
  889. */
  890. static int
  891. value_distinguished_at_csn(const Slapi_Entry *e, const Slapi_Attr *original_attr, Slapi_Value *original_value, const CSN *csn)
  892. {
  893. int r= 0;
  894. const CSN *mdcsn= value_get_csn(original_value,CSN_TYPE_VALUE_DISTINGUISHED);
  895. if(mdcsn!=NULL)
  896. {
  897. /*
  898. * Oh bugger. This means that we have to work out what the RDN components
  899. * were at this point in time. This is non-trivial since we must walk
  900. * through all the present and deleted attributes and their present and
  901. * deleted values. Slow :-(
  902. */
  903. Slapi_ValueSet *vs= slapi_valueset_new();
  904. const CSN *most_recent_mdcsn= distinguished_values_at_csn(e, csn, vs);
  905. /*
  906. * We now know what the RDN components were at the point in time we're interested in.
  907. * And the question we need to answer is :-
  908. * 'Was the provided value one of those RDN components?'
  909. */
  910. if(most_recent_mdcsn!=NULL)
  911. {
  912. Slapi_Value *v;
  913. int i= slapi_valueset_first_value( vs, &v );
  914. while(i!=-1)
  915. {
  916. if(slapi_value_compare(original_attr, original_value, v)==0)
  917. {
  918. /* This value was distinguished at the time in question. */
  919. r= 1;
  920. i= -1;
  921. }
  922. else
  923. {
  924. i= slapi_valueset_next_value( vs, i, &v );
  925. }
  926. }
  927. }
  928. slapi_valueset_free(vs);
  929. }
  930. else
  931. {
  932. /* This value has never been distinguished */
  933. r= 0;
  934. }
  935. return r;
  936. }
  937. static void
  938. resolve_attribute_state_multi_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, int delete_priority)
  939. {
  940. int i;
  941. const CSN *adcsn= attr_get_deletion_csn(a);
  942. Slapi_ValueSet *vs= valueset_dup(&a->a_present_values); /* JCM This is slow... but otherwise we end up iterating through a changing array */
  943. Slapi_Value *v;
  944. /* Loop over the present attribute values */
  945. i= slapi_valueset_first_value( vs, &v );
  946. while(v!=NULL)
  947. {
  948. const CSN *vdcsn;
  949. const CSN *vucsn;
  950. const CSN *deletedcsn;
  951. /* This call ensures that the value does not contain a deletion_csn
  952. * which is before the presence_csn or distinguished_csn of the value.
  953. */
  954. purge_attribute_state_multi_valued(a, v);
  955. vdcsn= value_get_csn(v, CSN_TYPE_VALUE_DELETED);
  956. vucsn= value_get_csn(v, CSN_TYPE_VALUE_UPDATED);
  957. deletedcsn= csn_max(vdcsn, adcsn);
  958. /* Check if the attribute or value was deleted after the value was
  959. * last updated. If the value update CSN and the deleted CSN are
  960. * the same (meaning they are separate mods from the same exact
  961. * operation), we should only delete the value if delete priority
  962. * is set. Delete priority should only be set when we are deleting
  963. * all value of an attribute. This prevents us from leaving a value
  964. * that was added as a previous mod in the same exact modify
  965. * operation as the subsequent delete.*/
  966. if((csn_compare(vucsn,deletedcsn)<0) ||
  967. (delete_priority && (csn_compare(vucsn,deletedcsn) == 0)))
  968. {
  969. if(!value_distinguished_at_csn(e, a, v, deletedcsn))
  970. {
  971. entry_present_value_to_deleted_value(a,v);
  972. }
  973. }
  974. i= slapi_valueset_next_value( vs, i, &v );
  975. }
  976. slapi_valueset_free(vs);
  977. /* Loop over the deleted attribute values */
  978. vs= valueset_dup(&a->a_deleted_values); /* JCM This is slow... but otherwise we end up iterating through a changing array */
  979. i= slapi_valueset_first_value( vs, &v );
  980. while(v!=NULL)
  981. {
  982. const CSN *vdcsn;
  983. const CSN *vucsn;
  984. const CSN *deletedcsn;
  985. /* This call ensures that the value does not contain a deletion_csn which is before the presence_csn or distinguished_csn of the value. */
  986. purge_attribute_state_multi_valued(a, v);
  987. vdcsn= value_get_csn(v, CSN_TYPE_VALUE_DELETED);
  988. vucsn= value_get_csn(v, CSN_TYPE_VALUE_UPDATED);
  989. deletedcsn= csn_max(vdcsn, adcsn);
  990. /* check if the attribute or value was deleted after the value was last updated */
  991. /* When a replace operation happens, the entry_replace_present_values_wsi() function
  992. * first calls entry_delete_present_values_wsi with vals == NULL to essentially delete
  993. * the attribute and set the deletion csn. If the urp flag is set (urp in this case
  994. * meaning the operation is a replicated op), entry_delete_present_values_wsi will
  995. * call this function which will move the present values to the deleted values
  996. * (see above - delete_priority will be 1) then the below code will move the
  997. * attribute to the deleted list.
  998. * next, entry_replace_present_values_wsi will call entry_add_present_values_wsi
  999. * to add the values provided in the replace operation. We need to be able to
  1000. * "resurrect" these deleted values and resurrect the deleted attribute. In the
  1001. * replace case, the deletedcsn will be the same as the vucsn of the values that
  1002. * should be present values.
  1003. */
  1004. if((csn_compare(vucsn,deletedcsn)>0) ||
  1005. ((delete_priority == 0) && (csn_compare(vucsn,deletedcsn)==0)) ||
  1006. value_distinguished_at_csn(e, a, v, deletedcsn))
  1007. {
  1008. entry_deleted_value_to_present_value(a,v);
  1009. }
  1010. i= slapi_valueset_next_value( vs, i, &v );
  1011. }
  1012. slapi_valueset_free(vs);
  1013. if(valueset_isempty(&a->a_present_values))
  1014. {
  1015. if(attribute_state==ATTRIBUTE_PRESENT)
  1016. {
  1017. entry_present_attribute_to_deleted_attribute(e, a);
  1018. }
  1019. }
  1020. else
  1021. {
  1022. if(attribute_state==ATTRIBUTE_DELETED)
  1023. {
  1024. entry_deleted_attribute_to_present_attribute(e, a);
  1025. }
  1026. }
  1027. }
  1028. static void
  1029. resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state)
  1030. {
  1031. Slapi_Value *current_value= NULL;
  1032. Slapi_Value *pending_value= NULL;
  1033. Slapi_Value *new_value= NULL;
  1034. const CSN *current_value_vucsn;
  1035. const CSN *pending_value_vucsn;
  1036. const CSN *adcsn;
  1037. int i;
  1038. /*
  1039. * this call makes sure that the attribute does not have a pending_value
  1040. * or deletion_csn which is before the current_value.
  1041. */
  1042. i= slapi_attr_first_value(a,&current_value);
  1043. if(i!=-1)
  1044. {
  1045. slapi_attr_next_value(a,i,&new_value);
  1046. }
  1047. attr_first_deleted_value(a,&pending_value);
  1048. /* purge_attribute_state_single_valued */
  1049. adcsn= attr_get_deletion_csn(a);
  1050. current_value_vucsn= value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
  1051. pending_value_vucsn= value_get_csn(pending_value, CSN_TYPE_VALUE_UPDATED);
  1052. if((pending_value!=NULL && (csn_compare(adcsn, pending_value_vucsn)<0)) ||
  1053. (pending_value==NULL && (csn_compare(adcsn, current_value_vucsn)<0)))
  1054. {
  1055. attr_set_deletion_csn(a,NULL);
  1056. adcsn= NULL;
  1057. }
  1058. if(new_value==NULL)
  1059. {
  1060. /* check if the pending value should become the current value */
  1061. if(pending_value!=NULL)
  1062. {
  1063. if(!value_distinguished_at_csn(e,a,current_value,pending_value_vucsn))
  1064. {
  1065. /* attribute.current_value = attribute.pending_value; */
  1066. /* attribute.pending_value = NULL; */
  1067. entry_present_value_to_zapped_value(a,current_value);
  1068. entry_deleted_value_to_present_value(a,pending_value);
  1069. current_value= pending_value;
  1070. pending_value= NULL;
  1071. current_value_vucsn= pending_value_vucsn;
  1072. pending_value_vucsn= NULL;
  1073. }
  1074. }
  1075. /* check if the current value should be deleted */
  1076. if(current_value!=NULL)
  1077. {
  1078. if(csn_compare(adcsn,current_value_vucsn)>0) /* check if the attribute was deleted after the value was last updated */
  1079. {
  1080. if(!value_distinguished_at_csn(e,a,current_value,current_value_vucsn))
  1081. {
  1082. entry_present_value_to_zapped_value(a,current_value);
  1083. current_value= NULL;
  1084. current_value_vucsn= NULL;
  1085. }
  1086. }
  1087. }
  1088. }
  1089. else /* addition of a new value */
  1090. {
  1091. const CSN *new_value_vucsn= value_get_csn(new_value,CSN_TYPE_VALUE_UPDATED);
  1092. if(csn_compare(new_value_vucsn,current_value_vucsn)<0)
  1093. {
  1094. /*
  1095. * if the new value was distinguished at the time the current value was added
  1096. * then the new value should become current
  1097. */
  1098. if(value_distinguished_at_csn(e,a,new_value,current_value_vucsn))
  1099. {
  1100. /* attribute.pending_value = attribute.current_value */
  1101. /* attribute.current_value = new_value */
  1102. if(pending_value==NULL)
  1103. {
  1104. entry_present_value_to_deleted_value(a,current_value);
  1105. }
  1106. else
  1107. {
  1108. entry_present_value_to_zapped_value(a,current_value);
  1109. }
  1110. pending_value= current_value;
  1111. current_value= new_value;
  1112. new_value= NULL;
  1113. pending_value_vucsn= current_value_vucsn;
  1114. current_value_vucsn= new_value_vucsn;
  1115. }
  1116. else
  1117. {
  1118. /* new_value= NULL */
  1119. entry_present_value_to_zapped_value(a, new_value);
  1120. new_value= NULL;
  1121. }
  1122. }
  1123. else /* new value is after the current value */
  1124. {
  1125. if(!value_distinguished_at_csn(e, a, current_value, new_value_vucsn))
  1126. {
  1127. /* attribute.current_value = new_value */
  1128. entry_present_value_to_zapped_value(a, current_value);
  1129. current_value= new_value;
  1130. new_value= NULL;
  1131. current_value_vucsn= new_value_vucsn;
  1132. }
  1133. else /* value is distinguished - check if we should replace the current pending value */
  1134. {
  1135. if(csn_compare(new_value_vucsn, pending_value_vucsn)>0)
  1136. {
  1137. /* attribute.pending_value = new_value */
  1138. entry_deleted_value_to_zapped_value(a,pending_value);
  1139. entry_present_value_to_deleted_value(a,new_value);
  1140. pending_value= new_value;
  1141. new_value= NULL;
  1142. pending_value_vucsn= new_value_vucsn;
  1143. }
  1144. }
  1145. }
  1146. }
  1147. /*
  1148. * This call ensures that the attribute does not have a pending_value
  1149. * or a deletion_csn that is earlier than the current_value.
  1150. */
  1151. /* purge_attribute_state_single_valued */
  1152. if((pending_value!=NULL && (csn_compare(adcsn, pending_value_vucsn)<0)) ||
  1153. (pending_value==NULL && (csn_compare(adcsn, current_value_vucsn)<0)))
  1154. {
  1155. attr_set_deletion_csn(a,NULL);
  1156. adcsn= NULL;
  1157. }
  1158. /* set attribute state */
  1159. if(current_value==NULL)
  1160. {
  1161. if(attribute_state==ATTRIBUTE_PRESENT)
  1162. {
  1163. entry_present_attribute_to_deleted_attribute(e, a);
  1164. }
  1165. }
  1166. else
  1167. {
  1168. if(attribute_state==ATTRIBUTE_DELETED)
  1169. {
  1170. entry_deleted_attribute_to_present_attribute(e, a);
  1171. }
  1172. }
  1173. }
  1174. static void
  1175. resolve_attribute_state(Slapi_Entry *e, Slapi_Attr *a, int attribute_state, int delete_priority)
  1176. {
  1177. if(slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE))
  1178. {
  1179. resolve_attribute_state_single_valued(e,a,attribute_state);
  1180. }
  1181. else
  1182. {
  1183. resolve_attribute_state_multi_valued(e,a,attribute_state, delete_priority);
  1184. }
  1185. }