aboutsummaryrefslogtreecommitdiff
path: root/src/fs/fs_download.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-04-26 15:25:27 +0000
committerChristian Grothoff <christian@grothoff.org>2010-04-26 15:25:27 +0000
commite6674963348824eb7d8bdfdc0e2d655ca9773a40 (patch)
treea46baf117e9b403de3ad618a3e5a85e2f616d278 /src/fs/fs_download.c
parent4868c316f36cbefb52e7823b7852a20373389a68 (diff)
downloadgnunet-e6674963348824eb7d8bdfdc0e2d655ca9773a40.tar.gz
gnunet-e6674963348824eb7d8bdfdc0e2d655ca9773a40.zip
fully implement in-line files in directories
Diffstat (limited to 'src/fs/fs_download.c')
-rw-r--r--src/fs/fs_download.c294
1 files changed, 165 insertions, 129 deletions
diff --git a/src/fs/fs_download.c b/src/fs/fs_download.c
index b179c70dc..8194ad9f5 100644
--- a/src/fs/fs_download.c
+++ b/src/fs/fs_download.c
@@ -532,11 +532,132 @@ trigger_recursive_download (void *cls,
532 const struct GNUNET_FS_Uri *uri, 532 const struct GNUNET_FS_Uri *uri,
533 const struct GNUNET_CONTAINER_MetaData *meta, 533 const struct GNUNET_CONTAINER_MetaData *meta,
534 size_t length, 534 size_t length,
535 const void *data);
536
537
538/**
539 * We're done downloading a directory. Open the file and
540 * trigger all of the (remaining) child downloads.
541 *
542 * @param dc context of download that just completed
543 */
544static void
545full_recursive_download (struct GNUNET_FS_DownloadContext *dc)
546{
547 size_t size;
548 uint64_t size64;
549 void *data;
550 struct GNUNET_DISK_FileHandle *h;
551 struct GNUNET_DISK_MapHandle *m;
552
553 size64 = GNUNET_FS_uri_chk_get_file_size (dc->uri);
554 size = (size_t) size64;
555 if (size64 != (uint64_t) size)
556 {
557 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
558 _("Recursive downloads of directories larger than 4 GB are not supported on 32-bit systems\n"));
559 return;
560 }
561 if (dc->filename != NULL)
562 {
563 h = GNUNET_DISK_file_open (dc->filename,
564 GNUNET_DISK_OPEN_READ,
565 GNUNET_DISK_PERM_NONE);
566 }
567 else
568 {
569 GNUNET_assert (dc->temp_filename != NULL);
570 h = GNUNET_DISK_file_open (dc->temp_filename,
571 GNUNET_DISK_OPEN_READ,
572 GNUNET_DISK_PERM_NONE);
573 }
574 if (h == NULL)
575 return; /* oops */
576 data = GNUNET_DISK_file_map (h, &m, GNUNET_DISK_MAP_TYPE_READ, size);
577 if (data == NULL)
578 {
579 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
580 _("Directory too large for system address space\n"));
581 }
582 else
583 {
584 GNUNET_FS_directory_list_contents (size,
585 data,
586 0,
587 &trigger_recursive_download,
588 dc);
589 GNUNET_DISK_file_unmap (m);
590 }
591 GNUNET_DISK_file_close (h);
592 if (dc->filename == NULL)
593 {
594 if (0 != UNLINK (dc->temp_filename))
595 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
596 "unlink",
597 dc->temp_filename);
598 GNUNET_free (dc->temp_filename);
599 dc->temp_filename = NULL;
600 }
601}
602
603
604/**
605 * Check if all child-downloads have completed and
606 * if so, signal completion (and possibly recurse to
607 * parent).
608 */
609static void
610check_completed (struct GNUNET_FS_DownloadContext *dc)
611{
612 struct GNUNET_FS_ProgressInfo pi;
613 struct GNUNET_FS_DownloadContext *pos;
614
615 pos = dc->child_head;
616 while (pos != NULL)
617 {
618 if ( (pos->emsg == NULL) &&
619 (pos->completed < pos->length) )
620 return; /* not done yet */
621 if ( (pos->child_head != NULL) &&
622 (pos->has_finished != GNUNET_YES) )
623 return; /* not transitively done yet */
624 pos = pos->next;
625 }
626 dc->has_finished = GNUNET_YES;
627 /* signal completion */
628 pi.status = GNUNET_FS_STATUS_DOWNLOAD_COMPLETED;
629 make_download_status (&pi, dc);
630 dc->client_info = dc->h->upcb (dc->h->upcb_cls,
631 &pi);
632 if (dc->parent != NULL)
633 check_completed (dc->parent);
634}
635
636
637/**
638 * We found an entry in a directory. Check if the respective child
639 * already exists and if not create the respective child download.
640 *
641 * @param cls the parent download
642 * @param filename name of the file in the directory
643 * @param uri URI of the file (CHK or LOC)
644 * @param meta meta data of the file
645 * @param length number of bytes in data
646 * @param data contents of the file (or NULL if they were not inlined)
647 */
648static void
649trigger_recursive_download (void *cls,
650 const char *filename,
651 const struct GNUNET_FS_Uri *uri,
652 const struct GNUNET_CONTAINER_MetaData *meta,
653 size_t length,
535 const void *data) 654 const void *data)
536{ 655{
537 struct GNUNET_FS_DownloadContext *dc = cls; 656 struct GNUNET_FS_DownloadContext *dc = cls;
538 struct GNUNET_FS_DownloadContext *cpos; 657 struct GNUNET_FS_DownloadContext *cpos;
539 struct GNUNET_DISK_FileHandle *fh; 658 struct GNUNET_DISK_FileHandle *fh;
659 char *temp_name;
660 const char *real_name;
540 char *fn; 661 char *fn;
541 char *us; 662 char *us;
542 char *ext; 663 char *ext;
@@ -632,45 +753,48 @@ trigger_recursive_download (void *cls,
632 GNUNET_free_non_null (fn); 753 GNUNET_free_non_null (fn);
633 return; 754 return;
634 } 755 }
635 756
636 if (data != NULL) 757 temp_name = NULL;
758 if ( (data != NULL) &&
759 (GNUNET_FS_uri_chk_get_file_size (uri) == length) )
637 { 760 {
638 if (full_name != NULL) 761 if (full_name == NULL)
639 { 762 {
640 fh = GNUNET_DISK_file_open (full_name, 763 temp_name = GNUNET_DISK_mktemp ("gnunet-directory-download-tmp");
641 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE | GNUNET_DISK_OPEN_CREATE, 764 real_name = temp_name;
642 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
643 if (fh == NULL)
644 {
645 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
646 "open",
647 full_name);
648 GNUNET_free (full_name);
649 GNUNET_free_non_null (fn);
650 return;
651 }
652 if (length !=
653 GNUNET_DISK_file_write (fh,
654 data,
655 length))
656 {
657 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
658 "write",
659 full_name);
660 }
661 GNUNET_DISK_file_close (fh);
662 } 765 }
663 else 766 else
664 { 767 {
665 /* FIXME: generate 'progress' events and move to 768 real_name = full_name;
666 instant completion! */
667 GNUNET_break (0); // FIXME: not implemented
668 } 769 }
770 /* write to disk, then trigger normal download which will instantly progress to completion */
771 fh = GNUNET_DISK_file_open (real_name,
772 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE | GNUNET_DISK_OPEN_CREATE,
773 GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
774 if (fh == NULL)
775 {
776 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
777 "open",
778 real_name);
779 GNUNET_free (full_name);
780 GNUNET_free_non_null (fn);
781 return;
782 }
783 if (length !=
784 GNUNET_DISK_file_write (fh,
785 data,
786 length))
787 {
788 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
789 "write",
790 full_name);
791 }
792 GNUNET_DISK_file_close (fh);
669 } 793 }
670 GNUNET_FS_download_start (dc->h, 794 GNUNET_FS_download_start (dc->h,
671 uri, 795 uri,
672 meta, 796 meta,
673 full_name, 797 full_name, temp_name,
674 0, 798 0,
675 GNUNET_FS_uri_chk_get_file_size (uri), 799 GNUNET_FS_uri_chk_get_file_size (uri),
676 dc->anonymity, 800 dc->anonymity,
@@ -678,110 +802,12 @@ trigger_recursive_download (void *cls,
678 NULL, 802 NULL,
679 dc); 803 dc);
680 GNUNET_free_non_null (full_name); 804 GNUNET_free_non_null (full_name);
805 GNUNET_free_non_null (temp_name);
681 GNUNET_free_non_null (fn); 806 GNUNET_free_non_null (fn);
682} 807}
683 808
684 809
685/** 810/**
686 * We're done downloading a directory. Open the file and
687 * trigger all of the (remaining) child downloads.
688 *
689 * @param dc context of download that just completed
690 */
691static void
692full_recursive_download (struct GNUNET_FS_DownloadContext *dc)
693{
694 size_t size;
695 uint64_t size64;
696 void *data;
697 struct GNUNET_DISK_FileHandle *h;
698 struct GNUNET_DISK_MapHandle *m;
699
700 size64 = GNUNET_FS_uri_chk_get_file_size (dc->uri);
701 size = (size_t) size64;
702 if (size64 != (uint64_t) size)
703 {
704 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
705 _("Recursive downloads of directories larger than 4 GB are not supported on 32-bit systems\n"));
706 return;
707 }
708 if (dc->filename != NULL)
709 {
710 h = GNUNET_DISK_file_open (dc->filename,
711 GNUNET_DISK_OPEN_READ,
712 GNUNET_DISK_PERM_NONE);
713 }
714 else
715 {
716 GNUNET_assert (dc->temp_filename != NULL);
717 h = GNUNET_DISK_file_open (dc->temp_filename,
718 GNUNET_DISK_OPEN_READ,
719 GNUNET_DISK_PERM_NONE);
720 }
721 if (h == NULL)
722 return; /* oops */
723 data = GNUNET_DISK_file_map (h, &m, GNUNET_DISK_MAP_TYPE_READ, size);
724 if (data == NULL)
725 {
726 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
727 _("Directory too large for system address space\n"));
728 }
729 else
730 {
731 GNUNET_FS_directory_list_contents (size,
732 data,
733 0,
734 &trigger_recursive_download,
735 dc);
736 GNUNET_DISK_file_unmap (m);
737 }
738 GNUNET_DISK_file_close (h);
739 if (dc->filename == NULL)
740 {
741 if (0 != UNLINK (dc->temp_filename))
742 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
743 "unlink",
744 dc->temp_filename);
745 GNUNET_free (dc->temp_filename);
746 dc->temp_filename = NULL;
747 }
748}
749
750
751/**
752 * Check if all child-downloads have completed and
753 * if so, signal completion (and possibly recurse to
754 * parent).
755 */
756static void
757check_completed (struct GNUNET_FS_DownloadContext *dc)
758{
759 struct GNUNET_FS_ProgressInfo pi;
760 struct GNUNET_FS_DownloadContext *pos;
761
762 pos = dc->child_head;
763 while (pos != NULL)
764 {
765 if ( (pos->emsg == NULL) &&
766 (pos->completed < pos->length) )
767 return; /* not done yet */
768 if ( (pos->child_head != NULL) &&
769 (pos->has_finished != GNUNET_YES) )
770 return; /* not transitively done yet */
771 pos = pos->next;
772 }
773 dc->has_finished = GNUNET_YES;
774 /* signal completion */
775 pi.status = GNUNET_FS_STATUS_DOWNLOAD_COMPLETED;
776 make_download_status (&pi, dc);
777 dc->client_info = dc->h->upcb (dc->h->upcb_cls,
778 &pi);
779 if (dc->parent != NULL)
780 check_completed (dc->parent);
781}
782
783
784/**
785 * Iterator over entries in the pending requests in the 'active' map for the 811 * Iterator over entries in the pending requests in the 'active' map for the
786 * reply that we just got. 812 * reply that we just got.
787 * 813 *
@@ -1264,6 +1290,10 @@ try_reconnect (struct GNUNET_FS_DownloadContext *dc)
1264 * @param meta known metadata for the file (can be NULL) 1290 * @param meta known metadata for the file (can be NULL)
1265 * @param filename where to store the file, maybe NULL (then no file is 1291 * @param filename where to store the file, maybe NULL (then no file is
1266 * created on disk and data must be grabbed from the callbacks) 1292 * created on disk and data must be grabbed from the callbacks)
1293 * @param tempname where to store temporary file data, not used if filename is non-NULL;
1294 * can be NULL (in which case we will pick a name if needed); the temporary file
1295 * may already exist, in which case we will try to use the data that is there and
1296 * if it is not what is desired, will overwrite it
1267 * @param offset at what offset should we start the download (typically 0) 1297 * @param offset at what offset should we start the download (typically 0)
1268 * @param length how many bytes should be downloaded starting at offset 1298 * @param length how many bytes should be downloaded starting at offset
1269 * @param anonymity anonymity level to use for the download 1299 * @param anonymity anonymity level to use for the download
@@ -1278,6 +1308,7 @@ GNUNET_FS_download_start (struct GNUNET_FS_Handle *h,
1278 const struct GNUNET_FS_Uri *uri, 1308 const struct GNUNET_FS_Uri *uri,
1279 const struct GNUNET_CONTAINER_MetaData *meta, 1309 const struct GNUNET_CONTAINER_MetaData *meta,
1280 const char *filename, 1310 const char *filename,
1311 const char *tempname,
1281 uint64_t offset, 1312 uint64_t offset,
1282 uint64_t length, 1313 uint64_t length,
1283 uint32_t anonymity, 1314 uint32_t anonymity,
@@ -1352,7 +1383,12 @@ GNUNET_FS_download_start (struct GNUNET_FS_Handle *h,
1352 dc->treedepth = GNUNET_FS_compute_depth (GNUNET_ntohll(dc->uri->data.chk.file_length)); 1383 dc->treedepth = GNUNET_FS_compute_depth (GNUNET_ntohll(dc->uri->data.chk.file_length));
1353 if ( (filename == NULL) && 1384 if ( (filename == NULL) &&
1354 (is_recursive_download (dc) ) ) 1385 (is_recursive_download (dc) ) )
1355 dc->temp_filename = GNUNET_DISK_mktemp ("gnunet-directory-download-tmp"); 1386 {
1387 if (tempname != NULL)
1388 dc->temp_filename = GNUNET_strdup (tempname);
1389 else
1390 dc->temp_filename = GNUNET_DISK_mktemp ("gnunet-directory-download-tmp");
1391 }
1356 1392
1357#if DEBUG_DOWNLOAD 1393#if DEBUG_DOWNLOAD
1358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,