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