fix #3704
[oweals/gnunet.git] / src / fs / fs_download.c
index 5d4c6d899128614353dc53dbbaaaaef88d6422f2..79674336e970e20516e371eec33de08bdc3c29cf 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2001-2012 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2001-2012 Christian Grothoff (and other contributing authors)
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -393,10 +393,10 @@ check_completed (struct GNUNET_FS_DownloadContext *dc)
     GNUNET_FS_dequeue_ (dc->job_queue);
     dc->job_queue = NULL;
   }
-  if (GNUNET_SCHEDULER_NO_TASK != dc->task)
+  if (NULL != dc->task)
   {
     GNUNET_SCHEDULER_cancel (dc->task);
-    dc->task = GNUNET_SCHEDULER_NO_TASK;
+    dc->task = NULL;
   }
   if (NULL != dc->rfh)
   {
@@ -450,6 +450,18 @@ try_match_block (struct GNUNET_FS_DownloadContext *dc,
     return;
   if (dr->depth > 0)
   {
+    if ( (dc->offset > 0) ||
+         (dc->length < GNUNET_ntohll (dc->uri->data.chk.file_length)) )
+    {
+      /* NOTE: this test is not tight, but should suffice; the issue
+         here is that 'dr->num_children' may inherently only specify a
+         smaller range than what is in the original file;
+         thus, reconstruction of (some) inner blocks will fail.
+         FIXME: we might eventually want to write a tighter test to
+         maximize the circumstances under which we do succeed with
+         IBlock reconstruction. (need good tests though). */
+      return;
+    }
     complete = GNUNET_YES;
     for (i = 0; i < dr->num_children; i++)
     {
@@ -494,39 +506,43 @@ try_match_block (struct GNUNET_FS_DownloadContext *dc,
     }
     /* write block to disk */
     fn = (NULL != dc->filename) ? dc->filename : dc->temp_filename;
-    fh = GNUNET_DISK_file_open (fn,
-                                GNUNET_DISK_OPEN_READWRITE |
-                                GNUNET_DISK_OPEN_CREATE |
-                                GNUNET_DISK_OPEN_TRUNCATE,
-                                GNUNET_DISK_PERM_USER_READ |
-                                GNUNET_DISK_PERM_USER_WRITE |
-                                GNUNET_DISK_PERM_GROUP_READ |
-                                GNUNET_DISK_PERM_OTHER_READ);
-    if (NULL == fh)
-    {
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn);
-      GNUNET_asprintf (&dc->emsg, _("Failed to open file `%s' for writing"),
-                       fn);
-      GNUNET_DISK_file_close (fh);
-      dr->state = BRS_ERROR;
-      pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR;
-      pi.value.download.specifics.error.message = dc->emsg;
-      GNUNET_FS_download_make_status_ (&pi, dc);
-      return;
-    }
-    if (data_len != GNUNET_DISK_file_write (fh, odata, odata_len))
+    if (NULL != fn)
     {
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", fn);
-      GNUNET_asprintf (&dc->emsg, _("Failed to open file `%s' for writing"),
-                       fn);
+      fh = GNUNET_DISK_file_open (fn,
+                                  GNUNET_DISK_OPEN_READWRITE |
+                                  GNUNET_DISK_OPEN_CREATE |
+                                  GNUNET_DISK_OPEN_TRUNCATE,
+                                  GNUNET_DISK_PERM_USER_READ |
+                                  GNUNET_DISK_PERM_USER_WRITE |
+                                  GNUNET_DISK_PERM_GROUP_READ |
+                                  GNUNET_DISK_PERM_OTHER_READ);
+      if (NULL == fh)
+      {
+        GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn);
+        GNUNET_asprintf (&dc->emsg,
+                         _("Failed to open file `%s' for writing"),
+                         fn);
+        GNUNET_DISK_file_close (fh);
+        dr->state = BRS_ERROR;
+        pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR;
+        pi.value.download.specifics.error.message = dc->emsg;
+        GNUNET_FS_download_make_status_ (&pi, dc);
+        return;
+      }
+      if (data_len != GNUNET_DISK_file_write (fh, odata, odata_len))
+      {
+        GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", fn);
+        GNUNET_asprintf (&dc->emsg, _("Failed to open file `%s' for writing"),
+                         fn);
+        GNUNET_DISK_file_close (fh);
+        dr->state = BRS_ERROR;
+        pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR;
+        pi.value.download.specifics.error.message = dc->emsg;
+        GNUNET_FS_download_make_status_ (&pi, dc);
+        return;
+      }
       GNUNET_DISK_file_close (fh);
-      dr->state = BRS_ERROR;
-      pi.status = GNUNET_FS_STATUS_DOWNLOAD_ERROR;
-      pi.value.download.specifics.error.message = dc->emsg;
-      GNUNET_FS_download_make_status_ (&pi, dc);
-      return;
     }
-    GNUNET_DISK_file_close (fh);
     /* signal success */
     dr->state = BRS_DOWNLOAD_UP;
     dc->completed = dc->length;
@@ -1364,7 +1380,7 @@ do_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct GNUNET_FS_DownloadContext *dc = cls;
   struct GNUNET_CLIENT_Connection *client;
 
-  dc->task = GNUNET_SCHEDULER_NO_TASK;
+  dc->task = NULL;
   client = GNUNET_CLIENT_connect ("fs", dc->h->cfg);
   if (NULL == client)
   {
@@ -1617,10 +1633,10 @@ reconstruct_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct GNUNET_FS_DownloadContext *dc = cls;
 
   /* clean up state from tree encoder */
-  if (dc->task != GNUNET_SCHEDULER_NO_TASK)
+  if (dc->task != NULL)
   {
     GNUNET_SCHEDULER_cancel (dc->task);
-    dc->task = GNUNET_SCHEDULER_NO_TASK;
+    dc->task = NULL;
   }
   if (NULL != dc->rfh)
   {
@@ -1646,7 +1662,7 @@ get_next_block (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct GNUNET_FS_DownloadContext *dc = cls;
 
-  dc->task = GNUNET_SCHEDULER_NO_TASK;
+  dc->task = NULL;
   GNUNET_FS_tree_encoder_next (dc->te);
 }
 
@@ -1850,7 +1866,7 @@ GNUNET_FS_download_start_task_ (void *cls,
   struct GNUNET_DISK_FileHandle *fh;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start task running...\n");
-  dc->task = GNUNET_SCHEDULER_NO_TASK;
+  dc->task = NULL;
   if (0 == dc->length)
   {
     /* no bytes required! */
@@ -2012,10 +2028,10 @@ GNUNET_FS_download_signal_suspend_ (void *cls)
   if (NULL != dc->parent)
     GNUNET_CONTAINER_DLL_remove (dc->parent->child_head, dc->parent->child_tail,
                                  dc);
-  if (GNUNET_SCHEDULER_NO_TASK != dc->task)
+  if (NULL != dc->task)
   {
     GNUNET_SCHEDULER_cancel (dc->task);
-    dc->task = GNUNET_SCHEDULER_NO_TASK;
+    dc->task = NULL;
   }
   pi.status = GNUNET_FS_STATUS_DOWNLOAD_SUSPEND;
   GNUNET_FS_download_make_status_ (&pi, dc);
@@ -2241,11 +2257,7 @@ GNUNET_FS_download_start_from_search (struct GNUNET_FS_Handle *h,
   {
     GNUNET_FS_download_stop (sr->probe_ctx, GNUNET_YES);
     sr->probe_ctx = NULL;
-  }
-  if (GNUNET_SCHEDULER_NO_TASK != sr->probe_ping_task)
-  {
-    GNUNET_SCHEDULER_cancel (sr->probe_ping_task);
-    sr->probe_ping_task = GNUNET_SCHEDULER_NO_TASK;
+    GNUNET_FS_stop_probe_ping_task_ (sr);
   }
   return dc;
 }
@@ -2275,6 +2287,39 @@ GNUNET_FS_download_start_downloading_ (struct GNUNET_FS_DownloadContext *dc)
              dc->job_queue);
 }
 
+/**
+ * Suspend a download.
+ *
+ * @param dc handle for the download
+ */
+void
+GNUNET_FS_download_suspend (struct GNUNET_FS_DownloadContext *dc)
+{
+       deactivate_fs_download(dc);
+}
+
+/**
+ * Resume a suspended download.
+ *
+ * @param dc handle for the download
+ */
+void
+GNUNET_FS_download_resume (struct GNUNET_FS_DownloadContext *dc)
+{
+    struct GNUNET_FS_ProgressInfo pi;
+
+    pi.status = GNUNET_FS_STATUS_DOWNLOAD_ACTIVE;
+    GNUNET_FS_download_make_status_ (&pi, dc);
+
+    dc->job_queue =
+      GNUNET_FS_queue_ (dc->h, &activate_fs_download, &deactivate_fs_download,
+                        dc, (dc->length + DBLOCK_SIZE - 1) / DBLOCK_SIZE,
+                       (0 == (dc->options & GNUNET_FS_DOWNLOAD_IS_PROBE))
+                       ? GNUNET_FS_QUEUE_PRIORITY_NORMAL
+                       : GNUNET_FS_QUEUE_PRIORITY_PROBE);
+
+}
+
 
 /**
  * Stop a download (aborts if download is incomplete).
@@ -2291,10 +2336,10 @@ GNUNET_FS_download_stop (struct GNUNET_FS_DownloadContext *dc, int do_delete)
 
   if (NULL != dc->top)
     GNUNET_FS_end_top (dc->h, dc->top);
-  if (GNUNET_SCHEDULER_NO_TASK != dc->task)
+  if (NULL != dc->task)
   {
     GNUNET_SCHEDULER_cancel (dc->task);
-    dc->task = GNUNET_SCHEDULER_NO_TASK;
+    dc->task = NULL;
   }
   search_was_null = (NULL == dc->search);
   if (NULL != dc->search)