📄 download.c
字号:
{ GNUNET_hash (data, size, &hc); if (0 == memcmp (&hc, &node->chk.key, sizeof (GNUNET_HashCode))) { notify_client_about_progress (node, data, size); if (node->level > 0) iblock_download_children (node, data, size); ret = GNUNET_YES; } } GNUNET_free (data); return ret;}/** * DOWNLOAD children of this GNUNET_EC_IBlock. * * @param node the node that should be downloaded */static voidiblock_download_children (const struct Node *node, const char *data, unsigned int size){ struct GNUNET_GE_Context *ectx = node->ctx->ectx; int i; struct Node *child; unsigned int childcount; const GNUNET_EC_ContentHashKey *chks; unsigned int levelSize; unsigned long long baseOffset; GNUNET_GE_ASSERT (ectx, node->level > 0); childcount = size / sizeof (GNUNET_EC_ContentHashKey); if (size != childcount * sizeof (GNUNET_EC_ContentHashKey)) { GNUNET_GE_BREAK (ectx, 0); return; } if (node->level == 1) { levelSize = GNUNET_ECRS_DBLOCK_SIZE; baseOffset = node->offset / sizeof (GNUNET_EC_ContentHashKey) * GNUNET_ECRS_DBLOCK_SIZE; } else { levelSize = sizeof (GNUNET_EC_ContentHashKey) * GNUNET_ECRS_CHK_PER_INODE; baseOffset = node->offset * GNUNET_ECRS_CHK_PER_INODE; } chks = (const GNUNET_EC_ContentHashKey *) data; for (i = 0; i < childcount; i++) { child = GNUNET_malloc (sizeof (struct Node)); child->ctx = node->ctx; child->chk = chks[i]; child->offset = baseOffset + i * levelSize; GNUNET_GE_ASSERT (ectx, child->offset < node->ctx->total); child->level = node->level - 1; GNUNET_GE_ASSERT (ectx, (child->level != 0) || ((child->offset % GNUNET_ECRS_DBLOCK_SIZE) == 0)); if (GNUNET_NO == check_node_present (child)) add_request (child); else GNUNET_free (child); /* done already! */ }}/** * Decrypts a given data block * * @param data represents the data block * @param hashcode represents the key concatenated with the initial * value used in the alg * @param result where to store the result (encrypted block) * @returns GNUNET_OK on success, GNUNET_SYSERR on error */static intdecrypt_content (const char *data, unsigned int size, const GNUNET_HashCode * hashcode, char *result){ GNUNET_AES_InitializationVector iv; GNUNET_AES_SessionKey skey; /* get key and init value from the GNUNET_HashCode */ GNUNET_hash_to_AES_key (hashcode, &skey, &iv); return GNUNET_AES_decrypt (&skey, data, size, &iv, result);}/** * We received a GNUNET_EC_ContentHashKey reply for a block. Decrypt. Note * that the caller (fslib) has already aquired the * RM lock (we sometimes aquire it again in callees, * mostly because our callees could be also be theoretically * called from elsewhere). * * @param cls the node for which the reply is given, freed in * the function! * @param query the query for which reply is the answer * @param reply the reply * @return GNUNET_OK if the reply was valid, GNUNET_SYSERR on error */static intcontent_receive_callback (const GNUNET_HashCode * query, const GNUNET_DatastoreValue * reply, void *cls, unsigned long long uid){ struct Node *node = cls; struct GNUNET_ECRS_DownloadContext *rm = node->ctx; struct GNUNET_GE_Context *ectx = rm->ectx; GNUNET_HashCode hc; unsigned int size; char *data; if (rm->abortFlag != GNUNET_NO) return GNUNET_SYSERR; GNUNET_GE_ASSERT (ectx, 0 == memcmp (query, &node->chk.query, sizeof (GNUNET_HashCode))); size = ntohl (reply->size) - sizeof (GNUNET_DatastoreValue); if ((size <= sizeof (GNUNET_EC_DBlock)) || (size - sizeof (GNUNET_EC_DBlock) != get_node_size (node))) { GNUNET_GE_BREAK (ectx, 0); return GNUNET_SYSERR; /* invalid size! */ } size -= sizeof (GNUNET_EC_DBlock); data = GNUNET_malloc (size); if (GNUNET_SYSERR == decrypt_content ((const char *) &((const GNUNET_EC_DBlock *) &reply[1])[1], size, &node->chk.key, data)) GNUNET_GE_ASSERT (ectx, 0); GNUNET_hash (data, size, &hc); if (0 != memcmp (&hc, &node->chk.key, sizeof (GNUNET_HashCode))) { GNUNET_free (data); GNUNET_GE_BREAK (ectx, 0); signal_abort (rm, _("Decrypted content does not match key. " "This is either a bug or a maliciously inserted " "file. Download aborted.\n")); return GNUNET_SYSERR; } if (size != write_to_files (rm, node->level, node->offset, data, size)) { GNUNET_GE_LOG_STRERROR (ectx, GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER | GNUNET_GE_BULK, "WRITE"); signal_abort (rm, _("IO error.")); return GNUNET_SYSERR; } notify_client_about_progress (node, data, size); if (node->level > 0) iblock_download_children (node, data, size); GNUNET_free (data); /* request satisfied, stop requesting! */ delete_node (node); return GNUNET_OK;}/** * Helper function to sanitize filename * and create necessary directories. */static char *get_real_download_filename (struct GNUNET_GE_Context *ectx, const char *filename){ struct stat buf; char *realFN; char *path; char *pos; if ((filename[strlen (filename) - 1] == '/') || (filename[strlen (filename) - 1] == '\\')) { realFN = GNUNET_malloc (strlen (filename) + strlen (GNUNET_DIRECTORY_EXT)); strcpy (realFN, filename); realFN[strlen (filename) - 1] = '\0'; strcat (realFN, GNUNET_DIRECTORY_EXT); } else { realFN = GNUNET_strdup (filename); } path = GNUNET_malloc (strlen (realFN) * strlen (GNUNET_DIRECTORY_EXT) + 1); strcpy (path, realFN); pos = path; while (*pos != '\0') { if (*pos == DIR_SEPARATOR) { *pos = '\0'; if ((0 == STAT (path, &buf)) && (!S_ISDIR (buf.st_mode))) { *pos = DIR_SEPARATOR; memmove (pos + strlen (GNUNET_DIRECTORY_EXT), pos, strlen (pos)); memcpy (pos, GNUNET_DIRECTORY_EXT, strlen (GNUNET_DIRECTORY_EXT)); pos += strlen (GNUNET_DIRECTORY_EXT); } else { *pos = DIR_SEPARATOR; } } pos++; } GNUNET_free (realFN); return path;}/* ***************** main method **************** *//** * Download parts of a file. Note that this will store * the blocks at the respective offset in the given file. * Also, the download is still using the blocking of the * underlying ECRS encoding. As a result, the download * may *write* outside of the given boundaries (if offset * and length do not match the 32k ECRS block boundaries). * <p> * * This function should be used to focus a download towards a * particular portion of the file (optimization), not to strictly * limit the download to exactly those bytes. * * @param uri the URI of the file (determines what to download) * @param filename where to store the file * @param no_temporaries set to GNUNET_YES to disallow generation of temporary files * @param start starting offset * @param length length of the download (starting at offset) */struct GNUNET_ECRS_DownloadContext *GNUNET_ECRS_file_download_partial_start (struct GNUNET_GE_Context *ectx, struct GNUNET_GC_Configuration *cfg, struct GNUNET_FS_SearchContext *sc, const struct GNUNET_ECRS_URI *uri, const char *filename, unsigned long long offset, unsigned long long length, unsigned int anonymityLevel, int no_temporaries, GNUNET_ECRS_DownloadProgressCallback dpcb, void *dpcbClosure){ struct GNUNET_ECRS_DownloadContext *rm; struct stat buf; struct Node *top; int ret; if ((!GNUNET_ECRS_uri_test_chk (uri)) && (!GNUNET_ECRS_uri_test_loc (uri))) { GNUNET_GE_BREAK (ectx, 0); return NULL; } rm = GNUNET_malloc (sizeof (struct GNUNET_ECRS_DownloadContext)); memset (rm, 0, sizeof (struct GNUNET_ECRS_DownloadContext)); if (sc == NULL) { rm->sctx = GNUNET_FS_create_search_context (ectx, cfg); if (rm->sctx == NULL) { GNUNET_free (rm); return NULL; } rm->my_sctx = GNUNET_YES; } else { rm->sctx = sc; rm->my_sctx = GNUNET_NO; } rm->ectx = ectx; rm->cfg = cfg; rm->startTime = GNUNET_get_time (); rm->anonymityLevel = anonymityLevel; rm->offset = offset; rm->length = length; rm->dpcb = dpcb; rm->dpcbClosure = dpcbClosure; rm->main = GNUNET_thread_get_self (); rm->total = GNUNET_ntohll (uri->data.fi.file_length); rm->filename = filename != NULL ? get_real_download_filename (ectx, filename) : NULL; if ((rm->filename != NULL) && (GNUNET_SYSERR == GNUNET_disk_directory_create_for_file (ectx, rm->filename))) { free_request_manager (rm); return NULL; } if (0 == rm->total) { if (rm->filename != NULL) { ret = GNUNET_disk_file_open (ectx, rm->filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); if (ret == -1) { free_request_manager (rm); return NULL; } CLOSE (ret); } dpcb (0, 0, rm->startTime, 0, NULL, 0, dpcbClosure); free_request_manager (rm); return NULL; } rm->treedepth = GNUNET_ECRS_compute_depth (rm->total); if ((NULL != rm->filename) && ((0 == STAT (rm->filename, &buf)) && ((size_t) buf.st_size > rm->total))) { /* if exists and oversized, truncate */ if (truncate (rm->filename, rm->total) != 0) { GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_BULK, "truncate", rm->filename); free_request_manager (rm); return NULL; } } if (rm->filename != NULL) { rm->handle = GNUNET_disk_file_open (ectx, rm->filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (rm->handle < 0) { free_request_manager (rm); return NULL; } } else rm->handle = -1; if (GNUNET_ECRS_uri_test_loc (uri)) { GNUNET_hash (&uri->data.loc.peer, sizeof (GNUNET_RSA_PublicKey), &rm->target.hashPubKey); rm->have_target = GNUNET_YES; } top = GNUNET_malloc (sizeof (struct Node)); memset (top, 0, sizeof (struct Node)); top->ctx = rm; top->chk = uri->data.fi.chk; top->offset = 0; top->level = rm->treedepth; if (GNUNET_NO == check_node_present (top)) add_request (top); else GNUNET_free (top); return rm;}intGNUNET_ECRS_file_download_partial_stop (struct GNUNET_ECRS_DownloadContext *rm){ int ret; ret = rm->abortFlag; free_request_manager (rm); if (ret == GNUNET_NO) ret = GNUNET_OK; /* normal termination */ return ret;}/** * Download parts of a file. Note that this will store * the blocks at the respective offset in the given file. * Also, the download is still using the blocking of the * underlying ECRS encoding. As a result, the download * may *write* outside of the given boundaries (if offset * and length do not match the 32k ECRS block boundaries). * <p> * * This function should be used to focus a download towards a * particular portion of the file (optimization), not to strictly * limit the download to exactly those bytes. * * @param uri the URI of the file (determines what to download) * @param filename where to store the file * @param no_temporaries set to GNUNET_YES to disallow generation of temporary files * @param start starting offset * @param length length of the download (starting at offset) */intGNUNET_ECRS_file_download_partial (struct GNUNET_GE_Context *ectx, struct GNUNET_GC_Configuration *cfg, const struct GNUNET_ECRS_URI *uri, const char *filename, unsigned long long offset, unsigned long long length, unsigned int anonymityLevel, int no_temporaries, GNUNET_ECRS_DownloadProgressCallback dpcb, void *dpcbClosure, GNUNET_ECRS_TestTerminate tt, void *ttClosure){ struct GNUNET_ECRS_DownloadContext *rm; int ret; if (length == 0) return GNUNET_OK; rm = GNUNET_ECRS_file_download_partial_start (ectx, cfg, NULL, uri, filename, offset, length, anonymityLevel, no_temporaries, dpcb, dpcbClosure); if (rm == NULL) return GNUNET_SYSERR; while ((GNUNET_OK == tt (ttClosure)) && (GNUNET_YES != GNUNET_shutdown_test ()) && (rm->abortFlag == GNUNET_NO) && (rm->head != NULL)) GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS); ret = GNUNET_ECRS_file_download_partial_stop (rm); return ret;}/** * Download a file (simplified API). * * @param uri the URI of the file (determines what to download) * @param filename where to store the file */intGNUNET_ECRS_file_download (struct GNUNET_GE_Context *ectx, struct GNUNET_GC_Configuration *cfg, const struct GNUNET_ECRS_URI *uri, const char *filename, unsigned int anonymityLevel, GNUNET_ECRS_DownloadProgressCallback dpcb, void *dpcbClosure, GNUNET_ECRS_TestTerminate tt, void *ttClosure){ return GNUNET_ECRS_file_download_partial (ectx, cfg, uri, filename, 0, GNUNET_ECRS_uri_get_file_size (uri), anonymityLevel, GNUNET_NO, dpcb, dpcbClosure, tt, ttClosure);}/* end of download.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -