fs_namespace.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301
  1. /*
  2. This file is part of GNUnet
  3. (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 create and destroy 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.h"
  28. #define DEBUG_NAMESPACE GNUNET_NO
  29. /**
  30. * Return the name of the directory in which we store
  31. * our local namespaces (or rather, their public keys).
  32. *
  33. * @param h global fs handle
  34. * @return NULL on error, otherwise the name of the directory
  35. */
  36. static char *
  37. get_namespace_directory (struct GNUNET_FS_Handle *h)
  38. {
  39. char *dn;
  40. if (GNUNET_OK !=
  41. GNUNET_CONFIGURATION_get_value_filename (h->cfg,
  42. "FS",
  43. "IDENTITY_DIR",
  44. &dn))
  45. {
  46. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  47. _("Configuration fails to specify `%s' in section `%s'\n"),
  48. "IDENTITY_DIR",
  49. "fs");
  50. return NULL;
  51. }
  52. return dn;
  53. }
  54. /**
  55. * Return the name of the directory in which we store
  56. * the update information graph for the given local namespace.
  57. *
  58. * @param ns namespace handle
  59. * @return NULL on error, otherwise the name of the directory
  60. */
  61. static char *
  62. get_update_information_directory (struct GNUNET_FS_Namespace *ns)
  63. {
  64. char *dn;
  65. char *ret;
  66. if (GNUNET_OK !=
  67. GNUNET_CONFIGURATION_get_value_filename (ns->h->cfg,
  68. "FS",
  69. "UPDATE_DIR",
  70. &dn))
  71. {
  72. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  73. _("Configuration fails to specify `%s' in section `%s'\n"),
  74. "UPDATE_DIR",
  75. "fs");
  76. return NULL;
  77. }
  78. GNUNET_asprintf (&ret,
  79. "%s%s%s",
  80. dn,
  81. DIR_SEPARATOR_STR,
  82. ns->name);
  83. GNUNET_free (dn);
  84. return ret;
  85. }
  86. /**
  87. * Write the namespace update node graph to a file.
  88. *
  89. * @param ns namespace to dump
  90. */
  91. static void
  92. write_update_information_graph (struct GNUNET_FS_Namespace *ns)
  93. {
  94. char * fn;
  95. struct GNUNET_BIO_WriteHandle *wh;
  96. unsigned int i;
  97. struct NamespaceUpdateNode *n;
  98. char *uris;
  99. fn = get_update_information_directory (ns);
  100. wh = GNUNET_BIO_write_open (fn);
  101. if (wh == NULL)
  102. {
  103. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  104. _("Failed to open `%s' for writing: %s\n"),
  105. STRERROR (errno));
  106. GNUNET_free (fn);
  107. return;
  108. }
  109. if (GNUNET_OK !=
  110. GNUNET_BIO_write_int32 (wh, ns->update_node_count))
  111. goto END;
  112. for (i=0;i<ns->update_node_count;i++)
  113. {
  114. n = ns->update_nodes[i];
  115. uris = GNUNET_FS_uri_to_string (n->uri);
  116. if ( (GNUNET_OK !=
  117. GNUNET_BIO_write_string (wh, n->id)) ||
  118. (GNUNET_OK !=
  119. GNUNET_BIO_write_meta_data (wh, n->md)) ||
  120. (GNUNET_OK !=
  121. GNUNET_BIO_write_string (wh, n->update)) ||
  122. (GNUNET_OK !=
  123. GNUNET_BIO_write_string (wh, uris)) )
  124. {
  125. GNUNET_free (uris);
  126. break;
  127. }
  128. GNUNET_free (uris);
  129. }
  130. END:
  131. if (GNUNET_OK != GNUNET_BIO_write_close (wh))
  132. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  133. _("Failed to write `%s': %s\n"),
  134. STRERROR (errno));
  135. GNUNET_free (fn);
  136. }
  137. /**
  138. * Read the namespace update node graph from a file.
  139. *
  140. * @param ns namespace to read
  141. */
  142. static void
  143. read_update_information_graph (struct GNUNET_FS_Namespace *ns)
  144. {
  145. char * fn;
  146. struct GNUNET_BIO_ReadHandle *rh;
  147. unsigned int i;
  148. struct NamespaceUpdateNode *n;
  149. char *uris;
  150. uint32_t count;
  151. char *emsg;
  152. fn = get_update_information_directory (ns);
  153. if (GNUNET_YES !=
  154. GNUNET_DISK_file_test (fn))
  155. {
  156. GNUNET_free (fn);
  157. return;
  158. }
  159. rh = GNUNET_BIO_read_open (fn);
  160. if (rh == NULL)
  161. {
  162. GNUNET_free (fn);
  163. return;
  164. }
  165. if (GNUNET_OK !=
  166. GNUNET_BIO_read_int32 (rh, &count))
  167. {
  168. GNUNET_break (0);
  169. goto END;
  170. }
  171. if (count > 1024 * 1024)
  172. {
  173. GNUNET_break (0);
  174. goto END;
  175. }
  176. if (count == 0)
  177. {
  178. GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL));
  179. GNUNET_free (fn);
  180. return;
  181. }
  182. ns->update_nodes = GNUNET_malloc (count * sizeof (struct NamespaceUpdateNode*));
  183. for (i=0;i<count;i++)
  184. {
  185. n = GNUNET_malloc (sizeof (struct NamespaceUpdateNode));
  186. if ( (GNUNET_OK !=
  187. GNUNET_BIO_read_string (rh, "identifier", &n->id, 1024)) ||
  188. (GNUNET_OK !=
  189. GNUNET_BIO_read_meta_data (rh, "meta", &n->md)) ||
  190. (GNUNET_OK !=
  191. GNUNET_BIO_read_string (rh, "update-id", &n->update, 1024)) ||
  192. (GNUNET_OK !=
  193. GNUNET_BIO_read_string (rh, "uri", &uris, 1024 * 2)) )
  194. {
  195. GNUNET_break (0);
  196. GNUNET_free_non_null (n->id);
  197. GNUNET_free_non_null (n->update);
  198. if (n->md != NULL)
  199. GNUNET_CONTAINER_meta_data_destroy (n->md);
  200. GNUNET_free (n);
  201. break;
  202. }
  203. n->uri = GNUNET_FS_uri_parse (uris, &emsg);
  204. GNUNET_free (uris);
  205. if (n->uri == NULL)
  206. {
  207. GNUNET_break (0);
  208. GNUNET_free (emsg);
  209. GNUNET_free (n->id);
  210. GNUNET_free_non_null (n->update);
  211. GNUNET_CONTAINER_meta_data_destroy (n->md);
  212. GNUNET_free (n);
  213. break;
  214. }
  215. ns->update_nodes[i] = n;
  216. }
  217. ns->update_node_count = i;
  218. END:
  219. if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
  220. {
  221. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  222. _("Failed to write `%s': %s\n"),
  223. emsg);
  224. GNUNET_free (emsg);
  225. }
  226. GNUNET_free (fn);
  227. }
  228. /**
  229. * Context for advertising a namespace.
  230. */
  231. struct AdvertisementContext
  232. {
  233. /**
  234. * Function to call with the result.
  235. */
  236. GNUNET_FS_PublishContinuation cont;
  237. /**
  238. * Closure for cont.
  239. */
  240. void *cont_cls;
  241. /**
  242. * Datastore handle.
  243. */
  244. struct GNUNET_DATASTORE_Handle *dsh;
  245. /**
  246. * Our KSK URI.
  247. */
  248. struct GNUNET_FS_Uri *ksk_uri;
  249. /**
  250. * Plaintext.
  251. */
  252. char *pt;
  253. /**
  254. * NBlock to sign and store.
  255. */
  256. struct NBlock *nb;
  257. /**
  258. * The namespace.
  259. */
  260. struct GNUNET_FS_Namespace *ns;
  261. /**
  262. * Block options.
  263. */
  264. struct GNUNET_FS_BlockOptions bo;
  265. /**
  266. * Number of bytes of plaintext.
  267. */
  268. size_t pt_size;
  269. /**
  270. * Current keyword offset.
  271. */
  272. unsigned int pos;
  273. };
  274. /**
  275. * Disconnect from the datastore.
  276. *
  277. * @param cls datastore handle
  278. * @param tc scheduler context
  279. */
  280. static void
  281. do_disconnect (void *cls,
  282. const struct GNUNET_SCHEDULER_TaskContext *tc)
  283. {
  284. struct GNUNET_DATASTORE_Handle *dsh = cls;
  285. GNUNET_DATASTORE_disconnect (dsh,
  286. GNUNET_NO);
  287. }
  288. /**
  289. * Continuation called to notify client about result of the
  290. * operation.
  291. *
  292. * @param cls closure (our struct AdvertismentContext)
  293. * @param success GNUNET_SYSERR on failure
  294. * @param msg NULL on success, otherwise an error message
  295. */
  296. static void
  297. advertisement_cont (void *cls,
  298. int success,
  299. const char *msg)
  300. {
  301. struct AdvertisementContext *ac = cls;
  302. const char *keyword;
  303. GNUNET_HashCode key;
  304. GNUNET_HashCode query;
  305. struct GNUNET_CRYPTO_AesSessionKey skey;
  306. struct GNUNET_CRYPTO_AesInitializationVector iv;
  307. struct GNUNET_CRYPTO_RsaPrivateKey *pk;
  308. if (GNUNET_OK != success)
  309. {
  310. /* error! */
  311. GNUNET_SCHEDULER_add_continuation (&do_disconnect,
  312. ac->dsh,
  313. GNUNET_SCHEDULER_REASON_PREREQ_DONE);
  314. if (ac->cont != NULL)
  315. ac->cont (ac->cont_cls, NULL, msg);
  316. GNUNET_FS_uri_destroy (ac->ksk_uri);
  317. GNUNET_free (ac->pt);
  318. GNUNET_free (ac->nb);
  319. GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO);
  320. GNUNET_free (ac);
  321. return;
  322. }
  323. if (ac->pos == ac->ksk_uri->data.ksk.keywordCount)
  324. {
  325. /* done! */
  326. GNUNET_SCHEDULER_add_continuation (&do_disconnect,
  327. ac->dsh,
  328. GNUNET_SCHEDULER_REASON_PREREQ_DONE);
  329. if (ac->cont != NULL)
  330. ac->cont (ac->cont_cls, ac->ksk_uri, NULL);
  331. GNUNET_FS_uri_destroy (ac->ksk_uri);
  332. GNUNET_free (ac->pt);
  333. GNUNET_free (ac->nb);
  334. GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO);
  335. GNUNET_free (ac);
  336. return;
  337. }
  338. keyword = ac->ksk_uri->data.ksk.keywords[ac->pos++];
  339. /* first character of keyword indicates if it is
  340. mandatory or not -- ignore for hashing */
  341. GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key);
  342. GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv);
  343. GNUNET_CRYPTO_aes_encrypt (ac->pt,
  344. ac->pt_size,
  345. &skey,
  346. &iv,
  347. &ac->nb[1]);
  348. GNUNET_break (GNUNET_OK ==
  349. GNUNET_CRYPTO_rsa_sign (ac->ns->key,
  350. &ac->nb->ns_purpose,
  351. &ac->nb->ns_signature));
  352. pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key);
  353. GNUNET_assert (pk != NULL);
  354. GNUNET_CRYPTO_rsa_key_get_public (pk, &ac->nb->keyspace);
  355. GNUNET_CRYPTO_hash (&ac->nb->keyspace,
  356. sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
  357. &query);
  358. GNUNET_break (GNUNET_OK ==
  359. GNUNET_CRYPTO_rsa_sign (pk,
  360. &ac->nb->ksk_purpose,
  361. &ac->nb->ksk_signature));
  362. GNUNET_CRYPTO_rsa_key_free (pk);
  363. GNUNET_DATASTORE_put (ac->dsh,
  364. 0 /* no reservation */,
  365. &query,
  366. ac->pt_size + sizeof (struct NBlock),
  367. ac->nb,
  368. GNUNET_BLOCK_TYPE_FS_NBLOCK,
  369. ac->bo.content_priority,
  370. ac->bo.anonymity_level,
  371. ac->bo.replication_level,
  372. ac->bo.expiration_time,
  373. -2, 1,
  374. GNUNET_CONSTANTS_SERVICE_TIMEOUT,
  375. &advertisement_cont,
  376. ac);
  377. }
  378. /**
  379. * Publish an advertismement for a namespace.
  380. *
  381. * @param h handle to the file sharing subsystem
  382. * @param ksk_uri keywords to use for advertisment
  383. * @param namespace handle for the namespace that should be advertised
  384. * @param meta meta-data for the namespace advertisement
  385. * @param bo block options
  386. * @param rootEntry name of the root of the namespace
  387. * @param cont continuation
  388. * @param cont_cls closure for cont
  389. */
  390. void
  391. GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h,
  392. struct GNUNET_FS_Uri *ksk_uri,
  393. struct GNUNET_FS_Namespace *namespace,
  394. const struct GNUNET_CONTAINER_MetaData *meta,
  395. const struct GNUNET_FS_BlockOptions *bo,
  396. const char *rootEntry,
  397. GNUNET_FS_PublishContinuation cont,
  398. void *cont_cls)
  399. {
  400. size_t reslen;
  401. size_t size;
  402. ssize_t mdsize;
  403. struct NBlock *nb;
  404. char *mdst;
  405. struct GNUNET_DATASTORE_Handle *dsh;
  406. struct AdvertisementContext *ctx;
  407. char *pt;
  408. /* create advertisements */
  409. mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta);
  410. if (-1 == mdsize)
  411. {
  412. cont (cont_cls, NULL, _("Failed to serialize meta data"));
  413. return;
  414. }
  415. reslen = strlen (rootEntry) + 1;
  416. size = mdsize + sizeof (struct NBlock) + reslen;
  417. if (size > MAX_NBLOCK_SIZE)
  418. {
  419. size = MAX_NBLOCK_SIZE;
  420. mdsize = size - sizeof (struct NBlock) - reslen;
  421. }
  422. pt = GNUNET_malloc (mdsize + reslen);
  423. memcpy (pt, rootEntry, reslen);
  424. mdst = &pt[reslen];
  425. mdsize = GNUNET_CONTAINER_meta_data_serialize (meta,
  426. &mdst,
  427. mdsize,
  428. GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
  429. if (mdsize == -1)
  430. {
  431. GNUNET_break (0);
  432. GNUNET_free (pt);
  433. cont (cont_cls, NULL, _("Failed to serialize meta data"));
  434. return;
  435. }
  436. size = mdsize + sizeof (struct NBlock) + reslen;
  437. nb = GNUNET_malloc (size);
  438. GNUNET_CRYPTO_rsa_key_get_public (namespace->key,
  439. &nb->subspace);
  440. nb->ns_purpose.size = htonl (mdsize + reslen +
  441. sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
  442. sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
  443. nb->ns_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK);
  444. nb->ksk_purpose.size = htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature));
  445. nb->ksk_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG);
  446. dsh = GNUNET_DATASTORE_connect (h->cfg);
  447. if (NULL == dsh)
  448. {
  449. GNUNET_free (nb);
  450. GNUNET_free (pt);
  451. cont (cont_cls, NULL, _("Failed to connect to datastore service"));
  452. return;
  453. }
  454. ctx = GNUNET_malloc (sizeof (struct AdvertisementContext));
  455. ctx->cont = cont;
  456. ctx->cont_cls = cont_cls;
  457. ctx->dsh = dsh;
  458. ctx->ksk_uri = GNUNET_FS_uri_dup (ksk_uri);
  459. ctx->nb = nb;
  460. ctx->pt = pt;
  461. ctx->pt_size = mdsize + reslen;
  462. ctx->ns = namespace;
  463. ctx->ns->rc++;
  464. ctx->bo = *bo;
  465. advertisement_cont (ctx, GNUNET_OK, NULL);
  466. }
  467. /**
  468. * Create a namespace with the given name; if one already
  469. * exists, return a handle to the existing namespace.
  470. *
  471. * @param h handle to the file sharing subsystem
  472. * @param name name to use for the namespace
  473. * @return handle to the namespace, NULL on error
  474. */
  475. struct GNUNET_FS_Namespace *
  476. GNUNET_FS_namespace_create (struct GNUNET_FS_Handle *h,
  477. const char *name)
  478. {
  479. char *dn;
  480. char *fn;
  481. struct GNUNET_FS_Namespace *ret;
  482. dn = get_namespace_directory (h);
  483. GNUNET_asprintf (&fn,
  484. "%s%s%s",
  485. dn,
  486. DIR_SEPARATOR_STR,
  487. name);
  488. GNUNET_free (dn);
  489. ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Namespace));
  490. ret->h = h;
  491. ret->rc = 1;
  492. ret->key = GNUNET_CRYPTO_rsa_key_create_from_file (fn);
  493. if (ret->key == NULL)
  494. {
  495. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  496. _("Failed to create or read private key for namespace `%s'\n"),
  497. name);
  498. GNUNET_free (ret);
  499. GNUNET_free (fn);
  500. return NULL;
  501. }
  502. ret->name = GNUNET_strdup (name);
  503. ret->filename = fn;
  504. return ret;
  505. }
  506. /**
  507. * Delete a namespace handle. Can be used for a clean shutdown (free
  508. * memory) or also to freeze the namespace to prevent further
  509. * insertions by anyone.
  510. *
  511. * @param namespace handle to the namespace that should be deleted / freed
  512. * @param freeze prevents future insertions; creating a namespace
  513. * with the same name again will create a fresh namespace instead
  514. *
  515. * @return GNUNET_OK on success, GNUNET_SYSERR on error
  516. */
  517. int
  518. GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *namespace,
  519. int freeze)
  520. {
  521. unsigned int i;
  522. struct NamespaceUpdateNode *nsn;
  523. namespace->rc--;
  524. if (freeze)
  525. {
  526. if (0 != UNLINK (namespace->filename))
  527. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
  528. "unlink",
  529. namespace->filename);
  530. }
  531. if (0 == namespace->rc)
  532. {
  533. GNUNET_CRYPTO_rsa_key_free (namespace->key);
  534. GNUNET_free (namespace->filename);
  535. GNUNET_free (namespace->name);
  536. for (i=0;i<namespace->update_node_count;i++)
  537. {
  538. nsn = namespace->update_nodes[i];
  539. GNUNET_CONTAINER_meta_data_destroy (nsn->md);
  540. GNUNET_FS_uri_destroy (nsn->uri);
  541. GNUNET_free (nsn->id);
  542. GNUNET_free (nsn->update);
  543. GNUNET_free (nsn);
  544. }
  545. GNUNET_array_grow (namespace->update_nodes,
  546. namespace->update_node_count,
  547. 0);
  548. if (namespace->update_map != NULL)
  549. GNUNET_CONTAINER_multihashmap_destroy (namespace->update_map);
  550. GNUNET_free (namespace);
  551. }
  552. return GNUNET_OK;
  553. }
  554. /**
  555. * Context for the 'process_namespace' callback.
  556. * Specifies a function to call on each namespace.
  557. */
  558. struct ProcessNamespaceContext
  559. {
  560. /**
  561. * Function to call.
  562. */
  563. GNUNET_FS_NamespaceInfoProcessor cb;
  564. /**
  565. * Closure for 'cb'.
  566. */
  567. void *cb_cls;
  568. };
  569. /**
  570. * Function called with a filename of a namespace. Reads the key and
  571. * calls the callback.
  572. *
  573. * @param cls closure (struct ProcessNamespaceContext)
  574. * @param filename complete filename (absolute path)
  575. * @return GNUNET_OK to continue to iterate,
  576. * GNUNET_SYSERR to abort iteration with error!
  577. */
  578. static int
  579. process_namespace (void *cls,
  580. const char *filename)
  581. {
  582. struct ProcessNamespaceContext *pnc = cls;
  583. struct GNUNET_CRYPTO_RsaPrivateKey *key;
  584. struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
  585. GNUNET_HashCode id;
  586. const char *name;
  587. const char *t;
  588. key = GNUNET_CRYPTO_rsa_key_create_from_file (filename);
  589. if (key == NULL)
  590. {
  591. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  592. _("Failed to read namespace private key file `%s', deleting it!\n"),
  593. filename);
  594. if (0 != UNLINK (filename))
  595. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  596. "unlink",
  597. filename);
  598. return GNUNET_OK;
  599. }
  600. GNUNET_CRYPTO_rsa_key_get_public (key, &pk);
  601. GNUNET_CRYPTO_rsa_key_free (key);
  602. GNUNET_CRYPTO_hash (&pk, sizeof(pk), &id);
  603. name = filename;
  604. while (NULL != (t = strstr (name, DIR_SEPARATOR_STR)))
  605. name = t + 1;
  606. pnc->cb (pnc->cb_cls,
  607. name,
  608. &id);
  609. return GNUNET_OK;
  610. }
  611. /**
  612. * Build a list of all available local (!) namespaces The returned
  613. * names are only the nicknames since we only iterate over the local
  614. * namespaces.
  615. *
  616. * @param h handle to the file sharing subsystem
  617. * @param cb function to call on each known namespace
  618. * @param cb_cls closure for cb
  619. */
  620. void
  621. GNUNET_FS_namespace_list (struct GNUNET_FS_Handle *h,
  622. GNUNET_FS_NamespaceInfoProcessor cb,
  623. void *cb_cls)
  624. {
  625. char *dn;
  626. struct ProcessNamespaceContext ctx;
  627. dn = get_namespace_directory (h);
  628. if (dn == NULL)
  629. return;
  630. ctx.cb = cb;
  631. ctx.cb_cls = cb_cls;
  632. GNUNET_DISK_directory_scan (dn,
  633. &process_namespace,
  634. &ctx);
  635. GNUNET_free (dn);
  636. }
  637. /**
  638. * Context for the SKS publication.
  639. */
  640. struct PublishSksContext
  641. {
  642. /**
  643. * URI of the new entry in the namespace.
  644. */
  645. struct GNUNET_FS_Uri *uri;
  646. /**
  647. * Namespace update node to add to namespace on success (or to be
  648. * deleted if publishing failed).
  649. */
  650. struct NamespaceUpdateNode *nsn;
  651. /**
  652. * Namespace we're publishing to.
  653. */
  654. struct GNUNET_FS_Namespace *namespace;
  655. /**
  656. * Handle to the datastore.
  657. */
  658. struct GNUNET_DATASTORE_Handle *dsh;
  659. /**
  660. * Function to call once we're done.
  661. */
  662. GNUNET_FS_PublishContinuation cont;
  663. /**
  664. * Closure for cont.
  665. */
  666. void *cont_cls;
  667. };
  668. /**
  669. * Function called by the datastore API with
  670. * the result from the PUT (SBlock) request.
  671. *
  672. * @param cls closure of type "struct PublishSksContext*"
  673. * @param success GNUNET_OK on success
  674. * @param msg error message (or NULL)
  675. */
  676. static void
  677. sb_put_cont (void *cls,
  678. int success,
  679. const char *msg)
  680. {
  681. struct PublishSksContext *psc = cls;
  682. GNUNET_HashCode hc;
  683. if (NULL != psc->dsh)
  684. {
  685. GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO);
  686. psc->dsh = NULL;
  687. }
  688. if (GNUNET_OK != success)
  689. {
  690. if (psc->cont != NULL)
  691. psc->cont (psc->cont_cls,
  692. NULL,
  693. msg);
  694. }
  695. else
  696. {
  697. if (psc->nsn != NULL)
  698. {
  699. /* FIXME: this can be done much more
  700. efficiently by simply appending to the
  701. file and overwriting the 4-byte header */
  702. if (psc->namespace->update_nodes == NULL)
  703. read_update_information_graph (psc->namespace);
  704. GNUNET_array_append (psc->namespace->update_nodes,
  705. psc->namespace->update_node_count,
  706. psc->nsn);
  707. if (psc->namespace->update_map != NULL)
  708. {
  709. GNUNET_CRYPTO_hash (psc->nsn->id,
  710. strlen (psc->nsn->id),
  711. &hc);
  712. GNUNET_CONTAINER_multihashmap_put (psc->namespace->update_map,
  713. &hc,
  714. psc->nsn,
  715. GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  716. }
  717. psc->nsn = NULL;
  718. write_update_information_graph (psc->namespace);
  719. }
  720. if (psc->cont != NULL)
  721. psc->cont (psc->cont_cls,
  722. psc->uri,
  723. NULL);
  724. }
  725. GNUNET_FS_namespace_delete (psc->namespace,
  726. GNUNET_NO);
  727. GNUNET_FS_uri_destroy (psc->uri);
  728. if (psc->nsn != NULL)
  729. {
  730. GNUNET_CONTAINER_meta_data_destroy (psc->nsn->md);
  731. GNUNET_FS_uri_destroy (psc->nsn->uri);
  732. GNUNET_free (psc->nsn->id);
  733. GNUNET_free (psc->nsn->update);
  734. GNUNET_free (psc->nsn);
  735. }
  736. GNUNET_free (psc);
  737. }
  738. /**
  739. * Publish an SBlock on GNUnet.
  740. *
  741. * @param h handle to the file sharing subsystem
  742. * @param namespace namespace to publish in
  743. * @param identifier identifier to use
  744. * @param update update identifier to use
  745. * @param meta metadata to use
  746. * @param uri URI to refer to in the SBlock
  747. * @param bo block options
  748. * @param options publication options
  749. * @param cont continuation
  750. * @param cont_cls closure for cont
  751. */
  752. void
  753. GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h,
  754. struct GNUNET_FS_Namespace *namespace,
  755. const char *identifier,
  756. const char *update,
  757. const struct GNUNET_CONTAINER_MetaData *meta,
  758. const struct GNUNET_FS_Uri *uri,
  759. const struct GNUNET_FS_BlockOptions *bo,
  760. enum GNUNET_FS_PublishOptions options,
  761. GNUNET_FS_PublishContinuation cont,
  762. void *cont_cls)
  763. {
  764. struct PublishSksContext *psc;
  765. struct GNUNET_CRYPTO_AesSessionKey sk;
  766. struct GNUNET_CRYPTO_AesInitializationVector iv;
  767. struct GNUNET_FS_Uri *sks_uri;
  768. char *uris;
  769. size_t size;
  770. size_t slen;
  771. size_t nidlen;
  772. size_t idlen;
  773. ssize_t mdsize;
  774. struct SBlock *sb;
  775. struct SBlock *sb_enc;
  776. char *dest;
  777. struct GNUNET_CONTAINER_MetaData *mmeta;
  778. GNUNET_HashCode key; /* hash of thisId = key */
  779. GNUNET_HashCode id; /* hash of hc = identifier */
  780. GNUNET_HashCode query; /* id ^ nsid = DB query */
  781. if (NULL == meta)
  782. mmeta = GNUNET_CONTAINER_meta_data_create ();
  783. else
  784. mmeta = GNUNET_CONTAINER_meta_data_duplicate (meta);
  785. uris = GNUNET_FS_uri_to_string (uri);
  786. slen = strlen (uris) + 1;
  787. idlen = strlen (identifier);
  788. if (update != NULL)
  789. nidlen = strlen (update) + 1;
  790. else
  791. nidlen = 1;
  792. mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (mmeta);
  793. size = sizeof (struct SBlock) + slen + nidlen + mdsize;
  794. if (size > MAX_SBLOCK_SIZE)
  795. {
  796. size = MAX_SBLOCK_SIZE;
  797. mdsize = size - (sizeof (struct SBlock) + slen + nidlen);
  798. }
  799. sb = GNUNET_malloc (sizeof (struct SBlock) + size);
  800. dest = (char *) &sb[1];
  801. if (update != NULL)
  802. memcpy (dest, update, nidlen);
  803. else
  804. memset (dest, 0, 1);
  805. dest += nidlen;
  806. memcpy (dest, uris, slen);
  807. GNUNET_free (uris);
  808. dest += slen;
  809. mdsize = GNUNET_CONTAINER_meta_data_serialize (mmeta,
  810. &dest,
  811. mdsize,
  812. GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
  813. GNUNET_CONTAINER_meta_data_destroy (mmeta);
  814. if (mdsize == -1)
  815. {
  816. GNUNET_break (0);
  817. GNUNET_free (sb);
  818. cont (cont_cls,
  819. NULL,
  820. _("Internal error."));
  821. return;
  822. }
  823. size = sizeof (struct SBlock) + mdsize + slen + nidlen;
  824. sb_enc = GNUNET_malloc (size);
  825. GNUNET_CRYPTO_hash (identifier, idlen, &key);
  826. GNUNET_CRYPTO_hash (&key, sizeof (GNUNET_HashCode), &id);
  827. sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
  828. sks_uri->type = sks;
  829. GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &sb_enc->subspace);
  830. GNUNET_CRYPTO_hash (&sb_enc->subspace,
  831. sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
  832. &sks_uri->data.sks.namespace);
  833. sks_uri->data.sks.identifier = GNUNET_strdup (identifier);
  834. GNUNET_CRYPTO_hash_xor (&id,
  835. &sks_uri->data.sks.namespace,
  836. &sb_enc->identifier);
  837. GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv);
  838. GNUNET_CRYPTO_aes_encrypt (&sb[1],
  839. size - sizeof (struct SBlock),
  840. &sk,
  841. &iv,
  842. &sb_enc[1]);
  843. sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK);
  844. sb_enc->purpose.size = htonl(slen + mdsize + nidlen
  845. + sizeof(struct SBlock)
  846. - sizeof(struct GNUNET_CRYPTO_RsaSignature));
  847. GNUNET_assert (GNUNET_OK ==
  848. GNUNET_CRYPTO_rsa_sign (namespace->key,
  849. &sb_enc->purpose,
  850. &sb_enc->signature));
  851. psc = GNUNET_malloc (sizeof(struct PublishSksContext));
  852. psc->uri = sks_uri;
  853. psc->cont = cont;
  854. psc->namespace = namespace;
  855. namespace->rc++;
  856. psc->cont_cls = cont_cls;
  857. if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
  858. {
  859. GNUNET_free (sb_enc);
  860. GNUNET_free (sb);
  861. sb_put_cont (psc,
  862. GNUNET_OK,
  863. NULL);
  864. return;
  865. }
  866. psc->dsh = GNUNET_DATASTORE_connect (h->cfg);
  867. if (NULL == psc->dsh)
  868. {
  869. GNUNET_free (sb_enc);
  870. GNUNET_free (sb);
  871. sb_put_cont (psc,
  872. GNUNET_NO,
  873. _("Failed to connect to datastore."));
  874. return;
  875. }
  876. GNUNET_CRYPTO_hash_xor (&sks_uri->data.sks.namespace,
  877. &id,
  878. &query);
  879. if (NULL != update)
  880. {
  881. psc->nsn = GNUNET_malloc (sizeof (struct NamespaceUpdateNode));
  882. psc->nsn->id = GNUNET_strdup (identifier);
  883. psc->nsn->update = GNUNET_strdup (update);
  884. psc->nsn->md = GNUNET_CONTAINER_meta_data_duplicate (meta);
  885. psc->nsn->uri = GNUNET_FS_uri_dup (uri);
  886. }
  887. GNUNET_DATASTORE_put (psc->dsh,
  888. 0,
  889. &sb_enc->identifier,
  890. size,
  891. sb_enc,
  892. GNUNET_BLOCK_TYPE_FS_SBLOCK,
  893. bo->content_priority,
  894. bo->anonymity_level,
  895. bo->replication_level,
  896. bo->expiration_time,
  897. -2, 1,
  898. GNUNET_CONSTANTS_SERVICE_TIMEOUT,
  899. &sb_put_cont,
  900. psc);
  901. GNUNET_free (sb);
  902. GNUNET_free (sb_enc);
  903. }
  904. /**
  905. * Closure for 'process_update_node'.
  906. */
  907. struct ProcessUpdateClosure
  908. {
  909. /**
  910. * Function to call for each node.
  911. */
  912. GNUNET_FS_IdentifierProcessor ip;
  913. /**
  914. * Closure for 'ip'.
  915. */
  916. void *ip_cls;
  917. };
  918. /**
  919. * Call the iterator in the closure for each node.
  920. *
  921. * @param cls closure (of type 'struct ProcessUpdateClosure *')
  922. * @param key current key code
  923. * @param value value in the hash map (of type 'struct NamespaceUpdateNode *')
  924. * @return GNUNET_YES if we should continue to
  925. * iterate,
  926. * GNUNET_NO if not.
  927. */
  928. static int
  929. process_update_node (void *cls,
  930. const GNUNET_HashCode * key,
  931. void *value)
  932. {
  933. struct ProcessUpdateClosure *pc = cls;
  934. struct NamespaceUpdateNode *nsn = value;
  935. pc->ip (pc->ip_cls,
  936. nsn->id,
  937. nsn->uri,
  938. nsn->md,
  939. nsn->update);
  940. return GNUNET_YES;
  941. }
  942. /**
  943. * Closure for 'find_trees'.
  944. */
  945. struct FindTreeClosure
  946. {
  947. /**
  948. * Namespace we are operating on.
  949. */
  950. struct GNUNET_FS_Namespace *namespace;
  951. /**
  952. * Array with 'head's of TREEs.
  953. */
  954. struct NamespaceUpdateNode **tree_array;
  955. /**
  956. * Size of 'tree_array'
  957. */
  958. unsigned int tree_array_size;
  959. /**
  960. * Current generational ID used.
  961. */
  962. unsigned int nug;
  963. /**
  964. * Identifier for the current TREE, or UINT_MAX for none yet.
  965. */
  966. unsigned int id;
  967. };
  968. /**
  969. * Find all nodes reachable from the current node (including the
  970. * current node itself). If they are in no tree, add them to the
  971. * current one. If they are the head of another tree, merge the
  972. * trees. If they are in the middle of another tree, let them be.
  973. * We can tell that a node is already in an tree by checking if
  974. * its 'nug' field is set to the current 'nug' value. It is the
  975. * head of an tree if it is in the 'tree_array' under its respective
  976. * 'tree_id'.
  977. *
  978. * In short, we're trying to find the smallest number of tree to
  979. * cover a directed graph.
  980. *
  981. * @param cls closure (of type 'struct FindTreeClosure')
  982. * @param key current key code
  983. * @param value value in the hash map
  984. * @return GNUNET_YES if we should continue to
  985. * iterate,
  986. * GNUNET_NO if not.
  987. */
  988. static int
  989. find_trees (void *cls,
  990. const GNUNET_HashCode * key,
  991. void *value)
  992. {
  993. struct FindTreeClosure *fc = cls;
  994. struct NamespaceUpdateNode *nsn = value;
  995. GNUNET_HashCode hc;
  996. if (nsn->nug == fc->nug)
  997. {
  998. if (nsn->tree_id == UINT_MAX)
  999. return GNUNET_YES; /* circular */
  1000. GNUNET_assert (nsn->tree_id < fc->tree_array_size);
  1001. if (fc->tree_array[nsn->tree_id] != nsn)
  1002. return GNUNET_YES; /* part of "another" (directed) TREE,
  1003. and not root of it, end trace */
  1004. if (nsn->tree_id == fc->id)
  1005. return GNUNET_YES; /* that's our own root (can this be?) */
  1006. /* merge existing TREE, we have a root for both */
  1007. fc->tree_array[nsn->tree_id] = NULL;
  1008. if (fc->id == UINT_MAX)
  1009. fc->id = nsn->tree_id; /* take over ID */
  1010. }
  1011. else
  1012. {
  1013. nsn->nug = fc->nug;
  1014. nsn->tree_id = UINT_MAX; /* mark as undef */
  1015. /* trace */
  1016. GNUNET_CRYPTO_hash (nsn->update,
  1017. strlen (nsn->update),
  1018. &hc);
  1019. GNUNET_CONTAINER_multihashmap_get_multiple (fc->namespace->update_map,
  1020. &hc,
  1021. &find_trees,
  1022. fc);
  1023. }
  1024. return GNUNET_YES;
  1025. }
  1026. /**
  1027. * List all of the identifiers in the namespace for which we could
  1028. * produce an update. Namespace updates form a graph where each node
  1029. * has a name. Each node can have any number of URI/meta-data entries
  1030. * which can each be linked to other nodes. Cycles are possible.
  1031. *
  1032. * Calling this function with "next_id" NULL will cause the library to
  1033. * call "ip" with a root for each strongly connected component of the
  1034. * graph (a root being a node from which all other nodes in the Tree
  1035. * are reachable).
  1036. *
  1037. * Calling this function with "next_id" being the name of a node will
  1038. * cause the library to call "ip" with all children of the node. Note
  1039. * that cycles within the final tree are possible (including self-loops).
  1040. * I know, odd definition of a tree, but the GUI will display an actual
  1041. * tree (GtkTreeView), so that's what counts for the term here.
  1042. *
  1043. * @param namespace namespace to inspect for updateable content
  1044. * @param next_id ID to look for; use NULL to look for tree roots
  1045. * @param ip function to call on each updateable identifier
  1046. * @param ip_cls closure for ip
  1047. */
  1048. void
  1049. GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *namespace,
  1050. const char *next_id,
  1051. GNUNET_FS_IdentifierProcessor ip,
  1052. void *ip_cls)
  1053. {
  1054. unsigned int i;
  1055. unsigned int nug;
  1056. GNUNET_HashCode hc;
  1057. struct NamespaceUpdateNode *nsn;
  1058. struct ProcessUpdateClosure pc;
  1059. struct FindTreeClosure fc;
  1060. if (namespace->update_nodes == NULL)
  1061. read_update_information_graph (namespace);
  1062. if (namespace->update_nodes == NULL)
  1063. {
  1064. #if DEBUG_NAMESPACE
  1065. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1066. "No updateable nodes found for ID `%s'\n",
  1067. next_id);
  1068. #endif
  1069. return; /* no nodes */
  1070. }
  1071. if (namespace->update_map == NULL)
  1072. {
  1073. /* need to construct */
  1074. namespace->update_map = GNUNET_CONTAINER_multihashmap_create (2 + 3 * namespace->update_node_count / 4);
  1075. for (i=0;i<namespace->update_node_count;i++)
  1076. {
  1077. nsn = namespace->update_nodes[i];
  1078. GNUNET_CRYPTO_hash (nsn->id,
  1079. strlen (nsn->id),
  1080. &hc);
  1081. GNUNET_CONTAINER_multihashmap_put (namespace->update_map,
  1082. &hc,
  1083. nsn,
  1084. GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  1085. }
  1086. }
  1087. if (next_id != NULL)
  1088. {
  1089. GNUNET_CRYPTO_hash (next_id,
  1090. strlen (next_id),
  1091. &hc);
  1092. pc.ip = ip;
  1093. pc.ip_cls = ip_cls;
  1094. GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map,
  1095. &hc,
  1096. &process_update_node,
  1097. &pc);
  1098. return;
  1099. }
  1100. #if DEBUG_NAMESPACE
  1101. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1102. "Calculating TREEs to find roots of update trees\n");
  1103. #endif
  1104. /* Find heads of TREEs in update graph */
  1105. nug = ++namespace->nug_gen;
  1106. fc.tree_array = NULL;
  1107. fc.tree_array_size = 0;
  1108. for (i=0;i<namespace->update_node_count;i++)
  1109. {
  1110. nsn = namespace->update_nodes[i];
  1111. if (nsn->nug == nug)
  1112. {
  1113. #if DEBUG_NAMESPACE
  1114. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1115. "TREE of node `%s' is %u\n",
  1116. nsn->id,
  1117. nsn->nug);
  1118. #endif
  1119. continue; /* already placed in TREE */
  1120. }
  1121. GNUNET_CRYPTO_hash (nsn->update,
  1122. strlen (nsn->update),
  1123. &hc);
  1124. nsn->nug = nug;
  1125. fc.id = UINT_MAX;
  1126. fc.nug = nug;
  1127. fc.namespace = namespace;
  1128. GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map,
  1129. &hc,
  1130. &find_trees,
  1131. &fc);
  1132. if (fc.id == UINT_MAX)
  1133. {
  1134. /* start new TREE */
  1135. for (fc.id=0;fc.id<fc.tree_array_size;fc.id++)
  1136. {
  1137. if (fc.tree_array[fc.id] == NULL)
  1138. {
  1139. fc.tree_array[fc.id] = nsn;
  1140. nsn->tree_id = fc.id;
  1141. break;
  1142. }
  1143. }
  1144. if (fc.id == fc.tree_array_size)
  1145. {
  1146. GNUNET_array_append (fc.tree_array,
  1147. fc.tree_array_size,
  1148. nsn);
  1149. nsn->tree_id = fc.id;
  1150. }
  1151. #if DEBUG_NAMESPACE
  1152. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1153. "Starting new TREE %u with node `%s'\n",
  1154. nsn->tree_id,
  1155. nsn->id);
  1156. #endif
  1157. /* put all nodes with same identifier into this TREE */
  1158. GNUNET_CRYPTO_hash (nsn->id,
  1159. strlen (nsn->id),
  1160. &hc);
  1161. fc.id = nsn->tree_id;
  1162. fc.nug = nug;
  1163. fc.namespace = namespace;
  1164. GNUNET_CONTAINER_multihashmap_get_multiple (namespace->update_map,
  1165. &hc,
  1166. &find_trees,
  1167. &fc);
  1168. }
  1169. else
  1170. {
  1171. /* make head of TREE "id" */
  1172. fc.tree_array[fc.id] = nsn;
  1173. nsn->tree_id = fc.id;
  1174. }
  1175. #if DEBUG_NAMESPACE
  1176. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1177. "TREE of node `%s' is %u\n",
  1178. nsn->id,
  1179. fc.id);
  1180. #endif
  1181. }
  1182. for (i=0;i<fc.tree_array_size;i++)
  1183. {
  1184. nsn = fc.tree_array[i];
  1185. if (NULL != nsn)
  1186. {
  1187. #if DEBUG_NAMESPACE
  1188. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1189. "Root of TREE %u is node `%s'\n",
  1190. i,
  1191. nsn->id);
  1192. #endif
  1193. ip (ip_cls,
  1194. nsn->id,
  1195. nsn->uri,
  1196. nsn->md,
  1197. nsn->update);
  1198. }
  1199. }
  1200. GNUNET_array_grow (fc.tree_array,
  1201. fc.tree_array_size,
  1202. 0);
  1203. #if DEBUG_NAMESPACE
  1204. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1205. "Done processing TREEs\n");
  1206. #endif
  1207. }
  1208. /* end of fs_namespace.c */