Changeset 100


Ignore:
Timestamp:
Feb 8, 2006, 4:31:49 PM (15 years ago)
Author:
joshe
Message:

Merge the version 1 extensible resume file format,
as well as compatability code to read the existing version 0 files.
Note that older versions of transmission won't understand the version 1 format
and a hash check will be done on all the files.

Save uploaded and downloaded totals in the resume file.

Location:
trunk/libtransmission
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/fastresume.h

    r20 r100  
    2424 * Fast resume
    2525 ***********************************************************************
    26  * Format of the resume file:
    27  *  - 4 bytes: format version (currently 0)
     26 * The format of the resume file is a 4 byte format version (currently 1),
     27 * followed by several variable-sized blocks of data.  Each block is
     28 * preceded by a 1 byte ID and a 4 byte length.  The currently recognized
     29 * IDs are defined below by the FR_ID_* macros.  The length does not include
     30 * the 5 bytes for the ID and length.
     31 *
     32 * The name of the resume file is "resume.<hash>".
     33 *
     34 * All values are stored in the native endianness. Moving a
     35 * libtransmission resume file from an architecture to another will not
     36 * work, although it will not hurt either (the version will be wrong,
     37 * so the resume file will not be read).
     38 **********************************************************************/
     39
     40/* progress data:
    2841 *  - 4 bytes * number of files: mtimes of files
    2942 *  - 1 bit * number of blocks: whether we have the block or not
    3043 *  - 4 bytes * number of pieces (byte aligned): the pieces that have
    3144 *    been completed or started in each slot
    32  *
    33  * The name of the resume file is "resume.<hash>".
    34  *
    35  * All values are stored in the native endianness. Moving a
    36  * libtransmission resume file from an architecture to another will not
    37  * work, although it will not hurt either (the mtimes will be wrong,
    38  * so the files will be scanned).
    39  **********************************************************************/
     45 */
     46#define FR_ID_PROGRESS          0x01
     47/* number of bytes downloaded */
     48#define FR_ID_DOWNLOADED        0x02
     49/* number of bytes uploaded */
     50#define FR_ID_UPLOADED          0x03
     51
     52/* macros for the length of various pieces of the progress data */
     53#define FR_MTIME_LEN( t ) \
     54  ( 4 * (t)->info.fileCount )
     55#define FR_BLOCK_BITFIELD_LEN( t ) \
     56  ( ( (t)->blockCount + 7 ) / 8 )
     57#define FR_SLOTPIECE_LEN( t ) \
     58  ( 4 * (t)->info.pieceCount )
     59#define FR_PROGRESS_LEN( t ) \
     60  ( FR_MTIME_LEN( t ) + FR_BLOCK_BITFIELD_LEN( t ) + FR_SLOTPIECE_LEN( t ) )
    4061
    4162static char * fastResumeFileName( tr_io_t * io )
     
    92113}
    93114
     115static inline void fastResumeWriteData( uint8_t id, void * data, uint32_t size,
     116                                        uint32_t count, FILE * file )
     117{
     118    uint32_t  datalen = size * count;
     119
     120    fwrite( &id, 1, 1, file );
     121    fwrite( &datalen, 4, 1, file );
     122    fwrite( data, size, count, file );
     123}
     124
    94125static void fastResumeSave( tr_io_t * io )
    95126{
    96127    tr_torrent_t * tor = io->tor;
    97     tr_info_t    * inf = &tor->info;
    98128   
    99129    FILE    * file;
    100     int       version = 0;
     130    int       version = 1;
    101131    char    * path;
    102     int     * fileMTimes;
    103     uint8_t * blockBitfield;
     132    uint8_t * buf;
     133
     134    buf = malloc( FR_PROGRESS_LEN( tor ) );
    104135
    105136    /* Get file sizes */
    106     fileMTimes = malloc( inf->fileCount * 4 );
    107     if( fastResumeMTimes( io, fileMTimes ) )
    108     {
    109         free( fileMTimes );
     137    if( fastResumeMTimes( io, (int*)buf ) )
     138    {
     139        free( buf );
    110140        return;
    111141    }
     
    116146    {
    117147        tr_err( "Could not open '%s' for writing", path );
    118         free( fileMTimes );
     148        free( buf );
    119149        free( path );
    120150        return;
     
    124154    fwrite( &version, 4, 1, file );
    125155
    126     /* Write file mtimes */
    127     fwrite( fileMTimes, 4, inf->fileCount, file );
    128     free( fileMTimes );
    129 
    130     /* Build and write the bitfield for blocks */
    131     blockBitfield = tr_cpBlockBitfield( tor->completion );
    132     fwrite( blockBitfield, ( tor->blockCount + 7 ) / 8, 1, file );
    133 
    134     /* Write the 'slotPiece' table */
    135     fwrite( io->slotPiece, 4, inf->pieceCount, file );
     156    /* Build and copy the bitfield for blocks */
     157    memcpy(buf + FR_MTIME_LEN( tor ), tr_cpBlockBitfield( tor->completion ),
     158           FR_BLOCK_BITFIELD_LEN( tor ) );
     159
     160    /* Copy the 'slotPiece' table */
     161    memcpy(buf + FR_MTIME_LEN( tor ) + FR_BLOCK_BITFIELD_LEN( tor ),
     162           io->slotPiece, FR_SLOTPIECE_LEN( tor ) );
     163
     164    /* Write progress data */
     165    fastResumeWriteData( FR_ID_PROGRESS, buf, 1, FR_PROGRESS_LEN( tor ), file );
     166    free( buf );
     167
     168    /* Write download and upload totals */
     169    fastResumeWriteData( FR_ID_DOWNLOADED, &tor->downloaded, 8, 1, file );
     170    fastResumeWriteData( FR_ID_UPLOADED, &tor->uploaded, 8, 1, file );
    136171
    137172    fclose( file );
     
    141176}
    142177
    143 static int fastResumeLoad( tr_io_t * io )
     178static int fastResumeLoadProgress( tr_io_t * io, FILE * file )
    144179{
    145180    tr_torrent_t * tor = io->tor;
    146181    tr_info_t    * inf = &tor->info;
    147    
    148     FILE    * file;
    149     int       version = 0;
    150     char    * path;
    151     int     * fileMTimes1, * fileMTimes2;
     182
     183    int     * fileMTimes;
    152184    int       i, j;
    153     uint8_t * blockBitfield;
    154 
    155     int size;
    156 
    157     /* Open resume file */
    158     path = fastResumeFileName( io );
    159     if( !( file = fopen( path, "r" ) ) )
    160     {
    161         tr_inf( "Could not open '%s' for reading", path );
    162         free( path );
    163         return 1;
    164     }
    165     tr_dbg( "Resume file '%s' loaded", path );
    166     free( path );
    167 
    168     /* Check the size */
    169     size = 4 + 4 * inf->fileCount + 4 * inf->pieceCount +
    170         ( tor->blockCount + 7 ) / 8;
    171     fseek( file, 0, SEEK_END );
    172     if( ftell( file ) != size )
    173     {
    174         tr_inf( "Wrong size for resume file (%d bytes, %d expected)",
    175                 ftell( file ), size );
    176         fclose( file );
    177         return 1;
    178     }
    179     fseek( file, 0, SEEK_SET );
    180 
    181     /* Check format version */
    182     fread( &version, 4, 1, file );
    183     if( version != 0 )
    184     {
    185         tr_inf( "Resume file has version %d, not supported",
    186                 version );
    187         fclose( file );
     185    uint8_t * buf;
     186    size_t    len;
     187
     188    len = FR_PROGRESS_LEN( tor );
     189    buf = calloc( len, 1 );
     190    if( len != fread( buf, 1, len, file ) )
     191    {
     192        tr_inf( "Could not read from resume file" );
     193        free( buf );
    188194        return 1;
    189195    }
    190196
    191197    /* Compare file mtimes */
    192     fileMTimes1 = malloc( inf->fileCount * 4 );
    193     if( fastResumeMTimes( io, fileMTimes1 ) )
    194     {
    195         free( fileMTimes1 );
    196         fclose( file );
    197         return 1;
    198     }
    199     fileMTimes2 = malloc( inf->fileCount * 4 );
    200     fread( fileMTimes2, 4, inf->fileCount, file );
    201     if( memcmp( fileMTimes1, fileMTimes2, inf->fileCount * 4 ) )
     198    fileMTimes = malloc( FR_MTIME_LEN( tor ) );
     199    if( fastResumeMTimes( io, fileMTimes ) )
     200    {
     201        free( buf );
     202        free( fileMTimes );
     203        return 1;
     204    }
     205    if( memcmp( fileMTimes, buf, FR_MTIME_LEN( tor ) ) )
    202206    {
    203207        tr_inf( "File mtimes don't match" );
    204         free( fileMTimes1 );
    205         free( fileMTimes2 );
    206         fclose( file );
    207         return 1;
    208     }
    209     free( fileMTimes1 );
    210     free( fileMTimes2 );
    211 
    212     /* Load the bitfield for blocks and fill blockHave */
    213     blockBitfield = calloc( ( tor->blockCount + 7 ) / 8, 1 );
    214     fread( blockBitfield, ( tor->blockCount + 7 ) / 8, 1, file );
    215     tr_cpBlockBitfieldSet( tor->completion, blockBitfield );
    216     free( blockBitfield );
    217 
    218     /* Load the 'slotPiece' table */
    219     fread( io->slotPiece, 4, inf->pieceCount, file );
    220 
    221     fclose( file );
     208        free( buf );
     209        free( fileMTimes );
     210        return 1;
     211    }
     212    free( fileMTimes );
     213
     214    /* Copy the bitfield for blocks and fill blockHave */
     215    tr_cpBlockBitfieldSet( tor->completion, buf + FR_MTIME_LEN( tor ) );
     216
     217    /* Copy the 'slotPiece' table */
     218    memcpy( io->slotPiece, buf + FR_MTIME_LEN( tor ) +
     219            FR_BLOCK_BITFIELD_LEN( tor ), FR_SLOTPIECE_LEN( tor ) );
     220
     221    free( buf );
    222222
    223223    /* Update io->pieceSlot, io->slotsUsed, and tor->bitfield */
     
    239239    // tr_dbg( "Slot used: %d", io->slotsUsed );
    240240
    241     tr_inf( "Fast resuming successful" );
    242    
    243241    return 0;
    244242}
     243
     244static int fastResumeLoadOld( tr_io_t * io, FILE * file )
     245{
     246    tr_torrent_t * tor = io->tor;
     247   
     248    int size;
     249
     250    /* Check the size */
     251    size = 4 + FR_PROGRESS_LEN( tor );
     252    fseek( file, 0, SEEK_END );
     253    if( ftell( file ) != size )
     254    {
     255        tr_inf( "Wrong size for resume file (%d bytes, %d expected)",
     256                ftell( file ), size );
     257        fclose( file );
     258        return 1;
     259    }
     260    fseek( file, 0, SEEK_SET );
     261
     262    /* load progress information */
     263    if( fastResumeLoadProgress( io, file ) )
     264    {
     265        fclose( file );
     266        return 1;
     267    }
     268
     269    fclose( file );
     270
     271    tr_inf( "Fast resuming successful (version 0)" );
     272   
     273    return 0;
     274}
     275
     276static int fastResumeLoad( tr_io_t * io )
     277{
     278    tr_torrent_t * tor = io->tor;
     279   
     280    FILE    * file;
     281    int       version = 0;
     282    char    * path;
     283    uint8_t   id;
     284    uint32_t  len;
     285    int       ret;
     286
     287    /* Open resume file */
     288    path = fastResumeFileName( io );
     289    if( !( file = fopen( path, "r" ) ) )
     290    {
     291        tr_inf( "Could not open '%s' for reading", path );
     292        free( path );
     293        return 1;
     294    }
     295    tr_dbg( "Resume file '%s' loaded", path );
     296    free( path );
     297
     298    /* Check format version */
     299    fread( &version, 4, 1, file );
     300    if( 0 == version )
     301    {
     302        return fastResumeLoadOld( io, file );
     303    }
     304    if( 1 != version )
     305    {
     306        tr_inf( "Resume file has version %d, not supported", version );
     307        fclose( file );
     308        return 1;
     309    }
     310
     311    ret = 1;
     312    /* read each block of data */
     313    while( 1 == fread( &id, 1, 1, file ) && 1 == fread( &len, 4, 1, file ) )
     314    {
     315        switch( id )
     316        {
     317            case FR_ID_PROGRESS:
     318                /* read progress data */
     319                if( (uint32_t)FR_PROGRESS_LEN( tor ) == len )
     320                {
     321                    if( fastResumeLoadProgress( io, file ) )
     322                    {
     323                        fclose( file );
     324                        return 1;
     325                    }
     326                    ret = 0;
     327                    continue;
     328                }
     329                break;
     330
     331            case FR_ID_DOWNLOADED:
     332                /* read download total */
     333                if( 8 == len)
     334                {
     335                    if( 1 != fread( &tor->downloaded, 8, 1, file ) )
     336                    {
     337                      fclose( file );
     338                      return 1;
     339                    }
     340                    continue;
     341                }
     342                break;
     343
     344            case FR_ID_UPLOADED:
     345                /* read upload total */
     346                if( 8 == len)
     347                {
     348                    if( 1 != fread( &tor->uploaded, 8, 1, file ) )
     349                    {
     350                      fclose( file );
     351                      return 1;
     352                    }
     353                    continue;
     354                }
     355                break;
     356
     357            default:
     358                break;
     359        }
     360
     361        /* if we didn't read the data, seek past it */
     362        tr_inf( "Skipping resume data type %02x, %u bytes", id, len );
     363        fseek( file, len, SEEK_CUR );
     364    }
     365
     366    fclose( file );
     367
     368    if( !ret )
     369    {
     370        tr_inf( "Fast resuming successful" );
     371    }
     372   
     373    return ret;
     374}
  • trunk/libtransmission/transmission.c

    r92 r100  
    340340        tr_peerRem( tor, 0 );
    341341    }
    342 
    343     tor->downloaded = 0;
    344     tor->uploaded   = 0;
    345342}
    346343
Note: See TracChangeset for help on using the changeset viewer.