📄 download.c
字号:
/* This file is part of GNUnet. (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008 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 by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 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.*//** * @file applications/fs/fsui/download.c * @brief download functions * @author Krista Bennett * @author Christian Grothoff */#include "platform.h"#include "gnunet_util.h"#include "gnunet_ecrs_lib.h"#include "gnunet_uritrack_lib.h"#include "gnunet_fsui_lib.h"#include "fsui.h"#define DEBUG_DTM GNUNET_NO/** * Mark the given URI as found in a directory * in URITRACK. */static intlistURIfoundDirectory (const GNUNET_ECRS_FileInfo * fi, const GNUNET_HashCode * key, int isRoot, void *prnt){ GNUNET_FSUI_DownloadList *dl = prnt; if (isRoot == GNUNET_YES) return GNUNET_OK; /* namespace ad, ignore */ GNUNET_URITRACK_add_state (dl->ctx->ectx, dl->ctx->cfg, fi->uri, GNUNET_URITRACK_DIRECTORY_FOUND); return GNUNET_OK;}/** * Start to download a file. */static GNUNET_FSUI_DownloadList *startDownload (struct GNUNET_FSUI_Context *ctx, unsigned int anonymityLevel, int is_recursive, const struct GNUNET_ECRS_URI *uri, const struct GNUNET_MetaData *meta, const char *filename, struct GNUNET_FSUI_SearchList *psearch, GNUNET_FSUI_DownloadList * parent);/** * Initiate a (recursive) download of the given * directory entry. */static inttriggerRecursiveDownload (const GNUNET_ECRS_FileInfo * fi, const GNUNET_HashCode * key, int isRoot, void *prnt){ GNUNET_FSUI_DownloadList *parent = prnt; struct GNUNET_GE_Context *ectx; int i; GNUNET_FSUI_DownloadList *pos; char *filename; char *fullName; char *dotdot; ectx = parent->ctx->ectx; if (isRoot == GNUNET_YES) return GNUNET_OK; /* namespace ad, ignore */ GNUNET_URITRACK_track (ectx, parent->ctx->cfg, fi); for (i = 0; i < parent->completedDownloadsCount; i++) if (GNUNET_ECRS_uri_test_equal (parent->completedDownloads[i], fi->uri)) return GNUNET_OK; /* already complete! */ pos = parent->child; while (pos != NULL) { if (GNUNET_ECRS_uri_test_equal (pos->fi.uri, fi->uri)) return GNUNET_OK; /* already downloading */ pos = pos->next; } filename = GNUNET_meta_data_get_by_type (fi->meta, EXTRACTOR_FILENAME); if (filename == NULL) { char *tmp = GNUNET_ECRS_uri_to_string (fi->uri); GNUNET_GE_ASSERT (ectx, strlen (tmp) >= strlen (GNUNET_ECRS_URI_PREFIX) + strlen (GNUNET_ECRS_FILE_INFIX)); filename = GNUNET_strdup (&tmp [strlen (GNUNET_ECRS_URI_PREFIX) + strlen (GNUNET_ECRS_FILE_INFIX)]); GNUNET_free (tmp); } fullName = GNUNET_malloc (strlen (parent->filename) + 2 + strlen (filename)); strcpy (fullName, parent->filename); strcat (fullName, filename); while (NULL != (dotdot = strstr (fullName, ".."))) dotdot[0] = dotdot[1] = '_'; GNUNET_free (filename);#if DEBUG_DTM GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER, "Starting recursive download of `%s'\n", fullName);#endif startDownload (parent->ctx, parent->anonymityLevel, GNUNET_YES, fi->uri, fi->meta, fullName, parent->search, parent); GNUNET_free (fullName); return GNUNET_OK;}/** * Trigger recursive download. */static voiddownload_recursive (GNUNET_FSUI_DownloadList * dl){ char *dirBlock; int fd; char *fn; size_t totalBytes; struct GNUNET_MetaData *md; totalBytes = GNUNET_ECRS_uri_get_file_size (dl->fi.uri); fn = GNUNET_malloc (strlen (dl->filename) + strlen (GNUNET_DIRECTORY_EXT) + 1); strcpy (fn, dl->filename); fd = strlen (fn) - 1; if (fn[fd] == '/' || fn[fd] == '\\') { fn[fd] = '\0'; strcat (fn, GNUNET_DIRECTORY_EXT); } fd = GNUNET_disk_file_open (dl->ctx->ectx, fn, O_LARGEFILE | O_RDONLY); if (fd != -1) { dirBlock = MMAP (NULL, totalBytes, PROT_READ, MAP_SHARED, fd, 0); if (MAP_FAILED == dirBlock) { GNUNET_GE_LOG_STRERROR_FILE (dl->ctx->ectx, GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_ADMIN | GNUNET_GE_USER, "mmap", fn); } else { md = NULL; GNUNET_ECRS_directory_list_contents (dl->ctx->ectx, dirBlock, totalBytes, &md, &listURIfoundDirectory, dl); if (md != NULL) GNUNET_meta_data_destroy (md); if (dl->is_recursive) { int n; /* load directory, start downloads */ md = NULL; GNUNET_mutex_lock (dl->ctx->lock); n = GNUNET_ECRS_directory_list_contents (dl->ctx->ectx, dirBlock, totalBytes, &md, &triggerRecursiveDownload, dl); GNUNET_mutex_unlock (dl->ctx->lock); if (n == 0) GNUNET_disk_directory_create (dl->ctx->ectx, dl->filename); GNUNET_meta_data_destroy (md); MUNMAP (dirBlock, totalBytes); } } CLOSE (fd); } GNUNET_free (fn);}/** * Update the progress bits (shifting). */static voidupdate_progress_bits(GNUNET_CronTime now, GNUNET_FSUI_DownloadList * dl){ GNUNET_CronTime delta; unsigned int minutes; if (now < dl->lastProgressTime) { GNUNET_GE_BREAK(NULL, 0); return; } delta = now - dl->lastProgressTime; minutes = delta / GNUNET_CRON_MINUTES; if (minutes == 0) return; if (minutes > 64) { dl->progressBits = 0; dl->lastProgressTime = now; return; } dl->progressBits <<= minutes; if (dl->progressBits == 0) dl->lastProgressTime = now; else dl->lastProgressTime += minutes * GNUNET_CRON_MINUTES;}/** * Progress notification from ECRS. Tell FSUI client. */static voiddownloadProgressCallback (unsigned long long totalBytes, unsigned long long completedBytes, GNUNET_CronTime eta, unsigned long long lastBlockOffset, const char *lastBlock, unsigned int lastBlockSize, void *cls){ GNUNET_FSUI_DownloadList *dl = cls; GNUNET_FSUI_Event event; GNUNET_CronTime now; GNUNET_CronTime run_time; now = GNUNET_get_time (); update_progress_bits(now, dl); dl->progressBits |= 1; if (dl->total + 1 == totalBytes) { /* error! */ dl->state = GNUNET_FSUI_ERROR; event.type = GNUNET_FSUI_download_error; event.data.DownloadError.dc.pos = dl; event.data.DownloadError.dc.cctx = dl->cctx; event.data.DownloadError.dc.ppos = dl->parent == &dl->ctx->activeDownloads ? NULL : dl->parent; event.data.DownloadError.dc.pcctx = dl->parent->cctx; event.data.DownloadError.dc.spos = dl->search; event.data.DownloadError.dc.sctx = dl->search == NULL ? NULL : dl->search->cctx; event.data.DownloadError.message = lastBlock; GNUNET_URITRACK_add_state (dl->ctx->ectx, dl->ctx->cfg, dl->fi.uri, GNUNET_URITRACK_DOWNLOAD_ABORTED); dl->ctx->ecb (dl->ctx->ecbClosure, &event); return; } GNUNET_GE_ASSERT (dl->ctx->ectx, dl->total == totalBytes); dl->completed = completedBytes; event.type = GNUNET_FSUI_download_progress; event.data.DownloadProgress.dc.pos = dl; event.data.DownloadProgress.dc.cctx = dl->cctx; event.data.DownloadProgress.dc.ppos = dl->parent == &dl->ctx->activeDownloads ? NULL : dl->parent; event.data.DownloadProgress.dc.pcctx = dl->parent->cctx; event.data.DownloadProgress.dc.spos = dl->search; event.data.DownloadProgress.dc.sctx = dl->search == NULL ? NULL : dl->search->cctx; event.data.DownloadProgress.completed = dl->completed; event.data.DownloadProgress.total = dl->total; event.data.DownloadProgress.last_offset = lastBlockOffset; run_time = now - dl->startTime; if ((dl->total == 0) || (dl->completed == 0)) { eta = now; } else { eta = (GNUNET_CronTime) (dl->startTime + (((double) (run_time) / (double) dl->completed)) * (double) dl->total); if (eta < now) eta = now; } event.data.DownloadProgress.eta = eta; event.data.DownloadProgress.filename = dl->filename; event.data.DownloadProgress.uri = dl->fi.uri; event.data.DownloadProgress.last_block = lastBlock; event.data.DownloadProgress.last_size = lastBlockSize; dl->ctx->ecb (dl->ctx->ecbClosure, &event); if ((lastBlockOffset == 0) && (dl->is_directory == GNUNET_SYSERR)) { /* check if this is a directory */ if ((dl->filename[strlen (dl->filename) - 1] == '/') && (lastBlockSize > strlen (GNUNET_DIRECTORY_MAGIC)) && (0 == strncmp (GNUNET_DIRECTORY_MAGIC, lastBlock, strlen (GNUNET_DIRECTORY_MAGIC)))) dl->is_directory = GNUNET_YES; else dl->is_directory = GNUNET_NO; } if (totalBytes == completedBytes) { dl->state = GNUNET_FSUI_COMPLETED; GNUNET_URITRACK_add_state (dl->ctx->ectx, dl->ctx->cfg, dl->fi.uri, GNUNET_URITRACK_DOWNLOAD_COMPLETED); }}/** * Start to download a file. */static GNUNET_FSUI_DownloadList *startDownload (struct GNUNET_FSUI_Context *ctx, unsigned int anonymityLevel, int is_recursive, const struct GNUNET_ECRS_URI *uri, const struct GNUNET_MetaData *meta, const char *filename, struct GNUNET_FSUI_SearchList *psearch, GNUNET_FSUI_DownloadList * parent){ GNUNET_FSUI_DownloadList *dl; GNUNET_FSUI_Event event; GNUNET_GE_ASSERT (NULL, ctx != NULL); GNUNET_GE_ASSERT (NULL, parent != NULL); if (!(GNUNET_ECRS_uri_test_chk (uri) || GNUNET_ECRS_uri_test_loc (uri))) { GNUNET_GE_BREAK (NULL, 0); /* wrong type of URI! */ return NULL; } dl = GNUNET_malloc (sizeof (GNUNET_FSUI_DownloadList)); memset (dl, 0, sizeof (GNUNET_FSUI_DownloadList)); dl->startTime = 0; /* not run at all so far! */ dl->runTime = 0; /* not run at all so far! */ dl->state = GNUNET_FSUI_PENDING; dl->is_recursive = is_recursive; dl->parent = parent; dl->search = psearch; dl->is_directory = GNUNET_SYSERR; /* don't know */ dl->anonymityLevel = anonymityLevel; dl->ctx = ctx; dl->filename = GNUNET_strdup (filename); dl->fi.uri = GNUNET_ECRS_uri_duplicate (uri); dl->fi.meta = GNUNET_meta_data_duplicate (meta); dl->total = GNUNET_ECRS_uri_get_file_size (uri); dl->child = NULL; dl->cctx = NULL; dl->lastProgressTime = GNUNET_get_time(); dl->progressBits = 1; /* signal start! */ event.type = GNUNET_FSUI_download_started; event.data.DownloadStarted.dc.pos = dl; event.data.DownloadStarted.dc.cctx = NULL; event.data.DownloadStarted.dc.ppos = dl->parent == &ctx->activeDownloads ? NULL : dl->parent; event.data.DownloadStarted.dc.pcctx = dl->parent->cctx; event.data.DownloadStarted.dc.spos = dl->search; event.data.DownloadStarted.dc.sctx = dl->search == NULL ? NULL : dl->search->cctx; event.data.DownloadStarted.total =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -