source: trunk/libtransmission/verify.c @ 6975

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

#1308: Transmission forgets it's verifying data

  • Property svn:keywords set to Date Rev Author Id
File size: 5.8 KB
Line 
1/*
2 * This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.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 6975 2008-10-28 15:13:07Z 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 *      torrent,
38               tr_verify_done_cb verify_done_cb )
39{
40    if( verify_done_cb )
41        verify_done_cb( torrent );
42}
43
44static struct verify_node currentNode;
45
46static tr_list *          verifyList = NULL;
47
48static tr_thread *        verifyThread = NULL;
49
50static int                stopCurrent = FALSE;
51
52static tr_lock*
53getVerifyLock( void )
54{
55    static tr_lock * lock = NULL;
56
57    if( lock == NULL )
58        lock = tr_lockNew( );
59    return lock;
60}
61
62static int
63checkFile( tr_torrent *    tor,
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(
88                tor->completion, i );
89
90            if( tr_ioTestPiece( tor, i ) ) /* yay */
91            {
92                tr_torrentSetHasPiece( tor, i, TRUE );
93                if( !wasComplete )
94                    changed = TRUE;
95            }
96            else
97            {
98                /* if we were wrong about it being complete,
99                 * reset and start again.  if we were right about
100                 * it being incomplete, do nothing -- we don't
101                 * want to lose blocks in those incomplete pieces */
102
103                if( wasComplete )
104                {
105                    tr_torrentSetHasPiece( tor, i, FALSE );
106                    changed = TRUE;
107                }
108            }
109        }
110
111        tr_torrentSetPieceChecked( tor, i, TRUE );
112    }
113
114    tr_free( path );
115
116    return changed;
117}
118
119static void
120verifyThreadFunc( void * unused UNUSED )
121{
122    for( ; ; )
123    {
124        int                  changed = 0;
125        tr_file_index_t      i;
126        tr_torrent *         tor;
127        struct verify_node * node;
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        tor->verifyState = TR_VERIFY_NOW;
145
146        tr_torinf( tor, _( "Verifying torrent" ) );
147        for( i = 0; i < tor->info.fileCount && !stopCurrent; ++i )
148            changed |= checkFile( tor, i, &stopCurrent );
149
150        tor->verifyState = TR_VERIFY_NONE;
151
152        if( !stopCurrent )
153        {
154            if( changed )
155                tr_torrentSaveResume( tor );
156            fireCheckDone( tor, currentNode.verify_done_cb );
157        }
158    }
159
160    verifyThread = NULL;
161    tr_lockUnlock( getVerifyLock( ) );
162}
163
164void
165tr_verifyAdd( tr_torrent *      tor,
166              tr_verify_done_cb verify_done_cb )
167{
168    const int uncheckedCount = tr_torrentCountUncheckedPieces( tor );
169
170    if( !uncheckedCount )
171    {
172        /* doesn't need to be checked... */
173        fireCheckDone( tor, verify_done_cb );
174    }
175    else
176    {
177        struct verify_node * node;
178
179        tr_torinf( tor, _( "Queued for verification" ) );
180
181        node = tr_new( struct verify_node, 1 );
182        node->torrent = tor;
183        node->verify_done_cb = verify_done_cb;
184
185        tr_lockLock( getVerifyLock( ) );
186        tor->verifyState = verifyList ? TR_VERIFY_WAIT : TR_VERIFY_NOW;
187        tr_list_append( &verifyList, node );
188        if( verifyThread == NULL )
189            verifyThread = tr_threadNew( verifyThreadFunc, NULL );
190        tr_lockUnlock( getVerifyLock( ) );
191    }
192}
193
194static int
195compareVerifyByTorrent( const void * va,
196                        const void * vb )
197{
198    const struct verify_node * a = va;
199    const tr_torrent *         b = vb;
200
201    return a->torrent - b;
202}
203
204int
205tr_verifyInProgress( const tr_torrent * tor )
206{
207    int found = FALSE;
208    tr_lock * lock = getVerifyLock( );
209    tr_lockLock( lock );
210
211    found = ( tor == currentNode.torrent )
212         || ( tr_list_find( verifyList, tor, compareVerifyByTorrent ) != NULL );
213
214    tr_lockUnlock( lock );
215    return found;
216}
217
218void
219tr_verifyRemove( tr_torrent * tor )
220{
221    tr_lock * lock = getVerifyLock( );
222
223    tr_lockLock( lock );
224
225    if( tor == currentNode.torrent )
226    {
227        stopCurrent = TRUE;
228        while( stopCurrent )
229        {
230            tr_lockUnlock( lock );
231            tr_wait( 100 );
232            tr_lockLock( lock );
233        }
234    }
235    else
236    {
237        tr_free( tr_list_remove( &verifyList, tor, compareVerifyByTorrent ) );
238        tor->verifyState = TR_VERIFY_NONE;
239    }
240
241    tr_lockUnlock( lock );
242}
243
Note: See TracBrowser for help on using the repository browser.