source: trunk/libtransmission/resume.c @ 11690

Last change on this file since 11690 was 11690, checked in by jch, 11 years ago

Consolidate both versions of tr_isPex into a single function.

There used to be two versions of tr_isPex; one correct in peer-mgr.c,
and one buggy in resume.c. The buggy version caused us to reject all
peers with non-trivial flags when resuming.

  • Property svn:keywords set to Date Rev Author Id
File size: 21.8 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 11690 2011-01-16 15:47:09Z jch $
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 "metainfo.h" /* tr_metainfoGetBasename() */
21#include "peer-mgr.h" /* pex */
22#include "platform.h" /* tr_getResumeDir() */
23#include "resume.h"
24#include "session.h"
25#include "torrent.h"
26#include "utils.h" /* tr_buildPath */
27
28#define KEY_ACTIVITY_DATE       "activity-date"
29#define KEY_ADDED_DATE          "added-date"
30#define KEY_CORRUPT             "corrupt"
31#define KEY_DONE_DATE           "done-date"
32#define KEY_DOWNLOAD_DIR        "destination"
33#define KEY_DND                 "dnd"
34#define KEY_DOWNLOADED          "downloaded"
35#define KEY_INCOMPLETE_DIR      "incomplete-dir"
36#define KEY_MAX_PEERS           "max-peers"
37#define KEY_PAUSED              "paused"
38#define KEY_PEERS               "peers2"
39#define KEY_PEERS6              "peers2-6"
40#define KEY_FILE_PRIORITIES     "priority"
41#define KEY_BANDWIDTH_PRIORITY  "bandwidth-priority"
42#define KEY_PROGRESS            "progress"
43#define KEY_SPEEDLIMIT_OLD      "speed-limit"
44#define KEY_SPEEDLIMIT_UP       "speed-limit-up"
45#define KEY_SPEEDLIMIT_DOWN     "speed-limit-down"
46#define KEY_RATIOLIMIT          "ratio-limit"
47#define KEY_IDLELIMIT           "idle-limit"
48#define KEY_UPLOADED            "uploaded"
49
50#define KEY_SPEED_KiBps            "speed"
51#define KEY_SPEED_Bps              "speed-Bps"
52#define KEY_USE_GLOBAL_SPEED_LIMIT "use-global-speed-limit"
53#define KEY_USE_SPEED_LIMIT        "use-speed-limit"
54#define KEY_TIME_SEEDING           "seeding-time-seconds"
55#define KEY_TIME_DOWNLOADING       "downloading-time-seconds"
56#define KEY_SPEEDLIMIT_DOWN_SPEED  "down-speed"
57#define KEY_SPEEDLIMIT_DOWN_MODE   "down-mode"
58#define KEY_SPEEDLIMIT_UP_SPEED    "up-speed"
59#define KEY_SPEEDLIMIT_UP_MODE     "up-mode"
60#define KEY_RATIOLIMIT_RATIO       "ratio-limit"
61#define KEY_RATIOLIMIT_MODE        "ratio-mode"
62#define KEY_IDLELIMIT_MINS         "idle-limit"
63#define KEY_IDLELIMIT_MODE         "idle-mode"
64
65#define KEY_PROGRESS_CHECKTIME "time-checked"
66#define KEY_PROGRESS_BITFIELD  "bitfield"
67#define KEY_PROGRESS_HAVE      "have"
68
69enum
70{
71    MAX_REMEMBERED_PEERS = 200
72};
73
74static char*
75getResumeFilename( const tr_torrent * tor )
76{
77    char * base = tr_metainfoGetBasename( tr_torrentInfo( tor ) );
78    char * filename = tr_strdup_printf( "%s" TR_PATH_DELIMITER_STR "%s.resume",
79                                        tr_getResumeDir( tor->session ), base );
80    tr_free( base );
81    return filename;
82}
83
84/***
85****
86***/
87
88static void
89savePeers( tr_benc * dict, const tr_torrent * tor )
90{
91    int count;
92    tr_pex * pex;
93
94    count = tr_peerMgrGetPeers( (tr_torrent*) tor, &pex, TR_AF_INET, TR_PEERS_ALL, MAX_REMEMBERED_PEERS );
95    if( count > 0 )
96        tr_bencDictAddRaw( dict, KEY_PEERS, pex, sizeof( tr_pex ) * count );
97    tr_free( pex );
98
99    count = tr_peerMgrGetPeers( (tr_torrent*) tor, &pex, TR_AF_INET6, TR_PEERS_ALL, MAX_REMEMBERED_PEERS );
100    if( count > 0 )
101        tr_bencDictAddRaw( dict, KEY_PEERS6, pex, sizeof( tr_pex ) * count );
102
103    tr_free( pex );
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_Bps, tr_torrentGetSpeedLimit_Bps( 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
292saveIdleLimits( tr_benc * dict, const tr_torrent * tor )
293{
294    tr_benc * d = tr_bencDictAddDict( dict, KEY_IDLELIMIT, 2 );
295    tr_bencDictAddInt( d, KEY_IDLELIMIT_MINS, tr_torrentGetIdleLimit( tor ) );
296    tr_bencDictAddInt( d, KEY_IDLELIMIT_MODE, tr_torrentGetIdleMode( tor ) );
297}
298
299static void
300loadSingleSpeedLimit( tr_benc * d, tr_direction dir, tr_torrent * tor )
301{
302    int64_t i;
303    tr_bool boolVal;
304
305    if( tr_bencDictFindInt( d, KEY_SPEED_Bps, &i ) )
306        tr_torrentSetSpeedLimit_Bps( tor, dir, i );
307    else if( tr_bencDictFindInt( d, KEY_SPEED_KiBps, &i ) )
308        tr_torrentSetSpeedLimit_Bps( tor, dir, i*1024 );
309
310    if( tr_bencDictFindBool( d, KEY_USE_SPEED_LIMIT, &boolVal ) )
311        tr_torrentUseSpeedLimit( tor, dir, boolVal );
312
313    if( tr_bencDictFindBool( d, KEY_USE_GLOBAL_SPEED_LIMIT, &boolVal ) )
314        tr_torrentUseSessionLimits( tor, boolVal );
315}
316
317enum old_speed_modes
318{
319    TR_SPEEDLIMIT_GLOBAL,   /* only follow the overall speed limit */
320    TR_SPEEDLIMIT_SINGLE    /* only follow the per-torrent limit */
321};
322
323static uint64_t
324loadSpeedLimits( tr_benc * dict, tr_torrent * tor )
325{
326    uint64_t  ret = 0;
327    tr_benc * d;
328
329    if( tr_bencDictFindDict( dict, KEY_SPEEDLIMIT_UP, &d ) )
330    {
331        loadSingleSpeedLimit( d, TR_UP, tor );
332        ret = TR_FR_SPEEDLIMIT;
333    }
334    if( tr_bencDictFindDict( dict, KEY_SPEEDLIMIT_DOWN, &d ) )
335    {
336        loadSingleSpeedLimit( d, TR_DOWN, tor );
337        ret = TR_FR_SPEEDLIMIT;
338    }
339
340    /* older speedlimit structure */
341    if( !ret && tr_bencDictFindDict( dict, KEY_SPEEDLIMIT_OLD, &d ) )
342    {
343
344        int64_t i;
345        if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_DOWN_SPEED, &i ) )
346            tr_torrentSetSpeedLimit_Bps( tor, TR_DOWN, i*1024 );
347        if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_DOWN_MODE, &i ) ) {
348            tr_torrentUseSpeedLimit( tor, TR_DOWN, i==TR_SPEEDLIMIT_SINGLE );
349            tr_torrentUseSessionLimits( tor, i==TR_SPEEDLIMIT_GLOBAL );
350         }
351        if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_UP_SPEED, &i ) )
352            tr_torrentSetSpeedLimit_Bps( tor, TR_UP, i*1024 );
353        if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_UP_MODE, &i ) ) {
354            tr_torrentUseSpeedLimit( tor, TR_UP, i==TR_SPEEDLIMIT_SINGLE );
355            tr_torrentUseSessionLimits( tor, i==TR_SPEEDLIMIT_GLOBAL );
356        }
357        ret = TR_FR_SPEEDLIMIT;
358    }
359
360    return ret;
361}
362
363static uint64_t
364loadRatioLimits( tr_benc *    dict,
365                 tr_torrent * tor )
366{
367    uint64_t  ret = 0;
368    tr_benc * d;
369
370    if( tr_bencDictFindDict( dict, KEY_RATIOLIMIT, &d ) )
371    {
372        int64_t i;
373        double dratio;
374        if( tr_bencDictFindReal( d, KEY_RATIOLIMIT_RATIO, &dratio ) )
375            tr_torrentSetRatioLimit( tor, dratio );
376        if( tr_bencDictFindInt( d, KEY_RATIOLIMIT_MODE, &i ) )
377            tr_torrentSetRatioMode( tor, i );
378      ret = TR_FR_RATIOLIMIT;
379    }
380
381    return ret;
382}
383
384static uint64_t
385loadIdleLimits( tr_benc *    dict,
386                      tr_torrent * tor )
387{
388    uint64_t  ret = 0;
389    tr_benc * d;
390
391    if( tr_bencDictFindDict( dict, KEY_IDLELIMIT, &d ) )
392    {
393        int64_t i;
394        int64_t imin;
395        if( tr_bencDictFindInt( d, KEY_IDLELIMIT_MINS, &imin ) )
396            tr_torrentSetIdleLimit( tor, imin );
397        if( tr_bencDictFindInt( d, KEY_IDLELIMIT_MODE, &i ) )
398            tr_torrentSetIdleMode( tor, i );
399      ret = TR_FR_IDLELIMIT;
400    }
401
402    return ret;
403}
404/***
405****
406***/
407
408static void
409saveProgress( tr_benc *          dict,
410              const tr_torrent * tor )
411{
412    size_t              i, n;
413    tr_benc *           p;
414    tr_benc *           m;
415    const tr_bitfield * bitfield;
416
417    p = tr_bencDictAdd( dict, KEY_PROGRESS );
418    tr_bencInitDict( p, 2 );
419
420    /* add each piece's timeChecked */
421    n = tor->info.pieceCount;
422    m = tr_bencDictAddList( p, KEY_PROGRESS_CHECKTIME, n );
423    for( i=0; i<n; ++i )
424        tr_bencListAddInt( m, tor->info.pieces[i].timeChecked );
425
426    /* add the progress */
427    if( tor->completeness == TR_SEED )
428        tr_bencDictAddStr( p, KEY_PROGRESS_HAVE, "all" );
429    bitfield = tr_cpBlockBitfield( &tor->completion );
430    tr_bencDictAddRaw( p, KEY_PROGRESS_BITFIELD,
431                       bitfield->bits, bitfield->byteCount );
432}
433
434static uint64_t
435loadProgress( tr_benc *    dict,
436              tr_torrent * tor )
437{
438    size_t    i, n;
439    uint64_t  ret = 0;
440    tr_benc * p;
441
442    for( i=0, n=tor->info.pieceCount; i<n; ++i )
443        tor->info.pieces[i].timeChecked = 0;
444
445    if( tr_bencDictFindDict( dict, KEY_PROGRESS, &p ) )
446    {
447        const char * err;
448        const char * str;
449        const uint8_t * raw;
450        size_t          rawlen;
451        tr_benc *       m;
452        int64_t  timeChecked;
453
454        /* load in the timestamp of when we last checked each piece */
455        if( tr_bencDictFindList( p, KEY_PROGRESS_CHECKTIME, &m ) )
456            for( i=0, n=tor->info.pieceCount; i<n; ++i )
457                if( tr_bencGetInt( tr_bencListChild( m, i ), &timeChecked ) )
458                    tor->info.pieces[i].timeChecked = (time_t)timeChecked;
459
460        err = NULL;
461        if( tr_bencDictFindStr( p, KEY_PROGRESS_HAVE, &str ) )
462        {
463            if( !strcmp( str, "all" ) )
464                tr_cpSetHaveAll( &tor->completion );
465            else
466                err = "Invalid value for HAVE";
467        }
468        else if( tr_bencDictFindRaw( p, KEY_PROGRESS_BITFIELD, &raw, &rawlen ) )
469        {
470            tr_bitfield tmp;
471            tmp.byteCount = rawlen;
472            tmp.bitCount = tmp.byteCount * 8;
473            tmp.bits = (uint8_t*) raw;
474            if( !tr_cpBlockBitfieldSet( &tor->completion, &tmp ) )
475                err = "Error loading bitfield";
476        }
477        else err = "Couldn't find 'have' or 'bitfield'";
478
479        if( err != NULL )
480            tr_tordbg( tor, "Torrent needs to be verified - %s", err );
481
482        ret = TR_FR_PROGRESS;
483    }
484
485    return ret;
486}
487
488/***
489****
490***/
491
492void
493tr_torrentSaveResume( tr_torrent * tor )
494{
495    int err;
496    tr_benc top;
497    char * filename;
498
499    if( !tr_isTorrent( tor ) )
500        return;
501
502    tr_bencInitDict( &top, 50 ); /* arbitrary "big enough" number */
503    tr_bencDictAddInt( &top, KEY_TIME_SEEDING, tor->secondsSeeding );
504    tr_bencDictAddInt( &top, KEY_TIME_DOWNLOADING, tor->secondsDownloading );
505    tr_bencDictAddInt( &top, KEY_ACTIVITY_DATE, tor->activityDate );
506    tr_bencDictAddInt( &top, KEY_ADDED_DATE, tor->addedDate );
507    tr_bencDictAddInt( &top, KEY_CORRUPT, tor->corruptPrev + tor->corruptCur );
508    tr_bencDictAddInt( &top, KEY_DONE_DATE, tor->doneDate );
509    tr_bencDictAddStr( &top, KEY_DOWNLOAD_DIR, tor->downloadDir );
510    if( tor->incompleteDir != NULL )
511        tr_bencDictAddStr( &top, KEY_INCOMPLETE_DIR, tor->incompleteDir );
512    tr_bencDictAddInt( &top, KEY_DOWNLOADED, tor->downloadedPrev + tor->downloadedCur );
513    tr_bencDictAddInt( &top, KEY_UPLOADED, tor->uploadedPrev + tor->uploadedCur );
514    tr_bencDictAddInt( &top, KEY_MAX_PEERS, tor->maxConnectedPeers );
515    tr_bencDictAddInt( &top, KEY_BANDWIDTH_PRIORITY, tr_torrentGetPriority( tor ) );
516    tr_bencDictAddBool( &top, KEY_PAUSED, !tor->isRunning );
517    savePeers( &top, tor );
518    if( tr_torrentHasMetadata( tor ) )
519    {
520        saveFilePriorities( &top, tor );
521        saveDND( &top, tor );
522        saveProgress( &top, tor );
523    }
524    saveSpeedLimits( &top, tor );
525    saveRatioLimits( &top, tor );
526    saveIdleLimits( &top, tor );
527
528    filename = getResumeFilename( tor );
529    if(( err = tr_bencToFile( &top, TR_FMT_BENC, filename )))
530        tr_torrentSetLocalError( tor, "Unable to save resume file: %s", tr_strerror( err ) );
531    tr_free( filename );
532
533    tr_bencFree( &top );
534}
535
536static uint64_t
537loadFromFile( tr_torrent * tor,
538              uint64_t     fieldsToLoad )
539{
540    int64_t  i;
541    const char * str;
542    uint64_t fieldsLoaded = 0;
543    char * filename;
544    tr_benc top;
545    tr_bool boolVal;
546    const tr_bool  wasDirty = tor->isDirty;
547
548    assert( tr_isTorrent( tor ) );
549
550    filename = getResumeFilename( tor );
551
552    if( tr_bencLoadFile( &top, TR_FMT_BENC, filename ) )
553    {
554        tr_tordbg( tor, "Couldn't read \"%s\"", filename );
555
556        tr_free( filename );
557        return fieldsLoaded;
558    }
559
560    tr_tordbg( tor, "Read resume file \"%s\"", filename );
561
562    if( ( fieldsToLoad & TR_FR_CORRUPT )
563      && tr_bencDictFindInt( &top, KEY_CORRUPT, &i ) )
564    {
565        tor->corruptPrev = i;
566        fieldsLoaded |= TR_FR_CORRUPT;
567    }
568
569    if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR ) )
570      && ( tr_bencDictFindStr( &top, KEY_DOWNLOAD_DIR, &str ) )
571      && ( str && *str ) )
572    {
573        tr_free( tor->downloadDir );
574        tor->downloadDir = tr_strdup( str );
575        fieldsLoaded |= TR_FR_DOWNLOAD_DIR;
576    }
577
578    if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_INCOMPLETE_DIR ) )
579      && ( tr_bencDictFindStr( &top, KEY_INCOMPLETE_DIR, &str ) )
580      && ( str && *str ) )
581    {
582        tr_free( tor->incompleteDir );
583        tor->incompleteDir = tr_strdup( str );
584        fieldsLoaded |= TR_FR_INCOMPLETE_DIR;
585    }
586
587    if( ( fieldsToLoad & TR_FR_DOWNLOADED )
588      && tr_bencDictFindInt( &top, KEY_DOWNLOADED, &i ) )
589    {
590        tor->downloadedPrev = i;
591        fieldsLoaded |= TR_FR_DOWNLOADED;
592    }
593
594    if( ( fieldsToLoad & TR_FR_UPLOADED )
595      && tr_bencDictFindInt( &top, KEY_UPLOADED, &i ) )
596    {
597        tor->uploadedPrev = i;
598        fieldsLoaded |= TR_FR_UPLOADED;
599    }
600
601    if( ( fieldsToLoad & TR_FR_MAX_PEERS )
602      && tr_bencDictFindInt( &top, KEY_MAX_PEERS, &i ) )
603    {
604        tor->maxConnectedPeers = i;
605        fieldsLoaded |= TR_FR_MAX_PEERS;
606    }
607
608    if( ( fieldsToLoad & TR_FR_RUN )
609      && tr_bencDictFindBool( &top, KEY_PAUSED, &boolVal ) )
610    {
611        tor->isRunning = !boolVal;
612        fieldsLoaded |= TR_FR_RUN;
613    }
614
615    if( ( fieldsToLoad & TR_FR_ADDED_DATE )
616      && tr_bencDictFindInt( &top, KEY_ADDED_DATE, &i ) )
617    {
618        tor->addedDate = i;
619        fieldsLoaded |= TR_FR_ADDED_DATE;
620    }
621
622    if( ( fieldsToLoad & TR_FR_DONE_DATE )
623      && tr_bencDictFindInt( &top, KEY_DONE_DATE, &i ) )
624    {
625        tor->doneDate = i;
626        fieldsLoaded |= TR_FR_DONE_DATE;
627    }
628
629    if( ( fieldsToLoad & TR_FR_ACTIVITY_DATE )
630      && tr_bencDictFindInt( &top, KEY_ACTIVITY_DATE, &i ) )
631    {
632        tr_torrentSetActivityDate( tor, i );
633        fieldsLoaded |= TR_FR_ACTIVITY_DATE;
634    }
635
636    if( ( fieldsToLoad & TR_FR_TIME_SEEDING )
637      && tr_bencDictFindInt( &top, KEY_TIME_SEEDING, &i ) )
638    {
639        tor->secondsSeeding = i;
640        fieldsLoaded |= TR_FR_TIME_SEEDING;
641    }
642
643    if( ( fieldsToLoad & TR_FR_TIME_DOWNLOADING )
644      && tr_bencDictFindInt( &top, KEY_TIME_DOWNLOADING, &i ) )
645    {
646        tor->secondsDownloading = i;
647        fieldsLoaded |= TR_FR_TIME_DOWNLOADING;
648    }
649
650    if( ( fieldsToLoad & TR_FR_BANDWIDTH_PRIORITY )
651      && tr_bencDictFindInt( &top, KEY_BANDWIDTH_PRIORITY, &i )
652      && tr_isPriority( i ) )
653    {
654        tr_torrentSetPriority( tor, i );
655        fieldsLoaded |= TR_FR_BANDWIDTH_PRIORITY;
656    }
657
658    if( fieldsToLoad & TR_FR_PEERS )
659        fieldsLoaded |= loadPeers( &top, tor );
660
661    if( fieldsToLoad & TR_FR_FILE_PRIORITIES )
662        fieldsLoaded |= loadFilePriorities( &top, tor );
663
664    if( fieldsToLoad & TR_FR_PROGRESS )
665        fieldsLoaded |= loadProgress( &top, tor );
666
667    if( fieldsToLoad & TR_FR_DND )
668        fieldsLoaded |= loadDND( &top, tor );
669
670    if( fieldsToLoad & TR_FR_SPEEDLIMIT )
671        fieldsLoaded |= loadSpeedLimits( &top, tor );
672
673    if( fieldsToLoad & TR_FR_RATIOLIMIT )
674        fieldsLoaded |= loadRatioLimits( &top, tor );
675
676    if( fieldsToLoad & TR_FR_IDLELIMIT )
677        fieldsLoaded |= loadIdleLimits( &top, tor );
678
679    /* loading the resume file triggers of a lot of changes,
680     * but none of them needs to trigger a re-saving of the
681     * same resume information... */
682    tor->isDirty = wasDirty;
683
684    tr_bencFree( &top );
685    tr_free( filename );
686    return fieldsLoaded;
687}
688
689static uint64_t
690setFromCtor( tr_torrent *    tor,
691             uint64_t        fields,
692             const tr_ctor * ctor,
693             int             mode )
694{
695    uint64_t ret = 0;
696
697    if( fields & TR_FR_RUN )
698    {
699        uint8_t isPaused;
700        if( !tr_ctorGetPaused( ctor, mode, &isPaused ) )
701        {
702            tor->isRunning = !isPaused;
703            ret |= TR_FR_RUN;
704        }
705    }
706
707    if( fields & TR_FR_MAX_PEERS )
708        if( !tr_ctorGetPeerLimit( ctor, mode, &tor->maxConnectedPeers ) )
709            ret |= TR_FR_MAX_PEERS;
710
711    if( fields & TR_FR_DOWNLOAD_DIR )
712    {
713        const char * path;
714        if( !tr_ctorGetDownloadDir( ctor, mode, &path ) && path && *path )
715        {
716            ret |= TR_FR_DOWNLOAD_DIR;
717            tr_free( tor->downloadDir );
718            tor->downloadDir = tr_strdup( path );
719        }
720    }
721
722    return ret;
723}
724
725static uint64_t
726useManditoryFields( tr_torrent *    tor,
727                    uint64_t        fields,
728                    const tr_ctor * ctor )
729{
730    return setFromCtor( tor, fields, ctor, TR_FORCE );
731}
732
733static uint64_t
734useFallbackFields( tr_torrent *    tor,
735                   uint64_t        fields,
736                   const tr_ctor * ctor )
737{
738    return setFromCtor( tor, fields, ctor, TR_FALLBACK );
739}
740
741uint64_t
742tr_torrentLoadResume( tr_torrent *    tor,
743                      uint64_t        fieldsToLoad,
744                      const tr_ctor * ctor )
745{
746    uint64_t ret = 0;
747
748    assert( tr_isTorrent( tor ) );
749
750    ret |= useManditoryFields( tor, fieldsToLoad, ctor );
751    fieldsToLoad &= ~ret;
752    ret |= loadFromFile( tor, fieldsToLoad );
753    fieldsToLoad &= ~ret;
754    ret |= useFallbackFields( tor, fieldsToLoad, ctor );
755
756    return ret;
757}
758
759void
760tr_torrentRemoveResume( const tr_torrent * tor )
761{
762    char * filename = getResumeFilename( tor );
763    unlink( filename );
764    tr_free( filename );
765}
766
Note: See TracBrowser for help on using the repository browser.