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