source: trunk/libtransmission/fastresume.c @ 3619

Last change on this file since 3619 was 3619, checked in by charles, 15 years ago

#426 0.91rc1: if pex is disabled on a stopped torrent, pressing "resume" causes pex to be re-enabled. (reported by pea)

  • Property svn:keywords set to Date Rev Author Id
File size: 24.0 KB
Line 
1/******************************************************************************
2 * $Id: fastresume.c 3619 2007-10-28 19:42:47Z charles $
3 *
4 * Copyright (c) 2005-2007 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25/***********************************************************************
26 * Fast resume
27 ***********************************************************************
28 * The format of the resume file is a 4 byte format version (currently 1),
29 * followed by several variable-sized blocks of data.  Each block is
30 * preceded by a 1 byte ID and a 4 byte length.  The currently recognized
31 * IDs are defined below by the FR_ID_* macros.  The length does not include
32 * the 5 bytes for the ID and length.
33 *
34 * The name of the resume file is "resume.<hash>-<tag>", although
35 * older files with a name of "resume.<hash>" will be recognized if
36 * the former doesn't exist.
37 *
38 * All values are stored in the native endianness. Moving a
39 * libtransmission resume file from an architecture to another will not
40 * work, although it will not hurt either (the version will be wrong,
41 * so the resume file will not be read).
42 **********************************************************************/
43
44#include <assert.h>
45#include <errno.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <time.h>
50
51#include <sys/types.h>
52#include <sys/stat.h>
53#include <unistd.h>
54
55#include "transmission.h"
56#include "completion.h"
57#include "fastresume.h"
58#include "peer-mgr.h"
59#include "platform.h"
60#include "utils.h"
61
62/* time_t can be 32 or 64 bits... for consistency we'll hardwire 64 */ 
63typedef uint64_t tr_time_t; 
64
65enum
66{
67    /* deprecated */
68    FR_ID_PROGRESS_SLOTS = 1,
69
70    /* number of bytes downloaded */
71    FR_ID_DOWNLOADED = 2,
72
73    /* number of bytes uploaded */
74    FR_ID_UPLOADED = 3,
75
76    /* IPs and ports of connectable peers */
77    FR_ID_PEERS_OLD = 4,
78
79    /* progress data:
80     *  - 4 bytes * number of files: mtimes of files
81     *  - 1 bit * number of blocks: whether we have the block or not */
82    FR_ID_PROGRESS = 5,
83
84    /* dnd and priority
85     * char * number of files: l,n,h for low, normal, high priority
86     * char * number of files: t,f for DND flags */
87    FR_ID_PRIORITY = 6,
88
89    /* transfer speeds
90     * uint32_t: dl speed rate to use when the mode is single
91     * uint32_t: dl's tr_speedlimit
92     * uint32_t: ul speed rate to use when the mode is single
93     * uint32_t: ul's tr_speedlimit
94     */
95    FR_ID_SPEED = 8,
96
97    /* active
98     * char: 't' if running, 'f' if paused
99     */
100    FR_ID_RUN = 9,
101
102    /* number of corrupt bytes downloaded */
103    FR_ID_CORRUPT = 10,
104
105    /* IPs and ports of connectable peers */
106    FR_ID_PEERS = 11,
107
108    /* destination of the torrent: zero-terminated string */
109    FR_ID_DESTINATION = 12,
110
111    /* pex flag
112     * 't' if pex is enabled, 'f' if disabled */
113    FR_ID_PEX = 13
114};
115
116
117/* macros for the length of various pieces of the progress data */
118#define FR_MTIME_LEN( t ) \
119  ( sizeof(tr_time_t) * (t)->info.fileCount )
120#define FR_BLOCK_BITFIELD_LEN( t ) \
121  ( ( (t)->blockCount + 7 ) / 8 )
122#define FR_PROGRESS_LEN( t ) \
123  ( FR_MTIME_LEN( t ) + FR_BLOCK_BITFIELD_LEN( t ) )
124#define FR_SPEED_LEN (2 * (sizeof(uint16_t) + sizeof(uint8_t) ) )
125
126static void
127fastResumeFileName( char * buf, size_t buflen, const tr_torrent * tor, int tag )
128{
129    const char * cacheDir = tr_getCacheDirectory ();
130    const char * hash = tor->info.hashString;
131
132    if( !tag )
133    {
134        tr_buildPath( buf, buflen, cacheDir, hash, NULL );
135    }
136    else
137    {
138        char base[1024];
139        snprintf( base, sizeof(base), "%s-%s", hash, tor->handle->tag );
140        tr_buildPath( buf, buflen, cacheDir, base, NULL );
141    }
142}
143
144static tr_time_t*
145getMTimes( const tr_torrent * tor, int * setme_n )
146{
147    int i;
148    const int n = tor->info.fileCount;
149    tr_time_t * m = calloc( n, sizeof(tr_time_t) );
150
151    for( i=0; i<n; ++i ) {
152        char fname[MAX_PATH_LENGTH];
153        struct stat sb;
154        tr_buildPath( fname, sizeof(fname),
155                      tor->destination, tor->info.files[i].name, NULL );
156        if ( !stat( fname, &sb ) && S_ISREG( sb.st_mode ) ) {
157#ifdef SYS_DARWIN
158            m[i] = sb.st_mtimespec.tv_sec;
159#else
160            m[i] = sb.st_mtime;
161#endif
162        }
163    }
164
165    *setme_n = n;
166    return m;
167}
168
169static void
170fastResumeWriteData( uint8_t       id,
171                     const void  * data,
172                     uint32_t      size,
173                     uint32_t      count,
174                     FILE        * file )
175{
176    uint32_t  datalen = size * count;
177
178    fwrite( &id, 1, 1, file );
179    fwrite( &datalen, 4, 1, file );
180    fwrite( data, size, count, file );
181}
182
183void
184tr_fastResumeSave( const tr_torrent * tor )
185{
186    char      path[MAX_PATH_LENGTH];
187    FILE    * file;
188    const int version = 1;
189    uint64_t  total;
190
191    fastResumeFileName( path, sizeof path, tor, 1 );
192    file = fopen( path, "wb+" );
193    if( NULL == file ) {
194        tr_err( "Couldn't open '%s' for writing", path );
195        return;
196    }
197   
198    /* Write format version */
199    fwrite( &version, 4, 1, file );
200
201    if( TRUE ) /* FR_ID_DESTINATION */
202    {
203        const char * d = tor->destination ? tor->destination : "";
204        const int byteCount = strlen( d ) + 1;
205        fastResumeWriteData( FR_ID_DESTINATION, d, 1, byteCount, file );
206    }
207
208    /* Write progress data */
209    if (1) {
210        int n;
211        tr_time_t * mtimes;
212        uint8_t * buf = malloc( FR_PROGRESS_LEN( tor ) );
213        uint8_t * walk = buf;
214        const tr_bitfield * bitfield;
215
216        /* mtimes */
217        mtimes = getMTimes( tor, &n );
218        memcpy( walk, mtimes, n*sizeof(tr_time_t) );
219        walk += n * sizeof(tr_time_t);
220
221        /* completion bitfield */
222        bitfield = tr_cpBlockBitfield( tor->completion );
223        assert( (unsigned)FR_BLOCK_BITFIELD_LEN( tor ) == bitfield->len );
224        memcpy( walk, bitfield->bits, bitfield->len );
225        walk += bitfield->len;
226
227        /* write it */
228        assert( walk-buf == (int)FR_PROGRESS_LEN( tor ) );
229        fastResumeWriteData( FR_ID_PROGRESS, buf, 1, walk-buf, file );
230
231        /* cleanup */
232        free( mtimes );
233        free( buf );
234    }
235
236
237    /* Write the priorities and DND flags */
238    if( TRUE )
239    {
240        int i;
241        const int n = tor->info.fileCount;
242        char * buf = tr_new0( char, n*2 );
243        char * walk = buf;
244
245        /* priorities */
246        for( i=0; i<n; ++i ) {
247            char ch;
248            const int priority = tor->info.files[i].priority;
249            switch( priority ) {
250               case TR_PRI_LOW:   ch = 'l'; break; /* low */
251               case TR_PRI_HIGH:  ch = 'h'; break; /* high */
252               default:           ch = 'n'; break; /* normal */
253            };
254            *walk++ = ch;
255        }
256
257        /* dnd flags */
258        for( i=0; i<n; ++i )
259            *walk++ = tor->info.files[i].dnd ? 't' : 'f';
260
261        /* write it */
262        assert( walk - buf == 2*n );
263        fastResumeWriteData( FR_ID_PRIORITY, buf, 1, walk-buf, file );
264
265        /* cleanup */
266        tr_free( buf );
267    }
268
269
270    /* Write the torrent ul/dl speed caps */
271    if( TRUE )
272    {
273        const int len = FR_SPEED_LEN;
274        char * buf = tr_new0( char, len );
275        char * walk = buf;
276        uint16_t i16;
277        uint8_t i8;
278
279        i16 = (uint16_t) tr_torrentGetSpeedLimit( tor, TR_DOWN );
280        memcpy( walk, &i16, 2 ); walk += 2;
281        i8 = (uint8_t) tr_torrentGetSpeedMode( tor, TR_DOWN );
282        memcpy( walk, &i8, 1 ); walk += 1;
283        i16 = (uint16_t) tr_torrentGetSpeedLimit( tor, TR_UP );
284        memcpy( walk, &i16, 2 ); walk += 2;
285        i8 = (uint8_t) tr_torrentGetSpeedMode( tor, TR_UP );
286        memcpy( walk, &i8, 1 ); walk += 1;
287
288        assert( walk - buf == len );
289        fastResumeWriteData( FR_ID_SPEED, buf, 1, walk-buf, file );
290        tr_free( buf );
291    }
292
293    if( TRUE ) /* FR_ID_PEX */
294    {
295        const char flag = tor->pexDisabled ? 'f' : 't';
296        fastResumeWriteData( FR_ID_PEX, &flag, 1, 1, file );
297    }
298
299    if( TRUE ) /* FR_ID_RUN */
300    {
301        const char is_running = tor->isRunning ? 't' : 'f';
302        fastResumeWriteData( FR_ID_RUN, &is_running, 1, 1, file );
303    }
304
305    /* Write download and upload totals */
306
307    total = tor->downloadedCur + tor->downloadedPrev;
308    fastResumeWriteData( FR_ID_DOWNLOADED, &total, 8, 1, file );
309
310    total = tor->uploadedCur + tor->uploadedPrev;
311    fastResumeWriteData( FR_ID_UPLOADED, &total, 8, 1, file );
312
313    total = tor->corruptCur + tor->corruptPrev;
314    fastResumeWriteData( FR_ID_CORRUPT, &total, 8, 1, file );
315
316    if( !tor->info.isPrivate )
317    {
318        tr_pex * pex;
319        const int count = tr_peerMgrGetPeers( tor->handle->peerMgr,
320                                              tor->info.hash,
321                                              &pex );
322        if( count > 0 )
323            fastResumeWriteData( FR_ID_PEERS, pex, sizeof(tr_pex), count, file );
324        tr_free( pex );
325    }
326
327    fclose( file );
328
329    tr_dbg( "Resume file '%s' written", path );
330}
331
332static int
333loadDestination( tr_torrent * tor, FILE * fp, const char * destination, int argIsFallback )
334{
335    int pathlen = 0;
336    char path[MAX_PATH_LENGTH];
337
338    for( ;; ) {
339        const int ch = fgetc( fp );
340        if( ch==EOF ) /* end of file */
341            return TR_ERROR_IO_OTHER;
342        if( ch=='\0' ) /* end of string */
343            break;
344        path[pathlen++] = (char) ch;
345    }
346
347    path[pathlen] = '\0';
348
349    if( argIsFallback )
350        tor->destination = tr_strdup( pathlen ? path : destination );
351    else
352        tor->destination = tr_strdup( destination && *destination ? destination : path );
353
354    return TR_OK;
355}
356
357static int
358loadSpeeds( tr_torrent * tor, FILE * file )
359{
360    const size_t len = FR_SPEED_LEN;
361    char * buf = tr_new0( char, len );
362    char * walk = buf;
363    uint16_t i16;
364    uint8_t i8;
365
366    if( len != fread( buf, 1, len, file ) ) {
367        tr_inf( "Couldn't read from resume file" );
368        free( buf );
369        return TR_ERROR_IO_OTHER;
370    }
371
372    memcpy( &i16, walk, 2 ); walk += 2;
373    tr_torrentSetSpeedLimit( tor, TR_DOWN, i16 );
374    memcpy( &i8, walk, 1 ); walk += 1;
375    tr_torrentSetSpeedMode( tor, TR_DOWN, (tr_speedlimit)i8 );
376    memcpy( &i16, walk, 2 ); walk += 2;
377    tr_torrentSetSpeedLimit( tor, TR_UP, i16 );
378    memcpy( &i8, walk, 1 ); walk += 1;
379    tr_torrentSetSpeedMode( tor, TR_UP, (tr_speedlimit)i8 );
380
381    tr_free( buf );
382    return TR_OK;
383}
384
385
386static int
387loadPriorities( tr_torrent * tor,
388                FILE       * file )
389{
390    const size_t n = tor->info.fileCount;
391    const size_t len = 2 * n;
392    int *dnd = NULL, dndCount = 0;
393    int *dl = NULL, dlCount = 0;
394    char * buf = tr_new0( char, len );
395    char * walk = buf;
396    size_t i;
397
398    if( len != fread( buf, 1, len, file ) ) {
399        tr_inf( "Couldn't read from resume file" );
400        free( buf );
401        return TR_ERROR_IO_OTHER;
402    }
403
404    /* set file priorities */
405    for( i=0; i<n; ++i ) {
406       tr_priority_t priority;
407       const char ch = *walk++;
408       switch( ch ) {
409           case 'l': priority = TR_PRI_LOW; break;
410           case 'h': priority = TR_PRI_HIGH; break;
411           default:  priority = TR_PRI_NORMAL; break;
412       }
413       tor->info.files[i].priority = priority;
414    }
415
416    /* set the dnd flags */
417    dl = tr_new( int, len );
418    dnd = tr_new( int, len );
419    for( i=0; i<n; ++i )
420        if( *walk++ == 't' ) /* 't' means the DND flag is true */
421            dnd[dndCount++] = i;
422        else
423            dl[dlCount++] = i;
424
425    if( dndCount )
426        tr_torrentSetFileDLs ( tor, dnd, dndCount, FALSE );
427    if( dlCount )
428        tr_torrentSetFileDLs ( tor, dl, dlCount, TRUE );
429
430    tr_free( dnd );
431    tr_free( dl );
432    tr_free( buf );
433    return TR_OK;
434}
435
436static int
437fastResumeLoadProgress( const tr_torrent  * tor,
438                        tr_bitfield       * uncheckedPieces,
439                        FILE              * file )
440{
441    const size_t len = FR_PROGRESS_LEN( tor );
442    uint8_t * buf = calloc( len, 1 );
443    int ret = 0;
444    int i;
445
446    if( len != fread( buf, 1, len, file ) )
447    {
448        tr_inf( "Couldn't read from resume file" );
449        tr_bitfieldAddRange( uncheckedPieces, 0, tor->info.pieceCount );
450        ret = TR_ERROR_IO_OTHER;
451    }
452    else
453    {
454        int n;
455        tr_bitfield bitfield;
456
457        /* compare file mtimes */
458        tr_time_t * curMTimes = getMTimes( tor, &n );
459        uint8_t * walk = buf;
460        const tr_time_t * oldMTimes = (const tr_time_t *) walk;
461        for( i=0; i<n; ++i ) {
462            if ( !curMTimes[i] || ( curMTimes[i] != oldMTimes[i] ) ) {
463                const tr_file * file = &tor->info.files[i];
464                tr_dbg( "File '%s' mtimes differ-- flagging pieces [%d..%d] for recheck",
465                        file->name, file->firstPiece, file->lastPiece);
466                tr_bitfieldAddRange( uncheckedPieces, 
467                                     file->firstPiece, file->lastPiece+1 );
468            }
469        }
470        free( curMTimes );
471        walk += n * sizeof(tr_time_t);
472
473        /* get the completion bitfield */
474        memset( &bitfield, 0, sizeof bitfield );
475        bitfield.len = FR_BLOCK_BITFIELD_LEN( tor );
476        bitfield.bits = walk;
477        tr_cpBlockBitfieldSet( tor->completion, &bitfield );
478    }
479
480    /* the files whose mtimes are wrong,
481       remove from completion pending a recheck... */
482    for( i=0; i<tor->info.pieceCount; ++i )
483        if( tr_bitfieldHas( uncheckedPieces, i ) )
484            tr_cpPieceRem( tor->completion, i );
485
486
487    free( buf );
488    return ret;
489}
490
491static uint64_t
492fastResumeLoadOld( tr_torrent   * tor,
493                   tr_bitfield  * uncheckedPieces, 
494                   FILE         * file )
495{
496    uint64_t ret = 0;
497
498    /* Check the size */
499    const int size = 4 + FR_PROGRESS_LEN( tor );
500    fseek( file, 0, SEEK_END );
501    if( ftell( file ) != size )
502    {
503        tr_inf( "Wrong size for resume file (%d bytes, %d expected)",
504                (int)ftell( file ), size );
505        fclose( file );
506        return 1;
507    }
508
509    /* load progress information */
510    fseek( file, 4, SEEK_SET );
511    if( fastResumeLoadProgress( tor, uncheckedPieces, file ) )
512    {
513        fclose( file );
514        return 1;
515    }
516
517    fclose( file );
518
519    ret |= TR_FR_PROGRESS;
520    tr_inf( "Fast resuming successful (version 0)" );
521
522    return ret;
523}
524
525static uint64_t
526internalIdToPublicBitfield( uint8_t id )
527{
528    uint64_t ret = 0;
529
530    switch( id )
531    {
532        case FR_ID_PROGRESS_SLOTS: ret = 0;                 break;
533        case FR_ID_DOWNLOADED:     ret = TR_FR_DOWNLOADED;  break;
534        case FR_ID_UPLOADED:       ret = TR_FR_UPLOADED;    break;
535        case FR_ID_PEERS_OLD:      ret = TR_FR_PEERS;       break;
536        case FR_ID_PROGRESS:       ret = TR_FR_PROGRESS;    break;
537        case FR_ID_PRIORITY:       ret = TR_FR_PRIORITY;    break;
538        case FR_ID_SPEED:          ret = TR_FR_SPEEDLIMIT;  break;
539        case FR_ID_RUN:            ret = TR_FR_RUN;         break;
540        case FR_ID_CORRUPT:        ret = TR_FR_CORRUPT;     break;
541        case FR_ID_PEERS:          ret = TR_FR_PEERS;       break;
542        case FR_ID_DESTINATION:    ret = TR_FR_DESTINATION; break;
543        case FR_ID_PEX:            ret = TR_FR_PEX;         break;
544    }
545
546    return ret;
547}
548
549static uint64_t
550fastResumeLoadImpl ( tr_torrent   * tor,
551                     uint64_t       fieldsToLoad,
552                     tr_bitfield  * uncheckedPieces,
553                     const char   * destination,
554                     int            argIsFallback )
555{
556    char      path[MAX_PATH_LENGTH];
557    FILE    * file;
558    int       version = 0;
559    uint8_t   id;
560    uint32_t  len;
561    uint64_t  ret = 0;
562
563    assert( tor != NULL );
564    assert( uncheckedPieces != NULL );
565
566    /* Open resume file */
567    fastResumeFileName( path, sizeof path, tor, 1 );
568    file = fopen( path, "rb" );
569    if( !file )
570    {
571        if( ENOENT == errno )
572        {
573            fastResumeFileName( path, sizeof path, tor, 0 );
574            file = fopen( path, "rb" );
575            if( !file )
576            {
577                fastResumeFileName( path, sizeof path, tor, 1 );
578                tr_inf( "Couldn't open '%s' for reading", path );
579                return ret;
580            }
581        }
582    }
583
584    tr_dbg( "Resume file '%s' loaded", path );
585
586    /* Check format version */
587    fread( &version, 4, 1, file );
588    if( 0 == version )
589    {
590        return fastResumeLoadOld( tor, uncheckedPieces, file );
591    }
592    if( 1 != version )
593    {
594        tr_inf( "Resume file has version %d, not supported", version );
595        fclose( file );
596        return ret;
597    }
598
599    /* read each block of data */
600    while( 1 == fread( &id, 1, 1, file ) && 1 == fread( &len, 4, 1, file ) )
601    {
602        if( fieldsToLoad & internalIdToPublicBitfield( id ) ) switch( id )
603        {
604            case FR_ID_PROGRESS:
605                /* read progress data */
606                if( (uint32_t)FR_PROGRESS_LEN( tor ) == len )
607                {
608                    const int rret = fastResumeLoadProgress( tor, uncheckedPieces, file );
609
610                    if( rret && ( feof(file) || ferror(file) ) )
611                    {
612                        fclose( file );
613                        return ret;
614                    }
615
616                    ret |= TR_FR_PROGRESS;
617                    continue;
618                }
619                break;
620
621            case FR_ID_PRIORITY:
622
623                /* read priority data */
624                if( len == (uint32_t)(2 * tor->info.fileCount) )
625                {
626                    const int rret = loadPriorities( tor, file );
627
628                    if( rret && ( feof(file) || ferror(file) ) )
629                    {
630                        fclose( file );
631                        return ret;
632                    }
633
634                    ret |= TR_FR_PRIORITY;
635                    continue;
636                }
637                break;
638
639            case FR_ID_SPEED:
640                /*  read speed data */
641                if( len == FR_SPEED_LEN )
642                {
643                    const int rret = loadSpeeds( tor, file );
644
645                    if( rret && ( feof(file) || ferror(file) ) )
646                    {
647                        fclose( file );
648                        return ret;
649                    }
650
651                    ret |= TR_FR_SPEEDLIMIT;
652                    continue;
653                }
654                break;
655
656            case FR_ID_DESTINATION:
657                {
658                    const int rret = loadDestination( tor, file, destination, argIsFallback );
659
660                    if( rret && ( feof(file) || ferror(file) ) )
661                    {
662                        fclose( file );
663                        return ret;
664                    }
665
666                    ret |= TR_FR_DESTINATION;
667                    continue;
668                }
669                break;
670           
671            case FR_ID_RUN:
672                {
673                    char ch;
674                    if( fread( &ch, 1, 1, file ) != 1 )
675                    {
676                        fclose( file );
677                        return ret;
678                    }
679                    tor->isRunning = ch=='t';
680                    ret |= TR_FR_RUN;
681                    continue;
682                }
683           
684            case FR_ID_PEX:
685                {
686                    char ch;
687                    if( fread( &ch, 1, 1, file ) != 1 )
688                    {
689                        fclose( file );
690                        return ret;
691                    }
692                    tor->pexDisabled = ch!='t';
693                    ret |= TR_FR_PEX;
694                    continue;
695                }
696
697            case FR_ID_DOWNLOADED:
698                /* read download total */
699                if( 8 == len)
700                {
701                    if( 1 != fread( &tor->downloadedPrev, 8, 1, file ) )
702                    {
703                        fclose( file );
704                        return ret;
705                    }
706                    tor->downloadedCur = 0;
707                    ret |= TR_FR_DOWNLOADED;
708                    continue;
709                }
710                break;
711
712            case FR_ID_UPLOADED:
713                /* read upload total */
714                if( 8 == len)
715                {
716                    if( 1 != fread( &tor->uploadedPrev, 8, 1, file ) )
717                    {
718                        fclose( file );
719                        return ret;
720                    }
721                    tor->uploadedCur = 0;
722                    ret |= TR_FR_UPLOADED;
723                    continue;
724                }
725                break;
726
727            case FR_ID_CORRUPT:
728                /* read upload total */
729                if( 8 == len )
730                {
731                    if( 1 != fread( &tor->corruptPrev, 8, 1, file ) )
732                    {
733                        fclose( file );
734                        return ret;
735                    }
736                    tor->corruptCur = 0;
737                    ret |= TR_FR_CORRUPT;
738                    continue;
739                }
740                break;
741
742            case FR_ID_PEERS_OLD:
743                if( !tor->info.isPrivate )
744                {
745                    uint8_t * buf = malloc( len );
746                    if( 1 != fread( buf, len, 1, file ) )
747                    {
748                        free( buf );
749                        fclose( file );
750                        return ret;
751                    }
752
753                    tr_peerMgrAddPeers( tor->handle->peerMgr,
754                                        tor->info.hash,
755                                        TR_PEER_FROM_CACHE,
756                                        buf, len / 6 );
757
758                    tr_dbg( "found %i peers in resume file", len/6 );
759                    free( buf );
760                    ret |= TR_FR_PEERS;
761                }
762
763            case FR_ID_PEERS:
764                if( !tor->info.isPrivate )
765                {
766                    const int count = len / sizeof(tr_pex);
767                    tr_pex * pex = tr_new0( tr_pex, count );
768                    if( 1 != fread( pex, sizeof(tr_pex), count, file ) )
769                    {
770                        free( pex );
771                        fclose( file );
772                        return ret;
773                    }
774
775                    tr_peerMgrAddPex( tor->handle->peerMgr,
776                                      tor->info.hash,
777                                      TR_PEER_FROM_CACHE,
778                                      pex, count );
779
780                    tr_dbg( "found %i peers in resume file", len/6 );
781                    free( pex );
782                    ret |= TR_FR_PEERS;
783                }
784                continue;
785
786            default:
787                break;
788        }
789
790        /* if we didn't read the data, seek past it */
791        tr_inf( "Skipping resume data type %02x, %u bytes", id, len );
792        fseek( file, len, SEEK_CUR );
793    }
794
795    fclose( file );
796    return ret;
797}
798
799uint64_t
800tr_fastResumeLoad( tr_torrent   * tor,
801                   uint64_t       fieldsToLoad,
802                   tr_bitfield  * uncheckedPieces,
803                   const char   * destination,
804                   int            argIsFallback )
805{
806    const uint64_t ret = fastResumeLoadImpl( tor, fieldsToLoad, uncheckedPieces, destination, argIsFallback );
807
808    if( ! ( ret & TR_FR_PROGRESS ) )
809        tr_bitfieldAddRange( uncheckedPieces, 0, tor->info.pieceCount );
810
811    if( !tor->destination )
812        tor->destination = tr_strdup( destination );
813
814    return ret;
815}
Note: See TracBrowser for help on using the repository browser.