source: branches/2.0x/libtransmission/torrent.c @ 10843

Last change on this file since 10843 was 10843, checked in by charles, 12 years ago

(2.0x) #3339 "crash when download some magnet links" -- fixed

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