source: trunk/libtransmission/torrent.c @ 10480

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

(trunk) #1869 "new status for torrents that reached the seed ratio" -- add temporary debug messages to help track down the issue leena's reporting in that ticket

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