repl5_updatedn_list.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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. /* repl5_updatedn_list.c */
  42. /*
  43. This is the internal representation for the list of update DNs in the replica.
  44. The list is implemented as a hash table - the key is the normalized DN, and the
  45. value is the Slapi_DN representation of the DN
  46. */
  47. #include "repl5.h"
  48. #include "plhash.h"
  49. /* global data */
  50. /* typedef ReplicaUpdateDNList PLHashTable; */
  51. struct repl_enum_data
  52. {
  53. FNEnumDN fn;
  54. void *arg;
  55. };
  56. /* Forward declarations */
  57. static PRIntn replica_destroy_hash_entry (PLHashEntry *he, PRIntn index, void *arg);
  58. static PRIntn updatedn_list_enumerate (PLHashEntry *he, PRIntn index, void *hash_data);
  59. static int
  60. updatedn_compare_dns(const void *d1, const void *d2)
  61. {
  62. return (0 == slapi_sdn_compare((const Slapi_DN *)d1, (const Slapi_DN *)d2));
  63. }
  64. /* create a new updatedn list - if the entry is given, initialize the list from
  65. the replicabinddn values given in the entry */
  66. ReplicaUpdateDNList
  67. replica_updatedn_list_new(const Slapi_Entry *entry)
  68. {
  69. /* allocate table */
  70. PLHashTable *hash = PL_NewHashTable(4, PL_HashString, PL_CompareStrings,
  71. updatedn_compare_dns, NULL, NULL);
  72. if (hash == NULL) {
  73. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_new_updatedn_list: "
  74. "failed to allocate hash table; NSPR error - %d\n",
  75. PR_GetError ());
  76. return NULL;
  77. }
  78. if (entry) {
  79. Slapi_Attr *attr = NULL;
  80. if (!slapi_entry_attr_find(entry, attr_replicaBindDn, &attr)) {
  81. Slapi_ValueSet *vs = NULL;
  82. slapi_attr_get_valueset(attr, &vs);
  83. replica_updatedn_list_replace(hash, vs);
  84. slapi_valueset_free(vs);
  85. }
  86. }
  87. return (ReplicaUpdateDNList)hash;
  88. }
  89. void
  90. replica_updatedn_list_free(ReplicaUpdateDNList list)
  91. {
  92. /* destroy the content */
  93. PLHashTable *hash = list;
  94. PL_HashTableEnumerateEntries(hash, replica_destroy_hash_entry, NULL);
  95. if (hash)
  96. PL_HashTableDestroy(hash);
  97. }
  98. void
  99. replica_updatedn_list_replace(ReplicaUpdateDNList list, const Slapi_ValueSet *vs)
  100. {
  101. replica_updatedn_list_delete(list, NULL); /* delete all values */
  102. replica_updatedn_list_add(list, vs);
  103. }
  104. /* if vs is given, delete only those values - otherwise, delete all values */
  105. void
  106. replica_updatedn_list_delete(ReplicaUpdateDNList list, const Slapi_ValueSet *vs)
  107. {
  108. PLHashTable *hash = list;
  109. if (!vs || slapi_valueset_count(vs) == 0) { /* just delete everything */
  110. PL_HashTableEnumerateEntries(hash, replica_destroy_hash_entry, NULL);
  111. } else {
  112. Slapi_ValueSet *vs_nc = (Slapi_ValueSet *)vs; /* cast away const */
  113. Slapi_Value *val = NULL;
  114. int index = 0;
  115. for (index = slapi_valueset_first_value(vs_nc, &val); val;
  116. index = slapi_valueset_next_value(vs_nc, index, &val)) {
  117. Slapi_DN *dn = slapi_sdn_new_dn_byval(slapi_value_get_string(val));
  118. /* locate object */
  119. Slapi_DN *deldn = (Slapi_DN *)PL_HashTableLookup(hash, slapi_sdn_get_ndn(dn));
  120. if (deldn == NULL)
  121. {
  122. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_updatedn_list_delete: "
  123. "update DN with value (%s) is not in the update DN list.\n",
  124. slapi_sdn_get_ndn(dn));
  125. } else {
  126. /* remove from hash */
  127. PL_HashTableRemove(hash, slapi_sdn_get_ndn(dn));
  128. /* free the pointer */
  129. slapi_sdn_free(&deldn);
  130. }
  131. /* free the temp dn */
  132. slapi_sdn_free(&dn);
  133. }
  134. }
  135. return;
  136. }
  137. void
  138. replica_updatedn_list_add(ReplicaUpdateDNList list, const Slapi_ValueSet *vs)
  139. {
  140. PLHashTable *hash = list;
  141. Slapi_ValueSet *vs_nc = (Slapi_ValueSet *)vs; /* cast away const */
  142. Slapi_Value *val = NULL;
  143. int index = 0;
  144. PR_ASSERT(list && vs);
  145. for (index = slapi_valueset_first_value(vs_nc, &val); val;
  146. index = slapi_valueset_next_value(vs_nc, index, &val)) {
  147. Slapi_DN *dn = slapi_sdn_new_dn_byval(slapi_value_get_string(val));
  148. const char *ndn = slapi_sdn_get_ndn(dn);
  149. /* make sure that the name is unique */
  150. if (PL_HashTableLookup(hash, ndn) != NULL)
  151. {
  152. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_updatedn_list_add: "
  153. "update DN with value (%s) already in the update DN list\n",
  154. ndn);
  155. slapi_sdn_free(&dn);
  156. } else {
  157. PL_HashTableAdd(hash, ndn, dn);
  158. }
  159. }
  160. return;
  161. }
  162. PRBool
  163. replica_updatedn_list_ismember(ReplicaUpdateDNList list, const Slapi_DN *dn)
  164. {
  165. PLHashTable *hash = list;
  166. PRBool ret = PR_FALSE;
  167. const char *ndn = slapi_sdn_get_ndn(dn);
  168. /* Bug 605169 - null ndn would cause core dump */
  169. if ( ndn ) {
  170. ret = (PRBool)((uintptr_t)PL_HashTableLookupConst(hash, ndn));
  171. }
  172. return ret;
  173. }
  174. struct list_to_string_data {
  175. char *string;
  176. const char *delimiter;
  177. };
  178. static int
  179. convert_to_string(Slapi_DN *dn, void *arg)
  180. {
  181. struct list_to_string_data *data = (struct list_to_string_data *)arg;
  182. int newlen = slapi_sdn_get_ndn_len(dn) + strlen(data->delimiter) + 1;
  183. if (data->string) {
  184. newlen += strlen(data->string);
  185. data->string = slapi_ch_realloc(data->string, newlen);
  186. } else {
  187. data->string = slapi_ch_calloc(1, newlen);
  188. }
  189. strcat(data->string, slapi_sdn_get_dn(dn));
  190. strcat(data->string, data->delimiter);
  191. return 1;
  192. }
  193. /* caller must slapi_ch_free_string the returned string */
  194. char *
  195. replica_updatedn_list_to_string(ReplicaUpdateDNList list, const char *delimiter)
  196. {
  197. struct list_to_string_data data;
  198. data.string = NULL;
  199. data.delimiter = delimiter;
  200. replica_updatedn_list_enumerate(list, convert_to_string, (void *)&data);
  201. return data.string;
  202. }
  203. void
  204. replica_updatedn_list_enumerate(ReplicaUpdateDNList list, FNEnumDN fn, void *arg)
  205. {
  206. PLHashTable *hash = list;
  207. struct repl_enum_data data;
  208. PR_ASSERT (fn);
  209. data.fn = fn;
  210. data.arg = arg;
  211. PL_HashTableEnumerateEntries(hash, updatedn_list_enumerate, &data);
  212. }
  213. /* Helper functions */
  214. /* this function called for each hash node during hash destruction */
  215. static PRIntn
  216. replica_destroy_hash_entry(PLHashEntry *he, PRIntn index, void *arg)
  217. {
  218. Slapi_DN *dn = NULL;
  219. if (he == NULL)
  220. return HT_ENUMERATE_NEXT;
  221. dn = (Slapi_DN *)he->value;
  222. PR_ASSERT (dn);
  223. slapi_sdn_free(&dn);
  224. return HT_ENUMERATE_REMOVE;
  225. }
  226. static PRIntn
  227. updatedn_list_enumerate(PLHashEntry *he, PRIntn index, void *hash_data)
  228. {
  229. Slapi_DN *dn = NULL;
  230. struct repl_enum_data *data = hash_data;
  231. dn = (Slapi_DN*)he->value;
  232. PR_ASSERT (dn);
  233. data->fn(dn, data->arg);
  234. return HT_ENUMERATE_NEXT;
  235. }