2007-06-18 03:40:41 +00:00
|
|
|
/*
|
|
|
|
* This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
|
2006-07-16 19:39:23 +00:00
|
|
|
*
|
2007-06-18 03:40:41 +00:00
|
|
|
* This file is licensed by the GPL version 2. Works owned by the
|
|
|
|
* Transmission project are granted a special exemption to clause 2(b)
|
|
|
|
* so that the bulk of its code can remain under the MIT license.
|
|
|
|
* This exemption does not extend to derived works not owned by
|
|
|
|
* the Transmission project.
|
2007-08-18 17:19:49 +00:00
|
|
|
*
|
|
|
|
* $Id$
|
2007-06-18 03:40:41 +00:00
|
|
|
*/
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-07-29 18:11:21 +00:00
|
|
|
#include <assert.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2007-07-12 17:51:45 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
2007-07-29 18:11:21 +00:00
|
|
|
|
2006-07-16 19:39:23 +00:00
|
|
|
#include "transmission.h"
|
2007-07-30 18:04:10 +00:00
|
|
|
#include "completion.h"
|
2007-09-20 16:32:01 +00:00
|
|
|
#include "crypto.h"
|
|
|
|
#include "fastresume.h"
|
2007-07-09 20:10:42 +00:00
|
|
|
#include "fdlimit.h"
|
2007-07-30 18:04:10 +00:00
|
|
|
#include "inout.h"
|
2007-09-20 16:32:01 +00:00
|
|
|
#include "list.h"
|
2007-07-31 14:26:44 +00:00
|
|
|
#include "net.h"
|
2007-09-20 16:32:01 +00:00
|
|
|
#include "platform.h"
|
|
|
|
#include "peer-mgr.h"
|
2007-07-30 18:04:10 +00:00
|
|
|
#include "utils.h"
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-09-20 16:32:01 +00:00
|
|
|
struct tr_io
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-09-20 16:32:01 +00:00
|
|
|
tr_torrent * tor;
|
2006-07-16 19:39:23 +00:00
|
|
|
};
|
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
/****
|
|
|
|
***** Low-level IO functions
|
|
|
|
****/
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-09-09 01:32:59 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
#define lseek _lseeki64
|
|
|
|
#endif
|
|
|
|
|
2007-09-20 16:32:01 +00:00
|
|
|
enum { TR_IO_READ, TR_IO_WRITE };
|
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
static int
|
2007-09-20 16:32:01 +00:00
|
|
|
readOrWriteBytes ( const tr_torrent * tor,
|
2007-06-18 03:40:41 +00:00
|
|
|
int ioMode,
|
|
|
|
int fileIndex,
|
2007-06-18 19:39:52 +00:00
|
|
|
uint64_t fileOffset,
|
2007-06-18 03:40:41 +00:00
|
|
|
void * buf,
|
|
|
|
size_t buflen )
|
|
|
|
{
|
2007-09-20 16:32:01 +00:00
|
|
|
const tr_info * info = &tor->info;
|
|
|
|
const tr_file * file = &info->files[fileIndex];
|
2007-06-18 03:40:41 +00:00
|
|
|
typedef size_t (* iofunc) ( int, void *, size_t );
|
|
|
|
iofunc func = ioMode == TR_IO_READ ? (iofunc)read : (iofunc)write;
|
2007-07-24 01:33:59 +00:00
|
|
|
char path[MAX_PATH_LENGTH];
|
|
|
|
struct stat sb;
|
|
|
|
int fd = -1;
|
|
|
|
int ret;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
assert ( 0<=fileIndex && fileIndex<info->fileCount );
|
|
|
|
assert ( !file->length || (fileOffset < file->length));
|
|
|
|
assert ( fileOffset + buflen <= file->length );
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-07-24 01:33:59 +00:00
|
|
|
tr_buildPath ( path, sizeof(path), tor->destination, file->name, NULL );
|
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
if( !file->length )
|
|
|
|
return 0;
|
2007-07-24 01:33:59 +00:00
|
|
|
else if ((ioMode==TR_IO_READ) && stat( path, &sb ) ) /* fast check to make sure file exists */
|
|
|
|
ret = tr_ioErrorFromErrno ();
|
2007-07-06 17:19:34 +00:00
|
|
|
else if ((fd = tr_fdFileOpen ( tor->destination, file->name, ioMode==TR_IO_WRITE )) < 0)
|
2007-06-18 03:40:41 +00:00
|
|
|
ret = fd;
|
2007-06-18 19:39:52 +00:00
|
|
|
else if( lseek( fd, (off_t)fileOffset, SEEK_SET ) == ((off_t)-1) )
|
2007-06-18 03:40:41 +00:00
|
|
|
ret = TR_ERROR_IO_OTHER;
|
|
|
|
else if( func( fd, buf, buflen ) != buflen )
|
|
|
|
ret = tr_ioErrorFromErrno ();
|
|
|
|
else
|
|
|
|
ret = TR_OK;
|
|
|
|
|
|
|
|
if( fd >= 0 )
|
|
|
|
tr_fdFileRelease( fd );
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
return ret;
|
2007-05-02 19:35:34 +00:00
|
|
|
}
|
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
static void
|
2007-09-20 16:32:01 +00:00
|
|
|
findFileLocation ( const tr_torrent * tor,
|
2007-06-18 19:39:52 +00:00
|
|
|
int pieceIndex,
|
|
|
|
int pieceOffset,
|
|
|
|
int * fileIndex,
|
|
|
|
uint64_t * fileOffset )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-09-20 16:32:01 +00:00
|
|
|
const tr_info * info = &tor->info;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
int i;
|
|
|
|
uint64_t piecePos = ((uint64_t)pieceIndex * info->pieceSize) + pieceOffset;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
assert ( 0<=pieceIndex && pieceIndex < info->pieceCount );
|
2007-06-18 19:39:52 +00:00
|
|
|
assert ( 0<=tor->info.pieceSize );
|
2007-07-28 15:43:34 +00:00
|
|
|
assert ( pieceOffset < tr_torPieceCountBytes( tor, pieceIndex ) );
|
2007-06-18 03:40:41 +00:00
|
|
|
assert ( piecePos < info->totalSize );
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
for ( i=0; info->files[i].length<=piecePos; ++i )
|
|
|
|
piecePos -= info->files[i].length;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
*fileIndex = i;
|
|
|
|
*fileOffset = piecePos;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
assert ( 0<=*fileIndex && *fileIndex<info->fileCount );
|
|
|
|
assert ( *fileOffset < info->files[i].length );
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-09-25 23:21:00 +00:00
|
|
|
#ifdef WIN32
|
2007-06-18 03:40:41 +00:00
|
|
|
static int
|
2007-09-20 16:32:01 +00:00
|
|
|
ensureMinimumFileSize ( const tr_torrent * tor,
|
2007-06-18 03:40:41 +00:00
|
|
|
int fileIndex,
|
2007-06-18 19:39:52 +00:00
|
|
|
uint64_t minSize ) /* in bytes */
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-06-18 03:40:41 +00:00
|
|
|
int fd;
|
|
|
|
int ret;
|
|
|
|
struct stat sb;
|
2007-09-20 16:32:01 +00:00
|
|
|
const tr_file * file = &tor->info.files[fileIndex];
|
2007-06-18 03:40:41 +00:00
|
|
|
|
|
|
|
assert ( 0<=fileIndex && fileIndex<tor->info.fileCount );
|
|
|
|
assert ( minSize <= file->length );
|
|
|
|
|
|
|
|
fd = tr_fdFileOpen( tor->destination, file->name, TRUE );
|
|
|
|
if( fd < 0 ) /* bad fd */
|
|
|
|
ret = fd;
|
|
|
|
else if (fstat (fd, &sb) ) /* how big is the file? */
|
|
|
|
ret = tr_ioErrorFromErrno ();
|
2007-09-06 16:28:24 +00:00
|
|
|
else if (sb.st_size >= (off_t)minSize) /* already big enough */
|
2007-06-18 03:40:41 +00:00
|
|
|
ret = TR_OK;
|
|
|
|
else if (!ftruncate( fd, minSize )) /* grow it */
|
|
|
|
ret = TR_OK;
|
|
|
|
else /* couldn't grow it */
|
|
|
|
ret = tr_ioErrorFromErrno ();
|
|
|
|
|
|
|
|
if( fd >= 0 )
|
|
|
|
tr_fdFileRelease( fd );
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2007-09-25 23:21:00 +00:00
|
|
|
#endif
|
2007-05-27 23:32:26 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
static int
|
2007-09-20 16:32:01 +00:00
|
|
|
readOrWritePiece ( tr_torrent * tor,
|
|
|
|
int ioMode,
|
|
|
|
int pieceIndex,
|
|
|
|
int pieceOffset,
|
|
|
|
uint8_t * buf,
|
|
|
|
size_t buflen )
|
2007-06-18 03:40:41 +00:00
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int fileIndex;
|
2007-06-18 19:39:52 +00:00
|
|
|
uint64_t fileOffset;
|
2007-09-20 16:32:01 +00:00
|
|
|
const tr_info * info = &tor->info;
|
2007-05-27 23:32:26 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
assert( 0<=pieceIndex && pieceIndex<tor->info.pieceCount );
|
2007-07-28 15:43:34 +00:00
|
|
|
assert( buflen <= (size_t) tr_torPieceCountBytes( tor, pieceIndex ) );
|
2007-05-27 23:32:26 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
findFileLocation ( tor, pieceIndex, pieceOffset, &fileIndex, &fileOffset );
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
while( buflen && !ret )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-09-20 16:32:01 +00:00
|
|
|
const tr_file * file = &info->files[fileIndex];
|
2007-06-18 19:39:52 +00:00
|
|
|
const uint64_t bytesThisPass = MIN( buflen, file->length - fileOffset );
|
2007-06-18 03:40:41 +00:00
|
|
|
|
2007-09-25 23:21:00 +00:00
|
|
|
#ifdef WIN32
|
2007-06-18 03:40:41 +00:00
|
|
|
if( ioMode == TR_IO_WRITE )
|
|
|
|
ret = ensureMinimumFileSize( tor, fileIndex,
|
|
|
|
fileOffset + bytesThisPass );
|
|
|
|
if( !ret )
|
2007-09-25 23:21:00 +00:00
|
|
|
#endif
|
2007-06-18 03:40:41 +00:00
|
|
|
ret = readOrWriteBytes( tor, ioMode,
|
|
|
|
fileIndex, fileOffset, buf, bytesThisPass );
|
|
|
|
buf += bytesThisPass;
|
|
|
|
buflen -= bytesThisPass;
|
|
|
|
fileIndex++;
|
|
|
|
fileOffset = 0;
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
return ret;
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
int
|
2007-09-20 16:32:01 +00:00
|
|
|
tr_ioRead( tr_torrent * tor, int pieceIndex, int begin, int len, uint8_t * buf )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-09-20 16:32:01 +00:00
|
|
|
return readOrWritePiece ( tor, TR_IO_READ, pieceIndex, begin, buf, len );
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
int
|
2007-09-20 16:32:01 +00:00
|
|
|
tr_ioWrite( tr_torrent * tor, int pieceIndex, int begin, int len, uint8_t * buf )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-09-20 16:32:01 +00:00
|
|
|
return readOrWritePiece ( tor, TR_IO_WRITE, pieceIndex, begin, buf, len );
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
/****
|
|
|
|
*****
|
|
|
|
****/
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
static int
|
2007-09-20 16:32:01 +00:00
|
|
|
tr_ioRecalculateHash ( tr_torrent * tor,
|
2007-06-18 03:40:41 +00:00
|
|
|
int pieceIndex,
|
|
|
|
uint8_t * setme )
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
int ret;
|
2006-07-16 19:39:23 +00:00
|
|
|
uint8_t * buf;
|
2007-09-20 16:32:01 +00:00
|
|
|
const tr_info * info;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
assert( tor != NULL );
|
|
|
|
assert( setme != NULL );
|
|
|
|
assert( 0<=pieceIndex && pieceIndex<tor->info.pieceCount );
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
info = &tor->info;
|
2007-07-28 15:43:34 +00:00
|
|
|
n = tr_torPieceCountBytes( tor, pieceIndex );
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
buf = malloc( n );
|
|
|
|
ret = readOrWritePiece ( tor, TR_IO_READ, pieceIndex, 0, buf, n );
|
2007-09-20 16:32:01 +00:00
|
|
|
if( !ret )
|
|
|
|
tr_sha1( setme, buf, n, NULL );
|
2006-07-16 19:39:23 +00:00
|
|
|
free( buf );
|
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
return ret;
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
static int
|
2007-09-20 16:32:01 +00:00
|
|
|
checkPiece ( tr_torrent * tor, int pieceIndex )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-06-18 03:40:41 +00:00
|
|
|
uint8_t hash[SHA_DIGEST_LENGTH];
|
|
|
|
int ret = tr_ioRecalculateHash( tor, pieceIndex, hash )
|
|
|
|
|| memcmp( hash, tor->info.pieces[pieceIndex].hash, SHA_DIGEST_LENGTH );
|
|
|
|
tr_dbg ("torrent [%s] piece %d hash check: %s",
|
|
|
|
tor->info.name, pieceIndex, (ret?"FAILED":"OK"));
|
|
|
|
return ret;
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-09-20 16:32:01 +00:00
|
|
|
/**
|
|
|
|
***
|
|
|
|
**/
|
|
|
|
|
2007-07-23 03:00:20 +00:00
|
|
|
void
|
2007-09-20 16:32:01 +00:00
|
|
|
tr_ioClose( const tr_torrent * tor )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-09-20 16:32:01 +00:00
|
|
|
int i;
|
|
|
|
const tr_info * info = &tor->info;
|
|
|
|
|
|
|
|
for( i=0; i<info->fileCount; ++i )
|
|
|
|
tr_fdFileClose( tor->destination, info->files[i].name );
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
tr_ioHash( tr_torrent * tor, int pieceIndex )
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
const int success = !checkPiece( tor, pieceIndex );
|
|
|
|
|
|
|
|
if( success )
|
|
|
|
{
|
|
|
|
tr_dbg( "Piece %d hash OK", pieceIndex );
|
|
|
|
tr_cpPieceAdd( tor->completion, pieceIndex );
|
|
|
|
ret = TR_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tr_err( "Piece %d hash FAILED", pieceIndex );
|
|
|
|
tr_cpPieceRem( tor->completion, pieceIndex );
|
|
|
|
ret = TR_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
tr_peerMgrSetBlame( tor->handle->peerMgr, tor->info.hash, pieceIndex, success );
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
***
|
|
|
|
**/
|
|
|
|
|
|
|
|
struct recheck_node
|
|
|
|
{
|
|
|
|
tr_torrent * torrent;
|
|
|
|
tr_recheck_done_cb recheck_done_cb;
|
|
|
|
run_status_t status_when_done;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
fireCheckDone( tr_torrent * torrent,
|
|
|
|
tr_recheck_done_cb recheck_done_cb,
|
|
|
|
run_status_t status_when_done )
|
|
|
|
{
|
|
|
|
torrent->runStatus = status_when_done;
|
|
|
|
(*recheck_done_cb)( torrent );
|
|
|
|
}
|
|
|
|
|
|
|
|
struct recheck_node currentNode;
|
|
|
|
|
|
|
|
static tr_list * recheckList = NULL;
|
|
|
|
|
|
|
|
static tr_thread * recheckThread = NULL;
|
|
|
|
|
|
|
|
static int stopCurrent = FALSE;
|
2007-07-24 20:49:47 +00:00
|
|
|
|
2007-09-24 17:47:15 +00:00
|
|
|
static tr_lock* getRecheckLock( void )
|
|
|
|
{
|
|
|
|
static tr_lock * lock = NULL;
|
|
|
|
if( lock == NULL )
|
|
|
|
lock = tr_lockNew( );
|
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
|
2007-09-20 16:32:01 +00:00
|
|
|
static void
|
|
|
|
recheckThreadFunc( void * unused UNUSED )
|
|
|
|
{
|
|
|
|
for( ;; )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-07-23 03:00:20 +00:00
|
|
|
int i;
|
2007-09-20 16:32:01 +00:00
|
|
|
tr_torrent * tor;
|
2007-09-24 17:47:15 +00:00
|
|
|
struct recheck_node * node;
|
2007-09-20 16:32:01 +00:00
|
|
|
|
2007-09-24 17:47:15 +00:00
|
|
|
tr_lockLock( getRecheckLock( ) );
|
|
|
|
node = (struct recheck_node*) recheckList ? recheckList->data : NULL;
|
2007-09-20 16:32:01 +00:00
|
|
|
if( node == NULL )
|
|
|
|
break;
|
|
|
|
|
|
|
|
currentNode = *node;
|
|
|
|
tor = currentNode.torrent;
|
|
|
|
tr_list_remove_data( &recheckList, node );
|
|
|
|
tr_free( node );
|
2007-09-24 17:47:15 +00:00
|
|
|
tr_lockUnlock( getRecheckLock( ) );
|
2007-09-20 16:32:01 +00:00
|
|
|
|
|
|
|
if( tor->uncheckedPieces == NULL ) {
|
|
|
|
fireCheckDone( tor, currentNode.recheck_done_cb, currentNode.status_when_done );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
tor->runStatus = TR_RUN_CHECKING;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-07-24 00:09:23 +00:00
|
|
|
/* remove the unchecked pieces from completion... */
|
|
|
|
for( i=0; i<tor->info.pieceCount; ++i )
|
2007-07-24 01:33:59 +00:00
|
|
|
if( tr_bitfieldHas( tor->uncheckedPieces, i ) )
|
2007-07-24 00:09:23 +00:00
|
|
|
tr_cpPieceRem( tor->completion, i );
|
|
|
|
|
2007-07-23 03:00:20 +00:00
|
|
|
tr_inf( "Verifying some pieces of \"%s\"", tor->info.name );
|
2007-05-27 23:32:26 +00:00
|
|
|
|
2007-09-20 16:32:01 +00:00
|
|
|
for( i=0; i<tor->info.pieceCount && !stopCurrent; ++i )
|
2007-07-23 03:00:20 +00:00
|
|
|
{
|
2007-07-24 01:33:59 +00:00
|
|
|
if( !tr_bitfieldHas( tor->uncheckedPieces, i ) )
|
2007-07-23 03:00:20 +00:00
|
|
|
continue;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-07-23 03:00:20 +00:00
|
|
|
tr_torrentSetHasPiece( tor, i, !checkPiece( tor, i ) );
|
2007-07-24 01:33:59 +00:00
|
|
|
tr_bitfieldRem( tor->uncheckedPieces, i );
|
2007-07-23 03:00:20 +00:00
|
|
|
}
|
2007-06-26 18:45:03 +00:00
|
|
|
|
2007-09-20 16:32:01 +00:00
|
|
|
if( !stopCurrent )
|
|
|
|
{
|
|
|
|
tr_bitfieldFree( tor->uncheckedPieces );
|
|
|
|
tor->uncheckedPieces = NULL;
|
|
|
|
}
|
|
|
|
stopCurrent = FALSE;
|
|
|
|
tr_fastResumeSave( tor );
|
|
|
|
fireCheckDone( tor, currentNode.recheck_done_cb, currentNode.status_when_done );
|
2007-07-23 03:00:20 +00:00
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2007-09-20 16:32:01 +00:00
|
|
|
recheckThread = NULL;
|
2007-09-24 17:47:15 +00:00
|
|
|
tr_lockUnlock( getRecheckLock( ) );
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2007-06-18 03:40:41 +00:00
|
|
|
void
|
2007-09-20 16:32:01 +00:00
|
|
|
tr_ioRecheckAdd( tr_torrent * tor,
|
|
|
|
tr_recheck_done_cb recheck_done_cb,
|
|
|
|
run_status_t status_when_done )
|
2007-05-27 23:32:26 +00:00
|
|
|
{
|
2007-09-24 17:47:15 +00:00
|
|
|
struct recheck_node * node;
|
|
|
|
node = tr_new( struct recheck_node, 1 );
|
|
|
|
node->torrent = tor;
|
|
|
|
node->recheck_done_cb = recheck_done_cb;
|
|
|
|
node->status_when_done = status_when_done;
|
|
|
|
|
|
|
|
tr_lockLock( getRecheckLock( ) );
|
|
|
|
tr_list_append( &recheckList, node );
|
|
|
|
tor->runStatus = TR_RUN_CHECKING_WAIT;
|
2007-09-24 19:12:52 +00:00
|
|
|
if( recheckThread == NULL )
|
2007-09-24 17:47:15 +00:00
|
|
|
recheckThread = tr_threadNew( recheckThreadFunc, NULL, "recheckThreadFunc" );
|
|
|
|
tr_lockUnlock( getRecheckLock( ) );
|
2007-05-27 23:32:26 +00:00
|
|
|
}
|
|
|
|
|
2007-09-20 16:32:01 +00:00
|
|
|
static int
|
|
|
|
compareRecheckByTorrent( const void * va, const void * vb )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-09-20 16:32:01 +00:00
|
|
|
const struct recheck_node * a = ( const struct recheck_node * ) va;
|
|
|
|
const struct recheck_node * b = ( const struct recheck_node * ) vb;
|
|
|
|
return a->torrent - b->torrent;
|
2007-06-18 03:40:41 +00:00
|
|
|
}
|
2007-05-27 23:32:26 +00:00
|
|
|
|
2007-09-20 16:32:01 +00:00
|
|
|
void
|
|
|
|
tr_ioRecheckRemove( tr_torrent * tor )
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2007-09-20 16:32:01 +00:00
|
|
|
if( tor == currentNode.torrent )
|
|
|
|
stopCurrent = TRUE;
|
|
|
|
else {
|
|
|
|
struct recheck_node tmp;
|
|
|
|
tmp.torrent = tor;
|
|
|
|
struct recheck_node * node = tr_list_remove( &recheckList, &tmp, compareRecheckByTorrent );
|
|
|
|
if( node != NULL ) {
|
|
|
|
fireCheckDone( tor, node->recheck_done_cb, node->status_when_done );
|
|
|
|
tr_free( node );
|
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
}
|