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