-fixing #2578
[oweals/gnunet.git] / src / fs / fs_namespace.c
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
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file fs/fs_namespace.c
23  * @brief create and destroy namespaces
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_constants.h"
28 #include "gnunet_signatures.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_fs_service.h"
31 #include "fs_api.h"
32
33
34 /**
35  * Maximum legal size for an sblock.
36  */
37 #define MAX_SBLOCK_SIZE (60 * 1024)
38
39
40 /**
41  * Return the name of the directory in which we store
42  * our local namespaces (or rather, their public keys).
43  *
44  * @param h global fs handle
45  * @return NULL on error, otherwise the name of the directory
46  */
47 static char *
48 get_namespace_directory (struct GNUNET_FS_Handle *h)
49 {
50   char *dn;
51
52   if (GNUNET_OK !=
53       GNUNET_CONFIGURATION_get_value_filename (h->cfg, "FS", "IDENTITY_DIR",
54                                                &dn))
55   {
56     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
57                                "fs", "IDENTITY_DIR");
58     return NULL;
59   }
60   return dn;
61 }
62
63
64 /**
65  * Return the name of the directory in which we store
66  * the update information graph for the given local namespace.
67  *
68  * @param ns namespace handle
69  * @return NULL on error, otherwise the name of the directory
70  */
71 static char *
72 get_update_information_directory (struct GNUNET_FS_Namespace *ns)
73 {
74   char *dn;
75   char *ret;
76
77   if (GNUNET_OK !=
78       GNUNET_CONFIGURATION_get_value_filename (ns->h->cfg, "FS", "UPDATE_DIR",
79                                                &dn))
80   {
81     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
82                                "fs", "UPDATE_DIR");
83     return NULL;
84   }
85   GNUNET_asprintf (&ret, "%s%s%s", dn, DIR_SEPARATOR_STR, ns->name);
86   GNUNET_free (dn);
87   return ret;
88 }
89
90
91 /**
92  * Write the namespace update node graph to a file.
93  *
94  * @param ns namespace to dump
95  */
96 static void
97 write_update_information_graph (struct GNUNET_FS_Namespace *ns)
98 {
99   char *fn;
100   struct GNUNET_BIO_WriteHandle *wh;
101   unsigned int i;
102   struct NamespaceUpdateNode *n;
103   char *uris;
104
105   fn = get_update_information_directory (ns);
106   wh = GNUNET_BIO_write_open (fn);
107   if (NULL == wh)
108   {
109     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
110                 _("Failed to open `%s' for writing: %s\n"), STRERROR (errno));
111     GNUNET_free (fn);
112     return;
113   }
114   if (GNUNET_OK != GNUNET_BIO_write_int32 (wh, ns->update_node_count))
115     goto END;
116   for (i = 0; i < ns->update_node_count; i++)
117   {
118     n = ns->update_nodes[i];
119     uris = GNUNET_FS_uri_to_string (n->uri);
120     if ((GNUNET_OK != GNUNET_BIO_write_string (wh, n->id)) ||
121         (GNUNET_OK != GNUNET_BIO_write_meta_data (wh, n->md)) ||
122         (GNUNET_OK != GNUNET_BIO_write_string (wh, n->update)) ||
123         (GNUNET_OK != 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, _("Failed to write `%s': %s\n"),
133                 STRERROR (errno));
134   GNUNET_free (fn);
135 }
136
137
138 /**
139  * Read the namespace update node graph from a file.
140  *
141  * @param ns namespace to read
142  */
143 static void
144 read_update_information_graph (struct GNUNET_FS_Namespace *ns)
145 {
146   char *fn;
147   struct GNUNET_BIO_ReadHandle *rh;
148   unsigned int i;
149   struct NamespaceUpdateNode *n;
150   char *uris;
151   uint32_t count;
152   char *emsg;
153
154   fn = get_update_information_directory (ns);
155   if (GNUNET_YES != GNUNET_DISK_file_test (fn))
156   {
157     GNUNET_free (fn);
158     return;
159   }
160   rh = GNUNET_BIO_read_open (fn);
161   if (NULL == rh)
162   {
163     GNUNET_free (fn);
164     return;
165   }
166   if (GNUNET_OK != 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 (0 == count)
177   {
178     GNUNET_break (GNUNET_OK == GNUNET_BIO_read_close (rh, NULL));
179     GNUNET_free (fn);
180     return;
181   }
182   ns->update_nodes =
183       GNUNET_malloc (count * sizeof (struct NamespaceUpdateNode *));
184
185   for (i = 0; i < count; i++)
186   {
187     n = GNUNET_malloc (sizeof (struct NamespaceUpdateNode));
188     if ((GNUNET_OK != GNUNET_BIO_read_string (rh, "identifier", &n->id, 1024))
189         || (GNUNET_OK != 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 != GNUNET_BIO_read_string (rh, "uri", &uris, 1024 * 2)))
193     {
194       GNUNET_break (0);
195       GNUNET_free_non_null (n->id);
196       GNUNET_free_non_null (n->update);
197       if (n->md != NULL)
198         GNUNET_CONTAINER_meta_data_destroy (n->md);
199       GNUNET_free (n);
200       break;
201     }
202     n->uri = GNUNET_FS_uri_parse (uris, &emsg);
203     GNUNET_free (uris);
204     if (n->uri == NULL)
205     {
206       GNUNET_break (0);
207       GNUNET_free (emsg);
208       GNUNET_free (n->id);
209       GNUNET_free_non_null (n->update);
210       GNUNET_CONTAINER_meta_data_destroy (n->md);
211       GNUNET_free (n);
212       break;
213     }
214     ns->update_nodes[i] = n;
215   }
216   ns->update_node_count = i;
217 END:
218   if (GNUNET_OK != GNUNET_BIO_read_close (rh, &emsg))
219   {
220     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to write `%s': %s\n"), emsg);
221     GNUNET_free (emsg);
222   }
223   GNUNET_free (fn);
224 }
225
226
227 /**
228  * Create a namespace with the given name; if one already
229  * exists, return a handle to the existing namespace.
230  *
231  * @param h handle to the file sharing subsystem
232  * @param name name to use for the namespace
233  * @return handle to the namespace, NULL on error (i.e. invalid filename)
234  */
235 struct GNUNET_FS_Namespace *
236 GNUNET_FS_namespace_create (struct GNUNET_FS_Handle *h, const char *name)
237 {
238   char *dn;
239   char *fn;
240   struct GNUNET_FS_Namespace *ret;
241
242   dn = get_namespace_directory (h);
243   GNUNET_asprintf (&fn, "%s%s%s", dn, DIR_SEPARATOR_STR, name);
244   GNUNET_free (dn);
245   ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Namespace));
246   ret->h = h;
247   ret->rc = 1;
248   ret->key = GNUNET_CRYPTO_rsa_key_create_from_file (fn);
249   if (NULL == ret->key)
250   {
251     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
252                 _("Failed to create or read private key for namespace `%s'\n"),
253                 name);
254     GNUNET_free (ret);
255     GNUNET_free (fn);
256     return NULL;
257   }
258   ret->name = GNUNET_strdup (name);
259   ret->filename = fn;
260   return ret;
261 }
262
263
264 /**
265  * Duplicate a namespace handle.
266  *
267  * @param ns namespace handle
268  * @return duplicated handle to the namespace
269  */
270 struct GNUNET_FS_Namespace *
271 GNUNET_FS_namespace_dup (struct GNUNET_FS_Namespace *ns)
272 {
273   ns->rc++;
274   return ns;
275 }
276
277
278 /**
279  * Delete a namespace handle.  Can be used for a clean shutdown (free
280  * memory) or also to freeze the namespace to prevent further
281  * insertions by anyone.
282  *
283  * @param ns handle to the namespace that should be deleted / freed
284  * @param freeze prevents future insertions; creating a namespace
285  *        with the same name again will create a fresh namespace instead
286  *
287  * @return GNUNET_OK on success, GNUNET_SYSERR on error
288  */
289 int
290 GNUNET_FS_namespace_delete (struct GNUNET_FS_Namespace *ns, int freeze)
291 {
292   unsigned int i;
293   struct NamespaceUpdateNode *nsn;
294
295   ns->rc--;
296   if (freeze)
297   {
298     if (0 != UNLINK (ns->filename))
299       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "unlink",
300                                 ns->filename);
301   }
302   if (0 != ns->rc)
303     return GNUNET_OK;
304   GNUNET_CRYPTO_rsa_key_free (ns->key);
305   GNUNET_free (ns->filename);
306   GNUNET_free (ns->name);
307   for (i = 0; i < ns->update_node_count; i++)
308   {
309     nsn = ns->update_nodes[i];
310     GNUNET_CONTAINER_meta_data_destroy (nsn->md);
311     GNUNET_FS_uri_destroy (nsn->uri);
312     GNUNET_free (nsn->id);
313     GNUNET_free (nsn->update);
314     GNUNET_free (nsn);
315   }
316   GNUNET_array_grow (ns->update_nodes, ns->update_node_count,
317                      0);
318   if (ns->update_map != NULL)
319     GNUNET_CONTAINER_multihashmap_destroy (ns->update_map);
320   GNUNET_free (ns);
321   return GNUNET_OK;
322 }
323
324
325 /**
326  * Context for the 'process_namespace' callback.
327  * Specifies a function to call on each namespace.
328  */
329 struct ProcessNamespaceContext
330 {
331   /**
332    * Function to call.
333    */
334   GNUNET_FS_NamespaceInfoProcessor cb;
335
336   /**
337    * Closure for 'cb'.
338    */
339   void *cb_cls;
340 };
341
342
343 /**
344  * Function called with a filename of a namespace. Reads the key and
345  * calls the callback.
346  *
347  * @param cls closure (struct ProcessNamespaceContext)
348  * @param filename complete filename (absolute path)
349  * @return GNUNET_OK to continue to iterate,
350  *  GNUNET_SYSERR to abort iteration with error!
351  */
352 static int
353 process_namespace (void *cls, const char *filename)
354 {
355   struct ProcessNamespaceContext *pnc = cls;
356   struct GNUNET_CRYPTO_RsaPrivateKey *key;
357   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
358   struct GNUNET_HashCode id;
359   const char *name;
360   const char *t;
361
362   key = GNUNET_CRYPTO_rsa_key_create_from_file (filename);
363   if (NULL == key)
364   {
365     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
366                 _
367                 ("Failed to read namespace private key file `%s', deleting it!\n"),
368                 filename);
369     if (0 != UNLINK (filename))
370       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", filename);
371     return GNUNET_OK;
372   }
373   GNUNET_CRYPTO_rsa_key_get_public (key, &pk);
374   GNUNET_CRYPTO_rsa_key_free (key);
375   GNUNET_CRYPTO_hash (&pk, sizeof (pk), &id);
376   name = filename;
377   while (NULL != (t = strstr (name, DIR_SEPARATOR_STR)))
378     name = t + 1;
379   pnc->cb (pnc->cb_cls, name, &id);
380   return GNUNET_OK;
381 }
382
383
384 /**
385  * Build a list of all available local (!) namespaces The returned
386  * names are only the nicknames since we only iterate over the local
387  * namespaces.
388  *
389  * @param h handle to the file sharing subsystem
390  * @param cb function to call on each known namespace
391  * @param cb_cls closure for cb
392  */
393 void
394 GNUNET_FS_namespace_list (struct GNUNET_FS_Handle *h,
395                           GNUNET_FS_NamespaceInfoProcessor cb, void *cb_cls)
396 {
397   char *dn;
398   struct ProcessNamespaceContext ctx;
399
400   dn = get_namespace_directory (h);
401   if (NULL == dn)
402     return;
403   ctx.cb = cb;
404   ctx.cb_cls = cb_cls;
405   GNUNET_DISK_directory_scan (dn, &process_namespace, &ctx);
406   GNUNET_free (dn);
407 }
408
409
410 /**
411  * Context for the SKS publication.
412  */
413 struct GNUNET_FS_PublishSksContext
414 {
415
416   /**
417    * URI of the new entry in the namespace.
418    */
419   struct GNUNET_FS_Uri *uri;
420
421   /**
422    * Namespace update node to add to namespace on success (or to be
423    * deleted if publishing failed).
424    */
425   struct NamespaceUpdateNode *nsn;
426
427   /**
428    * Namespace we're publishing to.
429    */
430   struct GNUNET_FS_Namespace *ns;
431
432   /**
433    * Handle to the datastore.
434    */
435   struct GNUNET_DATASTORE_Handle *dsh;
436
437   /**
438    * Function to call once we're done.
439    */
440   GNUNET_FS_PublishContinuation cont;
441
442   /**
443    * Closure for cont.
444    */
445   void *cont_cls;
446
447   /**
448    * Handle for our datastore request.
449    */
450   struct GNUNET_DATASTORE_QueueEntry *dqe;
451 };
452
453
454 /**
455  * Function called by the datastore API with
456  * the result from the PUT (SBlock) request.
457  *
458  * @param cls closure of type "struct GNUNET_FS_PublishSksContext*"
459  * @param success GNUNET_OK on success
460  * @param min_expiration minimum expiration time required for content to be stored
461  * @param msg error message (or NULL)
462  */
463 static void
464 sb_put_cont (void *cls, int success, 
465              struct GNUNET_TIME_Absolute min_expiration,
466              const char *msg)
467 {
468   struct GNUNET_FS_PublishSksContext *psc = cls;
469   struct GNUNET_HashCode hc;
470
471   psc->dqe = NULL;
472   if (GNUNET_OK != success)
473   {
474     if (NULL != psc->cont)
475       psc->cont (psc->cont_cls, NULL, msg);
476     GNUNET_FS_publish_sks_cancel (psc);
477     return;
478   }
479   if (NULL != psc->nsn)
480   {
481     /* FIXME: this can be done much more
482      * efficiently by simply appending to the
483      * file and overwriting the 4-byte header */
484     if (psc->ns->update_nodes == NULL)
485       read_update_information_graph (psc->ns);
486     GNUNET_array_append (psc->ns->update_nodes,
487                          psc->ns->update_node_count, psc->nsn);
488     if (psc->ns->update_map != NULL)
489     {
490       GNUNET_CRYPTO_hash (psc->nsn->id, strlen (psc->nsn->id), &hc);
491       GNUNET_CONTAINER_multihashmap_put (psc->ns->update_map, &hc,
492                                          psc->nsn,
493                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
494     }
495     psc->nsn = NULL;
496     write_update_information_graph (psc->ns);
497   }
498   if (NULL != psc->cont)
499     psc->cont (psc->cont_cls, psc->uri, NULL);
500   GNUNET_FS_publish_sks_cancel (psc);
501 }
502
503
504 /**
505  * Publish an SBlock on GNUnet.
506  *
507  * @param h handle to the file sharing subsystem
508  * @param ns namespace to publish in
509  * @param identifier identifier to use
510  * @param update update identifier to use
511  * @param meta metadata to use
512  * @param uri URI to refer to in the SBlock
513  * @param bo block options
514  * @param options publication options
515  * @param cont continuation
516  * @param cont_cls closure for cont
517  * @return NULL on error ('cont' will still be called)
518  */
519 struct GNUNET_FS_PublishSksContext *
520 GNUNET_FS_publish_sks (struct GNUNET_FS_Handle *h,
521                        struct GNUNET_FS_Namespace *ns,
522                        const char *identifier, const char *update,
523                        const struct GNUNET_CONTAINER_MetaData *meta,
524                        const struct GNUNET_FS_Uri *uri,
525                        const struct GNUNET_FS_BlockOptions *bo,
526                        enum GNUNET_FS_PublishOptions options,
527                        GNUNET_FS_PublishContinuation cont, void *cont_cls)
528 {
529   struct GNUNET_FS_PublishSksContext *psc;
530   struct GNUNET_CRYPTO_AesSessionKey sk;
531   struct GNUNET_CRYPTO_AesInitializationVector iv;
532   struct GNUNET_FS_Uri *sks_uri;
533   char *uris;
534   size_t size;
535   size_t slen;
536   size_t nidlen;
537   size_t idlen;
538   ssize_t mdsize;
539   struct SBlock *sb;
540   struct SBlock *sb_enc;
541   char *dest;
542   struct GNUNET_CONTAINER_MetaData *mmeta;
543   struct GNUNET_HashCode key;          /* hash of thisId = key */
544   struct GNUNET_HashCode id;           /* hash of hc = identifier */
545   struct GNUNET_HashCode query;        /* id ^ nsid = DB query */
546
547   if (NULL == meta)
548     mmeta = GNUNET_CONTAINER_meta_data_create ();
549   else
550     mmeta = GNUNET_CONTAINER_meta_data_duplicate (meta);
551   uris = GNUNET_FS_uri_to_string (uri);
552   slen = strlen (uris) + 1;
553   idlen = strlen (identifier);
554   if (NULL != update)
555     nidlen = strlen (update) + 1;
556   else
557     nidlen = 1;
558   mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (mmeta);
559   size = sizeof (struct SBlock) + slen + nidlen + mdsize;
560   if (size > MAX_SBLOCK_SIZE)
561   {
562     size = MAX_SBLOCK_SIZE;
563     mdsize = size - (sizeof (struct SBlock) + slen + nidlen);
564   }
565   sb = GNUNET_malloc (sizeof (struct SBlock) + size);
566   dest = (char *) &sb[1];
567   if (update != NULL)
568     memcpy (dest, update, nidlen);
569   else
570     memset (dest, 0, 1);
571   dest += nidlen;
572   memcpy (dest, uris, slen);
573   GNUNET_free (uris);
574   dest += slen;
575   mdsize =
576       GNUNET_CONTAINER_meta_data_serialize (mmeta, &dest, mdsize,
577                                             GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
578   GNUNET_CONTAINER_meta_data_destroy (mmeta);
579   if (-1 == mdsize)
580   {
581     GNUNET_break (0);
582     GNUNET_free (sb);
583     if (NULL != cont)
584       cont (cont_cls, NULL, _("Internal error."));
585     return NULL;
586   }
587   size = sizeof (struct SBlock) + mdsize + slen + nidlen;
588   sb_enc = GNUNET_malloc (size);
589   GNUNET_CRYPTO_hash (identifier, idlen, &key);
590   GNUNET_CRYPTO_hash (&key, sizeof (struct GNUNET_HashCode), &id);
591   sks_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
592   sks_uri->type = sks;
593   GNUNET_CRYPTO_rsa_key_get_public (ns->key, &sb_enc->subspace);
594   GNUNET_CRYPTO_hash (&sb_enc->subspace,
595                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
596                       &sks_uri->data.sks.ns);
597   sks_uri->data.sks.identifier = GNUNET_strdup (identifier);
598   GNUNET_CRYPTO_hash_xor (&id, &sks_uri->data.sks.ns,
599                           &sb_enc->identifier);
600   GNUNET_CRYPTO_hash_to_aes_key (&key, &sk, &iv);
601   GNUNET_CRYPTO_aes_encrypt (&sb[1], size - sizeof (struct SBlock), &sk, &iv,
602                              &sb_enc[1]);
603   sb_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_SBLOCK);
604   sb_enc->purpose.size =
605       htonl (slen + mdsize + nidlen + sizeof (struct SBlock) -
606              sizeof (struct GNUNET_CRYPTO_RsaSignature));
607   GNUNET_assert (GNUNET_OK ==
608                  GNUNET_CRYPTO_rsa_sign (ns->key, &sb_enc->purpose,
609                                          &sb_enc->signature));
610   psc = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishSksContext));
611   psc->uri = sks_uri;
612   psc->cont = cont;
613   psc->ns = GNUNET_FS_namespace_dup (ns);
614   psc->cont_cls = cont_cls;
615   if (0 != (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
616   {
617     GNUNET_free (sb_enc);
618     GNUNET_free (sb);
619     sb_put_cont (psc, GNUNET_OK, GNUNET_TIME_UNIT_ZERO_ABS, NULL);
620     return NULL;
621   }
622   psc->dsh = GNUNET_DATASTORE_connect (h->cfg);
623   if (NULL == psc->dsh)
624   {
625     GNUNET_free (sb_enc);
626     GNUNET_free (sb);
627     sb_put_cont (psc, GNUNET_NO, GNUNET_TIME_UNIT_ZERO_ABS, _("Failed to connect to datastore."));
628     return NULL;
629   }
630   GNUNET_CRYPTO_hash_xor (&sks_uri->data.sks.ns, &id, &query);
631   if (NULL != update)
632   {
633     psc->nsn = GNUNET_malloc (sizeof (struct NamespaceUpdateNode));
634     psc->nsn->id = GNUNET_strdup (identifier);
635     psc->nsn->update = GNUNET_strdup (update);
636     psc->nsn->md = GNUNET_CONTAINER_meta_data_duplicate (meta);
637     psc->nsn->uri = GNUNET_FS_uri_dup (uri);
638   }
639   psc->dqe = GNUNET_DATASTORE_put (psc->dsh, 0, &sb_enc->identifier, size, sb_enc,
640                                    GNUNET_BLOCK_TYPE_FS_SBLOCK, bo->content_priority,
641                                    bo->anonymity_level, bo->replication_level,
642                                    bo->expiration_time, -2, 1,
643                                    GNUNET_CONSTANTS_SERVICE_TIMEOUT, &sb_put_cont, psc);
644   GNUNET_free (sb);
645   GNUNET_free (sb_enc);
646   return psc;
647 }
648
649
650 /**
651  * Abort the SKS publishing operation.
652  *
653  * @param psc context of the operation to abort.
654  */
655 void
656 GNUNET_FS_publish_sks_cancel (struct GNUNET_FS_PublishSksContext *psc)
657 {
658   if (NULL != psc->dqe)
659   {
660     GNUNET_DATASTORE_cancel (psc->dqe);
661     psc->dqe = NULL;
662   }
663   if (NULL != psc->dsh)
664   {
665     GNUNET_DATASTORE_disconnect (psc->dsh, GNUNET_NO);
666     psc->dsh = NULL;
667   }
668   GNUNET_FS_namespace_delete (psc->ns, GNUNET_NO);
669   GNUNET_FS_uri_destroy (psc->uri);
670   if (NULL != psc->nsn)
671   {
672     GNUNET_CONTAINER_meta_data_destroy (psc->nsn->md);
673     GNUNET_FS_uri_destroy (psc->nsn->uri);
674     GNUNET_free (psc->nsn->id);
675     GNUNET_free (psc->nsn->update);
676     GNUNET_free (psc->nsn);
677   }
678   GNUNET_free (psc);
679 }
680
681
682 /**
683  * Closure for 'process_update_node'.
684  */
685 struct ProcessUpdateClosure
686 {
687   /**
688    * Function to call for each node.
689    */
690   GNUNET_FS_IdentifierProcessor ip;
691
692   /**
693    * Closure for 'ip'.
694    */
695   void *ip_cls;
696 };
697
698
699 /**
700  * Call the iterator in the closure for each node.
701  *
702  * @param cls closure (of type 'struct ProcessUpdateClosure *')
703  * @param key current key code
704  * @param value value in the hash map (of type 'struct NamespaceUpdateNode *')
705  * @return GNUNET_YES if we should continue to
706  *         iterate,
707  *         GNUNET_NO if not.
708  */
709 static int
710 process_update_node (void *cls, const struct GNUNET_HashCode * key, void *value)
711 {
712   struct ProcessUpdateClosure *pc = cls;
713   struct NamespaceUpdateNode *nsn = value;
714
715   pc->ip (pc->ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update);
716   return GNUNET_YES;
717 }
718
719
720 /**
721  * Closure for 'find_trees'.
722  */
723 struct FindTreeClosure
724 {
725   /**
726    * Namespace we are operating on.
727    */
728   struct GNUNET_FS_Namespace *ns;
729
730   /**
731    * Array with 'head's of TREEs.
732    */
733   struct NamespaceUpdateNode **tree_array;
734
735   /**
736    * Size of 'tree_array'
737    */
738   unsigned int tree_array_size;
739
740   /**
741    * Current generational ID used.
742    */
743   unsigned int nug;
744
745   /**
746    * Identifier for the current TREE, or UINT_MAX for none yet.
747    */
748   unsigned int id;
749 };
750
751
752 /**
753  * Find all nodes reachable from the current node (including the
754  * current node itself).  If they are in no tree, add them to the
755  * current one.   If they are the head of another tree, merge the
756  * trees.  If they are in the middle of another tree, let them be.
757  * We can tell that a node is already in an tree by checking if
758  * its 'nug' field is set to the current 'nug' value.  It is the
759  * head of an tree if it is in the 'tree_array' under its respective
760  * 'tree_id'.
761  *
762  * In short, we're trying to find the smallest number of tree to
763  * cover a directed graph.
764  *
765  * @param cls closure (of type 'struct FindTreeClosure')
766  * @param key current key code
767  * @param value value in the hash map
768  * @return GNUNET_YES if we should continue to
769  *         iterate,
770  *         GNUNET_NO if not.
771  */
772 static int
773 find_trees (void *cls, const struct GNUNET_HashCode * key, void *value)
774 {
775   struct FindTreeClosure *fc = cls;
776   struct NamespaceUpdateNode *nsn = value;
777   struct GNUNET_HashCode hc;
778
779   if (nsn->nug == fc->nug)
780   {
781     if (UINT_MAX == nsn->tree_id)
782       return GNUNET_YES;        /* circular */
783     GNUNET_assert (nsn->tree_id < fc->tree_array_size);
784     if (fc->tree_array[nsn->tree_id] != nsn)
785       return GNUNET_YES;        /* part of "another" (directed) TREE,
786                                  * and not root of it, end trace */
787     if (nsn->tree_id == fc->id)
788       return GNUNET_YES;        /* that's our own root (can this be?) */
789     /* merge existing TREE, we have a root for both */
790     fc->tree_array[nsn->tree_id] = NULL;
791     if (UINT_MAX == fc->id)
792       fc->id = nsn->tree_id;    /* take over ID */
793   }
794   else
795   {
796     nsn->nug = fc->nug;
797     nsn->tree_id = UINT_MAX;    /* mark as undef */
798     /* trace */
799     GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc);
800     GNUNET_CONTAINER_multihashmap_get_multiple (fc->ns->update_map, &hc,
801                                                 &find_trees, fc);
802   }
803   return GNUNET_YES;
804 }
805
806
807 /**
808  * List all of the identifiers in the namespace for which we could
809  * produce an update.  Namespace updates form a graph where each node
810  * has a name.  Each node can have any number of URI/meta-data entries
811  * which can each be linked to other nodes.  Cycles are possible.
812  *
813  * Calling this function with "next_id" NULL will cause the library to
814  * call "ip" with a root for each strongly connected component of the
815  * graph (a root being a node from which all other nodes in the Tree
816  * are reachable).
817  *
818  * Calling this function with "next_id" being the name of a node will
819  * cause the library to call "ip" with all children of the node.  Note
820  * that cycles within the final tree are possible (including self-loops).
821  * I know, odd definition of a tree, but the GUI will display an actual
822  * tree (GtkTreeView), so that's what counts for the term here.
823  *
824  * @param ns namespace to inspect for updateable content
825  * @param next_id ID to look for; use NULL to look for tree roots
826  * @param ip function to call on each updateable identifier
827  * @param ip_cls closure for ip
828  */
829 void
830 GNUNET_FS_namespace_list_updateable (struct GNUNET_FS_Namespace *ns,
831                                      const char *next_id,
832                                      GNUNET_FS_IdentifierProcessor ip,
833                                      void *ip_cls)
834 {
835   unsigned int i;
836   unsigned int nug;
837   struct GNUNET_HashCode hc;
838   struct NamespaceUpdateNode *nsn;
839   struct ProcessUpdateClosure pc;
840   struct FindTreeClosure fc;
841
842   if (NULL == ns->update_nodes)
843     read_update_information_graph (ns);
844   if (NULL == ns->update_nodes)
845   {
846     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
847                 "No updateable nodes found for ID `%s'\n", next_id);
848     return;                     /* no nodes */
849   }
850   if (NULL == ns->update_map)
851   {
852     /* need to construct */
853     ns->update_map =
854         GNUNET_CONTAINER_multihashmap_create (2 +
855                                               3 * ns->update_node_count /
856                                               4);
857     for (i = 0; i < ns->update_node_count; i++)
858     {
859       nsn = ns->update_nodes[i];
860       GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc);
861       GNUNET_CONTAINER_multihashmap_put (ns->update_map, &hc, nsn,
862                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
863     }
864   }
865   if (NULL != next_id)
866   {
867     GNUNET_CRYPTO_hash (next_id, strlen (next_id), &hc);
868     pc.ip = ip;
869     pc.ip_cls = ip_cls;
870     GNUNET_CONTAINER_multihashmap_get_multiple (ns->update_map, &hc,
871                                                 &process_update_node, &pc);
872     return;
873   }
874   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
875               "Calculating TREEs to find roots of update trees\n");
876   /* Find heads of TREEs in update graph */
877   nug = ++ns->nug_gen;
878   fc.tree_array = NULL;
879   fc.tree_array_size = 0;
880
881   for (i = 0; i < ns->update_node_count; i++)
882   {
883     nsn = ns->update_nodes[i];
884     if (nsn->nug == nug)
885     {
886       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TREE of node `%s' is %u\n", nsn->id,
887                   nsn->nug);
888       continue;                 /* already placed in TREE */
889     }
890     GNUNET_CRYPTO_hash (nsn->update, strlen (nsn->update), &hc);
891     nsn->nug = nug;
892     nsn->tree_id = UINT_MAX;
893     fc.id = UINT_MAX;
894     fc.nug = nug;
895     fc.ns = ns;
896     GNUNET_CONTAINER_multihashmap_get_multiple (ns->update_map, &hc,
897                                                 &find_trees, &fc);
898     if (UINT_MAX == fc.id)
899     {
900       /* start new TREE */
901       for (fc.id = 0; fc.id < fc.tree_array_size; fc.id++)
902       {
903         if (fc.tree_array[fc.id] == NULL)
904         {
905           fc.tree_array[fc.id] = nsn;
906           nsn->tree_id = fc.id;
907           break;
908         }
909       }
910       if (fc.id == fc.tree_array_size)
911       {
912         GNUNET_array_append (fc.tree_array, fc.tree_array_size, nsn);
913         nsn->tree_id = fc.id;
914       }
915       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
916                   "Starting new TREE %u with node `%s'\n", nsn->tree_id,
917                   nsn->id);
918       /* put all nodes with same identifier into this TREE */
919       GNUNET_CRYPTO_hash (nsn->id, strlen (nsn->id), &hc);
920       fc.id = nsn->tree_id;
921       fc.nug = nug;
922       fc.ns = ns;
923       GNUNET_CONTAINER_multihashmap_get_multiple (ns->update_map, &hc,
924                                                   &find_trees, &fc);
925     }
926     else
927     {
928       /* make head of TREE "id" */
929       fc.tree_array[fc.id] = nsn;
930       nsn->tree_id = fc.id;
931     }
932     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TREE of node `%s' is %u\n", nsn->id,
933                 fc.id);
934   }
935   for (i = 0; i < fc.tree_array_size; i++)
936   {
937     nsn = fc.tree_array[i];
938     if (NULL != nsn)
939     {
940       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Root of TREE %u is node `%s'\n", i,
941                   nsn->id);
942       ip (ip_cls, nsn->id, nsn->uri, nsn->md, nsn->update);
943     }
944   }
945   GNUNET_array_grow (fc.tree_array, fc.tree_array_size, 0);
946   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done processing TREEs\n");
947 }
948
949
950 /* end of fs_namespace.c */