1/* 2 * This file Copyright (C) Mnemosyne LLC 3 * 4 * This file is licensed by the GPL version 2. Works owned by the 5 * Transmission project are granted a special exemption to clause 2(b) 6 * so that the bulk of its code can remain under the MIT license. 7 * This exemption does not extend to derived works not owned by 8 * the Transmission project. 9 * 10 * $Id: torrent.c 13573 2012-10-15 03:11:16Z jordan $ 11 */ 12 13#include <signal.h> /* signal() */ 14#include <sys/types.h> /* stat */ 15#include <sys/stat.h> /* stat */ 16#ifndef WIN32 17 #include <sys/wait.h> /* wait() */ 18#else 19 #include <process.h> 20 #define waitpid(pid, status, options) _cwait(status, pid, WAIT_CHILD) 21#endif 22#include <unistd.h> /* stat */ 23#include <dirent.h> 24 25#include <assert.h> 26#include <math.h> 27#include <stdarg.h> 28#include <string.h> /* memcmp */ 29#include <stdlib.h> /* qsort */ 30#include <stdio.h> /* remove() */ 31 32#include <event2/util.h> /* evutil_vsnprintf() */ 33 34#include "transmission.h" 35#include "announcer.h" 36#include "bandwidth.h" 37#include "bencode.h" 38#include "cache.h" 39#include "completion.h" 40#include "crypto.h" /* for tr_sha1 */ 41#include "resume.h" 42#include "fdlimit.h" /* tr_fdTorrentClose */ 43#include "inout.h" /* tr_ioTestPiece() */ 44#include "magnet.h" 45#include "metainfo.h" 46#include "peer-common.h" /* MAX_BLOCK_SIZE */ 47#include "peer-mgr.h" 48#include "platform.h" /* TR_PATH_DELIMITER_STR */ 49#include "ptrarray.h" 50#include "session.h" 51#include "torrent.h" 52#include "torrent-magnet.h" 53#include "trevent.h" /* tr_runInEventThread() */ 54#include "utils.h" 55#include "verify.h" 56#include "version.h" 57 58/*** 59**** 60***/ 61 62#define tr_deeplog_tor( tor, ... ) \ 63 do { \ 64 if( tr_deepLoggingIsActive( ) ) \ 65 tr_deepLog( __FILE__, __LINE__, tr_torrentName( tor ), __VA_ARGS__ ); \ 66 } while( 0 ) 67 68/*** 69**** 70***/ 71 72const char * 73tr_torrentName( const tr_torrent * tor ) 74{ 75 assert( tr_isTorrent( tor ) ); 76 77 return tor->info.name; 78} 79 80int 81tr_torrentId( const tr_torrent * tor ) 82{ 83 return tor->uniqueId; 84} 85 86tr_torrent* 87tr_torrentFindFromId( tr_session * session, int id ) 88{ 89 tr_torrent * tor = NULL; 90 91 while(( tor = tr_torrentNext( session, tor ))) 92 if( tor->uniqueId == id ) 93 return tor; 94 95 return NULL; 96} 97 98tr_torrent* 99tr_torrentFindFromHashString( tr_session * session, const char * str ) 100{ 101 tr_torrent * tor = NULL; 102 103 while(( tor = tr_torrentNext( session, tor ))) 104 if( !evutil_ascii_strcasecmp( str, tor->info.hashString ) ) 105 return tor; 106 107 return NULL; 108} 109 110tr_torrent* 111tr_torrentFindFromHash( tr_session * session, const uint8_t * torrentHash ) 112{ 113 tr_torrent * tor = NULL; 114 115 while(( tor = tr_torrentNext( session, tor ))) 116 if( *tor->info.hash == *torrentHash ) 117 if( !memcmp( tor->info.hash, torrentHash, SHA_DIGEST_LENGTH ) ) 118 return tor; 119 120 return NULL; 121} 122 123tr_torrent* 124tr_torrentFindFromMagnetLink( tr_session * session, const char * magnet ) 125{ 126 tr_magnet_info * info; 127 tr_torrent * tor = NULL; 128 129 if(( info = tr_magnetParse( magnet ))) 130 { 131 tor = tr_torrentFindFromHash( session, info->hash ); 132 tr_magnetFree( info ); 133 } 134 135 return tor; 136} 137 138tr_torrent* 139tr_torrentFindFromObfuscatedHash( tr_session * session, 140 const uint8_t * obfuscatedTorrentHash ) 141{ 142 tr_torrent * tor = NULL; 143 144 while(( tor = tr_torrentNext( session, tor ))) 145 if( !memcmp( tor->obfuscatedHash, obfuscatedTorrentHash, 146 SHA_DIGEST_LENGTH ) ) 147 return tor; 148 149 return NULL; 150} 151 152bool 153tr_torrentIsPieceTransferAllowed( const tr_torrent * tor, 154 tr_direction direction ) 155{ 156 unsigned int limit; 157 bool allowed = true; 158 159 if( tr_torrentUsesSpeedLimit( tor, direction ) ) 160 if( tr_torrentGetSpeedLimit_Bps( tor, direction ) <= 0 ) 161 allowed = false; 162 163 if( tr_torrentUsesSessionLimits( tor ) ) 164 if( tr_sessionGetActiveSpeedLimit_Bps( tor->session, direction, &limit ) ) 165 if( limit <= 0 ) 166 allowed = false; 167 168 return allowed; 169} 170 171/*** 172**** PER-TORRENT UL / DL SPEEDS 173***/ 174 175void 176tr_torrentSetSpeedLimit_Bps( tr_torrent * tor, tr_direction dir, unsigned int Bps ) 177{ 178 assert( tr_isTorrent( tor ) ); 179 assert( tr_isDirection( dir ) ); 180 181 if( tr_bandwidthSetDesiredSpeed_Bps( &tor->bandwidth, dir, Bps ) ) 182 tr_torrentSetDirty( tor ); 183} 184void 185tr_torrentSetSpeedLimit_KBps( tr_torrent * tor, tr_direction dir, unsigned int KBps ) 186{ 187 tr_torrentSetSpeedLimit_Bps( tor, dir, toSpeedBytes( KBps ) ); 188} 189 190unsigned int 191tr_torrentGetSpeedLimit_Bps( const tr_torrent * tor, tr_direction dir ) 192{ 193 assert( tr_isTorrent( tor ) ); 194 assert( tr_isDirection( dir ) ); 195 196 return tr_bandwidthGetDesiredSpeed_Bps( &tor->bandwidth, dir ); 197} 198unsigned int 199tr_torrentGetSpeedLimit_KBps( const tr_torrent * tor, tr_direction dir ) 200{ 201 return toSpeedKBps( tr_torrentGetSpeedLimit_Bps( tor, dir ) ); 202} 203 204void 205tr_torrentUseSpeedLimit( tr_torrent * tor, tr_direction dir, bool do_use ) 206{ 207 assert( tr_isTorrent( tor ) ); 208 assert( tr_isDirection( dir ) ); 209 210 if( tr_bandwidthSetLimited( &tor->bandwidth, dir, do_use ) ) 211 tr_torrentSetDirty( tor ); 212} 213 214bool 215tr_torrentUsesSpeedLimit( const tr_torrent * tor, tr_direction dir ) 216{ 217 assert( tr_isTorrent( tor ) ); 218 assert( tr_isDirection( dir ) ); 219 220 return tr_bandwidthIsLimited( &tor->bandwidth, dir ); 221} 222 223void 224tr_torrentUseSessionLimits( tr_torrent * tor, bool doUse ) 225{ 226 bool changed; 227 228 assert( tr_isTorrent( tor ) ); 229 230 changed = tr_bandwidthHonorParentLimits( &tor->bandwidth, TR_UP, doUse ); 231 changed |= tr_bandwidthHonorParentLimits( &tor->bandwidth, TR_DOWN, doUse ); 232 233 if( changed ) 234 tr_torrentSetDirty( tor ); 235} 236 237bool 238tr_torrentUsesSessionLimits( const tr_torrent * tor ) 239{ 240 assert( tr_isTorrent( tor ) ); 241 242 return tr_bandwidthAreParentLimitsHonored( &tor->bandwidth, TR_UP ); 243} 244 245/*** 246**** 247***/ 248 249void 250tr_torrentSetRatioMode( tr_torrent * tor, tr_ratiolimit mode ) 251{ 252 assert( tr_isTorrent( tor ) ); 253 assert( mode==TR_RATIOLIMIT_GLOBAL || mode==TR_RATIOLIMIT_SINGLE || mode==TR_RATIOLIMIT_UNLIMITED ); 254 255 if( mode != tor->ratioLimitMode ) 256 { 257 tor->ratioLimitMode = mode; 258 259 tr_torrentSetDirty( tor ); 260 } 261} 262 263tr_ratiolimit 264tr_torrentGetRatioMode( const tr_torrent * tor ) 265{ 266 assert( tr_isTorrent( tor ) ); 267 268 return tor->ratioLimitMode; 269} 270 271void 272tr_torrentSetRatioLimit( tr_torrent * tor, double desiredRatio ) 273{ 274 assert( tr_isTorrent( tor ) ); 275 276 if( (int)(desiredRatio*100.0) != (int)(tor->desiredRatio*100.0) ) 277 { 278 tor->desiredRatio = desiredRatio; 279 280 tr_torrentSetDirty( tor ); 281 } 282} 283 284double 285tr_torrentGetRatioLimit( const tr_torrent * tor ) 286{ 287 assert( tr_isTorrent( tor ) ); 288 289 return tor->desiredRatio; 290} 291 292bool 293tr_torrentGetSeedRatio( const tr_torrent * tor, double * ratio ) 294{ 295 bool isLimited; 296 297 switch( tr_torrentGetRatioMode( tor ) ) 298 { 299 case TR_RATIOLIMIT_SINGLE: 300 isLimited = true; 301 if( ratio ) 302 *ratio = tr_torrentGetRatioLimit( tor ); 303 break; 304 305 case TR_RATIOLIMIT_GLOBAL: 306 isLimited = tr_sessionIsRatioLimited( tor->session ); 307 if( isLimited && ratio ) 308 *ratio = tr_sessionGetRatioLimit( tor->session ); 309 break; 310 311 default: /* TR_RATIOLIMIT_UNLIMITED */ 312 isLimited = false; 313 break; 314 } 315 316 return isLimited; 317} 318 319/* returns true if the seed ratio applies -- 320 * it applies if the torrent's a seed AND it has a seed ratio set */ 321static bool 322tr_torrentGetSeedRatioBytes( tr_torrent * tor, 323 uint64_t * setmeLeft, 324 uint64_t * setmeGoal ) 325{ 326 double seedRatio; 327 bool seedRatioApplies = false; 328 329 if( tr_torrentGetSeedRatio( tor, &seedRatio ) ) 330 { 331 const uint64_t u = tor->uploadedCur + tor->uploadedPrev; 332 const uint64_t d = tor->downloadedCur + tor->downloadedPrev; 333 const uint64_t baseline = d ? d : tr_cpSizeWhenDone( &tor->completion ); 334 const uint64_t goal = baseline * seedRatio; 335 if( setmeLeft ) *setmeLeft = goal > u ? goal - u : 0; 336 if( setmeGoal ) *setmeGoal = goal; 337 seedRatioApplies = tr_torrentIsSeed( tor ); 338 } 339 340 return seedRatioApplies; 341} 342 343static bool 344tr_torrentIsSeedRatioDone( tr_torrent * tor ) 345{ 346 uint64_t bytesLeft; 347 return tr_torrentGetSeedRatioBytes( tor, &bytesLeft, NULL ) && !bytesLeft; 348} 349 350/*** 351**** 352***/ 353 354void 355tr_torrentSetIdleMode( tr_torrent * tor, tr_idlelimit mode ) 356{ 357 assert( tr_isTorrent( tor ) ); 358 assert( mode==TR_IDLELIMIT_GLOBAL || mode==TR_IDLELIMIT_SINGLE || mode==TR_IDLELIMIT_UNLIMITED ); 359 360 if( mode != tor->idleLimitMode ) 361 { 362 tor->idleLimitMode = mode; 363 364 tr_torrentSetDirty( tor ); 365 } 366} 367 368tr_idlelimit 369tr_torrentGetIdleMode( const tr_torrent * tor ) 370{ 371 assert( tr_isTorrent( tor ) ); 372 373 return tor->idleLimitMode; 374} 375 376void 377tr_torrentSetIdleLimit( tr_torrent * tor, uint16_t idleMinutes ) 378{ 379 assert( tr_isTorrent( tor ) ); 380 381 if( idleMinutes > 0 ) 382 { 383 tor->idleLimitMinutes = idleMinutes; 384 385 tr_torrentSetDirty( tor ); 386 } 387} 388 389uint16_t 390tr_torrentGetIdleLimit( const tr_torrent * tor ) 391{ 392 assert( tr_isTorrent( tor ) ); 393 394 return tor->idleLimitMinutes; 395} 396 397bool 398tr_torrentGetSeedIdle( const tr_torrent * tor, uint16_t * idleMinutes ) 399{ 400 bool isLimited; 401 402 switch( tr_torrentGetIdleMode( tor ) ) 403 { 404 case TR_IDLELIMIT_SINGLE: 405 isLimited = true; 406 if( idleMinutes ) 407 *idleMinutes = tr_torrentGetIdleLimit( tor ); 408 break; 409 410 case TR_IDLELIMIT_GLOBAL: 411 isLimited = tr_sessionIsIdleLimited( tor->session ); 412 if( isLimited && idleMinutes ) 413 *idleMinutes = tr_sessionGetIdleLimit( tor->session ); 414 break; 415 416 default: /* TR_IDLELIMIT_UNLIMITED */ 417 isLimited = false; 418 break; 419 } 420 421 return isLimited; 422} 423 424static bool 425tr_torrentIsSeedIdleLimitDone( tr_torrent * tor ) 426{ 427 uint16_t idleMinutes; 428 return tr_torrentGetSeedIdle( tor, &idleMinutes ) 429 && difftime(tr_time(), MAX(tor->startDate, tor->activityDate)) >= idleMinutes * 60u; 430} 431 432/*** 433**** 434***/ 435 436void 437tr_torrentCheckSeedLimit( tr_torrent * tor ) 438{ 439 assert( tr_isTorrent( tor ) ); 440 441 if( !tor->isRunning || !tr_torrentIsSeed( tor ) ) 442 return; 443 444 /* if we're seeding and reach our seed ratio limit, stop the torrent */ 445 if( tr_torrentIsSeedRatioDone( tor ) ) 446 { 447 tr_torinf( tor, "Seed ratio reached; pausing torrent" ); 448 449 tor->isStopping = true; 450 451 /* maybe notify the client */ 452 if( tor->ratio_limit_hit_func != NULL ) 453 tor->ratio_limit_hit_func( tor, tor->ratio_limit_hit_func_user_data ); 454 } 455 /* if we're seeding and reach our inactiviy limit, stop the torrent */ 456 else if( tr_torrentIsSeedIdleLimitDone( tor ) ) 457 { 458 tr_torinf( tor, "Seeding idle limit reached; pausing torrent" ); 459 460 tor->isStopping = true; 461 tor->finishedSeedingByIdle = true; 462 463 /* maybe notify the client */ 464 if( tor->idle_limit_hit_func != NULL ) 465 tor->idle_limit_hit_func( tor, tor->idle_limit_hit_func_user_data ); 466 } 467} 468 469/*** 470**** 471***/ 472 473void 474tr_torrentSetLocalError( tr_torrent * tor, const char * fmt, ... ) 475{ 476 va_list ap; 477 478 assert( tr_isTorrent( tor ) ); 479 480 va_start( ap, fmt ); 481 tor->error = TR_STAT_LOCAL_ERROR; 482 tor->errorTracker[0] = '\0'; 483 evutil_vsnprintf( tor->errorString, sizeof( tor->errorString ), fmt, ap ); 484 va_end( ap ); 485 486 tr_torerr( tor, "%s", tor->errorString ); 487 488 if( tor->isRunning ) 489 tor->isStopping = true; 490} 491 492static void 493tr_torrentClearError( tr_torrent * tor ) 494{ 495 tor->error = TR_STAT_OK; 496 tor->errorString[0] = '\0'; 497 tor->errorTracker[0] = '\0'; 498} 499 500static void 501onTrackerResponse( tr_torrent * tor, const tr_tracker_event * event, void * unused UNUSED ) 502{ 503 switch( event->messageType ) 504 { 505 case TR_TRACKER_PEERS: 506 { 507 size_t i; 508 const int8_t seedProbability = event->seedProbability; 509 const bool allAreSeeds = seedProbability == 100; 510 511 if( allAreSeeds ) 512 tr_tordbg( tor, "Got %zu seeds from tracker", event->pexCount ); 513 else 514 tr_tordbg( tor, "Got %zu peers from tracker", event->pexCount ); 515 516 for( i = 0; i < event->pexCount; ++i ) 517 tr_peerMgrAddPex( tor, TR_PEER_FROM_TRACKER, &event->pex[i], seedProbability ); 518 519 break; 520 } 521 522 case TR_TRACKER_WARNING: 523 tr_torerr( tor, _( "Tracker warning: \"%s\"" ), event->text ); 524 tor->error = TR_STAT_TRACKER_WARNING; 525 tr_strlcpy( tor->errorTracker, event->tracker, sizeof( tor->errorTracker ) ); 526 tr_strlcpy( tor->errorString, event->text, sizeof( tor->errorString ) ); 527 break; 528 529 case TR_TRACKER_ERROR: 530 tr_torerr( tor, _( "Tracker error: \"%s\"" ), event->text ); 531 tor->error = TR_STAT_TRACKER_ERROR; 532 tr_strlcpy( tor->errorTracker, event->tracker, sizeof( tor->errorTracker ) ); 533 tr_strlcpy( tor->errorString, event->text, sizeof( tor->errorString ) ); 534 break; 535 536 case TR_TRACKER_ERROR_CLEAR: 537 if( tor->error != TR_STAT_LOCAL_ERROR ) 538 tr_torrentClearError( tor ); 539 break; 540 } 541} 542 543/*** 544**** 545**** TORRENT INSTANTIATION 546**** 547***/ 548 549static tr_piece_index_t 550getBytePiece( const tr_info * info, uint64_t byteOffset ) 551{ 552 assert( info ); 553 assert( info->pieceSize != 0 ); 554 555 return byteOffset / info->pieceSize; 556} 557 558static void 559initFilePieces( tr_info * info, 560 tr_file_index_t fileIndex ) 561{ 562 tr_file * file; 563 uint64_t firstByte, lastByte; 564 565 assert( info ); 566 assert( fileIndex < info->fileCount ); 567 568 file = &info->files[fileIndex]; 569 firstByte = file->offset; 570 lastByte = firstByte + ( file->length ? file->length - 1 : 0 ); 571 file->firstPiece = getBytePiece( info, firstByte ); 572 file->lastPiece = getBytePiece( info, lastByte ); 573} 574 575static int 576pieceHasFile( tr_piece_index_t piece, 577 const tr_file * file ) 578{ 579 return ( file->firstPiece <= piece ) && ( piece <= file->lastPiece ); 580} 581 582static tr_priority_t 583calculatePiecePriority( const tr_torrent * tor, 584 tr_piece_index_t piece, 585 int fileHint ) 586{ 587 tr_file_index_t i; 588 tr_priority_t priority = TR_PRI_LOW; 589 590 /* find the first file that has data in this piece */ 591 if( fileHint >= 0 ) { 592 i = fileHint; 593 while( i > 0 && pieceHasFile( piece, &tor->info.files[i - 1] ) ) 594 --i; 595 } else { 596 for( i = 0; i < tor->info.fileCount; ++i ) 597 if( pieceHasFile( piece, &tor->info.files[i] ) ) 598 break; 599 } 600 601 /* the piece's priority is the max of the priorities 602 * of all the files in that piece */ 603 for( ; i < tor->info.fileCount; ++i ) 604 { 605 const tr_file * file = &tor->info.files[i]; 606 607 if( !pieceHasFile( piece, file ) ) 608 break; 609 610 priority = MAX( priority, file->priority ); 611 612 /* when dealing with multimedia files, getting the first and 613 last pieces can sometimes allow you to preview it a bit 614 before it's fully downloaded... */ 615 if( file->priority >= TR_PRI_NORMAL ) 616 if( file->firstPiece == piece || file->lastPiece == piece ) 617 priority = TR_PRI_HIGH; 618 } 619 620 return priority; 621} 622 623static void 624tr_torrentInitFilePieces( tr_torrent * tor ) 625{ 626 int * firstFiles; 627 tr_file_index_t f; 628 tr_piece_index_t p; 629 uint64_t offset = 0; 630 tr_info * inf = &tor->info; 631 632 /* assign the file offsets */ 633 for( f=0; f<inf->fileCount; ++f ) { 634 inf->files[f].offset = offset; 635 offset += inf->files[f].length; 636 initFilePieces( inf, f ); 637 } 638 639 /* build the array of first-file hints to give calculatePiecePriority */ 640 firstFiles = tr_new( int, inf->pieceCount ); 641 for( p=f=0; p<inf->pieceCount; ++p ) { 642 while( inf->files[f].lastPiece < p ) 643 ++f; 644 firstFiles[p] = f; 645 } 646 647#if 0 648 /* test to confirm the first-file hints are correct */ 649 for( p=0; p<inf->pieceCount; ++p ) { 650 f = firstFiles[p]; 651 assert( inf->files[f].firstPiece <= p ); 652 assert( inf->files[f].lastPiece >= p ); 653 if( f > 0 ) 654 assert( inf->files[f-1].lastPiece < p ); 655 for( f=0; f<inf->fileCount; ++f ) 656 if( pieceHasFile( p, &inf->files[f] ) ) 657 break; 658 assert( (int)f == firstFiles[p] ); 659 } 660#endif 661 662 for( p=0; p<inf->pieceCount; ++p ) 663 inf->pieces[p].priority = calculatePiecePriority( tor, p, firstFiles[p] ); 664 665 tr_free( firstFiles ); 666} 667 668static void torrentStart( tr_torrent * tor, bool bypass_queue ); 669 670/** 671 * Decide on a block size. Constraints: 672 * (1) most clients decline requests over 16 KiB 673 * (2) pieceSize must be a multiple of block size 674 */ 675uint32_t 676tr_getBlockSize( uint32_t pieceSize ) 677{ 678 uint32_t b = pieceSize; 679 680 while( b > MAX_BLOCK_SIZE ) 681 b /= 2u; 682 683 if( !b || ( pieceSize % b ) ) /* not cleanly divisible */ 684 return 0; 685 return b; 686} 687 688static void refreshCurrentDir( tr_torrent * tor ); 689 690static void 691torrentInitFromInfo( tr_torrent * tor ) 692{ 693 uint64_t t; 694 tr_info * info = &tor->info; 695 696 tor->blockSize = tr_getBlockSize( info->pieceSize ); 697 698 if( info->pieceSize ) 699 tor->lastPieceSize = (uint32_t)(info->totalSize % info->pieceSize); 700 701 if( !tor->lastPieceSize ) 702 tor->lastPieceSize = info->pieceSize; 703 704 if( tor->blockSize ) 705 tor->lastBlockSize = info->totalSize % tor->blockSize; 706 707 if( !tor->lastBlockSize ) 708 tor->lastBlockSize = tor->blockSize; 709 710 tor->blockCount = tor->blockSize 711 ? ( info->totalSize + tor->blockSize - 1 ) / tor->blockSize 712 : 0; 713 714 tor->blockCountInPiece = tor->blockSize 715 ? info->pieceSize / tor->blockSize 716 : 0; 717 718 tor->blockCountInLastPiece = tor->blockSize 719 ? ( tor->lastPieceSize + tor->blockSize - 1 ) / tor->blockSize 720 : 0; 721 722 /* check our work */ 723 if( tor->blockSize != 0 ) 724 assert( ( info->pieceSize % tor->blockSize ) == 0 ); 725 t = info->pieceCount - 1; 726 t *= info->pieceSize; 727 t += tor->lastPieceSize; 728 assert( t == info->totalSize ); 729 t = tor->blockCount - 1; 730 t *= tor->blockSize; 731 t += tor->lastBlockSize; 732 assert( t == info->totalSize ); 733 t = info->pieceCount - 1; 734 t *= tor->blockCountInPiece; 735 t += tor->blockCountInLastPiece; 736 assert( t == (uint64_t)tor->blockCount ); 737 738 tr_cpConstruct( &tor->completion, tor ); 739 740 tr_torrentInitFilePieces( tor ); 741 742 tor->completeness = tr_cpGetStatus( &tor->completion ); 743} 744 745static void tr_torrentFireMetadataCompleted( tr_torrent * tor ); 746 747void 748tr_torrentGotNewInfoDict( tr_torrent * tor ) 749{ 750 torrentInitFromInfo( tor ); 751 752 tr_peerMgrOnTorrentGotMetainfo( tor ); 753 754 tr_torrentFireMetadataCompleted( tor ); 755} 756 757static bool 758hasAnyLocalData( const tr_torrent * tor ) 759{ 760 tr_file_index_t i; 761 762 for( i=0; i<tor->info.fileCount; ++i ) 763 if( tr_torrentFindFile2( tor, i, NULL, NULL, NULL ) ) 764 return true; 765 766 return false; 767} 768 769static bool 770setLocalErrorIfFilesDisappeared( tr_torrent * tor ) 771{ 772 const bool disappeared = ( tr_cpHaveTotal( &tor->completion ) > 0 ) && !hasAnyLocalData( tor ); 773 774 if( disappeared ) 775 { 776 /*Foxconn modified start by Gene Chen,01/21/2012@Downloading file disappears*/ 777 char command[4096]={}; 778 const tr_completion * trcomp; 779 tor->completion.sizeNow = 0; 780 sprintf(command, "rm -rf %s/resume/'%s'*.resume", tor->downloadDir, tor->info.name); 781 system(command); 782 return 0; 783 784 //tr_deeplog_tor( tor, "%s", "[LAZY] uh oh, the files disappeared" ); 785 //tr_torrentSetLocalError( tor, "%s", _( "No data found! Ensure your drives are connected or use \"Set Location\". To re-download, remove the torrent and re-add it." ) ); 786 /*Foxconn modified end by Gene Chen,01/21/2012@Downloading file disappears*/ 787 } 788 789 return disappeared; 790} 791 792static void 793torrentInit( tr_torrent * tor, const tr_ctor * ctor ) 794{ 795 int doStart; 796 uint64_t loaded; 797 const char * dir; 798 bool isNewTorrent; 799 struct stat st; 800 static int nextUniqueId = 1; 801 tr_session * session = tr_ctorGetSession( ctor ); 802 803 assert( session != NULL ); 804 805 tr_sessionLock( session ); 806 807 tor->session = session; 808 tor->uniqueId = nextUniqueId++; 809 tor->magicNumber = TORRENT_MAGIC_NUMBER; 810 tor->queuePosition = session->torrentCount; 811 812 tr_peerIdInit( tor->peer_id ); 813 814 tr_sha1( tor->obfuscatedHash, "req2", 4, 815 tor->info.hash, SHA_DIGEST_LENGTH, 816 NULL ); 817 818 if( !tr_ctorGetDownloadDir( ctor, TR_FORCE, &dir ) || 819 !tr_ctorGetDownloadDir( ctor, TR_FALLBACK, &dir ) ) 820 tor->downloadDir = tr_strdup( dir ); 821 822 if( tr_ctorGetIncompleteDir( ctor, &dir ) ) 823 dir = tr_sessionGetIncompleteDir( session ); 824 if( tr_sessionIsIncompleteDirEnabled( session ) ) 825 tor->incompleteDir = tr_strdup( dir ); 826 827 tr_bandwidthConstruct( &tor->bandwidth, session, &session->bandwidth ); 828 829 tor->bandwidth.priority = tr_ctorGetBandwidthPriority( ctor ); 830 831 tor->error = TR_STAT_OK; 832 833 tor->finishedSeedingByIdle = false; 834 835 tr_peerMgrAddTorrent( session->peerMgr, tor ); 836 837 assert( !tor->downloadedCur ); 838 assert( !tor->uploadedCur ); 839 840 tr_torrentSetAddedDate( tor, tr_time( ) ); /* this is a default value to be 841 overwritten by the resume file */ 842 843 torrentInitFromInfo( tor ); 844 loaded = tr_torrentLoadResume( tor, ~0, ctor ); 845 tor->completeness = tr_cpGetStatus( &tor->completion ); 846 setLocalErrorIfFilesDisappeared( tor ); 847 848 tr_ctorInitTorrentPriorities( ctor, tor ); 849 tr_ctorInitTorrentWanted( ctor, tor ); 850 851 refreshCurrentDir( tor ); 852 853 doStart = tor->isRunning; 854 tor->isRunning = 0; 855 856 if( !( loaded & TR_FR_SPEEDLIMIT ) ) 857 { 858 tr_torrentUseSpeedLimit( tor, TR_UP, false ); 859 tr_torrentSetSpeedLimit_Bps( tor, TR_UP, tr_sessionGetSpeedLimit_Bps( tor->session, TR_UP ) ); 860 tr_torrentUseSpeedLimit( tor, TR_DOWN, false ); 861 tr_torrentSetSpeedLimit_Bps( tor, TR_DOWN, tr_sessionGetSpeedLimit_Bps( tor->session, TR_DOWN ) ); 862 tr_torrentUseSessionLimits( tor, true ); 863 } 864 865 if( !( loaded & TR_FR_RATIOLIMIT ) ) 866 { 867 tr_torrentSetRatioMode( tor, TR_RATIOLIMIT_GLOBAL ); 868 tr_torrentSetRatioLimit( tor, tr_sessionGetRatioLimit( tor->session ) ); 869 } 870 871 if( !( loaded & TR_FR_IDLELIMIT ) ) 872 { 873 tr_torrentSetIdleMode( tor, TR_IDLELIMIT_GLOBAL ); 874 tr_torrentSetIdleLimit( tor, tr_sessionGetIdleLimit( tor->session ) ); 875 } 876 877 /* add the torrent to tr_session.torrentList */ 878 session->torrentCount++; 879 if( session->torrentList == NULL ) 880 session->torrentList = tor; 881 else { 882 tr_torrent * it = session->torrentList; 883 while( it->next != NULL ) 884 it = it->next; 885 it->next = tor; 886 } 887 888 /* if we don't have a local .torrent file already, assume the torrent is new */ 889 isNewTorrent = stat( tor->info.torrent, &st ); 890 891 /* maybe save our own copy of the metainfo */ 892 if( tr_ctorGetSave( ctor ) ) 893 { 894 const tr_benc * val; 895 if( !tr_ctorGetMetainfo( ctor, &val ) ) 896 { 897 const char * path = tor->info.torrent; 898 const int err = tr_bencToFile( val, TR_FMT_BENC, path ); 899 if( err ) 900 tr_torrentSetLocalError( tor, "Unable to save torrent file: %s", tr_strerror( err ) ); 901 tr_sessionSetTorrentFile( tor->session, tor->info.hashString, path ); 902 } 903 } 904 905 tor->tiers = tr_announcerAddTorrent( tor, onTrackerResponse, NULL ); 906 907 if( isNewTorrent ) 908 { 909 tor->startAfterVerify = doStart; 910 tr_torrentVerify( tor ); 911 } 912 else if( doStart ) 913 { 914 tr_torrentStart( tor ); 915 } 916 917 tr_sessionUnlock( session ); 918} 919 920static tr_parse_result 921torrentParseImpl( const tr_ctor * ctor, tr_info * setmeInfo, 922 bool * setmeHasInfo, int * dictLength ) 923{ 924 int doFree; 925 bool didParse; 926 bool hasInfo = false; 927 tr_info tmp; 928 const tr_benc * metainfo; 929 tr_session * session = tr_ctorGetSession( ctor ); 930 tr_parse_result result = TR_PARSE_OK; 931 932 if( setmeInfo == NULL ) 933 setmeInfo = &tmp; 934 memset( setmeInfo, 0, sizeof( tr_info ) ); 935 936 if( tr_ctorGetMetainfo( ctor, &metainfo ) ) 937 return TR_PARSE_ERR; 938 939 didParse = tr_metainfoParse( session, metainfo, setmeInfo, 940 &hasInfo, dictLength ); 941 doFree = didParse && ( setmeInfo == &tmp ); 942 943 if( !didParse ) 944 result = TR_PARSE_ERR; 945 946 if( didParse && hasInfo && !tr_getBlockSize( setmeInfo->pieceSize ) ) 947 result = TR_PARSE_ERR; 948 949 if( didParse && session && tr_torrentExists( session, setmeInfo->hash ) ) 950 result = TR_PARSE_DUPLICATE; 951 952 if( doFree ) 953 tr_metainfoFree( setmeInfo ); 954 955 if( setmeHasInfo != NULL ) 956 *setmeHasInfo = hasInfo; 957 958 return result; 959} 960 961tr_parse_result 962tr_torrentParse( const tr_ctor * ctor, tr_info * setmeInfo ) 963{ 964 return torrentParseImpl( ctor, setmeInfo, NULL, NULL ); 965} 966 967tr_torrent * 968tr_torrentNew( const tr_ctor * ctor, int * setmeError ) 969{ 970 int len; 971 bool hasInfo; 972 tr_info tmpInfo; 973 tr_parse_result r; 974 tr_torrent * tor = NULL; 975 976 assert( ctor != NULL ); 977 assert( tr_isSession( tr_ctorGetSession( ctor ) ) ); 978 979 r = torrentParseImpl( ctor, &tmpInfo, &hasInfo, &len ); 980 if( r == TR_PARSE_OK || !hasAnyLocalData( tor ))/* Foxconn modified by Jesse Chen, 05/20/2013 */ 981 { 982 tor = tr_new0( tr_torrent, 1 ); 983 tor->info = tmpInfo; 984 if( hasInfo ) 985 tor->infoDictLength = len; 986 torrentInit( tor, ctor ); 987 } 988 else 989 { 990 if( r == TR_PARSE_DUPLICATE ) 991 tr_metainfoFree( &tmpInfo ); 992 993 if( setmeError ) 994 *setmeError = r; 995 } 996 997 return tor; 998} 999 1000/** 1001*** 1002**/ 1003 1004void 1005tr_torrentSetDownloadDir( tr_torrent * tor, const char * path ) 1006{ 1007 assert( tr_isTorrent( tor ) ); 1008 1009 if( !path || !tor->downloadDir || strcmp( path, tor->downloadDir ) ) 1010 { 1011 tr_free( tor->downloadDir ); 1012 tor->downloadDir = tr_strdup( path ); 1013 tr_torrentSetDirty( tor ); 1014 } 1015 1016 refreshCurrentDir( tor ); 1017} 1018 1019const char* 1020tr_torrentGetDownloadDir( const tr_torrent * tor ) 1021{ 1022 assert( tr_isTorrent( tor ) ); 1023 1024 return tor->downloadDir; 1025} 1026 1027const char * 1028tr_torrentGetCurrentDir( const tr_torrent * tor ) 1029{ 1030 assert( tr_isTorrent( tor ) ); 1031 1032 return tor->currentDir; 1033} 1034 1035 1036void 1037tr_torrentChangeMyPort( tr_torrent * tor ) 1038{ 1039 assert( tr_isTorrent( tor ) ); 1040 1041 if( tor->isRunning ) 1042 tr_announcerChangeMyPort( tor ); 1043} 1044 1045static inline void 1046tr_torrentManualUpdateImpl( void * vtor ) 1047{ 1048 tr_torrent * tor = vtor; 1049 1050 assert( tr_isTorrent( tor ) ); 1051 1052 if( tor->isRunning ) 1053 tr_announcerManualAnnounce( tor ); 1054} 1055 1056void 1057tr_torrentManualUpdate( tr_torrent * tor ) 1058{ 1059 assert( tr_isTorrent( tor ) ); 1060 1061 tr_runInEventThread( tor->session, tr_torrentManualUpdateImpl, tor ); 1062} 1063 1064bool 1065tr_torrentCanManualUpdate( const tr_torrent * tor ) 1066{ 1067 return ( tr_isTorrent( tor ) ) 1068 && ( tor->isRunning ) 1069 && ( tr_announcerCanManualAnnounce( tor ) ); 1070} 1071 1072const tr_info * 1073tr_torrentInfo( const tr_torrent * tor ) 1074{ 1075 return tr_isTorrent( tor ) ? &tor->info : NULL; 1076} 1077 1078const tr_stat * 1079tr_torrentStatCached( tr_torrent * tor ) 1080{ 1081 const time_t now = tr_time( ); 1082 1083 return tr_isTorrent( tor ) && ( now == tor->lastStatTime ) 1084 ? &tor->stats 1085 : tr_torrentStat( tor ); 1086} 1087 1088void 1089tr_torrentSetVerifyState( tr_torrent * tor, tr_verify_state state ) 1090{ 1091 assert( tr_isTorrent( tor ) ); 1092 assert( state==TR_VERIFY_NONE || state==TR_VERIFY_WAIT || state==TR_VERIFY_NOW ); 1093 1094 tor->verifyState = state; 1095 tor->anyDate = tr_time( ); 1096} 1097 1098static tr_torrent_activity 1099torrentGetActivity( const tr_torrent * tor ) 1100{ 1101 const bool is_seed = tr_torrentIsSeed( tor ); 1102 assert( tr_isTorrent( tor ) ); 1103 1104 if( tor->verifyState == TR_VERIFY_NOW ) 1105 return TR_STATUS_CHECK; 1106 1107 if( tor->verifyState == TR_VERIFY_WAIT ) 1108 return TR_STATUS_CHECK_WAIT; 1109 1110 if( tor->isRunning ) 1111 return is_seed ? TR_STATUS_SEED : TR_STATUS_DOWNLOAD; 1112 1113 if( tr_torrentIsQueued( tor ) ) { 1114 if( is_seed && tr_sessionGetQueueEnabled( tor->session, TR_UP ) ) 1115 return TR_STATUS_SEED_WAIT; 1116 if( !is_seed && tr_sessionGetQueueEnabled( tor->session, TR_DOWN ) ) 1117 return TR_STATUS_DOWNLOAD_WAIT; 1118 } 1119 1120 return TR_STATUS_STOPPED; 1121} 1122 1123tr_torrent_activity 1124tr_torrentGetActivity( tr_torrent * tor ) 1125{ 1126 /* FIXME: is this call still needed? */ 1127 tr_torrentRecheckCompleteness( tor ); 1128 1129 return torrentGetActivity( tor ); 1130} 1131 1132static time_t 1133torrentGetIdleSecs( const tr_torrent * tor ) 1134{ 1135 int idle_secs; 1136 const tr_torrent_activity activity = torrentGetActivity( tor ); 1137 1138 if ((activity == TR_STATUS_DOWNLOAD || activity == TR_STATUS_SEED) && tor->startDate != 0) 1139 idle_secs = difftime(tr_time(), MAX(tor->startDate, tor->activityDate)); 1140 else 1141 idle_secs = -1; 1142 1143 return idle_secs; 1144} 1145 1146bool 1147tr_torrentIsStalled( const tr_torrent * tor ) 1148{ 1149 return tr_sessionGetQueueStalledEnabled( tor->session ) 1150 && ( torrentGetIdleSecs( tor ) > ( tr_sessionGetQueueStalledMinutes( tor->session ) * 60 ) ); 1151} 1152 1153 1154static double 1155getVerifyProgress( const tr_torrent * tor ) 1156{ 1157 double d = 0; 1158 1159 assert( tr_isTorrent( tor ) ); 1160 1161 if( tr_torrentHasMetadata( tor ) ) 1162 { 1163 tr_piece_index_t i, n; 1164 tr_piece_index_t checked = 0; 1165 1166 for( i=0, n=tor->info.pieceCount; i!=n; ++i ) 1167 if( tor->info.pieces[i].timeChecked ) 1168 ++checked; 1169 1170 d = checked / (double)tor->info.pieceCount; 1171 } 1172 1173 return d; 1174} 1175 1176const tr_stat * 1177tr_torrentStat( tr_torrent * tor ) 1178{ 1179 tr_stat * s; 1180 uint64_t now; 1181 uint64_t seedRatioBytesLeft; 1182 uint64_t seedRatioBytesGoal; 1183 bool seedRatioApplies; 1184 uint16_t seedIdleMinutes; 1185 1186 if( !tor ) 1187 return NULL; 1188 1189 assert( tr_isTorrent( tor ) ); 1190 tr_torrentLock( tor ); 1191 1192 tor->lastStatTime = tr_time( ); 1193 1194 s = &tor->stats; 1195 s->id = tor->uniqueId; 1196 s->activity = tr_torrentGetActivity( tor ); 1197 s->error = tor->error; 1198 s->queuePosition = tor->queuePosition; 1199 s->isStalled = tr_torrentIsStalled( tor ); 1200 tr_strlcpy( s->errorString, tor->errorString, sizeof( s->errorString ) ); 1201 1202 s->manualAnnounceTime = tr_announcerNextManualAnnounce( tor ); 1203 1204 tr_peerMgrTorrentStats( tor, 1205 &s->peersConnected, 1206 &s->webseedsSendingToUs, 1207 &s->peersSendingToUs, 1208 &s->peersGettingFromUs, 1209 s->peersFrom ); 1210 1211 now = tr_time_msec( ); 1212 s->rawUploadSpeed_KBps = toSpeedKBps( tr_bandwidthGetRawSpeed_Bps ( &tor->bandwidth, now, TR_UP ) ); 1213 s->pieceUploadSpeed_KBps = toSpeedKBps( tr_bandwidthGetPieceSpeed_Bps( &tor->bandwidth, now, TR_UP ) ); 1214 s->rawDownloadSpeed_KBps = toSpeedKBps( tr_bandwidthGetRawSpeed_Bps ( &tor->bandwidth, now, TR_DOWN ) ); 1215 s->pieceDownloadSpeed_KBps = toSpeedKBps( tr_bandwidthGetPieceSpeed_Bps( &tor->bandwidth, now, TR_DOWN ) ); 1216 1217 s->percentComplete = tr_cpPercentComplete ( &tor->completion ); 1218 s->metadataPercentComplete = tr_torrentGetMetadataPercent( tor ); 1219 1220 s->percentDone = tr_cpPercentDone ( &tor->completion ); 1221 s->leftUntilDone = tr_cpLeftUntilDone( &tor->completion ); 1222 s->sizeWhenDone = tr_cpSizeWhenDone ( &tor->completion ); 1223 s->recheckProgress = s->activity == TR_STATUS_CHECK ? getVerifyProgress( tor ) : 0; 1224 s->activityDate = tor->activityDate; 1225 s->addedDate = tor->addedDate; 1226 s->doneDate = tor->doneDate; 1227 s->startDate = tor->startDate; 1228 s->secondsSeeding = tor->secondsSeeding; 1229 s->secondsDownloading = tor->secondsDownloading; 1230 s->idleSecs = torrentGetIdleSecs( tor ); 1231 1232 s->corruptEver = tor->corruptCur + tor->corruptPrev; 1233 s->downloadedEver = tor->downloadedCur + tor->downloadedPrev; 1234 s->uploadedEver = tor->uploadedCur + tor->uploadedPrev; 1235 s->haveValid = tr_cpHaveValid( &tor->completion ); 1236 s->haveUnchecked = tr_cpHaveTotal( &tor->completion ) - s->haveValid; 1237 s->desiredAvailable = tr_peerMgrGetDesiredAvailable( tor ); 1238 1239 s->ratio = tr_getRatio( s->uploadedEver, 1240 s->downloadedEver ? s->downloadedEver : s->haveValid ); 1241 1242 seedRatioApplies = tr_torrentGetSeedRatioBytes( tor, &seedRatioBytesLeft, 1243 &seedRatioBytesGoal ); 1244 1245 switch( s->activity ) 1246 { 1247 /* etaXLSpeed exists because if we use the piece speed directly, 1248 * brief fluctuations cause the ETA to jump all over the place. 1249 * so, etaXLSpeed is a smoothed-out version of the piece speed 1250 * to dampen the effect of fluctuations */ 1251 1252 case TR_STATUS_DOWNLOAD: 1253 if( ( tor->etaDLSpeedCalculatedAt + 800 ) < now ) { 1254 tor->etaDLSpeed_KBps = ( ( tor->etaDLSpeedCalculatedAt + 4000 ) < now ) 1255 ? s->pieceDownloadSpeed_KBps /* if no recent previous speed, no need to smooth */ 1256 : ((tor->etaDLSpeed_KBps*4.0) + s->pieceDownloadSpeed_KBps)/5.0; /* smooth across 5 readings */ 1257 tor->etaDLSpeedCalculatedAt = now; 1258 } 1259 1260 if( s->leftUntilDone > s->desiredAvailable ) 1261 s->eta = TR_ETA_NOT_AVAIL; 1262 else if( tor->etaDLSpeed_KBps < 1 ) 1263 s->eta = TR_ETA_UNKNOWN; 1264 else 1265 s->eta = s->leftUntilDone / toSpeedBytes(tor->etaDLSpeed_KBps); 1266 1267 s->etaIdle = TR_ETA_NOT_AVAIL; 1268 break; 1269 1270 case TR_STATUS_SEED: { 1271 if( !seedRatioApplies ) 1272 s->eta = TR_ETA_NOT_AVAIL; 1273 else { 1274 if( ( tor->etaULSpeedCalculatedAt + 800 ) < now ) { 1275 tor->etaULSpeed_KBps = ( ( tor->etaULSpeedCalculatedAt + 4000 ) < now ) 1276 ? s->pieceUploadSpeed_KBps /* if no recent previous speed, no need to smooth */ 1277 : ((tor->etaULSpeed_KBps*4.0) + s->pieceUploadSpeed_KBps)/5.0; /* smooth across 5 readings */ 1278 tor->etaULSpeedCalculatedAt = now; 1279 } 1280 if( tor->etaULSpeed_KBps < 1 ) 1281 s->eta = TR_ETA_UNKNOWN; 1282 else 1283 s->eta = seedRatioBytesLeft / toSpeedBytes(tor->etaULSpeed_KBps); 1284 } 1285 1286 if( tor->etaULSpeed_KBps < 1 && tr_torrentGetSeedIdle( tor, &seedIdleMinutes ) ) 1287 s->etaIdle = seedIdleMinutes * 60 - s->idleSecs; 1288 else 1289 s->etaIdle = TR_ETA_NOT_AVAIL; 1290 break; 1291 } 1292 1293 default: 1294 s->eta = TR_ETA_NOT_AVAIL; 1295 s->etaIdle = TR_ETA_NOT_AVAIL; 1296 break; 1297 } 1298 1299 /* s->haveValid is here to make sure a torrent isn't marked 'finished' 1300 * when the user hits "uncheck all" prior to starting the torrent... */ 1301 s->finished = tor->finishedSeedingByIdle || (seedRatioApplies && !seedRatioBytesLeft && s->haveValid); 1302 1303 if( !seedRatioApplies || s->finished ) 1304 s->seedRatioPercentDone = 1; 1305 else if( !seedRatioBytesGoal ) /* impossible? safeguard for div by zero */ 1306 s->seedRatioPercentDone = 0; 1307 else 1308 s->seedRatioPercentDone = (double)(seedRatioBytesGoal - seedRatioBytesLeft) / seedRatioBytesGoal; 1309 1310 tr_torrentUnlock( tor ); 1311 1312 /* test some of the constraints */ 1313 assert( s->sizeWhenDone <= tor->info.totalSize ); 1314 assert( s->leftUntilDone <= s->sizeWhenDone ); 1315 assert( s->desiredAvailable <= s->leftUntilDone ); 1316 return s; 1317} 1318 1319/*** 1320**** 1321***/ 1322 1323static uint64_t 1324fileBytesCompleted( const tr_torrent * tor, tr_file_index_t index ) 1325{ 1326 uint64_t total = 0; 1327 const tr_file * f = &tor->info.files[index]; 1328 1329 if( f->length ) 1330 { 1331 tr_block_index_t first; 1332 tr_block_index_t last; 1333 tr_torGetFileBlockRange( tor, index, &first, &last ); 1334 1335 if( first == last ) 1336 { 1337 if( tr_cpBlockIsComplete( &tor->completion, first ) ) 1338 total = f->length; 1339 } 1340 else 1341 { 1342 /* the first block */ 1343 if( tr_cpBlockIsComplete( &tor->completion, first ) ) 1344 total += tor->blockSize - ( f->offset % tor->blockSize ); 1345 1346 /* the middle blocks */ 1347 if( first + 1 < last ) { 1348 uint64_t u = tr_bitfieldCountRange( &tor->completion.blockBitfield, first+1, last ); 1349 u *= tor->blockSize; 1350 total += u; 1351 } 1352 1353 /* the last block */ 1354 if( tr_cpBlockIsComplete( &tor->completion, last ) ) 1355 total += ( f->offset + f->length ) - ( (uint64_t)tor->blockSize * last ); 1356 } 1357 } 1358 1359 return total; 1360} 1361 1362tr_file_stat * 1363tr_torrentFiles( const tr_torrent * tor, 1364 tr_file_index_t * fileCount ) 1365{ 1366 tr_file_index_t i; 1367 const tr_file_index_t n = tor->info.fileCount; 1368 tr_file_stat * files = tr_new0( tr_file_stat, n ); 1369 tr_file_stat * walk = files; 1370 const bool isSeed = tor->completeness == TR_SEED; 1371 1372 assert( tr_isTorrent( tor ) ); 1373 1374 for( i=0; i<n; ++i, ++walk ) { 1375 const uint64_t b = isSeed ? tor->info.files[i].length : fileBytesCompleted( tor, i ); 1376 walk->bytesCompleted = b; 1377 walk->progress = tor->info.files[i].length > 0 ? ( (float)b / tor->info.files[i].length ) : 1.0f; 1378 } 1379 1380 if( fileCount ) 1381 *fileCount = n; 1382 1383 return files; 1384} 1385 1386void 1387tr_torrentFilesFree( tr_file_stat * files, 1388 tr_file_index_t fileCount UNUSED ) 1389{ 1390 tr_free( files ); 1391} 1392 1393/*** 1394**** 1395***/ 1396 1397double* 1398tr_torrentWebSpeeds_KBps( const tr_torrent * tor ) 1399{ 1400 double * ret = NULL; 1401 1402 if( tr_isTorrent( tor ) ) 1403 { 1404 tr_torrentLock( tor ); 1405 ret = tr_peerMgrWebSpeeds_KBps( tor ); 1406 tr_torrentUnlock( tor ); 1407 } 1408 1409 return ret; 1410} 1411 1412tr_peer_stat * 1413tr_torrentPeers( const tr_torrent * tor, int * peerCount ) 1414{ 1415 tr_peer_stat * ret = NULL; 1416 1417 if( tr_isTorrent( tor ) ) 1418 { 1419 tr_torrentLock( tor ); 1420 ret = tr_peerMgrPeerStats( tor, peerCount ); 1421 tr_torrentUnlock( tor ); 1422 } 1423 1424 return ret; 1425} 1426 1427void 1428tr_torrentPeersFree( tr_peer_stat * peers, int peerCount UNUSED ) 1429{ 1430 tr_free( peers ); 1431} 1432 1433tr_tracker_stat * 1434tr_torrentTrackers( const tr_torrent * torrent, int * setmeTrackerCount ) 1435{ 1436 tr_tracker_stat * ret = NULL; 1437 1438 if( tr_isTorrent( torrent ) ) 1439 { 1440 tr_torrentLock( torrent ); 1441 ret = tr_announcerStats( torrent, setmeTrackerCount ); 1442 tr_torrentUnlock( torrent ); 1443 } 1444 1445 return ret; 1446} 1447 1448void 1449tr_torrentTrackersFree( tr_tracker_stat * trackers, int trackerCount ) 1450{ 1451 tr_announcerStatsFree( trackers, trackerCount ); 1452} 1453 1454void 1455tr_torrentAvailability( const tr_torrent * tor, int8_t * tab, int size ) 1456{ 1457 if( tr_isTorrent( tor ) && ( tab != NULL ) && ( size > 0 ) ) 1458 { 1459 tr_torrentLock( tor ); 1460 tr_peerMgrTorrentAvailability( tor, tab, size ); 1461 tr_torrentUnlock( tor ); 1462 } 1463} 1464 1465void 1466tr_torrentAmountFinished( const tr_torrent * tor, 1467 float * tab, 1468 int size ) 1469{ 1470 assert( tr_isTorrent( tor ) ); 1471 1472 tr_torrentLock( tor ); 1473 tr_cpGetAmountDone( &tor->completion, tab, size ); 1474 tr_torrentUnlock( tor ); 1475} 1476 1477static void 1478tr_torrentResetTransferStats( tr_torrent * tor ) 1479{ 1480 tr_torrentLock( tor ); 1481 1482 tor->downloadedPrev += tor->downloadedCur; 1483 tor->downloadedCur = 0; 1484 tor->uploadedPrev += tor->uploadedCur; 1485 tor->uploadedCur = 0; 1486 tor->corruptPrev += tor->corruptCur; 1487 tor->corruptCur = 0; 1488 1489 tr_torrentSetDirty( tor ); 1490 1491 tr_torrentUnlock( tor ); 1492} 1493 1494void 1495tr_torrentSetHasPiece( tr_torrent * tor, 1496 tr_piece_index_t pieceIndex, 1497 bool has ) 1498{ 1499 assert( tr_isTorrent( tor ) ); 1500 assert( pieceIndex < tor->info.pieceCount ); 1501 1502 if( has ) 1503 tr_cpPieceAdd( &tor->completion, pieceIndex ); 1504 else 1505 tr_cpPieceRem( &tor->completion, pieceIndex ); 1506} 1507 1508/*** 1509**** 1510***/ 1511 1512#ifndef NDEBUG 1513static bool queueIsSequenced( tr_session * ); 1514#endif 1515 1516static void 1517freeTorrent( tr_torrent * tor ) 1518{ 1519 tr_torrent * t; 1520 tr_session * session = tor->session; 1521 tr_info * inf = &tor->info; 1522 const time_t now = tr_time( ); 1523 1524 assert( !tor->isRunning ); 1525 1526 tr_sessionLock( session ); 1527 1528 tr_peerMgrRemoveTorrent( tor ); 1529 1530 tr_announcerRemoveTorrent( session->announcer, tor ); 1531 1532 tr_cpDestruct( &tor->completion ); 1533 1534 tr_free( tor->downloadDir ); 1535 tr_free( tor->incompleteDir ); 1536 1537 if( tor == session->torrentList ) 1538 session->torrentList = tor->next; 1539 else for( t = session->torrentList; t != NULL; t = t->next ) { 1540 if( t->next == tor ) { 1541 t->next = tor->next; 1542 break; 1543 } 1544 } 1545 1546 /* decrement the torrent count */ 1547 assert( session->torrentCount >= 1 ); 1548 session->torrentCount--; 1549 1550 /* resequence the queue positions */ 1551 t = NULL; 1552 while(( t = tr_torrentNext( session, t ))) { 1553 if( t->queuePosition > tor->queuePosition ) { 1554 t->queuePosition--; 1555 t->anyDate = now; 1556 } 1557 } 1558 assert( queueIsSequenced( session ) ); 1559 1560 tr_bandwidthDestruct( &tor->bandwidth ); 1561 1562 tr_metainfoFree( inf ); 1563 memset( tor, ~0, sizeof( tr_torrent ) ); 1564 tr_free( tor ); 1565 1566 tr_sessionUnlock( session ); 1567} 1568 1569/** 1570*** Start/Stop Callback 1571**/ 1572 1573static void torrentSetQueued( tr_torrent * tor, bool queued ); 1574 1575static void 1576torrentStartImpl( void * vtor ) 1577{ 1578 time_t now; 1579 tr_torrent * tor = vtor; 1580 1581 assert( tr_isTorrent( tor ) ); 1582 1583 tr_sessionLock( tor->session ); 1584 1585 tr_torrentRecheckCompleteness( tor ); 1586 torrentSetQueued( tor, false ); 1587 1588 now = tr_time( ); 1589 tor->isRunning = true; 1590 tor->completeness = tr_cpGetStatus( &tor->completion ); 1591 tor->startDate = tor->anyDate = now; 1592 tr_torrentClearError( tor ); 1593 tor->finishedSeedingByIdle = false; 1594 1595 tr_torrentResetTransferStats( tor ); 1596 tr_announcerTorrentStarted( tor ); 1597 tor->dhtAnnounceAt = now + tr_cryptoWeakRandInt( 20 ); 1598 tor->dhtAnnounce6At = now + tr_cryptoWeakRandInt( 20 ); 1599 tor->lpdAnnounceAt = now; 1600 tr_peerMgrStartTorrent( tor ); 1601 1602 tr_sessionUnlock( tor->session ); 1603} 1604 1605uint64_t 1606tr_torrentGetCurrentSizeOnDisk( const tr_torrent * tor ) 1607{ 1608 tr_file_index_t i; 1609 uint64_t byte_count = 0; 1610 const tr_file_index_t n = tor->info.fileCount; 1611 1612 for( i=0; i<n; ++i ) 1613 { 1614 struct stat sb; 1615 char * filename = tr_torrentFindFile( tor, i ); 1616 1617 sb.st_size = 0; 1618 if( filename && !stat( filename, &sb ) ) 1619 byte_count += sb.st_size; 1620 1621 tr_free( filename ); 1622 } 1623 1624 return byte_count; 1625} 1626 1627static bool 1628torrentShouldQueue( const tr_torrent * tor ) 1629{ 1630 const tr_direction dir = tr_torrentGetQueueDirection( tor ); 1631 1632 return tr_sessionCountQueueFreeSlots( tor->session, dir ) == 0; 1633} 1634 1635static void 1636torrentStart( tr_torrent * tor, bool bypass_queue ) 1637{ 1638 switch( torrentGetActivity( tor ) ) 1639 { 1640 case TR_STATUS_SEED: 1641 case TR_STATUS_DOWNLOAD: 1642 return; /* already started */ 1643 break; 1644 1645 case TR_STATUS_SEED_WAIT: 1646 case TR_STATUS_DOWNLOAD_WAIT: 1647 if( !bypass_queue ) 1648 return; /* already queued */ 1649 break; 1650 1651 case TR_STATUS_CHECK: 1652 case TR_STATUS_CHECK_WAIT: 1653 /* verifying right now... wait until that's done so 1654 * we'll know what completeness to use/announce */ 1655 tor->startAfterVerify = true; 1656 return; 1657 break; 1658 1659 case TR_STATUS_STOPPED: 1660 if( !bypass_queue && torrentShouldQueue( tor ) ) { 1661 torrentSetQueued( tor, true ); 1662 return; 1663 } 1664 break; 1665 } 1666 1667 /* don't allow the torrent to be started if the files disappeared */ 1668 if( setLocalErrorIfFilesDisappeared( tor ) ) 1669 return; 1670 1671 /* otherwise, start it now... */ 1672 tr_sessionLock( tor->session ); 1673 1674 /* allow finished torrents to be resumed */ 1675 if( tr_torrentIsSeedRatioDone( tor ) ) { 1676 tr_torinf( tor, _( "Restarted manually -- disabling its seed ratio" ) ); 1677 tr_torrentSetRatioMode( tor, TR_RATIOLIMIT_UNLIMITED ); 1678 } 1679 1680 /* corresponds to the peer_id sent as a tracker request parameter. 1681 * one tracker admin says: "When the same torrent is opened and 1682 * closed and opened again without quitting Transmission ... 1683 * change the peerid. It would help sometimes if a stopped event 1684 * was missed to ensure that we didn't think someone was cheating. */ 1685 tr_peerIdInit( tor->peer_id ); 1686 tor->isRunning = 1; 1687 tr_torrentSetDirty( tor ); 1688 tr_runInEventThread( tor->session, torrentStartImpl, tor ); 1689 1690 tr_sessionUnlock( tor->session ); 1691} 1692 1693void 1694tr_torrentStart( tr_torrent * tor ) 1695{ 1696 if( tr_isTorrent( tor ) ) 1697 torrentStart( tor, false ); 1698} 1699 1700void 1701tr_torrentStartNow( tr_torrent * tor ) 1702{ 1703 if( tr_isTorrent( tor ) ) 1704 torrentStart( tor, true ); 1705} 1706 1707static void 1708torrentRecheckDoneImpl( void * vtor ) 1709{ 1710 tr_torrent * tor = vtor; 1711 assert( tr_isTorrent( tor ) ); 1712 1713 tr_torrentRecheckCompleteness( tor ); 1714 1715 if( tor->startAfterVerify ) { 1716 tor->startAfterVerify = false; 1717 torrentStart( tor, false ); 1718 } 1719} 1720 1721static void 1722torrentRecheckDoneCB( tr_torrent * tor ) 1723{ 1724 assert( tr_isTorrent( tor ) ); 1725 1726 tr_runInEventThread( tor->session, torrentRecheckDoneImpl, tor ); 1727} 1728 1729static void 1730verifyTorrent( void * vtor ) 1731{ 1732 bool startAfter; 1733 tr_torrent * tor = vtor; 1734 1735 tr_sessionLock( tor->session ); 1736 1737 /* if the torrent's already being verified, stop it */ 1738 tr_verifyRemove( tor ); 1739 1740 startAfter = (tor->isRunning || tor->startAfterVerify) && !tor->isStopping; 1741 1742 if( tor->isRunning ) 1743 tr_torrentStop( tor ); 1744 1745 tor->startAfterVerify = startAfter; 1746 1747 if( setLocalErrorIfFilesDisappeared( tor ) ) 1748 tor->startAfterVerify = false; 1749 else 1750 tr_verifyAdd( tor, torrentRecheckDoneCB ); 1751 1752 tr_sessionUnlock( tor->session ); 1753} 1754 1755void 1756tr_torrentVerify( tr_torrent * tor ) 1757{ 1758 if( tr_isTorrent( tor ) ) 1759 tr_runInEventThread( tor->session, verifyTorrent, tor ); 1760} 1761 1762void 1763tr_torrentSave( tr_torrent * tor ) 1764{ 1765 assert( tr_isTorrent( tor ) ); 1766 1767 if( tor->isDirty ) 1768 { 1769 tor->isDirty = false; 1770 tr_torrentSaveResume( tor ); 1771 } 1772} 1773 1774static void 1775stopTorrent( void * vtor ) 1776{ 1777 tr_torrent * tor = vtor; 1778 tr_torinf( tor, "Pausing" ); 1779 1780 assert( tr_isTorrent( tor ) ); 1781 1782 tr_torrentLock( tor ); 1783 1784 tr_verifyRemove( tor ); 1785 torrentSetQueued( tor, false ); 1786 tr_peerMgrStopTorrent( tor ); 1787 tr_announcerTorrentStopped( tor ); 1788 tr_cacheFlushTorrent( tor->session->cache, tor ); 1789 1790 tr_fdTorrentClose( tor->session, tor->uniqueId ); 1791 1792 if( !tor->isDeleting ) 1793 tr_torrentSave( tor ); 1794 1795 tr_torrentUnlock( tor ); 1796} 1797 1798void 1799tr_torrentStop( tr_torrent * tor ) 1800{ 1801 assert( tr_isTorrent( tor ) ); 1802 1803 if( tr_isTorrent( tor ) ) 1804 { 1805 tr_sessionLock( tor->session ); 1806 1807 tor->isRunning = 0; 1808 tor->isStopping = 0; 1809 tr_torrentSetDirty( tor ); 1810 tr_runInEventThread( tor->session, stopTorrent, tor ); 1811 1812 tr_sessionUnlock( tor->session ); 1813 } 1814} 1815 1816static void 1817closeTorrent( void * vtor ) 1818{ 1819 tr_benc * d; 1820 tr_torrent * tor = vtor; 1821 1822 assert( tr_isTorrent( tor ) ); 1823 1824 d = tr_bencListAddDict( &tor->session->removedTorrents, 2 ); 1825 tr_bencDictAddInt( d, "id", tor->uniqueId ); 1826 tr_bencDictAddInt( d, "date", tr_time( ) ); 1827 1828 tr_torinf( tor, "%s", _( "Removing torrent" ) ); 1829 1830 stopTorrent( tor ); 1831 1832 if( tor->isDeleting ) 1833 { 1834 tr_metainfoRemoveSaved( tor->session, &tor->info ); 1835 tr_torrentRemoveResume( tor ); 1836 } 1837 1838 tor->isRunning = 0; 1839 freeTorrent( tor ); 1840} 1841 1842void 1843tr_torrentFree( tr_torrent * tor ) 1844{ 1845 if( tr_isTorrent( tor ) ) 1846 { 1847 tr_session * session = tor->session; 1848 assert( tr_isSession( session ) ); 1849 tr_sessionLock( session ); 1850 1851 tr_torrentClearCompletenessCallback( tor ); 1852 tr_runInEventThread( session, closeTorrent, tor ); 1853 1854 tr_sessionUnlock( session ); 1855 } 1856} 1857 1858struct remove_data 1859{ 1860 tr_torrent * tor; 1861 bool deleteFlag; 1862 tr_fileFunc * deleteFunc; 1863}; 1864 1865static void tr_torrentDeleteLocalData( tr_torrent *, tr_fileFunc ); 1866 1867static void 1868removeTorrent( void * vdata ) 1869{ 1870 struct remove_data * data = vdata; 1871 1872 if( data->deleteFlag ) 1873 tr_torrentDeleteLocalData( data->tor, data->deleteFunc ); 1874 1875 tr_torrentClearCompletenessCallback( data->tor ); 1876 closeTorrent( data->tor ); 1877 tr_free( data ); 1878} 1879 1880void 1881tr_torrentRemove( tr_torrent * tor, 1882 bool deleteFlag, 1883 tr_fileFunc deleteFunc ) 1884{ 1885 struct remove_data * data; 1886 1887 assert( tr_isTorrent( tor ) ); 1888 tor->isDeleting = 1; 1889 1890 data = tr_new0( struct remove_data, 1 ); 1891 data->tor = tor; 1892 data->deleteFlag = deleteFlag; 1893 data->deleteFunc = deleteFunc; 1894 tr_runInEventThread( tor->session, removeTorrent, data ); 1895} 1896 1897/** 1898*** Completeness 1899**/ 1900 1901static const char * 1902getCompletionString( int type ) 1903{ 1904 switch( type ) 1905 { 1906 /* Translators: this is a minor point that's safe to skip over, but FYI: 1907 "Complete" and "Done" are specific, different terms in Transmission: 1908 "Complete" means we've downloaded every file in the torrent. 1909 "Done" means we're done downloading the files we wanted, but NOT all 1910 that exist */ 1911 case TR_PARTIAL_SEED: 1912 return _( "Done" ); 1913 1914 case TR_SEED: 1915 return _( "Complete" ); 1916 1917 default: 1918 return _( "Incomplete" ); 1919 } 1920} 1921 1922static void 1923fireCompletenessChange( tr_torrent * tor, 1924 tr_completeness status, 1925 bool wasRunning ) 1926{ 1927 assert( ( status == TR_LEECH ) 1928 || ( status == TR_SEED ) 1929 || ( status == TR_PARTIAL_SEED ) ); 1930 1931 if( tor->completeness_func ) 1932 tor->completeness_func( tor, status, wasRunning, 1933 tor->completeness_func_user_data ); 1934} 1935 1936void 1937tr_torrentSetCompletenessCallback( tr_torrent * tor, 1938 tr_torrent_completeness_func func, 1939 void * user_data ) 1940{ 1941 assert( tr_isTorrent( tor ) ); 1942 1943 tor->completeness_func = func; 1944 tor->completeness_func_user_data = user_data; 1945} 1946 1947void 1948tr_torrentClearCompletenessCallback( tr_torrent * torrent ) 1949{ 1950 tr_torrentSetCompletenessCallback( torrent, NULL, NULL ); 1951} 1952 1953void 1954tr_torrentSetRatioLimitHitCallback( tr_torrent * tor, 1955 tr_torrent_ratio_limit_hit_func func, 1956 void * user_data ) 1957{ 1958 assert( tr_isTorrent( tor ) ); 1959 1960 tor->ratio_limit_hit_func = func; 1961 tor->ratio_limit_hit_func_user_data = user_data; 1962} 1963 1964void 1965tr_torrentClearRatioLimitHitCallback( tr_torrent * torrent ) 1966{ 1967 tr_torrentSetRatioLimitHitCallback( torrent, NULL, NULL ); 1968} 1969 1970void 1971tr_torrentSetIdleLimitHitCallback( tr_torrent * tor, 1972 tr_torrent_idle_limit_hit_func func, 1973 void * user_data ) 1974{ 1975 assert( tr_isTorrent( tor ) ); 1976 1977 tor->idle_limit_hit_func = func; 1978 tor->idle_limit_hit_func_user_data = user_data; 1979} 1980 1981void 1982tr_torrentClearIdleLimitHitCallback( tr_torrent * torrent ) 1983{ 1984 tr_torrentSetIdleLimitHitCallback( torrent, NULL, NULL ); 1985} 1986 1987static void 1988onSigCHLD( int i UNUSED ) 1989{ 1990 waitpid( -1, NULL, WNOHANG ); 1991} 1992 1993static void 1994torrentCallScript( const tr_torrent * tor, const char * script ) 1995{ 1996 char timeStr[128]; 1997 const time_t now = tr_time( ); 1998 1999 tr_strlcpy( timeStr, ctime( &now ), sizeof( timeStr ) ); 2000 *strchr( timeStr,'\n' ) = '\0'; 2001 2002 if( script && *script ) 2003 { 2004 int i; 2005 char * cmd[] = { tr_strdup( script ), NULL }; 2006 char * env[] = { 2007 tr_strdup_printf( "TR_APP_VERSION=%s", SHORT_VERSION_STRING ), 2008 tr_strdup_printf( "TR_TIME_LOCALTIME=%s", timeStr ), 2009 tr_strdup_printf( "TR_TORRENT_DIR=%s", tor->currentDir ), 2010 tr_strdup_printf( "TR_TORRENT_ID=%d", tr_torrentId( tor ) ), 2011 tr_strdup_printf( "TR_TORRENT_HASH=%s", tor->info.hashString ), 2012 tr_strdup_printf( "TR_TORRENT_NAME=%s", tr_torrentName( tor ) ), 2013 NULL }; 2014 2015 tr_torinf( tor, "Calling script \"%s\"", script ); 2016 2017#ifdef WIN32 2018 _spawnvpe( _P_NOWAIT, script, (const char*)cmd, env ); 2019#else 2020 signal( SIGCHLD, onSigCHLD ); 2021 2022 if( !fork( ) ) 2023 { 2024 for (i=0; env[i]; ++i) 2025 putenv(env[i]); 2026 execvp( script, cmd ); 2027 _exit( 0 ); 2028 } 2029#endif 2030 2031 for( i=0; cmd[i]; ++i ) tr_free( cmd[i] ); 2032 for( i=0; env[i]; ++i ) tr_free( env[i] ); 2033 } 2034} 2035 2036void 2037tr_torrentRecheckCompleteness( tr_torrent * tor ) 2038{ 2039 tr_completeness completeness; 2040 2041 assert( tr_isTorrent( tor ) ); 2042 2043 tr_torrentLock( tor ); 2044 2045 completeness = tr_cpGetStatus( &tor->completion ); 2046 2047 if( completeness != tor->completeness ) 2048 { 2049 const int recentChange = tor->downloadedCur != 0; 2050 const bool wasLeeching = !tr_torrentIsSeed( tor ); 2051 const bool wasRunning = tor->isRunning; 2052 2053 if( recentChange ) 2054 { 2055 tr_torinf( tor, _( "State changed from \"%1$s\" to \"%2$s\"" ), 2056 getCompletionString( tor->completeness ), 2057 getCompletionString( completeness ) ); 2058 } 2059 2060 tor->completeness = completeness; 2061 tr_fdTorrentClose( tor->session, tor->uniqueId ); 2062 2063 if( tr_torrentIsSeed( tor ) ) 2064 { 2065 if( recentChange ) 2066 { 2067 tr_announcerTorrentCompleted( tor ); 2068 tor->doneDate = tor->anyDate = tr_time( ); 2069 } 2070 2071 if( wasLeeching && wasRunning ) 2072 { 2073 /* clear interested flag on all peers */ 2074 tr_peerMgrClearInterest( tor ); 2075 2076 /* if completeness was TR_LEECH then the seed limit check will have been skipped in bandwidthPulse */ 2077 tr_torrentCheckSeedLimit( tor ); 2078 } 2079 2080 if( tor->currentDir == tor->incompleteDir ) 2081 tr_torrentSetLocation( tor, tor->downloadDir, true, NULL, NULL ); 2082 2083 if( tr_sessionIsTorrentDoneScriptEnabled( tor->session ) ) 2084 torrentCallScript( tor, tr_sessionGetTorrentDoneScript( tor->session ) ); 2085 } 2086 2087 fireCompletenessChange( tor, completeness, wasRunning ); 2088 2089 tr_torrentSetDirty( tor ); 2090 } 2091 2092 tr_torrentUnlock( tor ); 2093} 2094 2095/*** 2096**** 2097***/ 2098 2099static void 2100tr_torrentFireMetadataCompleted( tr_torrent * tor ) 2101{ 2102 assert( tr_isTorrent( tor ) ); 2103 2104 if( tor->metadata_func ) 2105 tor->metadata_func( tor, tor->metadata_func_user_data ); 2106} 2107 2108void 2109tr_torrentSetMetadataCallback( tr_torrent * tor, 2110 tr_torrent_metadata_func func, 2111 void * user_data ) 2112{ 2113 assert( tr_isTorrent( tor ) ); 2114 2115 tor->metadata_func = func; 2116 tor->metadata_func_user_data = user_data; 2117} 2118 2119 2120/** 2121*** File priorities 2122**/ 2123 2124void 2125tr_torrentInitFilePriority( tr_torrent * tor, 2126 tr_file_index_t fileIndex, 2127 tr_priority_t priority ) 2128{ 2129 tr_piece_index_t i; 2130 tr_file * file; 2131 2132 assert( tr_isTorrent( tor ) ); 2133 assert( fileIndex < tor->info.fileCount ); 2134 assert( tr_isPriority( priority ) ); 2135 2136 file = &tor->info.files[fileIndex]; 2137 file->priority = priority; 2138 for( i = file->firstPiece; i <= file->lastPiece; ++i ) 2139 tor->info.pieces[i].priority = calculatePiecePriority( tor, i, fileIndex ); 2140} 2141 2142void 2143tr_torrentSetFilePriorities( tr_torrent * tor, 2144 const tr_file_index_t * files, 2145 tr_file_index_t fileCount, 2146 tr_priority_t priority ) 2147{ 2148 tr_file_index_t i; 2149 assert( tr_isTorrent( tor ) ); 2150 tr_torrentLock( tor ); 2151 2152 for( i = 0; i < fileCount; ++i ) 2153 if( files[i] < tor->info.fileCount ) 2154 tr_torrentInitFilePriority( tor, files[i], priority ); 2155 tr_torrentSetDirty( tor ); 2156 tr_peerMgrRebuildRequests( tor ); 2157 2158 tr_torrentUnlock( tor ); 2159} 2160 2161tr_priority_t* 2162tr_torrentGetFilePriorities( const tr_torrent * tor ) 2163{ 2164 tr_file_index_t i; 2165 tr_priority_t * p; 2166 2167 assert( tr_isTorrent( tor ) ); 2168 2169 tr_torrentLock( tor ); 2170 p = tr_new0( tr_priority_t, tor->info.fileCount ); 2171 for( i = 0; i < tor->info.fileCount; ++i ) 2172 p[i] = tor->info.files[i].priority; 2173 tr_torrentUnlock( tor ); 2174 2175 return p; 2176} 2177 2178/** 2179*** File DND 2180**/ 2181 2182static void 2183setFileDND( tr_torrent * tor, tr_file_index_t fileIndex, int doDownload ) 2184{ 2185 const int8_t dnd = !doDownload; 2186 tr_piece_index_t firstPiece; 2187 int8_t firstPieceDND; 2188 tr_piece_index_t lastPiece; 2189 int8_t lastPieceDND; 2190 tr_file_index_t i; 2191 tr_file * file = &tor->info.files[fileIndex]; 2192 2193 file->dnd = dnd; 2194 firstPiece = file->firstPiece; 2195 lastPiece = file->lastPiece; 2196 2197 /* can't set the first piece to DND unless 2198 every file using that piece is DND */ 2199 firstPieceDND = dnd; 2200 if( fileIndex > 0 ) 2201 { 2202 for( i = fileIndex - 1; firstPieceDND; --i ) 2203 { 2204 if( tor->info.files[i].lastPiece != firstPiece ) 2205 break; 2206 firstPieceDND = tor->info.files[i].dnd; 2207 if( !i ) 2208 break; 2209 } 2210 } 2211 2212 /* can't set the last piece to DND unless 2213 every file using that piece is DND */ 2214 lastPieceDND = dnd; 2215 for( i = fileIndex + 1; lastPieceDND && i < tor->info.fileCount; ++i ) 2216 { 2217 if( tor->info.files[i].firstPiece != lastPiece ) 2218 break; 2219 lastPieceDND = tor->info.files[i].dnd; 2220 } 2221 2222 if( firstPiece == lastPiece ) 2223 { 2224 tor->info.pieces[firstPiece].dnd = firstPieceDND && lastPieceDND; 2225 } 2226 else 2227 { 2228 tr_piece_index_t pp; 2229 tor->info.pieces[firstPiece].dnd = firstPieceDND; 2230 tor->info.pieces[lastPiece].dnd = lastPieceDND; 2231 for( pp = firstPiece + 1; pp < lastPiece; ++pp ) 2232 tor->info.pieces[pp].dnd = dnd; 2233 } 2234} 2235 2236void 2237tr_torrentInitFileDLs( tr_torrent * tor, 2238 const tr_file_index_t * files, 2239 tr_file_index_t fileCount, 2240 bool doDownload ) 2241{ 2242 tr_file_index_t i; 2243 2244 assert( tr_isTorrent( tor ) ); 2245 2246 tr_torrentLock( tor ); 2247 2248 for( i=0; i<fileCount; ++i ) 2249 if( files[i] < tor->info.fileCount ) 2250 setFileDND( tor, files[i], doDownload ); 2251 2252 tr_cpInvalidateDND( &tor->completion ); 2253 2254 tr_torrentUnlock( tor ); 2255} 2256 2257void 2258tr_torrentSetFileDLs( tr_torrent * tor, 2259 const tr_file_index_t * files, 2260 tr_file_index_t fileCount, 2261 bool doDownload ) 2262{ 2263 assert( tr_isTorrent( tor ) ); 2264 tr_torrentLock( tor ); 2265 2266 tr_torrentInitFileDLs( tor, files, fileCount, doDownload ); 2267 tr_torrentSetDirty( tor ); 2268 tr_peerMgrRebuildRequests( tor ); 2269 2270 tr_torrentUnlock( tor ); 2271} 2272 2273/*** 2274**** 2275***/ 2276 2277tr_priority_t 2278tr_torrentGetPriority( const tr_torrent * tor ) 2279{ 2280 assert( tr_isTorrent( tor ) ); 2281 2282 return tor->bandwidth.priority; 2283} 2284 2285void 2286tr_torrentSetPriority( tr_torrent * tor, tr_priority_t priority ) 2287{ 2288 assert( tr_isTorrent( tor ) ); 2289 assert( tr_isPriority( priority ) ); 2290 2291 if( tor->bandwidth.priority != priority ) 2292 { 2293 tor->bandwidth.priority = priority; 2294 2295 tr_torrentSetDirty( tor ); 2296 } 2297} 2298 2299/*** 2300**** 2301***/ 2302 2303void 2304tr_torrentSetPeerLimit( tr_torrent * tor, 2305 uint16_t maxConnectedPeers ) 2306{ 2307 assert( tr_isTorrent( tor ) ); 2308 2309 if ( tor->maxConnectedPeers != maxConnectedPeers ) 2310 { 2311 tor->maxConnectedPeers = maxConnectedPeers; 2312 2313 tr_torrentSetDirty( tor ); 2314 } 2315} 2316 2317uint16_t 2318tr_torrentGetPeerLimit( const tr_torrent * tor ) 2319{ 2320 assert( tr_isTorrent( tor ) ); 2321 2322 return tor->maxConnectedPeers; 2323} 2324 2325/*** 2326**** 2327***/ 2328 2329void 2330tr_torrentGetBlockLocation( const tr_torrent * tor, 2331 tr_block_index_t block, 2332 tr_piece_index_t * piece, 2333 uint32_t * offset, 2334 uint32_t * length ) 2335{ 2336 uint64_t pos = block; 2337 pos *= tor->blockSize; 2338 *piece = pos / tor->info.pieceSize; 2339 *offset = pos - ( *piece * tor->info.pieceSize ); 2340 *length = tr_torBlockCountBytes( tor, block ); 2341} 2342 2343 2344tr_block_index_t 2345_tr_block( const tr_torrent * tor, 2346 tr_piece_index_t index, 2347 uint32_t offset ) 2348{ 2349 tr_block_index_t ret; 2350 2351 assert( tr_isTorrent( tor ) ); 2352 2353 ret = index; 2354 ret *= ( tor->info.pieceSize / tor->blockSize ); 2355 ret += offset / tor->blockSize; 2356 return ret; 2357} 2358 2359bool 2360tr_torrentReqIsValid( const tr_torrent * tor, 2361 tr_piece_index_t index, 2362 uint32_t offset, 2363 uint32_t length ) 2364{ 2365 int err = 0; 2366 2367 assert( tr_isTorrent( tor ) ); 2368 2369 if( index >= tor->info.pieceCount ) 2370 err = 1; 2371 else if( length < 1 ) 2372 err = 2; 2373 else if( ( offset + length ) > tr_torPieceCountBytes( tor, index ) ) 2374 err = 3; 2375 else if( length > MAX_BLOCK_SIZE ) 2376 err = 4; 2377 else if( tr_pieceOffset( tor, index, offset, length ) > tor->info.totalSize ) 2378 err = 5; 2379 2380 if( err ) tr_tordbg( tor, "index %lu offset %lu length %lu err %d\n", 2381 (unsigned long)index, 2382 (unsigned long)offset, 2383 (unsigned long)length, 2384 err ); 2385 2386 return !err; 2387} 2388 2389uint64_t 2390tr_pieceOffset( const tr_torrent * tor, 2391 tr_piece_index_t index, 2392 uint32_t offset, 2393 uint32_t length ) 2394{ 2395 uint64_t ret; 2396 2397 assert( tr_isTorrent( tor ) ); 2398 2399 ret = tor->info.pieceSize; 2400 ret *= index; 2401 ret += offset; 2402 ret += length; 2403 return ret; 2404} 2405 2406void 2407tr_torGetFileBlockRange( const tr_torrent * tor, 2408 const tr_file_index_t file, 2409 tr_block_index_t * first, 2410 tr_block_index_t * last ) 2411{ 2412 const tr_file * f = &tor->info.files[file]; 2413 uint64_t offset = f->offset; 2414 *first = offset / tor->blockSize; 2415 if( !f->length ) 2416 *last = *first; 2417 else { 2418 offset += f->length - 1; 2419 *last = offset / tor->blockSize; 2420 } 2421} 2422 2423void 2424tr_torGetPieceBlockRange( const tr_torrent * tor, 2425 const tr_piece_index_t piece, 2426 tr_block_index_t * first, 2427 tr_block_index_t * last ) 2428{ 2429 uint64_t offset = tor->info.pieceSize; 2430 offset *= piece; 2431 *first = offset / tor->blockSize; 2432 offset += ( tr_torPieceCountBytes( tor, piece ) - 1 ); 2433 *last = offset / tor->blockSize; 2434} 2435 2436 2437/*** 2438**** 2439***/ 2440 2441void 2442tr_torrentSetPieceChecked( tr_torrent * tor, tr_piece_index_t pieceIndex ) 2443{ 2444 assert( tr_isTorrent( tor ) ); 2445 assert( pieceIndex < tor->info.pieceCount ); 2446 2447 tor->info.pieces[pieceIndex].timeChecked = tr_time( ); 2448} 2449 2450void 2451tr_torrentSetChecked( tr_torrent * tor, time_t when ) 2452{ 2453 tr_piece_index_t i, n; 2454 2455 assert( tr_isTorrent( tor ) ); 2456 2457 for( i=0, n=tor->info.pieceCount; i!=n; ++i ) 2458 tor->info.pieces[i].timeChecked = when; 2459} 2460 2461bool 2462tr_torrentCheckPiece( tr_torrent * tor, tr_piece_index_t pieceIndex ) 2463{ 2464 const bool pass = tr_ioTestPiece( tor, pieceIndex ); 2465 2466 tr_deeplog_tor( tor, "[LAZY] tr_torrentCheckPiece tested piece %zu, pass==%d", (size_t)pieceIndex, (int)pass ); 2467 tr_torrentSetHasPiece( tor, pieceIndex, pass ); 2468 tr_torrentSetPieceChecked( tor, pieceIndex ); 2469 tor->anyDate = tr_time( ); 2470 tr_torrentSetDirty( tor ); 2471 2472 return pass; 2473} 2474 2475time_t 2476tr_torrentGetFileMTime( const tr_torrent * tor, tr_file_index_t i ) 2477{ 2478 time_t mtime = 0; 2479 if( !tr_fdFileGetCachedMTime( tor->session, tor->uniqueId, i, &mtime ) ) 2480 tr_torrentFindFile2( tor, i, NULL, NULL, &mtime ); 2481 return mtime; 2482} 2483 2484bool 2485tr_torrentPieceNeedsCheck( const tr_torrent * tor, tr_piece_index_t p ) 2486{ 2487 uint64_t unused; 2488 tr_file_index_t f; 2489 const tr_info * inf = tr_torrentInfo( tor ); 2490 2491 /* if we've never checked this piece, then it needs to be checked */ 2492 if( !inf->pieces[p].timeChecked ) 2493 return true; 2494 2495 /* If we think we've completed one of the files in this piece, 2496 * but it's been modified since we last checked it, 2497 * then it needs to be rechecked */ 2498 tr_ioFindFileLocation( tor, p, 0, &f, &unused ); 2499 for( ; f < inf->fileCount && pieceHasFile( p, &inf->files[f] ); ++f ) 2500 if( tr_cpFileIsComplete( &tor->completion, f ) ) 2501 if( tr_torrentGetFileMTime( tor, f ) > inf->pieces[p].timeChecked ) 2502 return true; 2503 2504 return false; 2505} 2506 2507/*** 2508**** 2509***/ 2510 2511static int 2512compareTrackerByTier( const void * va, const void * vb ) 2513{ 2514 const tr_tracker_info * a = va; 2515 const tr_tracker_info * b = vb; 2516 2517 /* sort by tier */ 2518 if( a->tier != b->tier ) 2519 return a->tier - b->tier; 2520 2521 /* get the effects of a stable sort by comparing the two elements' addresses */ 2522 return a - b; 2523} 2524 2525bool 2526tr_torrentSetAnnounceList( tr_torrent * tor, 2527 const tr_tracker_info * trackers_in, 2528 int trackerCount ) 2529{ 2530 int i; 2531 tr_benc metainfo; 2532 bool ok = true; 2533 tr_tracker_info * trackers; 2534 2535 tr_torrentLock( tor ); 2536 2537 assert( tr_isTorrent( tor ) ); 2538 2539 /* ensure the trackers' tiers are in ascending order */ 2540 trackers = tr_memdup( trackers_in, sizeof( tr_tracker_info ) * trackerCount ); 2541 qsort( trackers, trackerCount, sizeof( tr_tracker_info ), compareTrackerByTier ); 2542 2543 /* look for bad URLs */ 2544 for( i=0; ok && i<trackerCount; ++i ) 2545 if( !tr_urlIsValidTracker( trackers[i].announce ) ) 2546 ok = false; 2547 2548 /* save to the .torrent file */ 2549 if( ok && !tr_bencLoadFile( &metainfo, TR_FMT_BENC, tor->info.torrent ) ) 2550 { 2551 bool hasInfo; 2552 tr_info tmpInfo; 2553 2554 /* remove the old fields */ 2555 tr_bencDictRemove( &metainfo, "announce" ); 2556 tr_bencDictRemove( &metainfo, "announce-list" ); 2557 2558 /* add the new fields */ 2559 if( trackerCount > 0 ) 2560 { 2561 tr_bencDictAddStr( &metainfo, "announce", trackers[0].announce ); 2562 } 2563 if( trackerCount > 1 ) 2564 { 2565 int i; 2566 int prevTier = -1; 2567 tr_benc * tier = NULL; 2568 tr_benc * announceList = tr_bencDictAddList( &metainfo, "announce-list", 0 ); 2569 2570 for( i=0; i<trackerCount; ++i ) { 2571 if( prevTier != trackers[i].tier ) { 2572 prevTier = trackers[i].tier; 2573 tier = tr_bencListAddList( announceList, 0 ); 2574 } 2575 tr_bencListAddStr( tier, trackers[i].announce ); 2576 } 2577 } 2578 2579 /* try to parse it back again, to make sure it's good */ 2580 memset( &tmpInfo, 0, sizeof( tr_info ) ); 2581 if( tr_metainfoParse( tor->session, &metainfo, &tmpInfo, 2582 &hasInfo, &tor->infoDictLength ) ) 2583 { 2584 /* it's good, so keep these new trackers and free the old ones */ 2585 2586 tr_info swap; 2587 swap.trackers = tor->info.trackers; 2588 swap.trackerCount = tor->info.trackerCount; 2589 tor->info.trackers = tmpInfo.trackers; 2590 tor->info.trackerCount = tmpInfo.trackerCount; 2591 tmpInfo.trackers = swap.trackers; 2592 tmpInfo.trackerCount = swap.trackerCount; 2593 2594 tr_metainfoFree( &tmpInfo ); 2595 tr_bencToFile( &metainfo, TR_FMT_BENC, tor->info.torrent ); 2596 } 2597 2598 /* cleanup */ 2599 tr_bencFree( &metainfo ); 2600 2601 /* if we had a tracker-related error on this torrent, 2602 * and that tracker's been removed, 2603 * then clear the error */ 2604 if( ( tor->error == TR_STAT_TRACKER_WARNING ) 2605 || ( tor->error == TR_STAT_TRACKER_ERROR ) ) 2606 { 2607 bool clear = true; 2608 2609 for( i=0; clear && i<trackerCount; ++i ) 2610 if( !strcmp( trackers[i].announce, tor->errorTracker ) ) 2611 clear = false; 2612 2613 if( clear ) 2614 tr_torrentClearError( tor ); 2615 } 2616 2617 /* tell the announcer to reload this torrent's tracker list */ 2618 tr_announcerResetTorrent( tor->session->announcer, tor ); 2619 } 2620 2621 tr_torrentUnlock( tor ); 2622 2623 tr_free( trackers ); 2624 return ok; 2625} 2626 2627/** 2628*** 2629**/ 2630 2631void 2632tr_torrentSetAddedDate( tr_torrent * tor, 2633 time_t t ) 2634{ 2635 assert( tr_isTorrent( tor ) ); 2636 2637 tor->addedDate = t; 2638 tor->anyDate = MAX( tor->anyDate, tor->addedDate ); 2639} 2640 2641void 2642tr_torrentSetActivityDate( tr_torrent * tor, time_t t ) 2643{ 2644 assert( tr_isTorrent( tor ) ); 2645 2646 tor->activityDate = t; 2647 tor->anyDate = MAX( tor->anyDate, tor->activityDate ); 2648} 2649 2650void 2651tr_torrentSetDoneDate( tr_torrent * tor, 2652 time_t t ) 2653{ 2654 assert( tr_isTorrent( tor ) ); 2655 2656 tor->doneDate = t; 2657 tor->anyDate = MAX( tor->anyDate, tor->doneDate ); 2658} 2659 2660/** 2661*** 2662**/ 2663 2664uint64_t 2665tr_torrentGetBytesLeftToAllocate( const tr_torrent * tor ) 2666{ 2667 tr_file_index_t i; 2668 uint64_t bytesLeft = 0; 2669 2670 assert( tr_isTorrent( tor ) ); 2671 2672 for( i=0; i<tor->info.fileCount; ++i ) 2673 { 2674 if( !tor->info.files[i].dnd ) 2675 { 2676 struct stat sb; 2677 const uint64_t length = tor->info.files[i].length; 2678 char * path = tr_torrentFindFile( tor, i ); 2679 2680 bytesLeft += length; 2681 2682 if( ( path != NULL ) && !stat( path, &sb ) 2683 && S_ISREG( sb.st_mode ) 2684 && ( (uint64_t)sb.st_size <= length ) ) 2685 bytesLeft -= sb.st_size; 2686 2687 tr_free( path ); 2688 } 2689 } 2690 2691 return bytesLeft; 2692} 2693 2694/**** 2695***** Removing the torrent's local data 2696****/ 2697 2698static bool 2699isJunkFile( const char * base ) 2700{ 2701 int i; 2702 static const char * files[] = { ".DS_Store", "desktop.ini", "Thumbs.db" }; 2703 static const int file_count = sizeof(files) / sizeof(files[0]); 2704 2705 for( i=0; i<file_count; ++i ) 2706 if( !strcmp( base, files[i] ) ) 2707 return true; 2708 2709#ifdef SYS_DARWIN 2710 /* check for resource forks. <http://support.apple.com/kb/TA20578> */ 2711 if( !memcmp( base, "._", 2 ) ) 2712 return true; 2713#endif 2714 2715 return false; 2716} 2717 2718static void 2719removeEmptyFoldersAndJunkFiles( const char * folder ) 2720{ 2721 DIR * odir; 2722 if(( odir = opendir( folder ))) { 2723 struct dirent * d; 2724 while(( d = readdir( odir ))) { 2725 if( strcmp( d->d_name, "." ) && strcmp( d->d_name, ".." ) ) { 2726 struct stat sb; 2727 char * filename = tr_buildPath( folder, d->d_name, NULL ); 2728 if( !stat( filename, &sb ) && S_ISDIR( sb.st_mode ) ) 2729 removeEmptyFoldersAndJunkFiles( filename ); 2730 else if( isJunkFile( d->d_name ) ) 2731 remove( filename ); 2732 tr_free( filename ); 2733 } 2734 } 2735 remove( folder ); 2736 closedir( odir ); 2737 } 2738} 2739 2740/** 2741 * This convoluted code does something (seemingly) simple: 2742 * remove the torrent's local files. 2743 * 2744 * Fun complications: 2745 * 1. Try to preserve the directory hierarchy in the recycle bin. 2746 * 2. If there are nontorrent files, don't delete them... 2747 * 3. ...unless the other files are "junk", such as .DS_Store 2748 */ 2749static void 2750deleteLocalData( tr_torrent * tor, tr_fileFunc func ) 2751{ 2752 int i, n; 2753 tr_file_index_t f; 2754 char * base; 2755 DIR * odir; 2756 char * tmpdir = NULL; 2757 tr_ptrArray files = TR_PTR_ARRAY_INIT; 2758 tr_ptrArray folders = TR_PTR_ARRAY_INIT; 2759 const void * const vstrcmp = strcmp; 2760 const char * const top = tor->currentDir; 2761 2762 /* if it's a magnet link, there's nothing to move... */ 2763 if( !tr_torrentHasMetadata( tor ) ) 2764 return; 2765 2766 /*** 2767 **** Move the local data to a new tmpdir 2768 ***/ 2769 2770 base = tr_strdup_printf( "%s__XXXXXX", tr_torrentName( tor ) ); 2771 tmpdir = tr_buildPath( top, base, NULL ); 2772 tr_mkdtemp( tmpdir ); 2773 tr_free( base ); 2774 2775 for( f=0; f<tor->info.fileCount; ++f ) 2776 { 2777 char * filename = tr_buildPath( top, tor->info.files[f].name, NULL ); 2778 if( !tr_fileExists( filename, NULL ) ) { 2779 char * partial = tr_torrentBuildPartial( tor, f ); 2780 tr_free( filename ); 2781 filename = tr_buildPath( top, partial, NULL ); 2782 tr_free( partial ); 2783 if( !tr_fileExists( filename, NULL ) ) { 2784 tr_free( filename ); 2785 filename = NULL; 2786 } 2787 } 2788 2789 if( filename != NULL ) 2790 { 2791 char * target = tr_buildPath( tmpdir, tor->info.files[f].name, NULL ); 2792 char * target_dir = tr_dirname( target ); 2793 tr_mkdirp( target_dir, 0777 ); 2794 rename( filename, target ); 2795 tr_ptrArrayAppend( &files, target ); 2796 tr_free( target_dir ); 2797 tr_free( filename ); 2798 } 2799 } 2800 2801 /*** 2802 **** Remove tmpdir. 2803 **** 2804 **** Try deleting the top-level files & folders to preserve 2805 **** the directory hierarchy in the recycle bin. 2806 **** If case that fails -- for example, rmdir() doesn't 2807 **** delete nonempty folders -- go from the bottom up too. 2808 ***/ 2809 2810 /* try deleting the local data's top-level files & folders */ 2811 if(( odir = opendir( tmpdir ))) 2812 { 2813 struct dirent * d; 2814 while(( d = readdir( odir ))) 2815 { 2816 if( strcmp( d->d_name, "." ) && strcmp( d->d_name, ".." ) ) 2817 { 2818 char * file = tr_buildPath( tmpdir, d->d_name, NULL ); 2819 func( file ); 2820 tr_free( file ); 2821 } 2822 } 2823 closedir( odir ); 2824 } 2825 2826 /* go from the bottom up */ 2827 for( i=0, n=tr_ptrArraySize(&files); i<n; ++i ) 2828 { 2829 char * walk = tr_strdup( tr_ptrArrayNth( &files, i ) ); 2830 while( tr_fileExists( walk, NULL ) && !tr_is_same_file( tmpdir, walk ) ) 2831 { 2832 char * tmp = tr_dirname( walk ); 2833 func( walk ); 2834 tr_free( walk ); 2835 walk = tmp; 2836 } 2837 tr_free( walk ); 2838 } 2839 2840 /*** 2841 **** The local data has been removed. 2842 **** What's left in top are empty folders, junk, and user-generated files. 2843 **** Remove the first two categories and leave the third. 2844 ***/ 2845 2846 /* build a list of 'top's child directories that belong to this torrent */ 2847 for( f=0; f<tor->info.fileCount; ++f ) 2848 { 2849 /* get the directory that this file goes in... */ 2850 char * filename = tr_buildPath( top, tor->info.files[f].name, NULL ); 2851 char * dir = tr_dirname( filename ); 2852 if( !tr_is_same_file( top, dir ) && strcmp( top, dir ) ) { 2853 for( ;; ) { 2854 char * parent = tr_dirname( dir ); 2855 if( tr_is_same_file( top, parent ) || !strcmp( top, parent ) ) { 2856 if( tr_ptrArrayFindSorted( &folders, dir, vstrcmp ) == NULL ) { 2857 tr_ptrArrayInsertSorted( &folders, tr_strdup( dir ), vstrcmp ); 2858 } 2859 break; 2860 } 2861 tr_free( dir ); 2862 dir = parent; 2863 } 2864 } 2865 tr_free( dir ); 2866 tr_free( filename ); 2867 } 2868 for( i=0, n=tr_ptrArraySize(&folders); i<n; ++i ) 2869 removeEmptyFoldersAndJunkFiles( tr_ptrArrayNth( &folders, i ) ); 2870 2871 /* cleanup */ 2872 rmdir( tmpdir ); 2873 tr_free( tmpdir ); 2874 tr_ptrArrayDestruct( &folders, tr_free ); 2875 tr_ptrArrayDestruct( &files, tr_free ); 2876} 2877 2878static void 2879tr_torrentDeleteLocalData( tr_torrent * tor, tr_fileFunc func ) 2880{ 2881 assert( tr_isTorrent( tor ) ); 2882 2883 if( func == NULL ) 2884 func = remove; 2885 2886 /* close all the files because we're about to delete them */ 2887 tr_cacheFlushTorrent( tor->session->cache, tor ); 2888 tr_fdTorrentClose( tor->session, tor->uniqueId ); 2889 2890 deleteLocalData( tor, func ); 2891} 2892 2893/*** 2894**** 2895***/ 2896 2897struct LocationData 2898{ 2899 bool move_from_old_location; 2900 volatile int * setme_state; 2901 volatile double * setme_progress; 2902 char * location; 2903 tr_torrent * tor; 2904}; 2905 2906static void 2907setLocation( void * vdata ) 2908{ 2909 bool err = false; 2910 struct LocationData * data = vdata; 2911 tr_torrent * tor = data->tor; 2912 const bool do_move = data->move_from_old_location; 2913 const char * location = data->location; 2914 double bytesHandled = 0; 2915 2916 assert( tr_isTorrent( tor ) ); 2917 2918 tr_dbg( "Moving \"%s\" location from currentDir \"%s\" to \"%s\"", 2919 tr_torrentName(tor), tor->currentDir, location ); 2920 2921 tr_mkdirp( location, 0777 ); 2922 2923 if( !tr_is_same_file( location, tor->currentDir ) ) 2924 { 2925 tr_file_index_t i; 2926 2927 /* bad idea to move files while they're being verified... */ 2928 tr_verifyRemove( tor ); 2929 2930 /* try to move the files. 2931 * FIXME: there are still all kinds of nasty cases, like what 2932 * if the target directory runs out of space halfway through... */ 2933 for( i=0; !err && i<tor->info.fileCount; ++i ) 2934 { 2935 const tr_file * f = &tor->info.files[i]; 2936 const char * oldbase; 2937 char * sub; 2938 if( tr_torrentFindFile2( tor, i, &oldbase, &sub, NULL ) ) 2939 { 2940 char * oldpath = tr_buildPath( oldbase, sub, NULL ); 2941 char * newpath = tr_buildPath( location, sub, NULL ); 2942 2943 tr_dbg( "Found file #%d: %s", (int)i, oldpath ); 2944 2945 if( do_move && !tr_is_same_file( oldpath, newpath ) ) 2946 { 2947 bool renamed = false; 2948 errno = 0; 2949 tr_torinf( tor, "moving \"%s\" to \"%s\"", oldpath, newpath ); 2950 if( tr_moveFile( oldpath, newpath, &renamed ) ) 2951 { 2952 err = true; 2953 tr_torerr( tor, "error moving \"%s\" to \"%s\": %s", 2954 oldpath, newpath, tr_strerror( errno ) ); 2955 } 2956 } 2957 2958 tr_free( newpath ); 2959 tr_free( oldpath ); 2960 tr_free( sub ); 2961 } 2962 2963 if( data->setme_progress ) 2964 { 2965 bytesHandled += f->length; 2966 *data->setme_progress = bytesHandled / tor->info.totalSize; 2967 } 2968 } 2969 2970 if( !err ) 2971 { 2972 /* blow away the leftover subdirectories in the old location */ 2973 if( do_move ) 2974 tr_torrentDeleteLocalData( tor, remove ); 2975 2976 /* set the new location and reverify */ 2977 tr_torrentSetDownloadDir( tor, location ); 2978 } 2979 } 2980 2981 if( !err && do_move ) 2982 { 2983 tr_free( tor->incompleteDir ); 2984 tor->incompleteDir = NULL; 2985 tor->currentDir = tor->downloadDir; 2986 } 2987 2988 if( data->setme_state ) 2989 *data->setme_state = err ? TR_LOC_ERROR : TR_LOC_DONE; 2990 2991 /* cleanup */ 2992 tr_free( data->location ); 2993 tr_free( data ); 2994} 2995 2996void 2997tr_torrentSetLocation( tr_torrent * tor, 2998 const char * location, 2999 bool move_from_old_location, 3000 volatile double * setme_progress, 3001 volatile int * setme_state ) 3002{ 3003 struct LocationData * data; 3004 3005 assert( tr_isTorrent( tor ) ); 3006 3007 if( setme_state ) 3008 *setme_state = TR_LOC_MOVING; 3009 if( setme_progress ) 3010 *setme_progress = 0; 3011 3012 /* run this in the libtransmission thread */ 3013 data = tr_new( struct LocationData, 1 ); 3014 data->tor = tor; 3015 data->location = tr_strdup( location ); 3016 data->move_from_old_location = move_from_old_location; 3017 data->setme_state = setme_state; 3018 data->setme_progress = setme_progress; 3019 tr_runInEventThread( tor->session, setLocation, data ); 3020} 3021 3022/*** 3023**** 3024***/ 3025 3026void 3027tr_torrentFileCompleted( tr_torrent * tor, tr_file_index_t fileNum ) 3028{ 3029 char * sub; 3030 const char * base; 3031 const tr_info * inf = &tor->info; 3032 const tr_file * f = &inf->files[fileNum]; 3033 tr_piece * p; 3034 const tr_piece * pend; 3035 const time_t now = tr_time( ); 3036 3037 /* close the file so that we can reopen in read-only mode as needed */ 3038 tr_fdFileClose( tor->session, tor, fileNum ); 3039 3040 /* now that the file is complete and closed, we can start watching its 3041 * mtime timestamp for changes to know if we need to reverify pieces */ 3042 for( p=&inf->pieces[f->firstPiece], pend=&inf->pieces[f->lastPiece]; p!=pend; ++p ) 3043 p->timeChecked = now; 3044 3045 /* if the torrent's current filename isn't the same as the one in the 3046 * metadata -- for example, if it had the ".part" suffix appended to 3047 * it until now -- then rename it to match the one in the metadata */ 3048 if( tr_torrentFindFile2( tor, fileNum, &base, &sub, NULL ) ) 3049 { 3050 if( strcmp( sub, f->name ) ) 3051 { 3052 char * oldpath = tr_buildPath( base, sub, NULL ); 3053 char * newpath = tr_buildPath( base, f->name, NULL ); 3054 3055 if( rename( oldpath, newpath ) ) 3056 tr_torerr( tor, "Error moving \"%s\" to \"%s\": %s", oldpath, newpath, tr_strerror( errno ) ); 3057 3058 tr_free( newpath ); 3059 tr_free( oldpath ); 3060 } 3061 3062 tr_free( sub ); 3063 } 3064} 3065 3066/*** 3067**** 3068***/ 3069 3070bool 3071tr_torrentFindFile2( const tr_torrent * tor, tr_file_index_t fileNum, 3072 const char ** base, char ** subpath, time_t * mtime ) 3073{ 3074 char * part = NULL; 3075 const tr_file * file; 3076 const char * b = NULL; 3077 const char * s = NULL; 3078 3079 assert( tr_isTorrent( tor ) ); 3080 assert( fileNum < tor->info.fileCount ); 3081 3082 file = &tor->info.files[fileNum]; 3083 3084 if( b == NULL ) { 3085 char * filename = tr_buildPath( tor->downloadDir, file->name, NULL ); 3086 if( tr_fileExists( filename, mtime ) ) { 3087 b = tor->downloadDir; 3088 s = file->name; 3089 } 3090 tr_free( filename ); 3091 } 3092 3093 if( ( b == NULL ) && ( tor->incompleteDir != NULL ) ) { 3094 char * filename = tr_buildPath( tor->incompleteDir, file->name, NULL ); 3095 if( tr_fileExists( filename, mtime ) ) { 3096 b = tor->incompleteDir; 3097 s = file->name; 3098 } 3099 tr_free( filename ); 3100 } 3101 3102 if( b == NULL ) 3103 part = tr_torrentBuildPartial( tor, fileNum ); 3104 3105 if( ( b == NULL ) && ( tor->incompleteDir != NULL ) ) { 3106 char * filename = tr_buildPath( tor->incompleteDir, part, NULL ); 3107 if( tr_fileExists( filename, mtime ) ) { 3108 b = tor->incompleteDir; 3109 s = part; 3110 } 3111 tr_free( filename ); 3112 } 3113 3114 if( b == NULL) { 3115 char * filename = tr_buildPath( tor->downloadDir, part, NULL ); 3116 if( tr_fileExists( filename, mtime ) ) { 3117 b = tor->downloadDir; 3118 s = part; 3119 } 3120 tr_free( filename ); 3121 } 3122 3123 if( base != NULL ) 3124 *base = b; 3125 if( subpath != NULL ) 3126 *subpath = tr_strdup( s ); 3127 3128 tr_free( part ); 3129 return b != NULL; 3130} 3131 3132char* 3133tr_torrentFindFile( const tr_torrent * tor, tr_file_index_t fileNum ) 3134{ 3135 char * subpath; 3136 char * ret = NULL; 3137 const char * base; 3138 3139 if( tr_torrentFindFile2( tor, fileNum, &base, &subpath, NULL ) ) 3140 { 3141 ret = tr_buildPath( base, subpath, NULL ); 3142 tr_free( subpath ); 3143 } 3144 3145 return ret; 3146} 3147 3148/* Decide whether we should be looking for files in downloadDir or incompleteDir. */ 3149static void 3150refreshCurrentDir( tr_torrent * tor ) 3151{ 3152 const char * dir = NULL; 3153 3154 if( tor->incompleteDir == NULL ) 3155 dir = tor->downloadDir; 3156 else if( !tr_torrentHasMetadata( tor ) ) /* no files to find */ 3157 dir = tor->incompleteDir; 3158 else if( !tr_torrentFindFile2( tor, 0, &dir, NULL, NULL ) ) 3159 dir = tor->incompleteDir; 3160 3161 assert( dir != NULL ); 3162 assert( ( dir == tor->downloadDir ) || ( dir == tor->incompleteDir ) ); 3163 tor->currentDir = dir; 3164} 3165 3166char* 3167tr_torrentBuildPartial( const tr_torrent * tor, tr_file_index_t fileNum ) 3168{ 3169 return tr_strdup_printf( "%s.part", tor->info.files[fileNum].name ); 3170} 3171 3172/*** 3173**** 3174***/ 3175 3176static int 3177compareTorrentByQueuePosition( const void * va, const void * vb ) 3178{ 3179 const tr_torrent * a = * (const tr_torrent **) va; 3180 const tr_torrent * b = * (const tr_torrent **) vb; 3181 3182 return a->queuePosition - b->queuePosition; 3183} 3184 3185#ifndef NDEBUG 3186static bool 3187queueIsSequenced( tr_session * session ) 3188{ 3189 int i ; 3190 int n ; 3191 bool is_sequenced = true; 3192 tr_torrent * tor; 3193 tr_torrent ** tmp = tr_new( tr_torrent *, session->torrentCount ); 3194 3195 /* get all the torrents */ 3196 n = 0; 3197 tor = NULL; 3198 while(( tor = tr_torrentNext( session, tor ))) 3199 tmp[n++] = tor; 3200 3201 /* sort them by position */ 3202 qsort( tmp, n, sizeof( tr_torrent * ), compareTorrentByQueuePosition ); 3203 3204#if 0 3205 fprintf( stderr, "%s", "queue: " ); 3206 for( i=0; i<n; ++i ) 3207 fprintf( stderr, "%d ", tmp[i]->queuePosition ); 3208 fputc( '\n', stderr ); 3209#endif 3210 3211 /* test them */ 3212 for( i=0; is_sequenced && i<n; ++i ) 3213 if( tmp[i]->queuePosition != i ) 3214 is_sequenced = false; 3215 3216 tr_free( tmp ); 3217 return is_sequenced; 3218} 3219#endif 3220 3221int 3222tr_torrentGetQueuePosition( const tr_torrent * tor ) 3223{ 3224 return tor->queuePosition; 3225} 3226 3227void 3228tr_torrentSetQueuePosition( tr_torrent * tor, int pos ) 3229{ 3230 int back = -1; 3231 tr_torrent * walk; 3232 const int old_pos = tor->queuePosition; 3233 const time_t now = tr_time( ); 3234 3235 if( pos < 0 ) 3236 pos = 0; 3237 3238 tor->queuePosition = -1; 3239 3240 walk = NULL; 3241 while(( walk = tr_torrentNext( tor->session, walk ))) 3242 { 3243 if( old_pos < pos ) { 3244 if( ( old_pos <= walk->queuePosition ) && ( walk->queuePosition <= pos ) ) { 3245 walk->queuePosition--; 3246 walk->anyDate = now; 3247 } 3248 } 3249 3250 if( old_pos > pos ) { 3251 if( ( pos <= walk->queuePosition ) && ( walk->queuePosition < old_pos ) ) { 3252 walk->queuePosition++; 3253 walk->anyDate = now; 3254 } 3255 } 3256 3257 if( back < walk->queuePosition ) 3258 back = walk->queuePosition; 3259 } 3260 3261 tor->queuePosition = MIN( pos, (back+1) ); 3262 tor->anyDate = now; 3263 3264 assert( queueIsSequenced( tor->session ) ); 3265} 3266 3267void 3268tr_torrentsQueueMoveTop( tr_torrent ** torrents_in, int n ) 3269{ 3270 int i; 3271 tr_torrent ** torrents = tr_memdup( torrents_in, sizeof( tr_torrent * ) * n ); 3272 qsort( torrents, n, sizeof( tr_torrent * ), compareTorrentByQueuePosition ); 3273 for( i=n-1; i>=0; --i ) 3274 tr_torrentSetQueuePosition( torrents[i], 0 ); 3275 tr_free( torrents ); 3276} 3277 3278void 3279tr_torrentsQueueMoveUp( tr_torrent ** torrents_in, int n ) 3280{ 3281 int i; 3282 tr_torrent ** torrents = tr_memdup( torrents_in, sizeof( tr_torrent * ) * n ); 3283 qsort( torrents, n, sizeof( tr_torrent * ), compareTorrentByQueuePosition ); 3284 for( i=0; i<n; ++i ) 3285 tr_torrentSetQueuePosition( torrents[i], torrents[i]->queuePosition - 1 ); 3286 tr_free( torrents ); 3287} 3288 3289void 3290tr_torrentsQueueMoveDown( tr_torrent ** torrents_in, int n ) 3291{ 3292 int i; 3293 tr_torrent ** torrents = tr_memdup( torrents_in, sizeof( tr_torrent * ) * n ); 3294 qsort( torrents, n, sizeof( tr_torrent * ), compareTorrentByQueuePosition ); 3295 for( i=n-1; i>=0; --i ) 3296 tr_torrentSetQueuePosition( torrents[i], torrents[i]->queuePosition + 1 ); 3297 tr_free( torrents ); 3298} 3299 3300void 3301tr_torrentsQueueMoveBottom( tr_torrent ** torrents_in, int n ) 3302{ 3303 int i; 3304 tr_torrent ** torrents = tr_memdup( torrents_in, sizeof( tr_torrent * ) * n ); 3305 qsort( torrents, n, sizeof( tr_torrent * ), compareTorrentByQueuePosition ); 3306 for( i=0; i<n; ++i ) 3307 tr_torrentSetQueuePosition( torrents[i], INT_MAX ); 3308 tr_free( torrents ); 3309} 3310 3311static void 3312torrentSetQueued( tr_torrent * tor, bool queued ) 3313{ 3314 assert( tr_isTorrent( tor ) ); 3315 assert( tr_isBool( queued ) ); 3316 3317 if( tr_torrentIsQueued( tor ) != queued ) 3318 { 3319 tor->isQueued = queued; 3320 tor->anyDate = tr_time( ); 3321 } 3322} 3323 3324void 3325tr_torrentSetQueueStartCallback( tr_torrent * torrent, void (*callback)( tr_torrent *, void * ), void * user_data ) 3326{ 3327 torrent->queue_started_callback = callback; 3328 torrent->queue_started_user_data = user_data; 3329} 3330 3331 3332