source: trunk/libtransmission/resume.c @ 13683

Last change on this file since 13683 was 13683, checked in by jordan, 8 years ago

(trunk, libT) first drop of the tr_quark patch.

  • Property svn:keywords set to Date Rev Author Id
File size: 24.2 KB
Line 
1/*
2 * This file Copyright (C) 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 13683 2012-12-22 20:35:19Z jordan $
11 */
12
13#include <unistd.h> /* unlink */
14
15#include <string.h>
16
17#include "transmission.h"
18#include "completion.h"
19#include "metainfo.h" /* tr_metainfoGetBasename () */
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#include "variant.h"
27
28enum
29{
30    MAX_REMEMBERED_PEERS = 200
31};
32
33static char*
34getResumeFilename (const tr_torrent * tor)
35{
36    char * base = tr_metainfoGetBasename (tr_torrentInfo (tor));
37    char * filename = tr_strdup_printf ("%s" TR_PATH_DELIMITER_STR "%s.resume",
38                                        tr_getResumeDir (tor->session), base);
39    tr_free (base);
40    return filename;
41}
42
43/***
44****
45***/
46
47static void
48savePeers (tr_variant * dict, const tr_torrent * tor)
49{
50    int count;
51    tr_pex * pex;
52
53    count = tr_peerMgrGetPeers ((tr_torrent*) tor, &pex, TR_AF_INET, TR_PEERS_INTERESTING, MAX_REMEMBERED_PEERS);
54    if (count > 0)
55        tr_variantDictAddRaw (dict, TR_KEY_peers2, pex, sizeof (tr_pex) * count);
56    tr_free (pex);
57
58    count = tr_peerMgrGetPeers ((tr_torrent*) tor, &pex, TR_AF_INET6, TR_PEERS_INTERESTING, MAX_REMEMBERED_PEERS);
59    if (count > 0)
60        tr_variantDictAddRaw (dict, TR_KEY_peers2_6, pex, sizeof (tr_pex) * count);
61
62    tr_free (pex);
63}
64
65static int
66addPeers (tr_torrent * tor, const uint8_t * buf, int buflen)
67{
68    int i;
69    int numAdded = 0;
70    const int count = buflen / sizeof (tr_pex);
71
72    for (i=0; i<count && numAdded<MAX_REMEMBERED_PEERS; ++i)
73    {
74        tr_pex pex;
75        memcpy (&pex, buf + (i * sizeof (tr_pex)), sizeof (tr_pex));
76        if (tr_isPex (&pex))
77        {
78            tr_peerMgrAddPex (tor, TR_PEER_FROM_RESUME, &pex, -1);
79            ++numAdded;
80        }
81    }
82
83    return numAdded;
84}
85
86
87static uint64_t
88loadPeers (tr_variant * dict, tr_torrent * tor)
89{
90    uint64_t        ret = 0;
91    const uint8_t * str;
92    size_t          len;
93
94    if (tr_variantDictFindRaw (dict, TR_KEY_peers, &str, &len))
95    {
96        const int numAdded = addPeers (tor, str, len);
97        tr_tordbg (tor, "Loaded %d IPv4 peers from resume file", numAdded);
98        ret = TR_FR_PEERS;
99    }
100
101    if (tr_variantDictFindRaw (dict, TR_KEY_peers6, &str, &len))
102    {
103        const int numAdded = addPeers (tor, str, len);
104        tr_tordbg (tor, "Loaded %d IPv6 peers from resume file", numAdded);
105        ret = TR_FR_PEERS;
106    }
107
108    return ret;
109}
110
111/***
112****
113***/
114
115static void
116saveDND (tr_variant * dict, const tr_torrent * tor)
117{
118    tr_variant * list;
119    tr_file_index_t i;
120    const tr_info * const inf = tr_torrentInfo (tor);
121    const tr_file_index_t n = inf->fileCount;
122
123    list = tr_variantDictAddList (dict, TR_KEY_dnd, n);
124    for (i=0; i<n; ++i)
125        tr_variantListAddInt (list, inf->files[i].dnd ? 1 : 0);
126}
127
128static uint64_t
129loadDND (tr_variant * dict, tr_torrent * tor)
130{
131    uint64_t ret = 0;
132    tr_variant * list = NULL;
133    const tr_file_index_t n = tor->info.fileCount;
134
135    if (tr_variantDictFindList (dict, TR_KEY_dnd, &list)
136      && (tr_variantListSize (list) == n))
137    {
138        int64_t           tmp;
139        tr_file_index_t * dl = tr_new (tr_file_index_t, n);
140        tr_file_index_t * dnd = tr_new (tr_file_index_t, n);
141        tr_file_index_t   i, dlCount = 0, dndCount = 0;
142
143        for (i=0; i<n; ++i)
144        {
145            if (tr_variantGetInt (tr_variantListChild (list, i), &tmp) && tmp)
146                dnd[dndCount++] = i;
147            else
148                dl[dlCount++] = i;
149        }
150
151        if (dndCount)
152        {
153            tr_torrentInitFileDLs (tor, dnd, dndCount, false);
154            tr_tordbg (tor, "Resume file found %d files listed as dnd",
155                       dndCount);
156        }
157        if (dlCount)
158        {
159            tr_torrentInitFileDLs (tor, dl, dlCount, true);
160            tr_tordbg (tor,
161                       "Resume file found %d files marked for download",
162                       dlCount);
163        }
164
165        tr_free (dnd);
166        tr_free (dl);
167        ret = TR_FR_DND;
168    }
169    else
170    {
171        tr_tordbg (
172            tor,
173            "Couldn't load DND flags. DND list (%p) has %zu children; torrent has %d files",
174            list, tr_variantListSize (list), (int)n);
175    }
176
177    return ret;
178}
179
180/***
181****
182***/
183
184static void
185saveFilePriorities (tr_variant * dict, const tr_torrent * tor)
186{
187    tr_variant * list;
188    tr_file_index_t i;
189    const tr_info * const inf = tr_torrentInfo (tor);
190    const tr_file_index_t n = inf->fileCount;
191
192    list = tr_variantDictAddList (dict, TR_KEY_priority, n);
193    for (i = 0; i < n; ++i)
194        tr_variantListAddInt (list, inf->files[i].priority);
195}
196
197static uint64_t
198loadFilePriorities (tr_variant * dict, tr_torrent * tor)
199{
200    tr_variant * list;
201    uint64_t ret = 0;
202    const tr_file_index_t n = tor->info.fileCount;
203
204    if (tr_variantDictFindList (dict, TR_KEY_priority, &list)
205      && (tr_variantListSize (list) == n))
206    {
207        int64_t priority;
208        tr_file_index_t i;
209        for (i = 0; i < n; ++i)
210            if (tr_variantGetInt (tr_variantListChild (list, i), &priority))
211                tr_torrentInitFilePriority (tor, i, priority);
212        ret = TR_FR_FILE_PRIORITIES;
213    }
214
215    return ret;
216}
217
218/***
219****
220***/
221
222static void
223saveSingleSpeedLimit (tr_variant * d, tr_torrent * tor, tr_direction dir)
224{
225    tr_variantDictReserve (d, 3);
226    tr_variantDictAddInt (d, TR_KEY_speed_Bps, tr_torrentGetSpeedLimit_Bps (tor, dir));
227    tr_variantDictAddBool (d, TR_KEY_use_global_speed_limit, tr_torrentUsesSessionLimits (tor));
228    tr_variantDictAddBool (d, TR_KEY_use_speed_limit, tr_torrentUsesSpeedLimit (tor, dir));
229}
230
231static void
232saveSpeedLimits (tr_variant * dict, tr_torrent * tor)
233{
234    saveSingleSpeedLimit (tr_variantDictAddDict (dict, TR_KEY_speed_limit_down, 0), tor, TR_DOWN);
235    saveSingleSpeedLimit (tr_variantDictAddDict (dict, TR_KEY_speed_limit_up, 0), tor, TR_UP);
236}
237
238static void
239saveRatioLimits (tr_variant * dict, tr_torrent * tor)
240{
241    tr_variant * d = tr_variantDictAddDict (dict, TR_KEY_ratio_limit, 2);
242    tr_variantDictAddReal (d, TR_KEY_ratio_limit, tr_torrentGetRatioLimit (tor));
243    tr_variantDictAddInt (d, TR_KEY_ratio_mode, tr_torrentGetRatioMode (tor));
244}
245
246static void
247saveIdleLimits (tr_variant * dict, tr_torrent * tor)
248{
249    tr_variant * d = tr_variantDictAddDict (dict, TR_KEY_idle_limit, 2);
250    tr_variantDictAddInt (d, TR_KEY_idle_limit, tr_torrentGetIdleLimit (tor));
251    tr_variantDictAddInt (d, TR_KEY_idle_mode, tr_torrentGetIdleMode (tor));
252}
253
254static void
255loadSingleSpeedLimit (tr_variant * d, tr_direction dir, tr_torrent * tor)
256{
257    int64_t i;
258    bool boolVal;
259
260    if (tr_variantDictFindInt (d, TR_KEY_speed_Bps, &i))
261        tr_torrentSetSpeedLimit_Bps (tor, dir, i);
262    else if (tr_variantDictFindInt (d, TR_KEY_speed, &i))
263        tr_torrentSetSpeedLimit_Bps (tor, dir, i*1024);
264
265    if (tr_variantDictFindBool (d, TR_KEY_use_speed_limit, &boolVal))
266        tr_torrentUseSpeedLimit (tor, dir, boolVal);
267
268    if (tr_variantDictFindBool (d, TR_KEY_use_global_speed_limit, &boolVal))
269        tr_torrentUseSessionLimits (tor, boolVal);
270}
271
272enum old_speed_modes
273{
274    TR_SPEEDLIMIT_GLOBAL,   /* only follow the overall speed limit */
275    TR_SPEEDLIMIT_SINGLE    /* only follow the per-torrent limit */
276};
277
278static uint64_t
279loadSpeedLimits (tr_variant * dict, tr_torrent * tor)
280{
281    tr_variant * d;
282    uint64_t ret = 0;
283
284
285    if (tr_variantDictFindDict (dict, TR_KEY_speed_limit_up, &d))
286    {
287        loadSingleSpeedLimit (d, TR_UP, tor);
288        ret = TR_FR_SPEEDLIMIT;
289    }
290    if (tr_variantDictFindDict (dict, TR_KEY_speed_limit_down, &d))
291    {
292        loadSingleSpeedLimit (d, TR_DOWN, tor);
293        ret = TR_FR_SPEEDLIMIT;
294    }
295
296    return ret;
297}
298
299static uint64_t
300loadRatioLimits (tr_variant * dict, tr_torrent * tor)
301{
302    tr_variant * d;
303    uint64_t ret = 0;
304
305    if (tr_variantDictFindDict (dict, TR_KEY_ratio_limit, &d))
306    {
307        int64_t i;
308        double dratio;
309        if (tr_variantDictFindReal (d, TR_KEY_ratio_limit, &dratio))
310            tr_torrentSetRatioLimit (tor, dratio);
311        if (tr_variantDictFindInt (d, TR_KEY_ratio_mode, &i))
312            tr_torrentSetRatioMode (tor, i);
313      ret = TR_FR_RATIOLIMIT;
314    }
315
316    return ret;
317}
318
319static uint64_t
320loadIdleLimits (tr_variant * dict, tr_torrent * tor)
321{
322    tr_variant * d;
323    uint64_t ret = 0;
324
325    if (tr_variantDictFindDict (dict, TR_KEY_idle_limit, &d))
326    {
327        int64_t i;
328        int64_t imin;
329        if (tr_variantDictFindInt (d, TR_KEY_idle_limit, &imin))
330            tr_torrentSetIdleLimit (tor, imin);
331        if (tr_variantDictFindInt (d, TR_KEY_idle_mode, &i))
332            tr_torrentSetIdleMode (tor, i);
333      ret = TR_FR_IDLELIMIT;
334    }
335
336    return ret;
337}
338/***
339****
340***/
341
342static void
343bitfieldToBenc (const tr_bitfield * b, tr_variant * benc)
344{
345    if (tr_bitfieldHasAll (b))
346        tr_variantInitStr (benc, "all", 3);
347    else if (tr_bitfieldHasNone (b))
348        tr_variantInitStr (benc, "none", 4);
349    else {
350        size_t byte_count = 0;
351        uint8_t * raw = tr_bitfieldGetRaw (b, &byte_count);
352        tr_variantInitRaw (benc, raw, byte_count);
353        tr_free (raw);
354    }
355}
356
357
358static void
359saveProgress (tr_variant * dict, tr_torrent * tor)
360{
361    tr_variant * l;
362    tr_variant * prog;
363    tr_file_index_t fi;
364    const tr_info * inf = tr_torrentInfo (tor);
365    const time_t now = tr_time ();
366
367    prog = tr_variantDictAddDict (dict, TR_KEY_progress, 3);
368
369    /* add the file/piece check timestamps... */
370    l = tr_variantDictAddList (prog, TR_KEY_time_checked, inf->fileCount);
371    for (fi=0; fi<inf->fileCount; ++fi)
372    {
373        const tr_piece * p;
374        const tr_piece * pend;
375        time_t oldest_nonzero = now;
376        time_t newest = 0;
377        bool has_zero = false;
378        const time_t mtime = tr_torrentGetFileMTime (tor, fi);
379        const tr_file * f = &inf->files[fi];
380
381        /* get the oldest and newest nonzero timestamps for pieces in this file */
382        for (p=&inf->pieces[f->firstPiece], pend=&inf->pieces[f->lastPiece]; p!=pend; ++p)
383        {
384            if (!p->timeChecked)
385                has_zero = true;
386            else if (oldest_nonzero > p->timeChecked)
387                oldest_nonzero = p->timeChecked;
388            if (newest < p->timeChecked)
389                newest = p->timeChecked;
390        }
391
392        /* If some of a file's pieces have been checked more recently than
393           the file's mtime, and some lest recently, then that file will
394           have a list containing timestamps for each piece.
395
396           However, the most common use case is that the file doesn't change
397           after it's downloaded. To reduce overhead in the .resume file,
398           only a single timestamp is saved for the file if *all* or *none*
399           of the pieces were tested more recently than the file's mtime. */
400
401        if (!has_zero && (mtime <= oldest_nonzero)) /* all checked */
402            tr_variantListAddInt (l, oldest_nonzero);
403        else if (newest < mtime) /* none checked */
404            tr_variantListAddInt (l, newest);
405        else { /* some are checked, some aren't... so list piece by piece */
406            const int offset = oldest_nonzero - 1;
407            tr_variant * ll = tr_variantListAddList (l, 2 + f->lastPiece - f->firstPiece);
408            tr_variantListAddInt (ll, offset);
409            for (p=&inf->pieces[f->firstPiece], pend=&inf->pieces[f->lastPiece]+1; p!=pend; ++p)
410                tr_variantListAddInt (ll, p->timeChecked ? p->timeChecked - offset : 0);
411        }
412    }
413
414    /* add the progress */
415    if (tor->completeness == TR_SEED)
416        tr_variantDictAddStr (prog, TR_KEY_have, "all");
417
418    /* add the blocks bitfield */
419    bitfieldToBenc (&tor->completion.blockBitfield, tr_variantDictAdd (prog, TR_KEY_blocks));
420}
421
422static uint64_t
423loadProgress (tr_variant * dict, tr_torrent * tor)
424{
425    size_t i, n;
426    uint64_t ret = 0;
427    tr_variant * prog;
428    const tr_info * inf = tr_torrentInfo (tor);
429
430    for (i=0, n=inf->pieceCount; i<n; ++i)
431        inf->pieces[i].timeChecked = 0;
432
433    if (tr_variantDictFindDict (dict, TR_KEY_progress, &prog))
434    {
435        const char * err;
436        const char * str;
437        const uint8_t * raw;
438        size_t rawlen;
439        tr_variant * l;
440        tr_variant * b;
441        struct tr_bitfield blocks = TR_BITFIELD_INIT;
442
443        if (tr_variantDictFindList (prog, TR_KEY_time_checked, &l))
444        {
445            /* per-piece timestamps were added in 2.20.
446
447               If some of a file's pieces have been checked more recently than
448               the file's mtime, and some lest recently, then that file will
449               have a list containing timestamps for each piece.
450
451               However, the most common use case is that the file doesn't change
452               after it's downloaded. To reduce overhead in the .resume file,
453               only a single timestamp is saved for the file if *all* or *none*
454               of the pieces were tested more recently than the file's mtime. */
455
456            tr_file_index_t fi;
457
458            for (fi=0; fi<inf->fileCount; ++fi)
459            {
460                tr_variant * b = tr_variantListChild (l, fi);
461                const tr_file * f = &inf->files[fi];
462                tr_piece * p = &inf->pieces[f->firstPiece];
463                const tr_piece * pend = &inf->pieces[f->lastPiece]+1;
464
465                if (tr_variantIsInt (b))
466                {
467                    int64_t t;
468                    tr_variantGetInt (b, &t);
469                    for (; p!=pend; ++p)
470                        p->timeChecked = (time_t)t;
471                }
472                else if (tr_variantIsList (b))
473                {
474                    int i = 0;
475                    int64_t offset = 0;
476                    const int pieces = f->lastPiece + 1 - f->firstPiece;
477
478                    tr_variantGetInt (tr_variantListChild (b, 0), &offset);
479
480                    for (i=0; i<pieces; ++i)
481                    {
482                        int64_t t = 0;
483                        tr_variantGetInt (tr_variantListChild (b, i+1), &t);
484                        inf->pieces[f->firstPiece+i].timeChecked = (time_t)(t ? t + offset : 0);
485                    }
486                }
487            }
488        }
489        else if (tr_variantDictFindList (prog, TR_KEY_mtimes, &l))
490        {
491            tr_file_index_t fi;
492
493            /* Before 2.20, we stored the files' mtimes in the .resume file.
494               When loading the .resume file, a torrent's file would be flagged
495               as untested if its stored mtime didn't match its real mtime. */
496
497            for (fi=0; fi<inf->fileCount; ++fi)
498            {
499                int64_t t;
500
501                if (tr_variantGetInt (tr_variantListChild (l, fi), &t))
502                {
503                    const tr_file * f = &inf->files[fi];
504                    tr_piece * p = &inf->pieces[f->firstPiece];
505                    const tr_piece * pend = &inf->pieces[f->lastPiece];
506                    const time_t mtime = tr_torrentGetFileMTime (tor, fi);
507                    const time_t timeChecked = mtime==t ? mtime : 0;
508
509                    for (; p!=pend; ++p)
510                        p->timeChecked = timeChecked;
511                }
512            }
513        }
514
515        err = NULL;
516        tr_bitfieldConstruct (&blocks, tor->blockCount);
517
518        if ((b = tr_variantDictFind (prog, TR_KEY_blocks)))
519        {
520            size_t buflen;
521            const uint8_t * buf;
522
523            if (!tr_variantGetRaw (b, &buf, &buflen))
524                err = "Invalid value for \"blocks\"";
525            else if ((buflen == 3) && !memcmp (buf, "all", 3))
526                tr_bitfieldSetHasAll (&blocks);
527            else if ((buflen == 4) && !memcmp (buf, "none", 4))
528                tr_bitfieldSetHasNone (&blocks);
529            else
530                tr_bitfieldSetRaw (&blocks, buf, buflen, true);
531        }
532        else if (tr_variantDictFindStr (prog, TR_KEY_have, &str, NULL))
533        {
534            if (!strcmp (str, "all"))
535                tr_bitfieldSetHasAll (&blocks);
536            else
537                err = "Invalid value for HAVE";
538        }
539        else if (tr_variantDictFindRaw (prog, TR_KEY_bitfield, &raw, &rawlen))
540        {
541            tr_bitfieldSetRaw (&blocks, raw, rawlen, true);
542        }
543        else err = "Couldn't find 'pieces' or 'have' or 'bitfield'";
544
545        if (err != NULL)
546            tr_tordbg (tor, "Torrent needs to be verified - %s", err);
547        else
548            tr_cpBlockInit (&tor->completion, &blocks);
549
550        tr_bitfieldDestruct (&blocks);
551        ret = TR_FR_PROGRESS;
552    }
553
554    return ret;
555}
556
557/***
558****
559***/
560
561void
562tr_torrentSaveResume (tr_torrent * tor)
563{
564    int err;
565    tr_variant top;
566    char * filename;
567
568    if (!tr_isTorrent (tor))
569        return;
570
571    tr_variantInitDict (&top, 50); /* arbitrary "big enough" number */
572    tr_variantDictAddInt (&top, TR_KEY_seeding_time_seconds, tor->secondsSeeding);
573    tr_variantDictAddInt (&top, TR_KEY_downloading_time_seconds, tor->secondsDownloading);
574    tr_variantDictAddInt (&top, TR_KEY_activity_date, tor->activityDate);
575    tr_variantDictAddInt (&top, TR_KEY_added_date, tor->addedDate);
576    tr_variantDictAddInt (&top, TR_KEY_corrupt, tor->corruptPrev + tor->corruptCur);
577    tr_variantDictAddInt (&top, TR_KEY_done_date, tor->doneDate);
578    tr_variantDictAddStr (&top, TR_KEY_destination, tor->downloadDir);
579    if (tor->incompleteDir != NULL)
580        tr_variantDictAddStr (&top, TR_KEY_incomplete_dir, tor->incompleteDir);
581    tr_variantDictAddInt (&top, TR_KEY_downloaded, tor->downloadedPrev + tor->downloadedCur);
582    tr_variantDictAddInt (&top, TR_KEY_uploaded, tor->uploadedPrev + tor->uploadedCur);
583    tr_variantDictAddInt (&top, TR_KEY_max_peers, tor->maxConnectedPeers);
584    tr_variantDictAddInt (&top, TR_KEY_bandwidth_priority, tr_torrentGetPriority (tor));
585    tr_variantDictAddBool (&top, TR_KEY_paused, !tor->isRunning);
586    savePeers (&top, tor);
587    if (tr_torrentHasMetadata (tor))
588    {
589        saveFilePriorities (&top, tor);
590        saveDND (&top, tor);
591        saveProgress (&top, tor);
592    }
593    saveSpeedLimits (&top, tor);
594    saveRatioLimits (&top, tor);
595    saveIdleLimits (&top, tor);
596
597    filename = getResumeFilename (tor);
598    if ((err = tr_variantToFile (&top, TR_VARIANT_FMT_BENC, filename)))
599        tr_torrentSetLocalError (tor, "Unable to save resume file: %s", tr_strerror (err));
600    tr_free (filename);
601
602    tr_variantFree (&top);
603}
604
605static uint64_t
606loadFromFile (tr_torrent * tor, uint64_t fieldsToLoad)
607{
608    size_t len;
609    int64_t  i;
610    const char * str;
611    char * filename;
612    tr_variant top;
613    bool boolVal;
614    uint64_t fieldsLoaded = 0;
615    const bool wasDirty = tor->isDirty;
616
617    assert (tr_isTorrent (tor));
618
619    filename = getResumeFilename (tor);
620
621    if (tr_variantFromFile (&top, TR_VARIANT_FMT_BENC, filename))
622    {
623        tr_tordbg (tor, "Couldn't read \"%s\"", filename);
624
625        tr_free (filename);
626        return fieldsLoaded;
627    }
628
629    tr_tordbg (tor, "Read resume file \"%s\"", filename);
630
631    if ((fieldsToLoad & TR_FR_CORRUPT)
632      && tr_variantDictFindInt (&top, TR_KEY_corrupt, &i))
633    {
634        tor->corruptPrev = i;
635        fieldsLoaded |= TR_FR_CORRUPT;
636    }
637
638    if ((fieldsToLoad & (TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR))
639      && (tr_variantDictFindStr (&top, TR_KEY_destination, &str, &len))
640      && (str && *str))
641    {
642        tr_free (tor->downloadDir);
643        tor->downloadDir = tr_strndup (str, len);
644        fieldsLoaded |= TR_FR_DOWNLOAD_DIR;
645    }
646
647    if ((fieldsToLoad & (TR_FR_PROGRESS | TR_FR_INCOMPLETE_DIR))
648      && (tr_variantDictFindStr (&top, TR_KEY_incomplete_dir, &str, &len))
649      && (str && *str))
650    {
651        tr_free (tor->incompleteDir);
652        tor->incompleteDir = tr_strndup (str, len);
653        fieldsLoaded |= TR_FR_INCOMPLETE_DIR;
654    }
655
656    if ((fieldsToLoad & TR_FR_DOWNLOADED)
657      && tr_variantDictFindInt (&top, TR_KEY_downloaded, &i))
658    {
659        tor->downloadedPrev = i;
660        fieldsLoaded |= TR_FR_DOWNLOADED;
661    }
662
663    if ((fieldsToLoad & TR_FR_UPLOADED)
664      && tr_variantDictFindInt (&top, TR_KEY_uploaded, &i))
665    {
666        tor->uploadedPrev = i;
667        fieldsLoaded |= TR_FR_UPLOADED;
668    }
669
670    if ((fieldsToLoad & TR_FR_MAX_PEERS)
671      && tr_variantDictFindInt (&top, TR_KEY_max_peers, &i))
672    {
673        tor->maxConnectedPeers = i;
674        fieldsLoaded |= TR_FR_MAX_PEERS;
675    }
676
677    if ((fieldsToLoad & TR_FR_RUN)
678      && tr_variantDictFindBool (&top, TR_KEY_paused, &boolVal))
679    {
680        tor->isRunning = !boolVal;
681        fieldsLoaded |= TR_FR_RUN;
682    }
683
684    if ((fieldsToLoad & TR_FR_ADDED_DATE)
685      && tr_variantDictFindInt (&top, TR_KEY_added_date, &i))
686    {
687        tor->addedDate = i;
688        fieldsLoaded |= TR_FR_ADDED_DATE;
689    }
690
691    if ((fieldsToLoad & TR_FR_DONE_DATE)
692      && tr_variantDictFindInt (&top, TR_KEY_done_date, &i))
693    {
694        tor->doneDate = i;
695        fieldsLoaded |= TR_FR_DONE_DATE;
696    }
697
698    if ((fieldsToLoad & TR_FR_ACTIVITY_DATE)
699      && tr_variantDictFindInt (&top, TR_KEY_activity_date, &i))
700    {
701        tr_torrentSetActivityDate (tor, i);
702        fieldsLoaded |= TR_FR_ACTIVITY_DATE;
703    }
704
705    if ((fieldsToLoad & TR_FR_TIME_SEEDING)
706      && tr_variantDictFindInt (&top, TR_KEY_seeding_time_seconds, &i))
707    {
708        tor->secondsSeeding = i;
709        fieldsLoaded |= TR_FR_TIME_SEEDING;
710    }
711
712    if ((fieldsToLoad & TR_FR_TIME_DOWNLOADING)
713      && tr_variantDictFindInt (&top, TR_KEY_downloading_time_seconds, &i))
714    {
715        tor->secondsDownloading = i;
716        fieldsLoaded |= TR_FR_TIME_DOWNLOADING;
717    }
718
719    if ((fieldsToLoad & TR_FR_BANDWIDTH_PRIORITY)
720      && tr_variantDictFindInt (&top, TR_KEY_bandwidth_priority, &i)
721      && tr_isPriority (i))
722    {
723        tr_torrentSetPriority (tor, i);
724        fieldsLoaded |= TR_FR_BANDWIDTH_PRIORITY;
725    }
726
727    if (fieldsToLoad & TR_FR_PEERS)
728        fieldsLoaded |= loadPeers (&top, tor);
729
730    if (fieldsToLoad & TR_FR_FILE_PRIORITIES)
731        fieldsLoaded |= loadFilePriorities (&top, tor);
732
733    if (fieldsToLoad & TR_FR_PROGRESS)
734        fieldsLoaded |= loadProgress (&top, tor);
735
736    if (fieldsToLoad & TR_FR_DND)
737        fieldsLoaded |= loadDND (&top, tor);
738
739    if (fieldsToLoad & TR_FR_SPEEDLIMIT)
740        fieldsLoaded |= loadSpeedLimits (&top, tor);
741
742    if (fieldsToLoad & TR_FR_RATIOLIMIT)
743        fieldsLoaded |= loadRatioLimits (&top, tor);
744
745    if (fieldsToLoad & TR_FR_IDLELIMIT)
746        fieldsLoaded |= loadIdleLimits (&top, tor);
747
748    /* loading the resume file triggers of a lot of changes,
749     * but none of them needs to trigger a re-saving of the
750     * same resume information... */
751    tor->isDirty = wasDirty;
752
753    tr_variantFree (&top);
754    tr_free (filename);
755    return fieldsLoaded;
756}
757
758static uint64_t
759setFromCtor (tr_torrent * tor, uint64_t fields, const tr_ctor * ctor, int mode)
760{
761    uint64_t ret = 0;
762
763    if (fields & TR_FR_RUN)
764    {
765        bool isPaused;
766        if (!tr_ctorGetPaused (ctor, mode, &isPaused))
767        {
768            tor->isRunning = !isPaused;
769            ret |= TR_FR_RUN;
770        }
771    }
772
773    if (fields & TR_FR_MAX_PEERS)
774        if (!tr_ctorGetPeerLimit (ctor, mode, &tor->maxConnectedPeers))
775            ret |= TR_FR_MAX_PEERS;
776
777    if (fields & TR_FR_DOWNLOAD_DIR)
778    {
779        const char * path;
780        if (!tr_ctorGetDownloadDir (ctor, mode, &path) && path && *path)
781        {
782            ret |= TR_FR_DOWNLOAD_DIR;
783            tr_free (tor->downloadDir);
784            tor->downloadDir = tr_strdup (path);
785        }
786    }
787
788    return ret;
789}
790
791static uint64_t
792useManditoryFields (tr_torrent * tor, uint64_t fields, const tr_ctor * ctor)
793{
794    return setFromCtor (tor, fields, ctor, TR_FORCE);
795}
796
797static uint64_t
798useFallbackFields (tr_torrent * tor, uint64_t fields, const tr_ctor * ctor)
799{
800    return setFromCtor (tor, fields, ctor, TR_FALLBACK);
801}
802
803uint64_t
804tr_torrentLoadResume (tr_torrent *    tor,
805                      uint64_t        fieldsToLoad,
806                      const tr_ctor * ctor)
807{
808    uint64_t ret = 0;
809
810    assert (tr_isTorrent (tor));
811
812    ret |= useManditoryFields (tor, fieldsToLoad, ctor);
813    fieldsToLoad &= ~ret;
814    ret |= loadFromFile (tor, fieldsToLoad);
815    fieldsToLoad &= ~ret;
816    ret |= useFallbackFields (tor, fieldsToLoad, ctor);
817
818    return ret;
819}
820
821void
822tr_torrentRemoveResume (const tr_torrent * tor)
823{
824    char * filename = getResumeFilename (tor);
825    unlink (filename);
826    tr_free (filename);
827}
Note: See TracBrowser for help on using the repository browser.