fix
[oweals/gnunet.git] / src / fs / fs_download.c
index d7c5370b1f0dd3dccf8d90348f83800abdba9a09..dca419fd35a59be53cbcf629d5def41810c0a4dd 100644 (file)
@@ -23,7 +23,6 @@
  * @author Christian Grothoff
  *
  * TODO:
- * - persistence (can wait)
  * - location URI suppport (can wait, easy)
  * - different priority for scheduling probe downloads?
  * - check if iblocks can be computed from existing blocks (can wait, hard)
@@ -306,12 +305,10 @@ schedule_block_download (struct GNUNET_FS_DownloadContext *dc,
                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
   fh = NULL;
   if ( (dc->old_file_size > off) &&
-       (dc->filename != NULL) )
-    {
-      fh = GNUNET_DISK_file_open (dc->filename,
-                                 GNUNET_DISK_OPEN_READ,
-                                 GNUNET_DISK_PERM_NONE);
-    }
+       (dc->filename != NULL) )    
+    fh = GNUNET_DISK_file_open (dc->filename,
+                               GNUNET_DISK_OPEN_READ,
+                               GNUNET_DISK_PERM_NONE);    
   if ( (fh != NULL) &&
        (off  == 
        GNUNET_DISK_file_seek (fh,
@@ -359,6 +356,7 @@ schedule_block_download (struct GNUNET_FS_DownloadContext *dc,
            {
              GNUNET_break_op (0);
            }
+         GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh));
          return;
        }
     }
@@ -640,6 +638,7 @@ check_completed (struct GNUNET_FS_DownloadContext *dc)
       pos = pos->next;
     }
   dc->has_finished = GNUNET_YES;
+  GNUNET_FS_download_sync_ (dc);
   /* signal completion */
   pi.status = GNUNET_FS_STATUS_DOWNLOAD_COMPLETED;
   GNUNET_FS_download_make_status_ (&pi, dc);
@@ -821,6 +820,24 @@ trigger_recursive_download (void *cls,
 }
 
 
+/**
+ * Free entries in the map.
+ *
+ * @param cls unused (NULL)
+ * @param key unused
+ * @param entry entry of type "struct DownloadRequest" which is freed
+ * @return GNUNET_OK
+ */
+static int
+free_entry (void *cls,
+           const GNUNET_HashCode *key,
+           void *entry)
+{
+  GNUNET_free (entry);
+  return GNUNET_OK;
+}
+
+
 /**
  * Iterator over entries in the pending requests in the 'active' map for the
  * reply that we just got.
@@ -1032,9 +1049,9 @@ process_result_with_request (void *cls,
        }
       GNUNET_assert (sm->depth == dc->treedepth);
     }
-  // FIXME: make persistent
   if (sm->depth == dc->treedepth) 
     {
+      GNUNET_FS_download_sync_ (dc);
       GNUNET_free (sm);      
       return GNUNET_YES;
     }
@@ -1060,6 +1077,7 @@ process_result_with_request (void *cls,
                                 sm->depth + 1);
     }
   GNUNET_free (sm);
+  GNUNET_FS_download_sync_ (dc);
   return GNUNET_YES;
 
  signal_error:
@@ -1075,8 +1093,13 @@ process_result_with_request (void *cls,
       dc->th = NULL;
     }
   GNUNET_CLIENT_disconnect (dc->client, GNUNET_NO);
+  GNUNET_CONTAINER_multihashmap_iterate (dc->active,
+                                        &free_entry,
+                                        NULL);
+  dc->pending = NULL;
   dc->client = NULL;
   GNUNET_free (sm);
+  GNUNET_FS_download_sync_ (dc);
   return GNUNET_NO;
 }
 
@@ -1336,6 +1359,8 @@ activate_fs_download (void *cls,
   struct GNUNET_FS_ProgressInfo pi;
 
   GNUNET_assert (NULL != client);
+  GNUNET_assert (dc->client == NULL);
+  GNUNET_assert (dc->th == NULL);
   dc->client = client;
   GNUNET_CLIENT_receive (client,
                         &receive_results,
@@ -1346,14 +1371,12 @@ activate_fs_download (void *cls,
   GNUNET_CONTAINER_multihashmap_iterate (dc->active,
                                         &retry_entry,
                                         dc);
-  if ( (dc->th == NULL) &&
-       (dc->client != NULL) )
-    dc->th = GNUNET_CLIENT_notify_transmit_ready (dc->client,
-                                                 sizeof (struct SearchMessage),
-                                                 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
-                                                 GNUNET_NO,
-                                                 &transmit_download_request,
-                                                 dc);
+  dc->th = GNUNET_CLIENT_notify_transmit_ready (dc->client,
+                                               sizeof (struct SearchMessage),
+                                               GNUNET_CONSTANTS_SERVICE_TIMEOUT,
+                                               GNUNET_NO,
+                                               &transmit_download_request,
+                                               dc);    
 }
 
 
@@ -1387,15 +1410,46 @@ deactivate_fs_download (void *cls)
  * Create SUSPEND event for the given download 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_DownloadContext' to signal for
  */
