コード例 #1
0
ファイル: fastresume.c プロジェクト: fangang190/canary
static uint64_t
parseProgress( tr_torrent *    tor,
               const uint8_t * buf,
               uint32_t        len )
{
    uint64_t ret = 0;

    if( len == FR_PROGRESS_LEN( tor ) )
    {
        int             i;
        int             n;
        tr_bitfield     bitfield;

        /* compare file mtimes */
        tr_time_t *     curMTimes = getMTimes( tor, &n );
        const uint8_t * walk = buf;
        tr_time_t       mtime;
        for( i = 0; i < n; ++i )
        {
            readBytes( &mtime, &walk, sizeof( tr_time_t ) );
            if( curMTimes[i] == mtime )
                tr_torrentSetFileChecked( tor, i, TRUE );
            else
            {
                tr_torrentSetFileChecked( tor, i, FALSE );
                tr_tordbg( tor, "Torrent needs to be verified" );
            }
        }
        free( curMTimes );

        /* get the completion bitfield */
        memset( &bitfield, 0, sizeof bitfield );
        bitfield.byteCount = FR_BLOCK_BITFIELD_LEN( tor );
        bitfield.bitCount = bitfield.byteCount * 8;
        bitfield.bits = (uint8_t*) walk;
        if( tr_cpBlockBitfieldSet( tor->completion, &bitfield ) )
            ret = TR_FR_PROGRESS;
        else {
            tr_torrentUncheck( tor );
            tr_tordbg( tor, "Torrent needs to be verified" );
        }
    }

    /* the files whose mtimes are wrong,
       remove from completion pending a recheck... */
    {
        tr_piece_index_t i;
        for( i = 0; i < tor->info.pieceCount; ++i )
            if( !tr_torrentIsPieceChecked( tor, i ) )
                tr_cpPieceRem( tor->completion, i );
    }

    return ret;
}
コード例 #2
0
ファイル: resume.c プロジェクト: ijuxda/transmission
static uint64_t
loadDND( tr_benc *    dict,
         tr_torrent * tor )
{
    uint64_t              ret = 0;
    tr_info *             inf = &tor->info;
    const tr_file_index_t n = inf->fileCount;
    tr_benc *             list = NULL;

    if( tr_bencDictFindList( dict, KEY_DND, &list )
      && ( tr_bencListSize( list ) == n ) )
    {
        int64_t           tmp;
        tr_file_index_t * dl = tr_new( tr_file_index_t, n );
        tr_file_index_t * dnd = tr_new( tr_file_index_t, n );
        tr_file_index_t   i, dlCount = 0, dndCount = 0;

        for( i = 0; i < n; ++i )
        {
            if( tr_bencGetInt( tr_bencListChild( list, i ), &tmp ) && tmp )
                dnd[dndCount++] = i;
            else
                dl[dlCount++] = i;
        }

        if( dndCount )
        {
            tr_torrentInitFileDLs ( tor, dnd, dndCount, FALSE );
            tr_tordbg( tor, "Resume file found %d files listed as dnd",
                       dndCount );
        }
        if( dlCount )
        {
            tr_torrentInitFileDLs ( tor, dl, dlCount, TRUE );
            tr_tordbg( tor,
                       "Resume file found %d files marked for download",
                       dlCount );
        }

        tr_free( dnd );
        tr_free( dl );
        ret = TR_FR_DND;
    }
    else
    {
        tr_tordbg(
            tor,
            "Couldn't load DND flags. DND list (%p) has %zu children; torrent has %d files",
            list, tr_bencListSize( list ), (int)n );
    }

    return ret;
}
コード例 #3
0
ファイル: fastresume.c プロジェクト: fangang190/canary
static uint64_t
parsePeers( tr_torrent *    tor,
            const uint8_t * buf,
            uint32_t        len )
{
    uint64_t ret = 0;

    if( !tor->info.isPrivate )
    {
        int       i;
        const int count = len / sizeof( tr_pex );

        for( i = 0; i < count; ++i )
        {
            tr_pex pex;
            readBytes( &pex, &buf, sizeof( tr_pex ) );
            tr_peerMgrAddPex( tor->session->peerMgr, tor->info.hash,
                              TR_PEER_FROM_CACHE,
                              &pex );
        }

        tr_tordbg( tor, "Loaded %d peers from resume file", count );
        ret = TR_FR_PEERS;
    }

    return ret;
}
コード例 #4
0
ファイル: resume.c プロジェクト: fangang190/canary
static uint64_t
loadPeers( tr_benc *    dict,
           tr_torrent * tor )
{
    uint64_t        ret = 0;
    const uint8_t * str;
    size_t          len;

    if( tr_bencDictFindRaw( dict, KEY_PEERS, &str, &len ) )
    {
        int       i;
        const int count = len / sizeof( tr_pex );
        for( i = 0; i < count; ++i )
        {
            tr_pex pex;
            memcpy( &pex, str + ( i * sizeof( tr_pex ) ), sizeof( tr_pex ) );
            tr_peerMgrAddPex( tor->session->peerMgr,
                              tor->info.hash, TR_PEER_FROM_CACHE, &pex );
        }
        tr_tordbg( tor, "Loaded %d peers from resume file", count );
        ret = TR_FR_PEERS;
    }

    return ret;
}
コード例 #5
0
ファイル: resume.c プロジェクト: ijuxda/transmission
static uint64_t
loadPeers( tr_benc * dict, tr_torrent * tor )
{
    uint64_t        ret = 0;
    const uint8_t * str;
    size_t          len;

    if( tr_bencDictFindRaw( dict, KEY_PEERS, &str, &len ) )
    {
        const int numAdded = addPeers( tor, str, len );
        tr_tordbg( tor, "Loaded %d IPv4 peers from resume file", numAdded );
        ret = TR_FR_PEERS;
    }

    if( tr_bencDictFindRaw( dict, KEY_PEERS6, &str, &len ) )
    {
        const int numAdded = addPeers( tor, str, len );
        tr_tordbg( tor, "Loaded %d IPv6 peers from resume file", numAdded );
        ret = TR_FR_PEERS;
    }

    return ret;
}
コード例 #6
0
ファイル: cache.c プロジェクト: marltu/transmission
static int
flushContiguous( tr_cache * cache, int pos, int n )
{
    int i;
    int err = 0;
    uint8_t * buf = tr_new( uint8_t, n * MAX_BLOCK_SIZE );
    uint8_t * walk = buf;
    struct cache_block ** blocks = (struct cache_block**) tr_ptrArrayBase( &cache->blocks );

    struct cache_block * b = blocks[pos];
    tr_torrent * tor             = b->tor;
    const tr_piece_index_t piece = b->piece;
    const uint32_t offset        = b->offset;

//fprintf( stderr, "flushing %d contiguous blocks [%d-%d) from cache to disk\n", n, pos, n+pos );

    for( i=pos; i<pos+n; ++i ) {
        b = blocks[i];
        memcpy( walk, b->buf, b->length );
        walk += b->length;
        tr_free( b->buf );
        tr_free( b );
    }
    tr_ptrArrayErase( &cache->blocks, pos, pos+n );

#if 0
    tr_tordbg( tor, "Writing to disk piece %d, offset %d, len %d", (int)piece, (int)offset, (int)(walk-buf) );
    tr_ndbg( MY_NAME, "Removing %d blocks from cache, rank: %d - %d left", n, rank, tr_ptrArraySize(&cache->blocks) );
    fprintf( stderr, "%s - Writing to disk piece %d, offset %d, len %d\n", tr_torrentName(tor), (int)piece, (int)offset, (int)(walk-buf) );
    fprintf( stderr, "%s - Removing %d blocks from cache; %d left\n", MY_NAME, n, tr_ptrArraySize(&cache->blocks) );
#endif

    err = tr_ioWrite( tor, piece, offset, walk-buf, buf );
    tr_free( buf );

    ++cache->disk_writes;
    cache->disk_write_bytes += walk-buf;
    return err;
}
コード例 #7
0
ファイル: resume.c プロジェクト: ijuxda/transmission
static uint64_t
loadFromFile( tr_torrent * tor,
              uint64_t     fieldsToLoad )
{
    int64_t  i;
    const char * str;
    uint64_t fieldsLoaded = 0;
    char * filename;
    tr_benc top;
    tr_bool boolVal;
    const tr_bool  wasDirty = tor->isDirty;

    assert( tr_isTorrent( tor ) );

    filename = getResumeFilename( tor );

    if( tr_bencLoadFile( &top, TR_FMT_BENC, filename ) )
    {
        tr_tordbg( tor, "Couldn't read \"%s\"", filename );

        tr_free( filename );
        return fieldsLoaded;
    }

    tr_tordbg( tor, "Read resume file \"%s\"", filename );

    if( ( fieldsToLoad & TR_FR_CORRUPT )
      && tr_bencDictFindInt( &top, KEY_CORRUPT, &i ) )
    {
        tor->corruptPrev = i;
        fieldsLoaded |= TR_FR_CORRUPT;
    }

    if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR ) )
      && ( tr_bencDictFindStr( &top, KEY_DOWNLOAD_DIR, &str ) )
      && ( str && *str ) )
    {
        tr_free( tor->downloadDir );
        tor->downloadDir = tr_strdup( str );
        fieldsLoaded |= TR_FR_DOWNLOAD_DIR;
    }

    if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_INCOMPLETE_DIR ) )
      && ( tr_bencDictFindStr( &top, KEY_INCOMPLETE_DIR, &str ) )
      && ( str && *str ) )
    {
        tr_free( tor->incompleteDir );
        tor->incompleteDir = tr_strdup( str );
        fieldsLoaded |= TR_FR_INCOMPLETE_DIR;
    }

    if( ( fieldsToLoad & TR_FR_DOWNLOADED )
      && tr_bencDictFindInt( &top, KEY_DOWNLOADED, &i ) )
    {
        tor->downloadedPrev = i;
        fieldsLoaded |= TR_FR_DOWNLOADED;
    }

    if( ( fieldsToLoad & TR_FR_UPLOADED )
      && tr_bencDictFindInt( &top, KEY_UPLOADED, &i ) )
    {
        tor->uploadedPrev = i;
        fieldsLoaded |= TR_FR_UPLOADED;
    }

    if( ( fieldsToLoad & TR_FR_MAX_PEERS )
      && tr_bencDictFindInt( &top, KEY_MAX_PEERS, &i ) )
    {
        tor->maxConnectedPeers = i;
        fieldsLoaded |= TR_FR_MAX_PEERS;
    }

    if( ( fieldsToLoad & TR_FR_RUN )
      && tr_bencDictFindBool( &top, KEY_PAUSED, &boolVal ) )
    {
        tor->isRunning = !boolVal;
        fieldsLoaded |= TR_FR_RUN;
    }

    if( ( fieldsToLoad & TR_FR_ADDED_DATE )
      && tr_bencDictFindInt( &top, KEY_ADDED_DATE, &i ) )
    {
        tor->addedDate = i;
        fieldsLoaded |= TR_FR_ADDED_DATE;
    }

    if( ( fieldsToLoad & TR_FR_DONE_DATE )
      && tr_bencDictFindInt( &top, KEY_DONE_DATE, &i ) )
    {
        tor->doneDate = i;
        fieldsLoaded |= TR_FR_DONE_DATE;
    }

    if( ( fieldsToLoad & TR_FR_ACTIVITY_DATE )
      && tr_bencDictFindInt( &top, KEY_ACTIVITY_DATE, &i ) )
    {
        tr_torrentSetActivityDate( tor, i );
        fieldsLoaded |= TR_FR_ACTIVITY_DATE;
    }

    if( ( fieldsToLoad & TR_FR_TIME_SEEDING )
      && tr_bencDictFindInt( &top, KEY_TIME_SEEDING, &i ) )
    {
        tor->secondsSeeding = i;
        fieldsLoaded |= TR_FR_TIME_SEEDING;
    }

    if( ( fieldsToLoad & TR_FR_TIME_DOWNLOADING )
      && tr_bencDictFindInt( &top, KEY_TIME_DOWNLOADING, &i ) )
    {
        tor->secondsDownloading = i;
        fieldsLoaded |= TR_FR_TIME_DOWNLOADING;
    }

    if( ( fieldsToLoad & TR_FR_BANDWIDTH_PRIORITY )
      && tr_bencDictFindInt( &top, KEY_BANDWIDTH_PRIORITY, &i )
      && tr_isPriority( i ) )
    {
        tr_torrentSetPriority( tor, i );
        fieldsLoaded |= TR_FR_BANDWIDTH_PRIORITY;
    }

    if( fieldsToLoad & TR_FR_PEERS )
        fieldsLoaded |= loadPeers( &top, tor );

    if( fieldsToLoad & TR_FR_FILE_PRIORITIES )
        fieldsLoaded |= loadFilePriorities( &top, tor );

    if( fieldsToLoad & TR_FR_PROGRESS )
        fieldsLoaded |= loadProgress( &top, tor );

    if( fieldsToLoad & TR_FR_DND )
        fieldsLoaded |= loadDND( &top, tor );

    if( fieldsToLoad & TR_FR_SPEEDLIMIT )
        fieldsLoaded |= loadSpeedLimits( &top, tor );

    if( fieldsToLoad & TR_FR_RATIOLIMIT )
        fieldsLoaded |= loadRatioLimits( &top, tor );

    if( fieldsToLoad & TR_FR_IDLELIMIT )
        fieldsLoaded |= loadIdleLimits( &top, tor );

    /* loading the resume file triggers of a lot of changes,
     * but none of them needs to trigger a re-saving of the
     * same resume information... */
    tor->isDirty = wasDirty;

    tr_bencFree( &top );
    tr_free( filename );
    return fieldsLoaded;
}
コード例 #8
0
ファイル: resume.c プロジェクト: ijuxda/transmission
static uint64_t
loadProgress( tr_benc * dict, tr_torrent * tor )
{
    size_t i, n;
    uint64_t ret = 0;
    tr_benc * prog;
    const tr_info * inf = tr_torrentInfo( tor );

    for( i=0, n=inf->pieceCount; i<n; ++i )
        inf->pieces[i].timeChecked = 0;

    if( tr_bencDictFindDict( dict, KEY_PROGRESS, &prog ) )
    {
        const char * err;
        const char * str;
        const uint8_t * raw;
        size_t rawlen;
        tr_benc * l;
        tr_benc * b;
        struct tr_bitset bitset = TR_BITSET_INIT;

        if( tr_bencDictFindList( prog, KEY_PROGRESS_CHECKTIME, &l ) )
        {
            /* per-piece timestamps were added in 2.20.
              
               If some of a file's pieces have been checked more recently than
               the file's mtime, and some lest recently, then that file will
               have a list containing timestamps for each piece.
              
               However, the most common use case is that the file doesn't change
               after it's downloaded. To reduce overhead in the .resume file,
               only a single timestamp is saved for the file if *all* or *none*
               of the pieces were tested more recently than the file's mtime. */

            tr_file_index_t fi;

            for( fi=0; fi<inf->fileCount; ++fi )
            {
                tr_benc * b = tr_bencListChild( l, fi );
                const tr_file * f = &inf->files[fi];
                tr_piece * p = &inf->pieces[f->firstPiece];
                const tr_piece * pend = &inf->pieces[f->lastPiece]+1;

                if( tr_bencIsInt( b ) )
                {
                    int64_t t;
                    tr_bencGetInt( b, &t );
                    for( ; p!=pend; ++p )
                        p->timeChecked = (time_t)t;
                }
                else if( tr_bencIsList( b ) )
                {
                    int i = 0;
                    int64_t offset = 0;
                    const int pieces = f->lastPiece + 1 - f->firstPiece;

                    tr_bencGetInt( tr_bencListChild( b, 0 ), &offset );

                    for( i=0; i<pieces; ++i )
                    {
                        int64_t t = 0;
                        tr_bencGetInt( tr_bencListChild( b, i+1 ), &t );
                        inf->pieces[f->firstPiece+i].timeChecked = (time_t)(t ? t + offset : 0);
                    }
                }
            }
        }
        else if( tr_bencDictFindList( prog, KEY_PROGRESS_MTIMES, &l ) )
        {
            tr_file_index_t fi;

            /* Before 2.20, we stored the files' mtimes in the .resume file.
               When loading the .resume file, a torrent's file would be flagged
               as untested if its stored mtime didn't match its real mtime. */

            for( fi=0; fi<inf->fileCount; ++fi )
            {
                int64_t t;

                if( tr_bencGetInt( tr_bencListChild( l, fi ), &t ) )
                {
                    const tr_file * f = &inf->files[fi];
                    tr_piece * p = &inf->pieces[f->firstPiece];
                    const tr_piece * pend = &inf->pieces[f->lastPiece];
                    const time_t mtime = tr_torrentGetFileMTime( tor, fi );
                    const time_t timeChecked = mtime==t ? mtime : 0;

                    for( ; p!=pend; ++p )
                        p->timeChecked = timeChecked;
                }
            }
        }

        err = NULL;

        if(( b = tr_bencDictFind( prog, KEY_PROGRESS_BLOCKS )))
        {
            if( !tr_bitsetFromBenc( &bitset, b ) )
                err = "Invalid value for PIECES";
        }
        else if( tr_bencDictFindStr( prog, KEY_PROGRESS_HAVE, &str ) )
        {
            if( !strcmp( str, "all" ) )
                tr_bitsetSetHaveAll( &bitset );
            else
                err = "Invalid value for HAVE";
        }
        else if( tr_bencDictFindRaw( prog, KEY_PROGRESS_BITFIELD, &raw, &rawlen ) )
        {
            bitset.bitfield.bits = (void*) raw;
            bitset.bitfield.byteCount = rawlen;
            bitset.bitfield.bitCount = rawlen * 8;
        }
        else err = "Couldn't find 'pieces' or 'have' or 'bitfield'";

        if( !err && !tr_cpBlockBitsetInit( &tor->completion, &bitset ) )
            err = "Error loading bitfield";
        if( err != NULL )
            tr_tordbg( tor, "Torrent needs to be verified - %s", err );

        ret = TR_FR_PROGRESS;
    }

    return ret;
}
コード例 #9
0
ファイル: verify.c プロジェクト: dreamcat4/transmission
static tr_bool
verifyTorrent( tr_torrent * tor, tr_bool * stopFlag )
{
    time_t end;
    SHA_CTX sha;
    int fd = -1;
    int64_t filePos = 0;
    tr_bool changed = 0;
    tr_bool hadPiece = 0;
    time_t lastSleptAt = 0;
    uint32_t piecePos = 0;
    tr_file_index_t fileIndex = 0;
    tr_file_index_t prevFileIndex = !fileIndex;
    tr_piece_index_t pieceIndex = 0;
    const time_t begin = tr_time( );
    const size_t buflen = 1024 * 128; /* 128 KiB buffer */
    uint8_t * buffer = tr_valloc( buflen );

    SHA1_Init( &sha );

    tr_tordbg( tor, "%s", "verifying torrent..." );
    tr_torrentSetChecked( tor, 0 );
    while( !*stopFlag && ( pieceIndex < tor->info.pieceCount ) )
    {
        uint32_t leftInPiece;
        uint32_t bytesThisPass;
        uint64_t leftInFile;
        const tr_file * file = &tor->info.files[fileIndex];

        /* if we're starting a new piece... */
        if( piecePos == 0 )
            hadPiece = tr_cpPieceIsComplete( &tor->completion, pieceIndex );

        /* if we're starting a new file... */
        if( !filePos && (fd<0) && (fileIndex!=prevFileIndex) )
        {
            char * filename = tr_torrentFindFile( tor, fileIndex );
            fd = filename == NULL ? -1 : tr_open_file_for_scanning( filename );
            tr_free( filename );
            prevFileIndex = fileIndex;
        }

        /* 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 );

        /* read a bit */
        if( fd >= 0 ) {
            const ssize_t numRead = tr_pread( fd, buffer, bytesThisPass, filePos );
            if( numRead > 0 ) {
                bytesThisPass = (uint32_t)numRead;
                SHA1_Update( &sha, buffer, bytesThisPass );
#if defined HAVE_POSIX_FADVISE && defined POSIX_FADV_DONTNEED
                posix_fadvise( fd, filePos, bytesThisPass, POSIX_FADV_DONTNEED );
#endif
            }
        }

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

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

            SHA1_Final( hash, &sha );
            hasPiece = !memcmp( hash, tor->info.pieces[pieceIndex].hash, SHA_DIGEST_LENGTH );

            if( hasPiece || hadPiece ) {
                tr_torrentSetHasPiece( tor, pieceIndex, hasPiece );
                changed |= hasPiece != hadPiece;
            }
            tr_torrentSetPieceChecked( tor, pieceIndex );
            now = tr_time( );
            tor->anyDate = now;

            /* sleeping even just a few msec per second goes a long
             * way towards reducing IO load... */
            if( lastSleptAt != now ) {
                lastSleptAt = now;
                tr_wait_msec( MSEC_TO_SLEEP_PER_SECOND_DURING_VERIFY );
            }

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

        /* if we're finishing a file... */
        if( leftInFile == 0 )
        {
            if( fd >= 0 ) { tr_close_file( fd ); fd = -1; }
            ++fileIndex;
            filePos = 0;
        }
    }

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

    /* stopwatch */
    end = tr_time( );
    tr_tordbg( tor, "Verification is done. It took %d seconds to verify %"PRIu64" bytes (%"PRIu64" bytes per second)",
               (int)(end-begin), tor->info.totalSize,
               (uint64_t)(tor->info.totalSize/(1+(end-begin))) );

    return changed;
}
コード例 #10
0
ファイル: inout.c プロジェクト: marltu/transmission
/* returns 0 on success, or an errno on failure */
static int
readOrWriteBytes( tr_session       * session,
                  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];

    int             fd = -1;
    int             err = 0;
    const tr_bool doWrite = ioMode >= TR_IO_WRITE;

