source: trunk/libtransmission/resume.c @ 9816

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

(trunk libT) #2632 "Add streaming capability to libtransmission (but not the Transmission GUI clients)" -- implemented

  • Property svn:keywords set to Date Rev Author Id
File size: 21.1 KB
Line 
1/*
2 * This file Copyright (C) 2008-2009 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 9816 2009-12-24 01:02:54Z 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_STREAMING           "streaming"
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
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 );
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 bitfield */
401    bitfield = tr_cpBlockBitfield( &tor->completion );
402    tr_bencDictAddRaw( p, KEY_PROGRESS_BITFIELD,
403                       bitfield->bits, bitfield->byteCount );
404
405    /* cleanup */
406    tr_free( mtimes );
407}
408
409static uint64_t
410loadProgress( tr_benc *    dict,
411              tr_torrent * tor )
412{
413    uint64_t  ret = 0;
414    tr_benc * p;
415
416    if( tr_bencDictFindDict( dict, KEY_PROGRESS, &p ) )
417    {
418        const uint8_t * raw;
419        size_t          rawlen;
420        tr_benc *       m;
421        size_t          n;
422        time_t *        curMTimes = tr_torrentGetMTimes( tor, &n );
423
424        if( tr_bencDictFindList( p, KEY_PROGRESS_MTIMES, &m )
425          && ( n == tor->info.fileCount )
426          && ( n == tr_bencListSize( m ) ) )
427        {
428            size_t i;
429            for( i = 0; i < n; ++i )
430            {
431                int64_t tmp;
432                if( !tr_bencGetInt( tr_bencListChild( m, i ), &tmp ) )
433                {
434                    tr_tordbg(
435                        tor,
436                        "File #%zu needs to be verified - couldn't find benc entry",
437                        i );
438                    tr_torrentSetFileChecked( tor, i, FALSE );
439                }
440                else
441                {
442                    const time_t t = (time_t) tmp;
443                    if( t == curMTimes[i] )
444                        tr_torrentSetFileChecked( tor, i, TRUE );
445                    else
446                    {
447                        tr_tordbg(
448                            tor,
449                            "File #%zu needs to be verified - times %lu and %lu don't match",
450                            i, t, curMTimes[i] );
451                        tr_torrentSetFileChecked( tor, i, FALSE );
452                    }
453                }
454            }
455        }
456        else
457        {
458            tr_torrentUncheck( tor );
459            tr_tordbg(
460                tor, "Torrent needs to be verified - unable to find mtimes" );
461        }
462
463        if( tr_bencDictFindRaw( p, KEY_PROGRESS_BITFIELD, &raw, &rawlen ) )
464        {
465            tr_bitfield tmp;
466            tmp.byteCount = rawlen;
467            tmp.bitCount = tmp.byteCount * 8;
468            tmp.bits = (uint8_t*) raw;
469            if( !tr_cpBlockBitfieldSet( &tor->completion, &tmp ) )
470            {
471                tr_torrentUncheck( tor );
472                tr_tordbg(
473                    tor,
474                    "Torrent needs to be verified - error loading bitfield" );
475            }
476        }
477        else
478        {
479            tr_torrentUncheck( tor );
480            tr_tordbg(
481                tor,
482                "Torrent needs to be verified - unable to find bitfield" );
483        }
484
485        tr_free( curMTimes );
486        ret = TR_FR_PROGRESS;
487    }
488
489    return ret;
490}
491
492/***
493****
494***/
495
496void
497tr_torrentSaveResume( const tr_torrent * tor )
498{
499    tr_benc top;
500    char *  filename;
501
502    if( !tr_isTorrent( tor ) )
503        return;
504
505    tr_tordbg( tor, "Saving .resume file for \"%s\"", tr_torrentName( tor ) );
506
507    tr_bencInitDict( &top, 34 ); /* arbitrary "big enough" number */
508    tr_bencDictAddInt( &top, KEY_ACTIVITY_DATE, tor->activityDate );
509    tr_bencDictAddInt( &top, KEY_ADDED_DATE, tor->addedDate );
510    tr_bencDictAddInt( &top, KEY_CORRUPT, tor->corruptPrev + tor->corruptCur );
511    tr_bencDictAddInt( &top, KEY_DONE_DATE, tor->doneDate );
512    tr_bencDictAddStr( &top, KEY_DOWNLOAD_DIR, tor->downloadDir );
513    if( tor->incompleteDir != NULL )
514        tr_bencDictAddStr( &top, KEY_INCOMPLETE_DIR, tor->incompleteDir );
515    tr_bencDictAddInt( &top, KEY_DOWNLOADED, tor->downloadedPrev + tor->downloadedCur );
516    tr_bencDictAddInt( &top, KEY_UPLOADED, tor->uploadedPrev + tor->uploadedCur );
517    tr_bencDictAddInt( &top, KEY_MAX_PEERS, tor->maxConnectedPeers );
518    tr_bencDictAddInt( &top, KEY_BANDWIDTH_PRIORITY, tr_torrentGetPriority( tor ) );
519    tr_bencDictAddBool( &top, KEY_PAUSED, !tor->isRunning );
520    tr_bencDictAddBool( &top, KEY_STREAMING, tr_torrentIsStreaming( tor ) );
521    savePeers( &top, tor );
522    saveFilePriorities( &top, tor );
523    saveDND( &top, tor );
524    saveProgress( &top, tor );
525    saveSpeedLimits( &top, tor );
526    saveRatioLimits( &top, tor );
527
528    filename = getResumeFilename( tor );
529    tr_bencToFile( &top, TR_FMT_BENC, filename );
530    tr_free( filename );
531
532    tr_bencFree( &top );
533}
534
535static uint64_t
536loadFromFile( tr_torrent * tor,
537              uint64_t     fieldsToLoad )
538{
539    int64_t  i;
540    const char * str;
541    uint64_t fieldsLoaded = 0;
542    char * filename;
543    tr_benc top;
544    tr_bool boolVal;
545    const tr_bool  wasDirty = tor->isDirty;
546
547    assert( tr_isTorrent( tor ) );
548
549    filename = getResumeFilename( tor );
550
551    if( tr_bencLoadFile( &top, TR_FMT_BENC, filename ) )
552    {
553        tr_tordbg( tor, "Couldn't read \"%s\"", filename );
554
555        tr_free( filename );
556        return fieldsLoaded;
557    }
558
559    tr_tordbg( tor, "Read resume file \"%s\"", filename );
560
561    if( ( fieldsToLoad & TR_FR_CORRUPT )
562      && tr_bencDictFindInt( &top, KEY_CORRUPT, &i ) )
563    {
564        tor->corruptPrev = i;
565        fieldsLoaded |= TR_FR_CORRUPT;
566    }
567
568    if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR ) )
569      && ( tr_bencDictFindStr( &top, KEY_DOWNLOAD_DIR, &str ) )
570      && ( str && *str ) )
571    {
572        tr_free( tor->downloadDir );
573        tor->downloadDir = tr_strdup( str );
574        fieldsLoaded |= TR_FR_DOWNLOAD_DIR;
575    }
576
577    if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_INCOMPLETE_DIR ) )
578      && ( tr_bencDictFindStr( &top, KEY_INCOMPLETE_DIR, &str ) )
579      && ( str && *str ) )
580    {
581        tr_free( tor->incompleteDir );
582        tor->incompleteDir = tr_strdup( str );
583        fieldsLoaded |= TR_FR_INCOMPLETE_DIR;
584    }
585
586    if( ( fieldsToLoad & TR_FR_DOWNLOADED )
587      && tr_bencDictFindInt( &top, KEY_DOWNLOADED, &i ) )
588    {
589        tor->downloadedPrev = i;
590        fieldsLoaded |= TR_FR_DOWNLOADED;
591    }
592
593    if( ( fieldsToLoad & TR_FR_UPLOADED )
594      && tr_bencDictFindInt( &top, KEY_UPLOADED, &i ) )
595    {
596        tor->uploadedPrev = i;
597        fieldsLoaded |= TR_FR_UPLOADED;
598    }
599
600    if( ( fieldsToLoad & TR_FR_MAX_PEERS )
601      && tr_bencDictFindInt( &top, KEY_MAX_PEERS, &i ) )
602    {
603        tor->maxConnectedPeers = i;
604        fieldsLoaded |= TR_FR_MAX_PEERS;
605    }
606
607    if( ( fieldsToLoad & TR_FR_RUN )
608      && tr_bencDictFindBool( &top, KEY_PAUSED, &boolVal ) )
609    {
610        tor->isRunning = !boolVal;
611        fieldsLoaded |= TR_FR_RUN;
612    }
613
614    if( ( fieldsToLoad & TR_FR_STREAMING )
615      && tr_bencDictFindBool( &top, KEY_STREAMING, &boolVal ) )
616    {
617        tor->isStreaming = boolVal;
618        fieldsLoaded |= TR_FR_STREAMING;
619    }
620
621    if( ( fieldsToLoad & TR_FR_ADDED_DATE )
622      && tr_bencDictFindInt( &top, KEY_ADDED_DATE, &i ) )
623    {
624        tor->addedDate = i;
625        fieldsLoaded |= TR_FR_ADDED_DATE;
626    }
627
628    if( ( fieldsToLoad & TR_FR_DONE_DATE )
629      && tr_bencDictFindInt( &top, KEY_DONE_DATE, &i ) )
630    {
631        tor->doneDate = i;
632        fieldsLoaded |= TR_FR_DONE_DATE;
633    }
634
635    if( ( fieldsToLoad & TR_FR_ACTIVITY_DATE )
636      && tr_bencDictFindInt( &top, KEY_ACTIVITY_DATE, &i ) )
637    {
638        tr_torrentSetActivityDate( tor, i );
639        fieldsLoaded |= TR_FR_ACTIVITY_DATE;
640    }
641
642    if( ( fieldsToLoad & TR_FR_BANDWIDTH_PRIORITY )
643      && tr_bencDictFindInt( &top, KEY_BANDWIDTH_PRIORITY, &i )
644      && tr_isPriority( i ) )
645    {
646        tr_torrentSetPriority( tor, i );
647        fieldsLoaded |= TR_FR_BANDWIDTH_PRIORITY;
648    }
649
650    if( fieldsToLoad & TR_FR_PEERS )
651        fieldsLoaded |= loadPeers( &top, tor );
652
653    if( fieldsToLoad & TR_FR_FILE_PRIORITIES )
654        fieldsLoaded |= loadFilePriorities( &top, tor );
655
656    if( fieldsToLoad & TR_FR_PROGRESS )
657        fieldsLoaded |= loadProgress( &top, tor );
658
659    if( fieldsToLoad & TR_FR_DND )
660        fieldsLoaded |= loadDND( &top, tor );
661
662    if( fieldsToLoad & TR_FR_SPEEDLIMIT )
663        fieldsLoaded |= loadSpeedLimits( &top, tor );
664
665    if( fieldsToLoad & TR_FR_RATIOLIMIT )
666        fieldsLoaded |= loadRatioLimits( &top, tor );
667
668    /* loading the resume file triggers of a lot of changes,
669     * but none of them needs to trigger a re-saving of the
670     * same resume information... */
671    tor->isDirty = wasDirty;
672
673    tr_bencFree( &top );
674    tr_free( filename );
675    return fieldsLoaded;
676}
677
678static uint64_t
679setFromCtor( tr_torrent *    tor,
680             uint64_t        fields,
681             const tr_ctor * ctor,
682             int             mode )
683{
684    uint64_t ret = 0;
685
686    if( fields & TR_FR_RUN )
687    {
688        uint8_t isPaused;
689        if( !tr_ctorGetPaused( ctor, mode, &isPaused ) )
690        {
691            tor->isRunning = !isPaused;
692            ret |= TR_FR_RUN;
693        }
694    }
695
696    if( fields & TR_FR_MAX_PEERS )
697        if( !tr_ctorGetPeerLimit( ctor, mode, &tor->maxConnectedPeers ) )
698            ret |= TR_FR_MAX_PEERS;
699
700    if( fields & TR_FR_DOWNLOAD_DIR )
701    {
702        const char * path;
703        if( !tr_ctorGetDownloadDir( ctor, mode, &path ) && path && *path )
704        {
705            ret |= TR_FR_DOWNLOAD_DIR;
706            tr_free( tor->downloadDir );
707            tor->downloadDir = tr_strdup( path );
708        }
709    }
710
711    return ret;
712}
713
714static uint64_t
715useManditoryFields( tr_torrent *    tor,
716                    uint64_t        fields,
717                    const tr_ctor * ctor )
718{
719    return setFromCtor( tor, fields, ctor, TR_FORCE );
720}
721
722static uint64_t
723useFallbackFields( tr_torrent *    tor,
724                   uint64_t        fields,
725                   const tr_ctor * ctor )
726{
727    return setFromCtor( tor, fields, ctor, TR_FALLBACK );
728}
729
730uint64_t
731tr_torrentLoadResume( tr_torrent *    tor,
732                      uint64_t        fieldsToLoad,
733                      const tr_ctor * ctor )
734{
735    uint64_t ret = 0;
736
737    assert( tr_isTorrent( tor ) );
738
739    ret |= useManditoryFields( tor, fieldsToLoad, ctor );
740    fieldsToLoad &= ~ret;
741    ret |= loadFromFile( tor, fieldsToLoad );
742    fieldsToLoad &= ~ret;
743    ret |= useFallbackFields( tor, fieldsToLoad, ctor );
744
745    return ret;
746}
747
748void
749tr_torrentRemoveResume( const tr_torrent * tor )
750{
751    char * filename = getResumeFilename( tor );
752    unlink( filename );
753    tr_free( filename );
754}
755
Note: See TracBrowser for help on using the repository browser.