Example #1
0
/* returns 0 on success, or an errno on failure */
static int
readOrWriteBytes( const tr_torrent * tor,
                  int                ioMode,
                  tr_file_index_t    fileIndex,
                  uint64_t           fileOffset,
                  void *             buf,
                  size_t             buflen )
{
    const tr_info * info = &tor->info;
    const tr_file * file = &info->files[fileIndex];

    typedef size_t ( *iofunc )( int, void *, size_t );
    iofunc          func = ioMode ==
                           TR_IO_READ ? (iofunc)read : (iofunc)write;
    char          * path;
    struct stat     sb;
    int             fd = -1;
    int             err;
    int             fileExists;

    assert( tor->downloadDir && *tor->downloadDir );
    assert( fileIndex < info->fileCount );
    assert( !file->length || ( fileOffset < file->length ) );
    assert( fileOffset + buflen <= file->length );

    path = tr_buildPath( tor->downloadDir, file->name, NULL );
    fileExists = !stat( path, &sb );
    tr_free( path );

    if( !file->length )
        return 0;

    if( ( ioMode == TR_IO_READ ) && !fileExists ) /* does file exist? */
        err = errno;
    else if( ( fd = tr_fdFileCheckout ( tor->downloadDir, file->name, ioMode == TR_IO_WRITE, !file->dnd, file->length ) ) < 0 )
        err = errno;
    else if( tr_lseek( fd, (int64_t)fileOffset, SEEK_SET ) == -1 )
        err = errno;
    else if( func( fd, buf, buflen ) != buflen )
        err = errno;
    else
        err = 0;

    if( ( !err ) && ( !fileExists ) && ( ioMode == TR_IO_WRITE ) )
        tr_statsFileCreated( tor->session );

    if( fd >= 0 )
        tr_fdFileReturn( fd );

    return err;
}
Example #2
0
static tr_bool
verifyTorrent( tr_torrent * tor, tr_bool * stopFlag )
{
    SHA_CTX sha;
    int fd = -1;
    int64_t filePos = 0;
    tr_bool changed = 0;
    tr_bool hadPiece = 0;
    uint32_t piecePos = 0;
    uint32_t pieceBytesRead = 0;
    tr_file_index_t fileIndex = 0;
    tr_piece_index_t pieceIndex = 0;
    const int64_t buflen = tor->info.pieceSize;
    uint8_t * buffer = tr_new( uint8_t, buflen );
#ifdef STOPWATCH
    time_t now = time( NULL );
#endif

    SHA1_Init( &sha );

    while( !*stopFlag && ( pieceIndex < tor->info.pieceCount ) )
    {
        int64_t leftInPiece;
        int64_t leftInFile;
        int64_t bytesThisPass;
        const tr_file * file = &tor->info.files[fileIndex];

        /* if we're starting a new piece... */
        if( piecePos == 0 )
        {
            hadPiece = tr_cpPieceIsComplete( &tor->completion, pieceIndex );
            /* fprintf( stderr, "starting piece %d of %d\n", (int)pieceIndex, (int)tor->info.pieceCount ); */
        }

        /* if we're starting a new file... */
        if( !filePos && (fd<0) )
        {
            char * filename = tr_buildPath( tor->downloadDir, file->name, NULL );
            fd = tr_open_file_for_scanning( filename );
            /* fprintf( stderr, "opening file #%d (%s) -- %d\n", fileIndex, filename, fd ); */
            tr_free( filename );
        }

        /* figure out how much we can read this pass */
        leftInPiece = tr_torPieceCountBytes( tor, pieceIndex ) - piecePos;
        leftInFile = file->length - filePos;
        bytesThisPass = MIN( leftInFile, leftInPiece );
        bytesThisPass = MIN( bytesThisPass, buflen );
        /* fprintf( stderr, "reading this pass: %d\n", (int)bytesThisPass ); */

        /* read a bit */
        if( (fd>=0) && tr_lseek( fd, filePos, SEEK_SET ) != -1 ) {
            const int64_t numRead = read( fd, buffer, bytesThisPass );
            if( numRead > 0 )
                pieceBytesRead += numRead;
            if( numRead == bytesThisPass )
                SHA1_Update( &sha, buffer, numRead );
        }

        /* move our offsets */
        leftInPiece -= bytesThisPass;
        leftInFile -= bytesThisPass;
        piecePos += bytesThisPass;
        filePos += bytesThisPass;

        /* if we're finishing a piece... */
        if( leftInPiece == 0 )
        {
            tr_bool hasPiece;
            uint8_t hash[SHA_DIGEST_LENGTH];

            SHA1_Final( hash, &sha );
            hasPiece = !memcmp( hash, tor->info.pieces[pieceIndex].hash, SHA_DIGEST_LENGTH );
            /* fprintf( stderr, "do the hashes match? %s\n", (hasPiece?"yes":"no") ); */

            if( hasPiece ) {
                tr_torrentSetHasPiece( tor, pieceIndex, TRUE );
                if( !hadPiece )
                    changed = TRUE;
            } else if( hadPiece ) {
                tr_torrentSetHasPiece( tor, pieceIndex, FALSE );
                changed = TRUE;
            }
            tr_torrentSetPieceChecked( tor, pieceIndex, TRUE );
            tor->anyDate = time( NULL );

            /* going full-throttle on a verify can choke other processes'
             * disk IO, so wait a fwe msec between pieces.
             * The msec is arbitrary, and the "if" clause is to make sure we
             * don't slow down verification of files that don't exist */
            if( pieceBytesRead == tr_torPieceCountBytes( tor, pieceIndex ) )
                tr_wait( 50 );

            SHA1_Init( &sha );
            ++pieceIndex;
            piecePos = 0;
            pieceBytesRead = 0;
        }

        /* if we're finishing a file... */
        if( leftInFile == 0 )
        {
            /* fprintf( stderr, "closing file\n" ); */
            if( fd >= 0 ) {
                tr_close_file( fd );
                fd = -1;
            }
            ++fileIndex;
            filePos = 0;
        }
    }

    /* cleanup */
    if( fd >= 0 )
        tr_close_file( fd );
    tr_free( buffer );

#ifdef STOPWATCH
    {
        time_t now2 = time( NULL );
        fprintf( stderr, "it took %d seconds to verify %"PRIu64" bytes (%"PRIu64" bytes per second)\n",
                 (int)(now2-now), tor->info.totalSize, (uint64_t)(tor->info.totalSize/(1+(now2-now))) );
    }
#endif

    return changed;
}