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