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