-static void
-download_signal_suspend (void *cls)
+void
+GNUNET_FS_download_signal_suspend_ (void *cls)
 {
   struct GNUNET_FS_DownloadContext *dc = cls;
+  struct GNUNET_FS_ProgressInfo pi;
   
-  GNUNET_FS_end_top (dc->h, dc->top);
-  /* FIXME: signal! */
+  if (dc->top != NULL)
+    GNUNET_FS_end_top (dc->h, dc->top);
+  while (NULL != dc->child_head)
+    GNUNET_FS_download_signal_suspend_ (dc->child_head);  
+  if (dc->search != NULL)
+    {
+      dc->search->download = NULL;
+      dc->search = NULL;
+    }
+  if (dc->job_queue != NULL)
+    {
+      GNUNET_FS_dequeue_ (dc->job_queue);
+      dc->job_queue = NULL;
+    }
+  if (dc->parent != NULL)
+    GNUNET_CONTAINER_DLL_remove (dc->parent->child_head,
+                                dc->parent->child_tail,
+                                dc);  
+  pi.status = GNUNET_FS_STATUS_DOWNLOAD_SUSPEND;
+  GNUNET_FS_download_make_status_ (&pi, dc);
+  if (GNUNET_SCHEDULER_NO_TASK != dc->task)
+    GNUNET_SCHEDULER_cancel (dc->h->sched,
+                            dc->task);
+  GNUNET_CONTAINER_multihashmap_iterate (dc->active,
+                                        &free_entry,
+                                        NULL);
+  GNUNET_CONTAINER_multihashmap_destroy (dc->active);
+  GNUNET_free_non_null (dc->filename);
+  GNUNET_CONTAINER_meta_data_destroy (dc->meta);
+  GNUNET_FS_uri_destroy (dc->uri);
+  GNUNET_free_non_null (dc->temp_filename);
+  GNUNET_free_non_null (dc->serialization);
   GNUNET_free (dc);
 }
 
@@ -1504,7 +1558,12 @@ GNUNET_FS_download_start (struct GNUNET_FS_Handle *h,
              "Download tree has depth %u\n",
              dc->treedepth);
 #endif
-  // FIXME: make persistent
+  if (parent == NULL)
+    {
+      dc->top = GNUNET_FS_make_top (dc->h,
+                                   &GNUNET_FS_download_signal_suspend_,
+                                   dc);
+    }
   pi.status = GNUNET_FS_STATUS_DOWNLOAD_START;
   pi.value.download.specifics.start.meta = meta;
   GNUNET_FS_download_make_status_ (&pi, dc);
@@ -1512,12 +1571,8 @@ GNUNET_FS_download_start (struct GNUNET_FS_Handle *h,
                           &dc->uri->data.chk.chk,
                           0, 
                           1 /* 0 == CHK, 1 == top */); 
+  GNUNET_FS_download_sync_ (dc);
   GNUNET_FS_download_start_downloading_ (dc);
-  if (parent == NULL)
-    dc->top = GNUNET_FS_make_top (dc->h,
-                                 &download_signal_suspend,
-                                 dc);
-
   return dc;
 }
 
