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;
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 )
{
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;
+}
/* 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 );
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 );
}
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,
}
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 ) );
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:
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
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
* $Id:$
*/
-#include <sys/types.h> /* stat */
-#include <sys/stat.h> /* stat */
-#include <unistd.h> /* unlink, stat */
+#include <unistd.h> /* unlink */
#include <string.h>
#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 );
}
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 );
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;
return ret;
}
+/***
+****
+***/
+
static void
savePriorities( tr_benc * dict, const 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;
return ret;
}
+/***
+****
+***/
+
static void
saveSpeedLimits( tr_benc * dict, const tr_torrent * tor )
{
return ret;
}
+/***
+****
+***/
+
static void
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 */
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 );
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 );
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 );
}
{
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 ) )
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;
}
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 );
}
* 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 */
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 );
}
void
tr_torrentRemoveSaved( tr_torrent * tor )
{
- tr_metainfoRemoveSaved( tor->handle, tor->info.hashString );
+ tr_metainfoRemoveSaved( tor->handle, &tor->info );
tr_torrentRemoveResume( 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;
+}
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,