the torrent ctor is here.

This commit is contained in:
Charles Kerr 2007-12-21 22:18:40 +00:00
parent 7a5369023e
commit 287975caf5
14 changed files with 424 additions and 389 deletions

View File

@ -254,7 +254,7 @@ torrent_cell_renderer_get_size( GtkCellRenderer * cell,
const tr_torrent * tor = self->priv->tor;
const tr_info * info = tr_torrentInfo( tor );
const char * name = info->name;
const tr_stat * torStat = tr_torrentStat( (tr_torrent*)tor );
const tr_stat * torStat = tr_torrentStatCached( (tr_torrent*)tor );
char * str;
int w=0, h=0;
struct TorrentCellRendererPrivate * p = self->priv;
@ -490,7 +490,7 @@ torrent_cell_renderer_render( GtkCellRenderer * cell,
const tr_torrent * tor = self->priv->tor;
const tr_info * info = tr_torrentInfo( tor );
const char * name = info->name;
const tr_stat * torStat = tr_torrentStat( (tr_torrent*)tor );
const tr_stat * torStat = tr_torrentStatCached( (tr_torrent*)tor );
GdkRectangle my_bg;
GdkRectangle my_cell;
GdkRectangle my_expose;

View File

@ -191,8 +191,8 @@ compareByActivity( GtkTreeModel * model,
gtk_tree_model_get( model, a, MC_TORRENT_RAW, &ta, -1 );
gtk_tree_model_get( model, b, MC_TORRENT_RAW, &tb, -1 );
sa = tr_torrentStat( ta );
sb = tr_torrentStat( tb );
sa = tr_torrentStatCached( ta );
sb = tr_torrentStatCached( tb );
if(( i = compareDouble( sa->rateUpload + sa->rateDownload,
sb->rateUpload + sb->rateDownload ) ))
@ -240,8 +240,8 @@ compareByProgress( GtkTreeModel * model,
const tr_stat *sa, *sb;
gtk_tree_model_get( model, a, MC_TORRENT_RAW, &ta, -1 );
gtk_tree_model_get( model, b, MC_TORRENT_RAW, &tb, -1 );
sa = tr_torrentStat( ta );
sb = tr_torrentStat( tb );
sa = tr_torrentStatCached( ta );
sb = tr_torrentStatCached( tb );
ret = compareDouble( sa->percentDone, sb->percentDone );
if( !ret )
ret = compareDouble( sa->ratio, sa->ratio );
@ -257,7 +257,7 @@ compareByState( GtkTreeModel * model,
tr_torrent *ta, *tb;
gtk_tree_model_get( model, a, MC_TORRENT_RAW, &ta, -1 );
gtk_tree_model_get( model, b, MC_TORRENT_RAW, &tb, -1 );
return tr_torrentStat(ta)->status - tr_torrentStat(tb)->status;
return tr_torrentStatCached(ta)->status - tr_torrentStatCached(tb)->status;
}
static int
@ -453,17 +453,24 @@ tr_core_load( TrCore * self, gboolean paused )
int count = 0;
tr_torrent ** torrents;
char * path;
tr_ctor * ctor;
TR_IS_CORE( self );
path = getdownloaddir( );
torrents = tr_loadTorrents ( self->handle, path, paused, &count );
ctor = tr_ctorNew( self->handle );
tr_ctorSetPaused( ctor, TR_FORCE, paused );
tr_ctorSetDestination( ctor, TR_FALLBACK, path );
torrents = tr_loadTorrents ( self->handle, ctor, &count );
for( i=0; i<count; ++i )
tr_core_insert( self, tr_torrent_new_preexisting( torrents[i] ) );
tr_free( torrents );
tr_free( torrents );
tr_ctorFree( ctor );
g_free( path );
return count;
}

View File

@ -129,7 +129,7 @@ tr_torrent_handle(TrTorrent *tor)
const tr_stat *
tr_torrent_stat(TrTorrent *tor)
{
return tor && !tor->severed ? tr_torrentStat( tor->handle ) : NULL;
return tor && !tor->severed ? tr_torrentStatCached( tor->handle ) : NULL;
}
const tr_info *

View File

@ -199,9 +199,6 @@ int _tr_bencLoad( char * buf, int len, benc_val_t * val, char ** end )
}
}
val->begin = buf;
val->end = *end;
return 0;
}

View File

