/* return a count of how many contiguous blocks there are starting at this pos */ static int getBlockRun (const tr_cache * cache, int pos, struct run_info * info) { int i; const int n = tr_ptrArraySize (&cache->blocks); const struct cache_block * const * blocks = (const struct cache_block* const *) tr_ptrArrayBase (&cache->blocks); const struct cache_block * ref = blocks[pos]; tr_block_index_t block = ref->block; for (i=pos; i<n; ++i, ++block) { const struct cache_block * b = blocks[i]; if (b->block != block) break; if (b->tor != ref->tor) break; //fprintf (stderr, "pos %d tor %d block %zu time %zu\n", i, b->tor->uniqueId, (size_t)b->block, (size_t)b->time); } //fprintf (stderr, "run is %d long from [%d to %d)\n", (int)(i-pos), i, (int)pos); if (info != NULL) { const struct cache_block * b = blocks[i-1]; info->last_block_time = b->time; info->is_piece_done = tr_torrentPieceIsComplete (b->tor, b->piece); info->is_multi_piece = b->piece != blocks[pos]->piece; info->len = i - pos; info->pos = pos; } return i-pos; }
/* return a count of how many contiguous blocks there are starting at this pos */ static int getBlockRun(tr_cache const* cache, int pos, struct run_info* info) { int const n = tr_ptrArraySize(&cache->blocks); struct cache_block const* const* blocks = (struct cache_block const* const*)tr_ptrArrayBase(&cache->blocks); struct cache_block const* ref = blocks[pos]; tr_block_index_t block = ref->block; int len = 0; for (int i = pos; i < n; ++i, ++block, ++len) { struct cache_block const* b = blocks[i]; if (b->block != block) { break; } if (b->tor != ref->tor) { break; } // fprintf(stderr, "pos %d tor %d block %zu time %zu\n", i, b->tor->uniqueId, (size_t)b->block, (size_t)b->time); } // fprintf(stderr, "run is %d long from [%d to %d)\n", len, pos, pos + len); if (info != NULL) { struct cache_block const* b = blocks[pos + len - 1]; info->last_block_time = b->time; info->is_piece_done = tr_torrentPieceIsComplete(b->tor, b->piece); info->is_multi_piece = b->piece != blocks[pos]->piece; info->len = len; info->pos = pos; } return len; }
static bool verifyTorrent(tr_torrent* tor, bool* stopFlag) { time_t end; tr_sha1_ctx_t sha; tr_sys_file_t fd = TR_BAD_SYS_FILE; uint64_t filePos = 0; bool changed = false; bool hadPiece = false; time_t lastSleptAt = 0; uint32_t piecePos = 0; tr_file_index_t fileIndex = 0; tr_file_index_t prevFileIndex = !fileIndex; tr_piece_index_t pieceIndex = 0; time_t const begin = tr_time(); size_t const buflen = 1024 * 128; /* 128 KiB buffer */ uint8_t* buffer = tr_valloc(buflen); sha = tr_sha1_init(); tr_logAddTorDbg(tor, "%s", "verifying torrent..."); tr_torrentSetChecked(tor, 0); while (!*stopFlag && pieceIndex < tor->info.pieceCount) { uint64_t leftInPiece; uint64_t bytesThisPass; uint64_t leftInFile; tr_file const* file = &tor->info.files[fileIndex]; /* if we're starting a new piece... */ if (piecePos == 0) { hadPiece = tr_torrentPieceIsComplete(tor, pieceIndex); } /* if we're starting a new file... */ if (filePos == 0 && fd == TR_BAD_SYS_FILE && fileIndex != prevFileIndex) { char* filename = tr_torrentFindFile(tor, fileIndex); fd = filename == NULL ? TR_BAD_SYS_FILE : tr_sys_file_open(filename, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, NULL); tr_free(filename); prevFileIndex = fileIndex; } /* figure out how much we can read this pass */ leftInPiece = tr_torPieceCountBytes(tor, pieceIndex) - piecePos; leftInFile = file->length - filePos; bytesThisPass = MIN(leftInFile, leftInPiece); bytesThisPass = MIN(bytesThisPass, buflen); /* read a bit */ if (fd != TR_BAD_SYS_FILE) { uint64_t numRead; if (tr_sys_file_read_at(fd, buffer, bytesThisPass, filePos, &numRead, NULL) && numRead > 0) { bytesThisPass = numRead; tr_sha1_update(sha, buffer, bytesThisPass); #if defined HAVE_POSIX_FADVISE && defined POSIX_FADV_DONTNEED (void)posix_fadvise(fd, filePos, bytesThisPass, POSIX_FADV_DONTNEED); #endif } } /* move our offsets */ leftInPiece -= bytesThisPass; leftInFile -= bytesThisPass; piecePos += bytesThisPass; filePos += bytesThisPass; /* if we're finishing a piece... */ if (leftInPiece == 0) { time_t now; bool hasPiece; uint8_t hash[SHA_DIGEST_LENGTH]; tr_sha1_final(sha, hash); hasPiece = memcmp(hash, tor->info.pieces[pieceIndex].hash, SHA_DIGEST_LENGTH) == 0; if (hasPiece || hadPiece) { tr_torrentSetHasPiece(tor, pieceIndex, hasPiece); changed |= hasPiece != hadPiece; } tr_torrentSetPieceChecked(tor, pieceIndex); now = tr_time(); tor->anyDate = now; /* sleeping even just a few msec per second goes a long * way towards reducing IO load... */ if (lastSleptAt != now) { lastSleptAt = now; tr_wait_msec(MSEC_TO_SLEEP_PER_SECOND_DURING_VERIFY); } sha = tr_sha1_init(); pieceIndex++; piecePos = 0; } /* if we're finishing a file... */ if (leftInFile == 0) { if (fd != TR_BAD_SYS_FILE) { tr_sys_file_close(fd, NULL); fd = TR_BAD_SYS_FILE; } fileIndex++; filePos = 0; } } /* cleanup */ if (fd != TR_BAD_SYS_FILE) { tr_sys_file_close(fd, NULL); } tr_sha1_final(sha, NULL); free(buffer); /* stopwatch */ end = tr_time(); tr_logAddTorDbg(tor, "Verification is done. It took %d seconds to verify %" PRIu64 " bytes (%" PRIu64 " bytes per second)", (int)(end - begin), tor->info.totalSize, (uint64_t)(tor->info.totalSize / (1 + (end - begin)))); return changed; }
static bool verifyTorrent (tr_torrent * tor, bool * stopFlag) { time_t end; SHA_CTX sha; int fd = -1; int64_t filePos = 0; bool changed = 0; bool hadPiece = 0; time_t lastSleptAt = 0; uint32_t piecePos = 0; tr_file_index_t fileIndex = 0; tr_file_index_t prevFileIndex = !fileIndex; tr_piece_index_t pieceIndex = 0; const time_t begin = tr_time (); const size_t buflen = 1024 * 128; /* 128 KiB buffer */ uint8_t * buffer = tr_valloc (buflen); SHA1_Init (&sha); tr_logAddTorDbg (tor, "%s", "verifying torrent..."); tr_torrentSetChecked (tor, 0); while (!*stopFlag && (pieceIndex < tor->info.pieceCount)) { uint32_t leftInPiece; uint32_t bytesThisPass; uint64_t leftInFile; const tr_file * file = &tor->info.files[fileIndex]; /* if we're starting a new piece... */ if (piecePos == 0) hadPiece = tr_torrentPieceIsComplete (tor, pieceIndex); /* if we're starting a new file... */ if (!filePos && (fd<0) && (fileIndex!=prevFileIndex)) { char * filename = tr_torrentFindFile (tor, fileIndex); fd = filename == NULL ? -1 : tr_open_file_for_scanning (filename); tr_free (filename); prevFileIndex = fileIndex; } /* figure out how much we can read this pass */ leftInPiece = tr_torPieceCountBytes (tor, pieceIndex) - piecePos; leftInFile = file->length - filePos; bytesThisPass = MIN (leftInFile, leftInPiece); bytesThisPass = MIN (bytesThisPass, buflen); /* read a bit */ if (fd >= 0) { const ssize_t numRead = tr_pread (fd, buffer, bytesThisPass, filePos); if (numRead > 0) { bytesThisPass = (uint32_t)numRead; SHA1_Update (&sha, buffer, bytesThisPass); #if defined HAVE_POSIX_FADVISE && defined POSIX_FADV_DONTNEED posix_fadvise (fd, filePos, bytesThisPass, POSIX_FADV_DONTNEED); #endif } } /* move our offsets */ leftInPiece -= bytesThisPass; leftInFile -= bytesThisPass; piecePos += bytesThisPass; filePos += bytesThisPass; /* if we're finishing a piece... */ if (leftInPiece == 0) { time_t now; bool hasPiece; uint8_t hash[SHA_DIGEST_LENGTH]; SHA1_Final (hash, &sha); hasPiece = !memcmp (hash, tor->info.pieces[pieceIndex].hash, SHA_DIGEST_LENGTH); if (hasPiece || hadPiece) { tr_torrentSetHasPiece (tor, pieceIndex, hasPiece); changed |= hasPiece != hadPiece; } tr_torrentSetPieceChecked (tor, pieceIndex); now = tr_time (); tor->anyDate = now; /* sleeping even just a few msec per second goes a long * way towards reducing IO load... */ if (lastSleptAt != now) { lastSleptAt = now; tr_wait_msec (MSEC_TO_SLEEP_PER_SECOND_DURING_VERIFY); } SHA1_Init (&sha); pieceIndex++; piecePos = 0; } /* if we're finishing a file... */ if (leftInFile == 0) { if (fd >= 0) { tr_close_file (fd); fd = -1; } fileIndex++; filePos = 0; } } /* cleanup */ if (fd >= 0) tr_close_file (fd); free (buffer); /* stopwatch */ end = tr_time (); tr_logAddTorDbg (tor, "Verification is done. It took %d seconds to verify %"PRIu64" bytes (%"PRIu64" bytes per second)", (int)(end-begin), tor->info.totalSize, (uint64_t)(tor->info.totalSize/ (1+ (end-begin)))); return changed; }