'resume' cleanup

This commit is contained in:
Charles Kerr 2008-04-14 11:52:50 +00:00
parent a08ef82039
commit afde752dc0
8 changed files with 227 additions and 147 deletions

View File

@ -313,7 +313,7 @@ tr_bencParse( const void * buf_in,
int
tr_bencLoad( const void * buf_in,
int buflen,
tr_benc * setme_benc,
tr_benc * setme_benc,
char ** setme_end )
{
const uint8_t * buf = buf_in;
@ -570,6 +570,14 @@ tr_bencListAdd( tr_benc * list )
return item;
}
tr_benc *
tr_bencListAddInt( tr_benc * list, int64_t i )
{
tr_benc * node = tr_bencListAdd( list );
tr_bencInitInt( node, i );
return node;
}
tr_benc *
tr_bencDictAdd( tr_benc * dict, const char * key )
{
@ -1051,3 +1059,48 @@ tr_bencSaveAsSerializedPHP( const tr_benc * top, int * len )
evbuffer_free( data.out );
return ret;
}
/***
****
***/
int
tr_bencSaveFile( const char * filename, const tr_benc * b )
{
int ret = TR_OK;
int len;
char * content = tr_bencSave( b, &len );
FILE * out = NULL;
out = fopen( filename, "wb+" );
if( !out )
{
tr_err( _( "Couldn't open \"%1$s\": %2$s" ),
filename, tr_strerror( errno ) );
ret = TR_EINVALID;
}
else if( fwrite( content, sizeof( char ), len, out ) != (size_t)len )
{
tr_err( _( "Couldn't save file \"%1$s\": %2$s" ),
filename, tr_strerror( errno ) );
ret = TR_EINVALID;
}
tr_dbg( "tr_bencSaveFile returned %d when saving \"%s\"", ret, filename );
tr_free( content );
if( out )
fclose( out );
return ret;
}
int
tr_bencLoadFile( const char * filename, tr_benc * b )
{
int ret = TR_ERROR;
size_t contentLen;
uint8_t * content = tr_loadFile( filename, &contentLen );
ret = content ? tr_bencLoad( content, contentLen, b, NULL )
: TR_ERROR_IO_OTHER;
tr_free( content );
return ret;
}

View File

@ -99,6 +99,7 @@ int tr_bencListReserve( tr_benc * list, int count );
/* note that for one key-value pair, count should be 1, not 2 */
int tr_bencDictReserve( tr_benc * dict, int count );
tr_benc * tr_bencListAdd( tr_benc * list );
tr_benc * tr_bencListAddInt( tr_benc * list, int64_t val );
/* note: key must not be freed or modified while val is in use */
tr_benc * tr_bencDictAdd( tr_benc * dict, const char * key );
tr_benc * tr_bencDictAddInt( tr_benc * dict, const char * key, int64_t val );
@ -107,7 +108,9 @@ tr_benc * tr_bencDictAddList( tr_benc * dict, const char * key, int reserveCo
tr_benc * tr_bencDictAddDict( tr_benc * dict, const char * key, int reserveCount );
char* tr_bencSave( const tr_benc * val, int * len );
char* tr_bencSaveAsSerializedPHP( const tr_benc * top, int * len );
char* tr_bencSaveAsSerializedPHP( const tr_benc * top, int * len );
int tr_bencSaveFile( const char * filename, const tr_benc * );
int tr_bencLoadFile( const char * filename, tr_benc * );
int tr_bencGetInt( const tr_benc * val, int64_t * setme );

View File

@ -125,25 +125,64 @@ strlcat_utf8( void * dest, const void * src, size_t len, char skip )
}
static void
savedname( const tr_handle * handle,
char * name,
size_t len,
const char * hash )
getTorrentFilename( const tr_handle * handle,
const tr_info * inf,
char * buf,
size_t buflen )
{
const char * dir = tr_getTorrentDir( handle );
char base[MAX_PATH_LENGTH];
snprintf( base, sizeof( base ), "%s.%16.16s.torrent", inf->name, inf->hashString );
tr_buildPath( buf, buflen, dir, base, NULL );
}
static void
getTorrentOldFilename( const tr_handle * handle,
const tr_info * info,
char * name,
size_t len )
{
const char * torDir = tr_getTorrentDir( handle );
if( !handle->tag )
{
tr_buildPath( name, len, torDir, hash, NULL );
tr_buildPath( name, len, torDir, info->hashString, NULL );
}
else
{
char base[1024];
snprintf( base, sizeof(base), "%s-%s", hash, handle->tag );
snprintf( base, sizeof(base), "%s-%s", info->hashString, handle->tag );
tr_buildPath( name, len, torDir, base, NULL );
}
}
void
tr_metainfoMigrate( const tr_handle * handle,
const tr_info * inf )
{
struct stat new_sb;
char new_name[MAX_PATH_LENGTH];
getTorrentFilename( handle, inf, new_name, sizeof( new_name ) );
if( stat( new_name, &new_sb ) || ( ( new_sb.st_mode & S_IFMT ) != S_IFREG ) )
{
char old_name[MAX_PATH_LENGTH];
size_t contentLen;
uint8_t * content;
getTorrentOldFilename( handle, inf, old_name, sizeof( old_name ) );
if(( content = tr_loadFile( old_name, &contentLen )))
{
FILE * out = fopen( new_name, "wb+" );
if( fwrite( content, sizeof( uint8_t ), contentLen, out ) == contentLen )
unlink( old_name );
fclose( out );
}
tr_free( content );
}
}
int
tr_metainfoParse( const tr_handle * handle,
@ -172,9 +211,6 @@ tr_metainfoParse( const tr_handle * handle,
}
tr_sha1_to_hex( inf->hashString, inf->hash );
savedname( handle, buf, sizeof( buf ), inf->hashString );
tr_free( inf->torrent );
inf->torrent = tr_strdup( buf );
/* comment */
memset( buf, '\0', sizeof( buf ) );
@ -274,6 +310,12 @@ tr_metainfoParse( const tr_handle * handle,
goto fail;
}
/* filename of Transmission's copy */
getTorrentFilename( handle, inf, buf, sizeof( buf ) );
tr_free( inf->torrent );
inf->torrent = tr_strdup( buf );
fprintf( stderr, "inf->torrent is [%s]\n", inf->torrent );
return TR_OK;
fail:
@ -569,40 +611,15 @@ tr_trackerInfoClear( tr_tracker_info * info )
void
tr_metainfoRemoveSaved( const tr_handle * handle,
const char * hashString )
const tr_info * inf )
{
char file[MAX_PATH_LENGTH];
savedname( handle, file, sizeof file, hashString );
unlink( file );
}
char filename[MAX_PATH_LENGTH];
/* Save a copy of the torrent file in the saved torrent directory */
int
tr_metainfoSave( const tr_handle * handle,
const char * hash,
const uint8_t * buf,
size_t buflen )
{
char path[MAX_PATH_LENGTH];
FILE * file;
getTorrentFilename( handle, inf, filename, sizeof( filename ) );
unlink( filename );
savedname( handle, path, sizeof path, hash );
file = fopen( path, "wb+" );
if( !file )
{
tr_err( _( "Couldn't open \"%1$s\": %2$s" ), path, tr_strerror( errno ) );
return TR_EINVALID;
}
fseek( file, 0, SEEK_SET );
if( fwrite( buf, 1, buflen, file ) != buflen )
{
tr_err( _( "Couldn't save file \"%1$s\": %2$s" ), path, tr_strerror( errno ) );
fclose( file );
return TR_EINVALID;
}
fclose( file );
return TR_OK;
getTorrentOldFilename( handle, inf, filename, sizeof( filename ) );
unlink( filename );
}
static int

View File

@ -36,11 +36,9 @@ int tr_metainfoParse( const tr_handle * handle,
void tr_metainfoFree( tr_info * inf );
void tr_metainfoRemoveSaved( const tr_handle * handle,
const char * hashString );
const tr_info * info );
int tr_metainfoSave( const tr_handle * handle,
const char * hashString,
const uint8_t * metainfo,
size_t len );
void tr_metainfoMigrate( const tr_handle * handle,
const tr_info * inf );
#endif

View File

@ -10,9 +10,7 @@
* $Id:$
*/
#include <sys/types.h> /* stat */
#include <sys/stat.h> /* stat */
#include <unistd.h> /* unlink, stat */
#include <unistd.h> /* unlink */
#include <string.h>
@ -45,41 +43,14 @@
#define KEY_PROGRESS_MTIMES "mtimes"
#define KEY_PROGRESS_BITFIELD "bitfield"
/***
****
***/
static time_t*
getMTimes( const tr_torrent * tor, int * setme_n )
{
int i;
const int n = tor->info.fileCount;
time_t * m = tr_new( time_t, n );
for( i=0; i<n; ++i ) {
char fname[MAX_PATH_LENGTH];
struct stat sb;
tr_buildPath( fname, sizeof(fname),
tor->destination, tor->info.files[i].name, NULL );
if ( !stat( fname, &sb ) && S_ISREG( sb.st_mode ) ) {
#ifdef SYS_DARWIN
m[i] = sb.st_mtimespec.tv_sec;
#else
m[i] = sb.st_mtime;
#endif
}
}
*setme_n = n;
return m;
}
static void
getResumeFilename( char * buf, size_t buflen, const tr_torrent * tor )
{
const char * dir = tr_getResumeDir( tor->handle );
char base[4096];
snprintf( base, sizeof( base ), "%s.%16.16s.resume", tor->info.name, tor->info.hashString );
snprintf( base, sizeof( base ), "%s.%16.16s.resume",
tor->info.name,
tor->info.hashString );
tr_buildPath( buf, buflen, dir, base, NULL );
}
@ -91,7 +62,8 @@ static void
savePeers( tr_benc * dict, const tr_torrent * tor )
{
tr_pex * pex;
const int count = tr_peerMgrGetPeers( tor->handle->peerMgr, tor->info.hash, &pex );
const int count = tr_peerMgrGetPeers( tor->handle->peerMgr,
tor->info.hash, &pex );
if( count > 0 ) {
tr_benc * child = tr_bencDictAdd( dict, KEY_PEERS );
tr_bencInitStrDupLen( child, (const char*)pex, sizeof(tr_pex)*count );
@ -114,7 +86,8 @@ loadPeers( tr_benc * dict, tr_torrent * tor )
for( i=0; i<count; ++i ) {
tr_pex pex;
memcpy( &pex, str + (i*sizeof(tr_pex)), sizeof(tr_pex) );
tr_peerMgrAddPex( tor->handle->peerMgr, tor->info.hash, TR_PEER_FROM_CACHE, &pex );
tr_peerMgrAddPex( tor->handle->peerMgr,
tor->info.hash, TR_PEER_FROM_CACHE, &pex );
}
tr_tordbg( tor, "Loaded %d peers from resume file", count );
ret = TR_FR_PEERS;
@ -123,6 +96,10 @@ loadPeers( tr_benc * dict, tr_torrent * tor )
return ret;
}
/***
****
***/
static void
savePriorities( tr_benc * dict, const tr_torrent * tor )
{
@ -144,7 +121,8 @@ loadPriorities( tr_benc * dict, tr_torrent * tor )
const tr_file_index_t n = inf->fileCount;
tr_benc * list;
if( tr_bencDictFindList( dict, KEY_PRIORITY, &list ) && ( list->val.l.count == (int)n ) )
if( tr_bencDictFindList( dict, KEY_PRIORITY, &list )
&& ( list->val.l.count == (int)n ) )
{
int64_t tmp;
tr_file_index_t i;
@ -157,6 +135,10 @@ loadPriorities( tr_benc * dict, tr_torrent * tor )
return ret;
}
/***
****
***/
static void
saveSpeedLimits( tr_benc * dict, const tr_torrent * tor )
{
@ -194,6 +176,10 @@ loadSpeedLimits( tr_benc * dict, tr_torrent * tor )
return ret;
}
/***
****
***/
static void
saveProgress( tr_benc * dict, const tr_torrent * tor )
{
@ -209,13 +195,12 @@ saveProgress( tr_benc * dict, const tr_torrent * tor )
tr_bencInitDict( p, 2 );
/* add the mtimes */
m = tr_bencDictAdd( p, KEY_PROGRESS_MTIMES );
mtimes = getMTimes( tor, &n );
tr_bencInitList( m, n );
mtimes = tr_torrentGetMTimes( tor, &n );
m = tr_bencDictAddList( p, KEY_PROGRESS_MTIMES, n );
for( i=0; i<n; ++i ) {
if( !tr_torrentIsFileChecked( tor, i ) )
mtimes[i] = ~(time_t)0; /* force a recheck next time */
tr_bencInitInt( tr_bencListAdd( m ), mtimes[i] );
tr_bencListAddInt( m, mtimes[i] );
}
/* add the bitfield */
@ -238,19 +223,19 @@ loadProgress( tr_benc * dict, tr_torrent * tor )
tr_benc * m;
tr_benc * b;
int n;
time_t * curMTimes = getMTimes( tor, &n );
time_t * curMTimes = tr_torrentGetMTimes( tor, &n );
if( tr_bencDictFindList( p, KEY_PROGRESS_MTIMES, &m )
&& ( m->val.l.count == (int64_t)tor->info.fileCount )
&& ( m->val.l.count == n ) )
{
int i;
const time_t recheck = ~(time_t)0;
for( i=0; i<m->val.l.count; ++i )
{
int64_t tmp;
const time_t t = tr_bencGetInt( &m->val.l.vals[i], &tmp )
? tmp : ~(time_t)0;
if( curMTimes[i] == t )
int64_t x;
time_t t = tr_bencGetInt( &m->val.l.vals[i], &x ) ? x : recheck;
if( ( t != recheck ) && ( curMTimes[i] == t ) )
tr_torrentSetFileChecked( tor, i, TRUE );
else {
tr_torrentSetFileChecked( tor, i, FALSE );
@ -287,19 +272,24 @@ loadProgress( tr_benc * dict, tr_torrent * tor )
return ret;
}
/***
****
***/
void
tr_torrentSaveResume( const tr_torrent * tor )
{
tr_benc top;
char * encoded;
int len;
char filename[MAX_PATH_LENGTH];
/* populate the bencoded data */
tr_bencInitDict( &top, 10 );
tr_bencDictAddInt( &top, KEY_CORRUPT, tor->corruptPrev + tor->corruptCur );
tr_bencDictAddStr( &top, KEY_DESTINATION, tor->destination );
tr_bencDictAddInt( &top, KEY_DOWNLOADED, tor->downloadedPrev + tor->downloadedCur );
tr_bencDictAddInt( &top, KEY_UPLOADED, tor->uploadedPrev + tor->uploadedCur );
tr_bencDictAddInt( &top, KEY_DOWNLOADED,
tor->downloadedPrev + tor->downloadedCur );
tr_bencDictAddInt( &top, KEY_UPLOADED,
tor->uploadedPrev + tor->uploadedCur );
tr_bencDictAddInt( &top, KEY_MAX_PEERS, tor->maxConnectedPeers );
tr_bencDictAddInt( &top, KEY_PAUSED, tor->isRunning?0:1 );
savePeers( &top, tor );
@ -307,19 +297,9 @@ tr_torrentSaveResume( const tr_torrent * tor )
saveProgress( &top, tor );
saveSpeedLimits( &top, tor );
/* save the bencoded data */
if(( encoded = tr_bencSave( &top, &len )))
{
char filename[MAX_PATH_LENGTH];
FILE * fp;
getResumeFilename( filename, sizeof( filename ), tor );
fp = fopen( filename, "wb+" );
fwrite( encoded, len, 1, fp );
fclose( fp );
tr_free( encoded );
}
getResumeFilename( filename, sizeof( filename ), tor );
tr_bencSaveFile( filename, &top );
/* cleanup */
tr_bencFree( &top );
}
@ -330,21 +310,15 @@ tr_torrentLoadResume( tr_torrent * tor,
{
int64_t i;
const char * str;
int benc_loaded = FALSE;
uint64_t fieldsLoaded = 0;
uint8_t * content = NULL;
size_t contentLen;
char filename[MAX_PATH_LENGTH];
tr_benc top;
getResumeFilename( filename, sizeof( filename ), tor );
content = tr_loadFile( filename, &contentLen );
benc_loaded = content && !tr_bencLoad( content, contentLen, &top, NULL );
if( !benc_loaded )
if( tr_bencLoadFile( filename, &top ) )
{
tr_free( content );
tr_tordbg( tor, "Couldn't read \"%s\"; trying old resume file format.", filename );
tr_tordbg( tor, "Couldn't read \"%s\"; trying old format.", filename );
fieldsLoaded = tr_fastResumeLoad( tor, fieldsToLoad, ctor );
if( ( fieldsLoaded != 0 ) && ( fieldsToLoad == ~(uint64_t)0 ) )
@ -359,41 +333,54 @@ tr_torrentLoadResume( tr_torrent * tor,
tr_tordbg( tor, "Read resume file \"%s\"", filename );
if( tr_bencDictFindInt( &top, KEY_CORRUPT, &i ) ) {
if( ( fieldsToLoad & TR_FR_CORRUPT )
&& tr_bencDictFindInt( &top, KEY_CORRUPT, &i ) ) {
tor->corruptPrev = i;
fieldsLoaded |= TR_FR_CORRUPT;
}
if( tr_bencDictFindStr( &top, KEY_DESTINATION, &str ) ) {
if( ( fieldsToLoad & TR_FR_DESTINATION )
&& tr_bencDictFindStr( &top, KEY_DESTINATION, &str ) ) {
tr_free( tor->destination );
tor->destination = tr_strdup( str );
fieldsLoaded |= TR_FR_DESTINATION;
}
if( tr_bencDictFindInt( &top, KEY_DOWNLOADED, &i ) ) {
if( ( fieldsToLoad & TR_FR_DOWNLOADED )
&& tr_bencDictFindInt( &top, KEY_DOWNLOADED, &i ) ) {
tor->downloadedPrev = i;
fieldsLoaded |= TR_FR_DOWNLOADED;
}
if( tr_bencDictFindInt( &top, KEY_UPLOADED, &i ) ) {
if( ( fieldsToLoad & TR_FR_UPLOADED )
&& tr_bencDictFindInt( &top, KEY_UPLOADED, &i ) ) {
tor->uploadedPrev = i;
fieldsLoaded |= TR_FR_UPLOADED;
}
if( tr_bencDictFindInt( &top, KEY_MAX_PEERS, &i ) ) {
if( ( fieldsToLoad & TR_FR_MAX_PEERS )
&& tr_bencDictFindInt( &top, KEY_MAX_PEERS, &i ) ) {
tor->maxConnectedPeers = i;
fieldsLoaded |= TR_FR_MAX_PEERS;
}
if( tr_bencDictFindInt( &top, KEY_PAUSED, &i ) ) {
if( ( fieldsToLoad & TR_FR_RUN )
&& tr_bencDictFindInt( &top, KEY_PAUSED, &i ) ) {
tor->isRunning = i ? 0 : 1;
fieldsLoaded |= TR_FR_RUN;
}
fieldsLoaded |= loadPeers( &top, tor );
fieldsLoaded |= loadPriorities( &top, tor );
fieldsLoaded |= loadProgress( &top, tor );
fieldsLoaded |= loadSpeedLimits( &top, tor );
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_SPEEDLIMIT )
fieldsLoaded |= loadSpeedLimits( &top, tor );
tr_bencFree( &top );
return fieldsLoaded;

View File

@ -81,27 +81,20 @@ loadCumulativeStats( const tr_handle * handle, tr_session_stats * setme )
}
static void
saveCumulativeStats( const tr_handle * handle, const tr_session_stats * stats )
saveCumulativeStats( const tr_handle * handle, const tr_session_stats * s )
{
FILE * fp;
char * str;
char filename[MAX_PATH_LENGTH];
int len;
tr_benc top;
tr_bencInitDict( &top, 5 );
tr_bencInitInt( tr_bencDictAdd( &top, "uploaded-bytes" ), stats->uploadedBytes );
tr_bencInitInt( tr_bencDictAdd( &top, "downloaded-bytes" ), stats->downloadedBytes );
tr_bencInitInt( tr_bencDictAdd( &top, "files-added" ), stats->filesAdded );
tr_bencInitInt( tr_bencDictAdd( &top, "session-count" ), stats->sessionCount );
tr_bencInitInt( tr_bencDictAdd( &top, "seconds-active" ), stats->secondsActive );
tr_bencInitInt( tr_bencDictAdd( &top, "uploaded-bytes" ), s->uploadedBytes );
tr_bencInitInt( tr_bencDictAdd( &top, "downloaded-bytes" ), s->downloadedBytes );
tr_bencInitInt( tr_bencDictAdd( &top, "files-added" ), s->filesAdded );
tr_bencInitInt( tr_bencDictAdd( &top, "session-count" ), s->sessionCount );
tr_bencInitInt( tr_bencDictAdd( &top, "seconds-active" ), s->secondsActive );
str = tr_bencSave( &top, &len );
getFilename( handle, filename, sizeof(filename) );
fp = fopen( filename, "wb+" );
fwrite( str, 1, len, fp );
fclose( fp );
tr_free( str );
tr_bencSaveFile( filename, &top );
tr_bencFree( &top );
}

View File

@ -22,6 +22,10 @@
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#include <sys/types.h> /* stat */
#include <sys/stat.h> /* stat */
#include <unistd.h> /* stat */
#include <assert.h>
#include <string.h> /* memcmp */
@ -381,15 +385,13 @@ torrentRealInit( tr_handle * h,
if( tr_ctorGetSave( ctor ) ) {
const tr_benc * val;
if( !tr_ctorGetMetainfo( ctor, &val ) ) {
int len;
uint8_t * text = (uint8_t*) tr_bencSave( val, &len );
tr_metainfoSave( tor->handle,
tor->info.hashString,
text, len );
tr_free( text );
const char * filename = tor->info.torrent;
tr_bencSaveFile( filename, val );
}
}
tr_metainfoMigrate( h, &tor->info );
if( doStart )
tr_torrentStart( tor );
}
@ -812,7 +814,7 @@ tr_torrentSetHasPiece( tr_torrent * tor, tr_piece_index_t pieceIndex, int has )
void
tr_torrentRemoveSaved( tr_torrent * tor )
{
tr_metainfoRemoveSaved( tor->handle, tor->info.hashString );
tr_metainfoRemoveSaved( tor->handle, &tor->info );
tr_torrentRemoveResume( tor );
}
@ -1419,3 +1421,28 @@ tr_torrentCountUncheckedPieces( const tr_torrent * tor )
{
return tor->info.pieceCount - tr_bitfieldCountTrueBits( tor->checkedPieces );
}
time_t*
tr_torrentGetMTimes( const tr_torrent * tor, int * setme_n )
{
int i;
const int n = tor->info.fileCount;
time_t * m = tr_new( time_t, n );
for( i=0; i<n; ++i ) {
char fname[MAX_PATH_LENGTH];
struct stat sb;
tr_buildPath( fname, sizeof(fname),
tor->destination, tor->info.files[i].name, NULL );
if ( !stat( fname, &sb ) && S_ISREG( sb.st_mode ) ) {
#ifdef SYS_DARWIN
m[i] = sb.st_mtimespec.tv_sec;
#else
m[i] = sb.st_mtime;
#endif
}
}
*setme_n = n;
return m;
}

View File

@ -101,6 +101,8 @@ void tr_torrentSetPieceChecked ( tr_torrent *, tr_piece_index_t piece, int i
void tr_torrentSetFileChecked ( tr_torrent *, tr_file_index_t file, int isChecked );
void tr_torrentUncheck ( tr_torrent * );
time_t* tr_torrentGetMTimes ( const tr_torrent *, int * setmeCount );
typedef enum
{
TR_VERIFY_NONE,