dn2entry.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* dn2entry.c - given a dn return an entry */
  42. #include "back-ldbm.h"
  43. /*
  44. * Fetch the entry for this DN.
  45. *
  46. * Retuns NULL of the entry doesn't exist
  47. */
  48. struct backentry *
  49. dn2entry(
  50. Slapi_Backend *be,
  51. const Slapi_DN *sdn,
  52. back_txn *txn,
  53. int *err
  54. )
  55. {
  56. ldbm_instance *inst;
  57. struct berval ndnv;
  58. struct backentry *e = NULL;
  59. LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2entry \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
  60. inst = (ldbm_instance *) be->be_instance_info;
  61. *err = 0;
  62. ndnv.bv_val = (void*)slapi_sdn_get_ndn(sdn); /* jcm - Had to cast away const */
  63. ndnv.bv_len = slapi_sdn_get_ndn_len(sdn);
  64. e = cache_find_dn(&inst->inst_cache, ndnv.bv_val, ndnv.bv_len);
  65. if (e == NULL)
  66. {
  67. /* convert dn to entry id */
  68. IDList *idl = NULL;
  69. if ( (idl = index_read( be, "entrydn", indextype_EQUALITY, &ndnv, txn, err )) == NULL )
  70. {
  71. /* There's no entry with this DN. */
  72. }
  73. else
  74. {
  75. /* convert entry id to entry */
  76. if ( (e = id2entry( be, idl_firstid( idl ), txn, err )) != NULL )
  77. {
  78. /* Means that we found the entry OK */
  79. }
  80. else
  81. {
  82. /* Hmm. The DN mapped onto an EntryID, but that didn't map onto an Entry. */
  83. if ( *err != 0 && *err != DB_NOTFOUND )
  84. {
  85. /* JCM - Not sure if this is ever OK or not. */
  86. }
  87. else
  88. {
  89. /*
  90. * this is pretty bad anyway. the dn was in the
  91. * entrydn index, but we could not read the entry
  92. * from the id2entry index. what should we do?
  93. */
  94. LDAPDebug( LDAP_DEBUG_ANY,
  95. "dn2entry: the dn was in the entrydn index (id %lu), "
  96. "but it did not exist in id2entry.\n",
  97. (u_long)idl_firstid( idl ), 0, 0 );
  98. }
  99. }
  100. slapi_ch_free((void**)&idl);
  101. }
  102. }
  103. LDAPDebug( LDAP_DEBUG_TRACE, "<= dn2entry %p\n", e, 0, 0 );
  104. return( e );
  105. }
  106. /*
  107. * Use the DN to fetch the parent of the entry.
  108. * If the parent entry doesn't exist, keep working
  109. * up the DN until we hit "" or an backend suffix.
  110. *
  111. * ancestordn should be initialized before calling this function, and
  112. * should be empty
  113. *
  114. * Returns NULL for no entry found.
  115. *
  116. * When the caller is finished with the entry returned, it should return it
  117. * to the cache:
  118. * e = dn2ancestor( ... );
  119. * if ( NULL != e ) {
  120. * cache_return( &inst->inst_cache, &e );
  121. * }
  122. */
  123. struct backentry *
  124. dn2ancestor(
  125. Slapi_Backend *be,
  126. const Slapi_DN *sdn,
  127. Slapi_DN *ancestordn,
  128. back_txn *txn,
  129. int *err
  130. )
  131. {
  132. struct backentry *e = NULL;
  133. LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2ancestor \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
  134. /* first, check to see if the given sdn is empty or a root suffix of the
  135. given backend - if so, it has no parent */
  136. if (!slapi_sdn_isempty(sdn) && !slapi_be_issuffix( be, sdn )) {
  137. Slapi_DN ancestorndn;
  138. const char *ptr;
  139. /* assign ancestordn to the parent of the given dn - ancestordn will contain
  140. the "raw" unnormalized DN from the caller, so we can give back the DN
  141. in the same format as we received it */
  142. ptr = slapi_dn_find_parent(slapi_sdn_get_dn(sdn));
  143. /* assign the ancestordn dn pointer to the parent of dn from sdn - sdn "owns"
  144. the memory, but ancestordn points to it */
  145. slapi_sdn_set_dn_byref(ancestordn, ptr); /* free any previous contents */
  146. /* now, do the same for the normalized version */
  147. /* ancestorndn holds the normalized version for iteration purposes and
  148. because dn2entry needs the normalized dn */
  149. ptr = slapi_dn_find_parent(slapi_sdn_get_ndn(sdn));
  150. slapi_sdn_init_ndn_byref(&ancestorndn, ptr);
  151. /*
  152. At this point you may be wondering why I need both ancestorndn and
  153. ancestordn. Because, with the slapi_sdn interface, you cannot set both
  154. the dn and ndn byref at the same time. Whenever you call set_dn or set_ndn,
  155. it calls slapi_sdn_done which wipes out the previous contents. I suppose I
  156. could have added another API to allow you to pass them both in. Also, using
  157. slapi_sdn_get_ndn(ancestordn) every time would result in making a copy then
  158. normalizing the copy every time - not efficient.
  159. So, why not just use a char* for the ancestorndn? Because dn2entry requires
  160. a Slapi_DN with the normalized dn.
  161. */
  162. /* stop when we get to "", or a backend suffix point */
  163. while (!e && !slapi_sdn_isempty(&ancestorndn) && !slapi_be_issuffix( be, &ancestorndn )) {
  164. /* find the entry - it uses the ndn, so no further conversion is necessary */
  165. e= dn2entry(be,&ancestorndn,txn,err);
  166. if (!e) {
  167. /* not found, so set ancestordn to its parent and try again */
  168. ptr = slapi_dn_find_parent(slapi_sdn_get_ndn(&ancestorndn));
  169. /* keep in mind that ptr points to the raw ndn pointer inside
  170. ancestorndn which is still the ndn string "owned" by sdn, the
  171. original dn we started with - we are careful not to touch
  172. or change it */
  173. slapi_sdn_set_ndn_byref(&ancestorndn, ptr); /* wipe out the previous contents */
  174. /* now do the same for the unnormalized one */
  175. ptr = slapi_dn_find_parent(slapi_sdn_get_dn(ancestordn));
  176. slapi_sdn_set_dn_byref(ancestordn, ptr); /* wipe out the previous contents */
  177. }
  178. }
  179. slapi_sdn_done(&ancestorndn);
  180. }
  181. /* post conditions:
  182. e is the entry of the ancestor of sdn OR e is the suffix entry
  183. OR e is NULL
  184. ancestordn contains the unnormalized DN of e or is empty */
  185. LDAPDebug( LDAP_DEBUG_TRACE, "<= dn2ancestor %p\n", e, 0, 0 );
  186. return( e );
  187. }
  188. /*
  189. * Use uniqueid2entry or dn2entry to fetch an entry from the cache,
  190. * make a copy of it, and stash it in the pblock.
  191. */
  192. int
  193. get_copy_of_entry(Slapi_PBlock *pb, const entry_address *addr, back_txn *txn, int plock_parameter, int must_exist) /* JCM - Move somewhere more appropriate */
  194. {
  195. int err= 0;
  196. int rc= LDAP_SUCCESS;
  197. backend *be;
  198. struct backentry *entry;
  199. slapi_pblock_get( pb, SLAPI_BACKEND, &be);
  200. if( addr->uniqueid!=NULL)
  201. {
  202. entry = uniqueid2entry(be, addr->uniqueid, txn, &err );
  203. }
  204. else
  205. {
  206. Slapi_DN sdn;
  207. slapi_sdn_init_dn_byref (&sdn, addr->dn); /* We assume that the DN is not normalized */
  208. entry = dn2entry( be, &sdn, txn, &err );
  209. slapi_sdn_done (&sdn);
  210. }
  211. if ( 0 != err && DB_NOTFOUND != err )
  212. {
  213. if(must_exist)
  214. {
  215. LDAPDebug( LDAP_DEBUG_ANY, "Operation error fetching %s (%s), error %d.\n",
  216. addr->dn, (addr->uniqueid==NULL?"null":addr->uniqueid), err );
  217. }
  218. rc= LDAP_OPERATIONS_ERROR;
  219. }
  220. else
  221. {
  222. /* If an entry is found, copy it into the PBlock. */
  223. if(entry!=NULL)
  224. {
  225. ldbm_instance *inst;
  226. slapi_pblock_set( pb, plock_parameter, slapi_entry_dup(entry->ep_entry));
  227. inst = (ldbm_instance *) be->be_instance_info;
  228. cache_return( &inst->inst_cache, &entry );
  229. }
  230. }
  231. /* JCMREPL - Free the backentry? */
  232. return rc;
  233. }
  234. void
  235. done_with_pblock_entry(Slapi_PBlock *pb, int plock_parameter) /* JCM - Move somewhere more appropriate */
  236. {
  237. Slapi_Entry *entry;
  238. slapi_pblock_get( pb, plock_parameter, &entry);
  239. if(entry!=NULL)
  240. {
  241. slapi_entry_free(entry);
  242. entry= NULL;
  243. slapi_pblock_set( pb, plock_parameter, entry);
  244. }
  245. }