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