Changeset 9328


Ignore:
Timestamp:
Oct 19, 2009, 5:05:00 AM (13 years ago)
Author:
charles
Message:

(trunk) #1483: move completed torrents to a user-specified directory + #629: different file extension for incomplete files

Location:
trunk
Files:
2 deleted
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/gtk/main.c

    r9308 r9328  
    11271127        tr_sessionSetPeerPortRandomOnStart( tr, pref_flag_get( key ) );
    11281128    }
     1129    else if( !strcmp( key, TR_PREFS_KEY_INCOMPLETE_DIR ) )
     1130    {
     1131        tr_sessionSetIncompleteDir( tr, pref_string_get( key ) );
     1132    }
     1133    else if( !strcmp( key, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED ) )
     1134    {
     1135        tr_sessionSetIncompleteDirEnabled( tr, pref_flag_get( key ) );
     1136    }
    11291137}
    11301138
  • trunk/gtk/tr-prefs.c

    r9284 r9328  
    290290    hig_workarea_add_row_w( t, &row, l, w, NULL );
    291291#endif
     292
     293    s = _( "Keep incomplete files in:" );
     294    l = new_check_button( s, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, core );
     295    w = new_path_chooser_button( TR_PREFS_KEY_INCOMPLETE_DIR, core );
     296    gtk_widget_set_sensitive( GTK_WIDGET( w ), pref_flag_get( TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED ) );
     297    g_signal_connect( l, "toggled", G_CALLBACK( target_cb ), w );
     298    hig_workarea_add_row_w( t, &row, l, w, NULL );
    292299
    293300    s = _( "Display _options dialog" );
  • trunk/libtransmission/Makefile.am

    r9259 r9328  
    2121    ConvertUTF.c \
    2222    crypto.c \
    23     fastresume.c \
    2423    fdlimit.c \
    2524    ggets.c \
     
    6968    crypto.h \
    7069    completion.h \
    71     fastresume.h \
    7270    fdlimit.h \
    7371    ggets.h \
  • trunk/libtransmission/fdlimit.c

    r9066 r9328  
    8484struct tr_openfile
    8585{
    86     tr_bool    isWritable;
    87     int        torrentId;
    88     char       filename[MAX_PATH_LENGTH];
    89     int        fd;
    90     uint64_t   date;
     86    tr_bool          isWritable;
     87    int              torrentId;
     88    tr_file_index_t  fileNum;
     89    char             filename[MAX_PATH_LENGTH];
     90    int              fd;
     91    uint64_t         date;
    9192};
    9293
     
    382383}
    383384
     385int
     386tr_fdFileGetCached( int              torrentId,
     387                    tr_file_index_t  fileNum,
     388                    tr_bool          doWrite )
     389{
     390    int i;
     391    struct tr_openfile * o;
     392
     393    assert( torrentId > 0 );
     394    assert( tr_isBool( doWrite ) );
     395
     396    /* is it already open? */
     397    for( i=0; i<gFd->openFileLimit; ++i )
     398    {
     399        o = &gFd->openFiles[i];
     400
     401        if( !fileIsOpen( o ) )
     402            continue;
     403        if( torrentId != o->torrentId )
     404            continue;
     405        if( fileNum != o->fileNum )
     406            continue;
     407
     408        break;
     409    }
     410
     411    if( ( o != NULL ) && ( !doWrite || o->isWritable ) )
     412    {
     413        o->date = tr_date( );
     414        return o->fd;
     415    }
     416
     417    return -1;
     418}
     419
    384420/* returns an fd on success, or a -1 on failure and sets errno */
    385421int
    386422tr_fdFileCheckout( int                      torrentId,
     423                   tr_file_index_t          fileNum,
    387424                   const char             * folder,
    388425                   const char             * torrentFile,
     
    412449        if( torrentId != o->torrentId )
    413450            continue;
    414         if( strcmp( filename, o->filename ) )
     451        if( fileNum != o->fileNum )
    415452            continue;
    416453
     
    479516    dbgmsg( "checking out '%s' in slot %d", filename, winner );
    480517    o->torrentId = torrentId;
     518    o->fileNum = fileNum;
    481519    o->date = tr_date( );
    482520    return o->fd;
     
    484522
    485523void
    486 tr_fdFileClose( const char * filename )
     524tr_fdFileClose( const tr_torrent * tor, tr_file_index_t fileNum )
    487525{
    488526    struct tr_openfile * o;
    489527    const struct tr_openfile * end;
    490 
     528    const int torrentId = tr_torrentId( tor );
    491529    for( o=gFd->openFiles, end=o+gFd->openFileLimit; o!=end; ++o )
    492530    {
    493         if( !fileIsOpen( o ) || strcmp( filename, o->filename ) )
    494             continue;
    495         dbgmsg( "tr_fdFileClose closing \"%s\"", filename );
     531        if( !fileIsOpen( o ) )
     532            continue;
     533        if( torrentId != o->torrentId )
     534            continue;
     535        if( fileNum != o->fileNum )
     536            continue;
     537
     538        dbgmsg( "tr_fdFileClose closing \"%s\"", o->filename );
    496539        TrCloseFile( o );
    497540    }
  • trunk/libtransmission/fdlimit.h

    r8935 r9328  
    6666 */
    6767int  tr_fdFileCheckout( int                      torrentId,
     68                        tr_file_index_t          fileNum,
    6869                        const char             * folder,
    6970                        const char             * torrentFile,
     
    7172                        tr_preallocation_mode    preallocationMode,
    7273                        uint64_t                 desiredFileSize );
     74
     75int tr_fdFileGetCached( int                      torrentId,
     76                        tr_file_index_t          fileNum,
     77                        tr_bool                  doWrite );
    7378
    7479/**
     
    8085 * @see tr_fdFileCheckout
    8186 */
    82 void     tr_fdFileClose( const char * filename );
     87void     tr_fdFileClose( const tr_torrent * tor, tr_file_index_t fileNo );
    8388
    8489
  • trunk/libtransmission/inout.c

    r9080 r9328  
    7676    const tr_info * info = &tor->info;
    7777    const tr_file * file = &info->files[fileIndex];
    78     tr_preallocation_mode preallocationMode;
    7978
    8079    typedef size_t ( *iofunc )( int, void *, size_t );
     
    8281    struct stat     sb;
    8382    int             fd = -1;
    84     int             err;
    85     int             fileExists;
    86 
    87     assert( tor->downloadDir && *tor->downloadDir );
     83    int             err = 0;
     84    const tr_bool doWrite = ioMode == TR_IO_WRITE;
     85
     86    assert( tor->currentDir && *tor->currentDir );
    8887    assert( fileIndex < info->fileCount );
    8988    assert( !file->length || ( fileOffset < file->length ) );
    9089    assert( fileOffset + buflen <= file->length );
    9190
    92     {
    93         char path[MAX_PATH_LENGTH];
    94         tr_snprintf( path, sizeof( path ), "%s%c%s", tor->downloadDir, TR_PATH_DELIMITER, file->name );
    95         fileExists = !stat( path, &sb );
    96     }
    97 
    9891    if( !file->length )
    9992        return 0;
    10093
    101     if( ( file->dnd ) || ( ioMode != TR_IO_WRITE ) )
    102         preallocationMode = TR_PREALLOCATE_NONE;
    103     else
    104         preallocationMode = tor->session->preallocationMode;
    105 
    106     if( ( ioMode == TR_IO_READ ) && !fileExists ) /* does file exist? */
    107         err = ENOENT;
    108     else if( ( fd = tr_fdFileCheckout( tor->uniqueId, tor->downloadDir, file->name, ioMode == TR_IO_WRITE, preallocationMode, file->length ) ) < 0 ) {
    109         err = errno;
    110         tr_torerr( tor, "tr_fdFileCheckout failed for \"%s\": %s", file->name, tr_strerror( err ) );
    111     }
    112     else if( tr_lseek( fd, (int64_t)fileOffset, SEEK_SET ) == -1 ) {
    113         err = errno;
    114         tr_torerr( tor, "tr_lseek failed for \"%s\": %s", file->name, tr_strerror( err ) );
    115     }
    116     else if( func( fd, buf, buflen ) != buflen ) {
    117         err = errno;
    118         tr_torerr( tor, "read/write failed for \"%s\": %s", file->name, tr_strerror( err ) );
    119     }
    120     else
    121         err = 0;
    122 
    123     if( ( !err ) && ( !fileExists ) && ( ioMode == TR_IO_WRITE ) )
    124         tr_statsFileCreated( tor->session );
     94    fd = tr_fdFileGetCached( tr_torrentId( tor ), fileIndex, doWrite );
     95
     96    if( fd < 0 )
     97    {
     98        /* the fd cache doesn't have this file...
     99         * we'll need to open it and maybe create it */
     100        char * name;
     101        tr_preallocation_mode preallocationMode;
     102        tr_bool fileExists;
     103   
     104        {
     105            char * path = tr_torrentFindFile( tor, fileIndex );
     106
     107            fileExists = !stat( path, &sb );
     108
     109            if( fileExists )
     110                name = tr_strdup( strstr( path, file->name ) );
     111            else
     112                name = tr_strdup_printf( "%s.part", file->name );
     113
     114            tr_free( path );
     115        }
     116
     117        if( ( file->dnd ) || ( ioMode != TR_IO_WRITE ) )
     118            preallocationMode = TR_PREALLOCATE_NONE;
     119        else
     120            preallocationMode = tor->session->preallocationMode;
     121
     122        if( ( ioMode == TR_IO_READ ) && !fileExists ) /* does file exist? */
     123        {
     124            err = ENOENT;
     125        }
     126        else if( ( fd = tr_fdFileCheckout( tor->uniqueId, fileIndex, tor->currentDir, name,
     127                                           doWrite, preallocationMode, file->length ) ) < 0 )
     128        {
     129            err = errno;
     130            tr_torerr( tor, "tr_fdFileCheckout failed for \"%s\": %s", name, tr_strerror( err ) );
     131        }
     132
     133        if( doWrite && !err )
     134            tr_statsFileCreated( tor->session );
     135    }
     136
     137    if( !err )
     138    {
     139        if( tr_lseek( fd, (int64_t)fileOffset, SEEK_SET ) == -1 )
     140        {
     141            err = errno;
     142            tr_torerr( tor, "tr_lseek failed for \"%s\": %s", file->name, tr_strerror( err ) );
     143        }
     144        else if( func( fd, buf, buflen ) != buflen )
     145        {
     146            err = errno;
     147            tr_torerr( tor, "read/write failed for \"%s\": %s", file->name, tr_strerror( err ) );
     148        }
     149    }
    125150
    126151    return err;
  • trunk/libtransmission/peer-mgr.c

    r9239 r9328  
    2626#include "completion.h"
    2727#include "crypto.h"
    28 #include "fdlimit.h"
    2928#include "handshake.h"
    3029#include "inout.h" /* tr_ioTestPiece */
     
    11561155                        tr_peerMsgsHave( peers[i]->msgs, p );
    11571156
    1158                     for( fileIndex=0; fileIndex<tor->info.fileCount; ++fileIndex )
    1159                     {
     1157                    for( fileIndex=0; fileIndex<tor->info.fileCount; ++fileIndex ) {
    11601158                        const tr_file * file = &tor->info.files[fileIndex];
    1161                         if( ( file->firstPiece <= p ) && ( p <= file->lastPiece ) && tr_cpFileIsComplete( &tor->completion, fileIndex ) )
    1162                         {
    1163                             char * path = tr_buildPath( tor->downloadDir, file->name, NULL );
    1164                             tordbg( t, "closing recently-completed file \"%s\"", path );
    1165                             tr_fdFileClose( path );
    1166                             tr_free( path );
    1167                         }
     1159                        if( ( file->firstPiece <= p ) && ( p <= file->lastPiece ) )
     1160                            if( tr_cpFileIsComplete( &tor->completion, fileIndex ) )
     1161                                tr_torrentFileCompleted( tor, fileIndex );
    11681162                    }
    11691163                }
    1170 
    1171                 tr_torrentRecheckCompleteness( tor );
    11721164            }
    11731165            break;
  • trunk/libtransmission/resume.c

    r9218 r9328  
    1818#include "bencode.h"
    1919#include "completion.h"
    20 #include "fastresume.h"
    2120#include "peer-mgr.h" /* pex */
    2221#include "platform.h" /* tr_getResumeDir */
     
    3332#define KEY_DND                 "dnd"
    3433#define KEY_DOWNLOADED          "downloaded"
     34#define KEY_INCOMPLETE_DIR      "incomplete-dir"
    3535#define KEY_MAX_PEERS           "max-peers"
    3636#define KEY_PAUSED              "paused"
     
    504504    tr_tordbg( tor, "Saving .resume file for \"%s\"", tr_torrentName( tor ) );
    505505
    506     tr_bencInitDict( &top, 32 ); /* arbitrary "big enough" number */
    507     tr_bencDictAddInt( &top, KEY_ACTIVITY_DATE,
    508                        tor->activityDate );
    509     tr_bencDictAddInt( &top, KEY_ADDED_DATE,
    510                        tor->addedDate );
    511     tr_bencDictAddInt( &top, KEY_CORRUPT,
    512                        tor->corruptPrev + tor->corruptCur );
    513     tr_bencDictAddInt( &top, KEY_DONE_DATE,
    514                        tor->doneDate );
    515     tr_bencDictAddStr( &top, KEY_DOWNLOAD_DIR,
    516                        tor->downloadDir );
    517     tr_bencDictAddInt( &top, KEY_DOWNLOADED,
    518                        tor->downloadedPrev + tor->downloadedCur );
    519     tr_bencDictAddInt( &top, KEY_UPLOADED,
    520                        tor->uploadedPrev + tor->uploadedCur );
    521     tr_bencDictAddInt( &top, KEY_MAX_PEERS,
    522                        tor->maxConnectedPeers );
    523     tr_bencDictAddInt( &top, KEY_BANDWIDTH_PRIORITY,
    524                        tr_torrentGetPriority( tor ) );
     506    tr_bencInitDict( &top, 33 ); /* arbitrary "big enough" number */
     507    tr_bencDictAddInt( &top, KEY_ACTIVITY_DATE, tor->activityDate );
     508    tr_bencDictAddInt( &top, KEY_ADDED_DATE, tor->addedDate );
     509    tr_bencDictAddInt( &top, KEY_CORRUPT, tor->corruptPrev + tor->corruptCur );
     510    tr_bencDictAddInt( &top, KEY_DONE_DATE, tor->doneDate );
     511    tr_bencDictAddStr( &top, KEY_DOWNLOAD_DIR, tor->downloadDir );
     512    if( tor->incompleteDir != NULL )
     513        tr_bencDictAddStr( &top, KEY_INCOMPLETE_DIR, tor->incompleteDir );
     514    tr_bencDictAddInt( &top, KEY_DOWNLOADED, tor->downloadedPrev + tor->downloadedCur );
     515    tr_bencDictAddInt( &top, KEY_UPLOADED, tor->uploadedPrev + tor->uploadedCur );
     516    tr_bencDictAddInt( &top, KEY_MAX_PEERS, tor->maxConnectedPeers );
     517    tr_bencDictAddInt( &top, KEY_BANDWIDTH_PRIORITY, tr_torrentGetPriority( tor ) );
    525518    tr_bencDictAddBool( &top, KEY_PAUSED, !tor->isRunning );
    526519    savePeers( &top, tor );
     
    556549    if( tr_bencLoadFile( &top, TR_FMT_BENC, filename ) )
    557550    {
    558         tr_tordbg( tor, "Couldn't read \"%s\"; trying old format.",
    559                    filename );
    560         fieldsLoaded = tr_fastResumeLoad( tor, fieldsToLoad );
    561 
    562         if( ( fieldsLoaded != 0 ) && ( fieldsToLoad == ~(uint64_t)0 ) )
    563         {
    564             tr_torrentSaveResume( tor );
    565             tr_fastResumeRemove( tor );
    566             tr_tordbg( tor, "Migrated resume file to \"%s\"", filename );
    567         }
     551        tr_tordbg( tor, "Couldn't read \"%s\"", filename );
    568552
    569553        tr_free( filename );
     
    587571        tor->downloadDir = tr_strdup( str );
    588572        fieldsLoaded |= TR_FR_DOWNLOAD_DIR;
     573    }
     574
     575    if( ( fieldsToLoad & ( TR_FR_PROGRESS | TR_FR_INCOMPLETE_DIR ) )
     576      && ( tr_bencDictFindStr( &top, KEY_INCOMPLETE_DIR, &str ) )
     577      && ( str && *str ) )
     578    {
     579        tr_free( tor->incompleteDir );
     580        tor->incompleteDir = tr_strdup( str );
     581        fieldsLoaded |= TR_FR_INCOMPLETE_DIR;
    589582    }
    590583
     
    748741{
    749742    char * filename = getResumeFilename( tor );
    750 
    751743    unlink( filename );
    752     tr_fastResumeRemove( tor );
    753744    tr_free( filename );
    754745}
  • trunk/libtransmission/resume.h

    r8254 r9328  
    3131    TR_FR_RUN                 = ( 1 << 9 ),
    3232    TR_FR_DOWNLOAD_DIR        = ( 1 << 10 ),
    33     TR_FR_MAX_PEERS           = ( 1 << 11 ),
    34     TR_FR_ADDED_DATE          = ( 1 << 12 ),
    35     TR_FR_DONE_DATE           = ( 1 << 13 ),
    36     TR_FR_ACTIVITY_DATE       = ( 1 << 14 ),
    37     TR_FR_RATIOLIMIT          = ( 1 << 15 )
     33    TR_FR_INCOMPLETE_DIR      = ( 1 << 11 ),
     34    TR_FR_MAX_PEERS           = ( 1 << 12 ),
     35    TR_FR_ADDED_DATE          = ( 1 << 13 ),
     36    TR_FR_DONE_DATE           = ( 1 << 14 ),
     37    TR_FR_ACTIVITY_DATE       = ( 1 << 15 ),
     38    TR_FR_RATIOLIMIT          = ( 1 << 16 )
    3839};
    3940
  • trunk/libtransmission/session.c

    r9189 r9328  
    348348
    349349void
    350 tr_sessionGetDefaultSettings( tr_benc * d )
    351 {
     350tr_sessionGetDefaultSettings( const char * configDir, tr_benc * d )
     351{
     352    char * incompleteDir = tr_buildPath( configDir, "Incomplete", NULL );
     353
    352354    assert( tr_bencIsDict( d ) );
    353355
     
    359361    tr_bencDictAddBool( d, TR_PREFS_KEY_DSPEED_ENABLED,           FALSE );
    360362    tr_bencDictAddInt ( d, TR_PREFS_KEY_ENCRYPTION,               TR_DEFAULT_ENCRYPTION );
     363    tr_bencDictAddStr ( d, TR_PREFS_KEY_INCOMPLETE_DIR,           incompleteDir );
     364    tr_bencDictAddBool( d, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED,   FALSE );
    361365    tr_bencDictAddBool( d, TR_PREFS_KEY_LAZY_BITFIELD,            TRUE );
    362366    tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL,                 TR_MSG_INF );
     
    402406    tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV4,        TR_DEFAULT_BIND_ADDRESS_IPV4 );
    403407    tr_bencDictAddStr ( d, TR_PREFS_KEY_BIND_ADDRESS_IPV6,        TR_DEFAULT_BIND_ADDRESS_IPV6 );
     408
     409    tr_free( incompleteDir );
    404410}
    405411
     
    416422    tr_bencDictAddBool( d, TR_PREFS_KEY_DSPEED_ENABLED,           tr_sessionIsSpeedLimited( s, TR_DOWN ) );
    417423    tr_bencDictAddInt ( d, TR_PREFS_KEY_ENCRYPTION,               s->encryptionMode );
     424    tr_bencDictAddStr ( d, TR_PREFS_KEY_INCOMPLETE_DIR,           tr_sessionGetIncompleteDir( s ) );
     425    tr_bencDictAddBool( d, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED,   tr_sessionGetIncompleteDirEnabled( s ) );
    418426    tr_bencDictAddBool( d, TR_PREFS_KEY_LAZY_BITFIELD,            s->useLazyBitfield );
    419427    tr_bencDictAddInt ( d, TR_PREFS_KEY_MSGLEVEL,                 tr_getMessageLevel( ) );
     
    474482     * preserve those and use the session defaults to fill in any missing gaps. */
    475483    tr_bencInitDict( &sessionDefaults, 0 );
    476     tr_sessionGetDefaultSettings( &sessionDefaults );
     484    tr_sessionGetDefaultSettings( configDir, &sessionDefaults );
    477485    tr_bencMergeDicts( &sessionDefaults, d );
    478486    tmp = *d; *d = sessionDefaults; sessionDefaults = tmp;
     
    635643
    636644    tr_bencInitDict( &settings, 0 );
    637     tr_sessionGetDefaultSettings( &settings );
     645    tr_sessionGetDefaultSettings( data->configDir, &settings );
    638646    tr_bencMergeDicts( &settings, clientSettings );
    639647
     
    684692    assert( found );
    685693    session->downloadDir = tr_strdup( str );
     694
     695    found = tr_bencDictFindStr( &settings, TR_PREFS_KEY_INCOMPLETE_DIR, &str );
     696    assert( found );
     697    tr_sessionSetIncompleteDir( session, str );
     698
     699    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED, &boolVal );
     700    assert( found );
     701    tr_sessionSetIncompleteDirEnabled( session, boolVal );
    686702
    687703    found = tr_bencDictFindBool( &settings, TR_PREFS_KEY_PROXY_ENABLED, &boolVal );
     
    909925
    910926    return session->downloadDir;
     927}
     928
     929/***
     930****
     931***/
     932
     933void
     934tr_sessionSetIncompleteDir( tr_session * session, const char * dir )
     935{
     936    assert( tr_isSession( session ) );
     937
     938    if( session->incompleteDir != dir )
     939    {
     940        tr_free( session->incompleteDir );
     941
     942        session->incompleteDir = tr_strdup( dir );
     943
     944        tr_mkdirp( session->incompleteDir, 0777 );
     945    }
     946}
     947
     948const char*
     949tr_sessionGetIncompleteDir( const tr_session * session )
     950{
     951    assert( tr_isSession( session ) );
     952
     953    return session->incompleteDir;
     954}
     955
     956void
     957tr_sessionSetIncompleteDirEnabled( tr_session * session, tr_bool b )
     958{
     959    assert( tr_isSession( session ) );
     960    assert( tr_isBool( b ) );
     961
     962    session->isIncompleteDirEnabled = b;
     963}
     964
     965tr_bool
     966tr_sessionGetIncompleteDirEnabled( const tr_session * session )
     967{
     968    assert( tr_isSession( session ) );
     969
     970    return session->isIncompleteDirEnabled;
    911971}
    912972
  • trunk/libtransmission/session.h

    r9170 r9328  
    5353    tr_bool                      useLazyBitfield;
    5454    tr_bool                      isRatioLimited;
     55    tr_bool                      isIncompleteDirEnabled;
    5556
    5657    tr_benc                      removedTorrents;
     
    102103    char *                       resumeDir;
    103104    char *                       torrentDir;
     105    char *                       incompleteDir;
    104106
    105107    tr_proxy_type                proxyType;
  • trunk/libtransmission/torrent.c

    r9276 r9328  
    551551}
    552552
     553static void refreshCurrentDir( tr_torrent * tor );;
     554
    553555static void
    554556torrentRealInit( tr_torrent * tor, const tr_ctor * ctor )
     
    579581        !tr_ctorGetDownloadDir( ctor, TR_FALLBACK, &dir ) )
    580582            tor->downloadDir = tr_strdup( dir );
     583
     584    if( tr_sessionGetIncompleteDirEnabled( session ) )
     585        tor->incompleteDir = tr_strdup( tr_sessionGetIncompleteDir( session ) );
    581586
    582587    tor->lastPieceSize = info->totalSize % info->pieceSize;
     
    643648    loaded = tr_torrentLoadResume( tor, ~0, ctor );
    644649
     650    refreshCurrentDir( tor );
     651
    645652    doStart = tor->isRunning;
    646653    tor->isRunning = 0;
     
    775782        tr_torrentSetDirty( tor );
    776783    }
     784
     785    refreshCurrentDir( tor );
    777786}
    778787
     
    12421251
    12431252    tr_free( tor->downloadDir );
     1253    tr_free( tor->incompleteDir );
    12441254    tr_free( tor->peer_id );
    12451255
     
    15971607        tor->needsSeedRatioCheck = TRUE;
    15981608        tr_fdTorrentClose( tor->uniqueId );
     1609
     1610        /* if the torrent is a seed now,
     1611         * and the files used to be in the incompleteDir,
     1612         * then move them to the destination directory */
     1613        if( tr_torrentIsSeed( tor ) && ( tor->currentDir == tor->incompleteDir ) )
     1614            tr_torrentSetLocation( tor, tor->downloadDir, TRUE, NULL, NULL );
     1615
    15991616        fireCompletenessChange( tor, completeness );
    16001617
     
    19801997
    19811998time_t*
    1982 tr_torrentGetMTimes( const tr_torrent * tor,
    1983                      size_t *           setme_n )
     1999tr_torrentGetMTimes( const tr_torrent * tor, size_t * setme_n )
    19842000{
    19852001    size_t       i;
     
    19922008    {
    19932009        struct stat sb;
    1994         char * path = tr_buildPath( tor->downloadDir, tor->info.files[i].name, NULL );
    1995         if( !stat( path, &sb ) )
     2010        char * path = tr_torrentFindFile( tor, i );
     2011        if( ( path != NULL ) && !stat( path, &sb ) && S_ISREG( sb.st_mode ) )
    19962012        {
    19972013#ifdef SYS_DARWIN
     
    21252141tr_torrentGetBytesLeftToAllocate( const tr_torrent * tor )
    21262142{
    2127     const tr_file * it;
    2128     const tr_file * end;
    2129     struct stat sb;
     2143    tr_file_index_t i;
    21302144    uint64_t bytesLeft = 0;
    21312145
    21322146    assert( tr_isTorrent( tor ) );
    21332147
    2134     for( it=tor->info.files, end=it+tor->info.fileCount; it!=end; ++it )
    2135     {
    2136         if( !it->dnd )
     2148    for( i=0; i<tor->info.fileCount; ++i )
     2149    {
     2150        if( !tor->info.files[i].dnd )
    21372151        {
    2138             char * path = tr_buildPath( tor->downloadDir, it->name, NULL );
    2139 
    2140             bytesLeft += it->length;
    2141 
    2142             if( !stat( path, &sb )
    2143                     && S_ISREG( sb.st_mode )
    2144                     && ( (uint64_t)sb.st_size <= it->length ) )
     2152            struct stat sb;
     2153            const uint64_t length = tor->info.files[i].length;
     2154            char * path = tr_torrentFindFile( tor, i );
     2155
     2156            bytesLeft += length;
     2157
     2158            if( ( path != NULL ) && !stat( path, &sb )
     2159                                 && S_ISREG( sb.st_mode )
     2160                                 && ( (uint64_t)sb.st_size <= length ) )
    21452161                bytesLeft -= sb.st_size;
    21462162
     
    22292245        else if( S_ISREG( sb.st_mode ) && ( sb.st_size > 0 ) )
    22302246        {
    2231             const char * sub = buf + strlen( tor->downloadDir ) + strlen( TR_PATH_DELIMITER_STR );
     2247            const char * sub = buf + strlen( tor->currentDir ) + strlen( TR_PATH_DELIMITER_STR );
    22322248            const tr_bool isTorrentFile = tr_ptrArrayFindSorted( torrentFiles, sub, vstrcmp ) != NULL;
    22332249            if( !isTorrentFile )
     
    22522268    const char * cpch = strchr( firstFile, TR_PATH_DELIMITER );
    22532269    char * tmp = cpch ? tr_strndup( firstFile, cpch - firstFile ) : NULL;
    2254     char * root = tr_buildPath( tor->downloadDir, tmp, NULL );
    2255 
    2256     assert( tr_isTorrent( tor ) );
    2257 
    2258     for( f=0; f<tor->info.fileCount; ++f )
    2259         tr_ptrArrayInsertSorted( &torrentFiles, tor->info.files[f].name, vstrcmp );
     2270    char * root = tr_buildPath( tor->currentDir, tmp, NULL );
     2271
     2272    assert( tr_isTorrent( tor ) );
     2273
     2274    for( f=0; f<tor->info.fileCount; ++f ) {
     2275        tr_ptrArrayInsertSorted( &torrentFiles, tr_strdup( tor->info.files[f].name ), vstrcmp );
     2276        tr_ptrArrayInsertSorted( &torrentFiles, tr_strdup_printf( "%s.part", tor->info.files[f].name ), vstrcmp );
     2277    }
    22602278
    22612279    /* build the set of folders and dirtyFolders */
     
    22702288    /* now blow away any remaining torrent files, such as torrent files in dirty folders */
    22712289    for( f=0; f<tor->info.fileCount; ++f ) {
    2272         char * path = tr_buildPath( tor->downloadDir, tor->info.files[f].name, NULL );
     2290        char * path = tr_buildPath( tor->currentDir, tor->info.files[f].name, NULL );
    22732291        fileFunc( path );
    22742292        tr_free( path );
     
    22932311    tr_ptrArrayDestruct( &dirtyFolders, tr_free );
    22942312    tr_ptrArrayDestruct( &folders, tr_free );
    2295     tr_ptrArrayDestruct( &torrentFiles, NULL );
     2313    tr_ptrArrayDestruct( &torrentFiles, tr_free );
    22962314    tr_free( root );
    22972315    tr_free( tmp );
     
    23132331    else {
    23142332        /* torrent only has one file */
    2315         char * path = tr_buildPath( tor->downloadDir, tor->info.files[0].name, NULL );
     2333        char * path = tr_torrentFindFile( tor, 0 );
    23162334        fileFunc( path );
    23172335        tr_free( path );
     
    23222340****
    23232341***/
     2342
     2343static char*
     2344rebaseFile( const tr_torrent * tor, tr_file_index_t fileNo,
     2345            const char * existingFile, const char * newRoot )
     2346{
     2347    const char * base = strstr( existingFile, tor->info.files[fileNo].name );
     2348    assert( base != NULL );
     2349    return tr_buildPath( newRoot, base, NULL );
     2350}
    23242351
    23252352struct LocationData
     
    23452372    assert( tr_isTorrent( tor ) );
    23462373
    2347     if( strcmp( location, tor->downloadDir ) )
     2374    if( strcmp( location, tor->currentDir ) )
    23482375    {
    23492376        tr_file_index_t i;
     
    23672394            struct stat sb;
    23682395            const tr_file * f = &tor->info.files[i];
    2369             char * oldpath = tr_buildPath( tor->downloadDir, f->name, NULL );
    2370             char * newpath = tr_buildPath( location, f->name, NULL );
    2371 
    2372             if( do_move )
     2396            char * oldpath = tr_torrentFindFile( tor, i );
     2397            char * newpath = oldpath ? rebaseFile( tor, i, oldpath, location ) : NULL;
     2398
     2399            if( do_move && ( oldpath != NULL ) )
    23732400            {
    23742401                errno = 0;
     
    24842511    }
    24852512}
     2513
     2514/***
     2515****
     2516***/
     2517
     2518void
     2519tr_torrentFileCompleted( tr_torrent * tor, tr_file_index_t fileNum )
     2520{
     2521    char * oldpath = tr_torrentFindFile( tor, fileNum );
     2522    char * newpath = tr_strdup( oldpath );
     2523    char * pch = strrchr( newpath, '.' );
     2524    assert( !strcmp( pch, ".part" ) );
     2525    *pch = '\0';
     2526
     2527    /* close the file so that we can reopen in read-only mode as needed */
     2528    tr_fdFileClose( tor, fileNum );
     2529
     2530    /* strip the trailing ".part" from the filename */
     2531    if( rename( oldpath, newpath ) )
     2532        tr_torerr( tor, "Error moving \"%s\" to \"%s\": %s", oldpath, newpath, tr_strerror( errno ) );
     2533
     2534    tr_free( newpath );
     2535    tr_free( oldpath );
     2536}
     2537
     2538/***
     2539****
     2540***/
     2541
     2542enum
     2543{
     2544    TR_FILE_PARTIAL         = (1<<0),
     2545    TR_FILE_INCOMPLETE_DIR  = (1<<1)
     2546};
     2547
     2548static char*
     2549tr_torrentBuildFilename( const tr_torrent * tor, tr_file_index_t fileNo, int flags )
     2550{
     2551    const char * root;
     2552    char * base;
     2553    char * path;
     2554    const tr_bool partial = ( flags & TR_FILE_PARTIAL ) != 0;
     2555    const tr_bool incomplete = ( flags & TR_FILE_INCOMPLETE_DIR ) != 0;
     2556
     2557    assert( tr_isTorrent( tor ) );
     2558    assert( fileNo < tor->info.fileCount );
     2559
     2560    if( incomplete && ( tor->incompleteDir != NULL ) )
     2561        root = tor->incompleteDir;
     2562    else
     2563        root = tor->downloadDir;
     2564
     2565    if( partial )
     2566        base = tr_strdup_printf( "%s.part", tor->info.files[fileNo].name );
     2567    else
     2568        base = tr_strdup( tor->info.files[fileNo].name );
     2569
     2570    path = tr_buildPath( root, base, NULL );
     2571
     2572    /* cleanup */
     2573    tr_free( base );
     2574    return path;
     2575}
     2576
     2577static tr_bool
     2578fileExists( const char * filename )
     2579{
     2580    struct stat sb;
     2581    const tr_bool ok = !stat( filename, &sb );
     2582    return ok;
     2583}
     2584
     2585char*
     2586tr_torrentFindFile( const tr_torrent * tor, tr_file_index_t fileNo )
     2587{
     2588    int i;
     2589    char * filename;
     2590    int flags[4];
     2591    int n = 0;
     2592
     2593    assert( tr_isTorrent( tor ) );
     2594    assert( fileNo < tor->info.fileCount );
     2595
     2596    /* based on what we know about the torrent,
     2597     * put the most likely hits first... */
     2598    if( tr_cpFileIsComplete( &tor->completion, fileNo ) ) {
     2599        flags[n++] = 0;
     2600        flags[n++] = TR_FILE_INCOMPLETE_DIR;
     2601        flags[n++] = TR_FILE_PARTIAL;
     2602        flags[n++] = TR_FILE_INCOMPLETE_DIR|TR_FILE_PARTIAL;
     2603    } else {
     2604        flags[n++] = TR_FILE_INCOMPLETE_DIR|TR_FILE_PARTIAL;
     2605        flags[n++] = TR_FILE_PARTIAL;
     2606        flags[n++] = TR_FILE_INCOMPLETE_DIR;
     2607        flags[n++] = 0;
     2608    }
     2609       
     2610    for( i=0; i<n; ++i ) {
     2611        filename = tr_torrentBuildFilename( tor, fileNo, flags[i] );
     2612        if( fileExists( filename ))
     2613            break;
     2614        tr_free( filename );
     2615        filename = NULL;
     2616    }
     2617
     2618    return filename;
     2619}
     2620
     2621/* Decide whether we should be looking for files in downloadDir or incompleteDir. */
     2622static void
     2623refreshCurrentDir( tr_torrent * tor )
     2624{
     2625    const char * dir = tor->downloadDir;
     2626
     2627    if( tor->incompleteDir != NULL )
     2628    {
     2629        char * tmp1 = tr_torrentBuildFilename( tor, 0, 0 );
     2630        char * tmp2 = tr_torrentBuildFilename( tor, 0, TR_FILE_PARTIAL );
     2631
     2632        if( !fileExists( tmp1 ) && !fileExists( tmp2 ) )
     2633            dir = tor->incompleteDir;
     2634
     2635        tr_free( tmp2 );
     2636        tr_free( tmp1 );
     2637    }
     2638
     2639    assert( dir != NULL );
     2640    assert( ( dir == tor->downloadDir ) || ( dir == tor->incompleteDir ) );
     2641    tor->currentDir = dir;
     2642}
  • trunk/libtransmission/torrent.h

    r9170 r9328  
    158158    uint8_t * peer_id;
    159159
    160     /* Where to download */
     160    /* Where the files will be when it's complete */
    161161    char * downloadDir;
     162
     163    /* Where the files are when the torrent is incomplete */
     164    char * incompleteDir;
     165
     166    /* Where the files are now.
     167     * This pointer will be equal to downloadDir or incompleteDir */
     168    const char * currentDir;
    162169
    163170    /* How many bytes we ask for per request */
     
    348355}
    349356
     357/**
     358 * Get the file that exists on the disk, or NULL if no file exists yet.
     359 * @return the file that exists on the disk, or NULL if no file exists yet.
     360 * @param tor the torrent whose file we're using
     361 * @param fileNum the fileIndex, in [0..tor->info.fileCount)
     362 */
     363char* tr_torrentFindFile( const tr_torrent * tor, tr_file_index_t fileNo );
     364
     365/**
     366 * Tell the tr_torrent that one of its files has become complete
     367 */
     368void tr_torrentFileCompleted( tr_torrent * tor, tr_file_index_t fileNo );
     369
     370
    350371#endif
  • trunk/libtransmission/transmission.h

    r9292 r9328  
    169169#define TR_PREFS_KEY_DOWNLOAD_DIR               "download-dir"
    170170#define TR_PREFS_KEY_ENCRYPTION                 "encryption"
     171#define TR_PREFS_KEY_INCOMPLETE_DIR             "incomplete-dir"
     172#define TR_PREFS_KEY_INCOMPLETE_DIR_ENABLED     "incomplete-dir-enabled"
    171173#define TR_PREFS_KEY_LAZY_BITFIELD              "lazy-bitfield-enabled"
    172174#define TR_PREFS_KEY_MSGLEVEL                   "message-level"
     
    227229 * @see tr_getDefaultConfigDir()
    228230 */
    229 void tr_sessionGetDefaultSettings( struct tr_benc * dictionary );
     231void tr_sessionGetDefaultSettings( const char * configDir, struct tr_benc * dictionary );
    230232
    231233/**
     
    329331 */
    330332const char * tr_sessionGetDownloadDir( const tr_session * session );
     333
     334/**
     335 * @brief Set the per-session incomplete download folder
     336 * @see tr_sessionInit()
     337 * @see tr_sessionGetIncompleteDir()
     338 * @see tr_sessionSetIncompleteDirEnabled()
     339 * @see tr_sessionGetIncompleteDirEnabled()
     340 */
     341void tr_sessionSetIncompleteDir( tr_session * session, const char * dir );
     342
     343const char* tr_sessionGetIncompleteDir( const tr_session * session );
     344
     345void tr_sessionSetIncompleteDirEnabled( tr_session * session, tr_bool );
     346
     347tr_bool tr_sessionGetIncompleteDirEnabled( const tr_session * session );
    331348
    332349/**
  • trunk/libtransmission/verify.c

    r9287 r9328  
    8080        if( !filePos && (fd<0) )
    8181        {
    82             char * filename = tr_buildPath( tor->downloadDir, file->name, NULL );
    83             fd = tr_open_file_for_scanning( filename );
     82            char * filename = tr_torrentFindFile( tor, fileIndex );
     83            fd = filename == NULL ? -1 : tr_open_file_for_scanning( filename );
    8484            /* fprintf( stderr, "opening file #%d (%s) -- %d\n", fileIndex, filename, fd ); */
    8585            tr_free( filename );
     
    255255    {
    256256        struct stat sb;
    257         char * path = tr_buildPath( tor->downloadDir, tor->info.files[i].name, NULL );
    258         if( !stat( path, &sb ) && ( sb.st_size > 0 ) )
     257        char * path = tr_torrentFindFile( tor, i );
     258        if( ( path != NULL ) && !stat( path, &sb ) && ( sb.st_size > 0 ) )
    259259            hasAny = TRUE;
    260260        tr_free( path );
  • trunk/macosx/Controller.m

    r9316 r9328  
    265265        tr_benc settings;
    266266        tr_bencInitDict(&settings, 34);
    267         tr_sessionGetDefaultSettings(&settings);
     267        const char * configDir = tr_getDefaultConfigDir("Transmission");
     268        tr_sessionGetDefaultSettings(configDir, &settings);
    268269       
    269270        const BOOL usesSpeedLimitSched = [fDefaults boolForKey: @"SpeedLimitAuto"];
     
    319320        tr_bencDictAddBool(&settings, TR_PREFS_KEY_RPC_WHITELIST_ENABLED,  [fDefaults boolForKey: @"RPCUseWhitelist"]);
    320321       
    321         fLib = tr_sessionInit("macosx", tr_getDefaultConfigDir("Transmission"), YES, &settings);
     322        fLib = tr_sessionInit("macosx", configDir, YES, &settings);
    322323        tr_bencFree(&settings);
    323324       
  • trunk/qt/session.cc

    r9244 r9328  
    263263        tr_benc settings;
    264264        tr_bencInitDict( &settings, 0 );
    265         tr_sessionGetDefaultSettings( &settings );
    266265        tr_sessionLoadSettings( &settings, myConfigDir.toUtf8().constData(), "qt" );
    267266        mySession = tr_sessionInit( "qt", myConfigDir.toUtf8().constData(), true, &settings );
Note: See TracChangeset for help on using the changeset viewer.