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