Ignore:
Timestamp:
Aug 20, 2008, 9:01:17 PM (13 years ago)
Author:
charles
Message:

more metainfo cleanup

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/metainfo.c

    r6602 r6603  
    2424
    2525#include <assert.h>
    26 #include <ctype.h> /* isspace */
    2726#include <errno.h>
    2827#include <stdio.h>
    29 #include <stdlib.h>
    3028
    3129#include <sys/types.h>
     
    4240#include "utils.h"
    4341
    44 /***********************************************************************
    45  * Local prototypes
    46  **********************************************************************/
    47 static int parseFiles( tr_info * inf, tr_benc * files, tr_benc * length );
    48 
    4942/***
    5043****
     
    6356
    6457static char*
    65 getTorrentOldFilename( const tr_handle * handle,
     58getOldTorrentFilename( const tr_handle * handle,
    6659                       const tr_info   * inf )
    6760{
    6861    char * ret;
    6962    struct evbuffer * buf = evbuffer_new( );
    70     evbuffer_add_printf( buf, "%s%c%s",
    71                         tr_getTorrentDir( handle ),
    72                          TR_PATH_DELIMITER,
    73                          inf->hashString );
     63
     64    evbuffer_add_printf( buf, "%s%c%s", tr_getTorrentDir( handle ),
     65                                        TR_PATH_DELIMITER,
     66                                        inf->hashString );
    7467    if( handle->tag )
    7568        evbuffer_add_printf( buf, "-%s", handle->tag );
     69
    7670    ret = tr_strndup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
    7771    evbuffer_free( buf );
     
    8882    if( stat( new_name, &new_sb ) || ( ( new_sb.st_mode & S_IFMT ) != S_IFREG ) )
    8983    {
    90         char * old_name = getTorrentOldFilename( handle, inf );
     84        char * old_name = getOldTorrentFilename( handle, inf );
    9185        size_t contentLen;
    9286        uint8_t * content;
     
    122116}
    123117
     118/***
     119****
     120***/
     121
     122static int
     123getfile( char ** setme, const char * root, tr_benc * path )
     124{
     125    int err;
     126
     127    if( !tr_bencIsList( path ) )
     128    {
     129        err = TR_EINVALID;
     130    }
     131    else
     132    {
     133        struct evbuffer * buf = evbuffer_new( );
     134        int n = tr_bencListSize( path );
     135        int i;
     136
     137        evbuffer_add( buf, root, strlen( root ) );
     138        for( i=0; i<n; ++i ) {
     139            const char * str;
     140            if( tr_bencGetStr( tr_bencListChild( path, i ), &str ) && strcmp( str, ".." ) ) {
     141                evbuffer_add( buf, TR_PATH_DELIMITER_STR, 1 );
     142                evbuffer_add( buf, str, strlen( str ) );
     143            }
     144        }
     145
     146        *setme = tr_strndup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
     147        /* fprintf( stderr, "[%s]\n", *setme ); */
     148        evbuffer_free( buf );
     149        err = TR_OK;
     150    }
     151
     152    return err;
     153}
     154
     155static const char*
     156parseFiles( tr_info * inf, tr_benc * files, tr_benc * length )
     157{
     158    tr_file_index_t i;
     159
     160    inf->totalSize = 0;
     161
     162    if( tr_bencIsList( files ) ) /* multi-file mode */
     163    {
     164        inf->isMultifile = 1;
     165        inf->fileCount   = tr_bencListSize( files );
     166        inf->files       = tr_new0( tr_file, inf->fileCount );
     167
     168        for( i=0; i<inf->fileCount; ++i )
     169        {
     170            tr_benc * file;
     171            tr_benc * path;
     172            int64_t length;
     173
     174            file = tr_bencListChild( files, i );
     175            if( !tr_bencIsDict( file ) )
     176                return "files";
     177
     178            if( !tr_bencDictFindList( file, "path.utf-8", &path ) )
     179                if( !tr_bencDictFindList( file, "path", &path ) )
     180                    return "path";
     181
     182            if( getfile( &inf->files[i].name, inf->name, path ) )
     183                return "path";
     184
     185            if( !tr_bencDictFindInt( file, "length", &length ) )
     186                return "length";
     187
     188            inf->files[i].length = length;
     189            inf->totalSize      += length;
     190        }
     191    }
     192    else if( tr_bencIsInt( length ) ) /* single-file mode */
     193    {
     194        inf->isMultifile      = 0;
     195        inf->fileCount        = 1;
     196        inf->files            = tr_new0( tr_file, 1 );
     197        inf->files[0].name    = tr_strdup( inf->name );
     198        inf->files[0].length  = length->val.i;
     199        inf->totalSize       += length->val.i;
     200    }
     201    else
     202    {
     203        return "length";
     204    }
     205
     206    return NULL;
     207}
     208
    124209static char *
    125210announceToScrape( const char * announce )
     
    147232}
    148233
    149 static void
    150 geturllist( tr_info * inf, tr_benc * meta )
    151 {
    152     benc_val_t * urls;
    153 
    154     if( tr_bencDictFindList( meta, "url-list", &urls ) )
    155     {
    156         int i;
    157         const char * url;
    158         const int n = tr_bencListSize( urls );
    159 
    160         inf->webseedCount = 0;
    161         inf->webseeds = tr_new0( char*, n );
    162 
    163         for( i=0; i<n; ++i )
    164             if( tr_bencGetStr( tr_bencListChild( urls, i ), &url ) )
    165                 inf->webseeds[inf->webseedCount++] = tr_strdup( url );
    166     }
    167 }
    168 
    169 static int
     234static const char*
    170235getannounce( tr_info * inf, tr_benc * meta )
    171236{
     
    204269        /* did we use any of the tiers? */
    205270        if( !trackerCount ) {
    206             tr_nerr( inf->name, _( "Invalid metadata entry \"%s\"" ), "announce-list" );
    207271            tr_free( trackers );
    208272            trackers = NULL;
     
    225289    inf->trackerCount = trackerCount;
    226290
    227     if( !inf->trackerCount )
    228         tr_nerr( inf->name, _( "Invalid metadata entry \"%s\"" ), "announce" );
    229 
    230     return inf->trackerCount ? TR_OK : TR_ERROR;
    231 }
    232 
    233 int
    234 tr_metainfoParse( const tr_handle  * handle,
    235                   tr_info          * inf,
    236                   const tr_benc    * meta_in )
     291    return inf->trackerCount ? NULL : "announce";
     292}
     293
     294static void
     295geturllist( tr_info * inf, tr_benc * meta )
     296{
     297    benc_val_t * urls;
     298
     299    if( tr_bencDictFindList( meta, "url-list", &urls ) )
     300    {
     301        int i;
     302        const char * url;
     303        const int n = tr_bencListSize( urls );
     304
     305        inf->webseedCount = 0;
     306        inf->webseeds = tr_new0( char*, n );
     307
     308        for( i=0; i<n; ++i )
     309            if( tr_bencGetStr( tr_bencListChild( urls, i ), &url ) )
     310                inf->webseeds[inf->webseedCount++] = tr_strdup( url );
     311    }
     312}
     313
     314static const char*
     315tr_metainfoParseImpl( const tr_handle  * handle,
     316                      tr_info          * inf,
     317                      const tr_benc    * meta_in )
    237318{
    238319    int64_t i;
     320    size_t raw_len;
    239321    const char * str;
    240322    const uint8_t * raw;
    241     size_t rawlen;
    242     tr_piece_index_t pi;
    243323    tr_benc * beInfo;
    244324    tr_benc * meta = (tr_benc *) meta_in;
     
    247327     * from the Metainfo file. Note that the value will be a bencoded
    248328     * dictionary, given the definition of the info key above. */
    249     if( tr_bencDictFindDict( meta, "info", &beInfo ) )
    250     {
     329    if( !tr_bencDictFindDict( meta, "info", &beInfo ) )
     330        return "info";
     331    else {
    251332        int len;
    252333        char * str = tr_bencSave( beInfo, &len );
     
    255336        tr_free( str );
    256337    }
    257     else
    258     {
    259         tr_err( _( "Missing metadata entry \"%s\"" ), "info" );
    260         return TR_EINVALID;
    261     }
    262338
    263339    /* name */
    264340    if( !tr_bencDictFindStr( beInfo, "name.utf-8", &str ) )
    265341        if( !tr_bencDictFindStr( beInfo, "name", &str ) )
    266             str = NULL;
     342            str = "";
     343    if( !str || !*str )
     344        return "name";
    267345    tr_free( inf->name );
    268346    inf->name = tr_strdup( str );
    269     if( !str || !*str ) {
    270         tr_err( _( "Invalid metadata entry \"%s\"" ), "name" );
    271         return TR_EINVALID;
    272     }
    273347
    274348    /* comment */
     
    279353    inf->comment = tr_strdup( str );
    280354   
    281     /* creator */
     355    /* created by */
    282356    if( !tr_bencDictFindStr( meta, "created by.utf-8", &str ) )
    283357        if( !tr_bencDictFindStr( meta, "created by", &str ) )
     
    286360    inf->creator = tr_strdup( str );
    287361   
    288     /* Date created */
     362    /* creation date */
    289363    if( !tr_bencDictFindInt( meta, "creation date", &i ) )
    290364        i = 0;
    291365    inf->dateCreated = i;
    292366   
    293     /* Private torrent */
     367    /* private */
    294368    if( !tr_bencDictFindInt( beInfo, "private", &i ) )
    295369        if( !tr_bencDictFindInt( meta, "private", &i ) )
     
    297371    inf->isPrivate = i != 0;
    298372   
    299     /* Piece length */
    300     if( tr_bencDictFindInt( beInfo, "piece length", &i ) && ( i > 0 ) )
    301         inf->pieceSize = i;
    302     else {
    303         tr_nerr( inf->name, _( "Invalid metadata entry \"%s\"" ), "piece length" );
    304         goto fail;
    305     }
    306 
    307     /* Hashes */
    308     if( !tr_bencDictFindRaw( beInfo, "pieces", &raw, &rawlen ) || ( rawlen % SHA_DIGEST_LENGTH ) ) {
    309         tr_nerr( inf->name, _( "Invalid metadata entry \"%s\"" ), "pieces" );
    310         goto fail;
    311     }
    312     inf->pieceCount = rawlen / SHA_DIGEST_LENGTH;
     373    /* piece length */
     374    if( !tr_bencDictFindInt( beInfo, "piece length", &i ) || ( i < 1 ) )
     375        return "piece length";
     376    inf->pieceSize = i;
     377
     378    /* pieces */
     379    if( !tr_bencDictFindRaw( beInfo, "pieces", &raw, &raw_len ) || ( raw_len % SHA_DIGEST_LENGTH ) )
     380        return "pieces";
     381    inf->pieceCount = raw_len / SHA_DIGEST_LENGTH;
    313382    inf->pieces = tr_new0( tr_piece, inf->pieceCount );
    314     for ( pi=0; pi<inf->pieceCount; ++pi )
    315         memcpy( inf->pieces[pi].hash, &raw[pi*SHA_DIGEST_LENGTH], SHA_DIGEST_LENGTH );
     383    for ( i=0; i<inf->pieceCount; ++i )
     384        memcpy( inf->pieces[i].hash, &raw[i*SHA_DIGEST_LENGTH], SHA_DIGEST_LENGTH );
    316385
    317386    /* files */
    318     if( parseFiles( inf, tr_bencDictFind( beInfo, "files" ),
    319                          tr_bencDictFind( beInfo, "length" ) ) )
    320     {
    321         goto fail;
    322     }
    323 
     387    if(( str = parseFiles( inf, tr_bencDictFind( beInfo, "files" ), tr_bencDictFind( beInfo, "length" ))))
     388        return str;
    324389    if( !inf->fileCount || !inf->totalSize )
    325     {
    326         tr_nerr( inf->name, _( "Torrent is corrupt" ) ); /* the content is missing! */
    327         goto fail;
    328     }
    329 
    330     /* TODO add more tests so we don't crash on weird files */
    331 
    332     if( (uint64_t) inf->pieceCount !=
    333         ( inf->totalSize + inf->pieceSize - 1 ) / inf->pieceSize )
    334     {
    335         tr_nerr( inf->name, _( "Torrent is corrupt" ) ); /* size of hashes and files don't match */
    336         goto fail;
    337     }
     390        return "files";
     391    if( (uint64_t) inf->pieceCount != ( inf->totalSize + inf->pieceSize - 1 ) / inf->pieceSize )
     392        return "files";
    338393
    339394    /* get announce or announce-list */
    340     if( getannounce( inf, meta ) )
    341         goto fail;
     395    if(( str = getannounce( inf, meta ) ))
     396        return str;
    342397
    343398    /* get the url-list */
     
    348403    inf->torrent = getTorrentFilename( handle, inf );
    349404
     405    return NULL;
     406}
     407
     408int
     409tr_metainfoParse( const tr_handle  * handle,
     410                  tr_info          * inf,
     411                  const tr_benc    * meta_in )
     412{
     413    const char * badTag = tr_metainfoParseImpl( handle, inf, meta_in );
     414    if( badTag )
     415    {
     416        tr_nerr( inf->name, _( "Invalid metadata entry \"%s\"" ), badTag );
     417        tr_metainfoFree( inf );
     418        return TR_EINVALID;
     419    }
    350420    return TR_OK;
    351 
    352   fail:
    353     tr_metainfoFree( inf );
    354     return TR_EINVALID;
    355 }
    356 
    357 void tr_metainfoFree( tr_info * inf )
     421}
     422
     423void
     424tr_metainfoFree( tr_info * inf )
    358425{
    359426    tr_file_index_t ff;
     
    383450}
    384451
    385 static int
    386 getfile( char ** setme, const char * root, tr_benc * path )
    387 {
    388     int err;
    389 
    390     if( !tr_bencIsList( path ) )
    391     {
    392         err = TR_EINVALID;
    393     }
    394     else
    395     {
    396         struct evbuffer * buf = evbuffer_new( );
    397         int n = tr_bencListSize( path );
    398         int i;
    399 
    400         evbuffer_add( buf, root, strlen( root ) );
    401         for( i=0; i<n; ++i ) {
    402             const char * str;
    403             if( tr_bencGetStr( tr_bencListChild( path, i ), &str ) && strcmp( str, ".." ) ) {
    404                 evbuffer_add( buf, TR_PATH_DELIMITER_STR, 1 );
    405                 evbuffer_add( buf, str, strlen( str ) );
    406             }
    407         }
    408 
    409         *setme = tr_strndup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) );
    410         /* fprintf( stderr, "[%s]\n", *setme ); */
    411         evbuffer_free( buf );
    412         err = TR_OK;
    413     }
    414 
    415     return err;
    416 }
    417 
    418452void
    419453tr_metainfoRemoveSaved( const tr_handle * handle,
     
    426460    tr_free( filename );
    427461
    428     filename = getTorrentOldFilename( handle, inf );
     462    filename = getOldTorrentFilename( handle, inf );
    429463    unlink( filename );
    430464    tr_free( filename );
    431465}
    432 
    433 static int
    434 parseFiles( tr_info * inf, tr_benc * files, tr_benc * length )
    435 {
    436     tr_benc * item, * path;
    437     int ii;
    438     inf->totalSize = 0;
    439 
    440     if( tr_bencIsList( files ) )
    441     {
    442         /* Multi-file mode */
    443         inf->isMultifile = 1;
    444         inf->fileCount   = files->val.l.count;
    445         inf->files       = tr_new0( tr_file, inf->fileCount );
    446 
    447         if( !inf->files )
    448             return TR_EINVALID;
    449 
    450         for( ii = 0; files->val.l.count > ii; ii++ )
    451         {
    452             item = &files->val.l.vals[ii];
    453             path = tr_bencDictFindFirst( item, "path.utf-8", "path", NULL );
    454             if( getfile( &inf->files[ii].name, inf->name, path ) )
    455             {
    456                 if( path )
    457                     tr_nerr( inf->name, _( "Invalid metadata entry \"%s\"" ), "path" );
    458                 else
    459                     tr_nerr( inf->name, _( "Missing metadata entry \"%s\"" ), "path" );
    460                 return TR_EINVALID;
    461             }
    462             length = tr_bencDictFind( item, "length" );
    463             if( !tr_bencIsInt( length ) )
    464             {
    465                 if( length )
    466                     tr_nerr( inf->name, _( "Invalid metadata entry \"%s\"" ), "length" );
    467                 else
    468                     tr_nerr( inf->name, _( "Missing metadata entry \"%s\"" ), "length" );
    469                 return TR_EINVALID;
    470             }
    471             inf->files[ii].length = length->val.i;
    472             inf->totalSize         += length->val.i;
    473         }
    474     }
    475     else if( tr_bencIsInt( length ) )
    476     {
    477         /* Single-file mode */
    478         inf->isMultifile = 0;
    479         inf->fileCount = 1;
    480         inf->files = tr_new0( tr_file, 1 );
    481 
    482         if( !inf->files )
    483             return TR_EINVALID;
    484 
    485         tr_free( inf->files[0].name );
    486         inf->files[0].name   = tr_strdup( inf->name );
    487         inf->files[0].length = length->val.i;
    488         inf->totalSize      += length->val.i;
    489     }
    490     else
    491     {
    492         tr_nerr( inf->name, _( "Invalid or missing metadata entries \"length\" and \"files\"" ) );
    493     }
    494 
    495     return TR_OK;
    496 }
Note: See TracChangeset for help on using the changeset viewer.