@@ -1633,7 +1688,6 @@ GNUNET_FS_download_start_from_search (struct GNUNET_FS_Handle *h,
              "Download tree has depth %u\n",
              dc->treedepth);
 #endif
-  // FIXME: make persistent
   pi.status = GNUNET_FS_STATUS_DOWNLOAD_START;
   pi.value.download.specifics.start.meta = dc->meta;
   GNUNET_FS_download_make_status_ (&pi, dc);
@@ -1641,6 +1695,7 @@ GNUNET_FS_download_start_from_search (struct GNUNET_FS_Handle *h,
                           &dc->uri->data.chk.chk,
                           0, 
                           1 /* 0 == CHK, 1 == top */); 
+  GNUNET_FS_download_sync_ (dc);
   GNUNET_FS_download_start_downloading_ (dc);
   return dc;  
 }
@@ -1654,6 +1709,7 @@ GNUNET_FS_download_start_from_search (struct GNUNET_FS_Handle *h,
 void
 GNUNET_FS_download_start_downloading_ (struct GNUNET_FS_DownloadContext *dc)
 {
+  GNUNET_assert (dc->job_queue == NULL);
   dc->job_queue = GNUNET_FS_queue_ (dc->h, 
                                    &activate_fs_download,
                                    &deactivate_fs_download,
@@ -1662,24 +1718,6 @@ GNUNET_FS_download_start_downloading_ (struct GNUNET_FS_DownloadContext *dc)
 }
 
 
-/**
- * Free entries in the map.
- *
- * @param cls unused (NULL)
- * @param key unused
- * @param entry entry of type "struct DownloadRequest" which is freed
- * @return GNUNET_OK
- */
-static int
-free_entry (void *cls,
-           const GNUNET_HashCode *key,
-           void *entry)
-{
-  GNUNET_free (entry);
-  return GNUNET_OK;
-}
-
-
 /**
  * Stop a download (aborts if download is incomplete).
  *
@@ -1691,6 +1729,7 @@ GNUNET_FS_download_stop (struct GNUNET_FS_DownloadContext *dc,
                         int do_delete)
 {
   struct GNUNET_FS_ProgressInfo pi;
+  int have_children;
 
   if (dc->top != NULL)
     GNUNET_FS_end_top (dc->h, dc->top);
@@ -1704,15 +1743,27 @@ GNUNET_FS_download_stop (struct GNUNET_FS_DownloadContext *dc,
       GNUNET_FS_dequeue_ (dc->job_queue);
       dc->job_queue = NULL;
     }
+  have_children = (NULL != dc->child_head) ? GNUNET_YES : GNUNET_NO;
   while (NULL != dc->child_head)
     GNUNET_FS_download_stop (dc->child_head, 
                             do_delete);
-  // FIXME: make unpersistent  
   if (dc->parent != NULL)
     GNUNET_CONTAINER_DLL_remove (dc->parent->child_head,
                                 dc->parent->child_tail,
-                                dc);
-  
+                                dc);  
+  if (dc->serialization != NULL)
+    GNUNET_FS_remove_sync_file_ (dc->h,
+                                ( (dc->parent != NULL)  || (dc->search != NULL) )
+                                ? GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD 
+                                : GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD , 
+                                dc->serialization);
+  if ( (GNUNET_YES == have_children) &&
+       (dc->parent == NULL) )
+    GNUNET_FS_remove_sync_dir_ (dc->h, 
+                               (dc->search != NULL) 
+                               ? GNUNET_FS_SYNC_PATH_CHILD_DOWNLOAD 
+                               : GNUNET_FS_SYNC_PATH_MASTER_DOWNLOAD,
+                               dc->serialization);  
   pi.status = GNUNET_FS_STATUS_DOWNLOAD_STOPPED;
   GNUNET_FS_download_make_status_ (&pi, dc);
   if (GNUNET_SCHEDULER_NO_TASK != dc->task)
@@ -1744,7 +1795,6 @@ GNUNET_FS_download_stop (struct GNUNET_FS_DownloadContext *dc,
                                  dc->temp_filename);
       GNUNET_free (dc->temp_filename);
     }
-  /* FIXME: clean up serialization file itself! */
   GNUNET_free_non_null (dc->serialization);
   GNUNET_free (dc);
 }