static void nap( int roughly_sec ) { const int roughly_msec = roughly_sec * 1000; const int msec = roughly_msec/2 + tr_cryptoWeakRandInt(roughly_msec); tr_wait_msec( msec ); }
static void nap (int roughly_sec) { const int roughly_msec = roughly_sec * 1000; const int msec = roughly_msec/2 + tr_rand_int_weak (roughly_msec); tr_wait_msec (msec); }
void tr_webClose( tr_session * session, tr_web_close_mode close_mode ) { if( session->web != NULL ) { session->web->close_mode = close_mode; if( close_mode == TR_WEB_CLOSE_NOW ) while( session->web != NULL ) tr_wait_msec( 100 ); } }
void tr_eventInit (tr_session * session) { tr_event_handle * eh; session->events = NULL; eh = tr_new0 (tr_event_handle, 1); eh->lock = tr_lockNew (); if (pipe (eh->fds) == -1) tr_logAddError ("Unable to write to pipe() in libtransmission: %s", tr_strerror(errno)); eh->session = session; eh->thread = tr_threadNew (libeventThreadFunc, eh); /* wait until the libevent thread is running */ while (session->events == NULL) tr_wait_msec (100); }
static struct tr_web_task * tr_webRunImpl (tr_session * session, int torrentId, const char * url, const char * range, const char * cookies, tr_web_done_func done_func, void * done_func_user_data, struct evbuffer * buffer) { struct tr_web_task * task = NULL; if (!session->isClosing) { if (session->web == NULL) { tr_threadNew (tr_webThreadFunc, session); while (session->web == NULL) tr_wait_msec (20); } task = tr_new0 (struct tr_web_task, 1); task->session = session; task->torrentId = torrentId; task->url = tr_strdup (url); task->range = tr_strdup (range); task->cookies = tr_strdup (cookies); task->done_func = done_func; task->done_func_user_data = done_func_user_data; task->response = buffer ? buffer : evbuffer_new (); task->freebuf = buffer ? NULL : task->response; tr_lockLock (session->web->taskLock); task->next = session->web->tasks; session->web->tasks = task; tr_lockUnlock (session->web->taskLock); } return task; }
int tr_dhtStatus( tr_session * session, int af, int * nodes_return ) { struct getstatus_closure closure = { af, -1, -1 }; if( !tr_dhtEnabled( session ) || (af == AF_INET && dht_socket < 0) || (af == AF_INET6 && dht6_socket < 0) ) { if( nodes_return ) *nodes_return = 0; return TR_DHT_STOPPED; } tr_runInEventThread( session, getstatus, &closure ); while( closure.status < 0 ) tr_wait_msec( 50 /*msec*/ ); if( nodes_return ) *nodes_return = closure.count; return closure.status; }
/** * Portability wrapper for select(). * * http://msdn.microsoft.com/en-us/library/ms740141%28VS.85%29.aspx * On win32, any two of the parameters, readfds, writefds, or exceptfds, * can be given as null. At least one must be non-null, and any non-null * descriptor set must contain at least one handle to a socket. */ static void tr_select( int nfds, fd_set * r_fd_set, fd_set * w_fd_set, fd_set * c_fd_set, struct timeval * t ) { #ifdef WIN32 if( !r_fd_set->fd_count && !w_fd_set->fd_count && !c_fd_set->fd_count ) { const long int msec = t->tv_sec*1000 + t->tv_usec/1000; tr_wait_msec( msec ); } else if( select( 0, r_fd_set->fd_count ? r_fd_set : NULL, w_fd_set->fd_count ? w_fd_set : NULL, c_fd_set->fd_count ? c_fd_set : NULL, t ) < 0 ) { char errstr[512]; const int e = EVUTIL_SOCKET_ERROR( ); tr_net_strerror( errstr, sizeof( errstr ), e ); dbgmsg( "Error: select (%d) %s", e, errstr ); } #else select( nfds, r_fd_set, w_fd_set, c_fd_set, t ); #endif }
int main (int argc, char * argv[]) { char * out2 = NULL; tr_metainfo_builder * b = NULL; tr_logSetLevel (TR_LOG_ERROR); if (parseCommandLine (argc, (const char**)argv)) return EXIT_FAILURE; if (showVersion) { fprintf (stderr, MY_NAME" "LONG_VERSION_STRING"\n"); return EXIT_SUCCESS; } if (!infile) { fprintf (stderr, "ERROR: No input file or directory specified.\n"); tr_getopt_usage (MY_NAME, getUsage (), options); fprintf (stderr, "\n"); return EXIT_FAILURE; } if (outfile == NULL) { char * base = tr_basename (infile); char * end = tr_strdup_printf ("%s.torrent", base); char * cwd = tr_getcwd (); outfile = out2 = tr_buildPath (cwd, end, NULL); tr_free (cwd); tr_free (end); tr_free (base); } if (!trackerCount) { if (isPrivate) { fprintf (stderr, "ERROR: no trackers specified for a private torrent\n"); return EXIT_FAILURE; } else { printf ("WARNING: no trackers specified\n"); } } printf ("Creating torrent \"%s\" ...", outfile); fflush (stdout); b = tr_metaInfoBuilderCreate (infile); if (piecesize_kib != 0) tr_metaInfoBuilderSetPieceSize (b, piecesize_kib * KiB); tr_makeMetaInfo (b, outfile, trackers, trackerCount, comment, isPrivate); while (!b->isDone) { tr_wait_msec (500); putc ('.', stdout); fflush (stdout); } putc (' ', stdout); switch (b->result) { case TR_MAKEMETA_OK: printf ("done!"); break; case TR_MAKEMETA_URL: printf ("bad announce URL: \"%s\"", b->errfile); break; case TR_MAKEMETA_IO_READ: printf ("error reading \"%s\": %s", b->errfile, tr_strerror (b->my_errno)); break; case TR_MAKEMETA_IO_WRITE: printf ("error writing \"%s\": %s", b->errfile, tr_strerror (b->my_errno)); break; case TR_MAKEMETA_CANCELLED: printf ("cancelled"); break; } putc ('\n', stdout); tr_metaInfoBuilderFree (b); tr_free (out2); return EXIT_SUCCESS; }
static tr_bool verifyTorrent( tr_torrent * tor, tr_bool * stopFlag ) { time_t end; SHA_CTX sha; int fd = -1; int64_t filePos = 0; tr_bool changed = 0; tr_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_tordbg( 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_cpPieceIsComplete( &tor->completion, 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; tr_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_tordbg( 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; }
int main( int argc, char ** argv ) { int c; const char * optarg; tr_benc settings; tr_bool boolVal; tr_bool loaded; tr_bool foreground = FALSE; tr_bool dumpSettings = FALSE; const char * configDir = NULL; const char * pid_filename; dtr_watchdir * watchdir = NULL; FILE * logfile = NULL; tr_bool pidfile_created = FALSE; signal( SIGINT, gotsig ); signal( SIGTERM, gotsig ); #ifndef WIN32 signal( SIGHUP, gotsig ); #endif /* load settings from defaults + config file */ tr_bencInitDict( &settings, 0 ); tr_bencDictAddBool( &settings, TR_PREFS_KEY_RPC_ENABLED, TRUE ); configDir = getConfigDir( argc, (const char**)argv ); loaded = tr_sessionLoadSettings( &settings, configDir, MY_NAME ); /* overwrite settings from the comamndline */ tr_optind = 1; while(( c = tr_getopt( getUsage(), argc, (const char**)argv, options, &optarg ))) { switch( c ) { case 'a': tr_bencDictAddStr( &settings, TR_PREFS_KEY_RPC_WHITELIST, optarg ); tr_bencDictAddBool( &settings, TR_PREFS_KEY_RPC_WHITELIST_ENABLED, TRUE ); break; case 'b': tr_bencDictAddBool( &settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, TRUE ); break; case 'B': tr_bencDictAddBool( &settings, TR_PREFS_KEY_BLOCKLIST_ENABLED, FALSE ); break; case 'c': tr_bencDictAddStr( &settings, PREF_KEY_DIR_WATCH, optarg ); tr_bencDictAddBool( &settings, PREF_KEY_DIR_WATCH_ENABLED, TRUE ); break; case 'C': tr_bencDictAddBool( &settings, PREF_KEY_DIR_WATCH_ENABLED, FALSE ); break; case 941: tr_bencDictAddStr( &settings, TR_PREFS_KEY_INCOMPLETE_DIR, optarg ); tr_bencDictAddBool( &settings, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, TRUE ); break; case 942: tr_bencDictAddBool( &settings, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, FALSE ); break; case 'd': dumpSettings = TRUE; break; case 'e': logfile = fopen( optarg, "a+" ); if( logfile == NULL ) fprintf( stderr, "Couldn't open \"%s\": %s\n", optarg, tr_strerror( errno ) ); break; case 'f': foreground = TRUE; break; case 'g': /* handled above */ break; case 'V': /* version */ fprintf(stderr, "%s %s\n", MY_NAME, LONG_VERSION_STRING); exit( 0 ); case 'o': tr_bencDictAddBool( &settings, TR_PREFS_KEY_DHT_ENABLED, TRUE ); break; case 'O': tr_bencDictAddBool( &settings, TR_PREFS_KEY_DHT_ENABLED, FALSE ); break; case 'p': tr_bencDictAddInt( &settings, TR_PREFS_KEY_RPC_PORT, atoi( optarg ) ); break; case 't': tr_bencDictAddBool( &settings, TR_PREFS_KEY_RPC_AUTH_REQUIRED, TRUE ); break; case 'T': tr_bencDictAddBool( &settings, TR_PREFS_KEY_RPC_AUTH_REQUIRED, FALSE ); break; case 'u': tr_bencDictAddStr( &settings, TR_PREFS_KEY_RPC_USERNAME, optarg ); break; case 'v': tr_bencDictAddStr( &settings, TR_PREFS_KEY_RPC_PASSWORD, optarg ); break; case 'w': tr_bencDictAddStr( &settings, TR_PREFS_KEY_DOWNLOAD_DIR, optarg ); break; case 'P': tr_bencDictAddInt( &settings, TR_PREFS_KEY_PEER_PORT, atoi( optarg ) ); break; case 'm': tr_bencDictAddBool( &settings, TR_PREFS_KEY_PORT_FORWARDING, TRUE ); break; case 'M': tr_bencDictAddBool( &settings, TR_PREFS_KEY_PORT_FORWARDING, FALSE ); break; case 'L': tr_bencDictAddInt( &settings, TR_PREFS_KEY_PEER_LIMIT_GLOBAL, atoi( optarg ) ); break; case 'l': tr_bencDictAddInt( &settings, TR_PREFS_KEY_PEER_LIMIT_TORRENT, atoi( optarg ) ); break; case 800: paused = TRUE; break; case 910: tr_bencDictAddInt( &settings, TR_PREFS_KEY_ENCRYPTION, TR_ENCRYPTION_REQUIRED ); break; case 911: tr_bencDictAddInt( &settings, TR_PREFS_KEY_ENCRYPTION, TR_ENCRYPTION_PREFERRED ); break; case 912: tr_bencDictAddInt( &settings, TR_PREFS_KEY_ENCRYPTION, TR_CLEAR_PREFERRED ); break; case 'i': tr_bencDictAddStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV4, optarg ); break; case 'I': tr_bencDictAddStr( &settings, TR_PREFS_KEY_BIND_ADDRESS_IPV6, optarg ); break; case 'r': tr_bencDictAddStr( &settings, TR_PREFS_KEY_RPC_BIND_ADDRESS, optarg ); break; case 953: tr_bencDictAddReal( &settings, TR_PREFS_KEY_RATIO, atof(optarg) ); tr_bencDictAddBool( &settings, TR_PREFS_KEY_RATIO_ENABLED, TRUE ); break; case 954: tr_bencDictAddBool( &settings, TR_PREFS_KEY_RATIO_ENABLED, FALSE ); break; case 'x': tr_bencDictAddStr( &settings, PREF_KEY_PIDFILE, optarg ); break; case 'y': tr_bencDictAddBool( &settings, TR_PREFS_KEY_LPD_ENABLED, TRUE ); break; case 'Y': tr_bencDictAddBool( &settings, TR_PREFS_KEY_LPD_ENABLED, FALSE ); break; case 810: tr_bencDictAddInt( &settings, TR_PREFS_KEY_MSGLEVEL, TR_MSG_ERR ); break; case 811: tr_bencDictAddInt( &settings, TR_PREFS_KEY_MSGLEVEL, TR_MSG_INF ); break; case 812: tr_bencDictAddInt( &settings, TR_PREFS_KEY_MSGLEVEL, TR_MSG_DBG ); break; default: showUsage( ); break; } } if( foreground && !logfile ) logfile = stderr; if( !loaded ) { printMessage( logfile, TR_MSG_ERR, MY_NAME, "Error loading config file -- exiting.", __FILE__, __LINE__ ); return -1; } if( dumpSettings ) { char * str = tr_bencToStr( &settings, TR_FMT_JSON, NULL ); fprintf( stderr, "%s", str ); tr_free( str ); return 0; } if( !foreground && tr_daemon( TRUE, FALSE ) < 0 ) { char buf[256]; tr_snprintf( buf, sizeof( buf ), "Failed to daemonize: %s", tr_strerror( errno ) ); printMessage( logfile, TR_MSG_ERR, MY_NAME, buf, __FILE__, __LINE__ ); exit( 1 ); } /* start the session */ tr_formatter_mem_init( MEM_K, MEM_K_STR, MEM_M_STR, MEM_G_STR, MEM_T_STR ); tr_formatter_size_init( DISK_K, DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR ); tr_formatter_speed_init( SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR ); mySession = tr_sessionInit( "daemon", configDir, TRUE, &settings ); tr_ninf( NULL, "Using settings from \"%s\"", configDir ); tr_sessionSaveSettings( mySession, configDir, &settings ); pid_filename = NULL; tr_bencDictFindStr( &settings, PREF_KEY_PIDFILE, &pid_filename ); if( pid_filename && *pid_filename ) { FILE * fp = fopen( pid_filename, "w+" ); if( fp != NULL ) { fprintf( fp, "%d", (int)getpid() ); fclose( fp ); tr_inf( "Saved pidfile \"%s\"", pid_filename ); pidfile_created = TRUE; } else tr_err( "Unable to save pidfile \"%s\": %s", pid_filename, strerror( errno ) ); } if( tr_bencDictFindBool( &settings, TR_PREFS_KEY_RPC_AUTH_REQUIRED, &boolVal ) && boolVal ) tr_ninf( MY_NAME, "requiring authentication" ); /* maybe add a watchdir */ { const char * dir; if( tr_bencDictFindBool( &settings, PREF_KEY_DIR_WATCH_ENABLED, &boolVal ) && boolVal && tr_bencDictFindStr( &settings, PREF_KEY_DIR_WATCH, &dir ) && dir && *dir ) { tr_inf( "Watching \"%s\" for new .torrent files", dir ); watchdir = dtr_watchdir_new( mySession, dir, onFileAdded ); } } /* load the torrents */ { tr_torrent ** torrents; tr_ctor * ctor = tr_ctorNew( mySession ); if( paused ) tr_ctorSetPaused( ctor, TR_FORCE, TRUE ); torrents = tr_sessionLoadTorrents( mySession, ctor, NULL ); tr_free( torrents ); tr_ctorFree( ctor ); } #ifdef HAVE_SYSLOG if( !foreground ) openlog( MY_NAME, LOG_CONS|LOG_PID, LOG_DAEMON ); #endif while( !closing ) { tr_wait_msec( 1000 ); /* sleep one second */ dtr_watchdir_update( watchdir ); pumpLogMessages( logfile ); } /* shutdown */ #if HAVE_SYSLOG if( !foreground ) { syslog( LOG_INFO, "%s", "Closing session" ); closelog( ); } #endif printf( "Closing transmission session..." ); tr_sessionSaveSettings( mySession, configDir, &settings ); dtr_watchdir_free( watchdir ); tr_sessionClose( mySession ); printf( " done.\n" ); /* cleanup */ if( pidfile_created ) remove( pid_filename ); tr_bencFree( &settings ); return 0; }
static int test_single_file_impl (const tr_tracker_info * trackers, const size_t trackerCount, const void * payload, const size_t payloadSize, const char * comment, bool isPrivate) { char* sandbox; char* input_file; char* torrent_file; tr_metainfo_builder* builder; tr_ctor * ctor; tr_parse_result parse_result; tr_info inf; char * tmpstr; /* set up our local test sandbox */ sandbox = libtest_sandbox_create(); /* create a single input file */ input_file = tr_buildPath (sandbox, "test.XXXXXX", NULL); libtest_create_tmpfile_with_contents (input_file, payload, payloadSize); builder = tr_metaInfoBuilderCreate (input_file); check_streq (input_file, builder->top); check_int_eq (1, builder->fileCount); check_streq (input_file, builder->files[0].filename); check_int_eq (payloadSize, builder->files[0].size); check_int_eq (payloadSize, builder->totalSize); check (!builder->isFolder); check (!builder->abortFlag); /* have tr_makeMetaInfo() build the .torrent file */ torrent_file = tr_strdup_printf ("%s.torrent", input_file); tr_makeMetaInfo (builder, torrent_file, trackers, trackerCount, comment, isPrivate); check (isPrivate == builder->isPrivate); check_streq (torrent_file, builder->outputFile); check_streq (comment, builder->comment); check_int_eq (trackerCount, builder->trackerCount); while (!builder->isDone) tr_wait_msec (100); /* now let's check our work: parse the .torrent file */ ctor = tr_ctorNew (NULL); libttest_sync (); tr_ctorSetMetainfoFromFile (ctor, torrent_file); parse_result = tr_torrentParse (ctor, &inf); check_int_eq (TR_PARSE_OK, parse_result); /* quick check of some of the parsed metainfo */ check_int_eq (payloadSize, inf.totalSize); tmpstr = tr_sys_path_basename (input_file, NULL); check_streq (tmpstr, inf.name); tr_free (tmpstr); check_streq (comment, inf.comment); check_int_eq (1, inf.fileCount); check_int_eq (isPrivate, inf.isPrivate); check (!inf.isFolder); check_int_eq (trackerCount, inf.trackerCount); /* cleanup */ tr_free (torrent_file); tr_free (input_file); tr_ctorFree (ctor); tr_metainfoFree (&inf); tr_metaInfoBuilderFree (builder); libtest_sandbox_destroy (sandbox); tr_free (sandbox); return 0; }
static int test_single_directory_impl (const tr_tracker_info * trackers, const size_t trackerCount, const void ** payloads, const size_t * payloadSizes, const size_t payloadCount, const char * comment, const bool isPrivate) { char* sandbox; char* torrent_file; tr_metainfo_builder* builder; tr_ctor * ctor; tr_parse_result parse_result; tr_info inf; char * top; char ** files; size_t totalSize; size_t i; char* tmpstr; /* set up our local test sandbox */ sandbox = libtest_sandbox_create(); /* create the top temp directory */ top = tr_buildPath (sandbox, "folder.XXXXXX", NULL); tr_sys_dir_create_temp (top, NULL); /* build the payload files that go into the top temp directory */ files = tr_new (char*, payloadCount); totalSize = 0; for (i=0; i<payloadCount; i++) { char tmpl[16]; tr_snprintf (tmpl, sizeof(tmpl), "file.%04zu%s", i, "XXXXXX"); files[i] = tr_buildPath (top, tmpl, NULL); libtest_create_tmpfile_with_contents (files[i], payloads[i], payloadSizes[i]); totalSize += payloadSizes[i]; } libttest_sync (); /* init the builder */ builder = tr_metaInfoBuilderCreate (top); check (!builder->abortFlag); check_streq (top, builder->top); check_int_eq (payloadCount, builder->fileCount); check_int_eq (totalSize, builder->totalSize); check (builder->isFolder); for (i=0; i<builder->fileCount; i++) { check_streq (files[i], builder->files[i].filename); check_int_eq (payloadSizes[i], builder->files[i].size); } /* call tr_makeMetaInfo() to build the .torrent file */ torrent_file = tr_strdup_printf ("%s.torrent", top); tr_makeMetaInfo (builder, torrent_file, trackers, trackerCount, comment, isPrivate); check (isPrivate == builder->isPrivate); check_streq (torrent_file, builder->outputFile); check_streq (comment, builder->comment); check_int_eq (trackerCount, builder->trackerCount); while (!builder->isDone) tr_wait_msec (100); /* now let's check our work: parse the .torrent file */ ctor = tr_ctorNew (NULL); libttest_sync (); tr_ctorSetMetainfoFromFile (ctor, torrent_file); parse_result = tr_torrentParse (ctor, &inf); check_int_eq (TR_PARSE_OK, parse_result); /* quick check of some of the parsed metainfo */ check_int_eq (totalSize, inf.totalSize); tmpstr = tr_sys_path_basename (top, NULL); check_streq (tmpstr, inf.name); tr_free (tmpstr); check_streq (comment, inf.comment); check_int_eq (payloadCount, inf.fileCount); check_int_eq (isPrivate, inf.isPrivate); check_int_eq (builder->isFolder, inf.isFolder); check_int_eq (trackerCount, inf.trackerCount); /* cleanup */ tr_free (torrent_file); tr_ctorFree (ctor); tr_metainfoFree (&inf); tr_metaInfoBuilderFree (builder); for (i=0; i<payloadCount; i++) tr_free (files[i]); tr_free (files); libtest_sandbox_destroy (sandbox); tr_free (sandbox); tr_free (top); return 0; }
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; }