@ -30,8 +30,6 @@
typedef struct benc_val_s
{
char * begin;
char * end;
#define TYPE_INT 1
#define TYPE_STR 2
#define TYPE_LIST 4

View File

@ -545,22 +545,23 @@ parsePeers( tr_torrent * tor, const uint8_t * buf, uint32_t len )
}
static uint64_t
parseDestination( tr_torrent * tor, const uint8_t * buf, uint32_t len,
const char * destination, int argIsFallback )
parseDestination( tr_torrent * tor, const uint8_t * buf, uint32_t len )
{
if( argIsFallback )
tor->destination = tr_strdup( len ? (const char*)buf : destination );
else
tor->destination = tr_strdup( len ? destination : (const char*)buf );
uint64_t ret = 0;
return TR_FR_DESTINATION;
if( buf && *buf && len ) {
tr_free( tor->destination );
tor->destination = tr_strndup( (char*)buf, len );
ret = TR_FR_DESTINATION;
}
return ret;
}
static uint64_t
parseVersion1( tr_torrent * tor, const uint8_t * buf, const uint8_t * end,
uint64_t fieldsToLoad,
tr_bitfield * uncheckedPieces,
const char * destination, int argIsFallback )
tr_bitfield * uncheckedPieces )
{
uint64_t ret = 0;
@ -582,7 +583,7 @@ parseVersion1( tr_torrent * tor, const uint8_t * buf, const uint8_t * end,
case FR_ID_CORRUPT: ret |= parseCorrupt( tor, buf, len ); break;
case FR_ID_PEERS: ret |= parsePeers( tor, buf, len ); break;
case FR_ID_PEX: ret |= parsePex( tor, buf, len ); break;
case FR_ID_DESTINATION: ret |= parseDestination( tor, buf, len, destination, argIsFallback ); break;
case FR_ID_DESTINATION: ret |= parseDestination( tor, buf, len ); break;
default: tr_dbg( "Skipping unknown resume code %d", (int)id ); break;
}
@ -620,9 +621,7 @@ loadResumeFile( const tr_torrent * tor, size_t * len )
static uint64_t
fastResumeLoadImpl ( tr_torrent * tor,
uint64_t fieldsToLoad,
tr_bitfield * uncheckedPieces,
const char * destination,
int argIsFallback )
tr_bitfield * uncheckedPieces )
{
uint64_t ret = 0;
size_t size = 0;
@ -637,7 +636,7 @@ fastResumeLoadImpl ( tr_torrent * tor,
uint32_t version;
readBytes( &version, &walk, sizeof(version) );
if( version == 1 )
ret |= parseVersion1 ( tor, walk, end, fieldsToLoad, uncheckedPieces, destination, argIsFallback );
ret |= parseVersion1 ( tor, walk, end, fieldsToLoad, uncheckedPieces );
else
tr_inf( "Unsupported resume file %d for '%s'", version, tor->info.name );
}
@ -648,20 +647,56 @@ fastResumeLoadImpl ( tr_torrent * tor,
return ret;
}
uint64_t
tr_fastResumeLoad( tr_torrent * tor,
uint64_t fieldsToLoad,
tr_bitfield * uncheckedPieces,
const char * destination,
int argIsFallback )
static uint64_t
setFromCtor( tr_torrent * tor, uint64_t fields, const tr_ctor * ctor, int mode )
{
const uint64_t ret = fastResumeLoadImpl( tor, fieldsToLoad, uncheckedPieces, destination, argIsFallback );
uint64_t ret = 0;
if( ! ( ret & TR_FR_PROGRESS ) )
tr_bitfieldAddRange( uncheckedPieces, 0, tor->info.pieceCount );
if( fields & TR_FR_MAX_UNCHOKED )
if( !tr_ctorGetMaxUnchokedPeers( ctor, mode, &tor->maxUnchokedPeers ) )
ret |= TR_FR_MAX_UNCHOKED;
if( !tor->destination )
tor->destination = tr_strdup( destination );
if( fields & TR_FR_MAX_PEERS )
if( !tr_ctorGetMaxConnectedPeers( ctor, mode, &tor->maxConnectedPeers ) )
ret |= TR_FR_MAX_PEERS;
if( fields & TR_FR_DESTINATION ) {
const char * destination;
if( !tr_ctorGetDestination( ctor, mode, &destination ) ) {
ret |= TR_FR_DESTINATION;
tr_free( tor->destination );
tor->destination = tr_strdup( destination );
}
}
return ret;
}
static uint64_t
useManditoryFields( tr_torrent * tor, uint64_t fields, const tr_ctor * ctor )
{
return setFromCtor( tor, fields, ctor, TR_FORCE );
}
static uint64_t
useFallbackFields( tr_torrent * tor, uint64_t fields, const tr_ctor * ctor )
{
return setFromCtor( tor, fields, ctor, TR_FALLBACK );
}
uint64_t
tr_fastResumeLoad( tr_torrent * tor,
uint64_t fieldsToLoad,
tr_bitfield * uncheckedPieces,
const tr_ctor * ctor )
{
uint64_t ret = 0;
ret |= useManditoryFields( tor, fieldsToLoad, ctor );
fieldsToLoad &= ~ret;
ret |= fastResumeLoadImpl( tor, fieldsToLoad, uncheckedPieces );
fieldsToLoad &= ~ret;
ret |= useFallbackFields( tor, fieldsToLoad, ctor );
return ret;
}

View File

@ -38,7 +38,9 @@ enum
TR_FR_SPEEDLIMIT = (1<<6),
TR_FR_RUN = (1<<7),
TR_FR_DESTINATION = (1<<8),
TR_FR_PEX = (1<<9)
TR_FR_PEX = (1<<9),
TR_FR_MAX_PEERS = (1<<10),
TR_FR_MAX_UNCHOKED = (1<<11),
};
/**
@ -47,7 +49,6 @@ enum
uint64_t tr_fastResumeLoad( tr_torrent * tor,
uint64_t fieldsToLoad,
struct tr_bitfield * uncheckedPieces,
const char * destination,
int destinationIsFallback );
const tr_ctor * ctor );
#endif

View File

@ -160,8 +160,8 @@ struct tr_torrent
unsigned int statCur : 1;
unsigned int isRunning : 1;
uint8_t maxUnchokedPeers;
uint16_t maxConnectedPeers;
uint16_t maxUnchokedPeers;
tr_recheck_state recheckState;

View File

@ -68,6 +68,7 @@ tr_httpParseUrl( const char * url_in, int len,
* Local prototypes
**********************************************************************/
static int realparse( tr_info * inf, const uint8_t * buf, size_t len );
static int realparse2( tr_info * inf, const benc_val_t * meta );
static void savedname( char * name, size_t len, const char * hash,
const char * tag );
static uint8_t * readtorrent( const char * path, size_t * len );
@ -221,6 +222,26 @@ tr_metainfoParseData( tr_info * inf, const char * tag,
return TR_OK;
}
int
tr_metainfoParseBenc( tr_info * inf, const char * tag, const benc_val_t * val, int save )
{
int err = 0;
if( !err && realparse2( inf, val ) )
err = TR_EINVALID;
if( !err && save ) {
int len;
uint8_t * text = (uint8_t *) tr_bencSave( val, &len );
err = savetorrent( inf->hashString, tag, text, len );
tr_free( text );
if( !err )
savedname( inf->torrent, sizeof( inf->torrent ), inf->hashString, tag );
}
return err;
}
int
tr_metainfoParseHash( tr_info * inf, const char * tag, const char * hash )
{
@ -273,26 +294,44 @@ tr_metainfoParseHash( tr_info * inf, const char * tag, const char * hash )
static int
realparse( tr_info * inf, const uint8_t * buf, size_t size )
{
benc_val_t meta, * beInfo, * val, * val2;
int i;
int err = 0;
benc_val_t meta;
/* Parse bencoded infos */
if( tr_bencLoad( buf, size, &meta, NULL ) )
{
if( !err && tr_bencLoad( buf, size, &meta, NULL ) ) {
err = TR_EINVALID;
tr_err( "Error while parsing bencoded data [%*.*s]", (int)size, (int)size, (char*)buf );
return TR_EINVALID;
}
/* Get info hash */
beInfo = tr_bencDictFind( &meta, "info" );
if( NULL == beInfo || TYPE_DICT != beInfo->type )
{
tr_err( "%s \"info\" dictionary", ( beInfo ? "Invalid" : "Missing" ) );
if( !err ) {
err = realparse2( inf, &meta );
tr_bencFree( &meta );
return TR_EINVALID;
}
tr_sha1( inf->hash, beInfo->begin, beInfo->end - beInfo->begin, NULL );
return err;
}
static int
realparse2( tr_info * inf, const benc_val_t * meta_in )
{
int i;
benc_val_t * beInfo, * val, * val2;
benc_val_t * meta = (benc_val_t *) meta_in;
/* info_hash: urlencoded 20-byte SHA1 hash of the value of the info key
* from the Metainfo file. Note that the value will be a bencoded
* dictionary, given the definition of the info key above. */
if(( beInfo = tr_bencDictFindType( meta, "info", TYPE_DICT )))
{
int len;
char * str = tr_bencSave( beInfo, &len );
tr_sha1( inf->hash, str, len, NULL );
tr_free( str );
}
else
{
tr_err( "info dictionary not found!" );
return TR_EINVALID;
}
for( i = 0; i < SHA_DIGEST_LENGTH; i++ )
{
@ -301,14 +340,14 @@ realparse( tr_info * inf, const uint8_t * buf, size_t size )
}
/* Comment info */
val = tr_bencDictFindFirst( &meta, "comment.utf-8", "comment", NULL );
val = tr_bencDictFindFirst( meta, "comment.utf-8", "comment", NULL );
if( NULL != val && TYPE_STR == val->type )
{
strlcat_utf8( inf->comment, val->val.s.s, sizeof( inf->comment ), 0 );
}
/* Creator info */
val = tr_bencDictFindFirst( &meta, "created by.utf-8", "created by", NULL );
val = tr_bencDictFindFirst( meta, "created by.utf-8", "created by", NULL );
if( NULL != val && TYPE_STR == val->type )
{
strlcat_utf8( inf->creator, val->val.s.s, sizeof( inf->creator ), 0 );
@ -316,7 +355,7 @@ realparse( tr_info * inf, const uint8_t * buf, size_t size )
/* Date created */
inf->dateCreated = 0;
val = tr_bencDictFind( &meta, "creation date" );
val = tr_bencDictFind( meta, "creation date" );
if( NULL != val && TYPE_INT == val->type )
{
inf->dateCreated = val->val.i;
@ -324,7 +363,7 @@ realparse( tr_info * inf, const uint8_t * buf, size_t size )
/* Private torrent */
val = tr_bencDictFind( beInfo, "private" );
val2 = tr_bencDictFind( &meta, "private" );
val2 = tr_bencDictFind( meta, "private" );
if( ( NULL != val && ( TYPE_INT != val->type || 0 != val->val.i ) ) ||
( NULL != val2 && ( TYPE_INT != val2->type || 0 != val2->val.i ) ) )
{
@ -393,17 +432,15 @@ realparse( tr_info * inf, const uint8_t * buf, size_t size )
}
/* get announce or announce-list */
if( getannounce( inf, &meta ) )
if( getannounce( inf, meta ) )
{
goto fail;
}
tr_bencFree( &meta );
return TR_OK;
fail:
tr_metainfoFree( inf );
tr_bencFree( &meta );
return TR_EINVALID;
}

View File

@ -27,11 +27,14 @@
#include "transmission.h"
struct benc_val_t;
int tr_metainfoParseFile( tr_info *, const char * tag,
const char * path, int save );
int tr_metainfoParseData( tr_info *, const char * tag,
const uint8_t * data, size_t size, int save );
int tr_metainfoParseHash( tr_info *, const char * tag, const char * hash );
int tr_metainfoParseBenc( tr_info *, const char * tag, const struct benc_val_s *, int save );
void tr_metainfoFree( tr_info * inf );
void tr_metainfoRemoveSaved( const char * hashString, const char * tag );

View File

@ -16,6 +16,9 @@
#include "trcompat.h" /* strlcpy */
#include "utils.h"
#define DEFAULT_MAX_UNCHOKED_PEERS 16
#define DEFAULT_MAX_CONNECTED_PEERS 50
struct optional_args
{
unsigned int isSet_paused : 1;
@ -31,74 +34,61 @@ struct optional_args
struct tr_ctor
{
tr_handle * handle;
const tr_handle * handle;
unsigned int isSet_metadata : 1;
benc_val_t metadata;
unsigned int isSet_metainfo : 1;
benc_val_t metainfo;
struct optional_args optionalArgs[2];
};
tr_ctor*
tr_ctorNew( tr_handle * handle )
{
tr_ctor * ctor = tr_new0( struct tr_ctor, 1 );
ctor->handle = handle;
tr_ctorSetMaxConnectedPeers( ctor, TR_FALLBACK, 50 );
tr_ctorSetMaxUnchokedPeers( ctor, TR_FALLBACK, 16 );
tr_ctorSetPaused( ctor, TR_FALLBACK, FALSE );
return ctor;
}
void
tr_ctorFree( tr_ctor * ctor )
{
tr_free( ctor );
}
/***
****
***/
static void
clearMetadata( tr_ctor * ctor )
clearMetainfo( tr_ctor * ctor )
{
if( ctor->isSet_metadata ) {
ctor->isSet_metadata = 0;
tr_bencFree( &ctor->metadata );
if( ctor->isSet_metainfo ) {
ctor->isSet_metainfo = 0;
tr_bencFree( &ctor->metainfo );
}
}
int
tr_ctorSetMetadata( tr_ctor * ctor,
const uint8_t * metadata,
tr_ctorSetMetainfo( tr_ctor * ctor,
const uint8_t * metainfo,
size_t len )
{
int err;
clearMetadata( ctor );
err = tr_bencLoad( metadata, len, &ctor->metadata, NULL );
ctor->isSet_metadata = !err;
clearMetainfo( ctor );
err = tr_bencLoad( metainfo, len, &ctor->metainfo, NULL );
ctor->isSet_metainfo = !err;
return err;
}
int
tr_ctorSetMetadataFromFile( tr_ctor * ctor,
tr_ctorSetMetainfoFromFile( tr_ctor * ctor,
const char * filename )
{
uint8_t * metadata;
uint8_t * metainfo;
size_t len;
int err;
metadata = tr_loadFile( filename, &len );
if( metadata && len )
err = tr_ctorSetMetadata( ctor, metadata, len );
metainfo = tr_loadFile( filename, &len );
if( metainfo && len )
err = tr_ctorSetMetainfo( ctor, metainfo, len );
else {
clearMetadata( ctor );
clearMetainfo( ctor );
err = 1;
}
tr_free( metadata );
tr_free( metainfo );
return err;
}
int
tr_ctorSetMetadataFromHash( tr_ctor * ctor,
tr_ctorSetMetainfoFromHash( tr_ctor * ctor,
const char * hashString )
{
int err = -1;
@ -108,12 +98,14 @@ tr_ctorSetMetadataFromHash( tr_ctor * ctor,
if( err && ( ctor->handle->tag != NULL ) ) {
snprintf( basename, sizeof(basename), "%s-%s", hashString, ctor->handle->tag );
tr_buildPath( filename, sizeof(filename), tr_getTorrentsDirectory(), basename );
err = tr_ctorSetMetadataFromFile( ctor, filename );
err = tr_ctorSetMetainfoFromFile( ctor, filename );
fprintf( stderr, "trying [%s] returned %d\n", filename, err );
}
if( err ) {
tr_buildPath( filename, sizeof(filename), tr_getTorrentsDirectory(), hashString );
err = tr_ctorSetMetadataFromFile( ctor, filename );
err = tr_ctorSetMetainfoFromFile( ctor, filename );
fprintf( stderr, "trying [%s] returned %d\n", filename, err );
}
return err;
@ -126,11 +118,11 @@ tr_ctorSetMetadataFromHash( tr_ctor * ctor,
void
tr_ctorSetPaused( tr_ctor * ctor,
tr_ctorMode mode,
int isPaused )
uint8_t isPaused )
{
struct optional_args * args = &ctor->optionalArgs[mode];
args->isSet_paused = 1;
args->isPaused = isPaused;
args->isPaused = isPaused ? 1 : 0;
}
void
@ -168,11 +160,15 @@ tr_ctorGetMaxConnectedPeers( const tr_ctor * ctor,
tr_ctorMode mode,
uint16_t * setmeCount )
{
int err = 0;
const struct optional_args * args = &ctor->optionalArgs[mode];
const int isSet = args->isSet_connected;
if( isSet )
if( args->isSet_connected )
*setmeCount = args->maxConnectedPeers;
return isSet;
else
err = 1;
return err;
}
int
@ -180,23 +176,31 @@ tr_ctorGetMaxUnchokedPeers( const tr_ctor * ctor,
tr_ctorMode mode,
uint8_t * setmeCount )
{
int err = 0;
const struct optional_args * args = &ctor->optionalArgs[mode];
const int isSet = args->isSet_unchoked;
if( isSet )
if( args->isSet_unchoked )
*setmeCount = args->maxUnchokedPeers;
return isSet;
else
err = 1;
return err;
}
int
tr_ctorGetIsPaused( const tr_ctor * ctor,
tr_ctorMode mode,
int * setmeIsPaused )
uint8_t * setmeIsPaused )
{
int err = 0;
const struct optional_args * args = &ctor->optionalArgs[mode];
const int isSet = args->isSet_paused;
if( isSet )
*setmeIsPaused = args->isPaused;
return isSet;
if( args->isSet_paused )
*setmeIsPaused = args->isPaused ? 1 : 0;
else
err = 1;
return err;
}
int
@ -204,19 +208,49 @@ tr_ctorGetDestination( const tr_ctor * ctor,
tr_ctorMode mode,
const char ** setmeDestination )
{
int err = 0;
const struct optional_args * args = &ctor->optionalArgs[mode];
const int isSet = args->isSet_destination;
if( isSet )
if( args->isSet_destination )
*setmeDestination = args->destination;
return isSet;
else
err = 1;
return err;
}
int
tr_ctorGetMetadata( const tr_ctor * ctor,
tr_ctorGetMetainfo( const tr_ctor * ctor,
const struct benc_val_s ** setme )
{
const int isSet = ctor->isSet_metadata;
if( isSet )
*setme = &ctor->metadata;
return isSet;
int err = 0;
if( ctor->isSet_metainfo )
*setme = &ctor->metainfo;
else
err = 1;
return err;
}
/***
****
***/
tr_ctor*
tr_ctorNew( const tr_handle * handle )
{
tr_ctor * ctor = tr_new0( struct tr_ctor, 1 );
ctor->handle = handle;
tr_ctorSetMaxConnectedPeers( ctor, TR_FALLBACK, DEFAULT_MAX_CONNECTED_PEERS );
tr_ctorSetMaxUnchokedPeers( ctor, TR_FALLBACK, DEFAULT_MAX_UNCHOKED_PEERS );
tr_ctorSetPaused( ctor, TR_FALLBACK, FALSE );
return ctor;
}
void
tr_ctorFree( tr_ctor * ctor )
{
clearMetainfo( ctor );
tr_free( ctor );
}

View File

@ -30,6 +30,7 @@
#include <sys/types.h>
#include "transmission.h"
#include "bencode.h"
#include "completion.h"
#include "crypto.h" /* for tr_sha1 */
#include "fastresume.h"
@ -47,9 +48,6 @@
#include "trevent.h"
#include "utils.h"
#define DEFAULT_MAX_CONNECTED_PEERS 50
#define DEFAULT_MAX_UNCHOKED_PEERS 16
/***
****
***/
@ -259,11 +257,12 @@ tr_torrentInitFilePieces( tr_torrent * tor )
}
static void
torrentRealInit( tr_handle * h,
tr_torrent * tor,
const char * destination,
int destinationIsFallback,
int isPaused )
torrentRealInit( tr_handle * h,
tr_torrent * tor,
const tr_ctor * ctor )
//const char * destination,
//int destinationIsFallback,
//int isPaused )
{
int doStart;
uint64_t loaded;
@ -275,8 +274,6 @@ torrentRealInit( tr_handle * h,
tor->handle = h;
tor->pexDisabled = 0;
tor->maxConnectedPeers = DEFAULT_MAX_CONNECTED_PEERS;
tor->maxUnchokedPeers = DEFAULT_MAX_UNCHOKED_PEERS;
/**
* Decide on a block size. constraints:
@ -345,18 +342,11 @@ torrentRealInit( tr_handle * h,
uncheckedPieces = tr_bitfieldNew( tor->info.pieceCount );
loaded = tr_fastResumeLoad( tor, ~0, uncheckedPieces, destination, destinationIsFallback );
loaded = tr_fastResumeLoad( tor, ~0, uncheckedPieces, ctor );
assert( tor->destination != NULL );
/* the `paused' flag has highest precedence...
after that, the fastresume setting is used...
if that's not found, default to RUNNING */
if( isPaused )
doStart = 0;
else if( loaded & TR_FR_RUN )
doStart = tor->isRunning;
else
doStart = 1;
doStart = tor->isRunning;
tor->isRunning = 0;
if( tr_bitfieldIsEmpty( uncheckedPieces ) )
@ -364,7 +354,6 @@ torrentRealInit( tr_handle * h,
else
tor->uncheckedPieces = uncheckedPieces;
if( !(loaded & TR_FR_SPEEDLIMIT ) ) {
int limit, enabled;
tr_getGlobalSpeedLimit( tor->handle, TR_UP, &enabled, &limit );
@ -388,21 +377,6 @@ torrentRealInit( tr_handle * h,
tr_torrentStart( tor );
}
static int
pathIsInUse ( const tr_handle * h,
const char * destination,
const char * name )
{
const tr_torrent * tor;
for( tor=h->torrentList; tor; tor=tor->next )
if( !strcmp( destination, tor->destination )
&& !strcmp( name, tor->info.name ) )
return TRUE;
return FALSE;
}
static int
hashExists( const tr_handle * h,
const uint8_t * hash )
@ -416,202 +390,147 @@ hashExists( const tr_handle * h,
return FALSE;
}
static int
infoCanAdd( const tr_handle * h,
const char * destination,
const tr_info * info )
{
if( hashExists( h, info->hash ) )
return TR_EDUPLICATE;
if( destination && pathIsInUse( h, destination, info->name ) )
return TR_EDUPLICATE;
return TR_OK;
}
int
tr_torrentParse( const tr_handle * h,
const char * path,
const char * destination,
tr_info * setme_info )
tr_torrentParseFromCtor( const tr_handle * handle,
const tr_ctor * ctor,
tr_info * setmeInfo )
{
int ret, doFree;
int err = 0;
int doFree;
tr_info tmp;
const benc_val_t * metainfo;
if( setme_info == NULL )
setme_info = &tmp;
if( setmeInfo == NULL )
setmeInfo = &tmp;
memset( setmeInfo, 0, sizeof( tr_info ) );
memset( setme_info, 0, sizeof( tr_info ) );
ret = tr_metainfoParseFile( setme_info, h->tag, path, FALSE );
doFree = !ret && (setme_info == &tmp);
if( !err && tr_ctorGetMetainfo( ctor, &metainfo ) )
return TR_EINVALID;
if( ret == TR_OK )
ret = infoCanAdd( h, destination, setme_info );
err = tr_metainfoParseBenc( setmeInfo, handle->tag, metainfo, FALSE );
doFree = !err && ( setmeInfo == &tmp );
if( !err && hashExists( handle, setmeInfo->hash ) )
err = TR_EDUPLICATE;
if( doFree )
tr_metainfoFree( &tmp );
tr_metainfoFree( setmeInfo );
return ret;
return err;
}
static tr_torrent *
tr_torrentInitImpl( tr_handle * h,
const char * path,
const char * destination,
int destinationIsFallback,
int isPaused,
int * error )
tr_torrent *
tr_torrentNew( tr_handle * handle,
const tr_ctor * ctor,
int * setmeError )
{
int val;
int tmpError;
int err;
tr_info tmpInfo;
tr_torrent * tor = NULL;
if( !error )
error = &tmpError;
if(( val = tr_torrentParse( h, path, destination, NULL )))
*error = val;
else if(!(( tor = tr_new0( tr_torrent, 1 ))))
*error = TR_EOTHER;
else {
tr_metainfoParseFile( &tor->info, h->tag, path, TRUE );
torrentRealInit( h, tor, destination, destinationIsFallback, isPaused );
err = tr_torrentParseFromCtor( handle, ctor, &tmpInfo );
if( !err ) {
tor = tr_new0( tr_torrent, 1 );
tor->info = tmpInfo;
torrentRealInit( handle, tor, ctor );
} else if( setmeError ) {
*setmeError = err;
}
return tor;
}
/***
****
***/
/** @deprecated */
int
tr_torrentParse( const tr_handle * h,
const char * path,
const char * destination,
tr_info * setmeInfo )
{
int err;
tr_ctor * ctor = tr_ctorNew( h );
tr_ctorSetMetainfoFromFile( ctor, path );
tr_ctorSetDestination( ctor, TR_FORCE, destination );
err = tr_torrentParseFromCtor( h, ctor, setmeInfo );
tr_ctorFree( ctor );
return err;
}
/** @deprecated */
tr_torrent *
tr_torrentInit( tr_handle * h,
const char * path,
const char * destination,
int isPaused,
int * error )
int * setmeError )
{
return tr_torrentInitImpl( h, path, destination, FALSE, isPaused, error );
}
tr_torrent *
tr_torrentLoad( tr_handle * h,
const char * metainfoFilename,
const char * destination,
int isPaused,
int * error )
{
return tr_torrentInitImpl( h, metainfoFilename, destination, TRUE, isPaused, error );
tr_torrent * tor;
tr_ctor * ctor = tr_ctorNew( h );
tr_ctorSetMetainfoFromFile( ctor, path );
tr_ctorSetDestination( ctor, TR_FORCE, destination );
tr_ctorSetPaused( ctor, TR_FORCE, isPaused );
tor = tr_torrentNew( h, ctor, setmeError );
tr_ctorFree( ctor );
return tor;
}
/** @deprecated */
int
tr_torrentParseHash( const tr_handle * h,
const char * hashStr,
const char * destination,
tr_info * setme_info )
tr_info * setmeInfo )
{
int ret, doFree;
tr_info tmp;
if( setme_info == NULL )
setme_info = &tmp;
memset( setme_info, 0, sizeof( tr_info ) );
ret = tr_metainfoParseHash( setme_info, h->tag, hashStr );
doFree = !ret && (setme_info == &tmp);
if( ret == TR_OK )
ret = infoCanAdd( h, destination, setme_info );
if( doFree )
tr_metainfoFree( &tmp );
return ret;
int err;
tr_ctor * ctor = tr_ctorNew( h );
tr_ctorSetMetainfoFromHash( ctor, hashStr );
tr_ctorSetDestination( ctor, TR_FORCE, destination );
err = tr_torrentParseFromCtor( h, ctor, setmeInfo );
tr_ctorFree( ctor );
return err;
}
/** @deprecated */
tr_torrent *
tr_torrentInitSaved( tr_handle * h,
const char * hashStr,
const char * destination,
int isPaused,
int * error )
int * setmeError )
{
int val;
int tmpError;
tr_torrent * tor = NULL;
if( !error )
error = &tmpError;
if(( val = tr_torrentParseHash( h, hashStr, destination, NULL )))
*error = val;
else if(!(( tor = tr_new0( tr_torrent, 1 ))))
*error = TR_EOTHER;
else {
tr_metainfoParseHash( &tor->info, h->tag, hashStr );
torrentRealInit( h, tor, destination, FALSE, isPaused );
}
tr_torrent * tor;
tr_ctor * ctor = tr_ctorNew( h );
tr_ctorSetMetainfoFromHash( ctor, hashStr );
tr_ctorSetDestination( ctor, TR_FORCE, destination );
tr_ctorSetPaused( ctor, TR_FORCE, isPaused );
tor = tr_torrentNew( h, ctor, setmeError );
tr_ctorFree( ctor );
return tor;
}
static int
tr_torrentParseData( const tr_handle * h,
const uint8_t * data,
size_t size,
const char * destination,
tr_info * setme_info )
{
int ret, doFree;
tr_info tmp;
if( setme_info == NULL )
setme_info = &tmp;
memset( setme_info, 0, sizeof( tr_info ) );
ret = tr_metainfoParseData( setme_info, h->tag, data, size, FALSE );
doFree = !ret && (setme_info == &tmp);
if( ret == TR_OK )
ret = infoCanAdd( h, destination, setme_info );
if( doFree )
tr_metainfoFree( &tmp );
return ret;
}
/** @deprecated */
tr_torrent *
tr_torrentInitData( tr_handle * h,
const uint8_t * data,
size_t size,
const uint8_t * metainfo,
size_t len,
const char * destination,
int isPaused,
int * error )
int * setmeError )
{
int val;
int tmpError;
tr_torrent * tor = NULL;
if( !error )
error = &tmpError;
if(( val = tr_torrentParseData( h, data, size, destination, NULL )))
*error = val;
else if(!(( tor = tr_new0( tr_torrent, 1 ))))
*error = TR_EOTHER;
else {
tr_metainfoParseData( &tor->info, h->tag, data, size, TRUE );
torrentRealInit( h, tor, destination, FALSE, isPaused );
}
tr_torrent * tor;
tr_ctor * ctor = tr_ctorNew( h );
tr_ctorSetMetainfo( ctor, metainfo, len );
tr_ctorSetDestination( ctor, TR_FORCE, destination );
tr_ctorSetPaused( ctor, TR_FORCE, isPaused );
tor = tr_torrentNew( h, ctor, setmeError );
tr_ctorFree( ctor );
return tor;
}
const tr_info *
tr_torrentInfo( const tr_torrent * tor )
{
return &tor->info;
}
/***
****
***/
@ -711,23 +630,31 @@ tr_torrentGetRates( const tr_torrent * tor,
if( toPeer )
*toPeer = showSpeed ? tr_rcRate( tor->upload ) : 0.0;
}
const tr_info *
tr_torrentInfo( const tr_torrent * tor )
{
return &tor->info;
}
const tr_stat *
tr_torrentStatCached( tr_torrent * tor )
{
const time_t now = time( NULL );
return now == tor->lastStatTime
? &tor->stats[tor->statCur]
: tr_torrentStat( tor );
}
const tr_stat *
tr_torrentStat( tr_torrent * tor )
{
tr_stat * s;
struct tr_tracker * tc;
const time_t now = time( NULL );
/* generating these stats is expensive --
* update a maximum of once per second */
if( tor->lastStatTime == now )
return &tor->stats[tor->statCur];
tor->lastStatTime = now;
tr_torrentLock( tor );
tor->lastStatTime = time( NULL );
tr_torrentRecheckCompleteness( tor );
tor->statCur = !tor->statCur;
@ -1074,7 +1001,7 @@ tr_torrentStart( tr_torrent * tor )
{
if( !tor->uncheckedPieces )
tor->uncheckedPieces = tr_bitfieldNew( tor->info.pieceCount );
tr_fastResumeLoad( tor, TR_FR_PROGRESS, tor->uncheckedPieces, tor->destination, FALSE );
tr_fastResumeLoad( tor, TR_FR_PROGRESS, tor->uncheckedPieces, NULL );
tor->isRunning = 1;
tr_ioRecheckAdd( tor, checkAndStartCB );
}

View File

@ -383,20 +383,19 @@ tr_close( tr_handle * h )
tr_torrent **
tr_loadTorrents ( tr_handle * h,
const char * fallbackDestination,
int isPaused,
tr_ctor * ctor,
int * setmeCount )
{
int i, n = 0;
struct stat sb;
DIR * odir = NULL;
const char * torrentDir = tr_getTorrentsDirectory( );
const char * dirname = tr_getTorrentsDirectory( );
tr_torrent ** torrents;
tr_list *l=NULL, *list=NULL;
if( !stat( torrentDir, &sb )
if( !stat( dirname, &sb )
&& S_ISDIR( sb.st_mode )
&& (( odir = opendir ( torrentDir ) )) )
&& (( odir = opendir ( dirname ) )) )
{
struct dirent *d;
for (d = readdir( odir ); d!=NULL; d=readdir( odir ) )
@ -404,9 +403,10 @@ tr_loadTorrents ( tr_handle * h,
if( d->d_name && d->d_name[0]!='.' ) /* skip dotfiles, ., and .. */
{
tr_torrent * tor;
char path[MAX_PATH_LENGTH];
tr_buildPath( path, sizeof(path), torrentDir, d->d_name, NULL );
tor = tr_torrentLoad( h, path, fallbackDestination, isPaused, NULL );
char filename[MAX_PATH_LENGTH];
tr_buildPath( filename, sizeof(filename), dirname, d->d_name, NULL );
tr_ctorSetMetainfoFromFile( ctor, filename );
tor = tr_torrentNew( h, ctor, NULL );
if( tor != NULL ) {
tr_list_append( &list, tor );
n++;

View File

@ -341,41 +341,31 @@ void tr_torrentRates( tr_handle *, float *, float * );
/**
* Load all the torrents in tr_getTorrentsDirectory().
* This can be used at startup to kickstart all the torrents
* from the previous session.
*/
tr_torrent ** tr_loadTorrents ( tr_handle * h,
const char * fallback_destination,
int isPaused,
int * setmeCount );
/**
* Torrent Instantiation
*
* Creating torrents has gotten more complicated as we've added options,
* and there are now a lot of functions for creating torrents, all slightly
* different. To remedy this, a Torrent Constructor (struct tr_ctor) has
* been introduced. You can fill in the settings you want, and leave the
* rest to the system defaults. It also gives us a backwards-compatable
* way of adding features in the future -- we can add new tr_ctor() functions
* and leave tr_torrentInit()'s signature alone.
* Instantiating a tr_torrent has gotten a lot more complaticated as we
* add more options to them. At the worst point there were four functions
* to check metainfo, and four (or five) functions to create tr_torrents.
* They all did mostly the same thing, but each was just *slightly* different.
*
* You _must_ call one of the SetMetadata() functions before creating
* To remedy this, a Torrent Constructor (struct tr_ctor) has been introduced:
* + Simplifies the API down to two (non-deprecated) functions.
* + You can set the fields you want; the system sets defaults for the rest.
* + You can specify whether or not your fields should supercede fastresume's.
* + We can add new features to tr_ctor without breaking tr_torrentNew()'s API.
*
* All the tr_ctor{Get,Set}*() functions with a return value return
* an error number, or zero if no error occurred.
*
* You must call one of the SetMetainfo() functions before creating
* a torrent with a tr_ctor. The other functions are optional.
*
* You can reuse a tr_ctor when creating a batch of torrents.
* Just call one of the SetMetadata() functions between each
* tr_torrentInit() call.
* You can reuse a single tr_ctor to create a batch of torrents --
* just call one of the SetMetainfo() functions between each
* tr_torrentNew() call.
*
* The tr_ctorGet*() functions will return nonzero if that field
* has been set via one of the tr_ctorSet*() functions.
*
* Every call to tr_ctorSetMetadata*() will free the previous metadata.
* The tr_ctorSetMetadata*() functions return an error number, or zero
* if no error occurred.
* Every call to tr_ctorSetMetainfo*() frees the previous metainfo.
*/
typedef enum
@ -383,25 +373,26 @@ typedef enum
TR_FALLBACK, /* indicates the ctor value should be used only
in case of missing fastresume settings */
TR_FORCE, /* manditory use -- overrides the fastresume settings */
TR_FORCE, /* indicates the ctor value should be used
regardless of what's in the fastresume settings */
}
tr_ctorMode;
typedef struct tr_ctor tr_ctor;
struct benc_val_s;
tr_ctor* tr_ctorNew ( tr_handle * handle);
tr_ctor* tr_ctorNew ( const tr_handle * handle);
void tr_ctorFree ( tr_ctor * ctor );
int tr_ctorSetMetadata ( tr_ctor * ctor,
const uint8_t * metadata,
int tr_ctorSetMetainfo ( tr_ctor * ctor,
const uint8_t * metainfo,
size_t len );
int tr_ctorSetMetadataFromFile ( tr_ctor * ctor,
int tr_ctorSetMetainfoFromFile ( tr_ctor * ctor,
const char * filename );
int tr_ctorSetMetadataFromHash ( tr_ctor * ctor,
int tr_ctorSetMetainfoFromHash ( tr_ctor * ctor,
const char * hashString );
void tr_ctorSetMaxConnectedPeers ( tr_ctor * ctor,
@ -418,7 +409,7 @@ void tr_ctorSetDestination ( tr_ctor * ctor,
void tr_ctorSetPaused ( tr_ctor * ctor,
tr_ctorMode mode,
int isPaused );
uint8_t isPaused );
int tr_ctorGetMaxConnectedPeers ( const tr_ctor * ctor,
tr_ctorMode mode,
@ -430,15 +421,17 @@ int tr_ctorGetMaxUnchokedPeers ( const tr_ctor * ctor,
int tr_ctorGetIsPaused ( const tr_ctor * ctor,
tr_ctorMode mode,
int * setmeIsPaused );
uint8_t * setmeIsPaused );
int tr_ctorGetDestination ( const tr_ctor * ctor,
tr_ctorMode mode,
const char ** setmeDestination );
int tr_ctorGetMetadata ( const tr_ctor * ctor,
int tr_ctorGetMetainfo ( const tr_ctor * ctor,
const struct benc_val_s ** setme );
typedef struct tr_info tr_info;
/**
* Parses the specified metainfo.
* Returns TR_OK if it parsed and can be added to Transmission.
@ -448,14 +441,15 @@ int tr_ctorGetMetadata ( const tr_ctor * ctor,
*
* "setme_info" can be NULL if you don't need the information.
* If the metainfo can be parsed and setme_info is non-NULL,
* it will be filled with the metadata's info. You'll need to
* it will be filled with the metainfo's info. You'll need to
* call tr_metainfoFree( setme_info ) when done with it.
*/
int tr_torrentParseFromCtor( tr_handle * handle,
const tr_ctor * ctor );
int tr_torrentParseFromCtor( const tr_handle * handle,
const tr_ctor * ctor,
tr_info * setme_info );
/**
* Instantiate the torrent from the given tr_ctor.
* Instantiate a single torrent.
*/
#define TR_EINVALID 1
#define TR_EUNSUPPORTED 2
@ -466,37 +460,36 @@ tr_torrent * tr_torrentNew( tr_handle * handle,
int * setmeError );
/**
* Load all the torrents in tr_getTorrentsDirectory().
* This can be used at startup to kickstart all the torrents
* from the previous session.
*/
tr_torrent ** tr_loadTorrents ( tr_handle * h,
tr_ctor * ctor,
int * setmeCount );
/**
***
**/
/***********************************************************************
* tr_torrentInit
***********************************************************************
* Opens and parses torrent file at 'path'. If the file exists and is
* a valid torrent file, returns an handle and adds it to the list of
* torrents (but doesn't start it). Returns NULL and sets *error
* otherwise. If hash is not NULL and the torrent is already loaded
* then it's 20-byte hash will be copied in. If the TR_FLAG_SAVE flag
* is passed then a copy of the torrent file will be saved.
**********************************************************************/
*
* !! DO NOT USE THIS FUNCTION IN NEW CODE !!
*/
tr_torrent * tr_torrentInit( tr_handle * handle,
const char * metainfo_filename,
const char * destination,
int isPaused,
int * setme_error );
/* This is a stupid hack to fix #415. Probably I should fold all
* these torrent constructors into a single function that takes
* a function object to hold all these esoteric arguments. */
tr_torrent * tr_torrentLoad( tr_handle * handle,
const char * metainfo_filename,
const char * fallback_destination,
int isPaused,
int * setme_error );
typedef struct tr_info tr_info;
/**
* Parses the specified metainfo file.
*
@ -509,8 +502,10 @@ typedef struct tr_info tr_info;
*
" "setme_info" can be NULL if you don't need the information.
* If the metainfo can be parsed and setme_info is non-NULL,
* it will be filled with the metadata's info. You'll need to
* it will be filled with the metainfo's info. You'll need to
* call tr_metainfoFree( setme_info ) when done with it.
*
* !! DO NOT USE THIS FUNCTION IN NEW CODE !!
*/
int tr_torrentParse( const tr_handle * handle,
const char * metainfo_filename,
@ -520,6 +515,8 @@ int tr_torrentParse( const tr_handle * handle,
/**
* Parses the cached metainfo file that matches the given hash string.
* See tr_torrentParse() for a description of the arguments
*
* !! DO NOT USE THIS FUNCTION IN NEW CODE !!
*/
int
tr_torrentParseHash( const tr_handle * h,
@ -529,11 +526,11 @@ tr_torrentParseHash( const tr_handle * h,
/***********************************************************************
* tr_torrentInitData
***********************************************************************
* Like tr_torrentInit, except the actual torrent data is passed in
* instead of the filename.
**********************************************************************/
*
* !! DO NOT USE THIS FUNCTION IN NEW CODE !!
*/
tr_torrent * tr_torrentInitData( tr_handle *,
const uint8_t * data, size_t size,
const char * destination,
@ -541,12 +538,12 @@ tr_torrent * tr_torrentInitData( tr_handle *,
int * error );
/***********************************************************************
* tr_torrentInitSaved
***********************************************************************
* Opens and parses a torrent file as with tr_torrentInit, only taking
* the hash string of a saved torrent file instead of a filename. There
* are currently no valid flags for this function.
**********************************************************************/
*
* !! DO NOT USE THIS FUNCTION IN NEW CODE !!
*/
tr_torrent * tr_torrentInitSaved( tr_handle *,
const char * hashStr,
const char * destination,
@ -641,6 +638,7 @@ int tr_torrentCanManualUpdate( const tr_torrent * );
**********************************************************************/
typedef struct tr_stat tr_stat;
const tr_stat * tr_torrentStat( tr_torrent * );
const tr_stat * tr_torrentStatCached( tr_torrent * );
/***********************************************************************
* tr_torrentPeers
@ -676,12 +674,10 @@ void tr_torrentRemoveSaved( tr_torrent * );
void tr_torrentRecheck( tr_torrent * );
/***********************************************************************
* tr_torrentClose
***********************************************************************
* Frees memory allocated by tr_torrentInit. If the torrent was running,
* it is stopped first.
**********************************************************************/
/**
* Frees memory allocated by tr_torrentNew().
* Running torrents are stopped first.
*/
void tr_torrentClose( tr_torrent * );
/***********************************************************************