Ignore:
Timestamp:
Apr 13, 2008, 10:31:07 PM (14 years ago)
Author:
charles
Message:

#394: resume files should use original name instead of hash name

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/resume.c

    r5606 r5608  
    1111 */
    1212
     13#include <sys/types.h> /* stat */
     14#include <sys/stat.h> /* stat */
     15#include <unistd.h> /* unlink, stat */
     16
    1317#include <string.h>
    14 #include <unistd.h> /* unlink */
    1518
    1619#include "transmission.h"
     20#include "bencode.h"
     21#include "completion.h"
    1722#include "fastresume.h"
     23#include "peer-mgr.h" /* pex */
    1824#include "platform.h" /* tr_getResumeDir */
    1925#include "resume.h"
     
    2127#include "utils.h" /* tr_buildPath */
    2228
     29#define KEY_CORRUPT     "corrupt"
     30#define KEY_DESTINATION "destination"
     31#define KEY_DOWNLOADED  "downloaded"
     32#define KEY_MAX_PEERS   "max-peers"
     33#define KEY_PAUSED      "paused"
     34#define KEY_PEERS       "peers"
     35#define KEY_PRIORITY    "priority"
     36#define KEY_PROGRESS    "progress"
     37#define KEY_SPEEDLIMIT  "speed-limit"
     38#define KEY_UPLOADED    "uploaded"
     39
     40#define KEY_SPEEDLIMIT_DOWN_SPEED "down-speed"
     41#define KEY_SPEEDLIMIT_DOWN_MODE  "down-mode"
     42#define KEY_SPEEDLIMIT_UP_SPEED   "up-speed"
     43#define KEY_SPEEDLIMIT_UP_MODE    "up-mode"
     44
     45#define KEY_PROGRESS_MTIMES "mtimes"
     46#define KEY_PROGRESS_BITFIELD "bitfield"
     47
     48/***
     49****
     50***/
     51
     52static time_t*
     53getMTimes( const tr_torrent * tor, int * setme_n )
     54{
     55    int i;
     56    const int n = tor->info.fileCount;
     57    time_t * m = tr_new( time_t, n );
     58
     59    for( i=0; i<n; ++i ) {
     60        char fname[MAX_PATH_LENGTH];
     61        struct stat sb;
     62        tr_buildPath( fname, sizeof(fname),
     63                      tor->destination, tor->info.files[i].name, NULL );
     64        if ( !stat( fname, &sb ) && S_ISREG( sb.st_mode ) ) {
     65#ifdef SYS_DARWIN
     66            m[i] = sb.st_mtimespec.tv_sec;
     67#else
     68            m[i] = sb.st_mtime;
     69#endif
     70        }
     71    }
     72
     73    *setme_n = n;
     74    return m;
     75}
     76
    2377static void
    2478getResumeFilename( char * buf, size_t buflen, const tr_torrent * tor )
     
    2680    const char * dir = tr_getResumeDir( tor->handle );
    2781    char base[4096];
    28     snprintf( base, sizeof( base ), "%s.%10.10s.resume", tor->info.name, tor->info.hashString );
     82    snprintf( base, sizeof( base ), "%s.%16.16s.resume", tor->info.name, tor->info.hashString );
    2983    tr_buildPath( buf, buflen, dir, base, NULL );
    30 fprintf( stderr, "filename is [%s]\n", buf );
     84}
     85
     86/***
     87****
     88***/
     89
     90static void
     91savePeers( tr_benc * dict, const tr_torrent * tor )
     92{
     93    tr_pex * pex;
     94    const int count = tr_peerMgrGetPeers( tor->handle->peerMgr, tor->info.hash, &pex );
     95    if( count > 0 ) {
     96        tr_benc * child = tr_bencDictAdd( dict, KEY_PEERS );
     97        tr_bencInitStrDupLen( child, (const char*)pex, sizeof(tr_pex)*count );
     98        tr_free( pex );
     99    }
     100}
     101
     102static uint64_t
     103loadPeers( tr_benc * dict, tr_torrent * tor )
     104{
     105    uint64_t ret = 0;
     106    tr_benc * p;
     107
     108    if(( p = tr_bencDictFindType( dict, KEY_PEERS, TYPE_STR )))
     109    {
     110        int i;
     111        const char * str = p->val.s.s;
     112        const size_t len = p->val.s.i;
     113        const int count = len / sizeof( tr_pex );
     114        for( i=0; i<count; ++i ) {
     115            tr_pex pex;
     116            memcpy( &pex, str + (i*sizeof(tr_pex)), sizeof(tr_pex) );
     117            tr_peerMgrAddPex( tor->handle->peerMgr, tor->info.hash, TR_PEER_FROM_CACHE, &pex );
     118        }
     119        tr_tordbg( tor, "Loaded %d peers from resume file", count );
     120        ret = TR_FR_PEERS;
     121    }
     122
     123    return ret;
     124}
     125
     126static void
     127savePriorities( tr_benc * dict, const tr_torrent * tor )
     128{
     129    const tr_info * inf = &tor->info;
     130    const tr_file_index_t n = inf->fileCount;
     131    tr_file_index_t i;
     132    tr_benc * list;
     133
     134    list = tr_bencDictAddList( dict, KEY_PRIORITY, tor->info.fileCount );
     135    for( i=0; i<n; ++i )
     136        tr_bencInitInt( tr_bencListAdd( list ), inf->files[i].priority );
     137}
     138
     139static uint64_t
     140loadPriorities( tr_benc * dict, tr_torrent * tor )
     141{
     142    uint64_t ret = 0;
     143    tr_info * inf = &tor->info;
     144    const tr_file_index_t n = inf->fileCount;
     145    tr_benc * list;
     146
     147    if( tr_bencDictFindList( dict, KEY_PRIORITY, &list ) && ( list->val.l.count == (int)n ) )
     148    {
     149        int64_t tmp;
     150        tr_file_index_t i;
     151        for( i=0; i<n; ++i )
     152            if( tr_bencGetInt( &list->val.l.vals[i], &tmp ) )
     153                inf->files[i].priority = tmp;
     154        ret = TR_FR_PRIORITY;
     155    }
     156
     157    return ret;
     158}
     159
     160static void
     161saveSpeedLimits( tr_benc * dict, const tr_torrent * tor )
     162{
     163    tr_benc * d = tr_bencDictAddDict( dict, KEY_SPEEDLIMIT, 4 );
     164    tr_bencDictAddInt( d, KEY_SPEEDLIMIT_DOWN_SPEED,
     165                       tr_torrentGetSpeedLimit( tor, TR_DOWN ) );
     166    tr_bencDictAddInt( d, KEY_SPEEDLIMIT_DOWN_MODE,
     167                       tr_torrentGetSpeedMode( tor, TR_DOWN ) );
     168    tr_bencDictAddInt( d, KEY_SPEEDLIMIT_UP_SPEED,
     169                       tr_torrentGetSpeedLimit( tor, TR_UP ) );
     170    tr_bencDictAddInt( d, KEY_SPEEDLIMIT_UP_MODE,
     171                       tr_torrentGetSpeedMode( tor, TR_UP ) );
     172}
     173
     174static uint64_t
     175loadSpeedLimits( tr_benc * dict, tr_torrent * tor )
     176{
     177    uint64_t ret = 0;
     178    tr_benc * d;
     179
     180    if( tr_bencDictFindDict( dict, KEY_SPEEDLIMIT, &d ) )
     181    {
     182        int64_t i;
     183        if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_DOWN_SPEED, &i ) )
     184            tr_torrentSetSpeedLimit( tor, TR_DOWN, i );
     185        if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_DOWN_MODE, &i ) )
     186            tr_torrentSetSpeedMode( tor, TR_DOWN, i );
     187        if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_UP_SPEED, &i ) )
     188            tr_torrentSetSpeedLimit( tor, TR_UP, i );
     189        if( tr_bencDictFindInt( d, KEY_SPEEDLIMIT_UP_MODE, &i ) )
     190            tr_torrentSetSpeedMode( tor, TR_UP, i );
     191        ret = TR_FR_SPEEDLIMIT;
     192    }
     193
     194    return ret;
     195}
     196
     197static void
     198saveProgress( tr_benc * dict, const tr_torrent * tor )
     199{
     200    int i;
     201    int n;
     202    time_t * mtimes;
     203    tr_benc * p;
     204    tr_benc * m;
     205    tr_benc * b;
     206    const tr_bitfield * bitfield;
     207
     208    p = tr_bencDictAdd( dict, KEY_PROGRESS );
     209    tr_bencInitDict( p, 2 );
     210
     211    /* add the mtimes */
     212    m = tr_bencDictAdd( p, KEY_PROGRESS_MTIMES );
     213    mtimes = getMTimes( tor, &n );
     214    tr_bencInitList( m, n );
     215    for( i=0; i<n; ++i ) {
     216        if( !tr_torrentIsFileChecked( tor, i ) )
     217            mtimes[i] = ~(time_t)0; /* force a recheck next time */
     218        tr_bencInitInt( tr_bencListAdd( m ), mtimes[i] );
     219    }
     220
     221    /* add the bitfield */
     222    bitfield = tr_cpBlockBitfield( tor->completion );
     223    b = tr_bencDictAdd( p, KEY_PROGRESS_BITFIELD );
     224    tr_bencInitStrDupLen( b, (const char*)bitfield->bits, bitfield->len );
     225
     226    /* cleanup */
     227    tr_free( mtimes );
     228}
     229
     230static uint64_t
     231loadProgress( tr_benc * dict, tr_torrent * tor )
     232{
     233    uint64_t ret = 0;
     234    tr_benc * p;
     235
     236    if( tr_bencDictFindDict( dict, KEY_PROGRESS, &p ) )
     237    {
     238        tr_benc * m;
     239        tr_benc * b;
     240        int n;
     241        time_t * curMTimes = getMTimes( tor, &n );
     242
     243        if( tr_bencDictFindList( p, KEY_PROGRESS_MTIMES, &m )
     244            && ( m->val.l.count == (int64_t)tor->info.fileCount )
     245            && ( m->val.l.count == n ) )
     246        {
     247            int i;
     248            for( i=0; i<m->val.l.count; ++i )
     249            {
     250                int64_t tmp;
     251                const time_t t = tr_bencGetInt( &m->val.l.vals[i], &tmp )
     252                               ? tmp : ~(time_t)0;
     253                if( curMTimes[i] == t )
     254                    tr_torrentSetFileChecked( tor, i, TRUE );
     255                else {
     256                    tr_torrentSetFileChecked( tor, i, FALSE );
     257                    tr_tordbg( tor, "File #%d needs to be verified", i );
     258                }
     259            }
     260        }
     261        else
     262        {
     263            tr_torrentUncheck( tor );
     264            tr_tordbg( tor, "Torrent needs to be verified - unable to find mtimes" );
     265        }
     266
     267        if(( b = tr_bencDictFindType( p, KEY_PROGRESS_BITFIELD, TYPE_STR )))
     268        {
     269            tr_bitfield tmp;
     270            tmp.len = b->val.s.i;
     271            tmp.bits = (uint8_t*) b->val.s.s;
     272            if( tr_cpBlockBitfieldSet( tor->completion, &tmp ) ) {
     273                tr_torrentUncheck( tor );
     274                tr_tordbg( tor, "Torrent needs to be verified - error loading bitfield" );
     275            }
     276        }
     277        else
     278        {
     279            tr_torrentUncheck( tor );
     280            tr_tordbg( tor, "Torrent needs to be verified - unable to find bitfield" );
     281        }
     282       
     283        tr_free( curMTimes );
     284        ret = TR_FR_PROGRESS;
     285    }
     286
     287    return ret;
     288}
     289
     290void
     291tr_torrentSaveResume( const tr_torrent * tor )
     292{
     293    tr_benc top;
     294    char * encoded;
     295    int len;
     296
     297    /* populate the bencoded data */
     298    tr_bencInitDict( &top, 10 );
     299    tr_bencDictAddInt( &top, KEY_CORRUPT, tor->corruptPrev + tor->corruptCur );
     300    tr_bencDictAddStr( &top, KEY_DESTINATION, tor->destination );
     301    tr_bencDictAddInt( &top, KEY_DOWNLOADED, tor->downloadedPrev + tor->downloadedCur );
     302    tr_bencDictAddInt( &top, KEY_UPLOADED, tor->uploadedPrev + tor->uploadedCur );
     303    tr_bencDictAddInt( &top, KEY_MAX_PEERS, tor->maxConnectedPeers );
     304    tr_bencDictAddInt( &top, KEY_PAUSED, tor->isRunning?0:1 );
     305    savePeers( &top, tor );
     306    savePriorities( &top, tor );
     307    saveProgress( &top, tor );
     308    saveSpeedLimits( &top, tor );
     309
     310    /* save the bencoded data */
     311    if(( encoded = tr_bencSave( &top, &len )))
     312    {
     313        char filename[MAX_PATH_LENGTH];
     314        FILE * fp;
     315        getResumeFilename( filename, sizeof( filename ), tor );
     316        fp = fopen( filename, "wb+" );
     317        fwrite( encoded, len, 1, fp );
     318        fclose( fp );
     319        tr_free( encoded );
     320    }
     321
     322    /* cleanup */
     323    tr_bencFree( &top );
    31324}
    32325
     
    36329                      const tr_ctor * ctor )
    37330{
     331    int64_t i;
     332    const char * str;
     333    int benc_loaded = FALSE;
    38334    uint64_t fieldsLoaded = 0;
    39     uint8_t * content;
     335    uint8_t * content = NULL;
    40336    size_t contentLen;
    41337    char filename[MAX_PATH_LENGTH];
     338    tr_benc top;
    42339
    43340    getResumeFilename( filename, sizeof( filename ), tor );
     341
    44342    content = tr_loadFile( filename, &contentLen );
    45     if( content )
    46     {
     343    benc_loaded = content && !tr_bencLoad( content, contentLen, &top, NULL );
     344    if( !benc_loaded ) {
    47345        tr_free( content );
    48     }
    49     else
    50     {
    51         fieldsLoaded = tr_fastResumeLoad( tor, fieldsToLoad, ctor );
    52     }
    53 
     346        tr_tordbg( tor, "Couldn't read \"%s\"; trying old resume file format.", filename );
     347        return tr_fastResumeLoad( tor, fieldsToLoad, ctor );
     348    }
     349
     350    tr_tordbg( tor, "Read resume file \"%s\"", filename );
     351
     352    if( tr_bencDictFindInt( &top, KEY_CORRUPT, &i ) ) {
     353        tor->corruptPrev = i;
     354        fieldsLoaded |= TR_FR_CORRUPT;
     355    }
     356
     357    if( tr_bencDictFindStr( &top, KEY_DESTINATION, &str ) ) {
     358        tr_free( tor->destination );
     359        tor->destination = tr_strdup( str );
     360        fieldsLoaded |= TR_FR_DESTINATION;
     361    }
     362
     363    if( tr_bencDictFindInt( &top, KEY_DOWNLOADED, &i ) ) {
     364        tor->downloadedPrev = i;
     365        fieldsLoaded |= TR_FR_DOWNLOADED;
     366    }
     367
     368    if( tr_bencDictFindInt( &top, KEY_UPLOADED, &i ) ) {
     369        tor->uploadedPrev = i;
     370        fieldsLoaded |= TR_FR_UPLOADED;
     371    }
     372
     373    if( tr_bencDictFindInt( &top, KEY_MAX_PEERS, &i ) ) {
     374        tor->maxConnectedPeers = i;
     375        fieldsLoaded |= TR_FR_MAX_PEERS;
     376    }
     377
     378    if( tr_bencDictFindInt( &top, KEY_PAUSED, &i ) ) {
     379        tor->isRunning = i ? 0 : 1;
     380        fieldsLoaded |= TR_FR_RUN;
     381    }
     382
     383    fieldsLoaded |= loadPeers( &top, tor );
     384    fieldsLoaded |= loadPriorities( &top, tor );
     385    fieldsLoaded |= loadProgress( &top, tor );
     386    fieldsLoaded |= loadSpeedLimits( &top, tor );
     387
     388    tr_bencFree( &top );
    54389    return fieldsLoaded;
    55 }
    56 
    57 void
    58 tr_torrentSaveResume( const tr_torrent * tor )
    59 {
    60     char filename[MAX_PATH_LENGTH];
    61     getResumeFilename( filename, sizeof( filename ), tor );
    62 
    63     /* (temporary) */
    64     tr_fastResumeSave( tor );
    65390}
    66391
Note: See TracChangeset for help on using the changeset viewer.