source: trunk/libtransmission/verify.c @ 8090

Last change on this file since 8090 was 8090, checked in by charles, 13 years ago

(trunk) rpc changes:

  1. new field "blocklist-size" to session-info, so RPC clients can know how big the blocklist is
  2. new method "torrent-reannounce" so RPC clients can ask the tracker for more peers
  • Property svn:keywords set to Date Rev Author Id
File size: 6.2 KB
Line 
1/*
2 * This file Copyright (C) 2007-2009 Charles Kerr <charles@transmissionbt.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: verify.c 8090 2009-03-26 18:06:54Z charles $
11 */
12
13#include <unistd.h> /* S_ISREG */
14#include <sys/stat.h>
15
16#include "transmission.h"
17#include "completion.h"
18#include "resume.h" /* tr_torrentSaveResume() */
19#include "inout.h"
20#include "list.h"
21#include "platform.h"
22#include "torrent.h"
23#include "utils.h" /* tr_buildPath */
24#include "verify.h"
25
26/**
27***
28**/
29
30struct verify_node
31{
32    tr_torrent *         torrent;
33    tr_verify_done_cb    verify_done_cb;
34};
35
36static void
37fireCheckDone( tr_torrent * tor, tr_verify_done_cb verify_done_cb )
38{
39    assert( tr_isTorrent( tor ) );
40
41    if( verify_done_cb )
42        verify_done_cb( tor );
43}
44
45static struct verify_node currentNode;
46static tr_list * verifyList = NULL;
47static tr_thread * verifyThread = NULL;
48static int stopCurrent = FALSE;
49
50static tr_lock*
51getVerifyLock( void )
52{
53    static tr_lock * lock = NULL;
54
55    if( lock == NULL )
56        lock = tr_lockNew( );
57    return lock;
58}
59
60static int
61checkFile( tr_torrent      * tor,
62           void            * buffer,
63           size_t            buflen,
64           tr_file_index_t   fileIndex,
65           int             * abortFlag )
66{
67    tr_piece_index_t i;
68    int              changed = FALSE;
69    int              nofile;
70    struct stat      sb;
71    char           * path;
72    const tr_file  * file = &tor->info.files[fileIndex];
73
74    path = tr_buildPath( tor->downloadDir, file->name, NULL );
75    nofile = stat( path, &sb ) || !S_ISREG( sb.st_mode );
76
77    for( i = file->firstPiece;
78         i <= file->lastPiece && i < tor->info.pieceCount && ( !*abortFlag );
79         ++i )
80    {
81        if( nofile )
82        {
83            tr_torrentSetHasPiece( tor, i, 0 );
84        }
85        else if( !tr_torrentIsPieceChecked( tor, i ) )
86        {
87            const int wasComplete = tr_cpPieceIsComplete( &tor->completion, i );
88
89            if( tr_ioTestPiece( tor, i, buffer, buflen ) ) /* yay */
90            {
91                tr_torrentSetHasPiece( tor, i, TRUE );
92                if( !wasComplete )
93                    changed = TRUE;
94            }
95            else
96            {
97                /* if we were wrong about it being complete,
98                 * reset and start again.  if we were right about
99                 * it being incomplete, do nothing -- we don't
100                 * want to lose blocks in those incomplete pieces */
101
102                if( wasComplete )
103                {
104                    tr_torrentSetHasPiece( tor, i, FALSE );
105                    changed = TRUE;
106                }
107            }
108        }
109
110        tr_torrentSetPieceChecked( tor, i, TRUE );
111    }
112
113    tr_free( path );
114
115    return changed;
116}
117
118static void
119verifyThreadFunc( void * unused UNUSED )
120{
121    for( ;; )
122    {
123        int                  changed = 0;
124        tr_file_index_t      i;
125        tr_torrent         * tor;
126        struct verify_node * node;
127        void               * buffer;
128
129        tr_lockLock( getVerifyLock( ) );
130        stopCurrent = FALSE;
131        node = (struct verify_node*) verifyList ? verifyList->data : NULL;
132        if( node == NULL )
133        {
134            currentNode.torrent = NULL;
135            break;
136        }
137
138        currentNode = *node;
139        tor = currentNode.torrent;
140        tr_list_remove_data( &verifyList, node );
141        tr_free( node );
142        tr_lockUnlock( getVerifyLock( ) );
143
144        tr_torinf( tor, _( "Verifying torrent" ) );
145        tr_torrentSetVerifyState( tor, TR_VERIFY_NOW );
146        buffer = tr_new( uint8_t, tor->info.pieceSize );
147        for( i = 0; i < tor->info.fileCount && !stopCurrent; ++i )
148            changed |= checkFile( tor, buffer, tor->info.pieceSize, i, &stopCurrent );
149        tr_free( buffer );
150        tr_torrentSetVerifyState( tor, TR_VERIFY_NONE );
151        assert( tr_isTorrent( tor ) );
152
153        if( !stopCurrent )
154        {
155            if( changed )
156                tr_torrentSaveResume( tor );
157            fireCheckDone( tor, currentNode.verify_done_cb );
158        }
159    }
160
161    verifyThread = NULL;
162    tr_lockUnlock( getVerifyLock( ) );
163}
164
165void
166tr_verifyAdd( tr_torrent *      tor,
167              tr_verify_done_cb verify_done_cb )
168{
169    const int uncheckedCount = tr_torrentCountUncheckedPieces( tor );
170
171    assert( tr_isTorrent( tor ) );
172
173    if( !uncheckedCount )
174    {
175        /* doesn't need to be checked... */
176        fireCheckDone( tor, verify_done_cb );
177    }
178    else
179    {
180        struct verify_node * node;
181
182        tr_torinf( tor, _( "Queued for verification" ) );
183
184        node = tr_new( struct verify_node, 1 );
185        node->torrent = tor;
186        node->verify_done_cb = verify_done_cb;
187
188        tr_lockLock( getVerifyLock( ) );
189        tr_torrentSetVerifyState( tor, verifyList ? TR_VERIFY_WAIT : TR_VERIFY_NOW );
190        tr_list_append( &verifyList, node );
191        if( verifyThread == NULL )
192            verifyThread = tr_threadNew( verifyThreadFunc, NULL );
193        tr_lockUnlock( getVerifyLock( ) );
194    }
195}
196
197static int
198compareVerifyByTorrent( const void * va,
199                        const void * vb )
200{
201    const struct verify_node * a = va;
202    const tr_torrent *         b = vb;
203
204    return a->torrent - b;
205}
206
207int
208tr_verifyInProgress( const tr_torrent * tor )
209{
210    int found = FALSE;
211    tr_lock * lock = getVerifyLock( );
212    tr_lockLock( lock );
213
214    assert( tr_isTorrent( tor ) );
215
216    found = ( tor == currentNode.torrent )
217         || ( tr_list_find( verifyList, tor, compareVerifyByTorrent ) != NULL );
218
219    tr_lockUnlock( lock );
220    return found;
221}
222
223void
224tr_verifyRemove( tr_torrent * tor )
225{
226    tr_lock * lock = getVerifyLock( );
227    tr_lockLock( lock );
228
229    assert( tr_isTorrent( tor ) );
230
231    if( tor == currentNode.torrent )
232    {
233        stopCurrent = TRUE;
234        while( stopCurrent )
235        {
236            tr_lockUnlock( lock );
237            tr_wait( 100 );
238            tr_lockLock( lock );
239        }
240    }
241    else
242    {
243        tr_free( tr_list_remove( &verifyList, tor, compareVerifyByTorrent ) );
244        tor->verifyState = TR_VERIFY_NONE;
245    }
246
247    tr_lockUnlock( lock );
248}
249
Note: See TracBrowser for help on using the repository browser.