source: trunk/libtransmission/resume.c @ 10502

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

(trunk libT) #3136 "slashes in magnet names" -- fixed in trunk for 2.00

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