2 * This file Copyright (C) Mnemosyne LLC
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.
10 * $Id: torrent.c 12540 2011-07-10 17:34:03Z jordan $
13 #include <signal.h> /* signal() */
14 #include <sys/types.h> /* stat */
15 #include <sys/stat.h> /* stat */
17 #include <sys/wait.h> /* wait() */
20 #define waitpid(pid, status, options) _cwait(status, pid, WAIT_CHILD)
22 #include <unistd.h> /* stat */
28 #include <string.h> /* memcmp */
29 #include <stdlib.h> /* qsort */
30 #include <stdio.h> /* remove() */
32 #include <event2/util.h> /* evutil_vsnprintf() */
34 #include "transmission.h"
35 #include "announcer.h"
36 #include "bandwidth.h"
39 #include "completion.h"
40 #include "crypto.h" /* for tr_sha1 */
42 #include "fdlimit.h" /* tr_fdTorrentClose */
43 #include "inout.h" /* tr_ioTestPiece() */
46 #include "peer-common.h" /* MAX_BLOCK_SIZE */
48 #include "platform.h" /* TR_PATH_DELIMITER_STR */
52 #include "torrent-magnet.h"
53 #include "trevent.h" /* tr_runInEventThread() */
62 #define tr_deeplog_tor( tor, ... ) \
64 if( tr_deepLoggingIsActive( ) ) \
65 tr_deepLog( __FILE__, __LINE__, tr_torrentName( tor ), __VA_ARGS__ ); \
73 tr_torrentName( const tr_torrent
* tor
)
75 assert( tr_isTorrent( tor
) );
77 return tor
->info
.name
;
81 tr_torrentId( const tr_torrent
* tor
)
87 tr_torrentFindFromId( tr_session
* session
, int id
)
89 tr_torrent
* tor
= NULL
;
91 while(( tor
= tr_torrentNext( session
, tor
)))
92 if( tor
->uniqueId
== id
)
99 tr_torrentFindFromHashString( tr_session
* session
, const char * str
)
101 tr_torrent
* tor
= NULL
;
103 while(( tor
= tr_torrentNext( session
, tor
)))
104 if( !evutil_ascii_strcasecmp( str
, tor
->info
.hashString
) )
111 tr_torrentFindFromHash( tr_session
* session
, const uint8_t * torrentHash
)
113 tr_torrent
* tor
= NULL
;
115 while(( tor
= tr_torrentNext( session
, tor
)))
116 if( *tor
->info
.hash
== *torrentHash
)
117 if( !memcmp( tor
->info
.hash
, torrentHash
, SHA_DIGEST_LENGTH
) )
124 tr_torrentFindFromMagnetLink( tr_session
* session
, const char * magnet
)
126 tr_magnet_info
* info
;
127 tr_torrent
* tor
= NULL
;
129 if(( info
= tr_magnetParse( magnet
)))
131 tor
= tr_torrentFindFromHash( session
, info
->hash
);
132 tr_magnetFree( info
);
139 tr_torrentFindFromObfuscatedHash( tr_session
* session
,
140 const uint8_t * obfuscatedTorrentHash
)
142 tr_torrent
* tor
= NULL
;
144 while(( tor
= tr_torrentNext( session
, tor
)))
145 if( !memcmp( tor
->obfuscatedHash
, obfuscatedTorrentHash
,
146 SHA_DIGEST_LENGTH
) )
153 tr_torrentIsPieceTransferAllowed( const tr_torrent
* tor
,
154 tr_direction direction
)
159 if( tr_torrentUsesSpeedLimit( tor
, direction
) )
160 if( tr_torrentGetSpeedLimit_Bps( tor
, direction
) <= 0 )
163 if( tr_torrentUsesSessionLimits( tor
) )
164 if( tr_sessionGetActiveSpeedLimit_Bps( tor
->session
, direction
, &limit
) )
172 **** PER-TORRENT UL / DL SPEEDS
176 tr_torrentSetSpeedLimit_Bps( tr_torrent
* tor
, tr_direction dir
, int Bps
)
178 assert( tr_isTorrent( tor
) );
179 assert( tr_isDirection( dir
) );
182 if( tr_bandwidthSetDesiredSpeed_Bps( &tor
->bandwidth
, dir
, Bps
) )
183 tr_torrentSetDirty( tor
);
186 tr_torrentSetSpeedLimit_KBps( tr_torrent
* tor
, tr_direction dir
, int KBps
)
188 tr_torrentSetSpeedLimit_Bps( tor
, dir
, toSpeedBytes( KBps
) );
192 tr_torrentGetSpeedLimit_Bps( const tr_torrent
* tor
, tr_direction dir
)
194 assert( tr_isTorrent( tor
) );
195 assert( tr_isDirection( dir
) );
197 return tr_bandwidthGetDesiredSpeed_Bps( &tor
->bandwidth
, dir
);
200 tr_torrentGetSpeedLimit_KBps( const tr_torrent
* tor
, tr_direction dir
)
202 return toSpeedKBps( tr_torrentGetSpeedLimit_Bps( tor
, dir
) );
206 tr_torrentUseSpeedLimit( tr_torrent
* tor
, tr_direction dir
, bool do_use
)
208 assert( tr_isTorrent( tor
) );
209 assert( tr_isDirection( dir
) );
211 if( tr_bandwidthSetLimited( &tor
->bandwidth
, dir
, do_use
) )
212 tr_torrentSetDirty( tor
);
216 tr_torrentUsesSpeedLimit( const tr_torrent
* tor
, tr_direction dir
)
218 assert( tr_isTorrent( tor
) );
219 assert( tr_isDirection( dir
) );
221 return tr_bandwidthIsLimited( &tor
->bandwidth
, dir
);
225 tr_torrentUseSessionLimits( tr_torrent
* tor
, bool doUse
)
229 assert( tr_isTorrent( tor
) );
231 changed
= tr_bandwidthHonorParentLimits( &tor
->bandwidth
, TR_UP
, doUse
);
232 changed
|= tr_bandwidthHonorParentLimits( &tor
->bandwidth
, TR_DOWN
, doUse
);
235 tr_torrentSetDirty( tor
);
239 tr_torrentUsesSessionLimits( const tr_torrent
* tor
)
241 assert( tr_isTorrent( tor
) );
243 return tr_bandwidthAreParentLimitsHonored( &tor
->bandwidth
, TR_UP
);
251 tr_torrentSetRatioMode( tr_torrent
* tor
, tr_ratiolimit mode
)
253 assert( tr_isTorrent( tor
) );
254 assert( mode
==TR_RATIOLIMIT_GLOBAL
|| mode
==TR_RATIOLIMIT_SINGLE
|| mode
==TR_RATIOLIMIT_UNLIMITED
);
256 if( mode
!= tor
->ratioLimitMode
)
258 tor
->ratioLimitMode
= mode
;
260 tr_torrentSetDirty( tor
);
265 tr_torrentGetRatioMode( const tr_torrent
* tor
)
267 assert( tr_isTorrent( tor
) );
269 return tor
->ratioLimitMode
;
273 tr_torrentSetRatioLimit( tr_torrent
* tor
, double desiredRatio
)
275 assert( tr_isTorrent( tor
) );
277 if( (int)(desiredRatio
*100.0) != (int)(tor
->desiredRatio
*100.0) )
279 tor
->desiredRatio
= desiredRatio
;
281 tr_torrentSetDirty( tor
);
286 tr_torrentGetRatioLimit( const tr_torrent
* tor
)
288 assert( tr_isTorrent( tor
) );
290 return tor
->desiredRatio
;
294 tr_torrentGetSeedRatio( const tr_torrent
* tor
, double * ratio
)
298 switch( tr_torrentGetRatioMode( tor
) )
300 case TR_RATIOLIMIT_SINGLE
:
303 *ratio
= tr_torrentGetRatioLimit( tor
);
306 case TR_RATIOLIMIT_GLOBAL
:
307 isLimited
= tr_sessionIsRatioLimited( tor
->session
);
308 if( isLimited
&& ratio
)
309 *ratio
= tr_sessionGetRatioLimit( tor
->session
);
312 default: /* TR_RATIOLIMIT_UNLIMITED */
320 /* returns true if the seed ratio applies --
321 * it applies if the torrent's a seed AND it has a seed ratio set */
323 tr_torrentGetSeedRatioBytes( tr_torrent
* tor
,
324 uint64_t * setmeLeft
,
325 uint64_t * setmeGoal
)
328 bool seedRatioApplies
= false;
330 if( tr_torrentGetSeedRatio( tor
, &seedRatio
) )
332 const uint64_t u
= tor
->uploadedCur
+ tor
->uploadedPrev
;
333 const uint64_t d
= tor
->downloadedCur
+ tor
->downloadedPrev
;
334 const uint64_t baseline
= d
? d
: tr_cpSizeWhenDone( &tor
->completion
);
335 const uint64_t goal
= baseline
* seedRatio
;
336 if( setmeLeft
) *setmeLeft
= goal
> u
? goal
- u
: 0;
337 if( setmeGoal
) *setmeGoal
= goal
;
338 seedRatioApplies
= tr_torrentIsSeed( tor
);
341 return seedRatioApplies
;
345 tr_torrentIsSeedRatioDone( tr_torrent
* tor
)
348 return tr_torrentGetSeedRatioBytes( tor
, &bytesLeft
, NULL
) && !bytesLeft
;
356 tr_torrentSetIdleMode( tr_torrent
* tor
, tr_idlelimit mode
)
358 assert( tr_isTorrent( tor
) );
359 assert( mode
==TR_IDLELIMIT_GLOBAL
|| mode
==TR_IDLELIMIT_SINGLE
|| mode
==TR_IDLELIMIT_UNLIMITED
);
361 if( mode
!= tor
->idleLimitMode
)
363 tor
->idleLimitMode
= mode
;
365 tr_torrentSetDirty( tor
);
370 tr_torrentGetIdleMode( const tr_torrent
* tor
)
372 assert( tr_isTorrent( tor
) );
374 return tor
->idleLimitMode
;
378 tr_torrentSetIdleLimit( tr_torrent
* tor
, uint16_t idleMinutes
)
380 assert( tr_isTorrent( tor
) );
382 if( idleMinutes
> 0 )
384 tor
->idleLimitMinutes
= idleMinutes
;
386 tr_torrentSetDirty( tor
);
391 tr_torrentGetIdleLimit( const tr_torrent
* tor
)
393 assert( tr_isTorrent( tor
) );
395 return tor
->idleLimitMinutes
;
399 tr_torrentGetSeedIdle( const tr_torrent
* tor
, uint16_t * idleMinutes
)
403 switch( tr_torrentGetIdleMode( tor
) )
405 case TR_IDLELIMIT_SINGLE
:
408 *idleMinutes
= tr_torrentGetIdleLimit( tor
);
411 case TR_IDLELIMIT_GLOBAL
:
412 isLimited
= tr_sessionIsIdleLimited( tor
->session
);
413 if( isLimited
&& idleMinutes
)
414 *idleMinutes
= tr_sessionGetIdleLimit( tor
->session
);
417 default: /* TR_IDLELIMIT_UNLIMITED */
426 tr_torrentIsSeedIdleLimitDone( tr_torrent
* tor
)
428 uint16_t idleMinutes
;
429 return tr_torrentGetSeedIdle( tor
, &idleMinutes
)
430 && difftime(tr_time(), MAX(tor
->startDate
, tor
->activityDate
)) >= idleMinutes
* 60u;
438 tr_torrentCheckSeedLimit( tr_torrent
* tor
)
440 assert( tr_isTorrent( tor
) );
442 if( !tor
->isRunning
|| !tr_torrentIsSeed( tor
) )
445 /* if we're seeding and reach our seed ratio limit, stop the torrent */
446 if( tr_torrentIsSeedRatioDone( tor
) )
448 tr_torinf( tor
, "Seed ratio reached; pausing torrent" );
450 tor
->isStopping
= true;
452 /* maybe notify the client */
453 if( tor
->ratio_limit_hit_func
!= NULL
)
454 tor
->ratio_limit_hit_func( tor
, tor
->ratio_limit_hit_func_user_data
);
456 /* if we're seeding and reach our inactiviy limit, stop the torrent */
457 else if( tr_torrentIsSeedIdleLimitDone( tor
) )
459 tr_torinf( tor
, "Seeding idle limit reached; pausing torrent" );
461 tor
->isStopping
= true;
462 tor
->finishedSeedingByIdle
= true;
464 /* maybe notify the client */
465 if( tor
->idle_limit_hit_func
!= NULL
)
466 tor
->idle_limit_hit_func( tor
, tor
->idle_limit_hit_func_user_data
);
475 tr_torrentSetLocalError( tr_torrent
* tor
, const char * fmt
, ... )
479 assert( tr_isTorrent( tor
) );
482 tor
->error
= TR_STAT_LOCAL_ERROR
;
483 tor
->errorTracker
[0] = '\0';
484 evutil_vsnprintf( tor
->errorString
, sizeof( tor
->errorString
), fmt
, ap
);
487 tr_torerr( tor
, "%s", tor
->errorString
);
490 tor
->isStopping
= true;
494 tr_torrentClearError( tr_torrent
* tor
)
496 tor
->error
= TR_STAT_OK
;
497 tor
->errorString
[0] = '\0';
498 tor
->errorTracker
[0] = '\0';
502 onTrackerResponse( tr_torrent
* tor
, const tr_tracker_event
* event
, void * unused UNUSED
)
504 switch( event
->messageType
)
506 case TR_TRACKER_PEERS
:
509 const int8_t seedProbability
= event
->seedProbability
;
510 const bool allAreSeeds
= seedProbability
== 100;
513 tr_tordbg( tor
, "Got %zu seeds from tracker", event
->pexCount
);
515 tr_tordbg( tor
, "Got %zu peers from tracker", event
->pexCount
);
517 for( i
= 0; i
< event
->pexCount
; ++i
)
518 tr_peerMgrAddPex( tor
, TR_PEER_FROM_TRACKER
, &event
->pex
[i
], seedProbability
);
520 if( allAreSeeds
&& tr_torrentIsPrivate( tor
) )
521 tr_peerMgrMarkAllAsSeeds( tor
);
526 case TR_TRACKER_WARNING
:
527 tr_torerr( tor
, _( "Tracker warning: \"%s\"" ), event
->text
);
528 tor
->error
= TR_STAT_TRACKER_WARNING
;
529 tr_strlcpy( tor
->errorTracker
, event
->tracker
, sizeof( tor
->errorTracker
) );
530 tr_strlcpy( tor
->errorString
, event
->text
, sizeof( tor
->errorString
) );
533 case TR_TRACKER_ERROR
:
534 tr_torerr( tor
, _( "Tracker error: \"%s\"" ), event
->text
);
535 tor
->error
= TR_STAT_TRACKER_ERROR
;
536 tr_strlcpy( tor
->errorTracker
, event
->tracker
, sizeof( tor
->errorTracker
) );
537 tr_strlcpy( tor
->errorString
, event
->text
, sizeof( tor
->errorString
) );
540 case TR_TRACKER_ERROR_CLEAR
:
541 if( tor
->error
!= TR_STAT_LOCAL_ERROR
)
542 tr_torrentClearError( tor
);
549 **** TORRENT INSTANTIATION
553 static tr_piece_index_t
554 getBytePiece( const tr_info
* info
, uint64_t byteOffset
)
557 assert( info
->pieceSize
!= 0 );
559 return byteOffset
/ info
->pieceSize
;
563 initFilePieces( tr_info
* info
,
564 tr_file_index_t fileIndex
)
567 uint64_t firstByte
, lastByte
;
570 assert( fileIndex
< info
->fileCount
);
572 file
= &info
->files
[fileIndex
];
573 firstByte
= file
->offset
;
574 lastByte
= firstByte
+ ( file
->length
? file
->length
- 1 : 0 );
575 file
->firstPiece
= getBytePiece( info
, firstByte
);
576 file
->lastPiece
= getBytePiece( info
, lastByte
);
580 pieceHasFile( tr_piece_index_t piece
,
581 const tr_file
* file
)
583 return ( file
->firstPiece
<= piece
) && ( piece
<= file
->lastPiece
);
587 calculatePiecePriority( const tr_torrent
* tor
,
588 tr_piece_index_t piece
,
592 tr_priority_t priority
= TR_PRI_LOW
;
594 /* find the first file that has data in this piece */
595 if( fileHint
>= 0 ) {
597 while( i
> 0 && pieceHasFile( piece
, &tor
->info
.files
[i
- 1] ) )
600 for( i
= 0; i
< tor
->info
.fileCount
; ++i
)
601 if( pieceHasFile( piece
, &tor
->info
.files
[i
] ) )
605 /* the piece's priority is the max of the priorities
606 * of all the files in that piece */
607 for( ; i
< tor
->info
.fileCount
; ++i
)
609 const tr_file
* file
= &tor
->info
.files
[i
];
611 if( !pieceHasFile( piece
, file
) )
614 priority
= MAX( priority
, file
->priority
);
616 /* when dealing with multimedia files, getting the first and
617 last pieces can sometimes allow you to preview it a bit
618 before it's fully downloaded... */
619 if( file
->priority
>= TR_PRI_NORMAL
)
620 if( file
->firstPiece
== piece
|| file
->lastPiece
== piece
)
621 priority
= TR_PRI_HIGH
;
628 tr_torrentInitFilePieces( tr_torrent
* tor
)
634 tr_info
* inf
= &tor
->info
;
636 /* assign the file offsets */
637 for( f
=0; f
<inf
->fileCount
; ++f
) {
638 inf
->files
[f
].offset
= offset
;
639 offset
+= inf
->files
[f
].length
;
640 initFilePieces( inf
, f
);
643 /* build the array of first-file hints to give calculatePiecePriority */
644 firstFiles
= tr_new( int, inf
->pieceCount
);
645 for( p
=f
=0; p
<inf
->pieceCount
; ++p
) {
646 while( inf
->files
[f
].lastPiece
< p
)
652 /* test to confirm the first-file hints are correct */
653 for( p
=0; p
<inf
->pieceCount
; ++p
) {
655 assert( inf
->files
[f
].firstPiece
<= p
);
656 assert( inf
->files
[f
].lastPiece
>= p
);
658 assert( inf
->files
[f
-1].lastPiece
< p
);
659 for( f
=0; f
<inf
->fileCount
; ++f
)
660 if( pieceHasFile( p
, &inf
->files
[f
] ) )
662 assert( (int)f
== firstFiles
[p
] );
666 for( p
=0; p
<inf
->pieceCount
; ++p
)
667 inf
->pieces
[p
].priority
= calculatePiecePriority( tor
, p
, firstFiles
[p
] );
669 tr_free( firstFiles
);
672 static void torrentStart( tr_torrent
* tor
);
675 * Decide on a block size. Constraints:
676 * (1) most clients decline requests over 16 KiB
677 * (2) pieceSize must be a multiple of block size
680 tr_getBlockSize( uint32_t pieceSize
)
682 uint32_t b
= pieceSize
;
684 while( b
> MAX_BLOCK_SIZE
)
687 if( !b
|| ( pieceSize
% b
) ) /* not cleanly divisible */
692 static void refreshCurrentDir( tr_torrent
* tor
);
695 torrentInitFromInfo( tr_torrent
* tor
)
698 tr_info
* info
= &tor
->info
;
700 tor
->blockSize
= tr_getBlockSize( info
->pieceSize
);
702 if( info
->pieceSize
)
703 tor
->lastPieceSize
= (uint32_t)(info
->totalSize
% info
->pieceSize
);
705 if( !tor
->lastPieceSize
)
706 tor
->lastPieceSize
= info
->pieceSize
;
709 tor
->lastBlockSize
= info
->totalSize
% tor
->blockSize
;
711 if( !tor
->lastBlockSize
)
712 tor
->lastBlockSize
= tor
->blockSize
;
714 tor
->blockCount
= tor
->blockSize
715 ? ( info
->totalSize
+ tor
->blockSize
- 1 ) / tor
->blockSize
718 tor
->blockCountInPiece
= tor
->blockSize
719 ? info
->pieceSize
/ tor
->blockSize
722 tor
->blockCountInLastPiece
= tor
->blockSize
723 ? ( tor
->lastPieceSize
+ tor
->blockSize
- 1 ) / tor
->blockSize
727 if( tor
->blockSize
!= 0 )
728 assert( ( info
->pieceSize
% tor
->blockSize
) == 0 );
729 t
= info
->pieceCount
- 1;
730 t
*= info
->pieceSize
;
731 t
+= tor
->lastPieceSize
;
732 assert( t
== info
->totalSize
);
733 t
= tor
->blockCount
- 1;
735 t
+= tor
->lastBlockSize
;
736 assert( t
== info
->totalSize
);
737 t
= info
->pieceCount
- 1;
738 t
*= tor
->blockCountInPiece
;
739 t
+= tor
->blockCountInLastPiece
;
740 assert( t
== (uint64_t)tor
->blockCount
);
742 tr_cpConstruct( &tor
->completion
, tor
);
744 tr_torrentInitFilePieces( tor
);
746 tor
->completeness
= tr_cpGetStatus( &tor
->completion
);
749 static void tr_torrentFireMetadataCompleted( tr_torrent
* tor
);
752 tr_torrentGotNewInfoDict( tr_torrent
* tor
)
754 torrentInitFromInfo( tor
);
756 tr_peerMgrOnTorrentGotMetainfo( tor
);
758 tr_torrentFireMetadataCompleted( tor
);
762 hasAnyLocalData( const tr_torrent
* tor
)
766 for( i
=0; i
<tor
->info
.fileCount
; ++i
)
767 if( tr_torrentFindFile2( tor
, i
, NULL
, NULL
, NULL
) )
774 setLocalErrorIfFilesDisappeared( tr_torrent
* tor
)
776 const bool disappeared
= ( tr_cpHaveTotal( &tor
->completion
) > 0 ) && !hasAnyLocalData( tor
);
780 tr_deeplog_tor( tor
, "%s", "[LAZY] uh oh, the files disappeared" );
781 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." ) );
788 torrentInit( tr_torrent
* tor
, const tr_ctor
* ctor
)
795 static int nextUniqueId
= 1;
796 tr_session
* session
= tr_ctorGetSession( ctor
);
798 assert( session
!= NULL
);
800 tr_sessionLock( session
);
802 tor
->session
= session
;
803 tor
->uniqueId
= nextUniqueId
++;
804 tor
->magicNumber
= TORRENT_MAGIC_NUMBER
;
806 tr_peerIdInit( tor
->peer_id
);
808 tr_sha1( tor
->obfuscatedHash
, "req2", 4,
809 tor
->info
.hash
, SHA_DIGEST_LENGTH
,
812 if( !tr_ctorGetDownloadDir( ctor
, TR_FORCE
, &dir
) ||
813 !tr_ctorGetDownloadDir( ctor
, TR_FALLBACK
, &dir
) )
814 tor
->downloadDir
= tr_strdup( dir
);
816 if( tr_ctorGetIncompleteDir( ctor
, &dir
) )
817 dir
= tr_sessionGetIncompleteDir( session
);
818 if( tr_sessionIsIncompleteDirEnabled( session
) )
819 tor
->incompleteDir
= tr_strdup( dir
);
821 tr_bandwidthConstruct( &tor
->bandwidth
, session
, &session
->bandwidth
);
823 tor
->bandwidth
.priority
= tr_ctorGetBandwidthPriority( ctor
);
825 tor
->error
= TR_STAT_OK
;
827 tor
->finishedSeedingByIdle
= false;
829 tr_peerMgrAddTorrent( session
->peerMgr
, tor
);
831 assert( !tor
->downloadedCur
);
832 assert( !tor
->uploadedCur
);
834 tr_torrentSetAddedDate( tor
, tr_time( ) ); /* this is a default value to be
835 overwritten by the resume file */
837 torrentInitFromInfo( tor
);
838 loaded
= tr_torrentLoadResume( tor
, ~0, ctor
);
839 tor
->completeness
= tr_cpGetStatus( &tor
->completion
);
840 setLocalErrorIfFilesDisappeared( tor
);
842 tr_ctorInitTorrentPriorities( ctor
, tor
);
843 tr_ctorInitTorrentWanted( ctor
, tor
);
845 refreshCurrentDir( tor
);
847 doStart
= tor
->isRunning
;
850 if( !( loaded
& TR_FR_SPEEDLIMIT
) )
852 tr_torrentUseSpeedLimit( tor
, TR_UP
, false );
853 tr_torrentSetSpeedLimit_Bps( tor
, TR_UP
, tr_sessionGetSpeedLimit_Bps( tor
->session
, TR_UP
) );
854 tr_torrentUseSpeedLimit( tor
, TR_DOWN
, false );
855 tr_torrentSetSpeedLimit_Bps( tor
, TR_DOWN
, tr_sessionGetSpeedLimit_Bps( tor
->session
, TR_DOWN
) );
856 tr_torrentUseSessionLimits( tor
, true );
859 if( !( loaded
& TR_FR_RATIOLIMIT
) )
861 tr_torrentSetRatioMode( tor
, TR_RATIOLIMIT_GLOBAL
);
862 tr_torrentSetRatioLimit( tor
, tr_sessionGetRatioLimit( tor
->session
) );
865 if( !( loaded
& TR_FR_IDLELIMIT
) )
867 tr_torrentSetIdleMode( tor
, TR_IDLELIMIT_GLOBAL
);
868 tr_torrentSetIdleLimit( tor
, tr_sessionGetIdleLimit( tor
->session
) );
871 /* add the torrent to tr_session.torrentList */
872 ++session
->torrentCount
;
873 if( session
->torrentList
== NULL
)
874 session
->torrentList
= tor
;
876 tr_torrent
* it
= session
->torrentList
;
877 while( it
->next
!= NULL
)
882 /* if we don't have a local .torrent file already, assume the torrent is new */
883 isNewTorrent
= stat( tor
->info
.torrent
, &st
);
885 /* maybe save our own copy of the metainfo */
886 if( tr_ctorGetSave( ctor
) )
889 if( !tr_ctorGetMetainfo( ctor
, &val
) )
891 const char * path
= tor
->info
.torrent
;
892 const int err
= tr_bencToFile( val
, TR_FMT_BENC
, path
);
894 tr_torrentSetLocalError( tor
, "Unable to save torrent file: %s", tr_strerror( err
) );
895 tr_sessionSetTorrentFile( tor
->session
, tor
->info
.hashString
, path
);
899 tor
->tiers
= tr_announcerAddTorrent( tor
, onTrackerResponse
, NULL
);
903 tor
->startAfterVerify
= doStart
;
904 tr_torrentVerify( tor
);
911 tr_sessionUnlock( session
);
914 static tr_parse_result
915 torrentParseImpl( const tr_ctor
* ctor
, tr_info
* setmeInfo
,
916 bool * setmeHasInfo
, int * dictLength
)
920 bool hasInfo
= false;
922 const tr_benc
* metainfo
;
923 tr_session
* session
= tr_ctorGetSession( ctor
);
924 tr_parse_result result
= TR_PARSE_OK
;
926 if( setmeInfo
== NULL
)
928 memset( setmeInfo
, 0, sizeof( tr_info
) );
930 if( tr_ctorGetMetainfo( ctor
, &metainfo
) )
933 didParse
= tr_metainfoParse( session
, metainfo
, setmeInfo
,
934 &hasInfo
, dictLength
);
935 doFree
= didParse
&& ( setmeInfo
== &tmp
);
938 result
= TR_PARSE_ERR
;
940 if( didParse
&& hasInfo
&& !tr_getBlockSize( setmeInfo
->pieceSize
) )
941 result
= TR_PARSE_ERR
;
943 if( didParse
&& session
&& tr_torrentExists( session
, setmeInfo
->hash
) )
944 result
= TR_PARSE_DUPLICATE
;
947 tr_metainfoFree( setmeInfo
);
949 if( setmeHasInfo
!= NULL
)
950 *setmeHasInfo
= hasInfo
;
956 tr_torrentParse( const tr_ctor
* ctor
, tr_info
* setmeInfo
)
958 return torrentParseImpl( ctor
, setmeInfo
, NULL
, NULL
);
962 tr_torrentNew( const tr_ctor
* ctor
, int * setmeError
)
968 tr_torrent
* tor
= NULL
;
970 assert( ctor
!= NULL
);
971 assert( tr_isSession( tr_ctorGetSession( ctor
) ) );
973 r
= torrentParseImpl( ctor
, &tmpInfo
, &hasInfo
, &len
);
974 if( r
== TR_PARSE_OK
)
976 tor
= tr_new0( tr_torrent
, 1 );
979 tor
->infoDictLength
= len
;
980 torrentInit( tor
, ctor
);
984 if( r
== TR_PARSE_DUPLICATE
)
985 tr_metainfoFree( &tmpInfo
);
999 tr_torrentSetDownloadDir( tr_torrent
* tor
, const char * path
)
1001 assert( tr_isTorrent( tor
) );
1003 if( !path
|| !tor
->downloadDir
|| strcmp( path
, tor
->downloadDir
) )
1005 tr_free( tor
->downloadDir
);
1006 tor
->downloadDir
= tr_strdup( path
);
1007 tr_torrentSetDirty( tor
);
1010 refreshCurrentDir( tor
);
1014 tr_torrentGetDownloadDir( const tr_torrent
* tor
)
1016 assert( tr_isTorrent( tor
) );
1018 return tor
->downloadDir
;
1022 tr_torrentGetCurrentDir( const tr_torrent
* tor
)
1024 assert( tr_isTorrent( tor
) );
1026 return tor
->currentDir
;
1031 tr_torrentChangeMyPort( tr_torrent
* tor
)
1033 assert( tr_isTorrent( tor
) );
1035 if( tor
->isRunning
)
1036 tr_announcerChangeMyPort( tor
);
1040 tr_torrentManualUpdateImpl( void * vtor
)
1042 tr_torrent
* tor
= vtor
;
1044 assert( tr_isTorrent( tor
) );
1046 if( tor
->isRunning
)
1047 tr_announcerManualAnnounce( tor
);
1051 tr_torrentManualUpdate( tr_torrent
* tor
)
1053 assert( tr_isTorrent( tor
) );
1055 tr_runInEventThread( tor
->session
, tr_torrentManualUpdateImpl
, tor
);
1059 tr_torrentCanManualUpdate( const tr_torrent
* tor
)
1061 return ( tr_isTorrent( tor
) )
1062 && ( tor
->isRunning
)
1063 && ( tr_announcerCanManualAnnounce( tor
) );
1067 tr_torrentInfo( const tr_torrent
* tor
)
1069 return tr_isTorrent( tor
) ? &tor
->info
: NULL
;
1073 tr_torrentStatCached( tr_torrent
* tor
)
1075 const time_t now
= tr_time( );
1077 return tr_isTorrent( tor
) && ( now
== tor
->lastStatTime
)
1079 : tr_torrentStat( tor
);
1083 tr_torrentSetVerifyState( tr_torrent
* tor
, tr_verify_state state
)
1085 assert( tr_isTorrent( tor
) );
1086 assert( state
==TR_VERIFY_NONE
|| state
==TR_VERIFY_WAIT
|| state
==TR_VERIFY_NOW
);
1088 tor
->verifyState
= state
;
1089 tor
->anyDate
= tr_time( );
1093 tr_torrentGetActivity( tr_torrent
* tor
)
1095 assert( tr_isTorrent( tor
) );
1097 tr_torrentRecheckCompleteness( tor
);
1099 if( tor
->verifyState
== TR_VERIFY_NOW
)
1100 return TR_STATUS_CHECK
;
1101 if( tor
->verifyState
== TR_VERIFY_WAIT
)
1102 return TR_STATUS_CHECK_WAIT
;
1103 if( !tor
->isRunning
)
1104 return TR_STATUS_STOPPED
;
1105 if( tor
->completeness
== TR_LEECH
)
1106 return TR_STATUS_DOWNLOAD
;
1108 return TR_STATUS_SEED
;
1112 getVerifyProgress( const tr_torrent
* tor
)
1114 tr_piece_index_t i
, n
;
1115 tr_piece_index_t checked
= 0;
1117 assert( tr_isTorrent( tor
) );
1119 for( i
=0, n
=tor
->info
.pieceCount
; i
!=n
; ++i
)
1120 if( tor
->info
.pieces
[i
].timeChecked
)
1123 return checked
/ (double)tor
->info
.pieceCount
;
1127 tr_torrentStat( tr_torrent
* tor
)
1131 uint64_t seedRatioBytesLeft
;
1132 uint64_t seedRatioBytesGoal
;
1133 bool seedRatioApplies
;
1134 uint16_t seedIdleMinutes
;
1139 assert( tr_isTorrent( tor
) );
1140 tr_torrentLock( tor
);
1142 tor
->lastStatTime
= tr_time( );
1145 s
->id
= tor
->uniqueId
;
1146 s
->activity
= tr_torrentGetActivity( tor
);
1147 s
->error
= tor
->error
;
1148 tr_strlcpy( s
->errorString
, tor
->errorString
, sizeof( s
->errorString
) );
1150 s
->manualAnnounceTime
= tr_announcerNextManualAnnounce( tor
);
1152 tr_peerMgrTorrentStats( tor
,
1154 &s
->webseedsSendingToUs
,
1155 &s
->peersSendingToUs
,
1156 &s
->peersGettingFromUs
,
1159 now
= tr_time_msec( );
1160 s
->rawUploadSpeed_KBps
= toSpeedKBps( tr_bandwidthGetRawSpeed_Bps ( &tor
->bandwidth
, now
, TR_UP
) );
1161 s
->pieceUploadSpeed_KBps
= toSpeedKBps( tr_bandwidthGetPieceSpeed_Bps( &tor
->bandwidth
, now
, TR_UP
) );
1162 s
->rawDownloadSpeed_KBps
= toSpeedKBps( tr_bandwidthGetRawSpeed_Bps ( &tor
->bandwidth
, now
, TR_DOWN
) );
1163 s
->pieceDownloadSpeed_KBps
= toSpeedKBps( tr_bandwidthGetPieceSpeed_Bps( &tor
->bandwidth
, now
, TR_DOWN
) );
1165 s
->percentComplete
= tr_cpPercentComplete ( &tor
->completion
);
1166 s
->metadataPercentComplete
= tr_torrentGetMetadataPercent( tor
);
1168 s
->percentDone
= tr_cpPercentDone ( &tor
->completion
);
1169 s
->leftUntilDone
= tr_cpLeftUntilDone( &tor
->completion
);
1170 s
->sizeWhenDone
= tr_cpSizeWhenDone ( &tor
->completion
);
1171 s
->recheckProgress
= s
->activity
== TR_STATUS_CHECK
? getVerifyProgress( tor
) : 0;
1172 s
->activityDate
= tor
->activityDate
;
1173 s
->addedDate
= tor
->addedDate
;
1174 s
->doneDate
= tor
->doneDate
;
1175 s
->startDate
= tor
->startDate
;
1176 s
->secondsSeeding
= tor
->secondsSeeding
;
1177 s
->secondsDownloading
= tor
->secondsDownloading
;
1179 if ((s
->activity
== TR_STATUS_DOWNLOAD
|| s
->activity
== TR_STATUS_SEED
) && s
->startDate
!= 0)
1180 s
->idleSecs
= difftime(tr_time(), MAX(s
->startDate
, s
->activityDate
));
1184 s
->corruptEver
= tor
->corruptCur
+ tor
->corruptPrev
;
1185 s
->downloadedEver
= tor
->downloadedCur
+ tor
->downloadedPrev
;
1186 s
->uploadedEver
= tor
->uploadedCur
+ tor
->uploadedPrev
;
1187 s
->haveValid
= tr_cpHaveValid( &tor
->completion
);
1188 s
->haveUnchecked
= tr_cpHaveTotal( &tor
->completion
) - s
->haveValid
;
1189 s
->desiredAvailable
= tr_peerMgrGetDesiredAvailable( tor
);
1191 s
->ratio
= tr_getRatio( s
->uploadedEver
,
1192 s
->downloadedEver
? s
->downloadedEver
: s
->haveValid
);
1194 seedRatioApplies
= tr_torrentGetSeedRatioBytes( tor
, &seedRatioBytesLeft
,
1195 &seedRatioBytesGoal
);
1197 switch( s
->activity
)
1199 /* etaXLSpeed exists because if we use the piece speed directly,
1200 * brief fluctuations cause the ETA to jump all over the place.
1201 * so, etaXLSpeed is a smoothed-out version of the piece speed
1202 * to dampen the effect of fluctuations */
1204 case TR_STATUS_DOWNLOAD
:
1205 if( ( tor
->etaDLSpeedCalculatedAt
+ 800 ) < now
) {
1206 tor
->etaDLSpeed_KBps
= ( ( tor
->etaDLSpeedCalculatedAt
+ 4000 ) < now
)
1207 ? s
->pieceDownloadSpeed_KBps
/* if no recent previous speed, no need to smooth */
1208 : ((tor
->etaDLSpeed_KBps
*4.0) + s
->pieceDownloadSpeed_KBps
)/5.0; /* smooth across 5 readings */
1209 tor
->etaDLSpeedCalculatedAt
= now
;
1212 if( s
->leftUntilDone
> s
->desiredAvailable
)
1213 s
->eta
= TR_ETA_NOT_AVAIL
;
1214 else if( tor
->etaDLSpeed_KBps
< 1 )
1215 s
->eta
= TR_ETA_UNKNOWN
;
1217 s
->eta
= s
->leftUntilDone
/ toSpeedBytes(tor
->etaDLSpeed_KBps
);
1219 s
->etaIdle
= TR_ETA_NOT_AVAIL
;
1222 case TR_STATUS_SEED
: {
1223 if( !seedRatioApplies
)
1224 s
->eta
= TR_ETA_NOT_AVAIL
;
1226 if( ( tor
->etaULSpeedCalculatedAt
+ 800 ) < now
) {
1227 tor
->etaULSpeed_KBps
= ( ( tor
->etaULSpeedCalculatedAt
+ 4000 ) < now
)
1228 ? s
->pieceUploadSpeed_KBps
/* if no recent previous speed, no need to smooth */
1229 : ((tor
->etaULSpeed_KBps
*4.0) + s
->pieceUploadSpeed_KBps
)/5.0; /* smooth across 5 readings */
1230 tor
->etaULSpeedCalculatedAt
= now
;
1232 if( tor
->etaULSpeed_KBps
< 1 )
1233 s
->eta
= TR_ETA_UNKNOWN
;
1235 s
->eta
= seedRatioBytesLeft
/ toSpeedBytes(tor
->etaULSpeed_KBps
);
1238 if( tor
->etaULSpeed_KBps
< 1 && tr_torrentGetSeedIdle( tor
, &seedIdleMinutes
) )
1239 s
->etaIdle
= seedIdleMinutes
* 60 - s
->idleSecs
;
1241 s
->etaIdle
= TR_ETA_NOT_AVAIL
;
1246 s
->eta
= TR_ETA_NOT_AVAIL
;
1247 s
->etaIdle
= TR_ETA_NOT_AVAIL
;
1251 /* s->haveValid is here to make sure a torrent isn't marked 'finished'
1252 * when the user hits "uncheck all" prior to starting the torrent... */
1253 s
->finished
= tor
->finishedSeedingByIdle
|| (seedRatioApplies
&& !seedRatioBytesLeft
&& s
->haveValid
);
1255 if( !seedRatioApplies
|| s
->finished
)
1256 s
->seedRatioPercentDone
= 1;
1257 else if( !seedRatioBytesGoal
) /* impossible? safeguard for div by zero */
1258 s
->seedRatioPercentDone
= 0;
1260 s
->seedRatioPercentDone
= (double)(seedRatioBytesGoal
- seedRatioBytesLeft
) / seedRatioBytesGoal
;
1262 tr_torrentUnlock( tor
);
1264 /* test some of the constraints */
1265 assert( s
->sizeWhenDone
<= tor
->info
.totalSize
);
1266 assert( s
->leftUntilDone
<= s
->sizeWhenDone
);
1267 assert( s
->desiredAvailable
<= s
->leftUntilDone
);
1276 fileBytesCompleted( const tr_torrent
* tor
, tr_file_index_t index
)
1279 const tr_file
* f
= &tor
->info
.files
[index
];
1283 tr_block_index_t first
;
1284 tr_block_index_t last
;
1285 tr_torGetFileBlockRange( tor
, index
, &first
, &last
);
1289 if( tr_cpBlockIsComplete( &tor
->completion
, first
) )
1294 /* the first block */
1295 if( tr_cpBlockIsComplete( &tor
->completion
, first
) )
1296 total
+= tor
->blockSize
- ( f
->offset
% tor
->blockSize
);
1298 /* the middle blocks */
1299 if( first
+ 1 < last
) {
1300 uint64_t u
= tr_bitfieldCountRange( &tor
->completion
.blockBitfield
, first
+1, last
);
1301 u
*= tor
->blockSize
;
1305 /* the last block */
1306 if( tr_cpBlockIsComplete( &tor
->completion
, last
) )
1307 total
+= ( f
->offset
+ f
->length
) - ( (uint64_t)tor
->blockSize
* last
);
1315 tr_torrentFiles( const tr_torrent
* tor
,
1316 tr_file_index_t
* fileCount
)
1319 const tr_file_index_t n
= tor
->info
.fileCount
;
1320 tr_file_stat
* files
= tr_new0( tr_file_stat
, n
);
1321 tr_file_stat
* walk
= files
;
1322 const bool isSeed
= tor
->completeness
== TR_SEED
;
1324 assert( tr_isTorrent( tor
) );
1326 for( i
=0; i
<n
; ++i
, ++walk
) {
1327 const uint64_t b
= isSeed
? tor
->info
.files
[i
].length
: fileBytesCompleted( tor
, i
);
1328 walk
->bytesCompleted
= b
;
1329 walk
->progress
= tor
->info
.files
[i
].length
> 0 ? ( (float)b
/ tor
->info
.files
[i
].length
) : 1.0f
;
1339 tr_torrentFilesFree( tr_file_stat
* files
,
1340 tr_file_index_t fileCount UNUSED
)
1350 tr_torrentWebSpeeds_KBps( const tr_torrent
* tor
)
1352 double * ret
= NULL
;
1354 if( tr_isTorrent( tor
) )
1356 tr_torrentLock( tor
);
1357 ret
= tr_peerMgrWebSpeeds_KBps( tor
);
1358 tr_torrentUnlock( tor
);
1365 tr_torrentPeers( const tr_torrent
* tor
, int * peerCount
)
1367 tr_peer_stat
* ret
= NULL
;
1369 if( tr_isTorrent( tor
) )
1371 tr_torrentLock( tor
);
1372 ret
= tr_peerMgrPeerStats( tor
, peerCount
);
1373 tr_torrentUnlock( tor
);
1380 tr_torrentPeersFree( tr_peer_stat
* peers
, int peerCount UNUSED
)
1386 tr_torrentTrackers( const tr_torrent
* torrent
, int * setmeTrackerCount
)
1388 tr_tracker_stat
* ret
= NULL
;
1390 if( tr_isTorrent( torrent
) )
1392 tr_torrentLock( torrent
);
1393 ret
= tr_announcerStats( torrent
, setmeTrackerCount
);
1394 tr_torrentUnlock( torrent
);
1401 tr_torrentTrackersFree( tr_tracker_stat
* trackers
, int trackerCount
)
1403 tr_announcerStatsFree( trackers
, trackerCount
);
1407 tr_torrentAvailability( const tr_torrent
* tor
, int8_t * tab
, int size
)
1409 if( tr_isTorrent( tor
) && ( tab
!= NULL
) && ( size
> 0 ) )
1411 tr_torrentLock( tor
);
1412 tr_peerMgrTorrentAvailability( tor
, tab
, size
);
1413 tr_torrentUnlock( tor
);
1418 tr_torrentAmountFinished( const tr_torrent
* tor
,
1422 assert( tr_isTorrent( tor
) );
1424 tr_torrentLock( tor
);
1425 tr_cpGetAmountDone( &tor
->completion
, tab
, size
);
1426 tr_torrentUnlock( tor
);
1430 tr_torrentResetTransferStats( tr_torrent
* tor
)
1432 tr_torrentLock( tor
);
1434 tor
->downloadedPrev
+= tor
->downloadedCur
;
1435 tor
->downloadedCur
= 0;
1436 tor
->uploadedPrev
+= tor
->uploadedCur
;
1437 tor
->uploadedCur
= 0;
1438 tor
->corruptPrev
+= tor
->corruptCur
;
1439 tor
->corruptCur
= 0;
1441 tr_torrentSetDirty( tor
);
1443 tr_torrentUnlock( tor
);
1447 tr_torrentSetHasPiece( tr_torrent
* tor
,
1448 tr_piece_index_t pieceIndex
,
1451 assert( tr_isTorrent( tor
) );
1452 assert( pieceIndex
< tor
->info
.pieceCount
);
1455 tr_cpPieceAdd( &tor
->completion
, pieceIndex
);
1457 tr_cpPieceRem( &tor
->completion
, pieceIndex
);
1465 freeTorrent( tr_torrent
* tor
)
1468 tr_session
* session
= tor
->session
;
1469 tr_info
* inf
= &tor
->info
;
1471 assert( !tor
->isRunning
);
1473 tr_sessionLock( session
);
1475 tr_peerMgrRemoveTorrent( tor
);
1477 tr_cpDestruct( &tor
->completion
);
1479 tr_announcerRemoveTorrent( session
->announcer
, tor
);
1481 tr_free( tor
->downloadDir
);
1482 tr_free( tor
->incompleteDir
);
1484 if( tor
== session
->torrentList
)
1485 session
->torrentList
= tor
->next
;
1486 else for( t
= session
->torrentList
; t
!= NULL
; t
= t
->next
) {
1487 if( t
->next
== tor
) {
1488 t
->next
= tor
->next
;
1493 assert( session
->torrentCount
>= 1 );
1494 session
->torrentCount
--;
1496 tr_bandwidthDestruct( &tor
->bandwidth
);
1498 tr_metainfoFree( inf
);
1501 tr_sessionUnlock( session
);
1505 *** Start/Stop Callback
1509 torrentStartImpl( void * vtor
)
1512 tr_torrent
* tor
= vtor
;
1514 assert( tr_isTorrent( tor
) );
1516 tr_sessionLock( tor
->session
);
1518 tr_torrentRecheckCompleteness( tor
);
1521 tor
->isRunning
= true;
1522 tor
->completeness
= tr_cpGetStatus( &tor
->completion
);
1523 tor
->startDate
= tor
->anyDate
= now
;
1524 tr_torrentClearError( tor
);
1525 tor
->finishedSeedingByIdle
= false;
1527 tr_torrentResetTransferStats( tor
);
1528 tr_announcerTorrentStarted( tor
);
1529 tor
->dhtAnnounceAt
= now
+ tr_cryptoWeakRandInt( 20 );
1530 tor
->dhtAnnounce6At
= now
+ tr_cryptoWeakRandInt( 20 );
1531 tor
->lpdAnnounceAt
= now
;
1532 tr_peerMgrStartTorrent( tor
);
1534 tr_sessionUnlock( tor
->session
);
1538 tr_torrentGetCurrentSizeOnDisk( const tr_torrent
* tor
)
1541 uint64_t byte_count
= 0;
1542 const tr_file_index_t n
= tor
->info
.fileCount
;
1544 for( i
=0; i
<n
; ++i
)
1547 char * filename
= tr_torrentFindFile( tor
, i
);
1550 if( filename
&& !stat( filename
, &sb
) )
1551 byte_count
+= sb
.st_size
;
1553 tr_free( filename
);
1560 torrentStart( tr_torrent
* tor
)
1562 /* already running... */
1563 if( tor
->isRunning
)
1566 /* don't allow the torrent to be started if the files disappeared */
1567 if( setLocalErrorIfFilesDisappeared( tor
) )
1570 /* verifying right now... wait until that's done so
1571 * we'll know what completeness to use/announce */
1572 if( tor
->verifyState
!= TR_VERIFY_NONE
) {
1573 tor
->startAfterVerify
= true;
1577 /* otherwise, start it now... */
1578 tr_sessionLock( tor
->session
);
1580 /* allow finished torrents to be resumed */
1581 if( tr_torrentIsSeedRatioDone( tor
) ) {
1582 tr_torinf( tor
, _( "Restarted manually -- disabling its seed ratio" ) );
1583 tr_torrentSetRatioMode( tor
, TR_RATIOLIMIT_UNLIMITED
);
1586 /* corresponds to the peer_id sent as a tracker request parameter.
1587 * one tracker admin says: "When the same torrent is opened and
1588 * closed and opened again without quitting Transmission ...
1589 * change the peerid. It would help sometimes if a stopped event
1590 * was missed to ensure that we didn't think someone was cheating. */
1591 tr_peerIdInit( tor
->peer_id
);
1593 tr_torrentSetDirty( tor
);
1594 tr_runInEventThread( tor
->session
, torrentStartImpl
, tor
);
1596 tr_sessionUnlock( tor
->session
);
1600 tr_torrentStart( tr_torrent
* tor
)
1602 if( tr_isTorrent( tor
) )
1603 torrentStart( tor
);
1607 torrentRecheckDoneImpl( void * vtor
)
1609 tr_torrent
* tor
= vtor
;
1610 assert( tr_isTorrent( tor
) );
1612 tr_torrentRecheckCompleteness( tor
);
1614 if( tor
->startAfterVerify
) {
1615 tor
->startAfterVerify
= false;
1616 torrentStart( tor
);
1621 torrentRecheckDoneCB( tr_torrent
* tor
)
1623 assert( tr_isTorrent( tor
) );
1625 tr_runInEventThread( tor
->session
, torrentRecheckDoneImpl
, tor
);
1629 verifyTorrent( void * vtor
)
1631 tr_torrent
* tor
= vtor
;
1633 tr_sessionLock( tor
->session
);
1635 /* if the torrent's already being verified, stop it */
1636 tr_verifyRemove( tor
);
1638 /* if the torrent's running, stop it & set the restart-after-verify flag */
1639 if( tor
->startAfterVerify
|| tor
->isRunning
) {
1640 /* don't clobber isStopping */
1641 const bool startAfter
= tor
->isStopping
? false : true;
1642 tr_torrentStop( tor
);
1643 tor
->startAfterVerify
= startAfter
;
1646 if( setLocalErrorIfFilesDisappeared( tor
) )
1647 tor
->startAfterVerify
= false;
1649 tr_verifyAdd( tor
, torrentRecheckDoneCB
);
1651 tr_sessionUnlock( tor
->session
);
1655 tr_torrentVerify( tr_torrent
* tor
)
1657 if( tr_isTorrent( tor
) )
1658 tr_runInEventThread( tor
->session
, verifyTorrent
, tor
);
1662 tr_torrentSave( tr_torrent
* tor
)
1664 assert( tr_isTorrent( tor
) );
1668 tor
->isDirty
= false;
1669 tr_torrentSaveResume( tor
);
1674 stopTorrent( void * vtor
)
1676 tr_torrent
* tor
= vtor
;
1677 tr_torinf( tor
, "Pausing" );
1679 assert( tr_isTorrent( tor
) );
1681 tr_torrentLock( tor
);
1683 tr_verifyRemove( tor
);
1684 tr_peerMgrStopTorrent( tor
);
1685 tr_announcerTorrentStopped( tor
);
1686 tr_cacheFlushTorrent( tor
->session
->cache
, tor
);
1688 tr_fdTorrentClose( tor
->session
, tor
->uniqueId
);
1690 if( !tor
->isDeleting
)
1691 tr_torrentSave( tor
);
1693 tr_torrentUnlock( tor
);
1697 tr_torrentStop( tr_torrent
* tor
)
1699 assert( tr_isTorrent( tor
) );
1701 if( tr_isTorrent( tor
) )
1703 tr_sessionLock( tor
->session
);
1706 tor
->isStopping
= 0;
1707 tr_torrentSetDirty( tor
);
1708 tr_runInEventThread( tor
->session
, stopTorrent
, tor
);
1710 tr_sessionUnlock( tor
->session
);
1715 closeTorrent( void * vtor
)
1718 tr_torrent
* tor
= vtor
;
1720 assert( tr_isTorrent( tor
) );
1722 d
= tr_bencListAddDict( &tor
->session
->removedTorrents
, 2 );
1723 tr_bencDictAddInt( d
, "id", tor
->uniqueId
);
1724 tr_bencDictAddInt( d
, "date", tr_time( ) );
1726 tr_torinf( tor
, "%s", _( "Removing torrent" ) );
1730 if( tor
->isDeleting
)
1732 tr_metainfoRemoveSaved( tor
->session
, &tor
->info
);
1733 tr_torrentRemoveResume( tor
);
1741 tr_torrentFree( tr_torrent
* tor
)
1743 if( tr_isTorrent( tor
) )
1745 tr_session
* session
= tor
->session
;
1746 assert( tr_isSession( session
) );
1747 tr_sessionLock( session
);
1749 tr_torrentClearCompletenessCallback( tor
);
1750 tr_runInEventThread( session
, closeTorrent
, tor
);
1752 tr_sessionUnlock( session
);
1760 tr_fileFunc
* deleteFunc
;
1763 static void tr_torrentDeleteLocalData( tr_torrent
*, tr_fileFunc
);
1766 removeTorrent( void * vdata
)
1768 struct remove_data
* data
= vdata
;
1770 if( data
->deleteFlag
)
1771 tr_torrentDeleteLocalData( data
->tor
, data
->deleteFunc
);
1773 tr_torrentClearCompletenessCallback( data
->tor
);
1774 closeTorrent( data
->tor
);
1779 tr_torrentRemove( tr_torrent
* tor
,
1781 tr_fileFunc deleteFunc
)
1783 struct remove_data
* data
;
1785 assert( tr_isTorrent( tor
) );
1786 tor
->isDeleting
= 1;
1788 data
= tr_new0( struct remove_data
, 1 );
1790 data
->deleteFlag
= deleteFlag
;
1791 data
->deleteFunc
= deleteFunc
;
1792 tr_runInEventThread( tor
->session
, removeTorrent
, data
);
1800 getCompletionString( int type
)
1804 /* Translators: this is a minor point that's safe to skip over, but FYI:
1805 "Complete" and "Done" are specific, different terms in Transmission:
1806 "Complete" means we've downloaded every file in the torrent.
1807 "Done" means we're done downloading the files we wanted, but NOT all
1809 case TR_PARTIAL_SEED
:
1813 return _( "Complete" );
1816 return _( "Incomplete" );
1821 fireCompletenessChange( tr_torrent
* tor
,
1822 tr_completeness status
,
1825 assert( ( status
== TR_LEECH
)
1826 || ( status
== TR_SEED
)
1827 || ( status
== TR_PARTIAL_SEED
) );
1829 if( tor
->completeness_func
)
1830 tor
->completeness_func( tor
, status
, wasRunning
,
1831 tor
->completeness_func_user_data
);
1835 tr_torrentSetCompletenessCallback( tr_torrent
* tor
,
1836 tr_torrent_completeness_func func
,
1839 assert( tr_isTorrent( tor
) );
1841 tor
->completeness_func
= func
;
1842 tor
->completeness_func_user_data
= user_data
;
1846 tr_torrentClearCompletenessCallback( tr_torrent
* torrent
)
1848 tr_torrentSetCompletenessCallback( torrent
, NULL
, NULL
);
1852 tr_torrentSetRatioLimitHitCallback( tr_torrent
* tor
,
1853 tr_torrent_ratio_limit_hit_func func
,
1856 assert( tr_isTorrent( tor
) );
1858 tor
->ratio_limit_hit_func
= func
;
1859 tor
->ratio_limit_hit_func_user_data
= user_data
;
1863 tr_torrentClearRatioLimitHitCallback( tr_torrent
* torrent
)
1865 tr_torrentSetRatioLimitHitCallback( torrent
, NULL
, NULL
);
1869 tr_torrentSetIdleLimitHitCallback( tr_torrent
* tor
,
1870 tr_torrent_idle_limit_hit_func func
,
1873 assert( tr_isTorrent( tor
) );
1875 tor
->idle_limit_hit_func
= func
;
1876 tor
->idle_limit_hit_func_user_data
= user_data
;
1880 tr_torrentClearIdleLimitHitCallback( tr_torrent
* torrent
)
1882 tr_torrentSetIdleLimitHitCallback( torrent
, NULL
, NULL
);
1886 onSigCHLD( int i UNUSED
)
1888 waitpid( -1, NULL
, WNOHANG
);
1892 torrentCallScript( const tr_torrent
* tor
, const char * script
)
1895 const time_t now
= tr_time( );
1897 tr_strlcpy( timeStr
, ctime( &now
), sizeof( timeStr
) );
1898 *strchr( timeStr
,'\n' ) = '\0';
1900 if( script
&& *script
)
1903 char * cmd
[] = { tr_strdup( script
), NULL
};
1905 tr_strdup_printf( "TR_APP_VERSION=%s", SHORT_VERSION_STRING
),
1906 tr_strdup_printf( "TR_TIME_LOCALTIME=%s", timeStr
),
1907 tr_strdup_printf( "TR_TORRENT_DIR=%s", tor
->currentDir
),
1908 tr_strdup_printf( "TR_TORRENT_ID=%d", tr_torrentId( tor
) ),
1909 tr_strdup_printf( "TR_TORRENT_HASH=%s", tor
->info
.hashString
),
1910 tr_strdup_printf( "TR_TORRENT_NAME=%s", tr_torrentName( tor
) ),
1913 tr_torinf( tor
, "Calling script \"%s\"", script
);
1916 _spawnvpe( _P_NOWAIT
, script
, (const char*)cmd
, env
);
1918 signal( SIGCHLD
, onSigCHLD
);
1922 for (i
=0; env
[i
]; ++i
)
1924 execvp( script
, cmd
);
1929 for( i
=0; cmd
[i
]; ++i
) tr_free( cmd
[i
] );
1930 for( i
=0; env
[i
]; ++i
) tr_free( env
[i
] );
1935 tr_torrentRecheckCompleteness( tr_torrent
* tor
)
1937 tr_completeness completeness
;
1939 assert( tr_isTorrent( tor
) );
1941 tr_torrentLock( tor
);
1943 completeness
= tr_cpGetStatus( &tor
->completion
);
1945 if( completeness
!= tor
->completeness
)
1947 const int recentChange
= tor
->downloadedCur
!= 0;
1948 const bool wasLeeching
= !tr_torrentIsSeed( tor
);
1949 const bool wasRunning
= tor
->isRunning
;
1953 tr_torinf( tor
, _( "State changed from \"%1$s\" to \"%2$s\"" ),
1954 getCompletionString( tor
->completeness
),
1955 getCompletionString( completeness
) );
1958 tor
->completeness
= completeness
;
1959 tr_fdTorrentClose( tor
->session
, tor
->uniqueId
);
1961 if( tr_torrentIsSeed( tor
) )
1965 tr_announcerTorrentCompleted( tor
);
1966 tor
->doneDate
= tor
->anyDate
= tr_time( );
1969 if( wasLeeching
&& wasRunning
)
1971 /* clear interested flag on all peers */
1972 tr_peerMgrClearInterest( tor
);
1974 /* if completeness was TR_LEECH then the seed limit check will have been skipped in bandwidthPulse */
1975 tr_torrentCheckSeedLimit( tor
);
1978 if( tor
->currentDir
== tor
->incompleteDir
)
1979 tr_torrentSetLocation( tor
, tor
->downloadDir
, true, NULL
, NULL
);
1981 if( tr_sessionIsTorrentDoneScriptEnabled( tor
->session
) )
1982 torrentCallScript( tor
, tr_sessionGetTorrentDoneScript( tor
->session
) );
1985 fireCompletenessChange( tor
, completeness
, wasRunning
);
1987 tr_torrentSetDirty( tor
);
1990 tr_torrentUnlock( tor
);
1998 tr_torrentFireMetadataCompleted( tr_torrent
* tor
)
2000 assert( tr_isTorrent( tor
) );
2002 if( tor
->metadata_func
)
2003 tor
->metadata_func( tor
, tor
->metadata_func_user_data
);
2007 tr_torrentSetMetadataCallback( tr_torrent
* tor
,
2008 tr_torrent_metadata_func func
,
2011 assert( tr_isTorrent( tor
) );
2013 tor
->metadata_func
= func
;
2014 tor
->metadata_func_user_data
= user_data
;
2023 tr_torrentInitFilePriority( tr_torrent
* tor
,
2024 tr_file_index_t fileIndex
,
2025 tr_priority_t priority
)
2030 assert( tr_isTorrent( tor
) );
2031 assert( fileIndex
< tor
->info
.fileCount
);
2032 assert( tr_isPriority( priority
) );
2034 file
= &tor
->info
.files
[fileIndex
];
2035 file
->priority
= priority
;
2036 for( i
= file
->firstPiece
; i
<= file
->lastPiece
; ++i
)
2037 tor
->info
.pieces
[i
].priority
= calculatePiecePriority( tor
, i
, fileIndex
);
2041 tr_torrentSetFilePriorities( tr_torrent
* tor
,
2042 const tr_file_index_t
* files
,
2043 tr_file_index_t fileCount
,
2044 tr_priority_t priority
)
2047 assert( tr_isTorrent( tor
) );
2048 tr_torrentLock( tor
);
2050 for( i
= 0; i
< fileCount
; ++i
)
2051 if( files
[i
] < tor
->info
.fileCount
)
2052 tr_torrentInitFilePriority( tor
, files
[i
], priority
);
2053 tr_torrentSetDirty( tor
);
2054 tr_peerMgrRebuildRequests( tor
);
2056 tr_torrentUnlock( tor
);
2060 tr_torrentGetFilePriorities( const tr_torrent
* tor
)
2065 assert( tr_isTorrent( tor
) );
2067 tr_torrentLock( tor
);
2068 p
= tr_new0( tr_priority_t
, tor
->info
.fileCount
);
2069 for( i
= 0; i
< tor
->info
.fileCount
; ++i
)
2070 p
[i
] = tor
->info
.files
[i
].priority
;
2071 tr_torrentUnlock( tor
);
2081 setFileDND( tr_torrent
* tor
, tr_file_index_t fileIndex
, int doDownload
)
2083 const int8_t dnd
= !doDownload
;
2084 tr_piece_index_t firstPiece
;
2085 int8_t firstPieceDND
;
2086 tr_piece_index_t lastPiece
;
2087 int8_t lastPieceDND
;
2089 tr_file
* file
= &tor
->info
.files
[fileIndex
];
2092 firstPiece
= file
->firstPiece
;
2093 lastPiece
= file
->lastPiece
;
2095 /* can't set the first piece to DND unless
2096 every file using that piece is DND */
2097 firstPieceDND
= dnd
;
2100 for( i
= fileIndex
- 1; firstPieceDND
; --i
)
2102 if( tor
->info
.files
[i
].lastPiece
!= firstPiece
)
2104 firstPieceDND
= tor
->info
.files
[i
].dnd
;
2110 /* can't set the last piece to DND unless
2111 every file using that piece is DND */
2113 for( i
= fileIndex
+ 1; lastPieceDND
&& i
< tor
->info
.fileCount
; ++i
)
2115 if( tor
->info
.files
[i
].firstPiece
!= lastPiece
)
2117 lastPieceDND
= tor
->info
.files
[i
].dnd
;
2120 if( firstPiece
== lastPiece
)
2122 tor
->info
.pieces
[firstPiece
].dnd
= firstPieceDND
&& lastPieceDND
;
2126 tr_piece_index_t pp
;
2127 tor
->info
.pieces
[firstPiece
].dnd
= firstPieceDND
;
2128 tor
->info
.pieces
[lastPiece
].dnd
= lastPieceDND
;
2129 for( pp
= firstPiece
+ 1; pp
< lastPiece
; ++pp
)
2130 tor
->info
.pieces
[pp
].dnd
= dnd
;
2135 tr_torrentInitFileDLs( tr_torrent
* tor
,
2136 const tr_file_index_t
* files
,
2137 tr_file_index_t fileCount
,
2142 assert( tr_isTorrent( tor
) );
2144 tr_torrentLock( tor
);
2146 for( i
=0; i
<fileCount
; ++i
)
2147 if( files
[i
] < tor
->info
.fileCount
)
2148 setFileDND( tor
, files
[i
], doDownload
);
2150 tr_cpInvalidateDND( &tor
->completion
);
2152 tr_torrentUnlock( tor
);
2156 tr_torrentSetFileDLs( tr_torrent
* tor
,
2157 const tr_file_index_t
* files
,
2158 tr_file_index_t fileCount
,
2161 assert( tr_isTorrent( tor
) );
2162 tr_torrentLock( tor
);
2164 tr_torrentInitFileDLs( tor
, files
, fileCount
, doDownload
);
2165 tr_torrentSetDirty( tor
);
2166 tr_peerMgrRebuildRequests( tor
);
2168 tr_torrentUnlock( tor
);
2176 tr_torrentGetPriority( const tr_torrent
* tor
)
2178 assert( tr_isTorrent( tor
) );
2180 return tor
->bandwidth
.priority
;
2184 tr_torrentSetPriority( tr_torrent
* tor
, tr_priority_t priority
)
2186 assert( tr_isTorrent( tor
) );
2187 assert( tr_isPriority( priority
) );
2189 if( tor
->bandwidth
.priority
!= priority
)
2191 tor
->bandwidth
.priority
= priority
;
2193 tr_torrentSetDirty( tor
);
2202 tr_torrentSetPeerLimit( tr_torrent
* tor
,
2203 uint16_t maxConnectedPeers
)
2205 assert( tr_isTorrent( tor
) );
2207 if ( tor
->maxConnectedPeers
!= maxConnectedPeers
)
2209 tor
->maxConnectedPeers
= maxConnectedPeers
;
2211 tr_torrentSetDirty( tor
);
2216 tr_torrentGetPeerLimit( const tr_torrent
* tor
)
2218 assert( tr_isTorrent( tor
) );
2220 return tor
->maxConnectedPeers
;
2228 tr_torrentGetBlockLocation( const tr_torrent
* tor
,
2229 tr_block_index_t block
,
2230 tr_piece_index_t
* piece
,
2234 uint64_t pos
= block
;
2235 pos
*= tor
->blockSize
;
2236 *piece
= pos
/ tor
->info
.pieceSize
;
2237 *offset
= pos
- ( *piece
* tor
->info
.pieceSize
);
2238 *length
= tr_torBlockCountBytes( tor
, block
);
2243 _tr_block( const tr_torrent
* tor
,
2244 tr_piece_index_t index
,
2247 tr_block_index_t ret
;
2249 assert( tr_isTorrent( tor
) );
2252 ret
*= ( tor
->info
.pieceSize
/ tor
->blockSize
);
2253 ret
+= offset
/ tor
->blockSize
;
2258 tr_torrentReqIsValid( const tr_torrent
* tor
,
2259 tr_piece_index_t index
,
2265 assert( tr_isTorrent( tor
) );
2267 if( index
>= tor
->info
.pieceCount
)
2269 else if( length
< 1 )
2271 else if( ( offset
+ length
) > tr_torPieceCountBytes( tor
, index
) )
2273 else if( length
> MAX_BLOCK_SIZE
)
2275 else if( tr_pieceOffset( tor
, index
, offset
, length
) > tor
->info
.totalSize
)
2278 if( err
) tr_tordbg( tor
, "index %lu offset %lu length %lu err %d\n",
2279 (unsigned long)index
,
2280 (unsigned long)offset
,
2281 (unsigned long)length
,
2288 tr_pieceOffset( const tr_torrent
* tor
,
2289 tr_piece_index_t index
,
2295 assert( tr_isTorrent( tor
) );
2297 ret
= tor
->info
.pieceSize
;
2305 tr_torGetFileBlockRange( const tr_torrent
* tor
,
2306 const tr_file_index_t file
,
2307 tr_block_index_t
* first
,
2308 tr_block_index_t
* last
)
2310 const tr_file
* f
= &tor
->info
.files
[file
];
2311 uint64_t offset
= f
->offset
;
2312 *first
= offset
/ tor
->blockSize
;
2316 offset
+= f
->length
- 1;
2317 *last
= offset
/ tor
->blockSize
;
2322 tr_torGetPieceBlockRange( const tr_torrent
* tor
,
2323 const tr_piece_index_t piece
,
2324 tr_block_index_t
* first
,
2325 tr_block_index_t
* last
)
2327 uint64_t offset
= tor
->info
.pieceSize
;
2329 *first
= offset
/ tor
->blockSize
;
2330 offset
+= ( tr_torPieceCountBytes( tor
, piece
) - 1 );
2331 *last
= offset
/ tor
->blockSize
;
2340 tr_torrentSetPieceChecked( tr_torrent
* tor
, tr_piece_index_t pieceIndex
)
2342 assert( tr_isTorrent( tor
) );
2343 assert( pieceIndex
< tor
->info
.pieceCount
);
2345 tor
->info
.pieces
[pieceIndex
].timeChecked
= tr_time( );
2349 tr_torrentSetChecked( tr_torrent
* tor
, time_t when
)
2351 tr_piece_index_t i
, n
;
2353 assert( tr_isTorrent( tor
) );
2355 for( i
=0, n
=tor
->info
.pieceCount
; i
!=n
; ++i
)
2356 tor
->info
.pieces
[i
].timeChecked
= when
;
2360 tr_torrentCheckPiece( tr_torrent
* tor
, tr_piece_index_t pieceIndex
)
2362 const bool pass
= tr_ioTestPiece( tor
, pieceIndex
);
2364 tr_deeplog_tor( tor
, "[LAZY] tr_torrentCheckPiece tested piece %zu, pass==%d", (size_t)pieceIndex
, (int)pass
);
2365 tr_torrentSetHasPiece( tor
, pieceIndex
, pass
);
2366 tr_torrentSetPieceChecked( tor
, pieceIndex
);
2367 tor
->anyDate
= tr_time( );
2368 tr_torrentSetDirty( tor
);
2374 tr_torrentGetFileMTime( const tr_torrent
* tor
, tr_file_index_t i
)
2377 if( !tr_fdFileGetCachedMTime( tor
->session
, tor
->uniqueId
, i
, &mtime
) )
2378 tr_torrentFindFile2( tor
, i
, NULL
, NULL
, &mtime
);
2383 tr_torrentPieceNeedsCheck( const tr_torrent
* tor
, tr_piece_index_t p
)
2387 const tr_info
* inf
= tr_torrentInfo( tor
);
2389 /* if we've never checked this piece, then it needs to be checked */
2390 if( !inf
->pieces
[p
].timeChecked
)
2393 /* If we think we've completed one of the files in this piece,
2394 * but it's been modified since we last checked it,
2395 * then it needs to be rechecked */
2396 tr_ioFindFileLocation( tor
, p
, 0, &f
, &unused
);
2397 for( ; f
< inf
->fileCount
&& pieceHasFile( p
, &inf
->files
[f
] ); ++f
)
2398 if( tr_cpFileIsComplete( &tor
->completion
, f
) )
2399 if( tr_torrentGetFileMTime( tor
, f
) > inf
->pieces
[p
].timeChecked
)
2410 compareTrackerByTier( const void * va
, const void * vb
)
2412 const tr_tracker_info
* a
= va
;
2413 const tr_tracker_info
* b
= vb
;
2416 if( a
->tier
!= b
->tier
)
2417 return a
->tier
- b
->tier
;
2419 /* get the effects of a stable sort by comparing the two elements' addresses */
2424 tr_torrentSetAnnounceList( tr_torrent
* tor
,
2425 const tr_tracker_info
* trackers_in
,
2431 tr_tracker_info
* trackers
;
2433 tr_torrentLock( tor
);
2435 assert( tr_isTorrent( tor
) );
2437 /* ensure the trackers' tiers are in ascending order */
2438 trackers
= tr_memdup( trackers_in
, sizeof( tr_tracker_info
) * trackerCount
);
2439 qsort( trackers
, trackerCount
, sizeof( tr_tracker_info
), compareTrackerByTier
);
2441 /* look for bad URLs */
2442 for( i
=0; ok
&& i
<trackerCount
; ++i
)
2443 if( !tr_urlIsValidTracker( trackers
[i
].announce
) )
2446 /* save to the .torrent file */
2447 if( ok
&& !tr_bencLoadFile( &metainfo
, TR_FMT_BENC
, tor
->info
.torrent
) )
2452 /* remove the old fields */
2453 tr_bencDictRemove( &metainfo
, "announce" );
2454 tr_bencDictRemove( &metainfo
, "announce-list" );
2456 /* add the new fields */
2457 if( trackerCount
> 0 )
2459 tr_bencDictAddStr( &metainfo
, "announce", trackers
[0].announce
);
2461 if( trackerCount
> 1 )
2465 tr_benc
* tier
= NULL
;
2466 tr_benc
* announceList
= tr_bencDictAddList( &metainfo
, "announce-list", 0 );
2468 for( i
=0; i
<trackerCount
; ++i
) {
2469 if( prevTier
!= trackers
[i
].tier
) {
2470 prevTier
= trackers
[i
].tier
;
2471 tier
= tr_bencListAddList( announceList
, 0 );
2473 tr_bencListAddStr( tier
, trackers
[i
].announce
);
2477 /* try to parse it back again, to make sure it's good */
2478 memset( &tmpInfo
, 0, sizeof( tr_info
) );
2479 if( tr_metainfoParse( tor
->session
, &metainfo
, &tmpInfo
,
2480 &hasInfo
, &tor
->infoDictLength
) )
2482 /* it's good, so keep these new trackers and free the old ones */
2485 swap
.trackers
= tor
->info
.trackers
;
2486 swap
.trackerCount
= tor
->info
.trackerCount
;
2487 tor
->info
.trackers
= tmpInfo
.trackers
;
2488 tor
->info
.trackerCount
= tmpInfo
.trackerCount
;
2489 tmpInfo
.trackers
= swap
.trackers
;
2490 tmpInfo
.trackerCount
= swap
.trackerCount
;
2492 tr_metainfoFree( &tmpInfo
);
2493 tr_bencToFile( &metainfo
, TR_FMT_BENC
, tor
->info
.torrent
);
2497 tr_bencFree( &metainfo
);
2499 /* if we had a tracker-related error on this torrent,
2500 * and that tracker's been removed,
2501 * then clear the error */
2502 if( ( tor
->error
== TR_STAT_TRACKER_WARNING
)
2503 || ( tor
->error
== TR_STAT_TRACKER_ERROR
) )
2507 for( i
=0; clear
&& i
<trackerCount
; ++i
)
2508 if( !strcmp( trackers
[i
].announce
, tor
->errorTracker
) )
2512 tr_torrentClearError( tor
);
2515 /* tell the announcer to reload this torrent's tracker list */
2516 tr_announcerResetTorrent( tor
->session
->announcer
, tor
);
2519 tr_torrentUnlock( tor
);
2521 tr_free( trackers
);
2530 tr_torrentSetAddedDate( tr_torrent
* tor
,
2533 assert( tr_isTorrent( tor
) );
2536 tor
->anyDate
= MAX( tor
->anyDate
, tor
->addedDate
);
2540 tr_torrentSetActivityDate( tr_torrent
* tor
, time_t t
)
2542 assert( tr_isTorrent( tor
) );
2544 tor
->activityDate
= t
;
2545 tor
->anyDate
= MAX( tor
->anyDate
, tor
->activityDate
);
2549 tr_torrentSetDoneDate( tr_torrent
* tor
,
2552 assert( tr_isTorrent( tor
) );
2555 tor
->anyDate
= MAX( tor
->anyDate
, tor
->doneDate
);
2563 tr_torrentGetBytesLeftToAllocate( const tr_torrent
* tor
)
2566 uint64_t bytesLeft
= 0;
2568 assert( tr_isTorrent( tor
) );
2570 for( i
=0; i
<tor
->info
.fileCount
; ++i
)
2572 if( !tor
->info
.files
[i
].dnd
)
2575 const uint64_t length
= tor
->info
.files
[i
].length
;
2576 char * path
= tr_torrentFindFile( tor
, i
);
2578 bytesLeft
+= length
;
2580 if( ( path
!= NULL
) && !stat( path
, &sb
)
2581 && S_ISREG( sb
.st_mode
)
2582 && ( (uint64_t)sb
.st_size
<= length
) )
2583 bytesLeft
-= sb
.st_size
;
2593 ***** Removing the torrent's local data
2597 vstrcmp( const void * a
, const void * b
)
2599 return strcmp( a
, b
);
2603 compareLongestFirst( const void * a
, const void * b
)
2605 const size_t alen
= strlen( a
);
2606 const size_t blen
= strlen( b
);
2609 return alen
> blen
? -1 : 1;
2611 return vstrcmp( a
, b
);
2615 addDirtyFile( const char * root
,
2616 const char * filename
,
2617 tr_ptrArray
* dirtyFolders
)
2619 char * dir
= tr_dirname( filename
);
2621 /* add the parent folders to dirtyFolders until we reach the root or a known-dirty */
2622 while ( ( dir
!= NULL
)
2623 && ( strlen( root
) <= strlen( dir
) )
2624 && ( tr_ptrArrayFindSorted( dirtyFolders
, dir
, vstrcmp
) == NULL
) )
2627 tr_ptrArrayInsertSorted( dirtyFolders
, tr_strdup( dir
), vstrcmp
);
2629 tmp
= tr_dirname( dir
);
2638 isSystemFile( const char * base
)
2641 static const char * stockFiles
[] = { ".DS_Store", "desktop.ini", "Thumbs.db" };
2642 static const int stockFileCount
= sizeof(stockFiles
) / sizeof(stockFiles
[0]);
2644 for( i
=0; i
<stockFileCount
; ++i
)
2645 if( !strcmp( base
, stockFiles
[i
] ) )
2648 /* check for resource forks. <http://support.apple.com/kb/TA20578> */
2649 if( !memcmp( base
, "._", 2 ) )
2656 deleteLocalFile( const tr_torrent
* tor
, const char * filename
, tr_fileFunc fileFunc
)
2660 /* add safeguards for (1) making sure the file exists and
2661 (2) that we haven't somehow walked up past the torrent's top directory... */
2662 if( !stat( filename
, &sb
) )
2663 if( !tr_is_same_file( tor
->currentDir
, filename
) )
2664 fileFunc( filename
);
2668 walkLocalData( const tr_torrent
* tor
,
2672 tr_ptrArray
* torrentFiles
,
2673 tr_ptrArray
* folders
,
2674 tr_ptrArray
* dirtyFolders
,
2675 tr_fileFunc fileFunc
)
2678 char * buf
= tr_buildPath( dir
, base
, NULL
);
2679 int i
= stat( buf
, &sb
);
2685 if( S_ISDIR( sb
.st_mode
) && ( ( odir
= opendir ( buf
) ) ) )
2688 tr_ptrArrayInsertSorted( folders
, tr_strdup( buf
), vstrcmp
);
2689 for( d
= readdir( odir
); d
!= NULL
; d
= readdir( odir
) )
2690 if( d
->d_name
&& strcmp( d
->d_name
, "." ) && strcmp( d
->d_name
, ".." ) )
2691 walkLocalData( tor
, root
, buf
, d
->d_name
, torrentFiles
, folders
, dirtyFolders
, fileFunc
);
2694 else if( S_ISREG( sb
.st_mode
) && ( sb
.st_size
> 0 ) )
2696 if( isSystemFile( base
) )
2697 deleteLocalFile( tor
, buf
, fileFunc
);
2699 const char * sub
= buf
+ strlen( tor
->currentDir
) + strlen( TR_PATH_DELIMITER_STR
);
2700 const bool isTorrentFile
= tr_ptrArrayFindSorted( torrentFiles
, sub
, vstrcmp
) != NULL
;
2701 if( !isTorrentFile
)
2702 addDirtyFile( root
, buf
, dirtyFolders
);
2711 deleteLocalData( tr_torrent
* tor
, tr_fileFunc fileFunc
)
2716 tr_ptrArray torrentFiles
= TR_PTR_ARRAY_INIT
;
2717 tr_ptrArray folders
= TR_PTR_ARRAY_INIT
;
2718 tr_ptrArray dirtyFolders
= TR_PTR_ARRAY_INIT
; /* dirty == contains non-torrent files */
2720 const char * firstFile
= tor
->info
.files
[0].name
;
2721 const char * cpch
= strchr( firstFile
, TR_PATH_DELIMITER
);
2722 char * tmp
= cpch
? tr_strndup( firstFile
, cpch
- firstFile
) : NULL
;
2723 char * root
= tr_buildPath( tor
->currentDir
, tmp
, NULL
);
2725 for( f
=0; f
<tor
->info
.fileCount
; ++f
) {
2726 tr_ptrArrayInsertSorted( &torrentFiles
, tr_strdup( tor
->info
.files
[f
].name
), vstrcmp
);
2727 tr_ptrArrayInsertSorted( &torrentFiles
, tr_torrentBuildPartial( tor
, f
), vstrcmp
);
2730 /* build the set of folders and dirtyFolders */
2731 walkLocalData( tor
, root
, root
, NULL
, &torrentFiles
, &folders
, &dirtyFolders
, fileFunc
);
2733 /* try to remove entire folders first, so that the recycle bin will be tidy */
2734 s
= (char**) tr_ptrArrayPeek( &folders
, &n
);
2735 for( i
=0; i
<n
; ++i
)
2736 if( tr_ptrArrayFindSorted( &dirtyFolders
, s
[i
], vstrcmp
) == NULL
)
2737 deleteLocalFile( tor
, s
[i
], fileFunc
);
2739 /* now blow away any remaining torrent files, such as torrent files in dirty folders */
2740 for( i
=0, n
=tr_ptrArraySize( &torrentFiles
); i
<n
; ++i
) {
2741 char * path
= tr_buildPath( tor
->currentDir
, tr_ptrArrayNth( &torrentFiles
, i
), NULL
);
2742 deleteLocalFile( tor
, path
, fileFunc
);
2746 /* Now clean out the directories left empty from the previous step.
2747 * Work from deepest to shallowest s.t. lower folders
2748 * won't prevent the upper folders from being deleted */
2750 tr_ptrArray cleanFolders
= TR_PTR_ARRAY_INIT
;
2751 s
= (char**) tr_ptrArrayPeek( &folders
, &n
);
2752 for( i
=0; i
<n
; ++i
)
2753 if( tr_ptrArrayFindSorted( &dirtyFolders
, s
[i
], vstrcmp
) == NULL
)
2754 tr_ptrArrayInsertSorted( &cleanFolders
, s
[i
], compareLongestFirst
);
2755 s
= (char**) tr_ptrArrayPeek( &cleanFolders
, &n
);
2756 for( i
=0; i
<n
; ++i
)
2757 deleteLocalFile( tor
, s
[i
], fileFunc
);
2758 tr_ptrArrayDestruct( &cleanFolders
, NULL
);
2762 tr_ptrArrayDestruct( &dirtyFolders
, tr_free
);
2763 tr_ptrArrayDestruct( &folders
, tr_free
);
2764 tr_ptrArrayDestruct( &torrentFiles
, tr_free
);
2770 tr_torrentDeleteLocalData( tr_torrent
* tor
, tr_fileFunc fileFunc
)
2772 assert( tr_isTorrent( tor
) );
2774 if( fileFunc
== NULL
)
2777 /* close all the files because we're about to delete them */
2778 tr_cacheFlushTorrent( tor
->session
->cache
, tor
);
2779 tr_fdTorrentClose( tor
->session
, tor
->uniqueId
);
2781 deleteLocalData( tor
, fileFunc
);
2790 bool move_from_old_location
;
2791 volatile int * setme_state
;
2792 volatile double * setme_progress
;
2798 setLocation( void * vdata
)
2801 struct LocationData
* data
= vdata
;
2802 tr_torrent
* tor
= data
->tor
;
2803 const bool do_move
= data
->move_from_old_location
;
2804 const char * location
= data
->location
;
2805 double bytesHandled
= 0;
2807 assert( tr_isTorrent( tor
) );
2809 tr_dbg( "Moving \"%s\" location from currentDir \"%s\" to \"%s\"",
2810 tr_torrentName(tor
), tor
->currentDir
, location
);
2812 tr_mkdirp( location
, 0777 );
2814 if( !tr_is_same_file( location
, tor
->currentDir
) )
2818 /* bad idea to move files while they're being verified... */
2819 tr_verifyRemove( tor
);
2821 /* try to move the files.
2822 * FIXME: there are still all kinds of nasty cases, like what
2823 * if the target directory runs out of space halfway through... */
2824 for( i
=0; !err
&& i
<tor
->info
.fileCount
; ++i
)
2826 const tr_file
* f
= &tor
->info
.files
[i
];
2827 const char * oldbase
;
2829 if( tr_torrentFindFile2( tor
, i
, &oldbase
, &sub
, NULL
) )
2831 char * oldpath
= tr_buildPath( oldbase
, sub
, NULL
);
2832 char * newpath
= tr_buildPath( location
, sub
, NULL
);
2834 tr_dbg( "Found file #%d: %s", (int)i
, oldpath
);
2836 if( do_move
&& !tr_is_same_file( oldpath
, newpath
) )
2838 bool renamed
= false;
2840 tr_torinf( tor
, "moving \"%s\" to \"%s\"", oldpath
, newpath
);
2841 if( tr_moveFile( oldpath
, newpath
, &renamed
) )
2844 tr_torerr( tor
, "error moving \"%s\" to \"%s\": %s",
2845 oldpath
, newpath
, tr_strerror( errno
) );
2854 if( data
->setme_progress
)
2856 bytesHandled
+= f
->length
;
2857 *data
->setme_progress
= bytesHandled
/ tor
->info
.totalSize
;
2863 /* blow away the leftover subdirectories in the old location */
2865 tr_torrentDeleteLocalData( tor
, remove
);
2867 /* set the new location and reverify */
2868 tr_torrentSetDownloadDir( tor
, location
);
2872 if( !err
&& do_move
)
2874 tr_free( tor
->incompleteDir
);
2875 tor
->incompleteDir
= NULL
;
2876 tor
->currentDir
= tor
->downloadDir
;
2879 if( data
->setme_state
)
2880 *data
->setme_state
= err
? TR_LOC_ERROR
: TR_LOC_DONE
;
2883 tr_free( data
->location
);
2888 tr_torrentSetLocation( tr_torrent
* tor
,
2889 const char * location
,
2890 bool move_from_old_location
,
2891 volatile double * setme_progress
,
2892 volatile int * setme_state
)
2894 struct LocationData
* data
;
2896 assert( tr_isTorrent( tor
) );
2899 *setme_state
= TR_LOC_MOVING
;
2900 if( setme_progress
)
2901 *setme_progress
= 0;
2903 /* run this in the libtransmission thread */
2904 data
= tr_new( struct LocationData
, 1 );
2906 data
->location
= tr_strdup( location
);
2907 data
->move_from_old_location
= move_from_old_location
;
2908 data
->setme_state
= setme_state
;
2909 data
->setme_progress
= setme_progress
;
2910 tr_runInEventThread( tor
->session
, setLocation
, data
);
2918 tr_torrentFileCompleted( tr_torrent
* tor
, tr_file_index_t fileNum
)
2922 const tr_info
* inf
= &tor
->info
;
2923 const tr_file
* f
= &inf
->files
[fileNum
];
2925 const tr_piece
* pend
;
2926 const time_t now
= tr_time( );
2928 /* close the file so that we can reopen in read-only mode as needed */
2929 tr_fdFileClose( tor
->session
, tor
, fileNum
);
2931 /* now that the file is complete and closed, we can start watching its
2932 * mtime timestamp for changes to know if we need to reverify pieces */
2933 for( p
=&inf
->pieces
[f
->firstPiece
], pend
=&inf
->pieces
[f
->lastPiece
]; p
!=pend
; ++p
)
2934 p
->timeChecked
= now
;
2936 /* if the torrent's current filename isn't the same as the one in the
2937 * metadata -- for example, if it had the ".part" suffix appended to
2938 * it until now -- then rename it to match the one in the metadata */
2939 if( tr_torrentFindFile2( tor
, fileNum
, &base
, &sub
, NULL
) )
2941 if( strcmp( sub
, f
->name
) )
2943 char * oldpath
= tr_buildPath( base
, sub
, NULL
);
2944 char * newpath
= tr_buildPath( base
, f
->name
, NULL
);
2946 if( rename( oldpath
, newpath
) )
2947 tr_torerr( tor
, "Error moving \"%s\" to \"%s\": %s", oldpath
, newpath
, tr_strerror( errno
) );
2962 #define TR_STAT_MTIME(sb) ((sb).st_mtimespec.tv_sec)
2964 #define TR_STAT_MTIME(sb) ((sb).st_mtime)
2969 fileExists( const char * filename
, time_t * mtime
)
2972 const bool ok
= !stat( filename
, &sb
);
2974 if( ok
&& ( mtime
!= NULL
) )
2975 *mtime
= TR_STAT_MTIME( sb
);
2981 tr_torrentFindFile2( const tr_torrent
* tor
, tr_file_index_t fileNum
,
2982 const char ** base
, char ** subpath
, time_t * mtime
)
2985 const tr_file
* file
;
2986 const char * b
= NULL
;
2987 const char * s
= NULL
;
2989 assert( tr_isTorrent( tor
) );
2990 assert( fileNum
< tor
->info
.fileCount
);
2992 file
= &tor
->info
.files
[fileNum
];
2995 char * filename
= tr_buildPath( tor
->downloadDir
, file
->name
, NULL
);
2996 if( fileExists( filename
, mtime
) ) {
2997 b
= tor
->downloadDir
;
3000 tr_free( filename
);
3003 if( ( b
== NULL
) && ( tor
->incompleteDir
!= NULL
) ) {
3004 char * filename
= tr_buildPath( tor
->incompleteDir
, file
->name
, NULL
);
3005 if( fileExists( filename
, mtime
) ) {
3006 b
= tor
->incompleteDir
;
3009 tr_free( filename
);
3013 part
= tr_torrentBuildPartial( tor
, fileNum
);
3015 if( ( b
== NULL
) && ( tor
->incompleteDir
!= NULL
) ) {
3016 char * filename
= tr_buildPath( tor
->incompleteDir
, part
, NULL
);
3017 if( fileExists( filename
, mtime
) ) {
3018 b
= tor
->incompleteDir
;
3021 tr_free( filename
);
3025 char * filename
= tr_buildPath( tor
->downloadDir
, part
, NULL
);
3026 if( fileExists( filename
, mtime
) ) {
3027 b
= tor
->downloadDir
;
3030 tr_free( filename
);
3035 if( subpath
!= NULL
)
3036 *subpath
= tr_strdup( s
);
3043 tr_torrentFindFile( const tr_torrent
* tor
, tr_file_index_t fileNum
)
3049 if( tr_torrentFindFile2( tor
, fileNum
, &base
, &subpath
, NULL
) )
3051 ret
= tr_buildPath( base
, subpath
, NULL
);
3058 /* Decide whether we should be looking for files in downloadDir or incompleteDir. */
3060 refreshCurrentDir( tr_torrent
* tor
)
3062 const char * dir
= NULL
;
3064 if( tor
->incompleteDir
== NULL
)
3065 dir
= tor
->downloadDir
;
3066 else if( !tr_torrentHasMetadata( tor
) ) /* no files to find */
3067 dir
= tor
->incompleteDir
;
3068 else if( !tr_torrentFindFile2( tor
, 0, &dir
, NULL
, NULL
) )
3069 dir
= tor
->incompleteDir
;
3071 assert( dir
!= NULL
);
3072 assert( ( dir
== tor
->downloadDir
) || ( dir
== tor
->incompleteDir
) );
3073 tor
->currentDir
= dir
;
3077 tr_torrentBuildPartial( const tr_torrent
* tor
, tr_file_index_t fileNum
)
3079 return tr_strdup_printf( "%s.part", tor
->info
.files
[fileNum
].name
);