source: trunk/libtransmission/resume.c @ 10500

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

(trunk libT) #3159 "better decision-making when choosing which peers to initiate new connections with" -- experimental commit

  • Property svn:keywords set to Date Rev Author Id
File size: 21.2 KB
Line 
1/*
2 * This file Copyright (C) 2008-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: resume.c 10500 2010-04-20 21:54:03Z charles $
11 */
12
13#include <unistd.h> /* unlink */
14
15#include <string.h>
16
17#include "transmission.h"
18#include "bencode.h"
19#include "completion.h"
20#include "peer-mgr.h" /* pex */
21#include "platform.h" /* tr_getResumeDir */
22#include "resume.h"
23#include "session.h"
24#include "torrent.h"
25#include "utils.h" /* tr_buildPath */
26
27#define KEY_ACTIVITY_DATE       "activity-date"
28#define KEY_ADDED_DATE          "added-date"
29#define KEY_CORRUPT             "corrupt"
30#define KEY_DONE_DATE           "done-date"
31#define KEY_DOWNLOAD_DIR        "destination"
32#define KEY_DND                 "dnd"
33#define KEY_DOWNLOADED          "downloaded"
34#define KEY_INCOMPLETE_DIR      "incomplete-dir"
35#define KEY_MAX_PEERS           "max-peers"
36#define KEY_PAUSED              "paused"
37#define KEY_PEERS               "peers2"
38#define KEY_PEERS6              "peers2-6"
39#define KEY_FILE_PRIORITIES     "priority"
40#define KEY_BANDWIDTH_PRIORITY  "bandwidth-priority"
41#define KEY_PROGRESS            "progress"
42#define KEY_SPEEDLIMIT_OLD      "speed-limit"
43#define KEY_SPEEDLIMIT_UP       "speed-limit-up"
44#define KEY_SPEEDLIMIT_DOWN     "speed-limit-down"
45#define KEY_RATIOLIMIT          "ratio-limit"
46#define KEY_UPLOADED            "uploaded"
47
48#define KEY_SPEED                  "speed"
49#define KEY_USE_GLOBAL_SPEED_LIMIT "use-global-speed-limit"
50#define KEY_USE_SPEED_LIMIT        "use-speed-limit"
51#define KEY_SPEEDLIMIT_DOWN_SPEED  "down-speed"
52#define KEY_SPEEDLIMIT_DOWN_MODE   "down-mode"
53#define KEY_SPEEDLIMIT_UP_SPEED    "up-speed"
54#define KEY_SPEEDLIMIT_UP_MODE     "up-mode"
55#define KEY_RATIOLIMIT_RATIO       "ratio-limit"
56#define KEY_RATIOLIMIT_MODE        "ratio-mode"
57
58#define KEY_PROGRESS_MTIMES    "mtimes"
59#define KEY_PROGRESS_BITFIELD  "bitfield"
60#define KEY_PROGRESS_HAVE      "have"
61
62enum
63{
64    MAX_REMEMBERED_PEERS = 200
65};
66
67static char*
68getResumeFilename( const tr_torrent * tor )
69{
70    return tr_strdup_printf( "%s%c%s.%16.16s.resume",
71                             tr_getResumeDir( tor->session ),
72                             TR_PATH_DELIMITER,
73                             tr_torrentName( tor ),
74                             tor->info.hashString );
75}
76
77/***
78****
79***/
80
81static void
82savePeers( tr_benc * dict, const tr_torrent * tor )
83{
84    int count;
85    tr_pex * pex;
86
87    count = tr_peerMgrGetPeers( (tr_torrent*) tor, &pex, TR_AF_INET, TR_PEERS_ALL, MAX_REMEMBERED_PEERS );
88    if( count > 0 )
89        tr_bencDictAddRaw( dict, KEY_PEERS, pex, sizeof( tr_pex ) * count );
90    tr_free( pex );
91
92    count = tr_peerMgrGetPeers( (tr_torrent*) tor, &pex, TR_AF_INET6, TR_PEERS_ALL, MAX_REMEMBERED_PEERS );
93    if( count > 0 )
94        tr_bencDictAddRaw( dict, KEY_PEERS6, pex, sizeof( tr_pex ) * count );
95
96    tr_free( pex );
97}
98
99static tr_bool
100tr_isPex( const tr_pex * pex )
101{
102    return tr_isAddress( &pex->addr )
103        && ( pex->flags & 3 ) == pex->flags;
104}
105
106static int
107addPeers( tr_torrent * tor, const uint8_t * buf, int buflen )
108{
109    int i;
110    int numAdded = 0;
111    const int count = buflen / sizeof( tr_pex );
112
113    for( i=0; i<count && numAdded<MAX_REMEMBERED_PEERS; ++i )
114    {
115        tr_pex pex;
116        memcpy( &pex, buf + ( i * sizeof( tr_pex ) ), sizeof( tr_pex ) );
117        if( tr_isPex( &pex ) )
118        {
119            tr_peerMgrAddPex( tor, TR_PEER_FROM_RESUME, &pex, -1 );
120            ++numAdded;
121        }
122    }
123
124    return numAdded;
125}
126
127
128static uint64_t
129loadPeers( tr_benc * dict, tr_torrent * tor )
130{
131    uint64_t        ret = 0;
132    const uint8_t * str;
133    size_t          len;
134
135    if( tr_bencDictFindRaw( dict, KEY_PEERS, &str, &len ) )
136    {
137        const int numAdded = addPeers( tor, str, len );
138        tr_tordbg( tor, "Loaded %d IPv4 peers from resume file", numAdded );
139        ret = TR_FR_PEERS;
140    }
141
142    if( tr_bencDictFindRaw( dict, KEY_PEERS6, &str, &len ) )
143    {
144        const int numAdded = addPeers( tor, str, len );
145        tr_tordbg( tor, "Loaded %d IPv6 peers from resume file", numAdded );
146        ret = TR_FR_PEERS;
147    }
148
149    return ret;
150}
151
152/***
153****
154***/
155
156static void
157saveDND( tr_benc *          dict,
158         const tr_torrent * tor )
159{
160    const tr_info *       inf = tr_torrentInfo( tor );
161    const tr_file_index_t n = inf->fileCount;
162    tr_file_index_t       i;
163    tr_benc *             list;
164
165    list = tr_bencDictAddList( dict, KEY_DND, n );
166    for( i = 0; i < n; ++i )
167        tr_bencListAddInt( list, inf->files[i].dnd ? 1 : 0 );
168}
169
170static uint64_t
171loadDND( tr_benc *    dict,
172         tr_torrent * tor )
173{
174    uint64_t              ret = 0;
175    tr_info *             inf = &tor->info;
176    const tr_file_index_t n = inf->fileCount;
177    tr_benc *             list = NULL;
178
179    if( tr_bencDictFindList( dict, KEY_DND, &list )
180      && ( tr_bencListSize( list ) == n ) )
181    {
182        int64_t           tmp;
183        tr_file_index_t * dl = tr_new( tr_file_index_t, n );
184        tr_file_index_t * dnd = tr_new( tr_file_index_t, n );
185        tr_file_index_t   i, dlCount = 0, dndCount = 0;
186
187        for( i = 0; i < n; ++i )
188        {
189            if( tr_bencGetInt( tr_bencListChild( list, i ), &tmp ) && tmp )
190                dnd[dndCount++] = i;
191            else
192                dl[dlCount++] = i;
193        }
194
195        if( dndCount )
196        {
197            tr_torrentInitFileDLs ( tor, dnd, dndCount, FALSE );
198            tr_tordbg( tor, "Resume file found %d files listed as dnd",
199                       dndCount );
200        }
201        if( dlCount )
202        {
203            tr_torrentInitFileDLs ( tor, dl, dlCount, TRUE );
204            tr_tordbg( tor,
205                       "Resume file found %d files marked for download",
206                       dlCount );
207        }
208
209        tr_free( dnd );
210        tr_free( dl );
211        ret = TR_FR_DND;
212    }
213    else
214    {
215        tr_tordbg(
216            tor,
217            "Couldn't load DND flags.  dnd list (%p) has %zu children; torrent has %d files",
218            list, tr_bencListSize( list ), (int)n );
219    }
220
221    return ret;
222}
223
224/***
225****
226***/
227
228static void
229saveFilePriorities( tr_benc * dict, const tr_torrent * tor )
230{
231    const tr_info *       inf = tr_torrentInfo( tor );
232    const tr_file_index_t n = inf->fileCount;
233    tr_file_index_t       i;
234    tr_benc *             list;
235
236    list = tr_bencDictAddList( dict, KEY_FILE_PRIORITIES, n );
237    for( i = 0; i < n; ++i )
238        tr_bencListAddInt( list, inf->files[i].priority );
239}
240
241static uint64_t
242loadFilePriorities( tr_benc * dict, tr_torrent * tor )
243{
244    uint64_t              ret = 0;
245    tr_info *             inf = &tor->info;
246    const tr_file_index_t n = inf->fileCount;
247    tr_benc *             list;
248
249    if( tr_bencDictFindList( dict, KEY_FILE_PRIORITIES, &list )
250      && ( tr_bencListSize( list ) == n ) )
251    {
252        int64_t priority;
253        tr_file_index_t i;
254        for( i = 0; i < n; ++i )
255            if( tr_bencGetInt( tr_bencListChild( list, i ), &priority ) )
256                tr_torrentInitFilePriority( tor, i, priority );
257        ret = TR_FR_FILE_PRIORITIES;
258    }
259
260    return ret;
261}
262
263/***
264****
265***/
266
267static void
268saveSingleSpeedLimit( tr_benc * d, const tr_torrent * tor, tr_direction dir )
269{
270    tr_bencDictReserve( d, 3 );
271    tr_bencDictAddInt( d, KEY_SPEED, tr_torrentGetSpeedLimit( tor, dir ) );
272    tr_bencDictAddBool( d, KEY_USE_GLOBAL_SPEED_LIMIT, tr_torrentUsesSessionLimits( tor ) );
273    tr_bencDictAddBool( d, KEY_USE_SPEED_LIMIT, tr_torrentUsesSpeedLimit( tor, dir ) );
274}
275
276static void
277saveSpeedLimits( tr_benc * dict, const tr_torrent * tor )
278{
279    saveSingleSpeedLimit( tr_bencDictAddDict( dict, KEY_SPEEDLIMIT_DOWN, 0 ), tor, TR_DOWN );
280    saveSingleSpeedLimit( tr_bencDictAddDict( dict, KEY_SPEEDLIMIT_UP, 0 ), tor, TR_UP );
281}
282
283static void
284saveRatioLimits( tr_benc * dict, const tr_torrent * tor )
285{
286    tr_benc * d = tr_bencDictAddDict( dict, KEY_RATIOLIMIT, 2 );
287    tr_bencDictAddReal( d, KEY_RATIOLIMIT_RATIO, tr_torrentGetRatioLimit( tor ) );
288    tr_bencDictAddInt( d, KEY_RATIOLIMIT_MODE, tr_torrentGetRatioMode( tor ) );
289}
290
291static void
292loadSingleSpeedLimit( tr_benc * d, tr_direction dir, tr_torrent * tor )
293{
294    int64_t i;
295    tr_bool boolVal;
296
297    if( tr_bencDictFindInt( d, KEY_SPEED, &i ) )
298        tr_torrentSetSpeedLimit( tor, dir, i );
299
300    if( tr_bencDictFindBool( d, KEY_USE_SPEED_LIMIT, &boolVal ) )
301        tr_torrentUseSpeedLimit( tor, dir, boolVal );
302
303    if( tr_bencDictFindBool( d, KEY_USE_GLOBAL_SPEED_LIMIT, &boolVal ) )
304        tr_torrentUseSessionLimits( tor, boolVal );
305}
306
307enum old_speed_modes
308{
309    TR_SPEEDLIMIT_GLOBAL,   /* only follow the overall speed limit */
310    TR_SPEEDLIMIT_SINGLE    /* only follow the per-torrent limit */
311};
312
313static uint64_t
314loadSpeedLimits( tr_benc * dict, tr_torrent * tor )
315{
316    uint64_t  ret = 0;
317    tr_benc * d;
318
319    if( tr_bencDictFindDict( dict, KEY_SPEEDLIMIT_UP, &d ) )
320    {
321        loadSingleSpeedLimit( d, TR_UP, tor );
322        ret = TR_FR_SPEEDLIMIT;
323    }
324    if( tr_bencDictFindDict( dict, KEY_SPEEDLIMIT_DOWN, &d ) )
325    {
326        loadSingleSpeedLimit( d, TR_DOWN, tor );
327        ret = TR_FR_SPEEDLIMIT;
328    }
329
330    /* older speedlimit structure */
331    if( !ret && tr_bencDictFindDict( dict, KEY_SPEEDLIMIT_OLD, &d ) )
332    {
333
334        int64_t i;
335        if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_DOWN_SPEED, &i ) )
336            tr_torrentSetSpeedLimit( tor, TR_DOWN, i );
337        if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_DOWN_MODE, &i ) ) {
338            tr_torrentUseSpeedLimit( tor, TR_DOWN, i==TR_SPEEDLIMIT_SINGLE );
339            tr_torrentUseSessionLimits( tor, i==TR_SPEEDLIMIT_GLOBAL );
340         }
341        if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_UP_SPEED, &i ) )
342            tr_torrentSetSpeedLimit( tor, TR_UP, i );
343        if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_UP_MODE, &i ) ) {
344            tr_torrentUseSpeedLimit( tor, TR_UP, i==TR_SPEEDLIMIT_SINGLE );
345            tr_torrentUseSessionLimits( tor, i==TR_SPEEDLIMIT_GLOBAL );
346        }
347        ret = TR_FR_SPEEDLIMIT;
348    }
349
350    return ret;
351}
352
353static uint64_t
354loadRatioLimits( tr_benc *    dict,
355                 tr_torrent * tor )
356{
357    uint64_t  ret = 0;
358    tr_benc * d;
359
360    if( tr_bencDictFindDict( dict, KEY_RATIOLIMIT, &d ) )
361    {
362        int64_t i;
363        double dratio;
364        if( tr_bencDictFindReal( d, KEY_RATIOLIMIT_RATIO, &dratio ) )
365            tr_torrentSetRatioLimit( tor, dratio );
366        if( tr_bencDictFindInt( d, KEY_RATIOLIMIT_MODE, &i ) )
367            tr_torrentSetRatioMode( tor, i );
368      ret = TR_FR_RATIOLIMIT;
369    }
370
371    return ret;
372}
373/***
374****
375***/
376
377static void
378saveProgress( tr_benc *          dict,
379              const tr_torrent * tor )
380{
381    size_t              i, n;
382    time_t *            mtimes;
383    tr_benc *           p;
384    tr_benc *           m;
385    const tr_bitfield * bitfield;
386
387    p = tr_bencDictAdd( dict, KEY_PROGRESS );
388    tr_bencInitDict( p, 2 );
389
390    /* add the mtimes */
391    mtimes = tr_torrentGetMTimes( tor, &n );
392    m = tr_bencDictAddList( p, KEY_PROGRESS_MTIMES, n );
393    for( i = 0; i < n; ++i )
394    {
395        if( !tr_torrentIsFileChecked( tor, i ) )
396            mtimes[i] = ~(time_t)0; /* force a recheck */
397        tr_bencListAddInt( m, mtimes[i] );
398    }
399
400    /* add the progress */
401    if( tor->completeness == TR_SEED )
402        tr_bencDictAddStr( p, KEY_PROGRESS_HAVE, "all" );
403    bitfield = tr_cpBlockBitfield( &tor->completion );
404    tr_bencDictAddRaw( p, KEY_PROGRESS_BITFIELD,
405                       bitfield->bits, bitfield->byteCount );
406
407    /* cleanup */
408    tr_free( mtimes );
409}
410
411static uint64_t
412loadProgress( tr_benc *    dict,
413              tr_torrent * tor )
414{
415    uint64_t  ret = 0;
416    tr_benc * p;
417
418    if( tr_bencDictFindDict( dict, KEY_PROGRESS, &p ) )
419    {
420        const char * err;
421        const char * str;
422        const uint8_t * raw;
423        size_t          rawlen;
424        tr_benc *       m;
425        size_t          n;
426        time_t *        curMTimes = tr_torrentGetMTimes( tor, &n );
427
428        if( tr_bencDictFindList( p, KEY_PROGRESS_MTIMES, &m )
429          && ( n == tor->info.fileCount )
430          && ( n == tr_bencListSize( m ) ) )
431        {
432            size_t i;
433            for( i = 0; i < n; ++i )
434            {
435                int64_t tmp;
436                if( !tr_bencGetInt( tr_bencListChild( m, i ), &tmp ) )
437                {
438                    tr_tordbg(
439                        tor,
440                        "File #%zu needs to be verified - couldn't find benc entry",
441                        i );
442                    tr_torrentSetFileChecked( tor, i, FALSE );
443                }
444                else
445                {
446                    const time_t t = (time_t) tmp;
447                    if( t == curMTimes[i] )
448                        tr_torrentSetFileChecked( tor, i, TRUE );
449                    else
450                    {
451                        tr_tordbg(
452                            tor,
453                            "File #%zu needs to be verified - times %lu and %lu don't match",
454                            i, t, curMTimes[i] );
455                        tr_torrentSetFileChecked( tor, i, FALSE );
456                    }
457                }
458            }
459        }
460        else
461        {
462            tr_torrentUncheck( tor );
463            tr_tordbg(
464                tor, "Torrent needs to be verified - unable to find mtimes" );
465        }
466
467        err = NULL;
468        if( tr_bencDictFindStr( p, KEY_PROGRESS_HAVE, &str ) )
469        {
470            if( !strcmp( str, "all" ) )
471                tr_cpSetHaveAll( &tor->completion );
472            else
473                err = "Invalid value for HAVE";
474        }
475        else if( tr_bencDictFindRaw( p, KEY_PROGRESS_BITFIELD, &raw, &rawlen ) )
476        {
477            tr_bitfield tmp;
478            tmp.byteCount = rawlen;
479            tmp.bitCount = tmp.byteCount * 8;
480            tmp.bits = (uint8_t*) raw;
481            if( !tr_cpBlockBitfieldSet( &tor->completion, &tmp ) )
482                err = "Error loading bitfield";
483        }
484        else err = "Couldn't find 'have' or 'bitfield'";
485        if( err != NULL )
486        {
487            tr_torrentUncheck( tor );
488            tr_tordbg( tor, "Torrent needs to be verified - %s", err );
489        }
490
491        tr_free( curMTimes );
492        ret = TR_FR_PROGRESS;
493    }
494
495    return ret;
496}
497
498/***
499****
500***/
501
502void
503tr_torrentSaveResume( tr_torrent * tor )
504{
505    int err;
506    tr_benc top;
507    char * filename;
508
509
510    if( !tr_isTorrent( tor ) )
511        return;
512
513    tr_tordbg( tor, "Saving .resume file for \"%s\"", tr_torrentName( tor ) );
514
515    tr_bencInitDict( &top, 33 ); /* arbitrary "big enough" number */
516    tr_bencDictAddInt( &top, KEY_ACTIVITY_DATE, tor->activityDate );
517    tr_bencDictAddInt( &top, KEY_ADDED_DATE, tor->addedDate );
518    tr_bencDictAddInt( &top, KEY_CORRUPT, tor->corruptPrev + tor->corruptCur );
519    tr_bencDictAddInt( &top, KEY_DONE_DATE, tor->doneDate );
520    tr_bencDictAddStr( &top, KEY_DOWNLOAD_DIR, tor->downloadDir );
521    if( tor->incompleteDir != NULL )
522        tr_bencDictAddStr( &top, KEY_INCOMPLETE_DIR, tor->incompleteDir );
523    tr_bencDictAddInt( &top, KEY_DOWNLOADED, tor->downloadedPrev + tor->downloadedCur );
524    tr_bencDictAddInt( &top, KEY_UPLOADED, tor->uploadedPrev + tor->uploadedCur );
525    tr_bencDictAddInt( &top, KEY_MAX_PEERS, tor->maxConnectedPeers );
526    tr_bencDictAddInt( &top, KEY_BANDWIDTH_PRIORITY, tr_torrentGetPriority( tor ) );
527    tr_bencDictAddBool( &top, KEY_PAUSED, !tor->isRunning );
528    savePeers( &top, tor );
529    if( tr_torrentHasMetadata( tor ) )
530    {
531        saveFilePriorities( &top, tor );
532        saveDND( &top, tor );
533        saveProgress( &top, tor );
534    }
535    saveSpeedLimits( &top, tor );
536    saveRatioLimits( &top, tor );
537
538    filename = getResumeFilename( tor );
539    if(( err = tr_bencToFile( &top, TR_FMT_BENC, filename )))
540        tr_torrentSetLocalError( tor, "Unable to save resume file: %s", tr_strerror( err ) );
541    tr_free( filename );
542
543    tr_bencFree( &top );
544}
545
546static uint64_t
547loadFromFile( tr_torrent * tor,
548              uint64_t     fieldsToLoad )
549{
550    int64_t  i;
551    const char * str;
552    uint64_t fieldsLoaded = 0;
553    char * filename;
554    tr_benc top;
555    tr_bool boolVal;
556    const tr_bool  wasDirty = tor->isDirty;
557
558    assert( tr_isTorrent( tor ) );
559
560    filename = getResumeFilename( tor );
561
562    if( tr_bencLoadFile( &top, TR_FMT_BENC, filename ) )
563    {
564        tr_tordbg( tor, "Couldn't read \"%s\"", filename );
565
566        tr_free( filename );
567        return fieldsLoaded;
568    }
569
570    tr_tordbg( tor, "Read resume file \"%s\"", filename );
571
572    if( ( fieldsToLoad & TR_FR_CORRUPT )
573      && tr_bencDictFindInt( &top, KEY_CORRUPT, &i ) )
574    {
575        tor->corruptPrev = i;
576        fieldsLoaded |= TR_FR_CORRUPT;
577    }
578
579    if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR ) )
580      && ( tr_bencDictFindStr( &top, KEY_DOWNLOAD_DIR, &str ) )
581      && ( str && *str ) )
582    {
583        tr_free( tor->downloadDir );
584        tor->downloadDir = tr_strdup( str );
585        fieldsLoaded |= TR_FR_DOWNLOAD_DIR;
586    }
587
588    if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_INCOMPLETE_DIR ) )
589      && ( tr_bencDictFindStr( &top, KEY_INCOMPLETE_DIR, &str ) )
590      && ( str && *str ) )
591    {
592        tr_free( tor->incompleteDir );
593        tor->incompleteDir = tr_strdup( str );
594        fieldsLoaded |= TR_FR_INCOMPLETE_DIR;
595    }
596
597    if( ( fieldsToLoad & TR_FR_DOWNLOADED )
598      && tr_bencDictFindInt( &top, KEY_DOWNLOADED, &i ) )
599    {
600        tor->downloadedPrev = i;
601        fieldsLoaded |= TR_FR_DOWNLOADED;
602    }
603
604    if( ( fieldsToLoad & TR_FR_UPLOADED )
605      && tr_bencDictFindInt( &top, KEY_UPLOADED, &i ) )
606    {
607        tor->uploadedPrev = i;
608        fieldsLoaded |= TR_FR_UPLOADED;
609    }
610
611    if( ( fieldsToLoad & TR_FR_MAX_PEERS )
612      && tr_bencDictFindInt( &top, KEY_MAX_PEERS, &i ) )
613    {
614        tor->maxConnectedPeers = i;
615        fieldsLoaded |= TR_FR_MAX_PEERS;
616    }
617
618    if( ( fieldsToLoad & TR_FR_RUN )
619      && tr_bencDictFindBool( &top, KEY_PAUSED, &boolVal ) )
620    {
621        tor->isRunning = !boolVal;
622        fieldsLoaded |= TR_FR_RUN;
623    }
624
625    if( ( fieldsToLoad & TR_FR_ADDED_DATE )
626      && tr_bencDictFindInt( &top, KEY_ADDED_DATE, &i ) )
627    {
628        tor->addedDate = i;
629        fieldsLoaded |= TR_FR_ADDED_DATE;
630    }
631
632    if( ( fieldsToLoad & TR_FR_DONE_DATE )
633      && tr_bencDictFindInt( &top, KEY_DONE_DATE, &i ) )
634    {
635        tor->doneDate = i;
636        fieldsLoaded |= TR_FR_DONE_DATE;
637    }
638
639    if( ( fieldsToLoad & TR_FR_ACTIVITY_DATE )
640      && tr_bencDictFindInt( &top, KEY_ACTIVITY_DATE, &i ) )
641    {
642        tr_torrentSetActivityDate( tor, i );
643        fieldsLoaded |= TR_FR_ACTIVITY_DATE;
644    }
645
646    if( ( fieldsToLoad & TR_FR_BANDWIDTH_PRIORITY )
647      && tr_bencDictFindInt( &top, KEY_BANDWIDTH_PRIORITY, &i )
648      && tr_isPriority( i ) )
649    {
650        tr_torrentSetPriority( tor, i );
651        fieldsLoaded |= TR_FR_BANDWIDTH_PRIORITY;
652    }
653
654    if( fieldsToLoad & TR_FR_PEERS )
655        fieldsLoaded |= loadPeers( &top, tor );
656
657    if( fieldsToLoad & TR_FR_FILE_PRIORITIES )
658        fieldsLoaded |= loadFilePriorities( &top, tor );
659
660    if( fieldsToLoad & TR_FR_PROGRESS )
661        fieldsLoaded |= loadProgress( &top, tor );
662
663    if( fieldsToLoad & TR_FR_DND )
664        fieldsLoaded |= loadDND( &top, tor );
665
666    if( fieldsToLoad & TR_FR_SPEEDLIMIT )
667        fieldsLoaded |= loadSpeedLimits( &top, tor );
668
669    if( fieldsToLoad & TR_FR_RATIOLIMIT )
670        fieldsLoaded |= loadRatioLimits( &top, tor );
671
672    /* loading the resume file triggers of a lot of changes,
673     * but none of them needs to trigger a re-saving of the
674     * same resume information... */
675    tor->isDirty = wasDirty;
676
677    tr_bencFree( &top );
678    tr_free( filename );
679    return fieldsLoaded;
680}
681
682static uint64_t
683setFromCtor( tr_torrent *    tor,
684             uint64_t        fields,
685             const tr_ctor * ctor,
686             int             mode )
687{
688    uint64_t ret = 0;
689
690    if( fields & TR_FR_RUN )
691    {
692        uint8_t isPaused;
693        if( !tr_ctorGetPaused( ctor, mode, &isPaused ) )
694        {
695            tor->isRunning = !isPaused;
696            ret |= TR_FR_RUN;
697        }
698    }
699
700    if( fields & TR_FR_MAX_PEERS )
701        if( !tr_ctorGetPeerLimit( ctor, mode, &tor->maxConnectedPeers ) )
702            ret |= TR_FR_MAX_PEERS;
703
704    if( fields & TR_FR_DOWNLOAD_DIR )
705    {
706        const char * path;
707        if( !tr_ctorGetDownloadDir( ctor, mode, &path ) && path && *path )
708        {
709            ret |= TR_FR_DOWNLOAD_DIR;
710            tr_free( tor->downloadDir );
711            tor->downloadDir = tr_strdup( path );
712        }
713    }
714
715    return ret;
716}
717
718static uint64_t
719useManditoryFields( tr_torrent *    tor,
720                    uint64_t        fields,
721                    const tr_ctor * ctor )
722{
723    return setFromCtor( tor, fields, ctor, TR_FORCE );
724}
725
726static uint64_t
727useFallbackFields( tr_torrent *    tor,
728                   uint64_t        fields,
729                   const tr_ctor * ctor )
730{
731    return setFromCtor( tor, fields, ctor, TR_FALLBACK );
732}
733
734uint64_t
735tr_torrentLoadResume( tr_torrent *    tor,
736                      uint64_t        fieldsToLoad,
737                      const tr_ctor * ctor )
738{
739    uint64_t ret = 0;
740
741    assert( tr_isTorrent( tor ) );
742
743    ret |= useManditoryFields( tor, fieldsToLoad, ctor );
744    fieldsToLoad &= ~ret;
745    ret |= loadFromFile( tor, fieldsToLoad );
746    fieldsToLoad &= ~ret;
747    ret |= useFallbackFields( tor, fieldsToLoad, ctor );
748
749    return ret;
750}
751
752void
753tr_torrentRemoveResume( const tr_torrent * tor )
754{
755    char * filename = getResumeFilename( tor );
756    unlink( filename );
757    tr_free( filename );
758}
759
Note: See TracBrowser for help on using the repository browser.