-only trigger check config if we actually need it
[oweals/gnunet.git] / src / fs / fs_unindex.c
index 5a956b0b5f3ff772932805b2dc4d8d9cedd64dd5..2c4cb6ae67be7a058df18e15ee31fe4f4e726ecd 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2003--2013 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2003--2013 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -14,8 +14,8 @@
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
@@ -31,6 +31,7 @@
 #include "fs_api.h"
 #include "fs_tree.h"
 #include "block_fs.h"
+#include "fs_publish_ublock.h"
 
 
 /**
  * @return number of bytes copied to buf, 0 on error
  */
 static size_t
-unindex_reader (void *cls, uint64_t offset, size_t max, void *buf, char **emsg)
+unindex_reader (void *cls,
+                uint64_t offset,
+                size_t max,
+                void *buf,
+                char **emsg)
 {
   struct GNUNET_FS_UnindexContext *uc = cls;
   size_t pt_size;
@@ -143,12 +148,15 @@ signal_unindex_error (struct GNUNET_FS_UnindexContext *uc)
  * datastore removal operation.
  *
  * @param cls closure
- * @param success GNUNET_SYSERR on failure
+ * @param success #GNUNET_SYSERR on failure
  * @param min_expiration minimum expiration time required for content to be stored
  * @param msg NULL on success, otherwise an error message
  */
 static void
-process_cont (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration, const char *msg)
+process_cont (void *cls,
+              int success,
+              struct GNUNET_TIME_Absolute min_expiration,
+              const char *msg)
 {
   struct GNUNET_FS_UnindexContext *uc = cls;
 
@@ -179,9 +187,13 @@ process_cont (void *cls, int success, struct GNUNET_TIME_Absolute min_expiration
  * @param block_size size of block (in bytes)
  */
 static void
-unindex_process (void *cls, const struct ContentHashKey *chk, uint64_t offset,
-                 unsigned int depth, enum GNUNET_BLOCK_Type type,
-                 const void *block, uint16_t block_size)
+unindex_process (void *cls,
+                 const struct ContentHashKey *chk,
+                 uint64_t offset,
+                 unsigned int depth,
+                 enum GNUNET_BLOCK_Type type,
+                 const void *block,
+                 uint16_t block_size)
 {
   struct GNUNET_FS_UnindexContext *uc = cls;
   uint32_t size;
@@ -203,7 +215,7 @@ unindex_process (void *cls, const struct ContentHashKey *chk, uint64_t offset,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Sending REMOVE request to DATASTORE service\n");
   GNUNET_DATASTORE_remove (uc->dsh, &chk->query, size, data, -2, 1,
-                           GNUNET_CONSTANTS_SERVICE_TIMEOUT, &process_cont, uc);
+                           &process_cont, uc);
   uc->chk = *chk;
 }
 
@@ -270,19 +282,18 @@ static void
 unindex_finish (struct GNUNET_FS_UnindexContext *uc)
 {
   char *emsg;
-  struct GNUNET_FS_Uri *uri;
   struct UnindexMessage req;
 
   /* generate final progress message */
   unindex_progress (uc, uc->file_size, NULL, 0, 0);
-  GNUNET_FS_tree_encoder_finish (uc->tc, &uri, &emsg);
+  GNUNET_FS_tree_encoder_finish (uc->tc, &emsg);
   uc->tc = NULL;
-  if (uri != NULL)
-    GNUNET_FS_uri_destroy (uri);
   GNUNET_DISK_file_close (uc->fh);
   uc->fh = NULL;
   GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO);
   uc->dsh = NULL;
+  GNUNET_CONTAINER_multihashmap_destroy (uc->seen_dh);
+  uc->seen_dh = NULL;
   uc->state = UNINDEX_STATE_FS_NOTIFY;
   GNUNET_FS_unindex_sync_ (uc);
   uc->client = GNUNET_CLIENT_connect ("fs", uc->h->cfg);
@@ -318,14 +329,14 @@ unindex_finish (struct GNUNET_FS_UnindexContext *uc)
  *
  * @param cls the 'struct GNUNET_FS_UnindexContext *'
  * @param filename which file we are making progress on
- * @param is_directory GNUNET_YES if this is a directory,
- *                     GNUNET_NO if this is a file
- *                     GNUNET_SYSERR if it is neither (or unknown)
+ * @param is_directory #GNUNET_YES if this is a directory,
+ *                     #GNUNET_NO if this is a file
+ *                     #GNUNET_SYSERR if it is neither (or unknown)
  * @param reason kind of progress we are making
  */
 static void
-unindex_directory_scan_cb (void *cls, 
-                          const char *filename, 
+unindex_directory_scan_cb (void *cls,
+                          const char *filename,
                           int is_directory,
                           enum GNUNET_FS_DirScannerProgressUpdateReason reason)
 {
@@ -383,7 +394,7 @@ GNUNET_FS_unindex_do_extract_keywords_ (struct GNUNET_FS_UnindexContext *uc)
     ex = NULL;
   uc->dscan = GNUNET_FS_directory_scan_start (uc->filename,
                                              GNUNET_NO, ex,
-                                             &unindex_directory_scan_cb, 
+                                             &unindex_directory_scan_cb,
                                              uc);
   GNUNET_free_non_null (ex);
 }
@@ -393,7 +404,7 @@ GNUNET_FS_unindex_do_extract_keywords_ (struct GNUNET_FS_UnindexContext *uc)
  * Continuation called to notify client about result of the remove
  * operation for the UBlock.
  *
- * @param cls the 'struct GNUNET_FS_UnindexContext *' 
+ * @param cls the 'struct GNUNET_FS_UnindexContext *'
  * @param success GNUNET_SYSERR on failure (including timeout/queue drop)
  *                GNUNET_NO if content was already there
  *                GNUNET_YES (or other positive value) on success
@@ -411,10 +422,11 @@ continue_after_remove (void *cls,
   struct GNUNET_FS_UnindexContext *uc = cls;
 
   uc->dqe = NULL;
-  if (success != GNUNET_YES)  
+  if (success != GNUNET_YES)
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _("Failed to remove UBlock: %s\n"),
-               msg);  
+               msg);
+  GNUNET_CONTAINER_multihashmap_clear (uc->seen_dh);
   uc->ksk_offset++;
   GNUNET_FS_unindex_do_remove_kblocks_ (uc);
 }
@@ -443,38 +455,46 @@ continue_after_remove (void *cls,
 static void
 process_kblock_for_unindex (void *cls,
                            const struct GNUNET_HashCode *key,
-                           size_t size, const void *data,
+                           size_t size,
+                            const void *data,
                            enum GNUNET_BLOCK_Type type,
                            uint32_t priority,
                            uint32_t anonymity,
-                           struct GNUNET_TIME_Absolute
-                           expiration, uint64_t uid)
+                           struct GNUNET_TIME_Absolute expiration,
+                            uint64_t uid)
 {
   struct GNUNET_FS_UnindexContext *uc = cls;
   const struct UBlock *ub;
   struct GNUNET_FS_Uri *chk_uri;
   struct GNUNET_HashCode query;
+  struct GNUNET_HashCode dh;
 
   uc->dqe = NULL;
   if (NULL == data)
   {
     /* no result */
+    GNUNET_CONTAINER_multihashmap_clear (uc->seen_dh);
     uc->ksk_offset++;
     GNUNET_FS_unindex_do_remove_kblocks_ (uc);
     return;
   }
-  if (0 == uc->first_uid)
-  {
-    /* remember UID of first result to detect cycles */
-    uc->first_uid = uid;    
-  }
-  else if (uid == uc->first_uid)
+  GNUNET_CRYPTO_hash (data,
+                      size,
+                      &dh);
+  if (GNUNET_YES ==
+      GNUNET_CONTAINER_multihashmap_contains (uc->seen_dh,
+                                              &dh))
   {
-    /* no more additional results */
+    GNUNET_CONTAINER_multihashmap_clear (uc->seen_dh);
     uc->ksk_offset++;
     GNUNET_FS_unindex_do_remove_kblocks_ (uc);
-    return;  
+    return;
   }
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multihashmap_put (uc->seen_dh,
+                                                    &dh,
+                                                    uc,
+                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
   GNUNET_assert (GNUNET_BLOCK_TYPE_FS_UBLOCK == type);
   if (size < sizeof (struct UBlock))
   {
@@ -485,24 +505,25 @@ process_kblock_for_unindex (void *cls,
   GNUNET_CRYPTO_hash (&ub->verification_key,
                      sizeof (ub->verification_key),
                      &query);
-  if (0 != memcmp (&query, key, sizeof (struct GNUNET_HashCode)))
+  if (0 != memcmp (&query,
+                   key,
+                   sizeof (struct GNUNET_HashCode)))
   {
     /* result does not match our keyword, skip */
     goto get_next;
   }
   {
-    char pt[size - sizeof (struct UBlock)];  
-    struct GNUNET_CRYPTO_AesSessionKey skey;
-    struct GNUNET_CRYPTO_AesInitializationVector iv;
-     
-    GNUNET_CRYPTO_hash_to_aes_key (&uc->ukey, &skey, &iv);
-    if (-1 ==
-       GNUNET_CRYPTO_aes_decrypt (&ub[1], size - sizeof (struct UBlock), &skey,
-                                  &iv, pt))
-    {
-      GNUNET_break (0);
-      goto get_next;
-    }       
+    char pt[size - sizeof (struct UBlock)];
+    struct GNUNET_CRYPTO_EcdsaPublicKey anon_pub;
+    const char *keyword;
+
+    GNUNET_CRYPTO_ecdsa_key_get_public (GNUNET_CRYPTO_ecdsa_key_get_anonymous (),
+                                        &anon_pub);
+    keyword = &uc->ksk_uri->data.ksk.keywords[uc->ksk_offset][1];
+    GNUNET_FS_ublock_decrypt_ (&ub[1], size - sizeof (struct UBlock),
+                              &anon_pub,
+                              keyword,
+                              pt);
     if (NULL == memchr (&pt[1], 0, sizeof (pt) - 1))
     {
       GNUNET_break_op (0); /* malformed UBlock */
@@ -526,9 +547,11 @@ process_kblock_for_unindex (void *cls,
   GNUNET_FS_uri_destroy (chk_uri);
   /* matches! */
   uc->dqe = GNUNET_DATASTORE_remove (uc->dsh,
-                                    key, size, data,
-                                    0 /* priority */, 1 /* queue size */,
-                                    GNUNET_TIME_UNIT_FOREVER_REL,
+                                    key,
+                                     size,
+                                     data,
+                                    0 /* priority */,
+                                     1 /* queue size */,
                                     &continue_after_remove,
                                     uc);
   return;
@@ -537,8 +560,8 @@ process_kblock_for_unindex (void *cls,
                                      uc->roff++,
                                      &uc->uquery,
                                      GNUNET_BLOCK_TYPE_FS_UBLOCK,
-                                     0 /* priority */, 1 /* queue size */,
-                                     GNUNET_TIME_UNIT_FOREVER_REL,
+                                     0 /* priority */,
+                                      1 /* queue size */,
                                      &process_kblock_for_unindex,
                                      uc);
 }
@@ -553,9 +576,9 @@ void
 GNUNET_FS_unindex_do_remove_kblocks_ (struct GNUNET_FS_UnindexContext *uc)
 {
   const char *keyword;
-  const struct GNUNET_CRYPTO_EccPrivateKey *anon;
-  struct GNUNET_CRYPTO_EccPublicKey anon_pub;
-  struct GNUNET_CRYPTO_EccPublicKey dpub;
+  const struct GNUNET_CRYPTO_EcdsaPrivateKey *anon;
+  struct GNUNET_CRYPTO_EcdsaPublicKey anon_pub;
+  struct GNUNET_CRYPTO_EcdsaPublicKey dpub;
 
   if (NULL == uc->dsh)
     uc->dsh = GNUNET_DATASTORE_connect (uc->h->cfg);
@@ -573,23 +596,23 @@ GNUNET_FS_unindex_do_remove_kblocks_ (struct GNUNET_FS_UnindexContext *uc)
     unindex_finish (uc);
     return;
   }
-  anon = GNUNET_CRYPTO_ecc_key_get_anonymous ();
-  GNUNET_CRYPTO_ecc_key_get_public (anon, &anon_pub);
+  anon = GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
+  GNUNET_CRYPTO_ecdsa_key_get_public (anon,
+                                      &anon_pub);
   keyword = &uc->ksk_uri->data.ksk.keywords[uc->ksk_offset][1];
-  GNUNET_CRYPTO_ecc_public_key_derive (&anon_pub,
-                                      keyword,
-                                      "fs-ublock",
-                                      &dpub);
+  GNUNET_CRYPTO_ecdsa_public_key_derive (&anon_pub,
+                                         keyword,
+                                         "fs-ublock",
+                                         &dpub);
   GNUNET_CRYPTO_hash (&dpub,
                      sizeof (dpub),
                      &uc->uquery);
-  uc->first_uid = 0;
   uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh,
                                      uc->roff++,
                                      &uc->uquery,
                                      GNUNET_BLOCK_TYPE_FS_UBLOCK,
-                                     0 /* priority */, 1 /* queue size */,
-                                     GNUNET_TIME_UNIT_FOREVER_REL,
+                                     0 /* priority */,
+                                      1 /* queue size */,
                                      &process_kblock_for_unindex,
                                      uc);
 }
@@ -600,10 +623,9 @@ GNUNET_FS_unindex_do_remove_kblocks_ (struct GNUNET_FS_UnindexContext *uc)
  * processed all blocks.  Clean up.
  *
  * @param cls our unindexing context
- * @param tc not used
  */
 static void
-unindex_extract_keywords (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+unindex_extract_keywords (void *cls)
 {
   struct GNUNET_FS_UnindexContext *uc = cls;
 
@@ -645,8 +667,12 @@ GNUNET_FS_unindex_do_remove_ (struct GNUNET_FS_UnindexContext *uc)
     return;
   }
   uc->tc =
-      GNUNET_FS_tree_encoder_create (uc->h, uc->file_size, uc, &unindex_reader,
-                                     &unindex_process, &unindex_progress,
+      GNUNET_FS_tree_encoder_create (uc->h,
+                                     uc->file_size,
+                                     uc,
+                                     &unindex_reader,
+                                     &unindex_process,
+                                     &unindex_progress,
                                      &unindex_extract_keywords);
   GNUNET_FS_tree_encoder_next (uc->tc);
 }
@@ -660,7 +686,8 @@ GNUNET_FS_unindex_do_remove_ (struct GNUNET_FS_UnindexContext *uc)
  * @param file_id computed hash, NULL on error
  */
 void
-GNUNET_FS_unindex_process_hash_ (void *cls, const struct GNUNET_HashCode * file_id)
+GNUNET_FS_unindex_process_hash_ (void *cls,
+                                 const struct GNUNET_HashCode *file_id)
 {
   struct GNUNET_FS_UnindexContext *uc = cls;
 
@@ -689,7 +716,7 @@ GNUNET_FS_unindex_process_hash_ (void *cls, const struct GNUNET_HashCode * file_
  * Create SUSPEND event for the given unindex operation
  * and then clean up our state (without stop signal).
  *
- * @param cls the 'struct GNUNET_FS_UnindexContext' to signal for
+ * @param cls the `struct GNUNET_FS_UnindexContext` to signal for
  */
 void
 GNUNET_FS_unindex_signal_suspend_ (void *cls)
@@ -730,7 +757,7 @@ GNUNET_FS_unindex_signal_suspend_ (void *cls)
   }
   if (NULL != uc->tc)
   {
-    GNUNET_FS_tree_encoder_finish (uc->tc, NULL, NULL);
+    GNUNET_FS_tree_encoder_finish (uc->tc, NULL);
     uc->tc = NULL;
   }
   if (uc->fh != NULL)
@@ -760,31 +787,41 @@ GNUNET_FS_unindex_signal_suspend_ (void *cls)
  * @return NULL on error, otherwise handle
  */
 struct GNUNET_FS_UnindexContext *
-GNUNET_FS_unindex_start (struct GNUNET_FS_Handle *h, const char *filename,
+GNUNET_FS_unindex_start (struct GNUNET_FS_Handle *h,
+                        const char *filename,
                          void *cctx)
 {
-  struct GNUNET_FS_UnindexContext *ret;
+  struct GNUNET_FS_UnindexContext *uc;
   struct GNUNET_FS_ProgressInfo pi;
   uint64_t size;
 
-  if (GNUNET_OK != GNUNET_DISK_file_size (filename, &size, GNUNET_YES, GNUNET_YES))
+  if (GNUNET_OK !=
+      GNUNET_DISK_file_size (filename,
+                             &size,
+                             GNUNET_YES,
+                             GNUNET_YES))
     return NULL;
-  ret = GNUNET_malloc (sizeof (struct GNUNET_FS_UnindexContext));
-  ret->h = h;
-  ret->filename = GNUNET_strdup (filename);
-  ret->start_time = GNUNET_TIME_absolute_get ();
-  ret->file_size = size;
-  ret->client_info = cctx;
-  GNUNET_FS_unindex_sync_ (ret);
+  uc = GNUNET_new (struct GNUNET_FS_UnindexContext);
+  uc->h = h;
+  uc->filename = GNUNET_strdup (filename);
+  uc->start_time = GNUNET_TIME_absolute_get ();
+  uc->file_size = size;
+  uc->client_info = cctx;
+  uc->seen_dh = GNUNET_CONTAINER_multihashmap_create (4,
+                                                       GNUNET_NO);
+  GNUNET_FS_unindex_sync_ (uc);
   pi.status = GNUNET_FS_STATUS_UNINDEX_START;
   pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL;
-  GNUNET_FS_unindex_make_status_ (&pi, ret, 0);
-  ret->fhc =
-      GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE, filename,
+  GNUNET_FS_unindex_make_status_ (&pi, uc, 0);
+  uc->fhc =
+      GNUNET_CRYPTO_hash_file (GNUNET_SCHEDULER_PRIORITY_IDLE,
+                               filename,
                                HASHING_BLOCKSIZE,
-                               &GNUNET_FS_unindex_process_hash_, ret);
-  ret->top = GNUNET_FS_make_top (h, &GNUNET_FS_unindex_signal_suspend_, ret);
-  return ret;
+                               &GNUNET_FS_unindex_process_hash_, uc);
+  uc->top = GNUNET_FS_make_top (h,
+                                &GNUNET_FS_unindex_signal_suspend_,
+                                uc);
+  return uc;
 }
 
 
@@ -830,7 +867,7 @@ GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc)
   }
   if (NULL != uc->tc)
   {
-    GNUNET_FS_tree_encoder_finish (uc->tc, NULL, NULL);
+    GNUNET_FS_tree_encoder_finish (uc->tc, NULL);
     uc->tc = NULL;
   }
   if (uc->fh != NULL)