ldbm_entryrdn.c 130 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555
  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) 2009 Red Hat, Inc.
  35. * All rights reserved.
  36. * END COPYRIGHT BLOCK **/
  37. #ifdef HAVE_CONFIG_H
  38. # include <config.h>
  39. #endif
  40. #if defined(DEBUG)
  41. /* #define LDAP_DEBUG_ENTRYRDN 1 -- very verbose */
  42. #define ENTRYRDN_DEBUG 1
  43. #endif
  44. /* ldbm_entryrdn.c - module to access entry rdn index */
  45. #include "back-ldbm.h"
  46. static int entryrdn_switch = 0;
  47. static int entryrdn_noancestorid = 0;
  48. #ifdef ENTRYRDN_DEBUG
  49. #define ASSERT(_x) do { \
  50. if (!(_x)) { \
  51. LDAPDebug(LDAP_DEBUG_ANY, "BAD ASSERTION at %s/%d: %s\n", \
  52. __FILE__, __LINE__, #_x); \
  53. *(char *)0L = 23; \
  54. } \
  55. } while (0)
  56. #else
  57. #define ASSERT(_x) ;
  58. #endif
  59. #define ENTRYRDN_LOGLEVEL(rc) \
  60. (((rc)==DB_LOCK_DEADLOCK)?SLAPI_LOG_BACKLDBM:SLAPI_LOG_FATAL)
  61. #define ENTRYRDN_DELAY \
  62. { \
  63. PRIntervalTime interval; \
  64. interval = PR_MillisecondsToInterval(slapi_rand() % 100); \
  65. DS_Sleep(interval); \
  66. }
  67. #define ENTRYRDN_TAG "entryrdn-index"
  68. #define RDN_INDEX_SELF 'S'
  69. #define RDN_INDEX_CHILD 'C'
  70. #define RDN_INDEX_PARENT 'P'
  71. #define RDN_BULK_FETCH_BUFFER_SIZE (size_t)8*1024 /* DBLAYER_INDEX_PAGESIZE */
  72. #define RDN_STRINGID_LEN 64
  73. typedef struct _rdn_elem {
  74. char rdn_elem_id[sizeof(ID)];
  75. char rdn_elem_nrdn_len[2]; /* ushort; length including '\0' */
  76. char rdn_elem_rdn_len[2]; /* ushort; length including '\0' */
  77. char rdn_elem_nrdn_rdn[1]; /* "normalized rdn" '\0' "rdn" '\0' */
  78. } rdn_elem;
  79. #define RDN_ADDR(elem) \
  80. ((elem)->rdn_elem_nrdn_rdn + \
  81. sizeushort_stored_to_internal((elem)->rdn_elem_nrdn_len))
  82. #define TMPID 0 /* Used for the fake ID */
  83. /* RDN(s) which can be added even if no suffix exists in the entryrdn index */
  84. const char *rdn_exceptions[] = {
  85. "nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff",
  86. NULL
  87. };
  88. /* helper functions */
  89. static rdn_elem *_entryrdn_new_rdn_elem(backend *be, ID id, Slapi_RDN *srdn, size_t *length);
  90. static void _entryrdn_dup_rdn_elem(const void *raw, rdn_elem **new);
  91. static size_t _entryrdn_rdn_elem_size(rdn_elem *elem);
  92. #ifdef LDAP_DEBUG_ENTRYRDN
  93. static void _entryrdn_dump_rdn_elem(rdn_elem *elem);
  94. #endif
  95. static int _entryrdn_open_index(backend *be, struct attrinfo **ai, DB **dbp);
  96. #if 0 /* not used */
  97. static char *_entryrdn_encrypt_key(backend *be, const char *key, struct attrinfo *ai);
  98. static char *_entryrdn_decrypt_key(backend *be, const char *key, struct attrinfo *ai);
  99. #endif
  100. static int _entryrdn_get_elem(DBC *cursor, DBT *key, DBT *data, const char *comp_key, rdn_elem **elem);
  101. static int _entryrdn_get_tombstone_elem(DBC *cursor, Slapi_RDN *srdn, DBT *key, const char *comp_key, rdn_elem **elem);
  102. static int _entryrdn_put_data(DBC *cursor, DBT *key, DBT *data, char type, DB_TXN *db_txn);
  103. static int _entryrdn_del_data(DBC *cursor, DBT *key, DBT *data, DB_TXN *db_txn);
  104. static int _entryrdn_insert_key(backend *be, DBC *cursor, Slapi_RDN *srdn, ID id, DB_TXN *db_txn);
  105. static int _entryrdn_insert_key_elems(backend *be, DBC *cursor, Slapi_RDN *srdn, DBT *key, rdn_elem *elem, rdn_elem *childelem, size_t childelemlen, DB_TXN *db_txn);
  106. static int _entryrdn_delete_key(backend *be, DBC *cursor, Slapi_RDN *srdn, ID id, DB_TXN *db_txn);
  107. static int _entryrdn_index_read(backend *be, DBC *cursor, Slapi_RDN *srdn, rdn_elem **elem, rdn_elem **parentelem, rdn_elem ***childelems, int flags, DB_TXN *db_txn);
  108. static int _entryrdn_append_childidl(DBC *cursor, const char *nrdn, ID id, IDList **affectedidl);
  109. static void _entryrdn_cursor_print_error(char *fn, void *key, size_t need, size_t actual, int rc);
  110. static int entryrdn_warning_on_encryption = 1;
  111. /*
  112. * This function sets the integer value val to entryrdn_switch.
  113. * If val is non-zero, the entryrdn index is used and moving subtree
  114. * and/or renaming an RDN which has children is enabled.
  115. * If val is zero, the entrydn index is used.
  116. */
  117. void
  118. entryrdn_set_switch(int val)
  119. {
  120. entryrdn_switch = val;
  121. return;
  122. }
  123. /*
  124. * This function gets the value of entry_switch.
  125. * All the entryrdn related codes are supposed to be in the
  126. * if (entryrdn_get_switch()) clauses.
  127. */
  128. int
  129. entryrdn_get_switch()
  130. {
  131. return entryrdn_switch;
  132. }
  133. /*
  134. * Note: nsslapd-noancestorid never be "on" unless nsslapd-subtree-rename-switch
  135. * is on.
  136. */
  137. void
  138. entryrdn_set_noancestorid(int val)
  139. {
  140. if (entryrdn_switch) {
  141. entryrdn_noancestorid = val;
  142. } else {
  143. entryrdn_noancestorid = 0;
  144. }
  145. return;
  146. }
  147. int
  148. entryrdn_get_noancestorid()
  149. {
  150. if (entryrdn_switch) {
  151. return entryrdn_noancestorid;
  152. } else {
  153. return 0;
  154. }
  155. }
  156. /*
  157. * Rules:
  158. * NULL comes before anything else.
  159. * Otherwise, strcmp(elem_a->rdn_elem_nrdn_rdn - elem_b->rdn_elem_nrdn_rdn) is
  160. * returned.
  161. */
  162. int
  163. entryrdn_compare_dups(DB *db, const DBT *a, const DBT *b)
  164. {
  165. rdn_elem *elem_a = NULL;
  166. rdn_elem *elem_b = NULL;
  167. int delta = 0;
  168. if (NULL == a) {
  169. if (NULL == b) {
  170. return 0;
  171. } else {
  172. return -1;
  173. }
  174. } else if (NULL == b) {
  175. return 1;
  176. }
  177. elem_a = (rdn_elem *)a->data;
  178. elem_b = (rdn_elem *)b->data;
  179. delta = strcmp((char *)elem_a->rdn_elem_nrdn_rdn,
  180. (char *)elem_b->rdn_elem_nrdn_rdn);
  181. return delta;
  182. }
  183. /*
  184. * Add/Delete an entry 'e' to/from the entryrdn index
  185. */
  186. int
  187. entryrdn_index_entry(backend *be,
  188. struct backentry *e,
  189. int flags, /* BE_INDEX_ADD or BE_INDEX_DEL */
  190. back_txn *txn)
  191. {
  192. int rc = -1;
  193. struct attrinfo *ai = NULL;
  194. DB *db = NULL;
  195. DBC *cursor = NULL;
  196. DB_TXN *db_txn = (txn != NULL) ? txn->back_txn_txn : NULL;
  197. const Slapi_DN *sdn = NULL;
  198. Slapi_RDN *srdn = NULL;
  199. int db_retry = 0;
  200. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  201. "--> entryrdn_index_entry\n");
  202. if (NULL == be || NULL == e) {
  203. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  204. "entryrdn_index_entry: Param error: Empty %s\n",
  205. NULL==be?"backend":NULL==e?"entry":"unknown");
  206. return rc;
  207. }
  208. /* Open the entryrdn index */
  209. rc = _entryrdn_open_index(be, &ai, &db);
  210. if (rc || (NULL == db)) {
  211. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  212. "entryrdn_index_entry: Opening the index failed: "
  213. "%s(%d)\n",
  214. rc<0?dblayer_strerror(rc):"Invalid parameter", rc);
  215. return rc;
  216. }
  217. srdn = slapi_entry_get_srdn(e->ep_entry);
  218. if (NULL == slapi_rdn_get_rdn(srdn)) {
  219. sdn = slapi_entry_get_sdn_const(e->ep_entry);
  220. if (NULL == sdn) {
  221. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  222. "entryrdn_index_entry: Empty dn\n");
  223. goto bail;
  224. }
  225. rc = slapi_rdn_init_all_sdn(srdn, sdn);
  226. if (rc < 0) {
  227. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  228. "entryrdn_index_entry: Failed to convert "
  229. "%s to Slapi_RDN\n", slapi_sdn_get_dn(sdn));
  230. rc = LDAP_INVALID_DN_SYNTAX;
  231. goto bail;
  232. } else if (rc > 0) {
  233. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  234. "entryrdn_index_entry: %s does not belong to "
  235. "the db\n", slapi_sdn_get_dn(sdn));
  236. rc = DB_NOTFOUND;
  237. goto bail;
  238. }
  239. }
  240. /* Make a cursor */
  241. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  242. rc = db->cursor(db, db_txn, &cursor, 0);
  243. if (rc) {
  244. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  245. "entryrdn_index_entry: Failed to make a cursor: %s(%d)\n",
  246. dblayer_strerror(rc), rc);
  247. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  248. ENTRYRDN_DELAY;
  249. continue;
  250. }
  251. cursor = NULL;
  252. goto bail;
  253. } else {
  254. break; /* success */
  255. }
  256. }
  257. if (RETRY_TIMES == db_retry) {
  258. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  259. "entryrdn_index_entry: cursor open failed after [%d] retries\n", db_retry);
  260. rc = DB_LOCK_DEADLOCK;
  261. goto bail;
  262. }
  263. if (flags & BE_INDEX_ADD) {
  264. rc = _entryrdn_insert_key(be, cursor, srdn, e->ep_id, db_txn);
  265. } else if (flags & BE_INDEX_DEL) {
  266. rc = _entryrdn_delete_key(be, cursor, srdn, e->ep_id, db_txn);
  267. if (DB_NOTFOUND == rc) {
  268. rc = 0;
  269. }
  270. }
  271. bail:
  272. /* Close the cursor */
  273. if (cursor) {
  274. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  275. int myrc = cursor->c_close(cursor);
  276. if (0 != myrc) {
  277. slapi_log_error(ENTRYRDN_LOGLEVEL(myrc), ENTRYRDN_TAG,
  278. "entryrdn_index_entry: Failed to close cursor: %s(%d)\n",
  279. dblayer_strerror(myrc), myrc);
  280. if ((DB_LOCK_DEADLOCK == myrc) && !db_txn) {
  281. ENTRYRDN_DELAY;
  282. continue;
  283. }
  284. if (!rc) {
  285. /* if cursor close returns DEADLOCK, we must bubble that up
  286. to the higher layers for retries */
  287. rc = myrc;
  288. break;
  289. }
  290. } else {
  291. break; /* success */
  292. }
  293. }
  294. if (RETRY_TIMES == db_retry) {
  295. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  296. "entryrdn_index_entry: cursor close failed after [%d] retries\n", db_retry);
  297. rc = DB_LOCK_DEADLOCK;
  298. }
  299. }
  300. if (db) {
  301. dblayer_release_index_file(be, ai, db);
  302. }
  303. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  304. "<-- entryrdn_index_entry\n");
  305. return rc;
  306. }
  307. /*
  308. * input: Full DN in Slapi_RDN rdn
  309. * output: ID
  310. *
  311. * return values: 0 -- success
  312. * -1 -- error
  313. * param error (broken rdn, failed to get index file)
  314. * Otherwise -- (DB errors)
  315. */
  316. int
  317. entryrdn_index_read(backend *be,
  318. const Slapi_DN *sdn,
  319. ID *id,
  320. back_txn *txn)
  321. {
  322. return entryrdn_index_read_ext(be, sdn, id, 0/*flags*/, txn);
  323. }
  324. int
  325. entryrdn_index_read_ext(backend *be,
  326. const Slapi_DN *sdn,
  327. ID *id,
  328. int flags,
  329. back_txn *txn)
  330. {
  331. int rc = -1;
  332. struct attrinfo *ai = NULL;
  333. Slapi_RDN srdn = {0};
  334. DB *db = NULL;
  335. DB_TXN *db_txn = (txn != NULL) ? txn->back_txn_txn : NULL;
  336. DBC *cursor = NULL;
  337. rdn_elem *elem = NULL;
  338. int db_retry = 0;
  339. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  340. "--> entryrdn_index_read\n");
  341. if (NULL == be || NULL == sdn || NULL == id) {
  342. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  343. "entryrdn_index_read: Param error: Empty %s\n",
  344. NULL==be?"backend":NULL==sdn?"DN":
  345. NULL==id?"id container":"unknown");
  346. goto bail;
  347. }
  348. *id = 0;
  349. rc = slapi_rdn_init_all_sdn(&srdn, sdn);
  350. if (rc < 0) {
  351. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  352. "entryrdn_index_read: Param error: Failed to convert "
  353. "%s to Slapi_RDN\n", slapi_sdn_get_dn(sdn));
  354. rc = LDAP_INVALID_DN_SYNTAX;
  355. goto bail;
  356. } else if (rc > 0) {
  357. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  358. "entryrdn_index_read: %s does not belong to the db\n",
  359. slapi_sdn_get_dn(sdn));
  360. rc = DB_NOTFOUND;
  361. goto bail;
  362. }
  363. /* Open the entryrdn index */
  364. rc = _entryrdn_open_index(be, &ai, &db);
  365. if (rc || (NULL == db)) {
  366. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  367. "entryrdn_index_read: Opening the index failed: "
  368. "%s(%d)\n",
  369. rc<0?dblayer_strerror(rc):"Invalid parameter", rc);
  370. db = NULL;
  371. goto bail;
  372. }
  373. /* Make a cursor */
  374. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  375. rc = db->cursor(db, db_txn, &cursor, 0);
  376. if (rc) {
  377. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  378. "entryrdn_index_read: Failed to make a cursor: %s(%d)\n",
  379. dblayer_strerror(rc), rc);
  380. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  381. ENTRYRDN_DELAY;
  382. continue;
  383. }
  384. cursor = NULL;
  385. goto bail;
  386. } else {
  387. break; /* success */
  388. }
  389. }
  390. if (RETRY_TIMES == db_retry) {
  391. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  392. "entryrdn_index_read: Failed to make a cursor after [%d] retries\n",
  393. db_retry);
  394. rc = DB_LOCK_DEADLOCK;
  395. goto bail;
  396. }
  397. rc = _entryrdn_index_read(be, cursor, &srdn, &elem, NULL, NULL,
  398. flags, db_txn);
  399. if (rc) {
  400. goto bail;
  401. }
  402. *id = id_stored_to_internal(elem->rdn_elem_id);
  403. bail:
  404. /* Close the cursor */
  405. if (cursor) {
  406. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  407. int myrc = cursor->c_close(cursor);
  408. if (0 != myrc) {
  409. slapi_log_error(ENTRYRDN_LOGLEVEL(myrc), ENTRYRDN_TAG,
  410. "entryrdn_index_read: Failed to close cursor: %s(%d)\n",
  411. dblayer_strerror(myrc), myrc);
  412. if ((DB_LOCK_DEADLOCK == myrc) && !db_txn) {
  413. ENTRYRDN_DELAY;
  414. continue;
  415. }
  416. if (!rc) {
  417. /* if cursor close returns DEADLOCK, we must bubble that up
  418. to the higher layers for retries */
  419. rc = myrc;
  420. break;
  421. }
  422. } else {
  423. break; /* success */
  424. }
  425. }
  426. if (RETRY_TIMES == db_retry) {
  427. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  428. "entryrdn_index_read: Failed to close cursor after [%d] retries\n",
  429. db_retry);
  430. rc = rc ? rc : DB_LOCK_DEADLOCK;
  431. }
  432. }
  433. if (db) {
  434. dblayer_release_index_file(be, ai, db);
  435. }
  436. slapi_rdn_done(&srdn);
  437. slapi_ch_free((void **)&elem);
  438. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  439. "<-- entryrdn_index_read\n");
  440. return rc;
  441. }
  442. /*
  443. * rename oldsdn <rdn>,<old superior> to <new rdn>,<new superior>
  444. *
  445. * This function renames and/or moves the given subtree.
  446. * The second argument ''oldsdn'' is the DN to be moved/renamed.
  447. * In the modrdn operation, the value of newrdn is set to this third argument
  448. * newsrdn. If the new RDN is not the same as the leaf RDN in the original
  449. * DN oldsdn, the original RDN is renamed to the new RDN.
  450. * If the newsuperior is set in the modrdn operation, the value is set to the
  451. * fourth argument newsupsdn. If the value is non-zero, the original leaf RDN
  452. * is moved under the new superior relinking the parent and child links.
  453. */
  454. int
  455. entryrdn_rename_subtree(backend *be,
  456. const Slapi_DN *oldsdn,
  457. Slapi_RDN *newsrdn, /* new rdn */
  458. const Slapi_DN *newsupsdn, /* new superior dn */
  459. ID id,
  460. back_txn *txn,
  461. int flags)
  462. {
  463. int rc = -1;
  464. struct attrinfo *ai = NULL;
  465. DB *db = NULL;
  466. DBC *cursor = NULL;
  467. DB_TXN *db_txn = (txn != NULL) ? txn->back_txn_txn : NULL;
  468. Slapi_RDN oldsrdn = {0};
  469. Slapi_RDN supsrdn = {0};
  470. Slapi_RDN newsupsrdn = {0};
  471. const char *nrdn = NULL; /* normalized rdn */
  472. int rdnidx = -1;
  473. char *keybuf = NULL;
  474. DBT key;
  475. DBT renamedata;
  476. rdn_elem *targetelem = NULL;
  477. rdn_elem *newelem = NULL;
  478. rdn_elem *newsupelem = NULL;
  479. rdn_elem *oldsupelem = NULL;
  480. rdn_elem **childelems = NULL;
  481. rdn_elem **cep = NULL;
  482. size_t targetelemlen = 0;
  483. size_t newelemlen = 0;
  484. size_t newsupelemlen = 0;
  485. size_t oldsupelemlen = 0;
  486. const Slapi_DN *mynewsupsdn = NULL;
  487. Slapi_RDN *mynewsrdn = NULL;
  488. ID targetid = 0;
  489. int db_retry = 0;
  490. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  491. "--> entryrdn_rename_subtree\n");
  492. if (NULL == be || NULL == oldsdn || 0 == id) {
  493. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  494. "entryrdn_rename_subtree: Param error: Empty %s\n",
  495. NULL==be?"backend":NULL==oldsdn?"old dn":
  496. (NULL==newsrdn&&NULL==newsupsdn)?"new dn and new superior":
  497. 0==id?"id":"unknown");
  498. goto bail;
  499. }
  500. rc = slapi_rdn_init_all_sdn_ext(&oldsrdn, oldsdn, flags);
  501. if (rc < 0) {
  502. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  503. "entryrdn_rename_subtree: Failed to convert olddn "
  504. "\"%s\" to Slapi_RDN\n", slapi_sdn_get_dn(oldsdn));
  505. rc = LDAP_INVALID_DN_SYNTAX;
  506. goto bail;
  507. } else if (rc > 0) {
  508. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  509. "entryrdn_rename_subtree: %s does not belong to "
  510. "the db\n", slapi_sdn_get_dn(oldsdn));
  511. rc = DB_NOTFOUND;
  512. goto bail;
  513. }
  514. /* newsupsdn is given and DN value is set in it. */
  515. if (newsupsdn && slapi_sdn_get_dn(newsupsdn)) {
  516. mynewsupsdn = newsupsdn;
  517. }
  518. /* newsrdn is given and RDN value is set in it. */
  519. if (newsrdn && slapi_rdn_get_rdn(newsrdn)) {
  520. /* if the new RDN value is identical to the old RDN,
  521. * we don't have to do "rename" */
  522. /* Don't miss the case changes, too. */
  523. if (strcmp(slapi_rdn_get_rdn(newsrdn), slapi_rdn_get_rdn(&oldsrdn))) {
  524. /* did not match; let's rename it */
  525. mynewsrdn = newsrdn;
  526. }
  527. }
  528. if (NULL == mynewsrdn && NULL == mynewsupsdn) {
  529. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  530. "entryrdn_rename_subtree: No new superior is given "
  531. "and new rdn %s is identical to the original\n",
  532. slapi_rdn_get_rdn(&oldsrdn));
  533. goto bail;
  534. }
  535. /* Checking the contents of oldsrdn */
  536. rdnidx = slapi_rdn_get_last_ext(&oldsrdn, &nrdn, FLAG_ALL_NRDNS);
  537. if (rdnidx < 0 || NULL == nrdn) {
  538. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  539. "entryrdn_rename_subtree: Empty RDN\n");
  540. goto bail;
  541. } else if (0 == rdnidx) {
  542. if (mynewsupsdn) {
  543. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  544. "entryrdn_move_subtree: Moving suffix \"%s\" is "
  545. "not alloweds\n", nrdn);
  546. goto bail;
  547. } else {
  548. /* newsupsdn == NULL, so newsrdn is not */
  549. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  550. "entryrdn_rename_subtree: Renaming suffix %s to %s\n",
  551. nrdn, slapi_rdn_get_nrdn((Slapi_RDN *)mynewsrdn));
  552. }
  553. }
  554. /* Open the entryrdn index */
  555. rc = _entryrdn_open_index(be, &ai, &db);
  556. if (rc || (NULL == db)) {
  557. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  558. "entryrdn_rename_subtree: Opening the index failed: "
  559. "%s(%d)\n",
  560. rc<0?dblayer_strerror(rc):"Invalid parameter", rc);
  561. db = NULL;
  562. return rc;
  563. }
  564. /* Make a cursor */
  565. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  566. rc = db->cursor(db, db_txn, &cursor, 0);
  567. if (rc) {
  568. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  569. "entryrdn_rename_subtree: Failed to make a cursor: %s(%d)\n",
  570. dblayer_strerror(rc), rc);
  571. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  572. ENTRYRDN_DELAY;
  573. continue;
  574. }
  575. cursor = NULL;
  576. goto bail;
  577. } else {
  578. break; /* success */
  579. }
  580. }
  581. if (RETRY_TIMES == db_retry) {
  582. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  583. "entryrdn_rename_subtree: create cursor failed after [%d] retries\n",
  584. db_retry);
  585. rc = DB_LOCK_DEADLOCK;
  586. goto bail;
  587. }
  588. /* prepare the element for the newly renamed rdn, if any. */
  589. if (mynewsrdn) {
  590. newelem = _entryrdn_new_rdn_elem(be, id, mynewsrdn, &newelemlen);
  591. if (NULL == newelem) {
  592. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  593. "entryrdn_rename_subtree: Failed to generate "
  594. "a new elem: id: %d, rdn: %s\n",
  595. id, slapi_rdn_get_rdn(mynewsrdn));
  596. goto bail;
  597. }
  598. }
  599. /* Get the new superior elem, if any. */
  600. if (mynewsupsdn) {
  601. rc = slapi_rdn_init_all_sdn(&newsupsrdn, mynewsupsdn);
  602. if (rc < 0) {
  603. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  604. "entryrdn_rename_subtree: Failed to convert "
  605. "new superior \"%s\" to Slapi_RDN\n",
  606. slapi_sdn_get_dn(mynewsupsdn));
  607. rc = LDAP_INVALID_DN_SYNTAX;
  608. goto bail;
  609. } else if (rc > 0) {
  610. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  611. "entryrdn_rename_subtree: %s does not belong "
  612. "to the db\n", slapi_sdn_get_dn(mynewsupsdn));
  613. rc = DB_NOTFOUND;
  614. goto bail;
  615. }
  616. rc = _entryrdn_index_read(be, cursor, &newsupsrdn, &newsupelem,
  617. NULL, NULL, 0/*flags*/, db_txn);
  618. if (rc) {
  619. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  620. "entryrdn_rename_subtree: Failed to read "
  621. "the element of new superior \"%s\" (%d)\n",
  622. slapi_sdn_get_dn(mynewsupsdn), rc);
  623. goto bail;
  624. }
  625. newsupelemlen = _entryrdn_rdn_elem_size(newsupelem);
  626. }
  627. if (mynewsrdn) {
  628. rc = _entryrdn_index_read(be, cursor, &oldsrdn, &targetelem,
  629. &oldsupelem, &childelems, 0/*flags*/, db_txn);
  630. } else {
  631. rc = _entryrdn_index_read(be, cursor, &oldsrdn, &targetelem,
  632. &oldsupelem, NULL, 0/*flags*/, db_txn);
  633. }
  634. if (rc || NULL == targetelem) {
  635. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  636. "entryrdn_rename_subtree: Failed to read "
  637. "the target element \"%s\" (%d)\n",
  638. slapi_sdn_get_dn(oldsdn), rc);
  639. goto bail;
  640. }
  641. targetid = id_stored_to_internal(targetelem->rdn_elem_id);
  642. targetelemlen = _entryrdn_rdn_elem_size(targetelem);
  643. if (oldsupelem) {
  644. oldsupelemlen = _entryrdn_rdn_elem_size(oldsupelem);
  645. }
  646. /* 1) rename targetelem */
  647. /* 2) update targetelem's child link, if renaming the target */
  648. if (mynewsrdn) {
  649. /* remove the old elem; (1) rename targetelem */
  650. keybuf = slapi_ch_smprintf("%u", targetid);
  651. key.data = keybuf;
  652. key.size = key.ulen = strlen(keybuf) + 1;
  653. key.flags = DB_DBT_USERMEM;
  654. memset(&renamedata, 0, sizeof(renamedata));
  655. renamedata.ulen = renamedata.size = targetelemlen;
  656. renamedata.data = (void *)targetelem;
  657. renamedata.flags = DB_DBT_USERMEM;
  658. rc = _entryrdn_del_data(cursor, &key, &renamedata, db_txn);
  659. if (rc) {
  660. goto bail;
  661. }
  662. if (childelems) {
  663. slapi_ch_free_string(&keybuf);
  664. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_CHILD, targetid);
  665. key.data = keybuf;
  666. key.size = key.ulen = strlen(keybuf) + 1;
  667. key.flags = DB_DBT_USERMEM;
  668. /* remove the old elem; (2) update targetelem's child link */
  669. for (cep = childelems; cep && *cep; cep++) {
  670. memset(&renamedata, 0, sizeof(renamedata));
  671. renamedata.ulen = renamedata.size =
  672. _entryrdn_rdn_elem_size(*cep);
  673. renamedata.data = (void *)(*cep);
  674. renamedata.flags = DB_DBT_USERMEM;
  675. rc = _entryrdn_del_data(cursor, &key, &renamedata, db_txn);
  676. if (rc) {
  677. goto bail;
  678. }
  679. }
  680. }
  681. /* add the new elem */
  682. slapi_ch_free_string(&keybuf);
  683. keybuf = slapi_ch_smprintf("%u", id);
  684. key.data = keybuf;
  685. key.size = key.ulen = strlen(keybuf) + 1;
  686. key.flags = DB_DBT_USERMEM;
  687. memset(&renamedata, 0, sizeof(renamedata));
  688. renamedata.ulen = renamedata.size = newelemlen;
  689. renamedata.data = (void *)newelem;
  690. renamedata.flags = DB_DBT_USERMEM;
  691. rc = _entryrdn_put_data(cursor, &key, &renamedata, RDN_INDEX_SELF, db_txn);
  692. if (rc && (DB_KEYEXIST != rc)) { /* failed && ignore already exists */
  693. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  694. "entryrdn_rename_subtree: Adding %s failed; "
  695. "%s(%d)\n", keybuf, dblayer_strerror(rc), rc);
  696. goto bail;
  697. }
  698. if (childelems) {
  699. slapi_ch_free_string(&keybuf);
  700. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_CHILD, id);
  701. key.data = keybuf;
  702. key.size = key.ulen = strlen(keybuf) + 1;
  703. key.flags = DB_DBT_USERMEM;
  704. /* add the new elem; (2) update targetelem's child link */
  705. for (cep = childelems; cep && *cep; cep++) {
  706. memset(&renamedata, 0, sizeof(renamedata));
  707. renamedata.ulen = renamedata.size =
  708. _entryrdn_rdn_elem_size(*cep);
  709. renamedata.data = (void *)(*cep);
  710. renamedata.flags = DB_DBT_USERMEM;
  711. rc = _entryrdn_put_data(cursor, &key,
  712. &renamedata, RDN_INDEX_CHILD, db_txn);
  713. if (rc && (DB_KEYEXIST != rc)) { /* failed && ignore already exists */
  714. goto bail;
  715. }
  716. }
  717. }
  718. }
  719. /* 3) update targetelem's parent link, if any */
  720. if (oldsupelem) {
  721. slapi_ch_free_string(&keybuf);
  722. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_PARENT, targetid);
  723. key.data = keybuf;
  724. key.size = key.ulen = strlen(keybuf) + 1;
  725. key.flags = DB_DBT_USERMEM;
  726. memset(&renamedata, 0, sizeof(renamedata));
  727. renamedata.ulen = renamedata.size = oldsupelemlen;
  728. renamedata.data = (void *)oldsupelem;
  729. renamedata.flags = DB_DBT_USERMEM;
  730. rc = _entryrdn_del_data(cursor, &key, &renamedata, db_txn);
  731. if (rc) {
  732. goto bail;
  733. }
  734. /* add the new elem */
  735. if (mynewsrdn) {
  736. slapi_ch_free_string(&keybuf);
  737. key.flags = DB_DBT_USERMEM;
  738. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_PARENT, id);
  739. key.data = keybuf;
  740. key.size = key.ulen = strlen(keybuf) + 1;
  741. memset(&renamedata, 0, sizeof(renamedata));
  742. renamedata.flags = DB_DBT_USERMEM;
  743. if (mynewsupsdn) {
  744. renamedata.ulen = renamedata.size = newsupelemlen;
  745. renamedata.data = (void *)newsupelem;
  746. } else {
  747. renamedata.ulen = renamedata.size = oldsupelemlen;
  748. renamedata.data = (void *)oldsupelem;
  749. }
  750. } else {
  751. renamedata.ulen = renamedata.size = newsupelemlen;
  752. renamedata.data = (void *)newsupelem;
  753. }
  754. rc = _entryrdn_put_data(cursor, &key, &renamedata, RDN_INDEX_PARENT, db_txn);
  755. if (rc && (DB_KEYEXIST != rc)) { /* failed && ignore already exists */
  756. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  757. "entryrdn_rename_subtree: Adding "
  758. "%s failed; %s(%d)\n",
  759. keybuf, dblayer_strerror(rc), rc);
  760. goto bail;
  761. }
  762. }
  763. /* 4) update targetelem's children's parent link, if renaming the target */
  764. if (mynewsrdn) {
  765. for (cep = childelems; cep && *cep; cep++) {
  766. /* remove the old elem */
  767. slapi_ch_free_string(&keybuf);
  768. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_PARENT,
  769. id_stored_to_internal((*cep)->rdn_elem_id));
  770. key.data = keybuf;
  771. key.size = key.ulen = strlen(keybuf) + 1;
  772. key.flags = DB_DBT_USERMEM;
  773. memset(&renamedata, 0, sizeof(renamedata));
  774. renamedata.ulen = renamedata.size = targetelemlen;
  775. renamedata.data = (void *)targetelem;
  776. renamedata.flags = DB_DBT_USERMEM;
  777. rc = _entryrdn_del_data(cursor, &key, &renamedata, db_txn);
  778. if (rc) {
  779. goto bail;
  780. }
  781. /* add the new elem */
  782. memset(&renamedata, 0, sizeof(renamedata));
  783. renamedata.ulen = renamedata.size = newelemlen;
  784. renamedata.data = (void *)newelem;
  785. renamedata.flags = DB_DBT_USERMEM;
  786. rc = _entryrdn_put_data(cursor, &key, &renamedata, RDN_INDEX_SELF, db_txn);
  787. if (rc && (DB_KEYEXIST != rc)) { /* failed && ignore already exists */
  788. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  789. "entryrdn_rename_subtree: Adding %s failed; "
  790. "%s(%d)\n", keybuf, dblayer_strerror(rc), rc);
  791. goto bail;
  792. }
  793. }
  794. }
  795. /* 5) update parentelem's child link (except renaming the suffix) */
  796. if (oldsupelem) {
  797. /* remove the old elem */
  798. slapi_ch_free_string(&keybuf);
  799. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_CHILD,
  800. id_stored_to_internal(oldsupelem->rdn_elem_id));
  801. key.data = keybuf;
  802. key.size = key.ulen = strlen(keybuf) + 1;
  803. key.flags = DB_DBT_USERMEM;
  804. memset(&renamedata, 0, sizeof(renamedata));
  805. renamedata.ulen = renamedata.size = targetelemlen;
  806. renamedata.data = (void *)targetelem;
  807. renamedata.flags = DB_DBT_USERMEM;
  808. rc = _entryrdn_del_data(cursor, &key, &renamedata, db_txn);
  809. if (rc) {
  810. goto bail;
  811. }
  812. /* add the new elem */
  813. if (mynewsupsdn) {
  814. slapi_ch_free_string(&keybuf);
  815. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_CHILD,
  816. id_stored_to_internal(newsupelem->rdn_elem_id));
  817. key.data = keybuf;
  818. key.size = key.ulen = strlen(keybuf) + 1;
  819. key.flags = DB_DBT_USERMEM;
  820. memset(&renamedata, 0, sizeof(renamedata));
  821. renamedata.flags = DB_DBT_USERMEM;
  822. if (mynewsrdn) {
  823. renamedata.ulen = renamedata.size = newelemlen;
  824. renamedata.data = (void *)newelem;
  825. } else {
  826. renamedata.ulen = renamedata.size = targetelemlen;
  827. renamedata.data = (void *)targetelem;
  828. }
  829. } else {
  830. memset(&renamedata, 0, sizeof(renamedata));
  831. renamedata.ulen = renamedata.size = newelemlen;
  832. renamedata.data = (void *)newelem;
  833. renamedata.flags = DB_DBT_USERMEM;
  834. }
  835. rc = _entryrdn_put_data(cursor, &key, &renamedata, RDN_INDEX_CHILD, db_txn);
  836. if (rc && (DB_KEYEXIST != rc)) { /* failed && ignore already exists */
  837. goto bail;
  838. }
  839. }
  840. bail:
  841. slapi_ch_free_string(&keybuf);
  842. slapi_ch_free((void **)&targetelem);
  843. slapi_ch_free((void **)&newelem);
  844. slapi_ch_free((void **)&newsupelem);
  845. slapi_ch_free((void **)&oldsupelem);
  846. slapi_rdn_done(&oldsrdn);
  847. slapi_rdn_done(&supsrdn);
  848. slapi_rdn_done(&newsupsrdn);
  849. if (childelems) {
  850. for (cep = childelems; *cep; cep++) {
  851. slapi_ch_free((void **)cep);
  852. }
  853. slapi_ch_free((void **)&childelems);
  854. }
  855. /* Close the cursor */
  856. if (cursor) {
  857. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  858. int myrc = cursor->c_close(cursor);
  859. if (0 != myrc) {
  860. slapi_log_error(ENTRYRDN_LOGLEVEL(myrc), ENTRYRDN_TAG,
  861. "entryrdn_rename_subtree: Failed to close cursor: %s(%d)\n",
  862. dblayer_strerror(myrc), myrc);
  863. if ((DB_LOCK_DEADLOCK == myrc) && !db_txn) {
  864. ENTRYRDN_DELAY;
  865. continue;
  866. }
  867. if (!rc) {
  868. /* if cursor close returns DEADLOCK, we must bubble that up
  869. to the higher layers for retries */
  870. rc = myrc;
  871. break;
  872. }
  873. } else {
  874. break; /* success */
  875. }
  876. }
  877. if (RETRY_TIMES == db_retry) {
  878. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  879. "entryrdn_rename_subtree: Failed to close cursor after [%d] retries.\n",
  880. db_retry);
  881. rc = rc ? rc : DB_LOCK_DEADLOCK;
  882. }
  883. }
  884. if (db) {
  885. dblayer_release_index_file(be, ai, db);
  886. }
  887. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  888. "<-- entryrdn_rename_subtree\n");
  889. return rc;
  890. }
  891. /*
  892. * Get the IDList of direct childen and indirect subordinates
  893. * OUTPUT: subordinates
  894. */
  895. int
  896. entryrdn_get_subordinates(backend *be,
  897. const Slapi_DN *sdn,
  898. ID id,
  899. IDList **subordinates,
  900. back_txn *txn,
  901. int flags)
  902. {
  903. int rc = -1;
  904. struct attrinfo *ai = NULL;
  905. DB *db = NULL;
  906. DBC *cursor = NULL;
  907. DB_TXN *db_txn = (txn != NULL) ? txn->back_txn_txn : NULL;
  908. Slapi_RDN srdn = {0};
  909. const char *nrdn = NULL; /* normalized rdn */
  910. int rdnidx = -1;
  911. char *keybuf = NULL;
  912. rdn_elem *elem = NULL;
  913. rdn_elem **childelems = NULL;
  914. rdn_elem **cep = NULL;
  915. int db_retry = 0;
  916. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  917. "--> entryrdn_get_subordinates\n");
  918. if (NULL == be || NULL == sdn || 0 == id) {
  919. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  920. "entryrdn_get_subordinates: Param error: Empty %s\n",
  921. NULL==be?"backend":NULL==sdn?"dn":0==id?"id":"unknown");
  922. goto bail;
  923. }
  924. if (subordinates) {
  925. *subordinates = NULL;
  926. } else {
  927. rc = 0;
  928. goto bail;
  929. }
  930. rc = slapi_rdn_init_all_sdn_ext(&srdn, sdn, flags);
  931. if (rc) {
  932. if (rc < 0) {
  933. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  934. "entryrdn_get_subordinates: Failed to convert "
  935. "\"%s\" to Slapi_RDN\n", slapi_sdn_get_dn(sdn));
  936. rc = LDAP_INVALID_DN_SYNTAX;
  937. } else if (rc > 0) {
  938. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  939. "entryrdn_get_subordinates: %s does not belong to "
  940. "the db\n", slapi_sdn_get_dn(sdn));
  941. rc = DB_NOTFOUND;
  942. }
  943. goto bail;
  944. }
  945. /* check the given dn/srdn */
  946. rdnidx = slapi_rdn_get_last_ext(&srdn, &nrdn, FLAG_ALL_NRDNS);
  947. if (rdnidx < 0 || NULL == nrdn) {
  948. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  949. "entryrdn_get_subordinates: Empty RDN\n");
  950. goto bail;
  951. }
  952. /* Open the entryrdn index */
  953. rc = _entryrdn_open_index(be, &ai, &db);
  954. if (rc || (NULL == db)) {
  955. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  956. "entryrdn_get_subordinates: Opening the index failed: "
  957. "%s(%d)\n",
  958. rc<0?dblayer_strerror(rc):"Invalid parameter", rc);
  959. db = NULL;
  960. goto bail;
  961. }
  962. /* Make a cursor */
  963. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  964. rc = db->cursor(db, db_txn, &cursor, 0);
  965. if (rc) {
  966. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  967. "entryrdn_get_subordinates: Failed to make a cursor: %s(%d)\n",
  968. dblayer_strerror(rc), rc);
  969. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  970. ENTRYRDN_DELAY;
  971. continue;
  972. }
  973. cursor = NULL;
  974. goto bail;
  975. } else {
  976. break; /* success */
  977. }
  978. }
  979. if (RETRY_TIMES == db_retry) {
  980. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  981. "entryrdn_get_subordinates: Failed to make a cursor after [%d] retries\n",
  982. db_retry);
  983. rc = DB_LOCK_DEADLOCK;
  984. goto bail;
  985. }
  986. rc = _entryrdn_index_read(be, cursor, &srdn, &elem,
  987. NULL, &childelems, 0/*flags*/, db_txn);
  988. for (cep = childelems; cep && *cep; cep++) {
  989. ID childid = id_stored_to_internal((*cep)->rdn_elem_id);
  990. /* set direct children to the idlist */
  991. rc = idl_append_extend(subordinates, childid);
  992. if (rc) {
  993. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  994. "entryrdn_get_subordinates: Appending %d to idl "
  995. "for direct children failed (%d)\n", childid, rc);
  996. goto bail;
  997. }
  998. /* set indirect subordinates to the idlist */
  999. rc = _entryrdn_append_childidl(cursor, (*cep)->rdn_elem_nrdn_rdn,
  1000. childid, subordinates);
  1001. if (rc) {
  1002. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1003. "entryrdn_get_subordinates: Appending %d to idl "
  1004. "for indirect children failed (%d)\n",
  1005. childid, rc);
  1006. goto bail;
  1007. }
  1008. }
  1009. bail:
  1010. if (rc && subordinates && *subordinates) {
  1011. idl_free(subordinates);
  1012. }
  1013. slapi_ch_free_string(&keybuf);
  1014. slapi_ch_free((void **)&elem);
  1015. slapi_rdn_done(&srdn);
  1016. if (childelems) {
  1017. for (cep = childelems; *cep; cep++) {
  1018. slapi_ch_free((void **)cep);
  1019. }
  1020. slapi_ch_free((void **)&childelems);
  1021. }
  1022. /* Close the cursor */
  1023. if (cursor) {
  1024. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  1025. int myrc = cursor->c_close(cursor);
  1026. if (0 != myrc) {
  1027. slapi_log_error(ENTRYRDN_LOGLEVEL(myrc), ENTRYRDN_TAG,
  1028. "entryrdn_get_subordinates: Failed to close cursor: %s(%d)\n",
  1029. dblayer_strerror(myrc), myrc);
  1030. if ((DB_LOCK_DEADLOCK == myrc) && !db_txn) {
  1031. ENTRYRDN_DELAY;
  1032. continue;
  1033. }
  1034. if (!rc) {
  1035. /* if cursor close returns DEADLOCK, we must bubble that up
  1036. to the higher layers for retries */
  1037. rc = myrc;
  1038. break;
  1039. }
  1040. } else {
  1041. break; /* success */
  1042. }
  1043. }
  1044. if (RETRY_TIMES == db_retry) {
  1045. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1046. "entryrdn_get_subordinates: Failed to close cursor after [%d] retries\n",
  1047. db_retry);
  1048. rc = rc ? rc : DB_LOCK_DEADLOCK;
  1049. goto bail;
  1050. }
  1051. }
  1052. if (db) {
  1053. dblayer_release_index_file(be, ai, db);
  1054. }
  1055. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1056. "<-- entryrdn_get_subordinates\n");
  1057. return rc;
  1058. }
  1059. /*
  1060. * Input: (rdn, id)
  1061. * Output: dn
  1062. *
  1063. * caller is responsible to release *dn
  1064. */
  1065. int
  1066. entryrdn_lookup_dn(backend *be,
  1067. const char *rdn,
  1068. ID id,
  1069. char **dn,
  1070. back_txn *txn)
  1071. {
  1072. int rc = -1;
  1073. struct attrinfo *ai = NULL;
  1074. DB *db = NULL;
  1075. DBC *cursor = NULL;
  1076. DB_TXN *db_txn = (txn != NULL) ? txn->back_txn_txn : NULL;
  1077. DBT key, data;
  1078. char *keybuf = NULL;
  1079. Slapi_RDN *srdn = NULL;
  1080. char *orignrdn = NULL;
  1081. char *nrdn = NULL;
  1082. size_t nrdn_len = 0;
  1083. ID workid = id; /* starting from the given id */
  1084. rdn_elem *elem = NULL;
  1085. int maybesuffix = 0;
  1086. int db_retry = 0;
  1087. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1088. "--> entryrdn_lookup_dn\n");
  1089. if (NULL == be || NULL == rdn || 0 == id || NULL == dn) {
  1090. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1091. "entryrdn_lookup_dn: Param error: Empty %s\n",
  1092. NULL==be?"backend":NULL==rdn?"rdn":0==id?"id":
  1093. NULL==dn?"dn container":"unknown");
  1094. return rc;
  1095. }
  1096. *dn = NULL;
  1097. /* Open the entryrdn index */
  1098. rc = _entryrdn_open_index(be, &ai, &db);
  1099. if (rc || (NULL == db)) {
  1100. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1101. "entryrdn_lookup_dn: Opening the index failed: "
  1102. "%s(%d)\n",
  1103. rc<0?dblayer_strerror(rc):"Invalid parameter", rc);
  1104. return rc;
  1105. }
  1106. memset(&data, 0, sizeof(data));
  1107. /* Make a cursor */
  1108. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  1109. rc = db->cursor(db, db_txn, &cursor, 0);
  1110. if (rc) {
  1111. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  1112. "entryrdn_lookup_dn: Failed to make a cursor: %s(%d)\n",
  1113. dblayer_strerror(rc), rc);
  1114. if (DB_LOCK_DEADLOCK == rc) {
  1115. #ifdef FIX_TXN_DEADLOCKS
  1116. #error if txn != NULL, have to retry the entire transaction
  1117. #endif
  1118. ENTRYRDN_DELAY;
  1119. continue;
  1120. }
  1121. cursor = NULL;
  1122. goto bail;
  1123. } else {
  1124. break; /* success */
  1125. }
  1126. }
  1127. srdn = slapi_rdn_new_all_dn(rdn);
  1128. orignrdn = slapi_ch_strdup(rdn);
  1129. rc = slapi_dn_normalize_case_ext(orignrdn, 0, &nrdn, &nrdn_len);
  1130. if (rc < 0) {
  1131. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1132. "entryrdn_get_parent: Failed to normalize %s\n", rdn);
  1133. goto bail;
  1134. }
  1135. if (rc == 0) { /* orignrdn is passed in */
  1136. *(nrdn + nrdn_len) = '\0';
  1137. } else {
  1138. slapi_ch_free_string(&orignrdn);
  1139. }
  1140. /* Setting the bulk fetch buffer */
  1141. data.flags = DB_DBT_MALLOC;
  1142. do {
  1143. /* Setting up a key for the node to get its parent */
  1144. slapi_ch_free_string(&keybuf);
  1145. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_PARENT, workid);
  1146. key.data = keybuf;
  1147. key.size = key.ulen = strlen(keybuf) + 1;
  1148. key.flags = DB_DBT_USERMEM;
  1149. /* Position cursor at the matching key */
  1150. retry_get0:
  1151. rc = cursor->c_get(cursor, &key, &data, DB_SET);
  1152. if (rc) {
  1153. if (DB_LOCK_DEADLOCK == rc) {
  1154. /* try again */
  1155. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  1156. "entryrdn_get_parent: cursor get deadlock\n");
  1157. #ifdef FIX_TXN_DEADLOCKS
  1158. #error if txn != NULL, have to retry the entire transaction
  1159. #endif
  1160. goto retry_get0;
  1161. } else if (DB_NOTFOUND == rc) { /* could be a suffix or
  1162. note: no parent for suffix */
  1163. slapi_ch_free_string(&keybuf);
  1164. keybuf = slapi_ch_smprintf("%s", nrdn);
  1165. key.data = keybuf;
  1166. key.size = key.ulen = strlen(keybuf) + 1;
  1167. key.flags = DB_DBT_USERMEM;
  1168. retry_get1:
  1169. rc = cursor->c_get(cursor, &key, &data, DB_SET);
  1170. if (rc) {
  1171. if (DB_LOCK_DEADLOCK == rc) {
  1172. /* try again */
  1173. #ifdef FIX_TXN_DEADLOCKS
  1174. #error if txn != NULL, have to retry the entire transaction
  1175. #endif
  1176. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  1177. "entryrdn_get_parent: retry cursor get deadlock\n");
  1178. goto retry_get1;
  1179. } else if (DB_NOTFOUND != rc) {
  1180. _entryrdn_cursor_print_error("entryrdn_lookup_dn",
  1181. key.data, data.size, data.ulen, rc);
  1182. }
  1183. goto bail;
  1184. }
  1185. maybesuffix = 1;
  1186. } else {
  1187. _entryrdn_cursor_print_error("entryrdn_lookup_dn",
  1188. key.data, data.size, data.ulen, rc);
  1189. goto bail;
  1190. }
  1191. }
  1192. /* Iterate over the duplicates to get the direct child's ID */
  1193. workid = 0;
  1194. if (maybesuffix) {
  1195. /* it is a suffix, indeed. done. */
  1196. /* generate sdn to return */
  1197. slapi_rdn_get_dn(srdn, dn);
  1198. rc = 0;
  1199. goto bail;
  1200. }
  1201. /* found a parent (there should be just one parent :) */
  1202. elem = (rdn_elem *)data.data;
  1203. #ifdef LDAP_DEBUG_ENTRYRDN
  1204. _entryrdn_dump_rdn_elem(elem);
  1205. #endif
  1206. slapi_ch_free_string(&nrdn);
  1207. nrdn = slapi_ch_strdup(elem->rdn_elem_nrdn_rdn);
  1208. workid = id_stored_to_internal(elem->rdn_elem_id);
  1209. /* 1 is byref, and the dup'ed rdn is freed with srdn */
  1210. slapi_rdn_add_rdn_to_all_rdns(srdn, slapi_ch_strdup(RDN_ADDR(elem)), 1);
  1211. slapi_ch_free(&data.data);
  1212. } while (workid);
  1213. if (0 == workid) {
  1214. rc = -1;
  1215. }
  1216. bail:
  1217. slapi_ch_free(&data.data);
  1218. /* Close the cursor */
  1219. if (cursor) {
  1220. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  1221. int myrc = cursor->c_close(cursor);
  1222. if (0 != myrc) {
  1223. slapi_log_error(ENTRYRDN_LOGLEVEL(myrc), ENTRYRDN_TAG,
  1224. "entryrdn_lookup_dn: Failed to close cursor: %s(%d)\n",
  1225. dblayer_strerror(myrc), myrc);
  1226. if (DB_LOCK_DEADLOCK == myrc) {
  1227. #ifdef FIX_TXN_DEADLOCKS
  1228. #error if txn != NULL, have to retry the entire transaction
  1229. #endif
  1230. ENTRYRDN_DELAY;
  1231. continue;
  1232. }
  1233. if (!rc) {
  1234. /* if cursor close returns DEADLOCK, we must bubble that up
  1235. to the higher layers for retries */
  1236. rc = myrc;
  1237. break;
  1238. }
  1239. } else {
  1240. break; /* success */
  1241. }
  1242. }
  1243. }
  1244. /* it is guaranteed that db is not NULL. */
  1245. dblayer_release_index_file(be, ai, db);
  1246. slapi_rdn_free(&srdn);
  1247. slapi_ch_free_string(&nrdn);
  1248. slapi_ch_free_string(&keybuf);
  1249. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1250. "<-- entryrdn_lookup_dn\n");
  1251. return rc;
  1252. }
  1253. /*
  1254. * Input: (rdn, id)
  1255. * Output: (prdn, pid)
  1256. *
  1257. * If Input is a suffix, the Output is also a suffix.
  1258. * If the rc is DB_NOTFOUND, the index is empty.
  1259. * caller is responsible to release *prdn
  1260. */
  1261. int
  1262. entryrdn_get_parent(backend *be,
  1263. const char *rdn,
  1264. ID id,
  1265. char **prdn,
  1266. ID *pid,
  1267. back_txn *txn)
  1268. {
  1269. int rc = -1;
  1270. struct attrinfo *ai = NULL;
  1271. DB *db = NULL;
  1272. DBC *cursor = NULL;
  1273. DB_TXN *db_txn = (txn != NULL) ? txn->back_txn_txn : NULL;
  1274. DBT key, data;
  1275. char *keybuf = NULL;
  1276. char *orignrdn = NULL;
  1277. char *nrdn = NULL;
  1278. size_t nrdn_len = 0;
  1279. rdn_elem *elem = NULL;
  1280. int db_retry = 0;
  1281. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1282. "--> entryrdn_get_parent\n");
  1283. /* Initialize data */
  1284. memset(&data, 0, sizeof(data));
  1285. if (NULL == be || NULL == rdn || 0 == id || NULL == prdn || NULL == pid) {
  1286. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1287. "entryrdn_get_parent: Param error: Empty %s\n",
  1288. NULL==be?"backend":NULL==rdn?"rdn":0==id?"id":
  1289. NULL==rdn?"rdn container":
  1290. NULL==pid?"pid":"unknown");
  1291. return rc;
  1292. }
  1293. *prdn = NULL;
  1294. *pid = 0;
  1295. /* Open the entryrdn index */
  1296. rc = _entryrdn_open_index(be, &ai, &db);
  1297. if (rc || (NULL == db)) {
  1298. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1299. "entryrdn_get_parent: Opening the index failed: "
  1300. "%s(%d)\n",
  1301. rc<0?dblayer_strerror(rc):"Invalid parameter", rc);
  1302. return rc;
  1303. }
  1304. /* Make a cursor */
  1305. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  1306. rc = db->cursor(db, db_txn, &cursor, 0);
  1307. if (rc) {
  1308. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  1309. "entryrdn_get_parent: Failed to make a cursor: %s(%d)\n",
  1310. dblayer_strerror(rc), rc);
  1311. if (DB_LOCK_DEADLOCK == rc) {
  1312. #ifdef FIX_TXN_DEADLOCKS
  1313. #error if txn != NULL, have to retry the entire transaction
  1314. #endif
  1315. ENTRYRDN_DELAY;
  1316. continue;
  1317. }
  1318. cursor = NULL;
  1319. goto bail;
  1320. } else {
  1321. break; /* success */
  1322. }
  1323. }
  1324. orignrdn = slapi_ch_strdup(rdn);
  1325. rc = slapi_dn_normalize_case_ext(orignrdn, 0, &nrdn, &nrdn_len);
  1326. if (rc < 0) {
  1327. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1328. "entryrdn_get_parent: Failed to normalize %s\n", rdn);
  1329. goto bail;
  1330. }
  1331. if (rc == 0) { /* orignrdn is passed in */
  1332. *(nrdn + nrdn_len) = '\0';
  1333. } else {
  1334. slapi_ch_free_string(&orignrdn);
  1335. }
  1336. data.flags = DB_DBT_MALLOC;
  1337. /* Setting up a key for the node to get its parent */
  1338. slapi_ch_free_string(&keybuf);
  1339. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_PARENT, id);
  1340. key.data = keybuf;
  1341. key.size = key.ulen = strlen(keybuf) + 1;
  1342. key.flags = DB_DBT_USERMEM;
  1343. /* Position cursor at the matching key */
  1344. retry_get0:
  1345. rc = cursor->c_get(cursor, &key, &data, DB_SET);
  1346. if (rc) {
  1347. if (DB_LOCK_DEADLOCK == rc) {
  1348. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  1349. "entryrdn_get_parent: cursor get deadlock\n");
  1350. #ifdef FIX_TXN_DEADLOCKS
  1351. #error if txn != NULL, have to retry the entire transaction
  1352. #endif
  1353. /* try again */
  1354. goto retry_get0;
  1355. } else if (DB_NOTFOUND == rc) { /* could be a suffix
  1356. note: no parent for suffix */
  1357. slapi_ch_free_string(&keybuf);
  1358. keybuf = slapi_ch_smprintf("%s", nrdn);
  1359. key.data = keybuf;
  1360. key.size = key.ulen = strlen(keybuf) + 1;
  1361. key.flags = DB_DBT_USERMEM;
  1362. retry_get1:
  1363. rc = cursor->c_get(cursor, &key, &data, DB_SET);
  1364. if (rc) {
  1365. if (DB_LOCK_DEADLOCK == rc) {
  1366. /* try again */
  1367. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  1368. "entryrdn_get_parent: retry cursor get deadlock\n");
  1369. #ifdef FIX_TXN_DEADLOCKS
  1370. #error if txn != NULL, have to retry the entire transaction
  1371. #endif
  1372. goto retry_get1;
  1373. } else if (DB_NOTFOUND != rc) {
  1374. _entryrdn_cursor_print_error("entryrdn_get_parent",
  1375. key.data, data.size, data.ulen, rc);
  1376. }
  1377. }
  1378. } else {
  1379. _entryrdn_cursor_print_error("entryrdn_get_parent",
  1380. key.data, data.size, data.ulen, rc);
  1381. }
  1382. goto bail;
  1383. }
  1384. elem = (rdn_elem *)data.data;
  1385. #ifdef LDAP_DEBUG_ENTRYRDN
  1386. _entryrdn_dump_rdn_elem(elem);
  1387. #endif
  1388. *pid = id_stored_to_internal(elem->rdn_elem_id);
  1389. *prdn = slapi_ch_strdup(RDN_ADDR(elem));
  1390. bail:
  1391. slapi_ch_free_string(&nrdn);
  1392. slapi_ch_free_string(&keybuf);
  1393. slapi_ch_free((void **)&data.data);
  1394. /* Close the cursor */
  1395. if (cursor) {
  1396. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  1397. int myrc = cursor->c_close(cursor);
  1398. if (0 != myrc) {
  1399. slapi_log_error(ENTRYRDN_LOGLEVEL(myrc), ENTRYRDN_TAG,
  1400. "entryrdn_get_parent: Failed to close cursor: %s(%d)\n",
  1401. dblayer_strerror(myrc), myrc);
  1402. if (DB_LOCK_DEADLOCK == myrc) {
  1403. #ifdef FIX_TXN_DEADLOCKS
  1404. #error if txn != NULL, have to retry the entire transaction
  1405. #endif
  1406. ENTRYRDN_DELAY;
  1407. continue;
  1408. }
  1409. if (!rc) {
  1410. /* if cursor close returns DEADLOCK, we must bubble that up
  1411. to the higher layers for retries */
  1412. rc = myrc;
  1413. break;
  1414. }
  1415. } else {
  1416. break; /* success */
  1417. }
  1418. }
  1419. }
  1420. /* it is guaranteed that db is not NULL. */
  1421. dblayer_release_index_file(be, ai, db);
  1422. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1423. "<-- entryrdn_get_parent\n");
  1424. return rc;
  1425. }
  1426. /* helper functions */
  1427. /*
  1428. * Input:
  1429. * id -- ID of the entry specified with srdn
  1430. * srdn -- should store the target entry's rdn
  1431. * Output:
  1432. * Return value: new rdn_elem
  1433. * length -- length of the new rdn_elem
  1434. */
  1435. static rdn_elem *
  1436. _entryrdn_new_rdn_elem(backend *be,
  1437. ID id,
  1438. Slapi_RDN *srdn,
  1439. size_t *length)
  1440. {
  1441. const char *rdn = NULL;
  1442. const char *nrdn = NULL;
  1443. size_t rdn_len = 0;
  1444. size_t nrdn_len = 0;
  1445. rdn_elem *re = NULL;
  1446. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1447. "--> _entryrdn_new_rdn_elem\n");
  1448. if (NULL == srdn || NULL == be) {
  1449. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1450. "_entryrdn_new_rdn_elem: Empty %s\n",
  1451. NULL==srdn?"RDN":NULL==be?"backend":"unknown");
  1452. *length = 0;
  1453. return NULL;
  1454. }
  1455. rdn = slapi_rdn_get_rdn(srdn);
  1456. nrdn = slapi_rdn_get_nrdn(srdn);
  1457. if (NULL == rdn || NULL == nrdn) {
  1458. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1459. "_entryrdn_new_rdn_elem: Empty rdn (%s) or "
  1460. "normalized rdn (%s)\n", rdn?rdn:"",
  1461. nrdn?nrdn:"");
  1462. *length = 0;
  1463. return NULL;
  1464. }
  1465. /* If necessary, encrypt this index key */
  1466. rdn_len = strlen(rdn) + 1;
  1467. nrdn_len = strlen(nrdn) + 1;
  1468. *length = sizeof(rdn_elem) + rdn_len + nrdn_len;
  1469. re = (rdn_elem *)slapi_ch_malloc(*length);
  1470. id_internal_to_stored(id, re->rdn_elem_id);
  1471. sizeushort_internal_to_stored(nrdn_len, re->rdn_elem_nrdn_len);
  1472. sizeushort_internal_to_stored(rdn_len, re->rdn_elem_rdn_len);
  1473. PL_strncpyz(re->rdn_elem_nrdn_rdn, nrdn, nrdn_len);
  1474. PL_strncpyz(RDN_ADDR(re), rdn, rdn_len);
  1475. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1476. "<-- _entryrdn_new_rdn_elem\n");
  1477. return re;
  1478. }
  1479. static void
  1480. _entryrdn_dup_rdn_elem(const void *raw, rdn_elem **new)
  1481. {
  1482. rdn_elem *orig = (rdn_elem *)raw;
  1483. size_t elem_len = _entryrdn_rdn_elem_size(orig);
  1484. *new = (rdn_elem *)slapi_ch_malloc(elem_len);
  1485. memcpy(*new, raw, elem_len);
  1486. }
  1487. static size_t
  1488. _entryrdn_rdn_elem_size(rdn_elem *elem)
  1489. {
  1490. size_t len = sizeof(rdn_elem);
  1491. len += sizeushort_stored_to_internal(elem->rdn_elem_rdn_len) +
  1492. sizeushort_stored_to_internal(elem->rdn_elem_nrdn_len);
  1493. return len;
  1494. }
  1495. #ifdef LDAP_DEBUG_ENTRYRDN
  1496. static void
  1497. _entryrdn_dump_rdn_elem(rdn_elem *elem)
  1498. {
  1499. if (NULL == elem) {
  1500. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG, "RDN ELEMENT: empty\n");
  1501. return;
  1502. }
  1503. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG, "RDN ELEMENT:\n");
  1504. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG, " ID: %u\n",
  1505. id_stored_to_internal(elem->rdn_elem_id));
  1506. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG, " RDN: \"%s\"\n",
  1507. RDN_ADDR(elem));
  1508. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG, " RDN length: %u\n",
  1509. sizeushort_stored_to_internal(elem->rdn_elem_rdn_len));
  1510. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG, " Normalized RDN: \"%s\"\n",
  1511. elem->rdn_elem_nrdn_rdn);
  1512. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG, " Normalized RDN length: %u\n",
  1513. sizeushort_stored_to_internal(elem->rdn_elem_nrdn_len));
  1514. return;
  1515. }
  1516. #endif
  1517. static int
  1518. _entryrdn_open_index(backend *be, struct attrinfo **ai, DB **dbp)
  1519. {
  1520. int rc = -1;
  1521. ldbm_instance *inst = NULL;
  1522. if (NULL == be || NULL == ai || NULL == dbp) {
  1523. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1524. "_entryrdn_open_index: Param error: Empty %s\n",
  1525. NULL==be?"be":NULL==ai?"attrinfo container":
  1526. NULL==dbp?"db container":"unknown");
  1527. goto bail;
  1528. }
  1529. *ai = NULL;
  1530. *dbp = NULL;
  1531. /* Open the entryrdn index */
  1532. ainfo_get(be, LDBM_ENTRYRDN_STR, ai);
  1533. if (NULL == *ai) {
  1534. rc = ENODATA;
  1535. goto bail;
  1536. }
  1537. inst = (ldbm_instance *)be->be_instance_info;
  1538. if ((*ai)->ai_attrcrypt && entryrdn_warning_on_encryption) {
  1539. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1540. "Encrypting entryrdn is not supported. "
  1541. "Ignoring the configuration entry \"dn: "
  1542. "cn=entryrdn, cn=encrypted attributes, cn=<backend>, "
  1543. "cn=%s, cn=plugins, cn=config\"\n",
  1544. inst->inst_li->li_plugin->plg_name);
  1545. entryrdn_warning_on_encryption = 0;
  1546. }
  1547. rc = dblayer_get_index_file(be, *ai, dbp, DBOPEN_CREATE);
  1548. bail:
  1549. return rc;
  1550. }
  1551. #if 0 /* not used */
  1552. /*
  1553. * We don't support attribute encryption for entryrdn.
  1554. * Since there is no way to encrypt RDN in the main db id2entry,
  1555. * encrypting/decrypting entryrdn does not add any benefit to the server.
  1556. */
  1557. static berval *
  1558. _entryrdn_encrypt_key(backend *be, const char *key, struct attrinfo *ai)
  1559. {
  1560. int rc = 0;
  1561. struct berval val = {0};
  1562. struct berval *encrypted_val = NULL;
  1563. char *encrypted = NULL;
  1564. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1565. "--> _entryrdn_encrypt_key\n");
  1566. if (NULL == key) {
  1567. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG, "Empty key\n");
  1568. goto bail;
  1569. }
  1570. if (NULL == be || NULL == key || NULL == ai) {
  1571. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1572. "_entryrdn_encrypt_key: Param error: Empty %s\n",
  1573. NULL==be?"be":NULL==key?"key":
  1574. NULL==ai?"attrinfo":"unknown");
  1575. goto bail;
  1576. }
  1577. val.bv_val = (void *)key;
  1578. val.bv_len = strlen(key);
  1579. rc = attrcrypt_encrypt_index_key(be, ai, &val, &encrypted_val);
  1580. if (NULL == encrypted_val) {
  1581. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1582. "Failed to encrypt index key for %s\n", key);
  1583. }
  1584. bail:
  1585. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1586. "<-- _entryrdn_encrypt_key\n");
  1587. return encrypted_val;
  1588. }
  1589. static char *
  1590. _entryrdn_decrypt_key(backend *be, const char *key, struct attrinfo *ai)
  1591. {
  1592. int rc = 0;
  1593. struct berval val = {0};
  1594. struct berval *decrypted_val = NULL;
  1595. char *decrypted = NULL;
  1596. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1597. "--> _entryrdn_decrypt_key\n");
  1598. if (NULL == key) {
  1599. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG, "Empty key\n");
  1600. goto bail;
  1601. }
  1602. if (NULL == be || NULL == key || NULL == ai) {
  1603. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1604. "_entryrdn_encrypt_key: Param error: Empty %s\n",
  1605. NULL==be?"be":NULL==key?"key":
  1606. NULL==ai?"attrinfo":"unknown");
  1607. goto bail;
  1608. }
  1609. val.bv_val = (void *)key;
  1610. val.bv_len = strlen(key);
  1611. rc = attrcrypt_decrypt_index_key(be, ai, &val, &decrypted_val);
  1612. if (decrypted_val) {
  1613. /* null terminated string */
  1614. decrypted = slapi_ch_strdup(decrypted_val->bv_val);
  1615. ber_bvfree(decrypted_val);
  1616. goto bail;
  1617. }
  1618. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1619. "Failed to decrypt index key for %s\n", key);
  1620. bail:
  1621. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1622. "<-- _detryrdn_encrypt_key\n");
  1623. return decrypted;
  1624. }
  1625. #endif
  1626. /* Notes:
  1627. * 1) data->data must be located in the data area (not in the stack).
  1628. * If c_get reallocate the memory, the given data is freed.
  1629. * 2) output elem returns data->data regardless of the result (success|failure)
  1630. */
  1631. static int
  1632. _entryrdn_get_elem(DBC *cursor,
  1633. DBT *key,
  1634. DBT *data,
  1635. const char *comp_key,
  1636. rdn_elem **elem)
  1637. {
  1638. int rc = 0;
  1639. void *ptr = NULL;
  1640. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG, "--> _entryrdn_get_elem\n");
  1641. if (NULL == cursor || NULL == key || NULL == data || NULL == elem ||
  1642. NULL == comp_key) {
  1643. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1644. "_entryrdn_get_elem: Param error: Empty %s\n",
  1645. NULL==cursor?"cursor":NULL==key?"key":
  1646. NULL==data?"data":NULL==elem?"elem container":
  1647. NULL==comp_key?"key to compare":"unknown");
  1648. goto bail;
  1649. }
  1650. /* Position cursor at the matching key */
  1651. ptr = data->data;
  1652. retry_get:
  1653. rc = cursor->c_get(cursor, key, data, DB_GET_BOTH_RANGE);
  1654. *elem = (rdn_elem *)data->data;
  1655. if (rc) {
  1656. if (DB_LOCK_DEADLOCK == rc) {
  1657. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  1658. "_entryrdn_get_elem: cursor get deadlock\n");
  1659. /* try again */
  1660. #ifdef FIX_TXN_DEADLOCKS
  1661. #error if txn != NULL, have to retry the entire transaction
  1662. #endif
  1663. goto retry_get;
  1664. } else if (DB_BUFFER_SMALL == rc) {
  1665. /* try again */
  1666. data->flags = DB_DBT_MALLOC;
  1667. goto retry_get;
  1668. } else if (DB_NOTFOUND != rc) {
  1669. _entryrdn_cursor_print_error("_entryrdn_get_elem",
  1670. key->data, data->size, data->ulen, rc);
  1671. }
  1672. goto bail;
  1673. }
  1674. if (0 != strcmp(comp_key, (char *)(*elem)->rdn_elem_nrdn_rdn)) {
  1675. /* the exact element was not found */
  1676. if ((DB_DBT_MALLOC == data->flags) && (ptr != data->data)) {
  1677. /* free the memory allocated in c_get when it returns an error */
  1678. slapi_ch_free(&data->data);
  1679. data->data = ptr;
  1680. *elem = (rdn_elem *)data->data;
  1681. }
  1682. rc = DB_NOTFOUND;
  1683. goto bail;
  1684. }
  1685. if ((0 == rc) && (DB_DBT_MALLOC == data->flags) && (ptr != data->data)) {
  1686. /* the given data->data has been replaced by c_get */
  1687. slapi_ch_free(&ptr);
  1688. }
  1689. bail:
  1690. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG, "<-- _entryrdn_get_elem\n");
  1691. return rc;
  1692. }
  1693. static int
  1694. _entryrdn_get_tombstone_elem(DBC *cursor,
  1695. Slapi_RDN *srdn,
  1696. DBT *key,
  1697. const char *comp_key,
  1698. rdn_elem **elem)
  1699. {
  1700. int rc = 0;
  1701. DBT data;
  1702. rdn_elem *childelem = NULL;
  1703. char buffer[RDN_BULK_FETCH_BUFFER_SIZE];
  1704. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1705. "--> _entryrdn_get_tombstone_elem\n");
  1706. if (NULL == cursor || NULL == srdn || NULL == key || NULL == elem ||
  1707. NULL == comp_key) {
  1708. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1709. "_entryrdn_get_tombstone_elem: Param error: Empty %s\n",
  1710. NULL==cursor?"cursor":NULL==key?"key":
  1711. NULL==srdn?"srdn":NULL==elem?"elem container":
  1712. NULL==comp_key?"key to compare":"unknown");
  1713. goto bail;
  1714. }
  1715. *elem = NULL;
  1716. /* get the child elems */
  1717. /* Setting the bulk fetch buffer */
  1718. memset(&data, 0, sizeof(data));
  1719. data.ulen = sizeof(buffer);
  1720. data.size = sizeof(buffer);
  1721. data.data = buffer;
  1722. data.flags = DB_DBT_USERMEM;
  1723. retry_get0:
  1724. rc = cursor->c_get(cursor, key, &data, DB_SET|DB_MULTIPLE);
  1725. if (DB_LOCK_DEADLOCK == rc) {
  1726. /* try again */
  1727. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  1728. "_entryrdn_get_tombstone_elem: cursor get deadlock\n");
  1729. #ifdef FIX_TXN_DEADLOCKS
  1730. #error if txn != NULL, have to retry the entire transaction
  1731. #endif
  1732. goto retry_get0;
  1733. } else if (DB_NOTFOUND == rc) {
  1734. rc = 0; /* Child not found is ok */
  1735. goto bail;
  1736. } else if (rc) {
  1737. _entryrdn_cursor_print_error("_entryrdn_get_tombstone_elem",
  1738. key->data, data.size, data.ulen, rc);
  1739. goto bail;
  1740. }
  1741. do {
  1742. DBT dataret;
  1743. void *ptr;
  1744. char *childnrdn = NULL;
  1745. char *comma = NULL;
  1746. DB_MULTIPLE_INIT(ptr, &data);
  1747. do {
  1748. memset(&dataret, 0, sizeof(dataret));
  1749. DB_MULTIPLE_NEXT(ptr, &data, dataret.data, dataret.size);
  1750. if (NULL == dataret.data || NULL == ptr) {
  1751. break;
  1752. }
  1753. childelem = (rdn_elem *)dataret.data;
  1754. childnrdn = (char *)childelem->rdn_elem_nrdn_rdn;
  1755. comma = strchr(childnrdn, ',');
  1756. if (NULL == comma) { /* No comma; This node is not a tombstone */
  1757. continue;
  1758. }
  1759. if (strncasecmp(childnrdn, SLAPI_ATTR_UNIQUEID,
  1760. sizeof(SLAPI_ATTR_UNIQUEID) - 1)) {
  1761. /* Does not start w/ UNIQUEID; not a tombstone */
  1762. continue;
  1763. }
  1764. if (0 == strcmp(comma + 1, slapi_rdn_get_nrdn(srdn))) {
  1765. /* found and done */
  1766. _entryrdn_dup_rdn_elem((const void *)dataret.data, elem);
  1767. goto bail;
  1768. }
  1769. if (0 == strncmp(childnrdn, slapi_rdn_get_nrdn(srdn),
  1770. comma - childnrdn)) {
  1771. /* found and done */
  1772. _entryrdn_dup_rdn_elem((const void *)dataret.data, elem);
  1773. goto bail;
  1774. }
  1775. } while (NULL != dataret.data && NULL != ptr);
  1776. retry_get1:
  1777. rc = cursor->c_get(cursor, key, &data, DB_NEXT_DUP|DB_MULTIPLE);
  1778. if (DB_LOCK_DEADLOCK == rc) {
  1779. /* try again */
  1780. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  1781. "_entryrdn_get_tombstone_elem: retry cursor get deadlock\n");
  1782. #ifdef FIX_TXN_DEADLOCKS
  1783. #error if txn != NULL, have to retry the entire transaction
  1784. #endif
  1785. goto retry_get1;
  1786. } else if (DB_NOTFOUND == rc) {
  1787. rc = 0;
  1788. goto bail; /* done */
  1789. } else if (rc) {
  1790. _entryrdn_cursor_print_error("_entryrdn_get_tombstone_elem",
  1791. key->data, data.size, data.ulen, rc);
  1792. goto bail;
  1793. }
  1794. } while (0 == rc);
  1795. bail:
  1796. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1797. "<-- _entryrdn_get_tombstone_elem\n");
  1798. return rc;
  1799. }
  1800. static int
  1801. _entryrdn_put_data(DBC *cursor, DBT *key, DBT *data, char type, DB_TXN *db_txn)
  1802. {
  1803. int rc = -1;
  1804. int db_retry = 0;
  1805. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1806. "--> _entryrdn_put_data\n");
  1807. if (NULL == cursor || NULL == key || NULL == data) {
  1808. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1809. "_entryrdn_put_data: Param error: Empty %s\n",
  1810. NULL==cursor?"cursor":NULL==key?"key":
  1811. NULL==data?"data":"unknown");
  1812. goto bail;
  1813. }
  1814. /* insert it */
  1815. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  1816. rc = cursor->c_put(cursor, key, data, DB_NODUPDATA);
  1817. if (rc) {
  1818. if (DB_KEYEXIST == rc) {
  1819. /* this is okay, but need to return DB_KEYEXIST to caller */
  1820. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  1821. "_entryrdn_put_data: The same key (%s) and the "
  1822. "data exists in index\n",
  1823. (char *)key->data);
  1824. break;
  1825. } else {
  1826. char *keyword = NULL;
  1827. if (type == RDN_INDEX_CHILD) {
  1828. keyword = "child";
  1829. } else if (type == RDN_INDEX_PARENT) {
  1830. keyword = "parent";
  1831. } else {
  1832. keyword = "self";
  1833. }
  1834. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  1835. "_entryrdn_put_data: Adding the %s link (%s) "
  1836. "failed: %s (%d)\n", keyword, (char *)key->data,
  1837. dblayer_strerror(rc), rc);
  1838. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  1839. ENTRYRDN_DELAY;
  1840. continue;
  1841. }
  1842. goto bail;
  1843. }
  1844. } else {
  1845. break; /* success */
  1846. }
  1847. }
  1848. if (RETRY_TIMES == db_retry) {
  1849. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1850. "_entryrdn_put_data: cursor put operation failed after [%d] retries\n",
  1851. db_retry);
  1852. rc = DB_LOCK_DEADLOCK;
  1853. }
  1854. bail:
  1855. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG, "<-- _entryrdn_put_data\n");
  1856. return rc;
  1857. }
  1858. static int
  1859. _entryrdn_del_data(DBC *cursor, DBT *key, DBT *data, DB_TXN *db_txn)
  1860. {
  1861. int rc = -1;
  1862. int db_retry = 0;
  1863. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1864. "--> _entryrdn_del_data\n");
  1865. if (NULL == cursor || NULL == key || NULL == data) {
  1866. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1867. "_entryrdn_del_data: Param error: Empty %s\n",
  1868. NULL==cursor?"cursor":NULL==key?"key":
  1869. NULL==data?"data":"unknown");
  1870. goto bail;
  1871. }
  1872. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  1873. rc = cursor->c_get(cursor, key, data, DB_GET_BOTH);
  1874. if (rc) {
  1875. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  1876. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  1877. "_entryrdn_del_data: cursor get deadlock\n");
  1878. /* try again */
  1879. } else if (DB_NOTFOUND == rc) {
  1880. rc = 0; /* not found is ok */
  1881. goto bail;
  1882. } else {
  1883. _entryrdn_cursor_print_error("_entryrdn_del_data",
  1884. key->data, data->size, data->ulen, rc);
  1885. goto bail;
  1886. }
  1887. } else {
  1888. break; /* found it */
  1889. }
  1890. }
  1891. if (RETRY_TIMES == db_retry) {
  1892. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1893. "_entryrdn_del_data: cursor get failed after [%d] retries\n",
  1894. db_retry);
  1895. rc = DB_LOCK_DEADLOCK;
  1896. goto bail;
  1897. }
  1898. /* We found it, so delete it */
  1899. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  1900. rc = cursor->c_del(cursor, 0);
  1901. if (rc) {
  1902. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  1903. "_entryrdn_del_data: Deleting %s failed; "
  1904. "%s(%d)\n", (char *)key->data,
  1905. dblayer_strerror(rc), rc);
  1906. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  1907. ENTRYRDN_DELAY;
  1908. continue;
  1909. }
  1910. goto bail;
  1911. } else {
  1912. break; /* success */
  1913. }
  1914. }
  1915. if (RETRY_TIMES == db_retry) {
  1916. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1917. "_entryrdn_del_data: cursor del failed after [%d] retries\n",
  1918. db_retry);
  1919. rc = DB_LOCK_DEADLOCK;
  1920. }
  1921. bail:
  1922. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1923. "<-- _entryrdn_del_data\n");
  1924. return rc;
  1925. }
  1926. /* Child is a Leaf RDN to be added */
  1927. static int
  1928. _entryrdn_insert_key_elems(backend *be,
  1929. DBC *cursor,
  1930. Slapi_RDN *srdn,
  1931. DBT *key,
  1932. rdn_elem *parentelem,
  1933. rdn_elem *elem,
  1934. size_t elemlen,
  1935. DB_TXN *db_txn)
  1936. {
  1937. /* We found a place to add RDN. */
  1938. DBT adddata;
  1939. char *keybuf = NULL;
  1940. size_t len = 0;
  1941. int rc = 0;
  1942. ID myid = 0;
  1943. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  1944. "--> _entryrdn_insert_key_elems\n");
  1945. if (NULL == be || NULL == cursor || NULL == srdn ||
  1946. NULL == key || NULL == parentelem || NULL == elem) {
  1947. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  1948. "_entryrdn_insert_key_elem: Param error: Empty %s\n",
  1949. NULL==be?"backend":NULL==cursor?"cursor":NULL==srdn?"RDN":
  1950. NULL==key?"key":NULL==parentelem?"parent element":
  1951. NULL==elem?"target element":"unknown");
  1952. goto bail;
  1953. }
  1954. #ifdef LDAP_DEBUG_ENTRYRDN
  1955. _entryrdn_dump_rdn_elem(elem);
  1956. #endif
  1957. memset(&adddata, 0, sizeof(adddata));
  1958. adddata.ulen = adddata.size = elemlen;
  1959. adddata.data = (void *)elem;
  1960. adddata.flags = DB_DBT_USERMEM;
  1961. /* adding RDN to the child key */
  1962. rc = _entryrdn_put_data(cursor, key, &adddata, RDN_INDEX_CHILD, db_txn);
  1963. keybuf = key->data;
  1964. if (rc && (DB_KEYEXIST != rc)) { /* failed && ignore already exists */
  1965. goto bail;
  1966. }
  1967. myid = id_stored_to_internal(elem->rdn_elem_id);
  1968. /* adding RDN to the self key */
  1969. slapi_ch_free_string(&keybuf);
  1970. /* Generate a key for self rdn */
  1971. /* E.g., 222 */
  1972. keybuf = slapi_ch_smprintf("%u", myid);
  1973. key->data = keybuf;
  1974. key->size = key->ulen = strlen(keybuf) + 1;
  1975. key->flags = DB_DBT_USERMEM;
  1976. rc = _entryrdn_put_data(cursor, key, &adddata, RDN_INDEX_SELF, db_txn);
  1977. if (rc && (DB_KEYEXIST != rc)) { /* failed && ignore already exists */
  1978. goto bail;
  1979. }
  1980. /* adding RDN to the parent key */
  1981. slapi_ch_free_string(&keybuf);
  1982. /* Generate a key for parent rdn */
  1983. /* E.g., P222 */
  1984. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_PARENT, myid);
  1985. key->data = keybuf;
  1986. key->size = key->ulen = strlen(keybuf) + 1;
  1987. key->flags = DB_DBT_USERMEM;
  1988. memset(&adddata, 0, sizeof(adddata));
  1989. len = _entryrdn_rdn_elem_size(parentelem);
  1990. adddata.ulen = adddata.size = len;
  1991. adddata.data = (void *)parentelem;
  1992. adddata.flags = DB_DBT_USERMEM;
  1993. /* adding RDN to the self key */
  1994. rc = _entryrdn_put_data(cursor, key, &adddata, RDN_INDEX_PARENT, db_txn);
  1995. if (DB_KEYEXIST == rc) { /* failed && ignore already exists */
  1996. rc = 0;
  1997. }
  1998. /* Succeeded or failed, it's done. */
  1999. bail:
  2000. slapi_ch_free_string(&keybuf);
  2001. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  2002. "<-- _entryrdn_insert_key_elems\n");
  2003. return rc;
  2004. }
  2005. /*
  2006. * Helper function to replace a temporary id assigned to suffix id.
  2007. */
  2008. static int
  2009. _entryrdn_replace_suffix_id(DBC *cursor, DBT *key, DBT *adddata,
  2010. ID id, const char *normsuffix, DB_TXN *db_txn)
  2011. {
  2012. int rc = 0;
  2013. char *keybuf = NULL;
  2014. char *realkeybuf = NULL;
  2015. DBT realkey;
  2016. char buffer[RDN_BULK_FETCH_BUFFER_SIZE];
  2017. DBT data = {0};
  2018. DBT moddata = {0};
  2019. rdn_elem **childelems = NULL;
  2020. rdn_elem **cep = NULL;
  2021. rdn_elem *childelem = NULL;
  2022. size_t childnum = 4;
  2023. size_t curr_childnum = 0;
  2024. int db_retry = 0;
  2025. memset(&moddata, 0, sizeof(moddata));
  2026. /* temporary id added for the non exisiting suffix */
  2027. /* Let's replace it with the real entry ID */
  2028. /* SELF */
  2029. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  2030. rc = cursor->c_put(cursor, key, adddata, DB_CURRENT);
  2031. if (rc) {
  2032. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2033. "_entryrdn_replace_suffix_id: Adding suffix %s failed: "
  2034. "%s (%d)\n", normsuffix, dblayer_strerror(rc), rc);
  2035. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  2036. ENTRYRDN_DELAY;
  2037. continue;
  2038. }
  2039. goto bail;
  2040. } else {
  2041. break; /* success */
  2042. }
  2043. }
  2044. if (RETRY_TIMES == db_retry) {
  2045. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2046. "_entryrdn_replace_suffix_id: cursor put failed after [%d] retries\n",
  2047. db_retry);
  2048. rc = DB_LOCK_DEADLOCK;
  2049. goto bail;
  2050. }
  2051. /*
  2052. * Fixing Child link:
  2053. * key: C0:Suffix --> C<realID>:Suffix
  2054. */
  2055. /* E.g., C1 */
  2056. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_CHILD, TMPID);
  2057. key->data = keybuf;
  2058. key->size = key->ulen = strlen(keybuf) + 1;
  2059. key->flags = DB_DBT_USERMEM;
  2060. /* Setting the bulk fetch buffer */
  2061. data.ulen = sizeof(buffer);
  2062. data.size = sizeof(buffer);
  2063. data.data = buffer;
  2064. data.flags = DB_DBT_USERMEM;
  2065. realkeybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_CHILD, id);
  2066. realkey.data = realkeybuf;
  2067. realkey.size = realkey.ulen = strlen(realkeybuf) + 1;
  2068. realkey.flags = DB_DBT_USERMEM;
  2069. moddata.flags = DB_DBT_USERMEM;
  2070. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  2071. rc = cursor->c_get(cursor, key, &data, DB_SET|DB_MULTIPLE);
  2072. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  2073. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2074. "_entryrdn_replace_suffix_id: cursor get deadlock\n");
  2075. /* try again */
  2076. ENTRYRDN_DELAY;
  2077. } else if (rc) {
  2078. _entryrdn_cursor_print_error("_entryrdn_replace_suffix_id",
  2079. key->data, data.size, data.ulen, rc);
  2080. goto bail;
  2081. } else {
  2082. break; /* found */
  2083. }
  2084. }
  2085. if (RETRY_TIMES == db_retry) {
  2086. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2087. "_entryrdn_replace_suffix_id: cursor get1 failed after [%d] retries\n",
  2088. db_retry);
  2089. rc = DB_LOCK_DEADLOCK;
  2090. goto bail;
  2091. }
  2092. childelems = (rdn_elem **)slapi_ch_calloc(childnum, sizeof(rdn_elem *));
  2093. do {
  2094. DBT dataret;
  2095. void *ptr;
  2096. DB_MULTIPLE_INIT(ptr, &data);
  2097. do {
  2098. memset(&dataret, 0, sizeof(dataret));
  2099. DB_MULTIPLE_NEXT(ptr, &data, dataret.data, dataret.size);
  2100. if (NULL == dataret.data || NULL == ptr) {
  2101. break;
  2102. }
  2103. _entryrdn_dup_rdn_elem((const void *)dataret.data, &childelem);
  2104. moddata.data = childelem;
  2105. moddata.ulen = moddata.size = _entryrdn_rdn_elem_size(childelem);
  2106. /* Delete it first */
  2107. rc = _entryrdn_del_data(cursor, key, &moddata, db_txn);
  2108. if (rc) {
  2109. goto bail0;
  2110. }
  2111. /* Add it back */
  2112. rc = _entryrdn_put_data(cursor, &realkey, &moddata,
  2113. RDN_INDEX_CHILD, db_txn);
  2114. if (rc && (DB_KEYEXIST != rc)) { /* failed && ignore already exists */
  2115. goto bail0;
  2116. }
  2117. if (curr_childnum + 1 == childnum) {
  2118. childnum *= 2;
  2119. childelems = (rdn_elem **)slapi_ch_realloc((char *)childelems,
  2120. sizeof(rdn_elem *) * childnum);
  2121. memset(childelems + curr_childnum, 0,
  2122. sizeof(rdn_elem *) * (childnum - curr_childnum));
  2123. }
  2124. childelems[curr_childnum++] = childelem;
  2125. /* We don't access the address with this variable any more */
  2126. childelem = NULL;
  2127. } while (NULL != dataret.data && NULL != ptr);
  2128. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  2129. rc = cursor->c_get(cursor, key, &data, DB_NEXT_DUP|DB_MULTIPLE);
  2130. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  2131. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2132. "_entryrdn_replace_suffix_id: retry cursor get deadlock\n");
  2133. /* try again */
  2134. ENTRYRDN_DELAY;
  2135. } else if (!rc || (DB_NOTFOUND == rc)) {
  2136. break; /* done */
  2137. } else {
  2138. _entryrdn_cursor_print_error("_entryrdn_replace_suffix_id",
  2139. key->data, data.size, data.ulen, rc);
  2140. goto bail0;
  2141. }
  2142. }
  2143. if (RETRY_TIMES == db_retry) {
  2144. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2145. "_entryrdn_replace_suffix_id: cursor get2 failed after [%d] retries\n",
  2146. db_retry);
  2147. rc = DB_LOCK_DEADLOCK;
  2148. goto bail0;
  2149. }
  2150. if (DB_NOTFOUND == rc) {
  2151. rc = 0; /* ok */
  2152. break; /* we're done */
  2153. }
  2154. } while (0 == rc);
  2155. /*
  2156. * Fixing Children's parent link:
  2157. * key: P<childID>:<childRDN> --> P<childID>:<childRDN>
  2158. * data: 0 --> <realID>
  2159. */
  2160. for (cep = childelems; cep && *cep; cep++) {
  2161. rdn_elem *pelem = NULL;
  2162. slapi_ch_free_string(&keybuf);
  2163. /* E.g., P1 */
  2164. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_PARENT,
  2165. id_stored_to_internal((*cep)->rdn_elem_id));
  2166. key->data = keybuf;
  2167. key->size = key->ulen = strlen(keybuf) + 1;
  2168. key->flags = DB_DBT_USERMEM;
  2169. memset(&moddata, 0, sizeof(moddata));
  2170. moddata.flags = DB_DBT_MALLOC;
  2171. /* Position cursor at the matching key */
  2172. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  2173. rc = cursor->c_get(cursor, key, &moddata, DB_SET);
  2174. if (rc) {
  2175. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  2176. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2177. "_entryrdn_replace_suffix_id: retry2 cursor get deadlock\n");
  2178. ENTRYRDN_DELAY;
  2179. } else {
  2180. _entryrdn_cursor_print_error("_entryrdn_replace_suffix_id",
  2181. key->data, data.size, data.ulen, rc);
  2182. goto bail0;
  2183. }
  2184. } else {
  2185. break;
  2186. }
  2187. }
  2188. if (RETRY_TIMES == db_retry) {
  2189. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2190. "_entryrdn_replace_suffix_id: cursor get3 failed after [%d] retries\n",
  2191. db_retry);
  2192. rc = DB_LOCK_DEADLOCK;
  2193. goto bail0;
  2194. }
  2195. pelem = (rdn_elem *)moddata.data;
  2196. if (TMPID == id_stored_to_internal(pelem->rdn_elem_id)) {
  2197. /* the parent id is TMPID;
  2198. * replace it with the given id */
  2199. id_internal_to_stored(id, pelem->rdn_elem_id);
  2200. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  2201. rc = cursor->c_put(cursor, key, &moddata, DB_CURRENT);
  2202. if (rc) {
  2203. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2204. "_entryrdn_replace_suffix_id: "
  2205. "Fixing the parent link (%s) failed: %s (%d)\n",
  2206. keybuf, dblayer_strerror(rc), rc);
  2207. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  2208. ENTRYRDN_DELAY;
  2209. continue;
  2210. }
  2211. goto bail0;
  2212. } else {
  2213. break; /* success */
  2214. }
  2215. }
  2216. if (RETRY_TIMES == db_retry) {
  2217. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2218. "_entryrdn_replace_suffix_id: cursor put failed after [%d] retries\n",
  2219. db_retry);
  2220. rc = DB_LOCK_DEADLOCK;
  2221. goto bail0;
  2222. }
  2223. }
  2224. slapi_ch_free((void **)&moddata.data);
  2225. } /* for (cep = childelems; cep && *cep; cep++) */
  2226. bail0:
  2227. for (cep = childelems; cep && *cep; cep++) {
  2228. slapi_ch_free((void **)cep);
  2229. }
  2230. slapi_ch_free((void **)&childelems);
  2231. bail:
  2232. slapi_ch_free_string(&keybuf);
  2233. slapi_ch_free_string(&realkeybuf);
  2234. if (moddata.data && (moddata.flags == DB_DBT_MALLOC)) {
  2235. slapi_ch_free((void **)&moddata.data);
  2236. }
  2237. return rc;
  2238. }
  2239. /*
  2240. * This function starts from the suffix following the child links to the bottom.
  2241. * If the target leaf node does not exist, the nodes (the child link of the
  2242. * parent node and the self link) are added.
  2243. */
  2244. static int
  2245. _entryrdn_insert_key(backend *be,
  2246. DBC *cursor,
  2247. Slapi_RDN *srdn,
  2248. ID id,
  2249. DB_TXN *db_txn)
  2250. {
  2251. int rc = -1;
  2252. size_t len = 0;
  2253. const char *nrdn = NULL; /* normalized rdn */
  2254. const char *childnrdn = NULL; /* normalized child rdn */
  2255. int rdnidx = -1;
  2256. char *keybuf = NULL;
  2257. DBT key, data;
  2258. ID workid = 0;
  2259. rdn_elem *elem = NULL;
  2260. rdn_elem *childelem = NULL;
  2261. rdn_elem *parentelem = NULL;
  2262. rdn_elem *tmpelem = NULL;
  2263. Slapi_RDN *tmpsrdn = NULL;
  2264. int db_retry = 0;
  2265. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  2266. "--> _entryrdn_insert_key\n");
  2267. if (NULL == be || NULL == cursor || NULL == srdn || 0 == id) {
  2268. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2269. "_entryrdn_insert_key: Param error: Empty %s\n",
  2270. NULL==be?"backend":NULL==cursor?"cursor":NULL==srdn?"RDN":
  2271. 0==id?"id":"unknown");
  2272. goto bail;
  2273. }
  2274. /* get the top normalized rdn */
  2275. rdnidx = slapi_rdn_get_last_ext(srdn, &nrdn, FLAG_ALL_NRDNS);
  2276. if (rdnidx < 0 || NULL == nrdn) {
  2277. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2278. "_entryrdn_insert_key: Empty RDN\n");
  2279. goto bail;
  2280. }
  2281. /* Setting up a key for suffix */
  2282. key.data = (void *)nrdn;
  2283. key.size = key.ulen = strlen(nrdn) + 1;
  2284. key.flags = DB_DBT_USERMEM;
  2285. if (0 == rdnidx) { /* "0 == rdnidx" means adding suffix */
  2286. /* adding suffix RDN to the self key */
  2287. DBT adddata;
  2288. elem = _entryrdn_new_rdn_elem(be, id, srdn, &len);
  2289. if (NULL == elem) {
  2290. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2291. "_entryrdn_insert_key: Failed to generate an elem: "
  2292. "id: %d, rdn: %s\n",
  2293. id, slapi_rdn_get_rdn(srdn));
  2294. goto bail;
  2295. }
  2296. #ifdef LDAP_DEBUG_ENTRYRDN
  2297. _entryrdn_dump_rdn_elem(elem);
  2298. #endif
  2299. memset(&adddata, 0, sizeof(adddata));
  2300. adddata.ulen = adddata.size = len;
  2301. adddata.data = (void *)elem;
  2302. adddata.flags = DB_DBT_USERMEM;
  2303. rc = _entryrdn_put_data(cursor, &key, &adddata, RDN_INDEX_SELF, db_txn);
  2304. if (DB_KEYEXIST == rc) {
  2305. DBT existdata;
  2306. rdn_elem *existelem = NULL;
  2307. ID tmpid;
  2308. memset(&existdata, 0, sizeof(existdata));
  2309. existdata.flags = DB_DBT_MALLOC;
  2310. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  2311. rc = cursor->c_get(cursor, &key, &existdata, DB_SET);
  2312. if (rc) {
  2313. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2314. "_entryrdn_insert_key: Get existing suffix %s "
  2315. "failed: %s (%d)\n",
  2316. nrdn, dblayer_strerror(rc), rc);
  2317. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  2318. ENTRYRDN_DELAY;
  2319. continue;
  2320. }
  2321. goto bail;
  2322. } else {
  2323. break; /* success */
  2324. }
  2325. }
  2326. if (RETRY_TIMES == db_retry) {
  2327. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2328. "_entryrdn_insert_key: cursor get failed after [%d] retries\n",
  2329. db_retry);
  2330. rc = DB_LOCK_DEADLOCK;
  2331. goto bail;
  2332. }
  2333. existelem = (rdn_elem *)existdata.data;
  2334. tmpid = id_stored_to_internal(existelem->rdn_elem_id);
  2335. slapi_ch_free((void **)&existelem);
  2336. if (TMPID == tmpid) {
  2337. rc = _entryrdn_replace_suffix_id(cursor, &key, &adddata,
  2338. id, nrdn, db_txn);
  2339. if (rc) {
  2340. goto bail;
  2341. }
  2342. } /* if (TMPID == tmpid) */
  2343. rc = 0;
  2344. } /* if (DB_KEYEXIST == rc) */
  2345. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  2346. "_entryrdn_insert_key: Suffix %s added: %d\n",
  2347. nrdn, rc);
  2348. goto bail; /* succeeded or failed, it's done */
  2349. }
  2350. /* (0 < rdnidx) */
  2351. /* get id of the suffix */
  2352. tmpsrdn = NULL;
  2353. /* tmpsrdn == suffix'es srdn */
  2354. rc = slapi_rdn_partial_dup(srdn, &tmpsrdn, rdnidx);
  2355. if (rc) {
  2356. char *dn = NULL;
  2357. slapi_rdn_get_dn(srdn, &dn);
  2358. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2359. "_entryrdn_insert_key: partial dup of %s (idx %d) "
  2360. "failed (%d)\n", dn, rdnidx, rc);
  2361. slapi_ch_free_string(&dn);
  2362. goto bail;
  2363. }
  2364. elem = _entryrdn_new_rdn_elem(be, TMPID, tmpsrdn, &len);
  2365. if (NULL == elem) {
  2366. char *dn = NULL;
  2367. slapi_rdn_get_dn(tmpsrdn, &dn);
  2368. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2369. "_entryrdn_insert_key: Failed to generate a new elem: "
  2370. "dn: %s\n", dn);
  2371. slapi_ch_free_string(&dn);
  2372. goto bail;
  2373. }
  2374. memset(&data, 0, sizeof(data));
  2375. data.ulen = data.size = len;
  2376. data.data = elem;
  2377. data.flags = DB_DBT_USERMEM;
  2378. /* getting the suffix element */
  2379. rc = _entryrdn_get_elem(cursor, &key, &data, nrdn, &elem);
  2380. if (rc) {
  2381. const char *myrdn = slapi_rdn_get_nrdn(srdn);
  2382. const char **ep = NULL;
  2383. int isexception = 0;
  2384. /* Check the RDN is in the exception list */
  2385. for (ep = rdn_exceptions; ep && *ep; ep++) {
  2386. if (!strcmp(*ep, myrdn)) {
  2387. isexception = 1;
  2388. break;
  2389. }
  2390. }
  2391. if (isexception) {
  2392. /* adding suffix RDN to the self key */
  2393. DBT adddata;
  2394. /* suffix ID = 0: fake ID to be replaced with the real one when
  2395. * it's really added. */
  2396. ID suffixid = TMPID;
  2397. slapi_ch_free((void **)&elem);
  2398. elem = _entryrdn_new_rdn_elem(be, suffixid, tmpsrdn, &len);
  2399. if (NULL == elem) {
  2400. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2401. "_entryrdn_insert_key: Failed to generate an elem: "
  2402. "id: %d, rdn: %s\n",
  2403. suffixid, slapi_rdn_get_rdn(tmpsrdn));
  2404. goto bail;
  2405. }
  2406. #ifdef LDAP_DEBUG_ENTRYRDN
  2407. _entryrdn_dump_rdn_elem(elem);
  2408. #endif
  2409. memset(&adddata, 0, sizeof(adddata));
  2410. adddata.ulen = adddata.size = len;
  2411. adddata.data = (void *)elem;
  2412. adddata.flags = DB_DBT_USERMEM;
  2413. rc = _entryrdn_put_data(cursor, &key, &adddata, RDN_INDEX_SELF, db_txn);
  2414. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  2415. "_entryrdn_insert_key: Suffix %s added: %d\n",
  2416. slapi_rdn_get_rdn(tmpsrdn), rc);
  2417. #ifdef FIX_TXN_DEADLOCKS
  2418. #error no checking for rc here? - what if rc is deadlock? should bail?
  2419. #endif
  2420. } else {
  2421. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2422. "_entryrdn_insert_key: Suffix \"%s\" not found: "
  2423. "%s(%d)\n", nrdn, dblayer_strerror(rc), rc);
  2424. goto bail;
  2425. }
  2426. }
  2427. slapi_rdn_free(&tmpsrdn);
  2428. /* workid: ID of suffix */
  2429. workid = id_stored_to_internal(elem->rdn_elem_id);
  2430. parentelem = elem;
  2431. elem = NULL;
  2432. do {
  2433. slapi_ch_free_string(&keybuf);
  2434. /* Check the direct child in the RDN array, first */
  2435. rdnidx = slapi_rdn_get_prev_ext(srdn, rdnidx,
  2436. &childnrdn, FLAG_ALL_NRDNS);
  2437. if ((rdnidx < 0) || (NULL == childnrdn)) {
  2438. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2439. "_entryrdn_insert_key: RDN list \"%s\" is broken: "
  2440. "idx(%d)\n", slapi_rdn_get_rdn(srdn), rdnidx);
  2441. goto bail;
  2442. }
  2443. /* Generate a key for child tree */
  2444. /* E.g., C1 */
  2445. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_CHILD, workid);
  2446. key.data = keybuf;
  2447. key.size = key.ulen = strlen(keybuf) + 1;
  2448. key.flags = DB_DBT_USERMEM;
  2449. tmpsrdn = srdn;
  2450. if (0 < rdnidx) {
  2451. rc = slapi_rdn_partial_dup(srdn, &tmpsrdn, rdnidx);
  2452. if (rc) {
  2453. char *dn = NULL;
  2454. slapi_rdn_get_dn(srdn, &dn);
  2455. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2456. "_entryrdn_insert_key: partial dup of %s "
  2457. "(idx %d) failed (%d)\n", dn, rdnidx, rc);
  2458. slapi_ch_free_string(&dn);
  2459. goto bail;
  2460. }
  2461. }
  2462. elem = _entryrdn_new_rdn_elem(be, TMPID, tmpsrdn, &len);
  2463. if (NULL == elem) {
  2464. char *dn = NULL;
  2465. slapi_rdn_get_dn(tmpsrdn, &dn);
  2466. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2467. "_entryrdn_insert_key: Failed to generate a new elem: "
  2468. "dn: %s\n", dn);
  2469. slapi_ch_free_string(&dn);
  2470. goto bail;
  2471. }
  2472. _entryrdn_dup_rdn_elem((const void *)elem, &tmpelem);
  2473. memset(&data, 0, sizeof(data));
  2474. data.ulen = data.size = len;
  2475. data.data = tmpelem;
  2476. data.flags = DB_DBT_USERMEM;
  2477. /* getting the child element */
  2478. rc = _entryrdn_get_elem(cursor, &key, &data, childnrdn, &tmpelem);
  2479. if (rc) {
  2480. slapi_ch_free((void **)&tmpelem);
  2481. if (DB_NOTFOUND == rc) {
  2482. /* if 0 == rdnidx, Child is a Leaf RDN to be added */
  2483. if (0 == rdnidx) {
  2484. /* keybuf (C#) is consumed in _entryrdn_insert_key_elems */
  2485. /* set id to the elem to be added */
  2486. id_internal_to_stored(id, elem->rdn_elem_id);
  2487. rc = _entryrdn_insert_key_elems(be, cursor, srdn, &key,
  2488. parentelem, elem, len, db_txn);
  2489. keybuf = NULL;
  2490. goto bail;
  2491. /* done */
  2492. } else {
  2493. ID currid = 0;
  2494. /*
  2495. * In DIT cn=A,ou=B,o=C, cn=A and ou=B are removed and
  2496. * turned to tombstone entries. We need to support both:
  2497. * nsuniqueid=...,cn=A,ou=B,o=C and
  2498. * nsuniqueid=...,cn=A,nsuniqueid=...,ou=B,o=C
  2499. * The former appears when cn=A is deleted;
  2500. * the latter appears when the entryrdn is reindexed.
  2501. * The former is taken care in _entryrdn_get_tombstone_elem;
  2502. * the else clause to skip "nsuniqueid" is needed for the
  2503. * latter case.
  2504. */
  2505. rc = _entryrdn_get_tombstone_elem(cursor, tmpsrdn, &key,
  2506. childnrdn, &tmpelem);
  2507. if (rc) {
  2508. char *dn = NULL;
  2509. slapi_rdn_get_dn(tmpsrdn, &dn);
  2510. if (DB_NOTFOUND == rc) {
  2511. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2512. "_entryrdn_insert_key: Node \"%s\" not found: "
  2513. "%s(%d)\n", dn, dblayer_strerror(rc), rc);
  2514. } else {
  2515. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2516. "_entryrdn_insert_key: Getting \"%s\" failed: "
  2517. "%s(%d)\n", dn, dblayer_strerror(rc), rc);
  2518. }
  2519. slapi_ch_free_string(&dn);
  2520. goto bail;
  2521. }
  2522. /* Node is a tombstone. */
  2523. if (tmpelem) {
  2524. currid = id_stored_to_internal(tmpelem->rdn_elem_id);
  2525. nrdn = childnrdn;
  2526. workid = currid;
  2527. slapi_ch_free((void **)&parentelem);
  2528. parentelem = tmpelem;
  2529. slapi_ch_free((void **)&elem);
  2530. }
  2531. }
  2532. } else {
  2533. char *dn = NULL;
  2534. slapi_rdn_get_dn(tmpsrdn, &dn);
  2535. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2536. "_entryrdn_insert_key: Suffix \"%s\" not found: "
  2537. "%s(%d)\n", nrdn, dblayer_strerror(rc), rc);
  2538. slapi_ch_free_string(&dn);
  2539. goto bail;
  2540. }
  2541. } else { /* rc == 0; succeeded to get an element */
  2542. ID currid = 0;
  2543. slapi_ch_free((void **)&elem);
  2544. elem = tmpelem;
  2545. currid = id_stored_to_internal(elem->rdn_elem_id);
  2546. if (0 == rdnidx) { /* Child is a Leaf RDN to be added */
  2547. if (currid == id) {
  2548. /* already in the file */
  2549. /* do nothing and return. */
  2550. rc = 0;
  2551. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  2552. "_entryrdn_insert_key: ID %d is already "
  2553. "in the index. NOOP.\n", currid);
  2554. } else { /* different id, error return */
  2555. char *dn = NULL;
  2556. int tmprc = slapi_rdn_get_dn(srdn, &dn);
  2557. slapi_log_error(SLAPI_LOG_FATAL,
  2558. ENTRYRDN_TAG,
  2559. "_entryrdn_insert_key: Same DN (%s: %s) "
  2560. "is already in the %s file with different ID "
  2561. "%d. Expected ID is %d.\n",
  2562. tmprc?"rdn":"dn", tmprc?childnrdn:dn,
  2563. LDBM_ENTRYRDN_STR, currid, id);
  2564. slapi_ch_free_string(&dn);
  2565. /* returning special error code for the upgrade */
  2566. rc = LDBM_ERROR_FOUND_DUPDN;
  2567. }
  2568. goto bail;
  2569. } else { /* if (0 != rdnidx) */
  2570. nrdn = childnrdn;
  2571. workid = currid;
  2572. slapi_ch_free((void **)&parentelem);
  2573. parentelem = elem;
  2574. elem = NULL;
  2575. }
  2576. }
  2577. if (tmpsrdn != srdn) {
  2578. slapi_rdn_free(&tmpsrdn);
  2579. }
  2580. } while (rdnidx >= 0 && workid > 0);
  2581. bail:
  2582. if (tmpsrdn != srdn) {
  2583. slapi_rdn_free(&tmpsrdn);
  2584. }
  2585. slapi_ch_free_string(&keybuf);
  2586. slapi_ch_free((void **)&elem);
  2587. slapi_ch_free((void **)&parentelem);
  2588. slapi_ch_free((void **)&childelem);
  2589. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  2590. "<-- _entryrdn_insert_key\n");
  2591. return rc;
  2592. }
  2593. /*
  2594. * This function checks the existence of the target self link (key ID:RDN;
  2595. * value ID,RDN,normalized RDN). If it exists and it does not have child links,
  2596. * then it deletes the parent's child link and the self link.
  2597. */
  2598. static int
  2599. _entryrdn_delete_key(backend *be,
  2600. DBC *cursor,
  2601. Slapi_RDN *srdn,
  2602. ID id,
  2603. DB_TXN *db_txn)
  2604. {
  2605. int rc = -1;
  2606. size_t len = 0;
  2607. const char *nrdn = NULL; /* normalized rdn */
  2608. const char *suffix = NULL; /* normalized suffix */
  2609. char *parentnrdn = NULL; /* normalized parent rdn */
  2610. const char *selfnrdn = NULL; /* normalized parent rdn */
  2611. int rdnidx = -1;
  2612. int lastidx = -1;
  2613. char *keybuf = NULL;
  2614. DBT key, data;
  2615. ID workid = 0;
  2616. rdn_elem *elem = NULL;
  2617. int issuffix = 0;
  2618. Slapi_RDN *tmpsrdn = NULL;
  2619. int db_retry = 0;
  2620. int done = 0;
  2621. char buffer[RDN_BULK_FETCH_BUFFER_SIZE];
  2622. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  2623. "--> _entryrdn_delete_key\n");
  2624. if (NULL == be || NULL == cursor || NULL == srdn || 0 == id) {
  2625. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2626. "_entryrdn_delete_key: Param error: Empty %s\n",
  2627. NULL==be?"backend":NULL==cursor?"cursor":NULL==srdn?"RDN":
  2628. 0==id?"ID":"unknown");
  2629. goto bail;
  2630. }
  2631. /* get the bottom normalized rdn (target to delete) */
  2632. rdnidx = slapi_rdn_get_first_ext(srdn, &nrdn, FLAG_ALL_NRDNS);
  2633. /* rdnidx is supposed to be 0 */
  2634. if (rdnidx < 0 || NULL == nrdn) {
  2635. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2636. "_entryrdn_delete_key: Empty RDN\n");
  2637. goto bail;
  2638. }
  2639. lastidx = slapi_rdn_get_last_ext(srdn, &suffix, FLAG_ALL_NRDNS);
  2640. if (0 == lastidx) {
  2641. issuffix = 1;
  2642. selfnrdn = suffix;
  2643. } else if (lastidx < 0 || NULL == suffix) {
  2644. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2645. "_entryrdn_delete_key: Empty suffix\n");
  2646. goto bail;
  2647. }
  2648. /* check if the target element has a child or not */
  2649. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_CHILD, id);
  2650. key.data = (void *)keybuf;
  2651. key.size = key.ulen = strlen(keybuf) + 1;
  2652. key.flags = DB_DBT_USERMEM;
  2653. /* Setting the bulk fetch buffer */
  2654. memset(&data, 0, sizeof(data));
  2655. data.ulen = sizeof(buffer);
  2656. data.size = sizeof(buffer);
  2657. data.data = buffer;
  2658. data.flags = DB_DBT_USERMEM;
  2659. done = 0;
  2660. while (!done) {
  2661. rc = cursor->c_get(cursor, &key, &data, DB_SET|DB_MULTIPLE);
  2662. if (DB_LOCK_DEADLOCK == rc) {
  2663. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2664. "_entryrdn_delete_key: cursor get deadlock\n");
  2665. #ifdef FIX_TXN_DEADLOCKS
  2666. #error if txn != NULL, have to retry the entire transaction
  2667. #endif
  2668. /* try again */
  2669. continue;
  2670. } else if (DB_NOTFOUND == rc) {
  2671. /* no children; ok */
  2672. done = 1;
  2673. continue;
  2674. } else if (rc) {
  2675. _entryrdn_cursor_print_error("_entryrdn_delete_key",
  2676. key.data, data.size, data.ulen, rc);
  2677. goto bail;
  2678. }
  2679. do {
  2680. rdn_elem *childelem = NULL;
  2681. DBT dataret;
  2682. void *ptr;
  2683. DB_MULTIPLE_INIT(ptr, &data);
  2684. do {
  2685. memset(&dataret, 0, sizeof(dataret));
  2686. DB_MULTIPLE_NEXT(ptr, &data, dataret.data, dataret.size);
  2687. if (NULL == dataret.data || NULL == ptr) {
  2688. break;
  2689. }
  2690. childelem = (rdn_elem *)dataret.data;
  2691. if (!slapi_is_special_rdn(childelem->rdn_elem_nrdn_rdn, RDN_IS_TOMBSTONE)) {
  2692. /* there's at least one live child */
  2693. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2694. "_entryrdn_delete_key: Failed to remove %s; "
  2695. "has a child %s\n", nrdn,
  2696. (char *)childelem->rdn_elem_nrdn_rdn);
  2697. rc = -1;
  2698. goto bail;
  2699. }
  2700. } while (NULL != dataret.data && NULL != ptr);
  2701. retry_get:
  2702. rc = cursor->c_get(cursor, &key, &data, DB_NEXT_DUP|DB_MULTIPLE);
  2703. if (DB_LOCK_DEADLOCK == rc) {
  2704. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2705. "_entryrdn_delete_key: retry cursor get deadlock\n");
  2706. #ifdef FIX_TXN_DEADLOCKS
  2707. #error if txn != NULL, have to retry the entire transaction
  2708. #endif
  2709. /* try again */
  2710. goto retry_get;
  2711. } else if (DB_NOTFOUND == rc) {
  2712. rc = 0;
  2713. done = 1;
  2714. break;
  2715. } else if (rc) {
  2716. _entryrdn_cursor_print_error("_entryrdn_delete_key",
  2717. key.data, data.size, data.ulen, rc);
  2718. goto bail;
  2719. }
  2720. } while (0 == rc);
  2721. }
  2722. workid = id;
  2723. do {
  2724. slapi_ch_free_string(&keybuf);
  2725. slapi_ch_free((void **)&elem);
  2726. tmpsrdn = srdn;
  2727. if (NULL == parentnrdn && NULL == selfnrdn) {
  2728. /* First, deleting parent link */
  2729. /* E.g., P10 */
  2730. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_PARENT, workid);
  2731. rc = slapi_rdn_partial_dup(srdn, &tmpsrdn, 1);
  2732. if (rc) {
  2733. char *dn = NULL;
  2734. slapi_rdn_get_dn(srdn, &dn);
  2735. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2736. "_entryrdn_delete_key: partial dup of %s (idx %d) "
  2737. "failed (%d)\n", dn, 1, rc);
  2738. slapi_ch_free_string(&dn);
  2739. goto bail;
  2740. }
  2741. elem = _entryrdn_new_rdn_elem(be, TMPID, tmpsrdn, &len);
  2742. if (NULL == elem) {
  2743. char *dn = NULL;
  2744. slapi_rdn_get_dn(tmpsrdn, &dn);
  2745. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2746. "_entryrdn_delete_key: Failed to generate a parent "
  2747. "elem: dn: %s\n", dn);
  2748. slapi_ch_free_string(&dn);
  2749. slapi_rdn_free(&tmpsrdn);
  2750. goto bail;
  2751. }
  2752. } else if (parentnrdn) {
  2753. /* Then, the child link from the parent */
  2754. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_CHILD, workid);
  2755. elem = _entryrdn_new_rdn_elem(be, id, srdn, &len);
  2756. if (NULL == elem) {
  2757. char *dn = NULL;
  2758. slapi_rdn_get_dn(srdn, &dn);
  2759. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2760. "_entryrdn_delete_key: Failed to generate a parent's "
  2761. "child elem: dn: %s\n", dn);
  2762. slapi_ch_free_string(&dn);
  2763. goto bail;
  2764. }
  2765. } else if (selfnrdn) {
  2766. /* Then, deleting the self elem */
  2767. if (issuffix) {
  2768. keybuf = slapi_ch_smprintf("%s", selfnrdn);
  2769. } else {
  2770. keybuf = slapi_ch_smprintf("%u", workid);
  2771. }
  2772. elem = _entryrdn_new_rdn_elem(be, id, srdn, &len);
  2773. if (NULL == elem) {
  2774. char *dn = NULL;
  2775. slapi_rdn_get_dn(srdn, &dn);
  2776. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2777. "_entryrdn_delete_key: Failed to generate a target "
  2778. "elem: dn: %s\n", dn);
  2779. slapi_ch_free_string(&dn);
  2780. goto bail;
  2781. }
  2782. }
  2783. key.data = keybuf;
  2784. key.size = key.ulen = strlen(keybuf) + 1;
  2785. key.flags = DB_DBT_USERMEM;
  2786. memset(&data, 0, sizeof(data));
  2787. data.ulen = data.size = len;
  2788. data.data = elem;
  2789. data.flags = DB_DBT_USERMEM;
  2790. /* Position cursor at the matching key */
  2791. rc = _entryrdn_get_elem(cursor, &key, &data,
  2792. slapi_rdn_get_nrdn(tmpsrdn), &elem);
  2793. if (tmpsrdn != srdn) {
  2794. slapi_rdn_free(&tmpsrdn);
  2795. }
  2796. if (rc) {
  2797. if (DB_NOTFOUND == rc) {
  2798. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  2799. "_entryrdn_delete_key: No parent link %s\n", keybuf);
  2800. goto bail;
  2801. } else {
  2802. /* There's no parent or positioning at parent failed */
  2803. _entryrdn_cursor_print_error("_entryrdn_delete_key",
  2804. key.data, data.size, data.ulen, rc);
  2805. goto bail;
  2806. }
  2807. }
  2808. if (NULL == parentnrdn && NULL == selfnrdn) {
  2809. /* First, deleting parent link */
  2810. #ifdef LDAP_DEBUG_ENTRYRDN
  2811. _entryrdn_dump_rdn_elem(elem);
  2812. #endif
  2813. parentnrdn = slapi_ch_strdup(elem->rdn_elem_nrdn_rdn);
  2814. workid = id_stored_to_internal(elem->rdn_elem_id);
  2815. /* deleteing the parent link */
  2816. /* the cursor is set at the parent link by _entryrdn_get_elem */
  2817. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  2818. rc = cursor->c_del(cursor, 0);
  2819. if (rc && (DB_NOTFOUND != rc)) {
  2820. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2821. "_entryrdn_delete_key: Deleting %s failed; "
  2822. "%s(%d)\n", (char *)key.data,
  2823. dblayer_strerror(rc), rc);
  2824. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  2825. ENTRYRDN_DELAY; /* sleep for a bit then retry immediately */
  2826. continue;
  2827. }
  2828. goto bail; /* if deadlock and txn, have to abort entire txn */
  2829. } else {
  2830. break; /* success */
  2831. }
  2832. }
  2833. if (RETRY_TIMES == db_retry) {
  2834. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2835. "_entryrdn_delete_key: delete parent link failed after [%d] retries\n",
  2836. db_retry);
  2837. rc = DB_LOCK_DEADLOCK;
  2838. goto bail;
  2839. }
  2840. } else if (parentnrdn) {
  2841. #ifdef LDAP_DEBUG_ENTRYRDN
  2842. _entryrdn_dump_rdn_elem(elem);
  2843. #endif
  2844. slapi_ch_free_string(&parentnrdn);
  2845. /* deleteing the parent's child link */
  2846. /* the cursor is set at the parent link by _entryrdn_get_elem */
  2847. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  2848. rc = cursor->c_del(cursor, 0);
  2849. if (rc && (DB_NOTFOUND != rc)) {
  2850. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2851. "_entryrdn_delete_key: Deleting %s failed; "
  2852. "%s(%d)\n", (char *)key.data,
  2853. dblayer_strerror(rc), rc);
  2854. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  2855. ENTRYRDN_DELAY;
  2856. continue;
  2857. }
  2858. goto bail; /* if deadlock and txn, have to abort entire txn */
  2859. } else {
  2860. break; /* success */
  2861. }
  2862. }
  2863. if (RETRY_TIMES == db_retry) {
  2864. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2865. "_entryrdn_delete_key: delete parent's child link failed after [%d] retries\n",
  2866. db_retry);
  2867. rc = DB_LOCK_DEADLOCK;
  2868. goto bail;
  2869. }
  2870. selfnrdn = nrdn;
  2871. workid = id;
  2872. } else if (selfnrdn) {
  2873. #ifdef LDAP_DEBUG_ENTRYRDN
  2874. _entryrdn_dump_rdn_elem(elem);
  2875. #endif
  2876. /* deleteing the self link */
  2877. /* the cursor is set at the parent link by _entryrdn_get_elem */
  2878. for (db_retry = 0; db_retry < RETRY_TIMES; db_retry++) {
  2879. rc = cursor->c_del(cursor, 0);
  2880. if (rc && (DB_NOTFOUND != rc)) {
  2881. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  2882. "_entryrdn_delete_key: Deleting %s failed; "
  2883. "%s(%d)\n", (char *)key.data,
  2884. dblayer_strerror(rc), rc);
  2885. if ((DB_LOCK_DEADLOCK == rc) && !db_txn) {
  2886. ENTRYRDN_DELAY;
  2887. continue;
  2888. }
  2889. goto bail; /* if deadlock and txn, have to abort entire txn */
  2890. } else {
  2891. break; /* success */
  2892. }
  2893. }
  2894. if (RETRY_TIMES == db_retry) {
  2895. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2896. "_entryrdn_delete_key: delete self link failed after [%d] retries\n",
  2897. db_retry);
  2898. rc = DB_LOCK_DEADLOCK;
  2899. }
  2900. goto bail; /* done */
  2901. }
  2902. } while (workid);
  2903. bail:
  2904. slapi_ch_free_string(&parentnrdn);
  2905. slapi_ch_free_string(&keybuf);
  2906. slapi_ch_free((void **)&elem);
  2907. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  2908. "<-- _entryrdn_delete_key\n");
  2909. return rc;
  2910. }
  2911. static int
  2912. _entryrdn_index_read(backend *be,
  2913. DBC *cursor,
  2914. Slapi_RDN *srdn,
  2915. rdn_elem **elem,
  2916. rdn_elem **parentelem,
  2917. rdn_elem ***childelems,
  2918. int flags,
  2919. DB_TXN *db_txn)
  2920. {
  2921. int rc = -1;
  2922. size_t len = 0;
  2923. ID id;
  2924. const char *nrdn = NULL; /* normalized rdn */
  2925. const char *childnrdn = NULL; /* normalized rdn */
  2926. int rdnidx = -1;
  2927. char *keybuf = NULL;
  2928. DBT key, data;
  2929. size_t childnum = 32;
  2930. size_t curr_childnum = 0;
  2931. Slapi_RDN *tmpsrdn = NULL;
  2932. rdn_elem *tmpelem = NULL;
  2933. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  2934. "--> _entryrdn_index_read\n");
  2935. if (NULL == be || NULL == cursor ||
  2936. NULL == srdn || NULL == elem) {
  2937. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2938. "_entryrdn_index_read: Param error: Empty %s\n",
  2939. NULL==be?"backend":NULL==cursor?"cursor":NULL==srdn?"RDN":
  2940. NULL==elem?"elem container":"unknown");
  2941. goto bail;
  2942. }
  2943. *elem = NULL;
  2944. if (parentelem) {
  2945. *parentelem = NULL;
  2946. }
  2947. if (childelems) {
  2948. *childelems = NULL;
  2949. }
  2950. /* get the top normalized rdn (normalized suffix) */
  2951. rdnidx = slapi_rdn_get_last_ext(srdn, &nrdn, FLAG_ALL_NRDNS);
  2952. if (rdnidx < 0 || NULL == nrdn) {
  2953. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2954. "_entryrdn_index_read: Empty RDN (Suffix)\n");
  2955. goto bail;
  2956. }
  2957. /* Setting up a key for suffix */
  2958. keybuf = slapi_ch_smprintf("%s", nrdn);
  2959. key.data = keybuf;
  2960. key.size = key.ulen = strlen(keybuf) + 1;
  2961. key.flags = DB_DBT_USERMEM;
  2962. /* get id of the suffix */
  2963. tmpsrdn = NULL;
  2964. /* tmpsrdn == suffix'es srdn */
  2965. rc = slapi_rdn_partial_dup(srdn, &tmpsrdn, rdnidx);
  2966. if (rc) {
  2967. char *dn = NULL;
  2968. slapi_rdn_get_dn(srdn, &dn);
  2969. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2970. "_entryrdn_index_read: partial dup of %s (idx %d) "
  2971. "failed (%d)\n", dn, rdnidx, rc);
  2972. slapi_ch_free_string(&dn);
  2973. goto bail;
  2974. }
  2975. *elem = _entryrdn_new_rdn_elem(be, TMPID, tmpsrdn, &len);
  2976. if (NULL == *elem) {
  2977. char *dn = NULL;
  2978. slapi_rdn_get_dn(tmpsrdn, &dn);
  2979. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  2980. "_entryrdn_index_read: Failed to generate a new elem: "
  2981. "dn: %s\n", dn);
  2982. slapi_ch_free_string(&dn);
  2983. slapi_rdn_free(&tmpsrdn);
  2984. goto bail;
  2985. }
  2986. memset(&data, 0, sizeof(data));
  2987. data.ulen = data.size = len;
  2988. data.data = *elem;
  2989. data.flags = DB_DBT_USERMEM;
  2990. /* getting the suffix element */
  2991. rc = _entryrdn_get_elem(cursor, &key, &data, nrdn, elem);
  2992. if (rc || NULL == *elem) {
  2993. slapi_ch_free((void **)elem);
  2994. if (flags & TOMBSTONE_INCLUDED) {
  2995. /* Node might be a tombstone. */
  2996. rc = _entryrdn_get_tombstone_elem(cursor, tmpsrdn,
  2997. &key, nrdn, elem);
  2998. rdnidx--; /* consider nsuniqueid=..,<RDN> one RDN */
  2999. }
  3000. if (rc || NULL == *elem) {
  3001. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  3002. "_entryrdn_index_read: Suffix \"%s\" not found: "
  3003. "%s(%d)\n", nrdn, dblayer_strerror(rc), rc);
  3004. rc = DB_NOTFOUND;
  3005. slapi_rdn_free(&tmpsrdn);
  3006. goto bail;
  3007. }
  3008. }
  3009. slapi_rdn_free(&tmpsrdn);
  3010. /* workid: ID of suffix */
  3011. id = id_stored_to_internal((*elem)->rdn_elem_id);
  3012. do {
  3013. slapi_ch_free_string(&keybuf);
  3014. /* Check the direct child in the RDN array, first */
  3015. childnrdn = NULL;
  3016. rdnidx = slapi_rdn_get_prev_ext(srdn, rdnidx,
  3017. &childnrdn, FLAG_ALL_NRDNS);
  3018. if (0 > rdnidx) {
  3019. if (childelems) {
  3020. break; /* get the child elems */
  3021. } else {
  3022. /* We got the targetelem.
  3023. * And we don't have to gather childelems, so we can return. */
  3024. #ifdef LDAP_DEBUG_ENTRYRDN
  3025. char *dn = NULL;
  3026. slapi_rdn_get_dn(srdn, &dn);
  3027. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  3028. "_entryrdn_index_read: done; DN %s => ID %d\n",
  3029. dn, id);
  3030. slapi_ch_free_string(&dn);
  3031. #endif
  3032. goto bail;
  3033. }
  3034. }
  3035. /* 0 <= rdnidx */
  3036. tmpsrdn = srdn;
  3037. if (0 < rdnidx) {
  3038. rc = slapi_rdn_partial_dup(srdn, &tmpsrdn, rdnidx);
  3039. if (rc) {
  3040. char *dn = NULL;
  3041. slapi_rdn_get_dn(srdn, &dn);
  3042. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  3043. "_entryrdn_delete_key: partial dup of %s "
  3044. "(idx %d) failed (%d)\n", dn, rdnidx, rc);
  3045. slapi_ch_free_string(&dn);
  3046. goto bail;
  3047. }
  3048. }
  3049. tmpelem = _entryrdn_new_rdn_elem(be, TMPID, tmpsrdn, &len);
  3050. if (NULL == tmpelem) {
  3051. char *dn = NULL;
  3052. slapi_rdn_get_dn(tmpsrdn, &dn);
  3053. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  3054. "_entryrdn_index_read: Failed to generate a new elem: "
  3055. "dn: %s\n", dn);
  3056. slapi_ch_free_string(&dn);
  3057. if (tmpsrdn != srdn) {
  3058. slapi_rdn_free(&tmpsrdn);
  3059. }
  3060. goto bail;
  3061. }
  3062. /* Generate a key for child tree */
  3063. /* E.g., C1 */
  3064. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_CHILD, id);
  3065. key.data = keybuf;
  3066. key.size = key.ulen = strlen(keybuf) + 1;
  3067. key.flags = DB_DBT_USERMEM;
  3068. memset(&data, 0, sizeof(data));
  3069. data.ulen = data.size = len;
  3070. data.data = tmpelem;
  3071. data.flags = DB_DBT_USERMEM;
  3072. /* Position cursor at the matching key */
  3073. rc = _entryrdn_get_elem(cursor, &key, &data, childnrdn, &tmpelem);
  3074. if (rc) {
  3075. slapi_ch_free((void **)&tmpelem);
  3076. if (flags & TOMBSTONE_INCLUDED) {
  3077. /* Node might be a tombstone */
  3078. /*
  3079. * In DIT cn=A,ou=B,o=C, cn=A and ou=B are removed and
  3080. * turned to tombstone entries. We need to support both:
  3081. * nsuniqueid=...,cn=A,ou=B,o=C and
  3082. * nsuniqueid=...,cn=A,nsuniqueid=...,ou=B,o=C
  3083. */
  3084. rc = _entryrdn_get_tombstone_elem(cursor, tmpsrdn, &key,
  3085. childnrdn, &tmpelem);
  3086. if (rc || (NULL == tmpelem)) {
  3087. slapi_ch_free((void **)&tmpelem);
  3088. if (DB_NOTFOUND != rc) {
  3089. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  3090. "_entryrdn_index_read: Child link \"%s\" of "
  3091. "key \"%s\" not found: %s(%d)\n",
  3092. childnrdn, keybuf, dblayer_strerror(rc), rc);
  3093. rc = DB_NOTFOUND;
  3094. }
  3095. if (tmpsrdn != srdn) {
  3096. slapi_rdn_free(&tmpsrdn);
  3097. }
  3098. goto bail;
  3099. }
  3100. rdnidx--; /* consider nsuniqueid=..,<RDN> one RDN */
  3101. } else {
  3102. slapi_ch_free((void **)&tmpelem);
  3103. if (DB_NOTFOUND != rc) {
  3104. slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
  3105. "_entryrdn_index_read: Child link \"%s\" of "
  3106. "key \"%s\" not found: %s(%d)\n",
  3107. childnrdn, keybuf, dblayer_strerror(rc), rc);
  3108. rc = DB_NOTFOUND;
  3109. }
  3110. if (tmpsrdn != srdn) {
  3111. slapi_rdn_free(&tmpsrdn);
  3112. }
  3113. goto bail;
  3114. }
  3115. }
  3116. if (tmpsrdn != srdn) {
  3117. slapi_rdn_free(&tmpsrdn);
  3118. }
  3119. #ifdef LDAP_DEBUG_ENTRYRDN
  3120. _entryrdn_dump_rdn_elem(tmpelem);
  3121. #endif
  3122. if (parentelem) {
  3123. slapi_ch_free((void **)parentelem);
  3124. *parentelem = *elem;
  3125. } else {
  3126. slapi_ch_free((void **)elem);
  3127. }
  3128. *elem = tmpelem;
  3129. #ifdef LDAP_DEBUG_ENTRYRDN
  3130. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  3131. "_entryrdn_index_read: %s matched normalized child "
  3132. "rdn %s\n", (*elem)->rdn_elem_nrdn_rdn, childnrdn);
  3133. #endif
  3134. id = id_stored_to_internal((*elem)->rdn_elem_id);
  3135. nrdn = childnrdn;
  3136. if (0 == id) {
  3137. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  3138. "_entryrdn_index_read: Child %s of %s not found\n",
  3139. childnrdn, nrdn);
  3140. break;
  3141. }
  3142. } while (rdnidx >= 0);
  3143. /* get the child elems */
  3144. if (childelems) {
  3145. char buffer[RDN_BULK_FETCH_BUFFER_SIZE];
  3146. slapi_ch_free_string(&keybuf);
  3147. keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_CHILD, id);
  3148. key.data = keybuf;
  3149. key.size = key.ulen = strlen(keybuf) + 1;
  3150. key.flags = DB_DBT_USERMEM;
  3151. /* Setting the bulk fetch buffer */
  3152. memset(&data, 0, sizeof(data));
  3153. data.ulen = sizeof(buffer);
  3154. data.size = sizeof(buffer);
  3155. data.data = buffer;
  3156. data.flags = DB_DBT_USERMEM;
  3157. retry_get0:
  3158. rc = cursor->c_get(cursor, &key, &data, DB_SET|DB_MULTIPLE);
  3159. if (DB_LOCK_DEADLOCK == rc) {
  3160. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  3161. "_entryrdn_index_read: cursor get deadlock\n");
  3162. #ifdef FIX_TXN_DEADLOCKS
  3163. #error if txn != NULL, have to retry the entire transaction
  3164. #endif
  3165. /* try again */
  3166. goto retry_get0;
  3167. } else if (DB_NOTFOUND == rc) {
  3168. rc = 0; /* Child not found is ok */
  3169. goto bail;
  3170. } else if (rc) {
  3171. _entryrdn_cursor_print_error("_entryrdn_index_read",
  3172. key.data, data.size, data.ulen, rc);
  3173. goto bail;
  3174. }
  3175. *childelems = (rdn_elem **)slapi_ch_calloc(childnum,
  3176. sizeof(rdn_elem *));
  3177. do {
  3178. rdn_elem *childelem = NULL;
  3179. DBT dataret;
  3180. void *ptr;
  3181. DB_MULTIPLE_INIT(ptr, &data);
  3182. do {
  3183. memset(&dataret, 0, sizeof(dataret));
  3184. DB_MULTIPLE_NEXT(ptr, &data, dataret.data, dataret.size);
  3185. if (NULL == dataret.data || NULL == ptr) {
  3186. break;
  3187. }
  3188. _entryrdn_dup_rdn_elem((const void *)dataret.data, &childelem);
  3189. if (curr_childnum + 1 == childnum) {
  3190. childnum *= 2;
  3191. *childelems =
  3192. (rdn_elem **)slapi_ch_realloc((char *)*childelems,
  3193. sizeof(rdn_elem *) * childnum);
  3194. memset(*childelems + curr_childnum, 0,
  3195. sizeof(rdn_elem *) * (childnum - curr_childnum));
  3196. }
  3197. (*childelems)[curr_childnum++] = childelem;
  3198. } while (NULL != dataret.data && NULL != ptr);
  3199. retry_get1:
  3200. rc = cursor->c_get(cursor, &key, &data, DB_NEXT_DUP|DB_MULTIPLE);
  3201. if (DB_LOCK_DEADLOCK == rc) {
  3202. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  3203. "_entryrdn_index_read: retry cursor get deadlock\n");
  3204. #ifdef FIX_TXN_DEADLOCKS
  3205. #error if txn != NULL, have to retry the entire transaction
  3206. #endif
  3207. /* try again */
  3208. goto retry_get1;
  3209. } else if (DB_NOTFOUND == rc) {
  3210. rc = 0;
  3211. goto bail; /* done */
  3212. } else if (rc) {
  3213. _entryrdn_cursor_print_error("_entryrdn_index_read",
  3214. key.data, data.size, data.ulen, rc);
  3215. goto bail;
  3216. }
  3217. } while (0 == rc);
  3218. }
  3219. bail:
  3220. if (childelems && *childelems && 0 == curr_childnum) {
  3221. slapi_ch_free((void **)childelems);
  3222. }
  3223. slapi_ch_free_string(&keybuf);
  3224. slapi_log_error(SLAPI_LOG_TRACE, ENTRYRDN_TAG,
  3225. "<-- _entryrdn_index_read\n");
  3226. return rc;
  3227. }
  3228. static int
  3229. _entryrdn_append_childidl(DBC *cursor,
  3230. const char *nrdn,
  3231. ID id,
  3232. IDList **affectedidl)
  3233. {
  3234. /* E.g., C5 */
  3235. char *keybuf = slapi_ch_smprintf("%c%u", RDN_INDEX_CHILD, id);
  3236. DBT key, data;
  3237. char buffer[RDN_BULK_FETCH_BUFFER_SIZE];
  3238. int rc = 0;
  3239. key.data = keybuf;
  3240. key.size = key.ulen = strlen(keybuf) + 1;
  3241. key.flags = DB_DBT_USERMEM;
  3242. /* Setting the bulk fetch buffer */
  3243. memset(&data, 0, sizeof(data));
  3244. data.ulen = sizeof(buffer);
  3245. data.size = sizeof(buffer);
  3246. data.data = buffer;
  3247. data.flags = DB_DBT_USERMEM;
  3248. /* Position cursor at the matching key */
  3249. retry_get0:
  3250. rc = cursor->c_get(cursor, &key, &data, DB_SET|DB_MULTIPLE);
  3251. if (rc) {
  3252. if (DB_LOCK_DEADLOCK == rc) {
  3253. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  3254. "_entryrdn_append_childidl: cursor get deadlock\n");
  3255. /* try again */
  3256. #ifdef FIX_TXN_DEADLOCKS
  3257. #error if txn != NULL, have to retry the entire transaction
  3258. #endif
  3259. goto retry_get0;
  3260. } else if (DB_NOTFOUND == rc) {
  3261. rc = 0; /* okay not to have children */
  3262. } else {
  3263. _entryrdn_cursor_print_error("_entryrdn_append_childidl",
  3264. key.data, data.size, data.ulen, rc);
  3265. }
  3266. goto bail;
  3267. }
  3268. /* Iterate over the duplicates to get the direct child's ID */
  3269. do {
  3270. rdn_elem *myelem = NULL;
  3271. DBT dataret;
  3272. void *ptr;
  3273. DB_MULTIPLE_INIT(ptr, &data);
  3274. do {
  3275. ID myid = 0;
  3276. myelem = NULL;
  3277. memset(&dataret, 0, sizeof(dataret));
  3278. DB_MULTIPLE_NEXT(ptr, &data, dataret.data, dataret.size);
  3279. if (NULL == dataret.data || NULL == ptr) {
  3280. break;
  3281. }
  3282. myelem = (rdn_elem *)dataret.data;
  3283. myid = id_stored_to_internal(myelem->rdn_elem_id);
  3284. rc = idl_append_extend(affectedidl, myid);
  3285. if (rc) {
  3286. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  3287. "_entryrdn_append_childidl: Appending %d to "
  3288. "affectedidl failed (%d)\n", myid, rc);
  3289. goto bail;
  3290. }
  3291. rc = _entryrdn_append_childidl(cursor,
  3292. (const char *)myelem->rdn_elem_nrdn_rdn,
  3293. myid, affectedidl);
  3294. if (rc) {
  3295. goto bail;
  3296. }
  3297. } while (NULL != dataret.data && NULL != ptr);
  3298. retry_get1:
  3299. rc = cursor->c_get(cursor, &key, &data, DB_NEXT_DUP|DB_MULTIPLE);
  3300. if (rc) {
  3301. if (DB_LOCK_DEADLOCK == rc) {
  3302. slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
  3303. "_entryrdn_append_childidl: retry cursor get deadlock\n");
  3304. /* try again */
  3305. #ifdef FIX_TXN_DEADLOCKS
  3306. #error if txn != NULL, have to retry the entire transaction
  3307. #endif
  3308. goto retry_get1;
  3309. } else if (DB_NOTFOUND == rc) {
  3310. rc = 0; /* okay not to have children */
  3311. } else {
  3312. _entryrdn_cursor_print_error("_entryrdn_append_childidl",
  3313. key.data, data.size, data.ulen, rc);
  3314. }
  3315. goto bail;
  3316. }
  3317. } while (0 == rc);
  3318. bail:
  3319. slapi_ch_free_string(&keybuf);
  3320. return rc;
  3321. }
  3322. static void
  3323. _entryrdn_cursor_print_error(char *fn, void *key,
  3324. size_t need, size_t actual, int rc)
  3325. {
  3326. if (DB_BUFFER_SMALL == rc) {
  3327. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  3328. "%s: Entryrdn index is corrupt; data item for key %s "
  3329. "is too large for the buffer need=%lu actual=%lu)\n",
  3330. fn, (char *)key, need, actual);
  3331. } else {
  3332. slapi_log_error(SLAPI_LOG_FATAL, ENTRYRDN_TAG,
  3333. "%s: Failed to position cursor at "
  3334. "the key: %s: %s(%d)\n",
  3335. fn, (char *)key, dblayer_strerror(rc), rc);
  3336. }
  3337. }