//if( doWrite )
//    fprintf( stderr, "in file %s at offset %zu, writing %zu bytes; file length is %zu\n", file->name, (size_t)fileOffset, buflen, (size_t)file->length );

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

    if( !file->length )
        return 0;

    fd = tr_fdFileGetCached( session, tr_torrentId( tor ), fileIndex, doWrite );

    if( fd < 0 )
    {
        /* the fd cache doesn't have this file...
         * we'll need to open it and maybe create it */
        char * subpath;
        const char * base;
        tr_bool fileExists;
        tr_preallocation_mode preallocationMode;

        fileExists = tr_torrentFindFile2( tor, fileIndex, &base, &subpath );

        if( !fileExists )
        {
            base = tr_torrentGetCurrentDir( tor );

            if( tr_sessionIsIncompleteFileNamingEnabled( tor->session ) )
                subpath = tr_torrentBuildPartial( tor, fileIndex );
            else
                subpath = tr_strdup( file->name );
        }

        if( ( file->dnd ) || ( ioMode < TR_IO_WRITE ) )
            preallocationMode = TR_PREALLOCATE_NONE;
        else
            preallocationMode = tor->session->preallocationMode;

        if( ( ioMode < TR_IO_WRITE ) && !fileExists ) /* does file exist? */
        {
            err = ENOENT;
        }
        else
        {
            char * filename = tr_buildPath( base, subpath, NULL );

            if( ( fd = tr_fdFileCheckout( session, tor->uniqueId, fileIndex, filename,
                                          doWrite, preallocationMode, file->length ) ) < 0 )
            {
                err = errno;
                tr_torerr( tor, "tr_fdFileCheckout failed for \"%s\": %s", filename, tr_strerror( err ) );
            }

            tr_free( filename );
        }

        if( doWrite && !err )
            tr_statsFileCreated( tor->session );

        tr_free( subpath );
    }

    if( !err )
    {
        /* check & see if someone deleted the file while it was in our cache */
        struct stat sb;
        const tr_bool file_disappeared = fstat( fd, &sb ) || sb.st_nlink < 1;
        if( file_disappeared ) {
            tr_torrentSetLocalError( tor, "Please Verify Local Data! A file disappeared: \"%s\"", tor->info.files[fileIndex].name );
            err = ENOENT;
        }

        if( ioMode == TR_IO_READ ) {
            const int rc = tr_pread( fd, buf, buflen, fileOffset );
            if( rc < 0 ) {
                err = errno;
                tr_torerr( tor, "read failed for \"%s\": %s",
                           file->name, tr_strerror( err ) );
            }
        } else if( ioMode == TR_IO_PREFETCH ) {
            const int rc = tr_prefetch( fd, fileOffset, buflen );
            if( rc < 0 ) {
                /* (don't set "err" here... it's okay for prefetch to fail) */
                tr_tordbg( tor, "prefetch failed for \"%s\": %s",
                           file->name, tr_strerror( errno ) );
            }
        } else if( ioMode == TR_IO_WRITE ) {
            const int rc = tr_pwrite( fd, buf, buflen, fileOffset );
            if( rc < 0 ) {
                err = errno;
                tr_torerr( tor, "write failed for \"%s\": %s",
                           file->name, tr_strerror( err ) );
            }
        } else {
            abort();
        }
    }

    return err;
}
コード例 #11
0
ファイル: fastresume.c プロジェクト: fangang190/canary
static uint64_t
parseVersion1( tr_torrent *    tor,
               const uint8_t * buf,
               const uint8_t * end,
               uint64_t        fieldsToLoad )
{
    uint64_t ret = 0;

    while( end - buf >= 5 )
    {
        uint8_t  id;
        uint32_t len;
        readBytes( &id, &buf, sizeof( id ) );
        readBytes( &len, &buf, sizeof( len ) );

        if( buf + len > end )
        {
            tr_torerr( tor, "Resume file seems to be corrupt.  Skipping." );
        }
        else if( fieldsToLoad &
                internalIdToPublicBitfield( id ) ) switch( id )
            {
                case FR_ID_DOWNLOADED:
                    ret |= parseDownloaded( tor, buf, len ); break;

                case FR_ID_UPLOADED:
                    ret |= parseUploaded( tor, buf, len ); break;

                case FR_ID_PROGRESS:
                    ret |= parseProgress( tor, buf, len ); break;

                case FR_ID_PRIORITY:
                    ret |= parsePriorities( tor, buf, len ); break;

                case FR_ID_SPEED:
                    ret |= parseSpeedLimit( tor, buf, len ); break;

                case FR_ID_RUN:
                    ret |= parseRun( tor, buf, len ); break;

                case FR_ID_CORRUPT:
                    ret |= parseCorrupt( tor, buf, len ); break;

                case FR_ID_PEERS:
                    ret |= parsePeers( tor, buf, len ); break;

                case FR_ID_MAX_PEERS:
                    ret |= parseConnections( tor, buf, len ); break;

                case FR_ID_DOWNLOAD_DIR:
                    ret |= parseDownloadDir( tor, buf, len ); break;

                default:
                    tr_tordbg( tor, "Skipping unknown resume code %d",
                               (int)id ); break;
            }

        buf += len;
    }

    return ret;
}
コード例 #12
0
ファイル: resume.c プロジェクト: fangang190/canary
static uint64_t
loadFromFile( tr_torrent * tor,
              uint64_t     fieldsToLoad )
{
    int64_t      i;
    const char * str;
    uint64_t     fieldsLoaded = 0;
    char *       filename;
    tr_benc      top;

    filename = getResumeFilename( tor );

    if( tr_bencLoadFile( filename, &top ) )
    {
        tr_tordbg( tor, "Couldn't read \"%s\"; trying old format.",
                   filename );
        fieldsLoaded = tr_fastResumeLoad( tor, fieldsToLoad );

        if( ( fieldsLoaded != 0 ) && ( fieldsToLoad == ~(uint64_t)0 ) )
        {
            tr_torrentSaveResume( tor );
            tr_fastResumeRemove( tor );
            tr_tordbg( tor, "Migrated resume file to \"%s\"", filename );
        }

        tr_free( filename );
        return fieldsLoaded;
    }

    tr_tordbg( tor, "Read resume file \"%s\"", filename );

    if( ( fieldsToLoad & TR_FR_CORRUPT )
      && tr_bencDictFindInt( &top, KEY_CORRUPT, &i ) )
    {
        tor->corruptPrev = i;
        fieldsLoaded |= TR_FR_CORRUPT;
    }

    if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR ) )
      && tr_bencDictFindStr( &top, KEY_DOWNLOAD_DIR, &str ) )
    {
        tr_free( tor->downloadDir );
        tor->downloadDir = tr_strdup( str );
        fieldsLoaded |= TR_FR_DOWNLOAD_DIR;
    }

    if( ( fieldsToLoad & TR_FR_DOWNLOADED )
      && tr_bencDictFindInt( &top, KEY_DOWNLOADED, &i ) )
    {
        tor->downloadedPrev = i;
        fieldsLoaded |= TR_FR_DOWNLOADED;
    }

    if( ( fieldsToLoad & TR_FR_UPLOADED )
      && tr_bencDictFindInt( &top, KEY_UPLOADED, &i ) )
    {
        tor->uploadedPrev = i;
        fieldsLoaded |= TR_FR_UPLOADED;
    }

    if( ( fieldsToLoad & TR_FR_MAX_PEERS )
      && tr_bencDictFindInt( &top, KEY_MAX_PEERS, &i ) )
    {
        tor->maxConnectedPeers = i;
        fieldsLoaded |= TR_FR_MAX_PEERS;
    }

    if( ( fieldsToLoad & TR_FR_RUN )
      && tr_bencDictFindInt( &top, KEY_PAUSED, &i ) )
    {
        tor->isRunning = i ? 0 : 1;
        fieldsLoaded |= TR_FR_RUN;
    }

    if( ( fieldsToLoad & TR_FR_ADDED_DATE )
      && tr_bencDictFindInt( &top, KEY_ADDED_DATE, &i ) )
    {
        tor->addedDate = i;
        fieldsLoaded |= TR_FR_ADDED_DATE;
    }

    if( ( fieldsToLoad & TR_FR_DONE_DATE )
      && tr_bencDictFindInt( &top, KEY_DONE_DATE, &i ) )
    {
        tor->doneDate = i;
        fieldsLoaded |= TR_FR_DONE_DATE;
    }

    if( ( fieldsToLoad & TR_FR_ACTIVITY_DATE )
      && tr_bencDictFindInt( &top, KEY_ACTIVITY_DATE, &i ) )
    {
        tor->activityDate = i;
        fieldsLoaded |= TR_FR_ACTIVITY_DATE;
    }

    if( fieldsToLoad & TR_FR_PEERS )
        fieldsLoaded |= loadPeers( &top, tor );

    if( fieldsToLoad & TR_FR_PRIORITY )
        fieldsLoaded |= loadPriorities( &top, tor );

    if( fieldsToLoad & TR_FR_PROGRESS )
        fieldsLoaded |= loadProgress( &top, tor );

    if( fieldsToLoad & TR_FR_DND )
        fieldsLoaded |= loadDND( &top, tor );

    if( fieldsToLoad & TR_FR_SPEEDLIMIT )
        fieldsLoaded |= loadSpeedLimits( &top, tor );

    tr_bencFree( &top );
    tr_free( filename );
    return fieldsLoaded;
}
コード例 #13
0
ファイル: resume.c プロジェクト: fangang190/canary
static uint64_t
loadProgress( tr_benc *    dict,
              tr_torrent * tor )
{
    uint64_t  ret = 0;
    tr_benc * p;

    if( tr_bencDictFindDict( dict, KEY_PROGRESS, &p ) )
    {
        const uint8_t * raw;
        size_t          rawlen;
        tr_benc *       m;
        size_t          n;
        time_t *        curMTimes = tr_torrentGetMTimes( tor, &n );

        if( tr_bencDictFindList( p, KEY_PROGRESS_MTIMES, &m )
          && ( n == tor->info.fileCount )
          && ( n == tr_bencListSize( m ) ) )
        {
            size_t i;
            for( i = 0; i < n; ++i )
            {
                int64_t tmp;
                if( !tr_bencGetInt( tr_bencListChild( m, i ), &tmp ) )
                {
                    tr_tordbg(
                        tor,
                        "File #%zu needs to be verified - couldn't find benc entry",
                        i );
                    tr_torrentSetFileChecked( tor, i, FALSE );
                }
                else
                {
                    const time_t t = (time_t) tmp;
                    if( t == curMTimes[i] )
                        tr_torrentSetFileChecked( tor, i, TRUE );
                    else
                    {
                        tr_tordbg(
                            tor,
                            "File #%zu needs to be verified - times %lu and %lu don't match",
                            i, t, curMTimes[i] );
                        tr_torrentSetFileChecked( tor, i, FALSE );
                    }
                }
            }
        }
        else
        {
            tr_torrentUncheck( tor );
            tr_tordbg(
                tor, "Torrent needs to be verified - unable to find mtimes" );
        }

        if( tr_bencDictFindRaw( p, KEY_PROGRESS_BITFIELD, &raw, &rawlen ) )
        {
            tr_bitfield tmp;
            tmp.byteCount = rawlen;
            tmp.bitCount = tmp.byteCount * 8;
            tmp.bits = (uint8_t*) raw;
            if( !tr_cpBlockBitfieldSet( tor->completion, &tmp ) )
            {
                tr_torrentUncheck( tor );
                tr_tordbg(
                    tor,
                    "Torrent needs to be verified - error loading bitfield" );
            }
        }
        else
        {
            tr_torrentUncheck( tor );
            tr_tordbg(
                tor,
                "Torrent needs to be verified - unable to find bitfield" );
        }

        tr_free( curMTimes );
        ret = TR_FR_PROGRESS;
    }

    return ret;
}