source: trunk/libtransmission/fastresume.c @ 6832

Last change on this file since 6832 was 6832, checked in by charles, 14 years ago

(libT) housekeeping: tr_torrent.handle --> tr_torrent.session

  • Property svn:keywords set to Date Rev Author Id
File size: 21.7 KB
Line 
1/******************************************************************************
2 * $Id: fastresume.c 6832 2008-10-02 15:53:33Z charles $
3 *
4 * Copyright (c) 2005-2008 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> /* calloc */
48#include <string.h> /* strcpy, memset, memcmp */
49
50#include <sys/types.h>
51#include <sys/stat.h> /* stat */
52#include <unistd.h> /* unlink */
53
54#include "transmission.h"
55#include "completion.h"
56#include "fastresume.h"
57#include "peer-mgr.h"
58#include "platform.h"
59#include "resume.h" /* TR_FR_ bitwise enum */
60#include "torrent.h"
61#include "utils.h"
62
63/* time_t can be 32 or 64 bits... for consistency we'll hardwire 64 */
64typedef uint64_t tr_time_t;
65
66enum
67{
68    /* number of bytes downloaded */
69    FR_ID_DOWNLOADED = 2,
70
71    /* number of bytes uploaded */
72    FR_ID_UPLOADED = 3,
73
74    /* progress data:
75     *  - 4 bytes * number of files: mtimes of files
76     *  - 1 bit * number of blocks: whether we have the block or not */
77    FR_ID_PROGRESS = 5,
78
79    /* dnd and priority
80     * char * number of files: l,n,h for low, normal, high priority
81     * char * number of files: t,f for DND flags */
82    FR_ID_PRIORITY = 6,
83
84    /* transfer speeds
85     * uint32_t: dl speed rate to use when the mode is single
86     * uint32_t: dl's tr_speedlimit
87     * uint32_t: ul speed rate to use when the mode is single
88     * uint32_t: ul's tr_speedlimit
89     */
90    FR_ID_SPEED = 8,
91
92    /* active
93     * char: 't' if running, 'f' if paused
94     */
95    FR_ID_RUN = 9,
96
97    /* number of corrupt bytes downloaded */
98    FR_ID_CORRUPT = 10,
99
100    /* IPs and ports of connectable peers */
101    FR_ID_PEERS = 11,
102
103    /* download dir of the torrent: zero-terminated string */
104    FR_ID_DOWNLOAD_DIR = 12,
105
106    /* pex flag
107     * 't' if pex is enabled, 'f' if disabled */
108    FR_ID_PEX = 13,
109
110    /* max connected peers -- uint16_t */
111    FR_ID_MAX_PEERS = 14
112};
113
114
115/* macros for the length of various pieces of the progress data */
116#define FR_MTIME_LEN( t ) \
117    ( sizeof( tr_time_t ) * ( t )->info.fileCount )
118#define FR_BLOCK_BITFIELD_LEN( t ) \
119    ( ( ( t )->blockCount + 7u ) / 8u )
120#define FR_PROGRESS_LEN( t ) \
121    ( FR_MTIME_LEN( t ) + FR_BLOCK_BITFIELD_LEN( t ) )
122#define FR_SPEED_LEN ( 2 * ( sizeof( uint16_t ) + sizeof( uint8_t ) ) )
123
124#if 0
125static void
126fastResumeFileName( char *             buf,
127                    size_t             buflen,
128                    const tr_torrent * tor,
129                    int                tag )
130{
131    const char * cacheDir = tr_getResumeDir( tor->handle );
132    const char * hash = tor->info.hashString;
133
134    if( !tag )
135    {
136        tr_buildPath( buf, buflen, cacheDir, hash, NULL );
137    }
138    else
139    {
140        char base[1024];
141        tr_snprintf( base, sizeof( base ), "%s-%s", hash, tor->handle->tag );
142        tr_buildPath( buf, buflen, cacheDir, base, NULL );
143    }
144}
145
146#endif
147
148static tr_time_t*
149getMTimes( const tr_torrent * tor,
150           int *              setme_n )
151{
152    int         i;
153    const int   n = tor->info.fileCount;
154    tr_time_t * m = calloc( n, sizeof( tr_time_t ) );
155
156    for( i = 0; i < n; ++i )
157    {
158        char        fname[MAX_PATH_LENGTH];
159        struct stat sb;
160        tr_buildPath( fname, sizeof( fname ),
161                      tor->downloadDir, tor->info.files[i].name, NULL );
162        if( !stat( fname, &sb ) && S_ISREG( sb.st_mode ) )
163        {
164#ifdef SYS_DARWIN
165            m[i] = sb.st_mtimespec.tv_sec;
166#else
167            m[i] = sb.st_mtime;
168#endif
169        }
170    }
171
172    *setme_n = n;
173    return m;
174}
175
176#if 0
177static void
178fastResumeWriteData( uint8_t      id,
179                     const void * data,
180                     uint32_t     size,
181                     uint32_t     count,
182                     FILE *       file )
183{
184    uint32_t datalen = size * count;
185
186    fwrite( &id, 1, 1, file );
187    fwrite( &datalen, 4, 1, file );
188    fwrite( data, size, count, file );
189}
190
191void
192tr_fastResumeSave( const tr_torrent * tor )
193{
194    char      path[MAX_PATH_LENGTH];
195    FILE *    file;
196    const int version = 1;
197    uint64_t  total;
198
199    fastResumeFileName( path, sizeof path, tor, 1 );
200    file = fopen( path, "wb+" );
201    if( !file )
202    {
203        tr_torerr( tor, _(
204                      "Couldn't open \"%1$s\": %2$s" ), path,
205                  tr_strerror( errno ) );
206        return;
207    }
208
209    /* Write format version */
210    fwrite( &version, 4, 1, file );
211
212    if( TRUE ) /* FR_ID_DOWNLOAD_DIR */
213    {
214        const char * d = tor->downloadDir ? tor->downloadDir : "";
215        const int    byteCount = strlen( d ) + 1;
216        fastResumeWriteData( FR_ID_DOWNLOAD_DIR, d, 1, byteCount, file );
217    }
218
219    /* Write progress data */
220    {
221        int                 i, n;
222        tr_time_t *         mtimes;
223        uint8_t *           buf = malloc( FR_PROGRESS_LEN( tor ) );
224        uint8_t *           walk = buf;
225        const tr_bitfield * bitfield;
226
227        /* mtimes */
228        mtimes = getMTimes( tor, &n );
229        for( i = 0; i < n; ++i )
230            if( !tr_torrentIsFileChecked( tor, i ) )
231                mtimes[i] = ~(tr_time_t)0; /* force a recheck next time */
232        memcpy( walk, mtimes, n * sizeof( tr_time_t ) );
233        walk += n * sizeof( tr_time_t );
234
235        /* completion bitfield */
236        bitfield = tr_cpBlockBitfield( tor->completion );
237        assert( (unsigned)FR_BLOCK_BITFIELD_LEN( tor ) == bitfield->len );
238        memcpy( walk, bitfield->bits, bitfield->len );
239        walk += bitfield->len;
240
241        /* write it */
242        assert( walk - buf == (int)FR_PROGRESS_LEN( tor ) );
243        fastResumeWriteData( FR_ID_PROGRESS, buf, 1, walk - buf, file );
244
245        /* cleanup */
246        free( mtimes );
247        free( buf );
248    }
249
250
251    /* Write the priorities and DND flags */
252    if( TRUE )
253    {
254        int       i;
255        const int n = tor->info.fileCount;
256        char *    buf = tr_new0( char, n * 2 );
257        char *    walk = buf;
258
259        /* priorities */
260        for( i = 0; i < n; ++i )
261        {
262            char      ch;
263            const int priority = tor->info.files[i].priority;
264            switch( priority )
265            {
266                case TR_PRI_LOW:
267                    ch = 'l'; break;              /* low */
268
269                case TR_PRI_HIGH:
270                    ch = 'h'; break;              /* high */
271
272                default:
273                    ch = 'n'; break;              /* normal */
274            }
275            *walk++ = ch;
276        }
277
278        /* dnd flags */
279        for( i = 0; i < n; ++i )
280            *walk++ = tor->info.files[i].dnd ? 't' : 'f';
281
282        /* write it */
283        assert( walk - buf == 2 * n );
284        fastResumeWriteData( FR_ID_PRIORITY, buf, 1, walk - buf, file );
285
286        /* cleanup */
287        tr_free( buf );
288    }
289
290
291    /* Write the torrent ul/dl speed caps */
292    if( TRUE )
293    {
294        const int len = FR_SPEED_LEN;
295        char *    buf = tr_new0( char, len );
296        char *    walk = buf;
297        uint16_t  i16;
298        uint8_t   i8;
299
300        i16 = (uint16_t) tr_torrentGetSpeedLimit( tor, TR_DOWN );
301        memcpy( walk, &i16, 2 ); walk += 2;
302        i8 = (uint8_t) tr_torrentGetSpeedMode( tor, TR_DOWN );
303        memcpy( walk, &i8, 1 ); walk += 1;
304        i16 = (uint16_t) tr_torrentGetSpeedLimit( tor, TR_UP );
305        memcpy( walk, &i16, 2 ); walk += 2;
306        i8 = (uint8_t) tr_torrentGetSpeedMode( tor, TR_UP );
307        memcpy( walk, &i8, 1 ); walk += 1;
308
309        assert( walk - buf == len );
310        fastResumeWriteData( FR_ID_SPEED, buf, 1, walk - buf, file );
311        tr_free( buf );
312    }
313
314    if( TRUE ) /* FR_ID_RUN */
315    {
316        const char is_running = tor->isRunning ? 't' : 'f';
317        fastResumeWriteData( FR_ID_RUN, &is_running, 1, 1, file );
318    }
319
320    /* Write download and upload totals */
321
322    total = tor->downloadedCur + tor->downloadedPrev;
323    fastResumeWriteData( FR_ID_DOWNLOADED, &total, 8, 1, file );
324
325    total = tor->uploadedCur + tor->uploadedPrev;
326    fastResumeWriteData( FR_ID_UPLOADED, &total, 8, 1, file );
327
328    total = tor->corruptCur + tor->corruptPrev;
329    fastResumeWriteData( FR_ID_CORRUPT, &total, 8, 1, file );
330
331    fastResumeWriteData( FR_ID_MAX_PEERS,
332                         &tor->maxConnectedPeers,
333                         sizeof( uint16_t ), 1, file );
334
335    if( !tor->info.isPrivate )
336    {
337        tr_pex *  pex;
338        const int count = tr_peerMgrGetPeers( tor->handle->peerMgr,
339                                              tor->info.hash,
340                                              &pex );
341        if( count > 0 )
342            fastResumeWriteData( FR_ID_PEERS, pex, sizeof( tr_pex ), count,
343                                 file );
344        tr_free( pex );
345    }
346
347    fclose( file );
348}
349
350#endif
351
352/***
353****
354***/
355
356static uint64_t
357internalIdToPublicBitfield( uint8_t id )
358{
359    uint64_t ret = 0;
360
361    switch( id )
362    {
363        case FR_ID_DOWNLOADED:
364            ret = TR_FR_DOWNLOADED;    break;
365
366        case FR_ID_UPLOADED:
367            ret = TR_FR_UPLOADED;      break;
368
369        case FR_ID_PROGRESS:
370            ret = TR_FR_PROGRESS;      break;
371
372        case FR_ID_PRIORITY:
373            ret = TR_FR_PRIORITY;      break;
374
375        case FR_ID_SPEED:
376            ret = TR_FR_SPEEDLIMIT;    break;
377
378        case FR_ID_RUN:
379            ret = TR_FR_RUN;           break;
380
381        case FR_ID_CORRUPT:
382            ret = TR_FR_CORRUPT;       break;
383
384        case FR_ID_PEERS:
385            ret = TR_FR_PEERS;         break;
386
387        case FR_ID_DOWNLOAD_DIR:
388            ret = TR_FR_DOWNLOAD_DIR;  break;
389
390        case FR_ID_MAX_PEERS:
391            ret = TR_FR_MAX_PEERS;     break;
392    }
393
394    return ret;
395}
396
397static void
398readBytes( void *           target,
399           const uint8_t ** source,
400           size_t           byteCount )
401{
402    memcpy( target, *source, byteCount );
403    *source += byteCount;
404}
405
406static uint64_t
407parseDownloaded( tr_torrent *    tor,
408                 const uint8_t * buf,
409                 uint32_t        len )
410{
411    if( len != sizeof( uint64_t ) )
412        return 0;
413    readBytes( &tor->downloadedPrev, &buf, sizeof( uint64_t ) );
414    return TR_FR_DOWNLOADED;
415}
416
417static uint64_t
418parseUploaded( tr_torrent *    tor,
419               const uint8_t * buf,
420               uint32_t        len )
421{
422    if( len != sizeof( uint64_t ) )
423        return 0;
424    readBytes( &tor->uploadedPrev, &buf, sizeof( uint64_t ) );
425    return TR_FR_UPLOADED;
426}
427
428static uint64_t
429parseCorrupt( tr_torrent *    tor,
430              const uint8_t * buf,
431              uint32_t        len )
432{
433    if( len != sizeof( uint64_t ) )
434        return 0;
435    readBytes( &tor->corruptPrev, &buf, sizeof( uint64_t ) );
436    return TR_FR_CORRUPT;
437}
438
439static uint64_t
440parseConnections( tr_torrent *    tor,
441                  const uint8_t * buf,
442                  uint32_t        len )
443{
444    if( len != sizeof( uint16_t ) )
445        return 0;
446    readBytes( &tor->maxConnectedPeers, &buf, sizeof( uint16_t ) );
447    return TR_FR_MAX_PEERS;
448}
449
450static uint64_t
451parseProgress( tr_torrent *    tor,
452               const uint8_t * buf,
453               uint32_t        len )
454{
455    uint64_t ret = 0;
456
457    if( len == FR_PROGRESS_LEN( tor ) )
458    {
459        int             i;
460        int             n;
461        tr_bitfield     bitfield;
462
463        /* compare file mtimes */
464        tr_time_t *     curMTimes = getMTimes( tor, &n );
465        const uint8_t * walk = buf;
466        tr_time_t       mtime;
467        for( i = 0; i < n; ++i )
468        {
469            readBytes( &mtime, &walk, sizeof( tr_time_t ) );
470            if( curMTimes[i] == mtime )
471                tr_torrentSetFileChecked( tor, i, TRUE );
472            else
473            {
474                tr_torrentSetFileChecked( tor, i, FALSE );
475                tr_tordbg( tor, "Torrent needs to be verified" );
476            }
477        }
478        free( curMTimes );
479
480        /* get the completion bitfield */
481        memset( &bitfield, 0, sizeof bitfield );
482        bitfield.byteCount = FR_BLOCK_BITFIELD_LEN( tor );
483        bitfield.bitCount = bitfield.byteCount * 8;
484        bitfield.bits = (uint8_t*) walk;
485        if( !tr_cpBlockBitfieldSet( tor->completion, &bitfield ) )
486            ret = TR_FR_PROGRESS;
487        else
488        {
489            tr_torrentUncheck( tor );
490            tr_tordbg( tor, "Torrent needs to be verified" );
491        }
492    }
493
494    /* the files whose mtimes are wrong,
495       remove from completion pending a recheck... */
496    {
497        tr_piece_index_t i;
498        for( i = 0; i < tor->info.pieceCount; ++i )
499            if( !tr_torrentIsPieceChecked( tor, i ) )
500                tr_cpPieceRem( tor->completion, i );
501    }
502
503    return ret;
504}
505
506static uint64_t
507parsePriorities( tr_torrent *    tor,
508                 const uint8_t * buf,
509                 uint32_t        len )
510{
511    uint64_t ret = 0;
512
513    if( len == (uint32_t)( 2 * tor->info.fileCount ) )
514    {
515        const size_t     n = tor->info.fileCount;
516        const size_t     len = 2 * n;
517        tr_file_index_t *dnd = NULL, dndCount = 0;
518        tr_file_index_t *dl = NULL, dlCount = 0;
519        size_t           i;
520        const uint8_t *  walk = buf;
521
522        /* set file priorities */
523        for( i = 0; i < n; ++i )
524        {
525            tr_priority_t priority;
526            const char    ch = *walk++;
527            switch( ch )
528            {
529                case 'l':
530                    priority = TR_PRI_LOW; break;
531
532                case 'h':
533                    priority = TR_PRI_HIGH; break;
534
535                default:
536                    priority = TR_PRI_NORMAL; break;
537            }
538            tr_torrentInitFilePriority( tor, i, priority );
539        }
540
541        /* set the dnd flags */
542        dl = tr_new( tr_file_index_t, len );
543        dnd = tr_new( tr_file_index_t, len );
544        for( i = 0; i < n; ++i )
545            if( *walk++ == 't' ) /* 't' means the DND flag is true */
546                dnd[dndCount++] = i;
547            else
548                dl[dlCount++] = i;
549
550        if( dndCount )
551            tr_torrentInitFileDLs ( tor, dnd, dndCount, FALSE );
552        if( dlCount )
553            tr_torrentInitFileDLs ( tor, dl, dlCount, TRUE );
554
555        tr_free( dnd );
556        tr_free( dl );
557
558        ret = TR_FR_PRIORITY;
559    }
560
561    return ret;
562}
563
564static uint64_t
565parseSpeedLimit( tr_torrent *    tor,
566                 const uint8_t * buf,
567                 uint32_t        len )
568{
569    uint64_t ret = 0;
570
571    if( len == FR_SPEED_LEN )
572    {
573        uint8_t  i8;
574        uint16_t i16;
575
576        readBytes( &i16, &buf, sizeof( i16 ) );
577        tr_torrentSetSpeedLimit( tor, TR_DOWN, i16 );
578        readBytes( &i8, &buf, sizeof( i8 ) );
579        tr_torrentSetSpeedMode( tor, TR_DOWN, (tr_speedlimit)i8 );
580        readBytes( &i16, &buf, sizeof( i16 ) );
581        tr_torrentSetSpeedLimit( tor, TR_UP, i16 );
582        readBytes( &i8, &buf, sizeof( i8 ) );
583        tr_torrentSetSpeedMode( tor, TR_UP, (tr_speedlimit)i8 );
584
585        ret = TR_FR_SPEEDLIMIT;
586    }
587
588    return ret;
589}
590
591static uint64_t
592parseRun( tr_torrent *    tor,
593          const uint8_t * buf,
594          uint32_t        len )
595{
596    if( len != 1 )
597        return 0;
598    tor->isRunning = *buf == 't';
599    return TR_FR_RUN;
600}
601
602static uint64_t
603parsePeers( tr_torrent *    tor,
604            const uint8_t * buf,
605            uint32_t        len )
606{
607    uint64_t ret = 0;
608
609    if( !tor->info.isPrivate )
610    {
611        int       i;
612        const int count = len / sizeof( tr_pex );
613
614        for( i = 0; i < count; ++i )
615        {
616            tr_pex pex;
617            readBytes( &pex, &buf, sizeof( tr_pex ) );
618            tr_peerMgrAddPex( tor->session->peerMgr, tor->info.hash,
619                              TR_PEER_FROM_CACHE,
620                              &pex );
621        }
622
623        tr_tordbg( tor, "Loaded %d peers from resume file", count );
624        ret = TR_FR_PEERS;
625    }
626
627    return ret;
628}
629
630static uint64_t
631parseDownloadDir( tr_torrent *    tor,
632                  const uint8_t * buf,
633                  uint32_t        len )
634{
635    uint64_t ret = 0;
636
637    if( buf && *buf && len )
638    {
639        tr_free( tor->downloadDir );
640        tor->downloadDir = tr_strndup( (char*)buf, len );
641        ret = TR_FR_DOWNLOAD_DIR;
642    }
643
644    return ret;
645}
646
647static uint64_t
648parseVersion1( tr_torrent *    tor,
649               const uint8_t * buf,
650               const uint8_t * end,
651               uint64_t        fieldsToLoad )
652{
653    uint64_t ret = 0;
654
655    while( end - buf >= 5 )
656    {
657        uint8_t  id;
658        uint32_t len;
659        readBytes( &id, &buf, sizeof( id ) );
660        readBytes( &len, &buf, sizeof( len ) );
661
662        if( buf + len > end )
663        {
664            tr_torerr( tor, "Resume file seems to be corrupt.  Skipping." );
665        }
666        else if( fieldsToLoad &
667                internalIdToPublicBitfield( id ) ) switch( id )
668            {
669                case FR_ID_DOWNLOADED:
670                    ret |= parseDownloaded( tor, buf, len ); break;
671
672                case FR_ID_UPLOADED:
673                    ret |= parseUploaded( tor, buf, len ); break;
674
675                case FR_ID_PROGRESS:
676                    ret |= parseProgress( tor, buf, len ); break;
677
678                case FR_ID_PRIORITY:
679                    ret |= parsePriorities( tor, buf, len ); break;
680
681                case FR_ID_SPEED:
682                    ret |= parseSpeedLimit( tor, buf, len ); break;
683
684                case FR_ID_RUN:
685                    ret |= parseRun( tor, buf, len ); break;
686
687                case FR_ID_CORRUPT:
688                    ret |= parseCorrupt( tor, buf, len ); break;
689
690                case FR_ID_PEERS:
691                    ret |= parsePeers( tor, buf, len ); break;
692
693                case FR_ID_MAX_PEERS:
694                    ret |= parseConnections( tor, buf, len ); break;
695
696                case FR_ID_DOWNLOAD_DIR:
697                    ret |= parseDownloadDir( tor, buf, len ); break;
698
699                default:
700                    tr_tordbg( tor, "Skipping unknown resume code %d",
701                               (int)id ); break;
702            }
703
704        buf += len;
705    }
706
707    return ret;
708}
709
710static uint8_t*
711loadResumeFile( const tr_torrent * tor,
712                size_t *           len )
713{
714    uint8_t *    ret = NULL;
715    char         path[MAX_PATH_LENGTH];
716    const char * cacheDir = tr_getResumeDir( tor->session );
717    const char * hash = tor->info.hashString;
718
719    if( !ret && tor->session->tag )
720    {
721        char base[1024];
722        tr_snprintf( base, sizeof( base ), "%s-%s", hash, tor->session->tag );
723        tr_buildPath( path, sizeof( path ), cacheDir, base, NULL );
724        ret = tr_loadFile( path, len );
725    }
726
727    if( !ret )
728    {
729        tr_buildPath( path, sizeof( path ), cacheDir, hash, NULL );
730        ret = tr_loadFile( path, len );
731    }
732
733    return ret;
734}
735
736static uint64_t
737fastResumeLoadImpl( tr_torrent * tor,
738                    uint64_t     fieldsToLoad )
739{
740    uint64_t  ret = 0;
741    size_t    size = 0;
742    uint8_t * buf = loadResumeFile( tor, &size );
743
744    if( !buf )
745        /* %s is the torrent name */
746        tr_torinf( tor, _( "Couldn't read resume file" ) );
747    else
748    {
749        const uint8_t * walk = buf;
750        const uint8_t * end = walk + size;
751        if( end - walk >= 4 )
752        {
753            uint32_t version;
754            readBytes( &version, &walk, sizeof( version ) );
755            if( version == 1 )
756                ret |= parseVersion1 ( tor, walk, end, fieldsToLoad );
757            else
758                /* %s is the torrent name */
759                tr_torinf( tor, _( "Couldn't read resume file" ) );
760        }
761
762        tr_free( buf );
763    }
764
765    return ret;
766}
767
768uint64_t
769tr_fastResumeLoad( tr_torrent * tor,
770                   uint64_t     fieldsToLoad )
771{
772    return fastResumeLoadImpl( tor, fieldsToLoad );
773}
774
775void
776tr_fastResumeRemove( const tr_torrent * tor )
777{
778    char         path[MAX_PATH_LENGTH];
779    const char * cacheDir = tr_getResumeDir( tor->session );
780    const char * hash = tor->info.hashString;
781
782    if( tor->session->tag )
783    {
784        char base[1024];
785        tr_snprintf( base, sizeof( base ), "%s-%s", hash, tor->session->tag );
786        tr_buildPath( path, sizeof( path ), cacheDir, base, NULL );
787        unlink( path );
788    }
789    else
790    {
791        tr_buildPath( path, sizeof( path ), cacheDir, hash, NULL );
792        unlink( path );
793    }
794}
795
Note: See TracBrowser for help on using the repository browser.