2009-01-07 06:53:29 +00:00
/*
2011-01-19 13:48:47 +00:00
* This file Copyright ( C ) Mnemosyne LLC
2007-01-19 08:36:49 +00:00
*
2010-12-27 19:18:17 +00:00
* This file is licensed by the GPL version 2. Works owned by the
2009-01-07 06:53:29 +00:00
* Transmission project are granted a special exemption to clause 2 ( b )
* so that the bulk of its code can remain under the MIT license .
* This exemption does not extend to derived works not owned by
* the Transmission project .
2007-01-19 08:36:49 +00:00
*
2009-01-07 06:53:29 +00:00
* $ Id $
*/
2007-01-19 08:36:49 +00:00
2011-02-28 13:10:56 +00:00
# include <signal.h> /* signal() */
2008-04-14 11:52:50 +00:00
# include <sys/types.h> /* stat */
# include <sys/stat.h> /* stat */
2011-01-30 01:41:48 +00:00
# ifndef WIN32
# include <sys/wait.h> /* wait() */
# else
# include <process.h>
# define waitpid(pid, status, options) _cwait(status, pid, WAIT_CHILD)
# endif
2008-04-14 11:52:50 +00:00
# include <unistd.h> /* stat */
2008-12-23 16:04:11 +00:00
# include <dirent.h>
2008-04-14 11:52:50 +00:00
2007-11-09 20:07:52 +00:00
# include <assert.h>
2010-01-20 23:58:09 +00:00
# include <math.h>
2009-08-13 17:25:26 +00:00
# include <stdarg.h>
2008-02-19 18:39:49 +00:00
# include <string.h> /* memcmp */
2008-05-05 18:54:19 +00:00
# include <stdlib.h> /* qsort */
2011-03-16 18:04:23 +00:00
# include <stdio.h> /* remove() */
2007-07-14 16:29:21 +00:00
2010-12-24 08:58:41 +00:00
# include <event2/util.h> /* evutil_vsnprintf() */
2009-01-12 19:58:16 +00:00
2007-01-19 08:36:49 +00:00
# include "transmission.h"
2009-09-25 21:05:59 +00:00
# include "announcer.h"
2008-11-24 04:21:23 +00:00
# include "bandwidth.h"
2007-12-21 22:18:40 +00:00
# include "bencode.h"
2010-06-19 14:25:11 +00:00
# include "cache.h"
2007-07-30 18:04:10 +00:00
# include "completion.h"
2007-09-20 16:32:01 +00:00
# include "crypto.h" /* for tr_sha1 */
2008-04-13 14:29:11 +00:00
# include "resume.h"
2009-08-03 16:24:44 +00:00
# include "fdlimit.h" /* tr_fdTorrentClose */
2010-12-09 20:43:23 +00:00
# include "inout.h" /* tr_ioTestPiece() */
2009-11-24 02:16:31 +00:00
# include "magnet.h"
2007-07-09 20:10:42 +00:00
# include "metainfo.h"
2010-05-26 15:23:21 +00:00
# include "peer-common.h" /* MAX_BLOCK_SIZE */
2007-09-20 16:32:01 +00:00
# include "peer-mgr.h"
2008-12-23 16:04:11 +00:00
# include "platform.h" /* TR_PATH_DELIMITER_STR */
# include "ptrarray.h"
2009-09-25 21:05:59 +00:00
# include "session.h"
2007-12-25 05:37:32 +00:00
# include "torrent.h"
2009-11-24 17:10:40 +00:00
# include "torrent-magnet.h"
2009-12-10 05:52:46 +00:00
# include "trevent.h" /* tr_runInEventThread() */
2007-07-30 18:04:10 +00:00
# include "utils.h"
2008-02-15 16:00:46 +00:00
# include "verify.h"
2010-05-12 03:03:29 +00:00
# include "version.h"
2007-01-19 08:36:49 +00:00
2007-06-26 18:45:03 +00:00
/***
2007-09-20 16:32:01 +00:00
* * * *
2007-06-26 18:45:03 +00:00
* * */
2011-01-18 02:17:47 +00:00
# define tr_deeplog_tor( tor, ... ) \
do { \
if ( tr_deepLoggingIsActive ( ) ) \
tr_deepLog ( __FILE__ , __LINE__ , tr_torrentName ( tor ) , __VA_ARGS__ ) ; \
} while ( 0 )
/***
* * * *
* * */
2011-02-15 15:18:51 +00:00
const char *
tr_torrentName ( const tr_torrent * tor )
{
assert ( tr_isTorrent ( tor ) ) ;
return tor - > info . name ;
}
2008-05-18 16:44:30 +00:00
int
tr_torrentId ( const tr_torrent * tor )
{
return tor - > uniqueId ;
}
2008-05-12 00:41:55 +00:00
tr_torrent *
2008-12-14 11:21:11 +00:00
tr_torrentFindFromId ( tr_session * session , int id )
2008-05-12 00:41:55 +00:00
{
tr_torrent * tor = NULL ;
2009-03-01 13:56:22 +00:00
while ( ( tor = tr_torrentNext ( session , tor ) ) )
2008-05-12 00:41:55 +00:00
if ( tor - > uniqueId = = id )
return tor ;
return NULL ;
}
tr_torrent *
2008-12-14 11:21:11 +00:00
tr_torrentFindFromHashString ( tr_session * session , const char * str )
2008-05-12 00:41:55 +00:00
{
tr_torrent * tor = NULL ;
2009-03-01 13:56:22 +00:00
while ( ( tor = tr_torrentNext ( session , tor ) ) )
2011-03-13 08:21:55 +00:00
if ( ! evutil_ascii_strcasecmp ( str , tor - > info . hashString ) )
2008-05-12 00:41:55 +00:00
return tor ;
return NULL ;
}
2007-09-20 16:32:01 +00:00
tr_torrent *
2008-12-14 11:21:11 +00:00
tr_torrentFindFromHash ( tr_session * session , const uint8_t * torrentHash )
2007-09-20 16:32:01 +00:00
{
2008-05-10 00:19:00 +00:00
tr_torrent * tor = NULL ;
2007-09-20 16:32:01 +00:00
2009-03-01 13:56:22 +00:00
while ( ( tor = tr_torrentNext ( session , tor ) ) )
2008-11-03 17:01:08 +00:00
if ( * tor - > info . hash = = * torrentHash )
if ( ! memcmp ( tor - > info . hash , torrentHash , SHA_DIGEST_LENGTH ) )
return tor ;
2007-09-20 16:32:01 +00:00
return NULL ;
}
2010-02-02 01:15:26 +00:00
tr_torrent *
tr_torrentFindFromMagnetLink ( tr_session * session , const char * magnet )
{
tr_magnet_info * info ;
tr_torrent * tor = NULL ;
if ( ( info = tr_magnetParse ( magnet ) ) )
{
tor = tr_torrentFindFromHash ( session , info - > hash ) ;
tr_magnetFree ( info ) ;
}
return tor ;
}
2007-09-20 16:32:01 +00:00
tr_torrent *
2008-12-14 11:21:11 +00:00
tr_torrentFindFromObfuscatedHash ( tr_session * session ,
2008-09-23 19:11:04 +00:00
const uint8_t * obfuscatedTorrentHash )
2007-06-26 18:45:03 +00:00
{
2008-05-10 00:19:00 +00:00
tr_torrent * tor = NULL ;
2007-09-20 16:32:01 +00:00
2009-03-01 13:56:22 +00:00
while ( ( tor = tr_torrentNext ( session , tor ) ) )
2008-09-23 19:11:04 +00:00
if ( ! memcmp ( tor - > obfuscatedHash , obfuscatedTorrentHash ,
SHA_DIGEST_LENGTH ) )
2007-09-20 16:32:01 +00:00
return tor ;
return NULL ;
2007-06-26 18:45:03 +00:00
}
2011-03-22 15:19:54 +00:00
bool
2010-07-16 03:12:57 +00:00
tr_torrentIsPieceTransferAllowed ( const tr_torrent * tor ,
tr_direction direction )
{
2012-07-01 02:17:35 +00:00
unsigned int limit ;
2011-03-22 15:19:54 +00:00
bool allowed = true ;
2010-07-16 03:12:57 +00:00
if ( tr_torrentUsesSpeedLimit ( tor , direction ) )
if ( tr_torrentGetSpeedLimit_Bps ( tor , direction ) < = 0 )
2011-03-22 15:19:54 +00:00
allowed = false ;
2010-07-16 03:12:57 +00:00
if ( tr_torrentUsesSessionLimits ( tor ) )
if ( tr_sessionGetActiveSpeedLimit_Bps ( tor - > session , direction , & limit ) )
if ( limit < = 0 )
2011-03-22 15:19:54 +00:00
allowed = false ;
2010-07-16 03:12:57 +00:00
return allowed ;
}
2007-06-26 18:45:03 +00:00
/***
* * * * PER - TORRENT UL / DL SPEEDS
* * */
2007-01-19 08:36:49 +00:00
2007-06-26 18:45:03 +00:00
void
2012-07-01 02:17:35 +00:00
tr_torrentSetSpeedLimit_Bps ( tr_torrent * tor , tr_direction dir , unsigned int Bps )
2007-01-19 08:36:49 +00:00
{
2009-03-04 19:52:57 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-12-21 18:15:00 +00:00
assert ( tr_isDirection ( dir ) ) ;
2008-09-23 19:11:04 +00:00
2011-03-31 14:53:22 +00:00
if ( tr_bandwidthSetDesiredSpeed_Bps ( & tor - > bandwidth , dir , Bps ) )
2009-08-14 14:41:59 +00:00
tr_torrentSetDirty ( tor ) ;
2009-03-04 19:52:57 +00:00
}
2010-07-04 06:07:21 +00:00
void
2012-07-01 02:17:35 +00:00
tr_torrentSetSpeedLimit_KBps ( tr_torrent * tor , tr_direction dir , unsigned int KBps )
2010-07-04 06:07:21 +00:00
{
tr_torrentSetSpeedLimit_Bps ( tor , dir , toSpeedBytes ( KBps ) ) ;
}
2009-03-04 19:52:57 +00:00
2012-07-01 02:17:35 +00:00
unsigned int
2010-07-03 00:25:22 +00:00
tr_torrentGetSpeedLimit_Bps ( const tr_torrent * tor , tr_direction dir )
2009-03-04 19:52:57 +00:00
{
assert ( tr_isTorrent ( tor ) ) ;
assert ( tr_isDirection ( dir ) ) ;
2011-03-31 14:53:22 +00:00
return tr_bandwidthGetDesiredSpeed_Bps ( & tor - > bandwidth , dir ) ;
2009-03-04 19:52:57 +00:00
}
2012-07-01 02:17:35 +00:00
unsigned int
2010-07-04 06:07:21 +00:00
tr_torrentGetSpeedLimit_KBps ( const tr_torrent * tor , tr_direction dir )
{
return toSpeedKBps ( tr_torrentGetSpeedLimit_Bps ( tor , dir ) ) ;
}
2009-03-04 19:52:57 +00:00
void
2011-03-22 15:19:54 +00:00
tr_torrentUseSpeedLimit ( tr_torrent * tor , tr_direction dir , bool do_use )
2009-03-04 19:52:57 +00:00
{
assert ( tr_isTorrent ( tor ) ) ;
assert ( tr_isDirection ( dir ) ) ;
2008-11-25 21:35:17 +00:00
2011-03-31 14:53:22 +00:00
if ( tr_bandwidthSetLimited ( & tor - > bandwidth , dir , do_use ) )
2009-08-14 14:41:59 +00:00
tr_torrentSetDirty ( tor ) ;
2007-02-02 17:33:32 +00:00
}
2007-07-20 03:24:04 +00:00
2011-03-22 15:19:54 +00:00
bool
2009-03-28 16:47:01 +00:00
tr_torrentUsesSpeedLimit ( const tr_torrent * tor , tr_direction dir )
2007-01-19 08:36:49 +00:00
{
2009-03-04 19:52:57 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-12-21 18:15:00 +00:00
assert ( tr_isDirection ( dir ) ) ;
2008-11-25 21:35:17 +00:00
2011-03-31 14:53:22 +00:00
return tr_bandwidthIsLimited ( & tor - > bandwidth , dir ) ;
2007-01-19 08:36:49 +00:00
}
2007-07-20 03:24:04 +00:00
2007-06-26 18:45:03 +00:00
void
2011-03-22 15:19:54 +00:00
tr_torrentUseSessionLimits ( tr_torrent * tor , bool doUse )
2007-07-18 05:27:45 +00:00
{
2011-03-22 15:19:54 +00:00
bool changed ;
2009-08-14 14:41:59 +00:00
2009-03-04 19:52:57 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2011-03-31 14:53:22 +00:00
changed = tr_bandwidthHonorParentLimits ( & tor - > bandwidth , TR_UP , doUse ) ;
changed | = tr_bandwidthHonorParentLimits ( & tor - > bandwidth , TR_DOWN , doUse ) ;
2009-08-07 05:29:37 +00:00
2009-08-14 14:41:59 +00:00
if ( changed )
tr_torrentSetDirty ( tor ) ;
2007-07-18 05:27:45 +00:00
}
2007-07-20 03:24:04 +00:00
2011-03-22 15:19:54 +00:00
bool
2009-03-28 16:47:01 +00:00
tr_torrentUsesSessionLimits ( const tr_torrent * tor )
2007-01-19 08:36:49 +00:00
{
2009-02-13 18:23:56 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2011-03-31 14:53:22 +00:00
return tr_bandwidthAreParentLimitsHonored ( & tor - > bandwidth , TR_UP ) ;
2007-01-19 08:36:49 +00:00
}
2009-03-04 19:52:57 +00:00
/***
* * * *
* * */
2009-02-13 18:23:56 +00:00
void
2009-03-01 13:56:22 +00:00
tr_torrentSetRatioMode ( tr_torrent * tor , tr_ratiolimit mode )
2009-02-13 18:23:56 +00:00
{
assert ( tr_isTorrent ( tor ) ) ;
assert ( mode = = TR_RATIOLIMIT_GLOBAL | | mode = = TR_RATIOLIMIT_SINGLE | | mode = = TR_RATIOLIMIT_UNLIMITED ) ;
2009-08-14 14:41:59 +00:00
if ( mode ! = tor - > ratioLimitMode )
{
tor - > ratioLimitMode = mode ;
2009-08-07 05:29:37 +00:00
2009-08-14 14:41:59 +00:00
tr_torrentSetDirty ( tor ) ;
}
2009-02-13 18:23:56 +00:00
}
tr_ratiolimit
tr_torrentGetRatioMode ( const tr_torrent * tor )
{
assert ( tr_isTorrent ( tor ) ) ;
return tor - > ratioLimitMode ;
}
void
2009-04-09 14:10:31 +00:00
tr_torrentSetRatioLimit ( tr_torrent * tor , double desiredRatio )
2009-02-13 18:23:56 +00:00
{
assert ( tr_isTorrent ( tor ) ) ;
2009-08-14 14:41:59 +00:00
if ( ( int ) ( desiredRatio * 100.0 ) ! = ( int ) ( tor - > desiredRatio * 100.0 ) )
{
tor - > desiredRatio = desiredRatio ;
2009-03-01 13:56:22 +00:00
2009-08-14 14:41:59 +00:00
tr_torrentSetDirty ( tor ) ;
}
2009-02-13 18:23:56 +00:00
}
double
tr_torrentGetRatioLimit ( const tr_torrent * tor )
{
assert ( tr_isTorrent ( tor ) ) ;
return tor - > desiredRatio ;
}
2011-03-22 15:19:54 +00:00
bool
2009-02-13 18:23:56 +00:00
tr_torrentGetSeedRatio ( const tr_torrent * tor , double * ratio )
{
2011-03-22 15:19:54 +00:00
bool isLimited ;
2009-02-13 18:23:56 +00:00
switch ( tr_torrentGetRatioMode ( tor ) )
{
case TR_RATIOLIMIT_SINGLE :
2011-03-22 15:19:54 +00:00
isLimited = true ;
2009-02-14 21:15:57 +00:00
if ( ratio )
* ratio = tr_torrentGetRatioLimit ( tor ) ;
2009-02-13 18:23:56 +00:00
break ;
case TR_RATIOLIMIT_GLOBAL :
2009-02-17 04:00:53 +00:00
isLimited = tr_sessionIsRatioLimited ( tor - > session ) ;
if ( isLimited & & ratio )
* ratio = tr_sessionGetRatioLimit ( tor - > session ) ;
2009-02-13 18:23:56 +00:00
break ;
2009-05-13 15:54:04 +00:00
default : /* TR_RATIOLIMIT_UNLIMITED */
2011-03-22 15:19:54 +00:00
isLimited = false ;
2009-02-13 18:23:56 +00:00
break ;
}
return isLimited ;
}
2010-04-14 00:03:23 +00:00
/* returns true if the seed ratio applies --
* it applies if the torrent ' s a seed AND it has a seed ratio set */
2011-03-22 15:19:54 +00:00
static bool
2010-04-14 00:34:31 +00:00
tr_torrentGetSeedRatioBytes ( tr_torrent * tor ,
uint64_t * setmeLeft ,
uint64_t * setmeGoal )
2010-04-14 00:03:23 +00:00
{
double seedRatio ;
2011-03-22 15:19:54 +00:00
bool seedRatioApplies = false ;
2010-04-14 00:03:23 +00:00
if ( tr_torrentGetSeedRatio ( tor , & seedRatio ) )
{
2010-04-14 00:34:31 +00:00
const uint64_t u = tor - > uploadedCur + tor - > uploadedPrev ;
const uint64_t d = tor - > downloadedCur + tor - > downloadedPrev ;
const uint64_t baseline = d ? d : tr_cpSizeWhenDone ( & tor - > completion ) ;
const uint64_t goal = baseline * seedRatio ;
if ( setmeLeft ) * setmeLeft = goal > u ? goal - u : 0 ;
2010-04-14 00:03:23 +00:00
if ( setmeGoal ) * setmeGoal = goal ;
seedRatioApplies = tr_torrentIsSeed ( tor ) ;
}
return seedRatioApplies ;
}
2011-03-22 15:19:54 +00:00
static bool
2010-04-14 00:03:23 +00:00
tr_torrentIsSeedRatioDone ( tr_torrent * tor )
{
uint64_t bytesLeft ;
return tr_torrentGetSeedRatioBytes ( tor , & bytesLeft , NULL ) & & ! bytesLeft ;
}
2010-07-16 03:12:57 +00:00
/***
* * * *
* * */
void
2010-07-24 02:57:39 +00:00
tr_torrentSetIdleMode ( tr_torrent * tor , tr_idlelimit mode )
2010-07-16 03:12:57 +00:00
{
assert ( tr_isTorrent ( tor ) ) ;
2010-07-24 02:57:39 +00:00
assert ( mode = = TR_IDLELIMIT_GLOBAL | | mode = = TR_IDLELIMIT_SINGLE | | mode = = TR_IDLELIMIT_UNLIMITED ) ;
2010-07-16 03:12:57 +00:00
2010-07-24 02:57:39 +00:00
if ( mode ! = tor - > idleLimitMode )
2010-07-16 03:12:57 +00:00
{
2010-07-24 02:57:39 +00:00
tor - > idleLimitMode = mode ;
2010-07-16 03:12:57 +00:00
tr_torrentSetDirty ( tor ) ;
}
}
2010-07-24 02:57:39 +00:00
tr_idlelimit
tr_torrentGetIdleMode ( const tr_torrent * tor )
2010-07-16 03:12:57 +00:00
{
assert ( tr_isTorrent ( tor ) ) ;
2010-07-24 02:57:39 +00:00
return tor - > idleLimitMode ;
2010-07-16 03:12:57 +00:00
}
void
2010-07-24 02:57:39 +00:00
tr_torrentSetIdleLimit ( tr_torrent * tor , uint16_t idleMinutes )
2010-07-16 03:12:57 +00:00
{
assert ( tr_isTorrent ( tor ) ) ;
2010-07-24 02:57:39 +00:00
if ( idleMinutes > 0 )
2010-07-16 03:12:57 +00:00
{
2010-07-24 02:57:39 +00:00
tor - > idleLimitMinutes = idleMinutes ;
2010-07-16 03:12:57 +00:00
tr_torrentSetDirty ( tor ) ;
}
}
2010-07-24 02:57:39 +00:00
uint16_t
tr_torrentGetIdleLimit ( const tr_torrent * tor )
2010-07-16 03:12:57 +00:00
{
assert ( tr_isTorrent ( tor ) ) ;
2010-07-24 02:57:39 +00:00
return tor - > idleLimitMinutes ;
2010-07-16 03:12:57 +00:00
}
2011-03-22 15:19:54 +00:00
bool
2010-07-24 02:57:39 +00:00
tr_torrentGetSeedIdle ( const tr_torrent * tor , uint16_t * idleMinutes )
2010-07-16 03:12:57 +00:00
{
2011-03-22 15:19:54 +00:00
bool isLimited ;
2010-07-16 03:12:57 +00:00
2010-07-24 02:57:39 +00:00
switch ( tr_torrentGetIdleMode ( tor ) )
2010-07-16 03:12:57 +00:00
{
2010-07-24 02:57:39 +00:00
case TR_IDLELIMIT_SINGLE :
2011-03-22 15:19:54 +00:00
isLimited = true ;
2010-07-24 02:57:39 +00:00
if ( idleMinutes )
* idleMinutes = tr_torrentGetIdleLimit ( tor ) ;
2010-07-16 03:12:57 +00:00
break ;
2010-07-24 02:57:39 +00:00
case TR_IDLELIMIT_GLOBAL :
isLimited = tr_sessionIsIdleLimited ( tor - > session ) ;
if ( isLimited & & idleMinutes )
* idleMinutes = tr_sessionGetIdleLimit ( tor - > session ) ;
2010-07-16 03:12:57 +00:00
break ;
2010-07-24 02:57:39 +00:00
default : /* TR_IDLELIMIT_UNLIMITED */
2011-03-22 15:19:54 +00:00
isLimited = false ;
2010-07-16 03:12:57 +00:00
break ;
}
return isLimited ;
}
2011-03-22 15:19:54 +00:00
static bool
2010-07-24 02:57:39 +00:00
tr_torrentIsSeedIdleLimitDone ( tr_torrent * tor )
2010-07-16 03:12:57 +00:00
{
2010-07-24 02:57:39 +00:00
uint16_t idleMinutes ;
return tr_torrentGetSeedIdle ( tor , & idleMinutes )
& & difftime ( tr_time ( ) , MAX ( tor - > startDate , tor - > activityDate ) ) > = idleMinutes * 60u ;
2010-07-16 03:12:57 +00:00
}
/***
* * * *
* * */
2010-04-14 00:03:23 +00:00
void
2010-07-16 03:12:57 +00:00
tr_torrentCheckSeedLimit ( tr_torrent * tor )
2010-04-14 00:03:23 +00:00
{
assert ( tr_isTorrent ( tor ) ) ;
2010-08-19 22:14:59 +00:00
if ( ! tor - > isRunning | | ! tr_torrentIsSeed ( tor ) )
2010-07-16 03:12:57 +00:00
return ;
2010-04-15 13:43:54 +00:00
/* if we're seeding and reach our seed ratio limit, stop the torrent */
2010-07-16 03:12:57 +00:00
if ( tr_torrentIsSeedRatioDone ( tor ) )
2010-04-14 00:03:23 +00:00
{
2010-04-14 13:36:43 +00:00
tr_torinf ( tor , " Seed ratio reached; pausing torrent " ) ;
2011-03-22 15:19:54 +00:00
tor - > isStopping = true ;
2010-04-14 00:03:23 +00:00
/* maybe notify the client */
if ( tor - > ratio_limit_hit_func ! = NULL )
tor - > ratio_limit_hit_func ( tor , tor - > ratio_limit_hit_func_user_data ) ;
}
2010-07-16 03:12:57 +00:00
/* if we're seeding and reach our inactiviy limit, stop the torrent */
2010-07-24 02:57:39 +00:00
else if ( tr_torrentIsSeedIdleLimitDone ( tor ) )
2010-07-16 03:12:57 +00:00
{
2010-07-24 03:19:41 +00:00
tr_torinf ( tor , " Seeding idle limit reached; pausing torrent " ) ;
2010-04-14 00:03:23 +00:00
2011-03-22 15:19:54 +00:00
tor - > isStopping = true ;
tor - > finishedSeedingByIdle = true ;
2010-07-16 03:12:57 +00:00
/* maybe notify the client */
2010-07-24 02:57:39 +00:00
if ( tor - > idle_limit_hit_func ! = NULL )
tor - > idle_limit_hit_func ( tor , tor - > idle_limit_hit_func_user_data ) ;
2010-07-16 03:12:57 +00:00
}
}
2010-04-14 00:03:23 +00:00
2007-08-16 20:00:06 +00:00
/***
* * * *
* * */
2009-08-13 17:25:26 +00:00
void
tr_torrentSetLocalError ( tr_torrent * tor , const char * fmt , . . . )
{
va_list ap ;
assert ( tr_isTorrent ( tor ) ) ;
va_start ( ap , fmt ) ;
tor - > error = TR_STAT_LOCAL_ERROR ;
2010-05-19 19:02:25 +00:00
tor - > errorTracker [ 0 ] = ' \0 ' ;
2009-08-13 17:25:26 +00:00
evutil_vsnprintf ( tor - > errorString , sizeof ( tor - > errorString ) , fmt , ap ) ;
va_end ( ap ) ;
2010-06-25 06:57:34 +00:00
2010-12-09 20:43:23 +00:00
tr_torerr ( tor , " %s " , tor - > errorString ) ;
2010-06-25 06:57:34 +00:00
if ( tor - > isRunning )
2011-03-22 15:19:54 +00:00
tor - > isStopping = true ;
2009-08-13 17:25:26 +00:00
}
2010-05-19 19:02:25 +00:00
static void
tr_torrentClearError ( tr_torrent * tor )
{
tor - > error = TR_STAT_OK ;
tor - > errorString [ 0 ] = ' \0 ' ;
tor - > errorTracker [ 0 ] = ' \0 ' ;
}
2007-08-16 20:00:06 +00:00
static void
2010-06-19 14:33:10 +00:00
onTrackerResponse ( tr_torrent * tor , const tr_tracker_event * event , void * unused UNUSED )
2007-08-16 20:00:06 +00:00
{
switch ( event - > messageType )
{
2008-09-23 19:11:04 +00:00
case TR_TRACKER_PEERS :
{
2011-01-22 17:45:54 +00:00
size_t i ;
2010-06-30 16:40:19 +00:00
const int8_t seedProbability = event - > seedProbability ;
2011-03-22 15:19:54 +00:00
const bool allAreSeeds = seedProbability = = 100 ;
2011-01-22 17:45:54 +00:00
2010-04-20 21:54:03 +00:00
if ( allAreSeeds )
2011-01-22 17:45:54 +00:00
tr_tordbg ( tor , " Got %zu seeds from tracker " , event - > pexCount ) ;
2008-04-19 15:07:59 +00:00
else
2011-01-22 17:45:54 +00:00
tr_tordbg ( tor , " Got %zu peers from tracker " , event - > pexCount ) ;
2008-04-19 15:07:59 +00:00
2011-01-22 17:45:54 +00:00
for ( i = 0 ; i < event - > pexCount ; + + i )
tr_peerMgrAddPex ( tor , TR_PEER_FROM_TRACKER , & event - > pex [ i ] , seedProbability ) ;
2010-04-20 21:54:03 +00:00
2007-08-16 20:00:06 +00:00
break ;
2008-04-19 15:07:59 +00:00
}
2007-08-16 20:00:06 +00:00
case TR_TRACKER_WARNING :
2008-03-19 20:07:27 +00:00
tr_torerr ( tor , _ ( " Tracker warning: \" %s \" " ) , event - > text ) ;
2009-08-05 01:25:36 +00:00
tor - > error = TR_STAT_TRACKER_WARNING ;
2010-05-19 19:02:25 +00:00
tr_strlcpy ( tor - > errorTracker , event - > tracker , sizeof ( tor - > errorTracker ) ) ;
2009-08-05 01:25:36 +00:00
tr_strlcpy ( tor - > errorString , event - > text , sizeof ( tor - > errorString ) ) ;
2007-08-16 20:00:06 +00:00
break ;
case TR_TRACKER_ERROR :
2008-03-19 20:07:27 +00:00
tr_torerr ( tor , _ ( " Tracker error: \" %s \" " ) , event - > text ) ;
2009-08-05 01:25:36 +00:00
tor - > error = TR_STAT_TRACKER_ERROR ;
2010-05-19 19:02:25 +00:00
tr_strlcpy ( tor - > errorTracker , event - > tracker , sizeof ( tor - > errorTracker ) ) ;
2009-08-05 01:25:36 +00:00
tr_strlcpy ( tor - > errorString , event - > text , sizeof ( tor - > errorString ) ) ;
2007-08-16 20:00:06 +00:00
break ;
2007-09-25 18:39:58 +00:00
case TR_TRACKER_ERROR_CLEAR :
2010-01-20 20:08:12 +00:00
if ( tor - > error ! = TR_STAT_LOCAL_ERROR )
2010-05-19 19:02:25 +00:00
tr_torrentClearError ( tor ) ;
2007-09-25 18:39:58 +00:00
break ;
2007-08-16 20:00:06 +00:00
}
}
2007-06-26 18:45:03 +00:00
/***
* * * *
* * * * TORRENT INSTANTIATION
* * * *
* * */
2007-04-02 20:38:23 +00:00
2010-06-30 16:40:19 +00:00
static tr_piece_index_t
getBytePiece ( const tr_info * info , uint64_t byteOffset )
2007-06-26 18:45:03 +00:00
{
2012-10-20 15:57:56 +00:00
tr_piece_index_t piece ;
2008-08-01 16:43:22 +00:00
assert ( info ) ;
2007-06-26 18:45:03 +00:00
assert ( info - > pieceSize ! = 0 ) ;
2007-04-02 20:38:23 +00:00
2012-10-20 15:57:56 +00:00
piece = byteOffset / info - > pieceSize ;
/* handle 0-byte files at the end of a torrent */
if ( byteOffset = = info - > totalSize )
piece = info - > pieceCount - 1 ;
return piece ;
2007-04-02 20:38:23 +00:00
}
2007-06-26 18:45:03 +00:00
static void
2008-09-23 19:11:04 +00:00
initFilePieces ( tr_info * info ,
tr_file_index_t fileIndex )
2007-04-02 20:38:23 +00:00
{
2008-07-17 20:33:34 +00:00
tr_file * file ;
2008-09-23 19:11:04 +00:00
uint64_t firstByte , lastByte ;
2007-04-02 20:38:23 +00:00
2008-08-01 16:43:22 +00:00
assert ( info ) ;
2008-03-22 18:10:59 +00:00
assert ( fileIndex < info - > fileCount ) ;
2007-01-19 08:36:49 +00:00
2007-06-26 18:45:03 +00:00
file = & info - > files [ fileIndex ] ;
firstByte = file - > offset ;
2008-09-23 19:11:04 +00:00
lastByte = firstByte + ( file - > length ? file - > length - 1 : 0 ) ;
2007-06-26 18:45:03 +00:00
file - > firstPiece = getBytePiece ( info , firstByte ) ;
file - > lastPiece = getBytePiece ( info , lastByte ) ;
}
2007-12-25 06:37:21 +00:00
static int
2008-09-23 19:11:04 +00:00
pieceHasFile ( tr_piece_index_t piece ,
const tr_file * file )
2007-12-25 06:37:21 +00:00
{
return ( file - > firstPiece < = piece ) & & ( piece < = file - > lastPiece ) ;
}
2007-06-26 18:45:03 +00:00
static tr_priority_t
2008-09-23 19:11:04 +00:00
calculatePiecePriority ( const tr_torrent * tor ,
tr_piece_index_t piece ,
int fileHint )
2007-06-26 18:45:03 +00:00
{
2008-03-22 18:10:59 +00:00
tr_file_index_t i ;
2010-06-30 16:40:19 +00:00
tr_priority_t priority = TR_PRI_LOW ;
2007-06-26 18:45:03 +00:00
2008-01-02 20:37:22 +00:00
/* find the first file that has data in this piece */
2009-04-11 06:58:14 +00:00
if ( fileHint > = 0 ) {
2008-01-02 20:37:22 +00:00
i = fileHint ;
2008-09-23 19:11:04 +00:00
while ( i > 0 & & pieceHasFile ( piece , & tor - > info . files [ i - 1 ] ) )
2008-01-02 20:37:22 +00:00
- - i ;
2009-04-11 06:58:14 +00:00
} else {
2008-09-23 19:11:04 +00:00
for ( i = 0 ; i < tor - > info . fileCount ; + + i )
2008-01-02 20:37:22 +00:00
if ( pieceHasFile ( piece , & tor - > info . files [ i ] ) )
break ;
}
2007-12-25 05:42:33 +00:00
/* the piece's priority is the max of the priorities
* of all the files in that piece */
2008-09-23 19:11:04 +00:00
for ( ; i < tor - > info . fileCount ; + + i )
2007-01-19 08:36:49 +00:00
{
2007-09-20 16:32:01 +00:00
const tr_file * file = & tor - > info . files [ i ] ;
2007-12-25 05:42:33 +00:00
2007-12-25 06:37:21 +00:00
if ( ! pieceHasFile ( piece , file ) )
2008-01-02 20:37:22 +00:00
break ;
2007-12-25 05:42:33 +00:00
priority = MAX ( priority , file - > priority ) ;
2007-08-08 15:07:06 +00:00
/* when dealing with multimedia files, getting the first and
last pieces can sometimes allow you to preview it a bit
before it ' s fully downloaded . . . */
2008-09-23 19:11:04 +00:00
if ( file - > priority > = TR_PRI_NORMAL )
if ( file - > firstPiece = = piece | | file - > lastPiece = = piece )
2007-08-08 15:07:06 +00:00
priority = TR_PRI_HIGH ;
2007-01-19 08:36:49 +00:00
}
2007-06-26 18:45:03 +00:00
return priority ;
2007-01-19 08:36:49 +00:00
}
2007-06-27 05:14:38 +00:00
static void
2007-09-20 16:32:01 +00:00
tr_torrentInitFilePieces ( tr_torrent * tor )
2007-01-19 08:36:49 +00:00
{
2010-12-09 20:43:23 +00:00
int * firstFiles ;
tr_file_index_t f ;
2009-04-11 06:58:14 +00:00
tr_piece_index_t p ;
uint64_t offset = 0 ;
tr_info * inf = & tor - > info ;
/* assign the file offsets */
for ( f = 0 ; f < inf - > fileCount ; + + f ) {
inf - > files [ f ] . offset = offset ;
offset + = inf - > files [ f ] . length ;
initFilePieces ( inf , f ) ;
}
2007-04-02 20:38:23 +00:00
2009-04-11 06:58:14 +00:00
/* build the array of first-file hints to give calculatePiecePriority */
firstFiles = tr_new ( int , inf - > pieceCount ) ;
for ( p = f = 0 ; p < inf - > pieceCount ; + + p ) {
2009-04-11 15:48:58 +00:00
while ( inf - > files [ f ] . lastPiece < p )
2009-04-11 06:58:14 +00:00
+ + f ;
firstFiles [ p ] = f ;
}
2007-01-19 08:36:49 +00:00
2009-04-11 06:58:14 +00:00
#if 0
/* test to confirm the first-file hints are correct */
for ( p = 0 ; p < inf - > pieceCount ; + + p ) {
f = firstFiles [ p ] ;
assert ( inf - > files [ f ] . firstPiece < = p ) ;
assert ( inf - > files [ f ] . lastPiece > = p ) ;
if ( f > 0 )
assert ( inf - > files [ f - 1 ] . lastPiece < p ) ;
2009-04-11 15:48:58 +00:00
for ( f = 0 ; f < inf - > fileCount ; + + f )
if ( pieceHasFile ( p , & inf - > files [ f ] ) )
break ;
assert ( ( int ) f = = firstFiles [ p ] ) ;
2007-01-19 08:36:49 +00:00
}
2009-04-11 06:58:14 +00:00
# endif
for ( p = 0 ; p < inf - > pieceCount ; + + p )
inf - > pieces [ p ] . priority = calculatePiecePriority ( tor , p , firstFiles [ p ] ) ;
2007-01-19 08:36:49 +00:00
2009-04-11 06:58:14 +00:00
tr_free ( firstFiles ) ;
2007-01-19 08:36:49 +00:00
}
2011-08-01 22:24:24 +00:00
static void torrentStart ( tr_torrent * tor , bool bypass_queue ) ;
2008-05-06 01:43:24 +00:00
2008-08-05 20:27:40 +00:00
/**
2010-12-27 19:18:17 +00:00
* Decide on a block size . Constraints :
2008-08-05 20:27:40 +00:00
* ( 1 ) most clients decline requests over 16 KiB
* ( 2 ) pieceSize must be a multiple of block size
*/
2010-06-24 20:36:05 +00:00
uint32_t
tr_getBlockSize ( uint32_t pieceSize )
2008-08-05 20:27:40 +00:00
{
uint32_t b = pieceSize ;
2008-09-23 19:11:04 +00:00
2008-08-05 20:27:40 +00:00
while ( b > MAX_BLOCK_SIZE )
b / = 2u ;
2008-09-23 19:11:04 +00:00
2008-08-06 11:39:30 +00:00
if ( ! b | | ( pieceSize % b ) ) /* not cleanly divisible */
2008-08-05 20:27:40 +00:00
return 0 ;
return b ;
}
2009-11-24 02:16:31 +00:00
static void refreshCurrentDir ( tr_torrent * tor ) ;
2009-10-19 05:05:00 +00:00
2007-06-27 05:14:38 +00:00
static void
2009-11-24 02:16:31 +00:00
torrentInitFromInfo ( tr_torrent * tor )
2007-01-19 08:36:49 +00:00
{
2009-11-24 02:16:31 +00:00
uint64_t t ;
tr_info * info = & tor - > info ;
2008-11-25 21:35:17 +00:00
2010-06-24 20:36:05 +00:00
tor - > blockSize = tr_getBlockSize ( info - > pieceSize ) ;
2007-07-28 15:43:34 +00:00
2009-11-24 02:16:31 +00:00
if ( info - > pieceSize )
2010-06-30 16:40:19 +00:00
tor - > lastPieceSize = ( uint32_t ) ( info - > totalSize % info - > pieceSize ) ;
2007-07-28 15:43:34 +00:00
2007-07-28 16:31:08 +00:00
if ( ! tor - > lastPieceSize )
2008-09-23 19:11:04 +00:00
tor - > lastPieceSize = info - > pieceSize ;
2007-07-28 16:31:08 +00:00
2009-11-24 02:16:31 +00:00
if ( tor - > blockSize )
tor - > lastBlockSize = info - > totalSize % tor - > blockSize ;
2007-07-28 15:43:34 +00:00
2007-07-28 16:31:08 +00:00
if ( ! tor - > lastBlockSize )
2008-09-23 19:11:04 +00:00
tor - > lastBlockSize = tor - > blockSize ;
2007-07-28 16:31:08 +00:00
2009-11-24 02:16:31 +00:00
tor - > blockCount = tor - > blockSize
? ( info - > totalSize + tor - > blockSize - 1 ) / tor - > blockSize
: 0 ;
2007-07-28 15:43:34 +00:00
2009-11-24 02:16:31 +00:00
tor - > blockCountInPiece = tor - > blockSize
? info - > pieceSize / tor - > blockSize
: 0 ;
2007-07-28 15:43:34 +00:00
2009-11-24 02:16:31 +00:00
tor - > blockCountInLastPiece = tor - > blockSize
? ( tor - > lastPieceSize + tor - > blockSize - 1 ) / tor - > blockSize
: 0 ;
2007-07-28 15:43:34 +00:00
/* check our work */
2009-11-24 02:16:31 +00:00
if ( tor - > blockSize ! = 0 )
assert ( ( info - > pieceSize % tor - > blockSize ) = = 0 ) ;
2007-07-28 15:43:34 +00:00
t = info - > pieceCount - 1 ;
t * = info - > pieceSize ;
t + = tor - > lastPieceSize ;
assert ( t = = info - > totalSize ) ;
t = tor - > blockCount - 1 ;
t * = tor - > blockSize ;
t + = tor - > lastBlockSize ;
assert ( t = = info - > totalSize ) ;
t = info - > pieceCount - 1 ;
t * = tor - > blockCountInPiece ;
t + = tor - > blockCountInLastPiece ;
assert ( t = = ( uint64_t ) tor - > blockCount ) ;
2009-01-02 17:01:55 +00:00
tr_cpConstruct ( & tor - > completion , tor ) ;
2007-01-19 08:36:49 +00:00
2007-07-25 01:59:46 +00:00
tr_torrentInitFilePieces ( tor ) ;
2009-11-24 02:16:31 +00:00
tor - > completeness = tr_cpGetStatus ( & tor - > completion ) ;
}
2009-11-26 17:58:44 +00:00
static void tr_torrentFireMetadataCompleted ( tr_torrent * tor ) ;
2009-11-24 02:16:31 +00:00
void
tr_torrentGotNewInfoDict ( tr_torrent * tor )
{
torrentInitFromInfo ( tor ) ;
2009-11-26 17:58:44 +00:00
2011-02-24 14:35:45 +00:00
tr_peerMgrOnTorrentGotMetainfo ( tor ) ;
2009-11-26 17:58:44 +00:00
tr_torrentFireMetadataCompleted ( tor ) ;
2009-11-24 02:16:31 +00:00
}
2011-03-22 15:19:54 +00:00
static bool
2010-12-17 14:57:19 +00:00
hasAnyLocalData ( const tr_torrent * tor )
{
tr_file_index_t i ;
2011-04-01 04:33:35 +00:00
for ( i = 0 ; i < tor - > info . fileCount ; + + i )
2011-04-02 07:36:34 +00:00
if ( tr_torrentFindFile2 ( tor , i , NULL , NULL , NULL ) )
2011-04-01 04:33:35 +00:00
return true ;
2010-12-17 14:57:19 +00:00
2011-04-01 04:33:35 +00:00
return false ;
2010-12-17 14:57:19 +00:00
}
2011-03-22 15:19:54 +00:00
static bool
2010-12-09 20:43:23 +00:00
setLocalErrorIfFilesDisappeared ( tr_torrent * tor )
{
2011-03-22 15:19:54 +00:00
const bool disappeared = ( tr_cpHaveTotal ( & tor - > completion ) > 0 ) & & ! hasAnyLocalData ( tor ) ;
2010-12-09 20:43:23 +00:00
if ( disappeared )
{
2011-01-18 02:17:47 +00:00
tr_deeplog_tor ( tor , " %s " , " [LAZY] uh oh, the files disappeared " ) ;
2010-12-30 18:35:18 +00:00
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. " ) ) ;
2010-12-09 20:43:23 +00:00
}
return disappeared ;
}
2009-11-24 02:16:31 +00:00
static void
torrentInit ( tr_torrent * tor , const tr_ctor * ctor )
{
int doStart ;
uint64_t loaded ;
const char * dir ;
2011-03-22 15:19:54 +00:00
bool isNewTorrent ;
2010-12-09 20:43:23 +00:00
struct stat st ;
2009-11-24 02:16:31 +00:00
static int nextUniqueId = 1 ;
tr_session * session = tr_ctorGetSession ( ctor ) ;
assert ( session ! = NULL ) ;
2010-01-04 09:05:02 +00:00
tr_sessionLock ( session ) ;
2009-11-24 02:16:31 +00:00
tor - > session = session ;
tor - > uniqueId = nextUniqueId + + ;
tor - > magicNumber = TORRENT_MAGIC_NUMBER ;
2011-08-02 03:59:54 +00:00
tor - > queuePosition = session - > torrentCount ;
2009-11-24 02:16:31 +00:00
2011-03-11 15:00:10 +00:00
tr_peerIdInit ( tor - > peer_id ) ;
2007-09-20 16:32:01 +00:00
tr_sha1 ( tor - > obfuscatedHash , " req2 " , 4 ,
2009-11-24 02:16:31 +00:00
tor - > info . hash , SHA_DIGEST_LENGTH ,
2008-09-23 19:11:04 +00:00
NULL ) ;
2007-01-19 08:36:49 +00:00
2009-11-24 02:16:31 +00:00
if ( ! tr_ctorGetDownloadDir ( ctor , TR_FORCE , & dir ) | |
! tr_ctorGetDownloadDir ( ctor , TR_FALLBACK , & dir ) )
tor - > downloadDir = tr_strdup ( dir ) ;
if ( tr_ctorGetIncompleteDir ( ctor , & dir ) )
dir = tr_sessionGetIncompleteDir ( session ) ;
if ( tr_sessionIsIncompleteDirEnabled ( session ) )
tor - > incompleteDir = tr_strdup ( dir ) ;
2011-03-31 14:53:22 +00:00
tr_bandwidthConstruct ( & tor - > bandwidth , session , & session - > bandwidth ) ;
2009-11-24 02:16:31 +00:00
2011-03-31 14:53:22 +00:00
tor - > bandwidth . priority = tr_ctorGetBandwidthPriority ( ctor ) ;
2010-02-02 07:48:03 +00:00
2009-11-24 02:16:31 +00:00
tor - > error = TR_STAT_OK ;
2010-09-12 19:49:06 +00:00
2011-03-22 15:19:54 +00:00
tor - > finishedSeedingByIdle = false ;
2009-11-24 02:16:31 +00:00
2008-12-14 11:21:11 +00:00
tr_peerMgrAddTorrent ( session - > peerMgr , tor ) ;
2007-01-19 08:36:49 +00:00
2007-07-09 23:09:00 +00:00
assert ( ! tor - > downloadedCur ) ;
assert ( ! tor - > uploadedCur ) ;
2007-06-18 03:40:41 +00:00
2009-11-26 18:47:08 +00:00
tr_torrentSetAddedDate ( tor , tr_time ( ) ) ; /* this is a default value to be
overwritten by the resume file */
2009-04-02 22:59:30 +00:00
2009-11-25 05:10:27 +00:00
torrentInitFromInfo ( tor ) ;
2008-04-13 14:29:11 +00:00
loaded = tr_torrentLoadResume ( tor , ~ 0 , ctor ) ;
2009-11-25 05:10:27 +00:00
tor - > completeness = tr_cpGetStatus ( & tor - > completion ) ;
2010-12-09 20:43:23 +00:00
setLocalErrorIfFilesDisappeared ( tor ) ;
2008-09-23 19:11:04 +00:00
2010-04-19 23:10:30 +00:00
tr_ctorInitTorrentPriorities ( ctor , tor ) ;
tr_ctorInitTorrentWanted ( ctor , tor ) ;
2009-10-19 05:05:00 +00:00
refreshCurrentDir ( tor ) ;
2007-12-21 22:18:40 +00:00
doStart = tor - > isRunning ;
2007-10-04 19:58:30 +00:00
tor - > isRunning = 0 ;
2007-08-13 16:43:33 +00:00
2008-09-23 19:11:04 +00:00
if ( ! ( loaded & TR_FR_SPEEDLIMIT ) )
{
2011-03-22 15:19:54 +00:00
tr_torrentUseSpeedLimit ( tor , TR_UP , false ) ;
2010-07-03 00:25:22 +00:00
tr_torrentSetSpeedLimit_Bps ( tor , TR_UP , tr_sessionGetSpeedLimit_Bps ( tor - > session , TR_UP ) ) ;
2011-03-22 15:19:54 +00:00
tr_torrentUseSpeedLimit ( tor , TR_DOWN , false ) ;
2010-07-03 00:25:22 +00:00
tr_torrentSetSpeedLimit_Bps ( tor , TR_DOWN , tr_sessionGetSpeedLimit_Bps ( tor - > session , TR_DOWN ) ) ;
2011-03-22 15:19:54 +00:00
tr_torrentUseSessionLimits ( tor , true ) ;
2009-02-13 18:23:56 +00:00
}
if ( ! ( loaded & TR_FR_RATIOLIMIT ) )
{
2009-02-17 01:42:10 +00:00
tr_torrentSetRatioMode ( tor , TR_RATIOLIMIT_GLOBAL ) ;
2009-02-13 18:23:56 +00:00
tr_torrentSetRatioLimit ( tor , tr_sessionGetRatioLimit ( tor - > session ) ) ;
2007-07-23 03:00:20 +00:00
}
2010-07-24 02:57:39 +00:00
if ( ! ( loaded & TR_FR_IDLELIMIT ) )
2010-07-16 03:12:57 +00:00
{
2010-07-24 02:57:39 +00:00
tr_torrentSetIdleMode ( tor , TR_IDLELIMIT_GLOBAL ) ;
tr_torrentSetIdleLimit ( tor , tr_sessionGetIdleLimit ( tor - > session ) ) ;
2010-07-16 03:12:57 +00:00
}
2011-05-10 04:46:44 +00:00
/* add the torrent to tr_session.torrentList */
2011-08-02 03:59:54 +00:00
session - > torrentCount + + ;
2011-05-16 07:11:21 +00:00
if ( session - > torrentList = = NULL )
session - > torrentList = tor ;
else {
tr_torrent * it = session - > torrentList ;
while ( it - > next ! = NULL )
it = it - > next ;
it - > next = tor ;
2011-05-16 02:09:31 +00:00
}
2007-10-01 15:17:15 +00:00
2010-12-09 20:43:23 +00:00
/* if we don't have a local .torrent file already, assume the torrent is new */
isNewTorrent = stat ( tor - > info . torrent , & st ) ;
2007-12-22 18:00:47 +00:00
/* maybe save our own copy of the metainfo */
2008-09-23 19:11:04 +00:00
if ( tr_ctorGetSave ( ctor ) )
{
2008-02-26 21:58:58 +00:00
const tr_benc * val ;
2008-09-23 19:11:04 +00:00
if ( ! tr_ctorGetMetainfo ( ctor , & val ) )
{
2009-11-24 02:16:31 +00:00
const char * path = tor - > info . torrent ;
2010-03-22 00:55:43 +00:00
const int err = tr_bencToFile ( val , TR_FMT_BENC , path ) ;
if ( err )
tr_torrentSetLocalError ( tor , " Unable to save torrent file: %s " , tr_strerror ( err ) ) ;
2009-11-24 02:16:31 +00:00
tr_sessionSetTorrentFile ( tor - > session , tor - > info . hashString , path ) ;
2007-12-22 18:00:47 +00:00
}
}
2011-02-07 23:09:36 +00:00
tor - > tiers = tr_announcerAddTorrent ( tor , onTrackerResponse , NULL ) ;
2009-09-25 21:05:59 +00:00
2010-12-09 20:43:23 +00:00
if ( isNewTorrent )
{
tor - > startAfterVerify = doStart ;
tr_torrentVerify ( tor ) ;
}
else if ( doStart )
{
2011-08-01 22:24:24 +00:00
tr_torrentStart ( tor ) ;
2010-12-09 20:43:23 +00:00
}
2009-11-24 02:16:31 +00:00
2010-01-04 09:05:02 +00:00
tr_sessionUnlock ( session ) ;
2007-06-27 05:14:38 +00:00
}
2007-06-26 18:45:03 +00:00
2010-01-04 20:28:54 +00:00
static tr_parse_result
torrentParseImpl ( const tr_ctor * ctor , tr_info * setmeInfo ,
2011-03-22 15:19:54 +00:00
bool * setmeHasInfo , int * dictLength )
2007-06-27 05:14:38 +00:00
{
2008-09-23 19:11:04 +00:00
int doFree ;
2011-03-22 15:19:54 +00:00
bool didParse ;
bool hasInfo = false ;
2008-09-23 19:11:04 +00:00
tr_info tmp ;
2008-02-26 21:58:58 +00:00
const tr_benc * metainfo ;
2009-04-02 17:30:29 +00:00
tr_session * session = tr_ctorGetSession ( ctor ) ;
2009-08-05 02:07:51 +00:00
tr_parse_result result = TR_PARSE_OK ;
2007-12-21 22:18:40 +00:00
if ( setmeInfo = = NULL )
setmeInfo = & tmp ;
memset ( setmeInfo , 0 , sizeof ( tr_info ) ) ;
2007-06-27 05:14:38 +00:00
2009-08-05 01:59:16 +00:00
if ( tr_ctorGetMetainfo ( ctor , & metainfo ) )
return TR_PARSE_ERR ;
2007-06-27 05:14:38 +00:00
2010-02-02 22:45:22 +00:00
didParse = tr_metainfoParse ( session , metainfo , setmeInfo ,
2010-06-16 03:05:23 +00:00
& hasInfo , dictLength ) ;
2009-08-05 01:59:16 +00:00
doFree = didParse & & ( setmeInfo = = & tmp ) ;
2007-06-27 14:54:31 +00:00
2009-09-05 16:51:22 +00:00
if ( ! didParse )
result = TR_PARSE_ERR ;
2010-06-24 20:36:05 +00:00
if ( didParse & & hasInfo & & ! tr_getBlockSize ( setmeInfo - > pieceSize ) )
2009-08-05 01:59:16 +00:00
result = TR_PARSE_ERR ;
2008-08-05 20:27:40 +00:00
2009-08-05 01:59:16 +00:00
if ( didParse & & session & & tr_torrentExists ( session , setmeInfo - > hash ) )
result = TR_PARSE_DUPLICATE ;
2008-02-27 20:16:01 +00:00
2007-08-19 04:03:06 +00:00
if ( doFree )
2007-12-21 22:18:40 +00:00
tr_metainfoFree ( setmeInfo ) ;
2007-06-28 01:12:16 +00:00
2010-02-02 22:45:22 +00:00
if ( setmeHasInfo ! = NULL )
* setmeHasInfo = hasInfo ;
2009-08-05 01:59:16 +00:00
return result ;
2007-06-27 05:14:38 +00:00
}
2007-12-21 22:18:40 +00:00
2010-01-04 20:28:54 +00:00
tr_parse_result
tr_torrentParse ( const tr_ctor * ctor , tr_info * setmeInfo )
{
2010-06-16 03:05:23 +00:00
return torrentParseImpl ( ctor , setmeInfo , NULL , NULL ) ;
2010-01-04 20:28:54 +00:00
}
2007-12-21 22:18:40 +00:00
tr_torrent *
2010-01-04 20:28:54 +00:00
tr_torrentNew ( const tr_ctor * ctor , int * setmeError )
2007-01-19 08:36:49 +00:00
{
2010-06-16 03:05:23 +00:00
int len ;
2011-03-22 15:19:54 +00:00
bool hasInfo ;
2009-11-24 02:16:31 +00:00
tr_info tmpInfo ;
2010-02-02 22:45:22 +00:00
tr_parse_result r ;
2007-09-20 16:32:01 +00:00
tr_torrent * tor = NULL ;
2007-05-24 15:57:04 +00:00
2009-04-02 17:30:29 +00:00
assert ( ctor ! = NULL ) ;
2010-02-10 05:27:14 +00:00
assert ( tr_isSession ( tr_ctorGetSession ( ctor ) ) ) ;
2009-04-02 17:30:29 +00:00
2010-06-16 03:05:23 +00:00
r = torrentParseImpl ( ctor , & tmpInfo , & hasInfo , & len ) ;
2010-02-02 22:45:22 +00:00
if ( r = = TR_PARSE_OK )
2008-09-23 19:11:04 +00:00
{
2010-02-02 22:45:22 +00:00
tor = tr_new0 ( tr_torrent , 1 ) ;
tor - > info = tmpInfo ;
if ( hasInfo )
2010-01-04 20:28:54 +00:00
tor - > infoDictLength = len ;
2010-02-02 22:45:22 +00:00
torrentInit ( tor , ctor ) ;
}
2010-02-15 00:22:18 +00:00
else
2010-02-02 22:45:22 +00:00
{
2010-02-12 04:13:51 +00:00
if ( r = = TR_PARSE_DUPLICATE )
tr_metainfoFree ( & tmpInfo ) ;
2010-02-15 00:22:18 +00:00
if ( setmeError )
* setmeError = r ;
2007-05-11 18:56:59 +00:00
}
2007-06-26 18:45:03 +00:00
2007-06-27 05:14:38 +00:00
return tor ;
2007-05-11 18:56:59 +00:00
}
2007-09-20 16:32:01 +00:00
/**
* * *
* */
2007-07-23 03:00:20 +00:00
void
2009-05-13 15:54:04 +00:00
tr_torrentSetDownloadDir ( tr_torrent * tor , const char * path )
2007-01-19 08:36:49 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-05-18 16:44:30 +00:00
if ( ! path | | ! tor - > downloadDir | | strcmp ( path , tor - > downloadDir ) )
2008-05-06 01:43:24 +00:00
{
2008-05-18 16:44:30 +00:00
tr_free ( tor - > downloadDir ) ;
tor - > downloadDir = tr_strdup ( path ) ;
2009-08-07 05:29:37 +00:00
tr_torrentSetDirty ( tor ) ;
2008-05-06 01:43:24 +00:00
}
2009-10-19 05:05:00 +00:00
refreshCurrentDir ( tor ) ;
2007-06-26 18:45:03 +00:00
}
2007-05-28 15:23:28 +00:00
2007-07-23 03:00:20 +00:00
const char *
2008-05-18 16:44:30 +00:00
tr_torrentGetDownloadDir ( const tr_torrent * tor )
2007-06-26 18:45:03 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-05-18 16:44:30 +00:00
return tor - > downloadDir ;
2007-01-19 08:36:49 +00:00
}
2009-10-21 05:03:10 +00:00
const char *
tr_torrentGetCurrentDir ( const tr_torrent * tor )
{
assert ( tr_isTorrent ( tor ) ) ;
return tor - > currentDir ;
}
2007-08-16 20:00:06 +00:00
void
2007-09-21 05:31:29 +00:00
tr_torrentChangeMyPort ( tr_torrent * tor )
2007-08-16 20:00:06 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2010-03-06 21:24:28 +00:00
if ( tor - > isRunning )
tr_announcerChangeMyPort ( tor ) ;
2007-08-16 20:00:06 +00:00
}
2007-06-26 18:45:03 +00:00
2010-01-01 22:26:35 +00:00
static inline void
2008-05-22 20:44:41 +00:00
tr_torrentManualUpdateImpl ( void * vtor )
2007-01-19 08:36:49 +00:00
{
2007-11-20 16:50:48 +00:00
tr_torrent * tor = vtor ;
2008-09-23 19:11:04 +00:00
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2007-10-04 19:58:30 +00:00
if ( tor - > isRunning )
2009-09-25 21:05:59 +00:00
tr_announcerManualAnnounce ( tor ) ;
2007-07-30 17:11:00 +00:00
}
2008-09-23 19:11:04 +00:00
2007-11-20 16:50:48 +00:00
void
2008-05-22 20:44:41 +00:00
tr_torrentManualUpdate ( tr_torrent * tor )
2007-11-20 16:50:48 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-10-02 15:53:33 +00:00
tr_runInEventThread ( tor - > session , tr_torrentManualUpdateImpl , tor ) ;
2007-11-20 16:50:48 +00:00
}
2008-09-23 19:11:04 +00:00
2011-03-22 15:19:54 +00:00
bool
2007-09-20 16:32:01 +00:00
tr_torrentCanManualUpdate ( const tr_torrent * tor )
2007-07-30 17:11:00 +00:00
{
2009-01-30 00:41:08 +00:00
return ( tr_isTorrent ( tor ) )
& & ( tor - > isRunning )
2009-09-25 21:05:59 +00:00
& & ( tr_announcerCanManualAnnounce ( tor ) ) ;
2007-01-19 08:36:49 +00:00
}
2007-12-21 22:18:40 +00:00
const tr_info *
tr_torrentInfo ( const tr_torrent * tor )
{
2009-01-30 00:41:08 +00:00
return tr_isTorrent ( tor ) ? & tor - > info : NULL ;
2007-12-21 22:18:40 +00:00
}
const tr_stat *
tr_torrentStatCached ( tr_torrent * tor )
{
2009-11-26 18:47:08 +00:00
const time_t now = tr_time ( ) ;
2007-10-21 15:47:26 +00:00
2009-01-30 00:41:08 +00:00
return tr_isTorrent ( tor ) & & ( now = = tor - > lastStatTime )
? & tor - > stats
: tr_torrentStat ( tor ) ;
2007-12-21 22:18:40 +00:00
}
2007-10-21 15:47:26 +00:00
2009-03-26 18:06:54 +00:00
void
tr_torrentSetVerifyState ( tr_torrent * tor , tr_verify_state state )
{
assert ( tr_isTorrent ( tor ) ) ;
assert ( state = = TR_VERIFY_NONE | | state = = TR_VERIFY_WAIT | | state = = TR_VERIFY_NOW ) ;
tor - > verifyState = state ;
2009-11-26 18:47:08 +00:00
tor - > anyDate = tr_time ( ) ;
2009-03-26 18:06:54 +00:00
}
2011-08-01 22:24:24 +00:00
static tr_torrent_activity
torrentGetActivity ( const tr_torrent * tor )
2008-04-01 02:35:04 +00:00
{
2011-08-01 22:24:24 +00:00
const bool is_seed = tr_torrentIsSeed ( tor ) ;
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-04-01 02:35:04 +00:00
if ( tor - > verifyState = = TR_VERIFY_NOW )
return TR_STATUS_CHECK ;
2011-08-01 22:24:24 +00:00
2008-04-01 02:35:04 +00:00
if ( tor - > verifyState = = TR_VERIFY_WAIT )
return TR_STATUS_CHECK_WAIT ;
2011-08-01 22:24:24 +00:00
if ( tor - > isRunning )
return is_seed ? TR_STATUS_SEED : TR_STATUS_DOWNLOAD ;
2011-08-02 03:59:54 +00:00
if ( tr_torrentIsQueued ( tor ) ) {
2011-08-01 22:24:24 +00:00
if ( is_seed & & tr_sessionGetQueueEnabled ( tor - > session , TR_UP ) )
return TR_STATUS_SEED_WAIT ;
if ( ! is_seed & & tr_sessionGetQueueEnabled ( tor - > session , TR_DOWN ) )
return TR_STATUS_DOWNLOAD_WAIT ;
}
return TR_STATUS_STOPPED ;
}
tr_torrent_activity
tr_torrentGetActivity ( tr_torrent * tor )
{
/* FIXME: is this call still needed? */
tr_torrentRecheckCompleteness ( tor ) ;
return torrentGetActivity ( tor ) ;
2008-04-01 02:35:04 +00:00
}
2011-08-01 22:24:24 +00:00
static time_t
torrentGetIdleSecs ( const tr_torrent * tor )
{
int idle_secs ;
const tr_torrent_activity activity = torrentGetActivity ( tor ) ;
if ( ( activity = = TR_STATUS_DOWNLOAD | | activity = = TR_STATUS_SEED ) & & tor - > startDate ! = 0 )
idle_secs = difftime ( tr_time ( ) , MAX ( tor - > startDate , tor - > activityDate ) ) ;
else
idle_secs = - 1 ;
return idle_secs ;
}
bool
tr_torrentIsStalled ( const tr_torrent * tor )
{
2011-08-07 19:24:33 +00:00
return tr_sessionGetQueueStalledEnabled ( tor - > session )
& & ( torrentGetIdleSecs ( tor ) > ( tr_sessionGetQueueStalledMinutes ( tor - > session ) * 60 ) ) ;
2011-08-01 22:24:24 +00:00
}
2010-12-09 20:43:23 +00:00
static double
getVerifyProgress ( const tr_torrent * tor )
{
2012-07-14 19:34:38 +00:00
double d = 0 ;
2010-12-09 20:43:23 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2012-07-14 19:34:38 +00:00
if ( tr_torrentHasMetadata ( tor ) )
{
tr_piece_index_t i , n ;
tr_piece_index_t checked = 0 ;
for ( i = 0 , n = tor - > info . pieceCount ; i ! = n ; + + i )
if ( tor - > info . pieces [ i ] . timeChecked )
+ + checked ;
d = checked / ( double ) tor - > info . pieceCount ;
}
2010-12-09 20:43:23 +00:00
2012-07-14 19:34:38 +00:00
return d ;
2010-12-09 20:43:23 +00:00
}
2007-09-20 16:32:01 +00:00
const tr_stat *
tr_torrentStat ( tr_torrent * tor )
2007-01-19 08:36:49 +00:00
{
2008-09-23 19:11:04 +00:00
tr_stat * s ;
2009-01-05 04:27:54 +00:00
uint64_t now ;
2010-04-14 00:03:23 +00:00
uint64_t seedRatioBytesLeft ;
uint64_t seedRatioBytesGoal ;
2011-03-22 15:19:54 +00:00
bool seedRatioApplies ;
2010-08-14 15:30:43 +00:00
uint16_t seedIdleMinutes ;
2007-01-19 08:36:49 +00:00
2008-04-06 17:12:15 +00:00
if ( ! tor )
return NULL ;
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2007-09-20 16:32:01 +00:00
tr_torrentLock ( tor ) ;
2007-06-26 18:45:03 +00:00
2009-11-26 18:47:08 +00:00
tor - > lastStatTime = tr_time ( ) ;
2007-10-20 21:07:11 +00:00
2008-03-31 19:34:20 +00:00
s = & tor - > stats ;
2008-05-22 16:59:51 +00:00
s - > id = tor - > uniqueId ;
2008-10-20 17:54:56 +00:00
s - > activity = tr_torrentGetActivity ( tor ) ;
2009-08-05 01:25:36 +00:00
s - > error = tor - > error ;
2011-08-01 22:24:24 +00:00
s - > queuePosition = tor - > queuePosition ;
2011-08-01 23:27:11 +00:00
s - > isStalled = tr_torrentIsStalled ( tor ) ;
2011-03-31 04:01:55 +00:00
tr_strlcpy ( s - > errorString , tor - > errorString , sizeof ( s - > errorString ) ) ;
2007-01-19 08:36:49 +00:00
2009-09-25 21:05:59 +00:00
s - > manualAnnounceTime = tr_announcerNextManualAnnounce ( tor ) ;
2008-12-02 19:46:51 +00:00
2009-01-13 21:00:05 +00:00
tr_peerMgrTorrentStats ( tor ,
2007-09-20 16:32:01 +00:00
& s - > peersConnected ,
2008-06-10 02:36:52 +00:00
& s - > webseedsSendingToUs ,
2007-09-20 16:32:01 +00:00
& s - > peersSendingToUs ,
& s - > peersGettingFromUs ,
2008-10-20 03:47:48 +00:00
s - > peersFrom ) ;
2010-07-11 20:49:19 +00:00
now = tr_time_msec ( ) ;
2011-03-31 14:53:22 +00:00
s - > rawUploadSpeed_KBps = toSpeedKBps ( tr_bandwidthGetRawSpeed_Bps ( & tor - > bandwidth , now , TR_UP ) ) ;
s - > pieceUploadSpeed_KBps = toSpeedKBps ( tr_bandwidthGetPieceSpeed_Bps ( & tor - > bandwidth , now , TR_UP ) ) ;
s - > rawDownloadSpeed_KBps = toSpeedKBps ( tr_bandwidthGetRawSpeed_Bps ( & tor - > bandwidth , now , TR_DOWN ) ) ;
s - > pieceDownloadSpeed_KBps = toSpeedKBps ( tr_bandwidthGetPieceSpeed_Bps ( & tor - > bandwidth , now , TR_DOWN ) ) ;
2007-01-19 08:36:49 +00:00
2009-01-02 17:01:55 +00:00
s - > percentComplete = tr_cpPercentComplete ( & tor - > completion ) ;
2009-11-24 17:10:40 +00:00
s - > metadataPercentComplete = tr_torrentGetMetadataPercent ( tor ) ;
2007-06-26 18:45:03 +00:00
2010-12-23 19:32:59 +00:00
s - > percentDone = tr_cpPercentDone ( & tor - > completion ) ;
s - > leftUntilDone = tr_cpLeftUntilDone ( & tor - > completion ) ;
s - > sizeWhenDone = tr_cpSizeWhenDone ( & tor - > completion ) ;
s - > recheckProgress = s - > activity = = TR_STATUS_CHECK ? getVerifyProgress ( tor ) : 0 ;
s - > activityDate = tor - > activityDate ;
s - > addedDate = tor - > addedDate ;
s - > doneDate = tor - > doneDate ;
s - > startDate = tor - > startDate ;
s - > secondsSeeding = tor - > secondsSeeding ;
s - > secondsDownloading = tor - > secondsDownloading ;
2011-08-01 22:24:24 +00:00
s - > idleSecs = torrentGetIdleSecs ( tor ) ;
2010-07-11 21:02:30 +00:00
2011-03-28 16:31:05 +00:00
s - > corruptEver = tor - > corruptCur + tor - > corruptPrev ;
s - > downloadedEver = tor - > downloadedCur + tor - > downloadedPrev ;
s - > uploadedEver = tor - > uploadedCur + tor - > uploadedPrev ;
s - > haveValid = tr_cpHaveValid ( & tor - > completion ) ;
s - > haveUnchecked = tr_cpHaveTotal ( & tor - > completion ) - s - > haveValid ;
s - > desiredAvailable = tr_peerMgrGetDesiredAvailable ( tor ) ;
2008-01-04 19:13:30 +00:00
2010-04-14 00:03:23 +00:00
s - > ratio = tr_getRatio ( s - > uploadedEver ,
s - > downloadedEver ? s - > downloadedEver : s - > haveValid ) ;
2008-04-06 14:42:47 +00:00
2010-04-14 00:03:23 +00:00
seedRatioApplies = tr_torrentGetSeedRatioBytes ( tor , & seedRatioBytesLeft ,
& seedRatioBytesGoal ) ;
2009-03-01 23:48:04 +00:00
2009-02-14 05:15:23 +00:00
switch ( s - > activity )
{
2009-10-25 02:42:57 +00:00
/* etaXLSpeed exists because if we use the piece speed directly,
* brief fluctuations cause the ETA to jump all over the place .
* so , etaXLSpeed is a smoothed - out version of the piece speed
* to dampen the effect of fluctuations */
2009-02-14 05:15:23 +00:00
case TR_STATUS_DOWNLOAD :
2009-10-25 02:42:57 +00:00
if ( ( tor - > etaDLSpeedCalculatedAt + 800 ) < now ) {
2010-07-04 06:07:21 +00:00
tor - > etaDLSpeed_KBps = ( ( tor - > etaDLSpeedCalculatedAt + 4000 ) < now )
? s - > pieceDownloadSpeed_KBps /* if no recent previous speed, no need to smooth */
: ( ( tor - > etaDLSpeed_KBps * 4.0 ) + s - > pieceDownloadSpeed_KBps ) / 5.0 ; /* smooth across 5 readings */
2009-10-25 02:42:57 +00:00
tor - > etaDLSpeedCalculatedAt = now ;
2009-10-25 02:36:03 +00:00
}
2009-11-24 02:16:31 +00:00
2009-02-14 05:15:23 +00:00
if ( s - > leftUntilDone > s - > desiredAvailable )
s - > eta = TR_ETA_NOT_AVAIL ;
2010-07-04 06:07:21 +00:00
else if ( tor - > etaDLSpeed_KBps < 1 )
2009-02-14 05:15:23 +00:00
s - > eta = TR_ETA_UNKNOWN ;
2009-10-25 02:36:03 +00:00
else
2010-07-04 06:07:21 +00:00
s - > eta = s - > leftUntilDone / toSpeedBytes ( tor - > etaDLSpeed_KBps ) ;
2010-08-14 15:30:43 +00:00
s - > etaIdle = TR_ETA_NOT_AVAIL ;
2009-02-14 05:15:23 +00:00
break ;
2009-03-01 13:56:22 +00:00
2010-04-14 00:03:23 +00:00
case TR_STATUS_SEED : {
if ( ! seedRatioApplies )
s - > eta = TR_ETA_NOT_AVAIL ;
else {
2009-10-25 02:42:57 +00:00
if ( ( tor - > etaULSpeedCalculatedAt + 800 ) < now ) {
2010-07-04 06:07:21 +00:00
tor - > etaULSpeed_KBps = ( ( tor - > etaULSpeedCalculatedAt + 4000 ) < now )
? s - > pieceUploadSpeed_KBps /* if no recent previous speed, no need to smooth */
: ( ( tor - > etaULSpeed_KBps * 4.0 ) + s - > pieceUploadSpeed_KBps ) / 5.0 ; /* smooth across 5 readings */
2009-10-25 02:42:57 +00:00
tor - > etaULSpeedCalculatedAt = now ;
}
2010-07-04 06:07:21 +00:00
if ( tor - > etaULSpeed_KBps < 1 )
2009-02-14 05:15:23 +00:00
s - > eta = TR_ETA_UNKNOWN ;
else
2010-07-04 06:07:21 +00:00
s - > eta = seedRatioBytesLeft / toSpeedBytes ( tor - > etaULSpeed_KBps ) ;
2009-02-14 05:15:23 +00:00
}
2010-08-14 15:30:43 +00:00
2010-08-14 19:44:43 +00:00
if ( tor - > etaULSpeed_KBps < 1 & & tr_torrentGetSeedIdle ( tor , & seedIdleMinutes ) )
2010-08-14 15:30:43 +00:00
s - > etaIdle = seedIdleMinutes * 60 - s - > idleSecs ;
else
s - > etaIdle = TR_ETA_NOT_AVAIL ;
2009-02-14 05:15:23 +00:00
break ;
2010-04-14 00:03:23 +00:00
}
2009-03-01 13:56:22 +00:00
2009-02-14 05:15:23 +00:00
default :
s - > eta = TR_ETA_NOT_AVAIL ;
2010-08-14 15:30:43 +00:00
s - > etaIdle = TR_ETA_NOT_AVAIL ;
2009-02-14 05:15:23 +00:00
break ;
}
2009-11-24 02:16:31 +00:00
2010-05-15 22:26:25 +00:00
/* s->haveValid is here to make sure a torrent isn't marked 'finished'
* when the user hits " uncheck all " prior to starting the torrent . . . */
2010-09-12 18:58:49 +00:00
s - > finished = tor - > finishedSeedingByIdle | | ( seedRatioApplies & & ! seedRatioBytesLeft & & s - > haveValid ) ;
2010-04-02 17:57:25 +00:00
2010-04-14 00:03:23 +00:00
if ( ! seedRatioApplies | | s - > finished )
s - > seedRatioPercentDone = 1 ;
else if ( ! seedRatioBytesGoal ) /* impossible? safeguard for div by zero */
s - > seedRatioPercentDone = 0 ;
2009-11-24 02:16:31 +00:00
else
2010-04-14 00:03:23 +00:00
s - > seedRatioPercentDone = ( double ) ( seedRatioBytesGoal - seedRatioBytesLeft ) / seedRatioBytesGoal ;
2008-09-23 19:11:04 +00:00
2007-09-20 16:32:01 +00:00
tr_torrentUnlock ( tor ) ;
2007-01-19 08:36:49 +00:00
2011-07-02 13:20:17 +00:00
/* test some of the constraints */
assert ( s - > sizeWhenDone < = tor - > info . totalSize ) ;
assert ( s - > leftUntilDone < = s - > sizeWhenDone ) ;
assert ( s - > desiredAvailable < = s - > leftUntilDone ) ;
2007-01-19 08:36:49 +00:00
return s ;
}
2007-07-15 20:05:32 +00:00
/***
* * * *
* * */
2009-05-16 01:43:21 +00:00
static uint64_t
fileBytesCompleted ( const tr_torrent * tor , tr_file_index_t index )
{
uint64_t total = 0 ;
const tr_file * f = & tor - > info . files [ index ] ;
2009-05-21 18:37:55 +00:00
if ( f - > length )
2009-05-16 01:43:21 +00:00
{
2011-02-23 03:54:04 +00:00
tr_block_index_t first ;
tr_block_index_t last ;
tr_torGetFileBlockRange ( tor , index , & first , & last ) ;
2009-05-16 01:43:21 +00:00
2011-02-23 03:54:04 +00:00
if ( first = = last )
2009-05-16 01:43:21 +00:00
{
2011-02-23 03:54:04 +00:00
if ( tr_cpBlockIsComplete ( & tor - > completion , first ) )
2009-05-21 18:37:55 +00:00
total = f - > length ;
2009-05-16 01:43:21 +00:00
}
else
{
2009-05-21 18:37:55 +00:00
/* the first block */
2011-02-23 03:54:04 +00:00
if ( tr_cpBlockIsComplete ( & tor - > completion , first ) )
2009-05-21 18:37:55 +00:00
total + = tor - > blockSize - ( f - > offset % tor - > blockSize ) ;
/* the middle blocks */
2011-02-23 03:54:04 +00:00
if ( first + 1 < last ) {
2011-03-28 16:31:05 +00:00
uint64_t u = tr_bitfieldCountRange ( & tor - > completion . blockBitfield , first + 1 , last ) ;
2011-02-23 03:54:04 +00:00
u * = tor - > blockSize ;
total + = u ;
2009-05-21 18:37:55 +00:00
}
/* the last block */
2011-02-23 03:54:04 +00:00
if ( tr_cpBlockIsComplete ( & tor - > completion , last ) )
total + = ( f - > offset + f - > length ) - ( ( uint64_t ) tor - > blockSize * last ) ;
2009-05-16 01:43:21 +00:00
}
2009-05-21 18:37:55 +00:00
}
2009-05-16 01:43:21 +00:00
return total ;
}
2007-09-20 16:32:01 +00:00
tr_file_stat *
2008-09-23 19:11:04 +00:00
tr_torrentFiles ( const tr_torrent * tor ,
tr_file_index_t * fileCount )
2007-07-15 20:05:32 +00:00
{
2008-09-23 19:11:04 +00:00
tr_file_index_t i ;
2008-03-22 18:10:59 +00:00
const tr_file_index_t n = tor - > info . fileCount ;
2008-09-23 19:11:04 +00:00
tr_file_stat * files = tr_new0 ( tr_file_stat , n ) ;
tr_file_stat * walk = files ;
2011-03-22 15:19:54 +00:00
const bool isSeed = tor - > completeness = = TR_SEED ;
2007-07-15 20:05:32 +00:00
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2009-10-31 00:54:03 +00:00
for ( i = 0 ; i < n ; + + i , + + walk ) {
2009-04-12 17:31:17 +00:00
const uint64_t b = isSeed ? tor - > info . files [ i ] . length : fileBytesCompleted ( tor , i ) ;
2008-04-24 15:25:01 +00:00
walk - > bytesCompleted = b ;
2010-07-10 21:30:37 +00:00
walk - > progress = tor - > info . files [ i ] . length > 0 ? ( ( float ) b / tor - > info . files [ i ] . length ) : 1.0f ;
2007-07-15 20:05:32 +00:00
}
2008-03-22 18:27:29 +00:00
if ( fileCount )
* fileCount = n ;
2007-07-15 20:05:32 +00:00
return files ;
}
void
2008-09-23 19:11:04 +00:00
tr_torrentFilesFree ( tr_file_stat * files ,
tr_file_index_t fileCount UNUSED )
2007-07-15 20:05:32 +00:00
{
tr_free ( files ) ;
}
/***
* * * *
* * */
2010-07-04 06:07:21 +00:00
double *
tr_torrentWebSpeeds_KBps ( const tr_torrent * tor )
2008-06-10 01:38:12 +00:00
{
2011-01-18 23:44:36 +00:00
double * ret = NULL ;
if ( tr_isTorrent ( tor ) )
{
tr_torrentLock ( tor ) ;
ret = tr_peerMgrWebSpeeds_KBps ( tor ) ;
tr_torrentUnlock ( tor ) ;
}
return ret ;
2008-06-10 01:38:12 +00:00
}
2007-09-20 16:32:01 +00:00
tr_peer_stat *
2011-01-18 23:44:36 +00:00
tr_torrentPeers ( const tr_torrent * tor , int * peerCount )
2007-01-19 08:36:49 +00:00
{
2007-11-23 02:14:21 +00:00
tr_peer_stat * ret = NULL ;
2009-01-30 00:41:08 +00:00
if ( tr_isTorrent ( tor ) )
2011-01-18 23:44:36 +00:00
{
tr_torrentLock ( tor ) ;
2009-01-13 21:00:05 +00:00
ret = tr_peerMgrPeerStats ( tor , peerCount ) ;
2011-01-18 23:44:36 +00:00
tr_torrentUnlock ( tor ) ;
}
2007-11-23 02:14:21 +00:00
return ret ;
2007-01-19 08:36:49 +00:00
}
2007-10-02 03:33:17 +00:00
void
2011-01-18 23:44:36 +00:00
tr_torrentPeersFree ( tr_peer_stat * peers , int peerCount UNUSED )
2007-01-19 08:36:49 +00:00
{
2007-06-26 18:45:03 +00:00
tr_free ( peers ) ;
2007-01-19 08:36:49 +00:00
}
2009-09-25 21:05:59 +00:00
tr_tracker_stat *
2011-01-18 23:44:36 +00:00
tr_torrentTrackers ( const tr_torrent * torrent , int * setmeTrackerCount )
2009-09-25 21:05:59 +00:00
{
2011-01-18 23:44:36 +00:00
tr_tracker_stat * ret = NULL ;
2009-09-25 21:05:59 +00:00
2011-01-18 23:44:36 +00:00
if ( tr_isTorrent ( torrent ) )
{
tr_torrentLock ( torrent ) ;
ret = tr_announcerStats ( torrent , setmeTrackerCount ) ;
tr_torrentUnlock ( torrent ) ;
}
return ret ;
2009-09-25 21:05:59 +00:00
}
void
2011-01-18 23:44:36 +00:00
tr_torrentTrackersFree ( tr_tracker_stat * trackers , int trackerCount )
2009-09-25 21:05:59 +00:00
{
tr_announcerStatsFree ( trackers , trackerCount ) ;
}
2008-05-28 13:03:34 +00:00
void
2011-01-18 22:51:29 +00:00
tr_torrentAvailability ( const tr_torrent * tor , int8_t * tab , int size )
2007-01-19 08:36:49 +00:00
{
2011-01-22 13:21:20 +00:00
if ( tr_isTorrent ( tor ) & & ( tab ! = NULL ) & & ( size > 0 ) )
{
tr_torrentLock ( tor ) ;
tr_peerMgrTorrentAvailability ( tor , tab , size ) ;
tr_torrentUnlock ( tor ) ;
}
2007-01-19 08:36:49 +00:00
}
2008-04-24 15:25:01 +00:00
void
2008-09-23 19:11:04 +00:00
tr_torrentAmountFinished ( const tr_torrent * tor ,
float * tab ,
int size )
2007-01-19 08:36:49 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2007-09-20 16:32:01 +00:00
tr_torrentLock ( tor ) ;
2009-01-02 17:01:55 +00:00
tr_cpGetAmountDone ( & tor - > completion , tab , size ) ;
2007-09-20 16:32:01 +00:00
tr_torrentUnlock ( tor ) ;
2007-04-28 01:34:39 +00:00
}
2009-09-25 21:05:59 +00:00
static void
2007-09-20 16:32:01 +00:00
tr_torrentResetTransferStats ( tr_torrent * tor )
2007-01-19 08:36:49 +00:00
{
2007-09-20 16:32:01 +00:00
tr_torrentLock ( tor ) ;
2007-01-19 08:36:49 +00:00
2007-06-26 18:45:03 +00:00
tor - > downloadedPrev + = tor - > downloadedCur ;
tor - > downloadedCur = 0 ;
tor - > uploadedPrev + = tor - > uploadedCur ;
tor - > uploadedCur = 0 ;
2007-08-21 15:17:02 +00:00
tor - > corruptPrev + = tor - > corruptCur ;
tor - > corruptCur = 0 ;
2007-01-19 08:36:49 +00:00
2009-08-07 05:29:37 +00:00
tr_torrentSetDirty ( tor ) ;
2007-09-20 16:32:01 +00:00
tr_torrentUnlock ( tor ) ;
2007-06-26 18:45:03 +00:00
}
2007-01-19 08:36:49 +00:00
2007-06-26 18:45:03 +00:00
void
2008-09-23 19:11:04 +00:00
tr_torrentSetHasPiece ( tr_torrent * tor ,
tr_piece_index_t pieceIndex ,
2011-03-22 15:19:54 +00:00
bool has )
2007-06-26 18:45:03 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-01-08 03:08:36 +00:00
assert ( pieceIndex < tor - > info . pieceCount ) ;
2007-06-26 18:45:03 +00:00
if ( has )
2009-01-02 17:01:55 +00:00
tr_cpPieceAdd ( & tor - > completion , pieceIndex ) ;
2007-06-26 18:45:03 +00:00
else
2009-01-02 17:01:55 +00:00
tr_cpPieceRem ( & tor - > completion , pieceIndex ) ;
2007-06-26 18:45:03 +00:00
}
2007-01-19 08:36:49 +00:00
2007-06-26 18:45:03 +00:00
/***
* * * *
* * */
2007-05-28 15:23:28 +00:00
2011-08-05 17:03:34 +00:00
# ifndef NDEBUG
2011-08-02 03:59:54 +00:00
static bool queueIsSequenced ( tr_session * ) ;
2011-08-05 17:03:34 +00:00
# endif
2011-08-02 03:59:54 +00:00
2007-06-26 18:45:03 +00:00
static void
2007-10-04 19:58:30 +00:00
freeTorrent ( tr_torrent * tor )
2007-06-26 18:45:03 +00:00
{
2007-09-20 16:32:01 +00:00
tr_torrent * t ;
2008-12-14 11:21:11 +00:00
tr_session * session = tor - > session ;
2008-09-23 19:11:04 +00:00
tr_info * inf = & tor - > info ;
2011-08-02 03:59:54 +00:00
const time_t now = tr_time ( ) ;
2007-09-20 16:32:01 +00:00
2007-10-04 19:58:30 +00:00
assert ( ! tor - > isRunning ) ;
2007-05-28 15:23:28 +00:00
2010-01-04 09:05:02 +00:00
tr_sessionLock ( session ) ;
2007-05-28 15:23:28 +00:00
2009-01-13 21:00:05 +00:00
tr_peerMgrRemoveTorrent ( tor ) ;
2007-09-23 19:24:06 +00:00
2009-09-25 21:05:59 +00:00
tr_announcerRemoveTorrent ( session - > announcer , tor ) ;
2007-08-16 20:00:06 +00:00
2011-09-26 05:57:03 +00:00
tr_cpDestruct ( & tor - > completion ) ;
2008-05-18 16:44:30 +00:00
tr_free ( tor - > downloadDir ) ;
2009-10-19 05:05:00 +00:00
tr_free ( tor - > incompleteDir ) ;
2007-05-28 15:23:28 +00:00
2008-12-14 11:21:11 +00:00
if ( tor = = session - > torrentList )
session - > torrentList = tor - > next ;
else for ( t = session - > torrentList ; t ! = NULL ; t = t - > next ) {
if ( t - > next = = tor ) {
t - > next = tor - > next ;
break ;
2007-05-28 16:40:56 +00:00
}
2008-12-14 11:21:11 +00:00
}
2007-05-28 15:23:28 +00:00
2011-08-02 03:59:54 +00:00
/* decrement the torrent count */
2008-12-14 11:21:11 +00:00
assert ( session - > torrentCount > = 1 ) ;
session - > torrentCount - - ;
2007-06-30 13:19:57 +00:00
2011-08-02 03:59:54 +00:00
/* resequence the queue positions */
t = NULL ;
2011-08-02 14:03:43 +00:00
while ( ( t = tr_torrentNext ( session , t ) ) ) {
2011-08-02 03:59:54 +00:00
if ( t - > queuePosition > tor - > queuePosition ) {
t - > queuePosition - - ;
t - > anyDate = now ;
}
}
assert ( queueIsSequenced ( session ) ) ;
2011-03-31 14:53:22 +00:00
tr_bandwidthDestruct ( & tor - > bandwidth ) ;
2008-11-06 02:56:51 +00:00
2007-09-20 16:32:01 +00:00
tr_metainfoFree ( inf ) ;
2011-09-28 16:06:19 +00:00
memset ( tor , ~ 0 , sizeof ( tr_torrent ) ) ;
2007-07-21 17:35:47 +00:00
tr_free ( tor ) ;
2010-01-04 09:05:02 +00:00
tr_sessionUnlock ( session ) ;
2007-05-28 15:23:28 +00:00
}
2008-01-18 19:13:32 +00:00
/**
* * * Start / Stop Callback
* */
2011-08-02 03:59:54 +00:00
static void torrentSetQueued ( tr_torrent * tor , bool queued ) ;
2011-08-01 22:24:24 +00:00
2007-10-04 19:58:30 +00:00
static void
2010-12-09 20:43:23 +00:00
torrentStartImpl ( void * vtor )
2007-10-04 19:58:30 +00:00
{
2010-12-09 20:43:23 +00:00
time_t now ;
2007-11-16 05:43:47 +00:00
tr_torrent * tor = vtor ;
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2010-01-04 09:05:02 +00:00
tr_sessionLock ( tor - > session ) ;
2007-10-04 19:58:30 +00:00
2010-12-09 20:43:23 +00:00
tr_torrentRecheckCompleteness ( tor ) ;
2011-08-02 03:59:54 +00:00
torrentSetQueued ( tor , false ) ;
2010-12-09 20:43:23 +00:00
now = tr_time ( ) ;
2011-03-22 15:19:54 +00:00
tor - > isRunning = true ;
2010-12-09 20:43:23 +00:00
tor - > completeness = tr_cpGetStatus ( & tor - > completion ) ;
tor - > startDate = tor - > anyDate = now ;
tr_torrentClearError ( tor ) ;
2011-03-22 15:19:54 +00:00
tor - > finishedSeedingByIdle = false ;
2010-12-09 20:43:23 +00:00
tr_torrentResetTransferStats ( tor ) ;
tr_announcerTorrentStarted ( tor ) ;
tor - > dhtAnnounceAt = now + tr_cryptoWeakRandInt ( 20 ) ;
tor - > dhtAnnounce6At = now + tr_cryptoWeakRandInt ( 20 ) ;
tor - > lpdAnnounceAt = now ;
tr_peerMgrStartTorrent ( tor ) ;
2007-10-04 19:58:30 +00:00
2010-01-04 09:05:02 +00:00
tr_sessionUnlock ( tor - > session ) ;
2007-10-04 19:58:30 +00:00
}
2007-11-16 05:43:47 +00:00
2010-12-09 20:43:23 +00:00
uint64_t
tr_torrentGetCurrentSizeOnDisk ( const tr_torrent * tor )
2007-11-16 05:43:47 +00:00
{
2010-12-09 20:43:23 +00:00
tr_file_index_t i ;
uint64_t byte_count = 0 ;
const tr_file_index_t n = tor - > info . fileCount ;
for ( i = 0 ; i < n ; + + i )
{
struct stat sb ;
char * filename = tr_torrentFindFile ( tor , i ) ;
2009-01-29 16:56:43 +00:00
2010-12-09 20:43:23 +00:00
sb . st_size = 0 ;
if ( filename & & ! stat ( filename , & sb ) )
byte_count + = sb . st_size ;
tr_free ( filename ) ;
}
return byte_count ;
2007-11-16 05:43:47 +00:00
}
2011-08-01 22:24:24 +00:00
static bool
torrentShouldQueue ( const tr_torrent * tor )
{
const tr_direction dir = tr_torrentGetQueueDirection ( tor ) ;
return tr_sessionCountQueueFreeSlots ( tor - > session , dir ) = = 0 ;
}
2008-05-06 01:43:24 +00:00
static void
2011-08-01 22:24:24 +00:00
torrentStart ( tr_torrent * tor , bool bypass_queue )
2007-07-19 03:48:27 +00:00
{
2011-08-01 22:24:24 +00:00
switch ( torrentGetActivity ( tor ) )
{
case TR_STATUS_SEED :
case TR_STATUS_DOWNLOAD :
return ; /* already started */
break ;
case TR_STATUS_SEED_WAIT :
case TR_STATUS_DOWNLOAD_WAIT :
if ( ! bypass_queue )
return ; /* already queued */
break ;
case TR_STATUS_CHECK :
case TR_STATUS_CHECK_WAIT :
/* verifying right now... wait until that's done so
* we ' ll know what completeness to use / announce */
tor - > startAfterVerify = true ;
return ;
break ;
case TR_STATUS_STOPPED :
if ( ! bypass_queue & & torrentShouldQueue ( tor ) ) {
2011-08-02 03:59:54 +00:00
torrentSetQueued ( tor , true ) ;
2011-08-01 22:24:24 +00:00
return ;
}
break ;
}
2010-04-02 17:57:25 +00:00
2010-12-09 20:43:23 +00:00
/* don't allow the torrent to be started if the files disappeared */
if ( setLocalErrorIfFilesDisappeared ( tor ) )
return ;
2009-09-25 21:05:59 +00:00
2010-12-09 20:43:23 +00:00
/* otherwise, start it now... */
tr_sessionLock ( tor - > session ) ;
2009-09-25 21:05:59 +00:00
2010-12-09 20:43:23 +00:00
/* allow finished torrents to be resumed */
if ( tr_torrentIsSeedRatioDone ( tor ) ) {
tr_torinf ( tor , _ ( " Restarted manually -- disabling its seed ratio " ) ) ;
tr_torrentSetRatioMode ( tor , TR_RATIOLIMIT_UNLIMITED ) ;
2007-10-04 19:58:30 +00:00
}
2007-07-19 03:48:27 +00:00
2010-12-09 20:43:23 +00:00
/* corresponds to the peer_id sent as a tracker request parameter.
* one tracker admin says : " When the same torrent is opened and
* closed and opened again without quitting Transmission . . .
* change the peerid . It would help sometimes if a stopped event
* was missed to ensure that we didn ' t think someone was cheating . */
2011-03-10 12:35:23 +00:00
tr_peerIdInit ( tor - > peer_id ) ;
2010-12-09 20:43:23 +00:00
tor - > isRunning = 1 ;
tr_torrentSetDirty ( tor ) ;
tr_runInEventThread ( tor - > session , torrentStartImpl , tor ) ;
2010-01-04 09:05:02 +00:00
tr_sessionUnlock ( tor - > session ) ;
2007-07-19 03:48:27 +00:00
}
2008-05-06 01:43:24 +00:00
void
tr_torrentStart ( tr_torrent * tor )
{
2009-01-30 00:41:08 +00:00
if ( tr_isTorrent ( tor ) )
2011-08-01 22:24:24 +00:00
torrentStart ( tor , false ) ;
}
void
tr_torrentStartNow ( tr_torrent * tor )
{
if ( tr_isTorrent ( tor ) )
torrentStart ( tor , true ) ;
2008-05-06 01:43:24 +00:00
}
2007-11-16 20:41:41 +00:00
static void
torrentRecheckDoneImpl ( void * vtor )
{
2009-01-30 00:41:08 +00:00
tr_torrent * tor = vtor ;
assert ( tr_isTorrent ( tor ) ) ;
2010-12-09 20:43:23 +00:00
2009-01-30 00:41:08 +00:00
tr_torrentRecheckCompleteness ( tor ) ;
2009-05-13 15:54:04 +00:00
2010-12-09 20:43:23 +00:00
if ( tor - > startAfterVerify ) {
2011-03-22 15:19:54 +00:00
tor - > startAfterVerify = false ;
2011-08-01 22:24:24 +00:00
torrentStart ( tor , false ) ;
2009-05-13 15:54:04 +00:00
}
2007-11-16 20:41:41 +00:00
}
2008-09-23 19:11:04 +00:00
2007-11-16 20:41:41 +00:00
static void
torrentRecheckDoneCB ( tr_torrent * tor )
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-10-02 15:53:33 +00:00
tr_runInEventThread ( tor - > session , torrentRecheckDoneImpl , tor ) ;
2007-11-16 20:41:41 +00:00
}
2008-09-23 19:11:04 +00:00
2009-08-12 04:08:25 +00:00
static void
verifyTorrent ( void * vtor )
2007-10-04 19:58:30 +00:00
{
2012-10-15 03:11:16 +00:00
bool startAfter ;
2009-08-12 04:08:25 +00:00
tr_torrent * tor = vtor ;
2010-01-04 09:05:02 +00:00
tr_sessionLock ( tor - > session ) ;
2009-01-30 00:41:08 +00:00
2009-05-13 15:54:04 +00:00
/* if the torrent's already being verified, stop it */
2008-04-27 06:34:34 +00:00
tr_verifyRemove ( tor ) ;
2012-10-15 03:11:16 +00:00
startAfter = ( tor - > isRunning | | tor - > startAfterVerify ) & & ! tor - > isStopping ;
if ( tor - > isRunning )
2009-05-13 15:54:04 +00:00
tr_torrentStop ( tor ) ;
2012-10-15 03:11:16 +00:00
tor - > startAfterVerify = startAfter ;
2007-10-04 23:47:49 +00:00
2010-12-09 20:43:23 +00:00
if ( setLocalErrorIfFilesDisappeared ( tor ) )
2011-03-22 15:19:54 +00:00
tor - > startAfterVerify = false ;
2010-12-09 20:43:23 +00:00
else
tr_verifyAdd ( tor , torrentRecheckDoneCB ) ;
2007-06-26 18:45:03 +00:00
2010-01-04 09:05:02 +00:00
tr_sessionUnlock ( tor - > session ) ;
2007-10-04 19:58:30 +00:00
}
2007-07-12 20:48:13 +00:00
2009-08-12 04:08:25 +00:00
void
tr_torrentVerify ( tr_torrent * tor )
{
if ( tr_isTorrent ( tor ) )
tr_runInEventThread ( tor - > session , verifyTorrent , tor ) ;
}
2009-08-13 14:47:56 +00:00
void
tr_torrentSave ( tr_torrent * tor )
{
assert ( tr_isTorrent ( tor ) ) ;
2010-02-02 22:45:22 +00:00
if ( tor - > isDirty )
2009-11-24 17:10:40 +00:00
{
2011-03-22 15:19:54 +00:00
tor - > isDirty = false ;
2009-08-13 14:47:56 +00:00
tr_torrentSaveResume ( tor ) ;
}
}
2009-01-12 19:58:16 +00:00
static void
stopTorrent ( void * vtor )
{
tr_torrent * tor = vtor ;
2010-04-14 13:36:43 +00:00
tr_torinf ( tor , " Pausing " ) ;
2008-09-23 19:11:04 +00:00
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2011-01-18 23:44:36 +00:00
tr_torrentLock ( tor ) ;
2008-02-15 16:00:46 +00:00
tr_verifyRemove ( tor ) ;
2011-08-02 03:59:54 +00:00
torrentSetQueued ( tor , false ) ;
2009-01-13 21:00:05 +00:00
tr_peerMgrStopTorrent ( tor ) ;
2009-09-25 21:05:59 +00:00
tr_announcerTorrentStopped ( tor ) ;
2010-06-19 14:25:11 +00:00
tr_cacheFlushTorrent ( tor - > session - > cache , tor ) ;
2007-11-21 16:16:59 +00:00
2009-10-23 03:41:36 +00:00
tr_fdTorrentClose ( tor - > session , tor - > uniqueId ) ;
2009-08-07 05:29:37 +00:00
2009-08-13 14:47:56 +00:00
if ( ! tor - > isDeleting )
tr_torrentSave ( tor ) ;
2011-01-18 23:44:36 +00:00
tr_torrentUnlock ( tor ) ;
2007-10-04 19:58:30 +00:00
}
void
tr_torrentStop ( tr_torrent * tor )
{
2009-04-19 16:21:27 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2009-01-30 00:41:08 +00:00
if ( tr_isTorrent ( tor ) )
2008-06-10 19:25:18 +00:00
{
2010-01-04 09:05:02 +00:00
tr_sessionLock ( tor - > session ) ;
2007-10-04 19:58:30 +00:00
2008-06-10 19:25:18 +00:00
tor - > isRunning = 0 ;
2010-06-25 06:57:34 +00:00
tor - > isStopping = 0 ;
2009-10-21 02:45:49 +00:00
tr_torrentSetDirty ( tor ) ;
2008-10-02 15:53:33 +00:00
tr_runInEventThread ( tor - > session , stopTorrent , tor ) ;
2007-06-26 18:45:03 +00:00
2010-01-04 09:05:02 +00:00
tr_sessionUnlock ( tor - > session ) ;
2008-06-10 19:25:18 +00:00
}
2007-09-20 16:32:01 +00:00
}
2007-06-26 18:45:03 +00:00
2007-10-04 19:58:30 +00:00
static void
closeTorrent ( void * vtor )
{
2009-04-04 05:29:08 +00:00
tr_benc * d ;
2007-10-04 19:58:30 +00:00
tr_torrent * tor = vtor ;
2008-09-23 19:11:04 +00:00
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2009-04-04 05:29:08 +00:00
d = tr_bencListAddDict ( & tor - > session - > removedTorrents , 2 ) ;
tr_bencDictAddInt ( d , " id " , tor - > uniqueId ) ;
2009-11-26 18:47:08 +00:00
tr_bencDictAddInt ( d , " date " , tr_time ( ) ) ;
2009-04-04 05:29:08 +00:00
2010-10-11 21:44:46 +00:00
tr_torinf ( tor , " %s " , _ ( " Removing torrent " ) ) ;
2010-04-17 04:07:56 +00:00
2007-10-04 19:58:30 +00:00
stopTorrent ( tor ) ;
2009-08-15 21:09:06 +00:00
2008-09-23 19:11:04 +00:00
if ( tor - > isDeleting )
{
2008-10-02 15:53:33 +00:00
tr_metainfoRemoveSaved ( tor - > session , & tor - > info ) ;
2008-05-22 23:11:21 +00:00
tr_torrentRemoveResume ( tor ) ;
}
2009-08-15 21:09:06 +00:00
tor - > isRunning = 0 ;
2007-10-04 19:58:30 +00:00
freeTorrent ( tor ) ;
}
2007-09-20 16:32:01 +00:00
void
2008-05-21 17:14:58 +00:00
tr_torrentFree ( tr_torrent * tor )
2007-09-20 16:32:01 +00:00
{
2009-01-30 00:41:08 +00:00
if ( tr_isTorrent ( tor ) )
2008-01-16 17:57:13 +00:00
{
2008-12-14 11:21:11 +00:00
tr_session * session = tor - > session ;
2009-01-30 00:41:08 +00:00
assert ( tr_isSession ( session ) ) ;
2010-01-04 09:05:02 +00:00
tr_sessionLock ( session ) ;
2007-10-02 02:59:07 +00:00
2008-10-20 17:54:56 +00:00
tr_torrentClearCompletenessCallback ( tor ) ;
2008-12-14 11:21:11 +00:00
tr_runInEventThread ( session , closeTorrent , tor ) ;
2007-10-02 02:59:07 +00:00
2010-01-04 09:05:02 +00:00
tr_sessionUnlock ( session ) ;
2008-01-16 17:57:13 +00:00
}
2007-09-20 16:32:01 +00:00
}
2007-06-26 18:45:03 +00:00
2010-12-16 03:38:07 +00:00
struct remove_data
{
tr_torrent * tor ;
2011-03-22 15:19:54 +00:00
bool deleteFlag ;
2010-12-16 03:38:07 +00:00
tr_fileFunc * deleteFunc ;
} ;
2010-12-16 03:41:46 +00:00
static void tr_torrentDeleteLocalData ( tr_torrent * , tr_fileFunc ) ;
2010-12-16 03:38:07 +00:00
static void
removeTorrent ( void * vdata )
{
struct remove_data * data = vdata ;
if ( data - > deleteFlag )
tr_torrentDeleteLocalData ( data - > tor , data - > deleteFunc ) ;
tr_torrentClearCompletenessCallback ( data - > tor ) ;
closeTorrent ( data - > tor ) ;
tr_free ( data ) ;
}
2008-02-19 05:03:56 +00:00
void
2010-12-16 03:38:07 +00:00
tr_torrentRemove ( tr_torrent * tor ,
2011-03-22 15:19:54 +00:00
bool deleteFlag ,
2010-12-16 03:38:07 +00:00
tr_fileFunc deleteFunc )
2008-02-19 05:03:56 +00:00
{
2010-12-16 03:38:07 +00:00
struct remove_data * data ;
2009-01-30 00:41:08 +00:00
2010-12-16 03:38:07 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-02-19 05:03:56 +00:00
tor - > isDeleting = 1 ;
2010-12-16 03:38:07 +00:00
data = tr_new0 ( struct remove_data , 1 ) ;
data - > tor = tor ;
data - > deleteFlag = deleteFlag ;
data - > deleteFunc = deleteFunc ;
tr_runInEventThread ( tor - > session , removeTorrent , data ) ;
2008-02-19 05:03:56 +00:00
}
2007-09-28 14:51:34 +00:00
/**
* * * Completeness
* */
2008-03-18 16:56:01 +00:00
static const char *
getCompletionString ( int type )
{
switch ( type )
{
2008-03-19 20:07:27 +00:00
/* Translators: this is a minor point that's safe to skip over, but FYI:
" Complete " and " Done " are specific , different terms in Transmission :
" Complete " means we ' ve downloaded every file in the torrent .
2008-09-23 19:11:04 +00:00
" Done " means we ' re done downloading the files we wanted , but NOT all
that exist */
2008-11-30 01:52:45 +00:00
case TR_PARTIAL_SEED :
2008-09-23 19:11:04 +00:00
return _ ( " Done " ) ;
2008-11-30 01:52:45 +00:00
case TR_SEED :
2008-09-23 19:11:04 +00:00
return _ ( " Complete " ) ;
default :
return _ ( " Incomplete " ) ;
2008-03-18 16:56:01 +00:00
}
}
2007-09-28 14:51:34 +00:00
static void
2008-10-20 17:54:56 +00:00
fireCompletenessChange ( tr_torrent * tor ,
2010-06-25 06:57:34 +00:00
tr_completeness status ,
2011-03-22 15:19:54 +00:00
bool wasRunning )
2007-09-28 14:51:34 +00:00
{
2008-11-30 01:52:45 +00:00
assert ( ( status = = TR_LEECH )
| | ( status = = TR_SEED )
| | ( status = = TR_PARTIAL_SEED ) ) ;
2007-09-28 14:51:34 +00:00
2008-10-20 17:54:56 +00:00
if ( tor - > completeness_func )
2010-06-25 15:39:17 +00:00
tor - > completeness_func ( tor , status , wasRunning ,
2010-06-25 06:57:34 +00:00
tor - > completeness_func_user_data ) ;
2007-09-28 14:51:34 +00:00
}
void
2008-10-20 17:54:56 +00:00
tr_torrentSetCompletenessCallback ( tr_torrent * tor ,
tr_torrent_completeness_func func ,
void * user_data )
2007-09-28 14:51:34 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-10-20 17:54:56 +00:00
tor - > completeness_func = func ;
tor - > completeness_func_user_data = user_data ;
2007-09-28 14:51:34 +00:00
}
2009-11-26 17:58:44 +00:00
void
tr_torrentClearCompletenessCallback ( tr_torrent * torrent )
{
tr_torrentSetCompletenessCallback ( torrent , NULL , NULL ) ;
}
2009-02-13 18:23:56 +00:00
void
tr_torrentSetRatioLimitHitCallback ( tr_torrent * tor ,
tr_torrent_ratio_limit_hit_func func ,
void * user_data )
{
assert ( tr_isTorrent ( tor ) ) ;
tor - > ratio_limit_hit_func = func ;
tor - > ratio_limit_hit_func_user_data = user_data ;
}
void
tr_torrentClearRatioLimitHitCallback ( tr_torrent * torrent )
{
tr_torrentSetRatioLimitHitCallback ( torrent , NULL , NULL ) ;
}
2010-07-24 03:19:41 +00:00
void
2010-07-24 02:57:39 +00:00
tr_torrentSetIdleLimitHitCallback ( tr_torrent * tor ,
tr_torrent_idle_limit_hit_func func ,
void * user_data )
2010-07-16 03:12:57 +00:00
{
assert ( tr_isTorrent ( tor ) ) ;
2010-07-24 02:57:39 +00:00
tor - > idle_limit_hit_func = func ;
tor - > idle_limit_hit_func_user_data = user_data ;
2010-07-16 03:12:57 +00:00
}
void
2010-07-24 02:57:39 +00:00
tr_torrentClearIdleLimitHitCallback ( tr_torrent * torrent )
2010-07-16 03:12:57 +00:00
{
2010-07-24 02:57:39 +00:00
tr_torrentSetIdleLimitHitCallback ( torrent , NULL , NULL ) ;
2010-07-16 03:12:57 +00:00
}
2010-12-15 15:35:06 +00:00
static void
onSigCHLD ( int i UNUSED )
{
2011-01-30 01:41:48 +00:00
waitpid ( - 1 , NULL , WNOHANG ) ;
2010-12-15 15:35:06 +00:00
}
2010-06-22 00:12:52 +00:00
static void
2010-12-15 04:35:41 +00:00
torrentCallScript ( const tr_torrent * tor , const char * script )
2010-06-22 00:12:52 +00:00
{
2010-12-15 04:35:41 +00:00
char timeStr [ 128 ] ;
const time_t now = tr_time ( ) ;
2010-05-08 22:42:28 +00:00
2010-12-15 04:35:41 +00:00
tr_strlcpy ( timeStr , ctime ( & now ) , sizeof ( timeStr ) ) ;
* strchr ( timeStr , ' \n ' ) = ' \0 ' ;
2010-05-08 22:42:28 +00:00
if ( script & & * script )
{
2010-12-29 21:00:07 +00:00
int i ;
2010-12-15 04:35:41 +00:00
char * cmd [ ] = { tr_strdup ( script ) , NULL } ;
2010-12-15 14:55:20 +00:00
char * env [ ] = {
tr_strdup_printf ( " TR_APP_VERSION=%s " , SHORT_VERSION_STRING ) ,
tr_strdup_printf ( " TR_TIME_LOCALTIME=%s " , timeStr ) ,
tr_strdup_printf ( " TR_TORRENT_DIR=%s " , tor - > currentDir ) ,
tr_strdup_printf ( " TR_TORRENT_ID=%d " , tr_torrentId ( tor ) ) ,
tr_strdup_printf ( " TR_TORRENT_HASH=%s " , tor - > info . hashString ) ,
tr_strdup_printf ( " TR_TORRENT_NAME=%s " , tr_torrentName ( tor ) ) ,
NULL } ;
2011-03-04 23:26:10 +00:00
tr_torinf ( tor , " Calling script \" %s \" " , script ) ;
2011-01-30 01:41:48 +00:00
# ifdef WIN32
_spawnvpe ( _P_NOWAIT , script , ( const char * ) cmd , env ) ;
# else
2010-12-15 15:35:06 +00:00
signal ( SIGCHLD , onSigCHLD ) ;
2010-12-15 14:55:20 +00:00
2010-12-15 04:35:41 +00:00
if ( ! fork ( ) )
{
2011-03-16 18:11:48 +00:00
for ( i = 0 ; env [ i ] ; + + i )
putenv ( env [ i ] ) ;
execvp ( script , cmd ) ;
2010-12-15 04:35:41 +00:00
_exit ( 0 ) ;
}
2011-01-30 01:41:48 +00:00
# endif
2010-12-29 21:00:07 +00:00
for ( i = 0 ; cmd [ i ] ; + + i ) tr_free ( cmd [ i ] ) ;
for ( i = 0 ; env [ i ] ; + + i ) tr_free ( env [ i ] ) ;
2010-05-08 22:42:28 +00:00
}
}
2007-09-23 13:53:44 +00:00
void
tr_torrentRecheckCompleteness ( tr_torrent * tor )
2007-09-20 16:32:01 +00:00
{
2008-10-20 17:54:56 +00:00
tr_completeness completeness ;
2007-07-15 04:19:39 +00:00
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2007-09-20 16:32:01 +00:00
tr_torrentLock ( tor ) ;
2007-01-21 06:42:05 +00:00
2009-01-02 17:01:55 +00:00
completeness = tr_cpGetStatus ( & tor - > completion ) ;
2008-03-18 16:56:01 +00:00
2008-10-20 17:54:56 +00:00
if ( completeness ! = tor - > completeness )
2008-03-18 16:56:01 +00:00
{
const int recentChange = tor - > downloadedCur ! = 0 ;
2011-03-22 15:19:54 +00:00
const bool wasLeeching = ! tr_torrentIsSeed ( tor ) ;
const bool wasRunning = tor - > isRunning ;
2008-03-18 16:56:01 +00:00
if ( recentChange )
{
2008-04-21 15:22:54 +00:00
tr_torinf ( tor , _ ( " State changed from \" %1$s \" to \" %2$s \" " ) ,
2008-10-20 17:54:56 +00:00
getCompletionString ( tor - > completeness ) ,
getCompletionString ( completeness ) ) ;
2008-03-18 16:56:01 +00:00
}
2008-10-20 17:54:56 +00:00
tor - > completeness = completeness ;
2009-10-23 03:41:36 +00:00
tr_fdTorrentClose ( tor - > session , tor - > uniqueId ) ;
2009-10-19 05:05:00 +00:00
2010-04-29 23:35:44 +00:00
if ( tr_torrentIsSeed ( tor ) )
{
2010-06-03 16:37:50 +00:00
if ( recentChange )
{
tr_announcerTorrentCompleted ( tor ) ;
tor - > doneDate = tor - > anyDate = tr_time ( ) ;
}
2010-09-25 00:34:15 +00:00
if ( wasLeeching & & wasRunning )
{
/* clear interested flag on all peers */
tr_peerMgrClearInterest ( tor ) ;
/* if completeness was TR_LEECH then the seed limit check will have been skipped in bandwidthPulse */
tr_torrentCheckSeedLimit ( tor ) ;
}
2010-04-29 23:35:44 +00:00
if ( tor - > currentDir = = tor - > incompleteDir )
2011-03-22 15:19:54 +00:00
tr_torrentSetLocation ( tor , tor - > downloadDir , true , NULL , NULL ) ;
2010-05-08 22:42:28 +00:00
if ( tr_sessionIsTorrentDoneScriptEnabled ( tor - > session ) )
torrentCallScript ( tor , tr_sessionGetTorrentDoneScript ( tor - > session ) ) ;
2010-04-29 23:35:44 +00:00
}
2009-10-19 05:05:00 +00:00
2011-06-19 03:31:41 +00:00
fireCompletenessChange ( tor , completeness , wasRunning ) ;
2008-03-18 16:56:01 +00:00
2009-08-07 05:29:37 +00:00
tr_torrentSetDirty ( tor ) ;
2007-01-19 15:24:20 +00:00
}
2008-03-18 16:56:01 +00:00
2007-09-20 16:32:01 +00:00
tr_torrentUnlock ( tor ) ;
2007-01-19 08:36:49 +00:00
}
2009-11-26 17:58:44 +00:00
/***
* * * *
* * */
static void
tr_torrentFireMetadataCompleted ( tr_torrent * tor )
{
assert ( tr_isTorrent ( tor ) ) ;
if ( tor - > metadata_func )
tor - > metadata_func ( tor , tor - > metadata_func_user_data ) ;
}
void
tr_torrentSetMetadataCallback ( tr_torrent * tor ,
tr_torrent_metadata_func func ,
void * user_data )
{
assert ( tr_isTorrent ( tor ) ) ;
tor - > metadata_func = func ;
tor - > metadata_func_user_data = user_data ;
}
2007-07-16 19:57:34 +00:00
/**
* * * File priorities
* */
2007-06-18 03:40:41 +00:00
2007-12-25 06:37:21 +00:00
void
2008-09-23 19:11:04 +00:00
tr_torrentInitFilePriority ( tr_torrent * tor ,
tr_file_index_t fileIndex ,
tr_priority_t priority )
2007-06-18 03:40:41 +00:00
{
2008-03-22 18:10:59 +00:00
tr_piece_index_t i ;
2008-09-23 19:11:04 +00:00
tr_file * file ;
2007-06-18 03:40:41 +00:00
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-03-22 18:10:59 +00:00
assert ( fileIndex < tor - > info . fileCount ) ;
2009-04-18 23:17:30 +00:00
assert ( tr_isPriority ( priority ) ) ;
2007-06-18 03:40:41 +00:00
file = & tor - > info . files [ fileIndex ] ;
file - > priority = priority ;
2008-09-23 19:11:04 +00:00
for ( i = file - > firstPiece ; i < = file - > lastPiece ; + + i )
2009-04-11 06:58:14 +00:00
tor - > info . pieces [ i ] . priority = calculatePiecePriority ( tor , i , fileIndex ) ;
2007-06-18 03:40:41 +00:00
}
2007-07-10 03:12:46 +00:00
void
2010-05-12 03:03:29 +00:00
tr_torrentSetFilePriorities ( tr_torrent * tor ,
const tr_file_index_t * files ,
tr_file_index_t fileCount ,
tr_priority_t priority )
2007-07-10 03:12:46 +00:00
{
2008-03-22 18:10:59 +00:00
tr_file_index_t i ;
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2007-10-19 23:44:01 +00:00
tr_torrentLock ( tor ) ;
2008-09-23 19:11:04 +00:00
for ( i = 0 ; i < fileCount ; + + i )
2010-01-03 17:21:10 +00:00
if ( files [ i ] < tor - > info . fileCount )
tr_torrentInitFilePriority ( tor , files [ i ] , priority ) ;
2009-08-07 05:29:37 +00:00
tr_torrentSetDirty ( tor ) ;
2009-11-08 23:20:00 +00:00
tr_peerMgrRebuildRequests ( tor ) ;
2007-10-19 23:44:01 +00:00
tr_torrentUnlock ( tor ) ;
2007-07-10 03:12:46 +00:00
}
2007-06-18 03:40:41 +00:00
tr_priority_t *
2007-09-20 16:32:01 +00:00
tr_torrentGetFilePriorities ( const tr_torrent * tor )
2007-06-18 03:40:41 +00:00
{
2008-03-22 18:10:59 +00:00
tr_file_index_t i ;
2007-06-26 18:45:03 +00:00
tr_priority_t * p ;
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2007-09-20 16:32:01 +00:00
tr_torrentLock ( tor ) ;
2007-06-27 05:14:38 +00:00
p = tr_new0 ( tr_priority_t , tor - > info . fileCount ) ;
2008-09-23 19:11:04 +00:00
for ( i = 0 ; i < tor - > info . fileCount ; + + i )
2007-06-18 03:40:41 +00:00
p [ i ] = tor - > info . files [ i ] . priority ;
2007-09-20 16:32:01 +00:00
tr_torrentUnlock ( tor ) ;
2007-06-26 18:45:03 +00:00
2007-06-18 03:40:41 +00:00
return p ;
}
2007-07-10 03:12:46 +00:00
2007-07-16 19:57:34 +00:00
/**
* * * File DND
* */
2007-10-19 23:23:21 +00:00
static void
2009-03-01 13:56:22 +00:00
setFileDND ( tr_torrent * tor , tr_file_index_t fileIndex , int doDownload )
2007-07-10 03:12:46 +00:00
{
2010-07-01 05:14:34 +00:00
const int8_t dnd = ! doDownload ;
2010-07-01 05:39:54 +00:00
tr_piece_index_t firstPiece ;
int8_t firstPieceDND ;
tr_piece_index_t lastPiece ;
int8_t lastPieceDND ;
2008-09-23 19:11:04 +00:00
tr_file_index_t i ;
2011-02-03 22:53:02 +00:00
tr_file * file = & tor - > info . files [ fileIndex ] ;
2007-07-10 03:41:16 +00:00
2007-07-16 23:52:05 +00:00
file - > dnd = dnd ;
2007-07-16 19:57:34 +00:00
firstPiece = file - > firstPiece ;
lastPiece = file - > lastPiece ;
/* can't set the first piece to DND unless
every file using that piece is DND */
firstPieceDND = dnd ;
2008-09-23 19:11:04 +00:00
if ( fileIndex > 0 )
{
for ( i = fileIndex - 1 ; firstPieceDND ; - - i )
{
2008-03-24 16:10:04 +00:00
if ( tor - > info . files [ i ] . lastPiece ! = firstPiece )
break ;
firstPieceDND = tor - > info . files [ i ] . dnd ;
if ( ! i )
break ;
}
2007-07-16 19:57:34 +00:00
}
/* can't set the last piece to DND unless
every file using that piece is DND */
lastPieceDND = dnd ;
2008-09-23 19:11:04 +00:00
for ( i = fileIndex + 1 ; lastPieceDND & & i < tor - > info . fileCount ; + + i )
{
2007-07-16 19:57:34 +00:00
if ( tor - > info . files [ i ] . firstPiece ! = lastPiece )
break ;
lastPieceDND = tor - > info . files [ i ] . dnd ;
}
if ( firstPiece = = lastPiece )
{
tor - > info . pieces [ firstPiece ] . dnd = firstPieceDND & & lastPieceDND ;
}
else
{
2008-03-22 18:10:59 +00:00
tr_piece_index_t pp ;
2007-07-16 19:57:34 +00:00
tor - > info . pieces [ firstPiece ] . dnd = firstPieceDND ;
tor - > info . pieces [ lastPiece ] . dnd = lastPieceDND ;
2008-09-23 19:11:04 +00:00
for ( pp = firstPiece + 1 ; pp < lastPiece ; + + pp )
2008-03-22 18:10:59 +00:00
tor - > info . pieces [ pp ] . dnd = dnd ;
2007-07-16 19:57:34 +00:00
}
2007-07-10 03:41:16 +00:00
}
void
2010-05-12 03:03:29 +00:00
tr_torrentInitFileDLs ( tr_torrent * tor ,
const tr_file_index_t * files ,
tr_file_index_t fileCount ,
2011-03-22 15:19:54 +00:00
bool doDownload )
2007-07-10 03:41:16 +00:00
{
2008-03-22 18:10:59 +00:00
tr_file_index_t i ;
2008-09-23 19:11:04 +00:00
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2007-10-19 23:23:21 +00:00
tr_torrentLock ( tor ) ;
2009-03-01 13:56:22 +00:00
for ( i = 0 ; i < fileCount ; + + i )
2010-01-03 17:21:10 +00:00
if ( files [ i ] < tor - > info . fileCount )
setFileDND ( tor , files [ i ] , doDownload ) ;
2009-03-01 13:56:22 +00:00
tr_cpInvalidateDND ( & tor - > completion ) ;
2007-10-19 23:23:21 +00:00
tr_torrentUnlock ( tor ) ;
2007-07-10 03:12:46 +00:00
}
2007-07-19 11:54:37 +00:00
2007-12-22 17:30:31 +00:00
void
2010-05-12 03:03:29 +00:00
tr_torrentSetFileDLs ( tr_torrent * tor ,
const tr_file_index_t * files ,
tr_file_index_t fileCount ,
2011-03-22 15:19:54 +00:00
bool doDownload )
2007-12-22 17:30:31 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2007-12-22 17:30:31 +00:00
tr_torrentLock ( tor ) ;
2009-11-08 23:20:00 +00:00
2007-12-22 17:30:31 +00:00
tr_torrentInitFileDLs ( tor , files , fileCount , doDownload ) ;
2009-08-07 05:29:37 +00:00
tr_torrentSetDirty ( tor ) ;
2009-11-08 23:20:00 +00:00
tr_peerMgrRebuildRequests ( tor ) ;
2007-12-22 17:30:31 +00:00
tr_torrentUnlock ( tor ) ;
}
2007-07-19 11:54:37 +00:00
/***
* * * *
* * */
2009-04-18 23:17:30 +00:00
tr_priority_t
tr_torrentGetPriority ( const tr_torrent * tor )
{
assert ( tr_isTorrent ( tor ) ) ;
2011-03-31 14:53:22 +00:00
return tor - > bandwidth . priority ;
2009-04-18 23:17:30 +00:00
}
void
tr_torrentSetPriority ( tr_torrent * tor , tr_priority_t priority )
{
assert ( tr_isTorrent ( tor ) ) ;
assert ( tr_isPriority ( priority ) ) ;
2011-03-31 14:53:22 +00:00
if ( tor - > bandwidth . priority ! = priority )
2009-08-14 14:41:59 +00:00
{
2011-03-31 14:53:22 +00:00
tor - > bandwidth . priority = priority ;
2009-08-07 05:29:37 +00:00
2009-08-14 14:41:59 +00:00
tr_torrentSetDirty ( tor ) ;
}
2009-04-18 23:17:30 +00:00
}
/***
* * * *
* * */
2007-12-20 21:44:16 +00:00
void
2008-09-23 19:11:04 +00:00
tr_torrentSetPeerLimit ( tr_torrent * tor ,
uint16_t maxConnectedPeers )
2007-12-20 21:44:16 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2009-10-21 23:32:02 +00:00
if ( tor - > maxConnectedPeers ! = maxConnectedPeers )
{
tor - > maxConnectedPeers = maxConnectedPeers ;
tr_torrentSetDirty ( tor ) ;
}
2007-12-20 21:44:16 +00:00
}
2007-12-22 04:11:17 +00:00
uint16_t
2008-09-23 19:11:04 +00:00
tr_torrentGetPeerLimit ( const tr_torrent * tor )
2007-12-22 04:00:19 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2007-12-22 04:00:19 +00:00
return tor - > maxConnectedPeers ;
}
2007-12-20 21:44:16 +00:00
/***
* * * *
* * */
2011-02-23 03:54:04 +00:00
void
2011-03-04 23:26:10 +00:00
tr_torrentGetBlockLocation ( const tr_torrent * tor ,
2011-02-23 03:54:04 +00:00
tr_block_index_t block ,
tr_piece_index_t * piece ,
uint32_t * offset ,
uint32_t * length )
{
uint64_t pos = block ;
pos * = tor - > blockSize ;
* piece = pos / tor - > info . pieceSize ;
* offset = pos - ( * piece * tor - > info . pieceSize ) ;
* length = tr_torBlockCountBytes ( tor , block ) ;
}
2008-03-22 18:10:59 +00:00
tr_block_index_t
2008-09-23 19:11:04 +00:00
_tr_block ( const tr_torrent * tor ,
tr_piece_index_t index ,
uint32_t offset )
2007-07-19 11:54:37 +00:00
{
2008-03-22 18:10:59 +00:00
tr_block_index_t ret ;
2008-09-23 19:11:04 +00:00
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-03-22 18:10:59 +00:00
ret = index ;
2009-01-30 00:41:08 +00:00
ret * = ( tor - > info . pieceSize / tor - > blockSize ) ;
2008-03-22 18:10:59 +00:00
ret + = offset / tor - > blockSize ;
return ret ;
2007-07-19 11:54:37 +00:00
}
2007-09-23 23:38:39 +00:00
2011-03-22 15:19:54 +00:00
bool
2008-03-06 13:24:44 +00:00
tr_torrentReqIsValid ( const tr_torrent * tor ,
2008-03-22 18:10:59 +00:00
tr_piece_index_t index ,
2008-03-06 13:24:44 +00:00
uint32_t offset ,
uint32_t length )
{
int err = 0 ;
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-03-22 18:10:59 +00:00
if ( index > = tor - > info . pieceCount )
2008-03-06 13:24:44 +00:00
err = 1 ;
2008-10-27 17:35:22 +00:00
else if ( length < 1 )
2008-03-06 13:24:44 +00:00
err = 2 ;
2008-10-27 04:39:30 +00:00
else if ( ( offset + length ) > tr_torPieceCountBytes ( tor , index ) )
2008-03-06 13:24:44 +00:00
err = 3 ;
2008-10-27 04:39:30 +00:00
else if ( length > MAX_BLOCK_SIZE )
2008-03-06 13:24:44 +00:00
err = 4 ;
2008-10-27 04:39:30 +00:00
else if ( tr_pieceOffset ( tor , index , offset , length ) > tor - > info . totalSize )
err = 5 ;
2008-03-06 13:24:44 +00:00
2009-08-16 21:09:08 +00:00
if ( err ) tr_tordbg ( tor , " index %lu offset %lu length %lu err %d \n " ,
( unsigned long ) index ,
( unsigned long ) offset ,
( unsigned long ) length ,
err ) ;
2008-06-09 22:53:45 +00:00
2008-03-06 13:24:44 +00:00
return ! err ;
}
2007-09-23 23:38:39 +00:00
uint64_t
2008-03-22 18:10:59 +00:00
tr_pieceOffset ( const tr_torrent * tor ,
tr_piece_index_t index ,
uint32_t offset ,
uint32_t length )
2007-09-23 23:38:39 +00:00
{
uint64_t ret ;
2008-09-23 19:11:04 +00:00
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2007-09-23 23:38:39 +00:00
ret = tor - > info . pieceSize ;
ret * = index ;
2008-03-22 18:10:59 +00:00
ret + = offset ;
2007-09-23 23:38:39 +00:00
ret + = length ;
return ret ;
}
2008-01-02 18:05:05 +00:00
2011-02-23 03:54:04 +00:00
void
tr_torGetFileBlockRange ( const tr_torrent * tor ,
const tr_file_index_t file ,
tr_block_index_t * first ,
tr_block_index_t * last )
{
const tr_file * f = & tor - > info . files [ file ] ;
uint64_t offset = f - > offset ;
* first = offset / tor - > blockSize ;
if ( ! f - > length )
* last = * first ;
else {
offset + = f - > length - 1 ;
* last = offset / tor - > blockSize ;
}
}
void
tr_torGetPieceBlockRange ( const tr_torrent * tor ,
const tr_piece_index_t piece ,
tr_block_index_t * first ,
tr_block_index_t * last )
{
uint64_t offset = tor - > info . pieceSize ;
offset * = piece ;
* first = offset / tor - > blockSize ;
offset + = ( tr_torPieceCountBytes ( tor , piece ) - 1 ) ;
* last = offset / tor - > blockSize ;
}
2008-01-02 18:05:05 +00:00
/***
* * * *
* * */
void
2010-12-09 20:43:23 +00:00
tr_torrentSetPieceChecked ( tr_torrent * tor , tr_piece_index_t pieceIndex )
2008-01-02 18:05:05 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2010-12-09 20:43:23 +00:00
assert ( pieceIndex < tor - > info . pieceCount ) ;
2009-01-30 00:41:08 +00:00
2010-12-09 20:43:23 +00:00
tor - > info . pieces [ pieceIndex ] . timeChecked = tr_time ( ) ;
2008-01-02 18:05:05 +00:00
}
void
2010-12-09 20:43:23 +00:00
tr_torrentSetChecked ( tr_torrent * tor , time_t when )
2008-01-02 18:05:05 +00:00
{
2010-12-09 20:43:23 +00:00
tr_piece_index_t i , n ;
2008-01-02 18:05:05 +00:00
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2010-12-09 20:43:23 +00:00
for ( i = 0 , n = tor - > info . pieceCount ; i ! = n ; + + i )
tor - > info . pieces [ i ] . timeChecked = when ;
2008-01-02 18:05:05 +00:00
}
2011-03-22 15:19:54 +00:00
bool
2010-12-09 20:43:23 +00:00
tr_torrentCheckPiece ( tr_torrent * tor , tr_piece_index_t pieceIndex )
2008-02-01 01:38:55 +00:00
{
2011-03-22 15:19:54 +00:00
const bool pass = tr_ioTestPiece ( tor , pieceIndex ) ;
2009-01-30 00:41:08 +00:00
2011-01-18 02:17:47 +00:00
tr_deeplog_tor ( tor , " [LAZY] tr_torrentCheckPiece tested piece %zu, pass==%d " , ( size_t ) pieceIndex , ( int ) pass ) ;
2010-12-09 20:43:23 +00:00
tr_torrentSetHasPiece ( tor , pieceIndex , pass ) ;
tr_torrentSetPieceChecked ( tor , pieceIndex ) ;
tor - > anyDate = tr_time ( ) ;
tr_torrentSetDirty ( tor ) ;
2009-01-30 00:41:08 +00:00
2010-12-09 20:43:23 +00:00
return pass ;
2008-01-02 18:05:05 +00:00
}
2008-04-14 11:52:50 +00:00
2011-02-02 21:17:16 +00:00
time_t
tr_torrentGetFileMTime ( const tr_torrent * tor , tr_file_index_t i )
2008-04-14 11:52:50 +00:00
{
2010-12-09 20:43:23 +00:00
time_t mtime = 0 ;
2011-04-28 18:40:46 +00:00
if ( ! tr_fdFileGetCachedMTime ( tor - > session , tor - > uniqueId , i , & mtime ) )
tr_torrentFindFile2 ( tor , i , NULL , NULL , & mtime ) ;
2010-12-09 20:43:23 +00:00
return mtime ;
}
2011-03-22 15:19:54 +00:00
bool
2010-12-09 20:43:23 +00:00
tr_torrentPieceNeedsCheck ( const tr_torrent * tor , tr_piece_index_t p )
{
uint64_t unused ;
tr_file_index_t f ;
const tr_info * inf = tr_torrentInfo ( tor ) ;
2010-12-12 16:43:19 +00:00
/* if we've never checked this piece, then it needs to be checked */
2010-12-21 23:09:26 +00:00
if ( ! inf - > pieces [ p ] . timeChecked )
2011-03-22 15:19:54 +00:00
return true ;
2010-12-09 20:43:23 +00:00
/* If we think we've completed one of the files in this piece,
* but it ' s been modified since we last checked it ,
* then it needs to be rechecked */
tr_ioFindFileLocation ( tor , p , 0 , & f , & unused ) ;
2010-12-21 23:09:26 +00:00
for ( ; f < inf - > fileCount & & pieceHasFile ( p , & inf - > files [ f ] ) ; + + f )
if ( tr_cpFileIsComplete ( & tor - > completion , f ) )
2011-02-02 21:17:16 +00:00
if ( tr_torrentGetFileMTime ( tor , f ) > inf - > pieces [ p ] . timeChecked )
2011-03-22 15:19:54 +00:00
return true ;
2008-04-14 11:52:50 +00:00
2011-03-22 15:19:54 +00:00
return false ;
2008-04-14 11:52:50 +00:00
}
2008-06-01 01:40:32 +00:00
/***
* * * *
* * */
2010-06-23 16:06:15 +00:00
static int
compareTrackerByTier ( const void * va , const void * vb )
{
const tr_tracker_info * a = va ;
const tr_tracker_info * b = vb ;
/* sort by tier */
if ( a - > tier ! = b - > tier )
return a - > tier - b - > tier ;
/* get the effects of a stable sort by comparing the two elements' addresses */
return a - b ;
}
2011-03-22 15:19:54 +00:00
bool
2010-01-04 20:14:25 +00:00
tr_torrentSetAnnounceList ( tr_torrent * tor ,
2010-06-23 16:06:15 +00:00
const tr_tracker_info * trackers_in ,
2010-01-04 20:14:25 +00:00
int trackerCount )
2008-06-01 01:40:32 +00:00
{
2009-12-12 04:12:04 +00:00
int i ;
2008-06-12 16:25:36 +00:00
tr_benc metainfo ;
2011-03-22 15:19:54 +00:00
bool ok = true ;
2010-06-23 16:06:15 +00:00
tr_tracker_info * trackers ;
2010-01-04 09:11:27 +00:00
tr_torrentLock ( tor ) ;
2008-06-01 01:40:32 +00:00
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2010-06-23 16:06:15 +00:00
/* ensure the trackers' tiers are in ascending order */
trackers = tr_memdup ( trackers_in , sizeof ( tr_tracker_info ) * trackerCount ) ;
qsort ( trackers , trackerCount , sizeof ( tr_tracker_info ) , compareTrackerByTier ) ;
2009-10-10 19:16:21 +00:00
/* look for bad URLs */
2010-01-04 09:11:27 +00:00
for ( i = 0 ; ok & & i < trackerCount ; + + i )
2010-02-20 15:57:05 +00:00
if ( ! tr_urlIsValidTracker ( trackers [ i ] . announce ) )
2011-03-22 15:19:54 +00:00
ok = false ;
2009-10-10 19:16:21 +00:00
2008-06-01 01:40:32 +00:00
/* save to the .torrent file */
2010-01-04 09:11:27 +00:00
if ( ok & & ! tr_bencLoadFile ( & metainfo , TR_FMT_BENC , tor - > info . torrent ) )
2008-06-01 01:40:32 +00:00
{
2011-03-22 15:19:54 +00:00
bool hasInfo ;
2010-02-02 22:45:22 +00:00
tr_info tmpInfo ;
2008-06-01 01:40:32 +00:00
/* remove the old fields */
tr_bencDictRemove ( & metainfo , " announce " ) ;
tr_bencDictRemove ( & metainfo , " announce-list " ) ;
/* add the new fields */
2009-11-25 18:57:54 +00:00
if ( trackerCount > 0 )
{
tr_bencDictAddStr ( & metainfo , " announce " , trackers [ 0 ] . announce ) ;
}
if ( trackerCount > 1 )
{
int i ;
int prevTier = - 1 ;
tr_benc * tier = NULL ;
tr_benc * announceList = tr_bencDictAddList ( & metainfo , " announce-list " , 0 ) ;
for ( i = 0 ; i < trackerCount ; + + i ) {
if ( prevTier ! = trackers [ i ] . tier ) {
prevTier = trackers [ i ] . tier ;
tier = tr_bencListAddList ( announceList , 0 ) ;
}
tr_bencListAddStr ( tier , trackers [ i ] . announce ) ;
2008-06-01 01:40:32 +00:00
}
}
/* try to parse it back again, to make sure it's good */
memset ( & tmpInfo , 0 , sizeof ( tr_info ) ) ;
2010-02-02 22:45:22 +00:00
if ( tr_metainfoParse ( tor - > session , & metainfo , & tmpInfo ,
2010-06-16 03:05:23 +00:00
& hasInfo , & tor - > infoDictLength ) )
2008-06-01 01:40:32 +00:00
{
2008-12-02 23:27:45 +00:00
/* it's good, so keep these new trackers and free the old ones */
tr_info swap ;
swap . trackers = tor - > info . trackers ;
swap . trackerCount = tor - > info . trackerCount ;
tor - > info . trackers = tmpInfo . trackers ;
tor - > info . trackerCount = tmpInfo . trackerCount ;
tmpInfo . trackers = swap . trackers ;
tmpInfo . trackerCount = swap . trackerCount ;
tr_metainfoFree ( & tmpInfo ) ;
2009-06-02 01:48:48 +00:00
tr_bencToFile ( & metainfo , TR_FMT_BENC , tor - > info . torrent ) ;
2008-06-01 01:40:32 +00:00
}
2008-09-23 19:11:04 +00:00
/* cleanup */
2008-06-01 01:40:32 +00:00
tr_bencFree ( & metainfo ) ;
2009-10-02 04:54:02 +00:00
2010-05-19 19:02:25 +00:00
/* if we had a tracker-related error on this torrent,
* and that tracker ' s been removed ,
* then clear the error */
if ( ( tor - > error = = TR_STAT_TRACKER_WARNING )
| | ( tor - > error = = TR_STAT_TRACKER_ERROR ) )
{
2011-03-22 15:19:54 +00:00
bool clear = true ;
2010-05-19 19:02:25 +00:00
for ( i = 0 ; clear & & i < trackerCount ; + + i )
if ( ! strcmp ( trackers [ i ] . announce , tor - > errorTracker ) )
2011-03-22 15:19:54 +00:00
clear = false ;
2010-05-19 19:02:25 +00:00
if ( clear )
tr_torrentClearError ( tor ) ;
}
2009-10-02 04:54:02 +00:00
/* tell the announcer to reload this torrent's tracker list */
tr_announcerResetTorrent ( tor - > session - > announcer , tor ) ;
2008-06-01 01:40:32 +00:00
}
2009-10-10 19:16:21 +00:00
2010-01-04 09:11:27 +00:00
tr_torrentUnlock ( tor ) ;
2010-06-23 16:06:15 +00:00
tr_free ( trackers ) ;
2010-01-04 20:14:25 +00:00
return ok ;
2008-06-01 01:40:32 +00:00
}
2008-06-03 19:22:22 +00:00
/**
* * *
* */
void
2008-09-23 19:11:04 +00:00
tr_torrentSetAddedDate ( tr_torrent * tor ,
time_t t )
2008-06-03 19:22:22 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-06-03 19:22:22 +00:00
tor - > addedDate = t ;
2009-04-02 22:59:30 +00:00
tor - > anyDate = MAX ( tor - > anyDate , tor - > addedDate ) ;
2008-06-03 19:22:22 +00:00
}
void
2009-08-14 14:41:59 +00:00
tr_torrentSetActivityDate ( tr_torrent * tor , time_t t )
2008-06-03 19:22:22 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-06-03 19:22:22 +00:00
tor - > activityDate = t ;
2009-04-02 22:59:30 +00:00
tor - > anyDate = MAX ( tor - > anyDate , tor - > activityDate ) ;
2008-06-03 19:22:22 +00:00
}
2008-06-03 19:42:54 +00:00
void
2008-09-23 19:11:04 +00:00
tr_torrentSetDoneDate ( tr_torrent * tor ,
time_t t )
2008-06-03 19:42:54 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2008-06-03 19:42:54 +00:00
tor - > doneDate = t ;
2009-04-02 22:59:30 +00:00
tor - > anyDate = MAX ( tor - > anyDate , tor - > doneDate ) ;
2008-06-03 19:42:54 +00:00
}
2008-09-23 19:11:04 +00:00
2008-11-05 05:56:06 +00:00
/**
* * *
* */
uint64_t
tr_torrentGetBytesLeftToAllocate ( const tr_torrent * tor )
{
2009-10-19 05:05:00 +00:00
tr_file_index_t i ;
2008-11-05 05:56:06 +00:00
uint64_t bytesLeft = 0 ;
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2009-10-19 05:05:00 +00:00
for ( i = 0 ; i < tor - > info . fileCount ; + + i )
2008-11-05 05:56:06 +00:00
{
2009-10-19 05:05:00 +00:00
if ( ! tor - > info . files [ i ] . dnd )
2008-11-05 05:56:06 +00:00
{
2009-10-19 05:05:00 +00:00
struct stat sb ;
const uint64_t length = tor - > info . files [ i ] . length ;
char * path = tr_torrentFindFile ( tor , i ) ;
2008-11-05 05:56:06 +00:00
2009-10-19 05:05:00 +00:00
bytesLeft + = length ;
2008-11-05 05:56:06 +00:00
2009-10-19 05:05:00 +00:00
if ( ( path ! = NULL ) & & ! stat ( path , & sb )
& & S_ISREG ( sb . st_mode )
& & ( ( uint64_t ) sb . st_size < = length ) )
2008-11-05 05:56:06 +00:00
bytesLeft - = sb . st_size ;
tr_free ( path ) ;
}
}
return bytesLeft ;
}
2008-12-23 16:04:11 +00:00
/****
* * * * * Removing the torrent ' s local data
* * * */
2011-07-10 17:34:03 +00:00
static bool
2011-08-11 14:16:29 +00:00
isJunkFile ( const char * base )
2011-07-10 17:34:03 +00:00
{
int i ;
2011-08-11 14:16:29 +00:00
static const char * files [ ] = { " .DS_Store " , " desktop.ini " , " Thumbs.db " } ;
static const int file_count = sizeof ( files ) / sizeof ( files [ 0 ] ) ;
2011-07-10 17:34:03 +00:00
2011-08-11 14:16:29 +00:00
for ( i = 0 ; i < file_count ; + + i )
if ( ! strcmp ( base , files [ i ] ) )
2011-07-10 17:34:03 +00:00
return true ;
2011-08-11 14:16:29 +00:00
# ifdef SYS_DARWIN
2011-07-10 17:34:03 +00:00
/* check for resource forks. <http://support.apple.com/kb/TA20578> */
if ( ! memcmp ( base , " ._ " , 2 ) )
return true ;
2011-08-11 14:16:29 +00:00
# endif
2011-07-10 17:34:03 +00:00
return false ;
}
static void
2011-08-11 14:16:29 +00:00
removeEmptyFoldersAndJunkFiles ( const char * folder )
{
DIR * odir ;
if ( ( odir = opendir ( folder ) ) ) {
struct dirent * d ;
while ( ( d = readdir ( odir ) ) ) {
if ( strcmp ( d - > d_name , " . " ) & & strcmp ( d - > d_name , " .. " ) ) {
struct stat sb ;
char * filename = tr_buildPath ( folder , d - > d_name , NULL ) ;
2011-08-11 21:02:15 +00:00
if ( ! stat ( filename , & sb ) & & S_ISDIR ( sb . st_mode ) )
removeEmptyFoldersAndJunkFiles ( filename ) ;
else if ( isJunkFile ( d - > d_name ) )
remove ( filename ) ;
2011-08-11 14:16:29 +00:00
tr_free ( filename ) ;
2011-07-10 17:34:03 +00:00
}
2008-12-23 16:04:11 +00:00
}
2011-08-11 14:16:29 +00:00
remove ( folder ) ;
closedir ( odir ) ;
2008-12-23 16:04:11 +00:00
}
}
2011-08-11 14:16:29 +00:00
/**
* This convoluted code does something ( seemingly ) simple :
* remove the torrent ' s local files .
*
* Fun complications :
* 1. Try to preserve the directory hierarchy in the recycle bin .
* 2. If there are nontorrent files , don ' t delete them . . .
* 3. . . . unless the other files are " junk " , such as . DS_Store
*/
2008-12-23 16:04:11 +00:00
static void
2011-08-11 14:16:29 +00:00
deleteLocalData ( tr_torrent * tor , tr_fileFunc func )
2008-12-23 16:04:11 +00:00
{
int i , n ;
tr_file_index_t f ;
2011-08-11 14:16:29 +00:00
char * base ;
DIR * odir ;
char * tmpdir = NULL ;
tr_ptrArray files = TR_PTR_ARRAY_INIT ;
tr_ptrArray folders = TR_PTR_ARRAY_INIT ;
const void * const vstrcmp = strcmp ;
const char * const top = tor - > currentDir ;
2011-09-16 23:08:35 +00:00
/* if it's a magnet link, there's nothing to move... */
if ( ! tr_torrentHasMetadata ( tor ) )
return ;
2011-08-11 14:16:29 +00:00
/***
* * * * Move the local data to a new tmpdir
* * */
base = tr_strdup_printf ( " %s__XXXXXX " , tr_torrentName ( tor ) ) ;
tmpdir = tr_buildPath ( top , base , NULL ) ;
2011-11-10 03:31:43 +00:00
tr_mkdtemp ( tmpdir ) ;
2011-08-11 14:16:29 +00:00
tr_free ( base ) ;
for ( f = 0 ; f < tor - > info . fileCount ; + + f )
{
2011-08-16 22:42:43 +00:00
char * filename = tr_buildPath ( top , tor - > info . files [ f ] . name , NULL ) ;
2012-07-01 03:05:36 +00:00
if ( ! tr_fileExists ( filename , NULL ) ) {
2011-08-16 22:42:43 +00:00
char * partial = tr_torrentBuildPartial ( tor , f ) ;
tr_free ( filename ) ;
filename = tr_buildPath ( top , partial , NULL ) ;
tr_free ( partial ) ;
2012-07-01 03:05:36 +00:00
if ( ! tr_fileExists ( filename , NULL ) ) {
2011-08-16 22:42:43 +00:00
tr_free ( filename ) ;
filename = NULL ;
}
}
2008-12-23 16:04:11 +00:00
2011-08-16 22:42:43 +00:00
if ( filename ! = NULL )
2011-08-11 14:16:29 +00:00
{
2011-08-16 22:42:43 +00:00
char * target = tr_buildPath ( tmpdir , tor - > info . files [ f ] . name , NULL ) ;
2011-08-11 14:16:29 +00:00
char * target_dir = tr_dirname ( target ) ;
tr_mkdirp ( target_dir , 0777 ) ;
2011-08-16 22:42:43 +00:00
rename ( filename , target ) ;
2011-08-12 01:56:35 +00:00
tr_ptrArrayAppend ( & files , target ) ;
2011-08-11 14:16:29 +00:00
tr_free ( target_dir ) ;
2011-08-16 22:42:43 +00:00
tr_free ( filename ) ;
2011-08-11 14:16:29 +00:00
}
2009-10-19 05:05:00 +00:00
}
2008-12-23 16:04:11 +00:00
2011-08-11 14:16:29 +00:00
/***
* * * * Remove tmpdir .
* * * *
* * * * Try deleting the top - level files & folders to preserve
* * * * the directory hierarchy in the recycle bin .
* * * * If case that fails - - for example , rmdir ( ) doesn ' t
* * * * delete nonempty folders - - go from the bottom up too .
* * */
/* try deleting the local data's top-level files & folders */
if ( ( odir = opendir ( tmpdir ) ) )
{
struct dirent * d ;
while ( ( d = readdir ( odir ) ) )
{
if ( strcmp ( d - > d_name , " . " ) & & strcmp ( d - > d_name , " .. " ) )
{
char * file = tr_buildPath ( tmpdir , d - > d_name , NULL ) ;
func ( file ) ;
tr_free ( file ) ;
}
}
closedir ( odir ) ;
}
2008-12-23 16:04:11 +00:00
2011-08-11 14:16:29 +00:00
/* go from the bottom up */
for ( i = 0 , n = tr_ptrArraySize ( & files ) ; i < n ; + + i )
{
char * walk = tr_strdup ( tr_ptrArrayNth ( & files , i ) ) ;
2012-07-01 03:05:36 +00:00
while ( tr_fileExists ( walk , NULL ) & & ! tr_is_same_file ( tmpdir , walk ) )
2011-08-11 14:16:29 +00:00
{
char * tmp = tr_dirname ( walk ) ;
func ( walk ) ;
tr_free ( walk ) ;
walk = tmp ;
}
tr_free ( walk ) ;
2008-12-23 16:04:11 +00:00
}
2011-08-11 14:16:29 +00:00
/***
* * * * The local data has been removed .
* * * * What ' s left in top are empty folders , junk , and user - generated files .
* * * * Remove the first two categories and leave the third .
* * */
2011-08-16 22:42:43 +00:00
/* build a list of 'top's child directories that belong to this torrent */
for ( f = 0 ; f < tor - > info . fileCount ; + + f )
2008-12-23 16:04:11 +00:00
{
2011-08-16 22:42:43 +00:00
/* get the directory that this file goes in... */
2012-02-04 03:09:31 +00:00
char * filename = tr_buildPath ( top , tor - > info . files [ f ] . name , NULL ) ;
char * dir = tr_dirname ( filename ) ;
2011-08-20 18:41:45 +00:00
if ( ! tr_is_same_file ( top , dir ) & & strcmp ( top , dir ) ) {
2011-08-16 22:42:43 +00:00
for ( ; ; ) {
char * parent = tr_dirname ( dir ) ;
2011-08-20 18:41:45 +00:00
if ( tr_is_same_file ( top , parent ) | | ! strcmp ( top , parent ) ) {
2011-08-16 22:42:43 +00:00
if ( tr_ptrArrayFindSorted ( & folders , dir , vstrcmp ) = = NULL ) {
tr_ptrArrayInsertSorted ( & folders , tr_strdup ( dir ) , vstrcmp ) ;
}
break ;
}
tr_free ( dir ) ;
dir = parent ;
}
}
2012-02-04 03:09:31 +00:00
tr_free ( dir ) ;
tr_free ( filename ) ;
2008-12-23 16:04:11 +00:00
}
2011-08-16 22:42:43 +00:00
for ( i = 0 , n = tr_ptrArraySize ( & folders ) ; i < n ; + + i )
removeEmptyFoldersAndJunkFiles ( tr_ptrArrayNth ( & folders , i ) ) ;
2008-12-23 16:04:11 +00:00
/* cleanup */
2011-08-11 14:16:29 +00:00
rmdir ( tmpdir ) ;
tr_free ( tmpdir ) ;
2008-12-29 08:54:36 +00:00
tr_ptrArrayDestruct ( & folders , tr_free ) ;
2011-08-11 21:02:15 +00:00
tr_ptrArrayDestruct ( & files , tr_free ) ;
2008-12-23 16:04:11 +00:00
}
2010-12-16 03:41:46 +00:00
static void
2011-08-11 14:16:29 +00:00
tr_torrentDeleteLocalData ( tr_torrent * tor , tr_fileFunc func )
2008-12-23 16:04:11 +00:00
{
2009-01-30 00:41:08 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2011-08-11 14:16:29 +00:00
if ( func = = NULL )
func = remove ;
2008-12-23 16:04:11 +00:00
2009-01-12 19:58:16 +00:00
/* close all the files because we're about to delete them */
2010-12-15 20:28:49 +00:00
tr_cacheFlushTorrent ( tor - > session - > cache , tor ) ;
2009-10-23 03:41:36 +00:00
tr_fdTorrentClose ( tor - > session , tor - > uniqueId ) ;
2009-01-12 19:58:16 +00:00
2011-08-11 14:16:29 +00:00
deleteLocalData ( tor , func ) ;
2008-12-23 16:04:11 +00:00
}
2009-03-01 13:56:22 +00:00
/***
* * * *
* * */
2009-05-13 15:54:04 +00:00
struct LocationData
{
2011-03-22 15:19:54 +00:00
bool move_from_old_location ;
2011-02-19 20:10:05 +00:00
volatile int * setme_state ;
volatile double * setme_progress ;
2009-05-13 15:54:04 +00:00
char * location ;
tr_torrent * tor ;
} ;
static void
setLocation ( void * vdata )
{
2011-03-22 15:19:54 +00:00
bool err = false ;
2009-05-13 15:54:04 +00:00
struct LocationData * data = vdata ;
tr_torrent * tor = data - > tor ;
2011-03-22 15:19:54 +00:00
const bool do_move = data - > move_from_old_location ;
2009-05-13 15:54:04 +00:00
const char * location = data - > location ;
2009-05-20 16:02:12 +00:00
double bytesHandled = 0 ;
2009-05-13 15:54:04 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2010-02-27 18:52:46 +00:00
tr_dbg ( " Moving \" %s \" location from currentDir \" %s \" to \" %s \" " ,
tr_torrentName ( tor ) , tor - > currentDir , location ) ;
tr_mkdirp ( location , 0777 ) ;
2010-12-22 07:04:11 +00:00
if ( ! tr_is_same_file ( location , tor - > currentDir ) )
2009-05-13 15:54:04 +00:00
{
tr_file_index_t i ;
/* bad idea to move files while they're being verified... */
tr_verifyRemove ( tor ) ;
/* try to move the files.
* FIXME : there are still all kinds of nasty cases , like what
* if the target directory runs out of space halfway through . . . */
2009-05-20 16:02:12 +00:00
for ( i = 0 ; ! err & & i < tor - > info . fileCount ; + + i )
2009-05-13 15:54:04 +00:00
{
2009-05-20 16:02:12 +00:00
const tr_file * f = & tor - > info . files [ i ] ;
2009-10-20 03:14:44 +00:00
const char * oldbase ;
char * sub ;
2011-04-02 07:36:34 +00:00
if ( tr_torrentFindFile2 ( tor , i , & oldbase , & sub , NULL ) )
2009-05-13 15:54:04 +00:00
{
2009-10-20 03:14:44 +00:00
char * oldpath = tr_buildPath ( oldbase , sub , NULL ) ;
char * newpath = tr_buildPath ( location , sub , NULL ) ;
2010-02-27 18:52:46 +00:00
tr_dbg ( " Found file #%d: %s " , ( int ) i , oldpath ) ;
2011-01-24 06:07:06 +00:00
if ( do_move & & ! tr_is_same_file ( oldpath , newpath ) )
2009-10-07 03:49:55 +00:00
{
2011-03-22 15:19:54 +00:00
bool renamed = false ;
2009-10-20 03:14:44 +00:00
errno = 0 ;
tr_torinf ( tor , " moving \" %s \" to \" %s \" " , oldpath , newpath ) ;
2009-10-27 23:00:34 +00:00
if ( tr_moveFile ( oldpath , newpath , & renamed ) )
{
2011-03-22 15:19:54 +00:00
err = true ;
2009-10-27 23:00:34 +00:00
tr_torerr ( tor , " error moving \" %s \" to \" %s \" : %s " ,
oldpath , newpath , tr_strerror ( errno ) ) ;
}
2009-05-20 16:02:12 +00:00
}
2009-10-20 03:14:44 +00:00
tr_free ( newpath ) ;
tr_free ( oldpath ) ;
tr_free ( sub ) ;
2009-05-13 15:54:04 +00:00
}
2009-05-20 16:02:12 +00:00
if ( data - > setme_progress )
{
bytesHandled + = f - > length ;
* data - > setme_progress = bytesHandled / tor - > info . totalSize ;
}
2009-05-13 15:54:04 +00:00
}
2009-05-20 16:02:12 +00:00
if ( ! err )
{
/* blow away the leftover subdirectories in the old location */
2009-10-28 04:50:37 +00:00
if ( do_move )
2009-12-09 03:51:21 +00:00
tr_torrentDeleteLocalData ( tor , remove ) ;
2009-05-13 15:54:04 +00:00
2009-05-20 16:02:12 +00:00
/* set the new location and reverify */
tr_torrentSetDownloadDir ( tor , location ) ;
}
2009-05-13 15:54:04 +00:00
}
2010-03-06 22:33:45 +00:00
if ( ! err & & do_move )
{
tr_free ( tor - > incompleteDir ) ;
tor - > incompleteDir = NULL ;
tor - > currentDir = tor - > downloadDir ;
}
2009-05-20 16:02:12 +00:00
if ( data - > setme_state )
* data - > setme_state = err ? TR_LOC_ERROR : TR_LOC_DONE ;
2009-05-13 15:54:04 +00:00
/* cleanup */
tr_free ( data - > location ) ;
tr_free ( data ) ;
}
void
2011-02-19 20:10:05 +00:00
tr_torrentSetLocation ( tr_torrent * tor ,
const char * location ,
2011-03-22 15:19:54 +00:00
bool move_from_old_location ,
2011-02-19 20:10:05 +00:00
volatile double * setme_progress ,
volatile int * setme_state )
2009-05-13 15:54:04 +00:00
{
struct LocationData * data ;
assert ( tr_isTorrent ( tor ) ) ;
2009-05-20 16:02:12 +00:00
if ( setme_state )
* setme_state = TR_LOC_MOVING ;
if ( setme_progress )
* setme_progress = 0 ;
2009-05-13 15:54:04 +00:00
/* run this in the libtransmission thread */
data = tr_new ( struct LocationData , 1 ) ;
data - > tor = tor ;
data - > location = tr_strdup ( location ) ;
data - > move_from_old_location = move_from_old_location ;
2009-05-20 16:02:12 +00:00
data - > setme_state = setme_state ;
data - > setme_progress = setme_progress ;
2009-05-13 15:54:04 +00:00
tr_runInEventThread ( tor - > session , setLocation , data ) ;
}
/***
* * * *
* * */
2009-10-19 05:05:00 +00:00
void
tr_torrentFileCompleted ( tr_torrent * tor , tr_file_index_t fileNum )
{
2009-10-20 03:14:44 +00:00
char * sub ;
const char * base ;
2011-02-02 20:30:04 +00:00
const tr_info * inf = & tor - > info ;
const tr_file * f = & inf - > files [ fileNum ] ;
tr_piece * p ;
const tr_piece * pend ;
const time_t now = tr_time ( ) ;
2009-10-19 05:05:00 +00:00
/* close the file so that we can reopen in read-only mode as needed */
2009-10-23 03:41:36 +00:00
tr_fdFileClose ( tor - > session , tor , fileNum ) ;
2009-10-19 05:05:00 +00:00
2011-02-02 20:30:04 +00:00
/* now that the file is complete and closed, we can start watching its
* mtime timestamp for changes to know if we need to reverify pieces */
for ( p = & inf - > pieces [ f - > firstPiece ] , pend = & inf - > pieces [ f - > lastPiece ] ; p ! = pend ; + + p )
p - > timeChecked = now ;
2010-04-25 15:19:08 +00:00
/* if the torrent's current filename isn't the same as the one in the
* metadata - - for example , if it had the " .part " suffix appended to
* it until now - - then rename it to match the one in the metadata */
2011-04-02 07:36:34 +00:00
if ( tr_torrentFindFile2 ( tor , fileNum , & base , & sub , NULL ) )
2009-10-20 03:14:44 +00:00
{
2011-02-02 20:30:04 +00:00
if ( strcmp ( sub , f - > name ) )
2009-10-20 03:14:44 +00:00
{
char * oldpath = tr_buildPath ( base , sub , NULL ) ;
2011-02-02 20:30:04 +00:00
char * newpath = tr_buildPath ( base , f - > name , NULL ) ;
2009-10-20 03:14:44 +00:00
2009-10-19 13:15:46 +00:00
if ( rename ( oldpath , newpath ) )
tr_torerr ( tor , " Error moving \" %s \" to \" %s \" : %s " , oldpath , newpath , tr_strerror ( errno ) ) ;
2009-10-20 03:14:44 +00:00
tr_free ( newpath ) ;
tr_free ( oldpath ) ;
2009-10-19 13:15:46 +00:00
}
2009-10-20 03:14:44 +00:00
tr_free ( sub ) ;
2009-10-19 13:15:46 +00:00
}
2009-10-19 05:05:00 +00:00
}
/***
* * * *
* * */
2011-03-22 15:19:54 +00:00
bool
2009-10-20 03:14:44 +00:00
tr_torrentFindFile2 ( const tr_torrent * tor , tr_file_index_t fileNum ,
2011-04-02 07:36:34 +00:00
const char * * base , char * * subpath , time_t * mtime )
2009-10-19 05:05:00 +00:00
{
2011-04-02 03:31:41 +00:00
char * part = NULL ;
2009-10-20 03:14:44 +00:00
const tr_file * file ;
const char * b = NULL ;
const char * s = NULL ;
2009-10-19 05:05:00 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2009-10-20 03:14:44 +00:00
assert ( fileNum < tor - > info . fileCount ) ;
2009-10-19 05:05:00 +00:00
2009-10-20 03:14:44 +00:00
file = & tor - > info . files [ fileNum ] ;
2009-10-19 05:05:00 +00:00
2009-10-20 03:14:44 +00:00
if ( b = = NULL ) {
2009-10-20 04:15:10 +00:00
char * filename = tr_buildPath ( tor - > downloadDir , file - > name , NULL ) ;
2012-07-01 03:05:36 +00:00
if ( tr_fileExists ( filename , mtime ) ) {
2009-10-20 03:14:44 +00:00
b = tor - > downloadDir ;
2009-10-20 04:15:10 +00:00
s = file - > name ;
2009-10-20 03:14:44 +00:00
}
tr_free ( filename ) ;
}
2009-10-20 04:15:10 +00:00
if ( ( b = = NULL ) & & ( tor - > incompleteDir ! = NULL ) ) {
char * filename = tr_buildPath ( tor - > incompleteDir , file - > name , NULL ) ;
2012-07-01 03:05:36 +00:00
if ( tr_fileExists ( filename , mtime ) ) {
2009-10-20 04:15:10 +00:00
b = tor - > incompleteDir ;
2009-10-20 03:14:44 +00:00
s = file - > name ;
}
tr_free ( filename ) ;
}
2009-10-19 05:05:00 +00:00
2011-04-02 03:31:41 +00:00
if ( b = = NULL )
part = tr_torrentBuildPartial ( tor , fileNum ) ;
2009-10-20 04:15:10 +00:00
if ( ( b = = NULL ) & & ( tor - > incompleteDir ! = NULL ) ) {
char * filename = tr_buildPath ( tor - > incompleteDir , part , NULL ) ;
2012-07-01 03:05:36 +00:00
if ( tr_fileExists ( filename , mtime ) ) {
2009-10-20 04:15:10 +00:00
b = tor - > incompleteDir ;
s = part ;
2009-10-20 03:14:44 +00:00
}
2009-10-20 04:15:10 +00:00
tr_free ( filename ) ;
}
2009-10-19 05:05:00 +00:00
2009-10-20 04:15:10 +00:00
if ( b = = NULL ) {
char * filename = tr_buildPath ( tor - > downloadDir , part , NULL ) ;
2012-07-01 03:05:36 +00:00
if ( tr_fileExists ( filename , mtime ) ) {
2009-10-20 04:15:10 +00:00
b = tor - > downloadDir ;
s = part ;
2009-10-20 03:14:44 +00:00
}
2009-10-20 04:15:10 +00:00
tr_free ( filename ) ;
2009-10-20 03:14:44 +00:00
}
2009-10-19 05:05:00 +00:00
2009-10-20 03:14:44 +00:00
if ( base ! = NULL )
* base = b ;
if ( subpath ! = NULL )
* subpath = tr_strdup ( s ) ;
tr_free ( part ) ;
return b ! = NULL ;
2009-10-19 05:05:00 +00:00
}
char *
2009-10-20 03:14:44 +00:00
tr_torrentFindFile ( const tr_torrent * tor , tr_file_index_t fileNum )
2009-10-19 05:05:00 +00:00
{
2009-10-20 03:14:44 +00:00
char * subpath ;
char * ret = NULL ;
const char * base ;
2009-10-19 05:05:00 +00:00
2011-04-02 07:36:34 +00:00
if ( tr_torrentFindFile2 ( tor , fileNum , & base , & subpath , NULL ) )
2009-10-20 03:14:44 +00:00
{
ret = tr_buildPath ( base , subpath , NULL ) ;
tr_free ( subpath ) ;
2009-10-19 05:05:00 +00:00
}
2009-10-20 03:14:44 +00:00
return ret ;
2009-10-19 05:05:00 +00:00
}
/* Decide whether we should be looking for files in downloadDir or incompleteDir. */
static void
refreshCurrentDir ( tr_torrent * tor )
{
2009-10-20 03:14:44 +00:00
const char * dir = NULL ;
2009-10-19 05:05:00 +00:00
2009-10-20 03:14:44 +00:00
if ( tor - > incompleteDir = = NULL )
dir = tor - > downloadDir ;
2009-11-25 08:22:57 +00:00
else if ( ! tr_torrentHasMetadata ( tor ) ) /* no files to find */
dir = tor - > incompleteDir ;
2011-04-02 07:36:34 +00:00
else if ( ! tr_torrentFindFile2 ( tor , 0 , & dir , NULL , NULL ) )
2009-10-20 03:14:44 +00:00
dir = tor - > incompleteDir ;
2009-10-19 05:05:00 +00:00
assert ( dir ! = NULL ) ;
assert ( ( dir = = tor - > downloadDir ) | | ( dir = = tor - > incompleteDir ) ) ;
tor - > currentDir = dir ;
}
2009-10-20 03:14:44 +00:00
char *
tr_torrentBuildPartial ( const tr_torrent * tor , tr_file_index_t fileNum )
{
return tr_strdup_printf ( " %s.part " , tor - > info . files [ fileNum ] . name ) ;
}
2011-08-01 22:24:24 +00:00
/***
* * * *
* * */
static int
compareTorrentByQueuePosition ( const void * va , const void * vb )
{
const tr_torrent * a = * ( const tr_torrent * * ) va ;
const tr_torrent * b = * ( const tr_torrent * * ) vb ;
return a - > queuePosition - b - > queuePosition ;
}
2011-08-05 17:03:34 +00:00
# ifndef NDEBUG
2011-08-01 22:24:24 +00:00
static bool
2011-08-02 03:59:54 +00:00
queueIsSequenced ( tr_session * session )
2011-08-01 22:24:24 +00:00
{
int i ;
int n ;
bool is_sequenced = true ;
2011-08-02 03:59:54 +00:00
tr_torrent * tor ;
2011-08-01 22:24:24 +00:00
tr_torrent * * tmp = tr_new ( tr_torrent * , session - > torrentCount ) ;
2011-08-02 03:59:54 +00:00
/* get all the torrents */
2011-08-01 22:24:24 +00:00
n = 0 ;
tor = NULL ;
while ( ( tor = tr_torrentNext ( session , tor ) ) )
2011-08-02 03:59:54 +00:00
tmp [ n + + ] = tor ;
2011-08-01 22:24:24 +00:00
/* sort them by position */
qsort ( tmp , n , sizeof ( tr_torrent * ) , compareTorrentByQueuePosition ) ;
#if 0
2011-08-02 03:59:54 +00:00
fprintf ( stderr , " %s " , " queue: " ) ;
2011-08-01 22:24:24 +00:00
for ( i = 0 ; i < n ; + + i )
fprintf ( stderr , " %d " , tmp [ i ] - > queuePosition ) ;
2011-08-02 03:59:54 +00:00
fputc ( ' \n ' , stderr ) ;
2011-08-01 22:24:24 +00:00
# endif
/* test them */
for ( i = 0 ; is_sequenced & & i < n ; + + i )
if ( tmp [ i ] - > queuePosition ! = i )
is_sequenced = false ;
tr_free ( tmp ) ;
return is_sequenced ;
}
2011-08-05 17:03:34 +00:00
# endif
2011-08-01 22:24:24 +00:00
int
tr_torrentGetQueuePosition ( const tr_torrent * tor )
{
return tor - > queuePosition ;
}
void
tr_torrentSetQueuePosition ( tr_torrent * tor , int pos )
{
2011-08-02 03:59:54 +00:00
int back = - 1 ;
tr_torrent * walk ;
const int old_pos = tor - > queuePosition ;
const time_t now = tr_time ( ) ;
2011-08-01 22:24:24 +00:00
2011-08-02 03:59:54 +00:00
if ( pos < 0 )
pos = 0 ;
2011-08-01 22:24:24 +00:00
2011-08-02 03:59:54 +00:00
tor - > queuePosition = - 1 ;
2011-08-01 22:24:24 +00:00
2011-08-02 03:59:54 +00:00
walk = NULL ;
while ( ( walk = tr_torrentNext ( tor - > session , walk ) ) )
{
if ( old_pos < pos ) {
if ( ( old_pos < = walk - > queuePosition ) & & ( walk - > queuePosition < = pos ) ) {
walk - > queuePosition - - ;
walk - > anyDate = now ;
}
}
2011-08-01 22:24:24 +00:00
2011-08-02 03:59:54 +00:00
if ( old_pos > pos ) {
if ( ( pos < = walk - > queuePosition ) & & ( walk - > queuePosition < old_pos ) ) {
walk - > queuePosition + + ;
walk - > anyDate = now ;
2011-08-01 22:24:24 +00:00
}
}
2011-08-02 03:59:54 +00:00
if ( back < walk - > queuePosition )
back = walk - > queuePosition ;
2011-08-01 22:24:24 +00:00
}
2011-08-02 03:59:54 +00:00
tor - > queuePosition = MIN ( pos , ( back + 1 ) ) ;
tor - > anyDate = now ;
assert ( queueIsSequenced ( tor - > session ) ) ;
2011-08-01 22:24:24 +00:00
}
void
tr_torrentsQueueMoveTop ( tr_torrent * * torrents_in , int n )
{
int i ;
tr_torrent * * torrents = tr_memdup ( torrents_in , sizeof ( tr_torrent * ) * n ) ;
qsort ( torrents , n , sizeof ( tr_torrent * ) , compareTorrentByQueuePosition ) ;
for ( i = n - 1 ; i > = 0 ; - - i )
tr_torrentSetQueuePosition ( torrents [ i ] , 0 ) ;
tr_free ( torrents ) ;
}
void
tr_torrentsQueueMoveUp ( tr_torrent * * torrents_in , int n )
{
int i ;
tr_torrent * * torrents = tr_memdup ( torrents_in , sizeof ( tr_torrent * ) * n ) ;
qsort ( torrents , n , sizeof ( tr_torrent * ) , compareTorrentByQueuePosition ) ;
for ( i = 0 ; i < n ; + + i )
tr_torrentSetQueuePosition ( torrents [ i ] , torrents [ i ] - > queuePosition - 1 ) ;
tr_free ( torrents ) ;
}
void
tr_torrentsQueueMoveDown ( tr_torrent * * torrents_in , int n )
{
int i ;
tr_torrent * * torrents = tr_memdup ( torrents_in , sizeof ( tr_torrent * ) * n ) ;
qsort ( torrents , n , sizeof ( tr_torrent * ) , compareTorrentByQueuePosition ) ;
for ( i = n - 1 ; i > = 0 ; - - i )
tr_torrentSetQueuePosition ( torrents [ i ] , torrents [ i ] - > queuePosition + 1 ) ;
tr_free ( torrents ) ;
}
void
tr_torrentsQueueMoveBottom ( tr_torrent * * torrents_in , int n )
{
int i ;
tr_torrent * * torrents = tr_memdup ( torrents_in , sizeof ( tr_torrent * ) * n ) ;
qsort ( torrents , n , sizeof ( tr_torrent * ) , compareTorrentByQueuePosition ) ;
for ( i = 0 ; i < n ; + + i )
tr_torrentSetQueuePosition ( torrents [ i ] , INT_MAX ) ;
tr_free ( torrents ) ;
}
static void
2011-08-02 03:59:54 +00:00
torrentSetQueued ( tr_torrent * tor , bool queued )
2011-08-01 22:24:24 +00:00
{
2011-08-02 03:59:54 +00:00
assert ( tr_isTorrent ( tor ) ) ;
assert ( tr_isBool ( queued ) ) ;
2011-08-01 22:24:24 +00:00
2011-08-02 03:59:54 +00:00
if ( tr_torrentIsQueued ( tor ) ! = queued )
2011-08-01 22:24:24 +00:00
{
2011-08-02 03:59:54 +00:00
tor - > isQueued = queued ;
tor - > anyDate = tr_time ( ) ;
2011-08-01 22:24:24 +00:00
}
}
2011-08-03 03:14:57 +00:00
void
2011-08-03 23:40:51 +00:00
tr_torrentSetQueueStartCallback ( tr_torrent * torrent , void ( * callback ) ( tr_torrent * , void * ) , void * user_data )
2011-08-03 03:14:57 +00:00
{
torrent - > queue_started_callback = callback ;
2011-08-03 23:40:51 +00:00
torrent - > queue_started_user_data = user_data ;
2011-08-03 03:14:57 +00:00
}