aboutsummaryrefslogtreecommitdiff
path: root/src/fs/fs_download.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs/fs_download.c')
-rw-r--r--src/fs/fs_download.c197
1 files changed, 175 insertions, 22 deletions
diff --git a/src/fs/fs_download.c b/src/fs/fs_download.c
index 3de192e12..46759f495 100644
--- a/src/fs/fs_download.c
+++ b/src/fs/fs_download.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009 Christian Grothoff (and other contributing authors) 3 (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -25,6 +25,8 @@
25 * TODO: 25 * TODO:
26 * - handle recursive downloads (need directory & 26 * - handle recursive downloads (need directory &
27 * fs-level download-parallelism management) 27 * fs-level download-parallelism management)
28 * - handle recursive downloads where directory file is
29 * NOT saved on disk (need temporary file instead then!)
28 * - location URI suppport (can wait, easy) 30 * - location URI suppport (can wait, easy)
29 * - check if blocks exist already (can wait, easy) 31 * - check if blocks exist already (can wait, easy)
30 * - check if iblocks can be computed from existing blocks (can wait, hard) 32 * - check if iblocks can be computed from existing blocks (can wait, hard)
@@ -39,15 +41,12 @@
39#define DEBUG_DOWNLOAD GNUNET_NO 41#define DEBUG_DOWNLOAD GNUNET_NO
40 42
41/** 43/**
42 * We're storing the IBLOCKS after the 44 * We're storing the IBLOCKS after the DBLOCKS on disk (so that we
43 * DBLOCKS on disk (so that we only have 45 * only have to truncate the file once we're done).
44 * to truncate the file once we're done).
45 * 46 *
46 * Given the offset of a block (with respect 47 * Given the offset of a block (with respect to the DBLOCKS) and its
47 * to the DBLOCKS) and its depth, return the 48 * depth, return the offset where we would store this block in the
48 * offset where we would store this block 49 * file.
49 * in the file.
50
51 * 50 *
52 * @param fsize overall file size 51 * @param fsize overall file size
53 * @param off offset of the block in the file 52 * @param off offset of the block in the file
@@ -245,8 +244,7 @@ schedule_block_download (struct GNUNET_FS_DownloadContext *dc,
245 GNUNET_CONSTANTS_SERVICE_TIMEOUT, 244 GNUNET_CONSTANTS_SERVICE_TIMEOUT,
246 GNUNET_NO, 245 GNUNET_NO,
247 &transmit_download_request, 246 &transmit_download_request,
248 dc); 247 dc);
249
250} 248}
251 249
252 250
@@ -341,6 +339,129 @@ struct ProcessResultClosure
341 339
342 340
343/** 341/**
342 * We found an entry in a directory. Check if the respective child
343 * already exists and if not create the respective child download.
344 *
345 * @param cls the parent download
346 * @param filename name of the file in the directory
347 * @param uri URI of the file (CHK or LOC)
348 * @param meta meta data of the file
349 * @param length number of bytes in data
350 * @param data contents of the file (or NULL if they were not inlined)
351 */
352static void
353trigger_recursive_download (void *cls,
354 const char *filename,
355 const struct GNUNET_FS_Uri *uri,
356 const struct GNUNET_CONTAINER_MetaData *meta,
357 size_t length,
358 const void *data)
359{
360 struct GNUNET_FS_DownloadContext *dc = cls;
361 struct GNUNET_FS_DownloadContext *cpos;
362
363 cpos = dc->child_head;
364 while (cpos != NULL)
365 {
366 if (0 == strcmp (cpos->filename,
367 filename))
368 {
369 GNUNET_break_op (GNUNET_FS_uri_test_equal (uri,
370 cpos->uri));
371 break;
372 }
373 cpos = cpos->next;
374 }
375 if (cpos != NULL)
376 return; /* already exists */
377 if (data != NULL)
378 {
379 /* determine on-disk filename, write data! */
380 GNUNET_break (0); // FIXME: not implemented
381 }
382 GNUNET_FS_download_start (dc->h,
383 uri,
384 meta,
385 filename, /* FIXME: prepend directory name! */
386 0,
387 GNUNET_FS_uri_chk_get_file_size (uri),
388 dc->anonymity,
389 dc->options,
390 NULL,
391 dc);
392}
393
394
395/**
396 * We're done downloading a directory. Open the file and
397 * trigger all of the (remaining) child downloads.
398 *
399 * @param dc context of download that just completed
400 */
401static void
402full_recursive_download (struct GNUNET_FS_DownloadContext *dc)
403{
404 size_t size;
405 uint64_t size64;
406 void *data;
407 struct GNUNET_DISK_FileHandle *h;
408 struct GNUNET_DISK_MapHandle *m;
409
410 size64 = GNUNET_FS_uri_chk_get_file_size (dc->uri);
411 size = (size_t) size64;
412 if (size64 != (uint64_t) size)
413 {
414 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
415 _("Recursive downloads of directories larger than 4 GB are not supported on 32-bit systems\n"));
416 return;
417 }
418 if (dc->filename != NULL)
419 {
420 h = GNUNET_DISK_file_open (dc->filename,
421 GNUNET_DISK_OPEN_READ,
422 GNUNET_DISK_PERM_NONE);
423 }
424 else
425 {
426 /* FIXME: need to initialize (and use) temp_filename
427 in various places in order for this assertion to
428 not fail; right now, it will always fail! */
429 GNUNET_assert (dc->temp_filename != NULL);
430 h = GNUNET_DISK_file_open (dc->temp_filename,
431 GNUNET_DISK_OPEN_READ,
432 GNUNET_DISK_PERM_NONE);
433 }
434 if (h == NULL)
435 return; /* oops */
436 data = GNUNET_DISK_file_map (h, &m, GNUNET_DISK_MAP_TYPE_READ, size);
437 if (data == NULL)
438 {
439 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
440 _("Directory too large for system address space\n"));
441 }
442 else
443 {
444 GNUNET_FS_directory_list_contents (size,
445 data,
446 0,
447 &trigger_recursive_download,
448 dc);
449 GNUNET_DISK_file_unmap (m);
450 }
451 GNUNET_DISK_file_close (h);
452 if (dc->filename == NULL)
453 {
454 if (0 != UNLINK (dc->temp_filename))
455 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
456 "unlink",
457 dc->temp_filename);
458 GNUNET_free (dc->temp_filename);
459 dc->temp_filename = NULL;
460 }
461}
462
463
464/**
344 * Iterator over entries in the pending requests in the 'active' map for the 465 * Iterator over entries in the pending requests in the 'active' map for the
345 * reply that we just got. 466 * reply that we just got.
346 * 467 *
@@ -484,6 +605,17 @@ process_result_with_request (void *cls,
484 app -= (sm->offset + prc->size) - (dc->offset + dc->length); 605 app -= (sm->offset + prc->size) - (dc->offset + dc->length);
485 } 606 }
486 dc->completed += app; 607 dc->completed += app;
608
609 if ( (0 != (dc->options & GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE)) &&
610 (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (dc->meta)) )
611 {
612 GNUNET_FS_directory_list_contents (prc->size,
613 pt,
614 off,
615 &trigger_recursive_download,
616 dc);
617 }
618
487 } 619 }
488 620
489 pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS; 621 pi.status = GNUNET_FS_STATUS_DOWNLOAD_PROGRESS;
@@ -513,11 +645,18 @@ process_result_with_request (void *cls,
513 "truncate", 645 "truncate",
514 dc->filename); 646 dc->filename);
515 } 647 }
516 /* signal completion */ 648
517 pi.status = GNUNET_FS_STATUS_DOWNLOAD_COMPLETED; 649 if ( (0 != (dc->options & GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE)) &&
518 make_download_status (&pi, dc); 650 (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (dc->meta)) )
519 dc->client_info = dc->h->upcb (dc->h->upcb_cls, 651 full_recursive_download (dc);
520 &pi); 652 if (dc->child_head == NULL)
653 {
654 /* signal completion */
655 pi.status = GNUNET_FS_STATUS_DOWNLOAD_COMPLETED;
656 make_download_status (&pi, dc);
657 dc->client_info = dc->h->upcb (dc->h->upcb_cls,
658 &pi);
659 }
521 GNUNET_assert (sm->depth == dc->treedepth); 660 GNUNET_assert (sm->depth == dc->treedepth);
522 } 661 }
523 // FIXME: make persistent 662 // FIXME: make persistent
@@ -836,11 +975,6 @@ GNUNET_FS_download_start (struct GNUNET_FS_Handle *h,
836 GNUNET_break (0); 975 GNUNET_break (0);
837 return NULL; 976 return NULL;
838 } 977 }
839 client = GNUNET_CLIENT_connect (h->sched,
840 "fs",
841 h->cfg);
842 if (NULL == client)
843 return NULL;
844 // FIXME: add support for "loc" URIs! 978 // FIXME: add support for "loc" URIs!
845#if DEBUG_DOWNLOAD 979#if DEBUG_DOWNLOAD
846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 980 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -850,8 +984,13 @@ GNUNET_FS_download_start (struct GNUNET_FS_Handle *h,
850#endif 984#endif
851 dc = GNUNET_malloc (sizeof(struct GNUNET_FS_DownloadContext)); 985 dc = GNUNET_malloc (sizeof(struct GNUNET_FS_DownloadContext));
852 dc->h = h; 986 dc->h = h;
853 dc->client = client;
854 dc->parent = parent; 987 dc->parent = parent;
988 if (parent != NULL)
989 {
990 GNUNET_CONTAINER_DLL_insert (parent->child_head,
991 parent->child_tail,
992 dc);
993 }
855 dc->uri = GNUNET_FS_uri_dup (uri); 994 dc->uri = GNUNET_FS_uri_dup (uri);
856 dc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta); 995 dc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
857 dc->client_info = cctx; 996 dc->client_info = cctx;
@@ -897,6 +1036,12 @@ GNUNET_FS_download_start (struct GNUNET_FS_Handle *h,
897 dc->treedepth); 1036 dc->treedepth);
898#endif 1037#endif
899 // FIXME: make persistent 1038 // FIXME: make persistent
1039
1040 // FIXME: bound parallelism here!
1041 client = GNUNET_CLIENT_connect (h->sched,
1042 "fs",
1043 h->cfg);
1044 dc->client = client;
900 schedule_block_download (dc, 1045 schedule_block_download (dc,
901 &dc->uri->data.chk.chk, 1046 &dc->uri->data.chk.chk,
902 0, 1047 0,
@@ -945,7 +1090,15 @@ GNUNET_FS_download_stop (struct GNUNET_FS_DownloadContext *dc,
945{ 1090{
946 struct GNUNET_FS_ProgressInfo pi; 1091 struct GNUNET_FS_ProgressInfo pi;
947 1092
1093 while (NULL != dc->child_head)
1094 GNUNET_FS_download_stop (dc->child_head,
1095 do_delete);
948 // FIXME: make unpersistent 1096 // FIXME: make unpersistent
1097 if (dc->parent != NULL)
1098 GNUNET_CONTAINER_DLL_remove (dc->parent->child_head,
1099 dc->parent->child_tail,
1100 dc);
1101
949 pi.status = GNUNET_FS_STATUS_DOWNLOAD_STOPPED; 1102 pi.status = GNUNET_FS_STATUS_DOWNLOAD_STOPPED;
950 make_download_status (&pi, dc); 1103 make_download_status (&pi, dc);
951 dc->client_info = dc->h->upcb (dc->h->upcb_cls, 1104 dc->client_info = dc->h->upcb (dc->h->upcb_cls,