source: trunk/libtransmission/torrent.c @ 10999

Last change on this file since 10999 was 10999, checked in by livings124, 12 years ago

Have libtransmission keep track of idle seconds. Use this value for determining the stalled minutes in the Mac code.

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