fs_namespace.c 22 KB

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