fs_namespace.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. /*
  2. This file is part of GNUnet
  3. (C) 2003-2013 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file fs/fs_namespace.c
  19. * @brief publishing to namespaces, and tracking updateable entries
  20. * for our namespaces
  21. * @author Christian Grothoff
  22. */
  23. #include "platform.h"
  24. #include "gnunet_constants.h"
  25. #include "gnunet_signatures.h"
  26. #include "gnunet_util_lib.h"
  27. #include "gnunet_fs_service.h"
  28. #include "fs_api.h"
  29. #include "fs_publish_ublock.h"
  30. /**
  31. * Information about an (updateable) node in the
  32. * namespace.
  33. */
  34. struct NamespaceUpdateNode
  35. {
  36. /**
  37. * Identifier for this node.
  38. */
  39. char *id;
  40. /**
  41. * Identifier of children of this node.
  42. */
  43. char *update;
  44. /**
  45. * Metadata for this entry.
  46. */
  47. struct GNUNET_CONTAINER_MetaData *md;
  48. /**
  49. * URI of this entry in the namespace.
  50. */
  51. struct GNUNET_FS_Uri *uri;
  52. /**
  53. * Namespace update generation ID. Used to ensure
  54. * freshness of the tree_id.
  55. */
  56. unsigned int nug;
  57. /**
  58. * TREE this entry belongs to (if nug is current).
  59. */
  60. unsigned int tree_id;
  61. };
  62. /**
  63. * Handle to update information for a namespace.
  64. */
  65. struct GNUNET_FS_UpdateInformationGraph
  66. {
  67. /**
  68. * Handle to the FS service context.
  69. */
  70. struct GNUNET_FS_Handle *h;
  71. /**
  72. * Array with information about nodes in the namespace.
  73. */
  74. struct NamespaceUpdateNode **update_nodes;
  75. /**
  76. * Private key for the namespace.
  77. */
  78. struct GNUNET_CRYPTO_EcdsaPrivateKey ns;
  79. /**
  80. * Hash map mapping identifiers of update nodes
  81. * to the update nodes (initialized on-demand).
  82. */
  83. struct GNUNET_CONTAINER_MultiHashMap *update_map;
  84. /**
  85. * Size of the update nodes array.
  86. */
  87. unsigned int update_node_count;
  88. /**
  89. * Reference counter.
  90. */
  91. unsigned int rc;
  92. /**
  93. * Generator for unique nug numbers.
  94. */
  95. unsigned int nug_gen;
  96. };
  97. /**
  98. * Return the name of the directory in which we store
  99. * the update information graph for the given local namespace.
  100. *
  101. * @param h file-sharing handle
  102. * @param ns namespace handle
  103. * @return NULL on error, otherwise the name of the directory
  104. */
  105. static char *
  106. get_update_information_directory (struct GNUNET_FS_Handle *h,
  107. const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns)
  108. {
  109. char *dn;
  110. char *ret;
  111. struct GNUNET_CRYPTO_EcdsaPublicKey pub;
  112. struct GNUNET_HashCode hc;
  113. struct GNUNET_CRYPTO_HashAsciiEncoded enc;
  114. if (GNUNET_OK !=
  115. GNUNET_CONFIGURATION_get_value_filename (h->cfg, "FS", "UPDATE_DIR",
  116. &dn))
  117. {
  118. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
  119. "fs", "UPDATE_DIR");
  120. return NULL;
  121. }
  122. GNUNET_CRYPTO_ecdsa_key_get_public (ns, &pub);
  123. GNUNET_CRYPTO_hash (&pub, sizeof (pub), &hc);
  124. GNUNET_CRYPTO_hash_to_enc (&hc,
  125. &enc);
  126. GNUNET_asprintf (&ret, "%s%s%s",
  127. dn,
  128. DIR_SEPARATOR_STR,
  129. (const char *) enc.encoding);
  130. GNUNET_free (dn);
  131. return ret;
  132. }
  133. /**
  134. * Release memory occupied by UIG datastructure.
  135. *
  136. * @param uig data structure to free
  137. */
  138. static void
  139. free_update_information_graph (struct GNUNET_FS_UpdateInformationGraph *uig)
  140. {
  141. unsigned int i;
  142. struct NamespaceUpdateNode *nsn;
  143. for (i = 0; i < uig->update_node_count; i++)
  144. {
  145. nsn = uig->update_nodes[i];
  146. GNUNET_CONTAINER_meta_data_destroy (nsn->md);
  147. GNUNET_FS_uri_destroy (nsn->uri);
  148. GNUNET_free (nsn->id);
  149. GNUNET_free (nsn->update);
  150. GNUNET_free (nsn);
  151. }
  152. GNUNET_array_grow (uig->update_nodes, uig->update_node_count,
  153. 0);
  154. if (NULL != uig->update_map)
  155. GNUNET_CONTAINER_multihashmap_destroy (uig->update_map);
  156. GNUNET_free (uig);
  157. }
  158. /**
  159. * Write a namespace's update node graph to a file.
  160. *
  161. * @param uig update information graph to dump
  162. */
  163. static void
  164. write_update_information_graph (struct GNUNET_FS_UpdateInformationGraph *uig)
  165. {
  166. char *fn;
  167. struct GNUNET_BIO_WriteHandle *wh;
  168. unsigned int i;
  169. struct NamespaceUpdateNode *n;
  170. char *uris;
  171. fn = get_update_information_directory (uig->h,
  172. &uig->ns);
  173. wh = GNUNET_BIO_write_open (fn);
  174. if (NULL == wh)
  175. {
  176. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  177. _("Failed to open `%s' for writing: %s\n"), STRERROR (errno));
  178. GNUNET_free (fn);
  179. return;
  180. }
  181. if (GNUNET_OK != GNUNET_BIO_write_int32 (wh, uig->update_node_count))
  182. goto END;
  183. for (i = 0; i < uig->update_node_count; i++)
  184. {
  185. n = uig->update_nodes[i];
  186. uris = GNUNET_FS_uri_to_string (n->uri);
  187. if ((GNUNET_OK != GNUNET_BIO_write_string (wh, n->id)) ||
  188. (GNUNET_OK != GNUNET_BIO_write_meta_data (wh, n->md)) ||
  189. (GNUNET_OK != GNUNET_BIO_write_string (wh, n->update)) ||
  190. (GNUNET_OK != GNUNET_BIO_write_string (wh, uris)))
  191. {
  192. GNUNET_free (uris);
  193. break;
  194. }
  195. GNUNET_free (uris);
  196. }
  197. END:
  198. if (GNUNET_OK != GNUNET_BIO_write_close (wh))
  199. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to write `%s': %s\n"),
  200. STRERROR (errno));
  201. GNUNET_free (fn);
  202. }
  203. /**
  204. * Read the namespace update node graph from a file.
  205. *
  206. * @param h FS handle to use
  207. * @param ns namespace to read
  208. * @return update graph, never NULL
  209. */
  210. static struct GNUNET_FS_UpdateInformationGraph *
  211. read_update_information_graph (struct GNUNET_FS_Handle *h,
  212. const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns)
  213. {
  214. struct GNUNET_FS_UpdateInformationGraph *uig;
  215. char *fn;
  216. struct GNUNET_BIO_ReadHandle *rh;
  217. unsigned int i;
  218. struct NamespaceUpdateNode *n;
  219. char *uris;
  220. uint32_t count;
  221. char *emsg;
  222. uig = GNUNET_new (struct GNUNET_FS_UpdateInformationGraph);
  223. uig->h = h;
  224. uig->ns = *ns;
  225. fn = get_update_information_directory (h, ns);
  226. if (GNUNET_YES != GNUNET_DISK_file_test (fn))
  227. {
  228. GNUNET_free (fn);
  229. return uig;
  230. }
  231. rh = GNUNET_BIO_read_open (fn);
  232. if (NULL == rh)
  233. {
  234. GNUNET_free (fn);
  235. return uig;
  236. }
  237. if (GNUNET_OK != GNUNET_BIO_read_int32 (rh, &count))
  238. {
  239. GNUNET_break (0);
  240. goto END;
  241. }
  242. if (count > 1024 * 1024)
  243. {
  244. GNUNET_break (0);
  245. goto END;
  246. }
  247. if (0 == count)
  248. goto END;
  249. uig->update_nodes =
  250. GNUNET_malloc (count * sizeof (struct NamespaceUpdateNode *));
  251. for (i = 0; i < count; i++)
  252. {
  253. n = GNUNET_new (struct NamespaceUpdateNode);
  254. if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "identifier", &n->id, 1024))
  255. || (GNUNET_OK != GNUNET_BIO_read_meta_data (rh, "meta", &n->md)) ||
  256. (GNUNET_OK !=
  257. GNUNET_BIO_read_string (rh, "update-id", &n->update, 1024)) ||
  258. (GNUNET_OK != GNUNET_BIO_read_string (rh, "uri", &uris, 1024 * 2)))
  259. {
  260. GNUNET_break (0);
  261. GNUNET_free_non_null (n->id);
  262. GNUNET_free_non_null (n->update);
  263. if (n->md != NULL)
  264. GNUNET_CONTAINER_meta_data_destroy (n->md);
  265. GNUNET_free (n);
  266. break;
  267. }
  268. n->uri = GNUNET_FS_uri_parse (uris, &emsg);
  269. GNUNET_free (uris);
  270. if (n->uri == NULL)
  271. {
  272. GNUNET_break (0);
  273. GNUNET_free (emsg);
  274. GNUNET_free (n->id);
  275. GNUNET_free_non_null (n->update);
  276. GNUNET_CONTAINER_meta_data_destroy (n->md);
  277. GNUNET_free (n);
  278. break;
  279. }
  280. uig->update_nodes[i] = n;
  281. }
  282. uig->update_node_count = i;
  283. END:
  284. if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
  285. {
  286. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to read `%s': %s\n"),
  287. fn, emsg);
  288. GNUNET_free (emsg);
  289. }
  290. GNUNET_free (fn);
  291. return uig;
  292. }
  293. /**
  294. * Context for the SKS publication.
  295. */
  296. struct GNUNET_FS_PublishSksContext
  297. {
  298. /**
  299. * URI of the new entry in the namespace.
  300. */
  301. struct GNUNET_FS_Uri *uri;
  302. /**
  303. * Namespace update node to add to namespace on success (or to be
  304. * deleted if publishing failed).
  305. */
  306. struct NamespaceUpdateNode *nsn;
  307. /**
  308. * Namespace we're publishing to.
  309. */
  310. struct GNUNET_CRYPTO_EcdsaPrivateKey ns;
  311. /**
  312. * Handle to the datastore.
  313. */
  314. struct GNUNET_DATASTORE_Handle *dsh;
  315. /**
  316. * Handle to FS.
  317. */
  318. struct GNUNET_FS_Handle *h;
  319. /**
  320. * Function to call once we're done.
  321. */
  322. GNUNET_FS_PublishContinuation cont;
  323. /**
  324. * Closure for cont.
  325. */
  326. void *cont_cls;
  327. /**
  328. * Handle for our UBlock operation request.
  329. */
  330. struct GNUNET_FS_PublishUblockContext *uc;
  331. };
  332. /**
  333. * Function called by the UBlock construction with
  334. * the result from the PUT (UBlock) request.
  335. *
  336. * @param cls closure of type "struct GNUNET_FS_PublishSksContext*"
  337. * @param msg error message (or NULL)
  338. */
  339. static void
  340. sks_publish_cont (void *cls,
  341. const char *msg)
  342. {
  343. struct GNUNET_FS_PublishSksContext *psc = cls;
  344. struct GNUNET_FS_UpdateInformationGraph *uig;
  345. psc->uc = NULL;
  346. if (NULL != msg)
  347. {
  348. if (NULL != psc->cont)
  349. psc->cont (psc->cont_cls, NULL, msg);
  350. GNUNET_FS_publish_sks_cancel (psc);
  351. return;
  352. }
  353. if (NULL != psc->nsn)
  354. {
  355. /* FIXME: this can be done much more
  356. * efficiently by simply appending to the
  357. * file and overwriting the 4-byte header */
  358. uig = read_update_information_graph (psc->h,
  359. &psc->ns);
  360. GNUNET_array_append (uig->update_nodes,
  361. uig->update_node_count,
  362. psc->nsn);
  363. psc->nsn = NULL;
  364. write_update_information_graph (uig);
  365. free_update_information_graph (uig);
  366. }
  367. if (NULL != psc->cont)
  368. psc->cont (psc->cont_cls, psc->uri, NULL);
  369. GNUNET_FS_publish_sks_cancel (psc);
  370. }
  371. /**
  372. * Publish an SBlock on GNUnet.
  373. *
  374. * @param h handle to the file sharing subsystem
  375. * @param ns namespace to publish in
  376. * @param identifier identifier to use
  377. * @param update update identifier to use
  378. * @param meta metadata to use
  379. * @param uri URI to refer to in the SBlock
  380. * @param bo block options
  381. * @param options publication options
  382. * @param cont continuation
  383. * @param cont_cls closure for cont
  384. * @return NULL on error ('cont' will still be called)
  385. */
  386. struct GNUNET_FS_PublishSksContext *
  387. GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h,
  388. const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns,
  389. const char *identifier, const char *update,
  390. const struct GNUNET_CONTAINER_MetaData *meta,
  391. const struct GNUNET_FS_Uri *uri,
  392. const struct GNUNET_FS_BlockOptions *bo,
  393. enum GNUNET_FS_PublishOptions options,
  394. GNUNET_FS_PublishContinuation cont, void *cont_cls)
  395. {
  396. struct GNUNET_FS_PublishSksContext *psc;
  397. struct GNUNET_FS_Uri *sks_uri;
  398. sks_uri = GNUNET_new (struct GNUNET_FS_Uri);
  399. sks_uri->type = GNUNET_FS_URI_SKS;
  400. sks_uri->data.sks.identifier = GNUNET_strdup (identifier);
  401. GNUNET_CRYPTO_ecdsa_key_get_public (ns,
  402. &sks_uri->data.sks.ns);
  403. psc = GNUNET_new (struct GNUNET_FS_PublishSksContext);
  404. psc->h = h;
  405. psc->uri = sks_uri;
  406. psc->cont = cont;
  407. psc->cont_cls = cont_cls;
  408. psc->ns = *ns;
  409. if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
  410. {
  411. psc->dsh = GNUNET_DATASTORE_connect (h->cfg);
  412. if (NULL == psc->dsh)
  413. {
  414. sks_publish_cont (psc,
  415. _("Failed to connect to datastore."));
  416. return NULL;
  417. }
  418. }
  419. if (NULL != update)
  420. {
  421. psc->nsn = GNUNET_new (struct NamespaceUpdateNode);
  422. psc->nsn->id = GNUNET_strdup (identifier);
  423. psc->nsn->update = GNUNET_strdup (update);
  424. psc->nsn->md = GNUNET_CONTAINER_meta_data_duplicate (meta);
  425. psc->nsn->uri = GNUNET_FS_uri_dup (uri);
  426. }
  427. psc->uc = GNUNET_FS_publish_ublock_ (h,
  428. psc->dsh,
  429. identifier,
  430. update,
  431. ns,
  432. meta,
  433. uri,
  434. bo,
  435. options,
  436. &sks_publish_cont,
  437. psc);
  438. return psc;
  439. }
  440. /**
  441. * Abort the SKS publishing operation.
  442. *
  443. * @param psc context of the operation to abort.
  444. */
  445. void
  446. GNUNET_FS_publish_sks_cancel (struct GNUNET_FS_PublishSksContext *psc)
  447. {
  448. if (NULL != psc->uc)
  449. {
  450. GNUNET_FS_publish_ublock_cancel_ (psc->uc);
  451. psc->uc = NULL;
  452. }
  453. if (NULL != psc->dsh)
  454. {
  455. GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO);
  456. psc->dsh = NULL;
  457. }
  458. GNUNET_FS_uri_destroy (psc->uri);
  459. if (NULL != psc->nsn)
  460. {
  461. GNUNET_CONTAINER_meta_data_destroy (psc->nsn->md);
  462. GNUNET_FS_uri_destroy (psc->nsn->uri);
  463. GNUNET_free (psc->nsn->id);
  464. GNUNET_free (psc->nsn->update);
  465. GNUNET_free (psc->nsn);
  466. }
  467. GNUNET_free (psc);
  468. }
  469. /**
  470. * Closure for 'process_update_node'.
  471. */
  472. struct ProcessUpdateClosure
  473. {
  474. /**
  475. * Function to call for each node.
  476. */
  477. GNUNET_FS_IdentifierProcessor ip;
  478. /**
  479. * Closure for 'ip'.
  480. */
  481. void *ip_cls;
  482. };
  483. /**
  484. * Call the iterator in the closure for each node.
  485. *
  486. * @param cls closure (of type 'struct ProcessUpdateClosure *')
  487. * @param key current key code
  488. * @param value value in the hash map (of type 'struct NamespaceUpdateNode *')
  489. * @return GNUNET_YES if we should continue to
  490. * iterate,
  491. * GNUNET_NO if not.
  492. */
  493. static int
  494. process_update_node (void *cls,
  495. const struct GNUNET_HashCode *key,
  496. void *value)
  497. {
  498. struct ProcessUpdateClosure *pc = cls;
  499. struct NamespaceUpdateNode *nsn = value;
  500. pc->ip (pc->ip_cls,
  501. nsn->id,
  502. nsn->uri,
  503. nsn->md,
  504. nsn->update);
  505. return GNUNET_YES;
  506. }
  507. /**
  508. * Closure for 'find_trees'.
  509. */
  510. struct FindTreeClosure
  511. {
  512. /**
  513. * UIG we are operating on.
  514. */
  515. struct GNUNET_FS_UpdateInformationGraph *uig;
  516. /**
  517. * Array with 'head's of TREEs.
  518. */
  519. struct NamespaceUpdateNode **tree_array;
  520. /**
  521. * Size of 'tree_array'
  522. */
  523. unsigned int tree_array_size;
  524. /**
  525. * Current generational ID used.
  526. */
  527. unsigned int nug;
  528. /**
  529. * Identifier for the current TREE, or UINT_MAX for none yet.
  530. */
  531. unsigned int id;
  532. };
  533. /**
  534. * Find all nodes reachable from the current node (including the
  535. * current node itself). If they are in no tree, add them to the
  536. * current one. If they are the head of another tree, merge the
  537. * trees. If they are in the middle of another tree, let them be.
  538. * We can tell that a node is already in an tree by checking if
  539. * its 'nug' field is set to the current 'nug' value. It is the
  540. * head of an tree if it is in the 'tree_array' under its respective
  541. * 'tree_id'.
  542. *
  543. * In short, we're trying to find the smallest number of tree to
  544. * cover a directed graph.
  545. *
  546. * @param cls closure (of type 'struct FindTreeClosure')
  547. * @param key current key code
  548. * @param value value in the hash map
  549. * @return GNUNET_YES if we should continue to
  550. * iterate,
  551. * GNUNET_NO if not.
  552. */
  553. static int
  554. find_trees (void *cls,
  555. const struct GNUNET_HashCode *key,
  556. void *value)
  557. {
  558. struct FindTreeClosure *fc = cls;
  559. struct NamespaceUpdateNode *nsn = value;
  560. struct GNUNET_HashCode hc;
  561. if (nsn->nug == fc->nug)
  562. {
  563. if (UINT_MAX == nsn->tree_id)
  564. return GNUNET_YES; /* circular */
  565. GNUNET_assert (nsn->tree_id < fc->tree_array_size);
  566. if (fc->tree_array[nsn->tree_id] != nsn)
  567. return GNUNET_YES; /* part of "another" (directed) TREE,
  568. * and not root of it, end trace */
  569. if (nsn->tree_id == fc->id)
  570. return GNUNET_YES; /* that's our own root (can this be?) */
  571. /* merge existing TREE, we have a root for both */
  572. fc->tree_array[nsn->tree_id] = NULL;
  573. if (UINT_MAX == fc->id)
  574. fc->id = nsn->tree_id; /* take over ID */
  575. }
  576. else
  577. {
  578. nsn->nug = fc->nug;
  579. nsn->tree_id = UINT_MAX; /* mark as undef */
  580. /* trace */
  581. GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc);
  582. GNUNET_CONTAINER_multihashmap_get_multiple (fc->uig->update_map, &hc,
  583. &find_trees, fc);
  584. }
  585. return GNUNET_YES;
  586. }
  587. /**
  588. * List all of the identifiers in the namespace for which we could
  589. * produce an update. Namespace updates form a graph where each node
  590. * has a name. Each node can have any number of URI/meta-data entries
  591. * which can each be linked to other nodes. Cycles are possible.
  592. *
  593. * Calling this function with "next_id" NULL will cause the library to
  594. * call "ip" with a root for each strongly connected component of the
  595. * graph (a root being a node from which all other nodes in the Tree
  596. * are reachable).
  597. *
  598. * Calling this function with "next_id" being the name of a node will
  599. * cause the library to call "ip" with all children of the node. Note
  600. * that cycles within the final tree are possible (including self-loops).
  601. * I know, odd definition of a tree, but the GUI will display an actual
  602. * tree (GtkTreeView), so that's what counts for the term here.
  603. *
  604. * @param h fs handle to use
  605. * @param ns namespace to inspect for updateable content
  606. * @param next_id ID to look for; use NULL to look for tree roots
  607. * @param ip function to call on each updateable identifier
  608. * @param ip_cls closure for ip
  609. */
  610. void
  611. GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Handle *h,
  612. const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns,
  613. const char *next_id,
  614. GNUNET_FS_IdentifierProcessor ip,
  615. void *ip_cls)
  616. {
  617. unsigned int i;
  618. unsigned int nug;
  619. struct GNUNET_HashCode hc;
  620. struct NamespaceUpdateNode *nsn;
  621. struct ProcessUpdateClosure pc;
  622. struct FindTreeClosure fc;
  623. struct GNUNET_FS_UpdateInformationGraph *uig;
  624. uig = read_update_information_graph (h, ns);
  625. if (NULL == uig->update_nodes)
  626. {
  627. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  628. "No updateable nodes found for ID `%s'\n", next_id);
  629. free_update_information_graph (uig);
  630. return; /* no nodes */
  631. }
  632. uig->update_map =
  633. GNUNET_CONTAINER_multihashmap_create (2 +
  634. 3 * uig->update_node_count /
  635. 4,
  636. GNUNET_NO);
  637. for (i = 0; i < uig->update_node_count; i++)
  638. {
  639. nsn = uig->update_nodes[i];
  640. GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc);
  641. GNUNET_CONTAINER_multihashmap_put (uig->update_map, &hc, nsn,
  642. GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  643. }
  644. if (NULL != next_id)
  645. {
  646. GNUNET_CRYPTO_hash (next_id, strlen (next_id), &hc);
  647. pc.ip = ip;
  648. pc.ip_cls = ip_cls;
  649. GNUNET_CONTAINER_multihashmap_get_multiple (uig->update_map, &hc,
  650. &process_update_node, &pc);
  651. free_update_information_graph (uig);
  652. return;
  653. }
  654. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  655. "Calculating TREEs to find roots of update trees\n");
  656. /* Find heads of TREEs in update graph */
  657. nug = ++uig->nug_gen;
  658. fc.tree_array = NULL;
  659. fc.tree_array_size = 0;
  660. for (i = 0; i < uig->update_node_count; i++)
  661. {
  662. nsn = uig->update_nodes[i];
  663. if (nsn->nug == nug)
  664. {
  665. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TREE of node `%s' is %u\n", nsn->id,
  666. nsn->nug);
  667. continue; /* already placed in TREE */
  668. }
  669. GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc);
  670. nsn->nug = nug;
  671. nsn->tree_id = UINT_MAX;
  672. fc.id = UINT_MAX;
  673. fc.nug = nug;
  674. fc.uig = uig;
  675. GNUNET_CONTAINER_multihashmap_get_multiple (uig->update_map, &hc,
  676. &find_trees, &fc);
  677. if (UINT_MAX == fc.id)
  678. {
  679. /* start new TREE */
  680. for (fc.id = 0; fc.id < fc.tree_array_size; fc.id++)
  681. {
  682. if (NULL == fc.tree_array[fc.id])
  683. {
  684. fc.tree_array[fc.id] = nsn;
  685. nsn->tree_id = fc.id;
  686. break;
  687. }
  688. }
  689. if (fc.id == fc.tree_array_size)
  690. {
  691. GNUNET_array_append (fc.tree_array, fc.tree_array_size, nsn);
  692. nsn->tree_id = fc.id;
  693. }
  694. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  695. "Starting new TREE %u with node `%s'\n", nsn->tree_id,
  696. nsn->id);
  697. /* put all nodes with same identifier into this TREE */
  698. GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc);
  699. fc.id = nsn->tree_id;
  700. fc.nug = nug;
  701. fc.uig = uig;
  702. GNUNET_CONTAINER_multihashmap_get_multiple (uig->update_map, &hc,
  703. &find_trees, &fc);
  704. }
  705. else
  706. {
  707. /* make head of TREE "id" */
  708. fc.tree_array[fc.id] = nsn;
  709. nsn->tree_id = fc.id;
  710. }
  711. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  712. "TREE of node `%s' is %u\n", nsn->id,
  713. fc.id);
  714. }
  715. for (i = 0; i < fc.tree_array_size; i++)
  716. {
  717. nsn = fc.tree_array[i];
  718. if (NULL != nsn)
  719. {
  720. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Root of TREE %u is node `%s'\n", i,
  721. nsn->id);
  722. ip (ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update);
  723. }
  724. }
  725. GNUNET_array_grow (fc.tree_array, fc.tree_array_size, 0);
  726. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done processing TREEs\n");
  727. free_update_information_graph (uig);
  728. }
  729. /* end of fs_namespace.c */