source: trunk/libtransmission/verify.c @ 5045

Last change on this file since 5045 was 5045, checked in by charles, 14 years ago

make the code a little easier to read. make tr_ioFileTest()'s return value consistent with other inout funcs.

File size: 5.3 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: inout.c 4886 2008-02-01 01:54:04Z charles $
11 */
12
13#include <assert.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <unistd.h>
20
21#include <openssl/sha.h>
22
23#include "transmission.h"
24#include "completion.h"
25#include "crypto.h"
26#include "fastresume.h"
27#include "fdlimit.h"
28#include "inout.h"
29#include "list.h"
30#include "platform.h"
31#include "peer-mgr.h"
32#include "stats.h"
33#include "torrent.h"
34#include "utils.h"
35#include "verify.h"
36
37/**
38***
39**/
40
41struct verify_node
42{
43    tr_torrent * torrent;
44    tr_verify_done_cb verify_done_cb;
45};
46
47static void
48fireCheckDone( tr_torrent          * torrent,
49               tr_verify_done_cb    verify_done_cb )
50{
51    if( verify_done_cb != NULL )
52        (*verify_done_cb)( torrent );
53}
54
55static struct verify_node currentNode;
56
57static tr_list * verifyList = NULL;
58
59static tr_thread * verifyThread = NULL;
60
61static int stopCurrent = FALSE;
62
63static tr_lock* getVerifyLock( void )
64{
65    static tr_lock * lock = NULL;
66    if( lock == NULL )
67        lock = tr_lockNew( );
68    return lock;
69}
70
71static void
72checkFile( tr_torrent   * tor,
73           int            fileIndex,
74           int          * abortFlag )
75{
76    int i;
77    int nofile;
78    struct stat sb;
79    char path[MAX_PATH_LENGTH];
80    const tr_file * file = &tor->info.files[fileIndex];
81
82    tr_buildPath ( path, sizeof(path), tor->destination, file->name, NULL );
83    nofile = stat( path, &sb ) || !S_ISREG( sb.st_mode );
84
85    for( i=file->firstPiece; i<=file->lastPiece && i<tor->info.pieceCount && (!*abortFlag); ++i )
86    {
87        if( nofile )
88        {
89            tr_torrentSetHasPiece( tor, i, 0 );
90        }
91        else if( !tr_torrentIsPieceChecked( tor, i ) )
92        {
93            const tr_errno err = tr_ioTestPiece( tor, i );
94
95            if( !err ) /* yay */
96            {
97                tr_torrentSetHasPiece( tor, i, TRUE );
98            }
99            else
100            {
101                /* if we were wrong about it being complete,
102                 * reset and start again.  if we were right about
103                 * it being incomplete, do nothing -- we don't
104                 * want to lose blocks in those incomplete pieces */
105
106                if( tr_cpPieceIsComplete( tor->completion, i ) )
107                    tr_torrentSetHasPiece( tor, i, FALSE );
108            }
109               
110            tr_torrentSetPieceChecked( tor, i, TRUE );
111        }
112    }
113}
114
115static void
116verifyThreadFunc( void * unused UNUSED )
117{
118    for( ;; )
119    {
120        int i;
121        tr_torrent * tor;
122        struct verify_node * node;
123
124        tr_lockLock( getVerifyLock( ) );
125        stopCurrent = FALSE;
126        node = (struct verify_node*) verifyList ? verifyList->data : NULL;
127        if( node == NULL ) {
128            currentNode.torrent = NULL;
129            break;
130        }
131
132        currentNode = *node;
133        tor = currentNode.torrent;
134        tr_list_remove_data( &verifyList, node );
135        tr_free( node );
136        tr_lockUnlock( getVerifyLock( ) );
137
138        tor->verifyState = TR_VERIFY_NOW;
139
140        tr_inf( "Verifying some pieces of \"%s\"", tor->info.name );
141        for( i=0; i<tor->info.fileCount && !stopCurrent; ++i )
142            checkFile( tor, i, &stopCurrent );
143
144        tor->verifyState = TR_VERIFY_NONE;
145
146        if( !stopCurrent )
147        {
148            tr_fastResumeSave( tor );
149            fireCheckDone( tor, currentNode.verify_done_cb );
150        }
151    }
152
153    verifyThread = NULL;
154    tr_lockUnlock( getVerifyLock( ) );
155}
156
157void
158tr_verifyAdd( tr_torrent          * tor,
159              tr_verify_done_cb    verify_done_cb )
160{
161    const int uncheckedCount = tr_torrentCountUncheckedPieces( tor );
162
163    if( !uncheckedCount )
164    {
165        /* doesn't need to be checked... */
166        verify_done_cb( tor );
167    }
168    else
169    {
170        struct verify_node * node;
171
172        tr_inf( "Queueing %s to verify %d local file pieces", tor->info.name, uncheckedCount );
173
174        node = tr_new( struct verify_node, 1 );
175        node->torrent = tor;
176        node->verify_done_cb = verify_done_cb;
177
178        tr_lockLock( getVerifyLock( ) );
179        tor->verifyState = verifyList ? TR_VERIFY_WAIT : TR_VERIFY_NOW;
180        tr_list_append( &verifyList, node );
181        if( verifyThread == NULL )
182            verifyThread = tr_threadNew( verifyThreadFunc, NULL, "verifyThreadFunc" );
183        tr_lockUnlock( getVerifyLock( ) );
184    }
185}
186
187static int
188compareVerifyByTorrent( const void * va, const void * vb )
189{
190    const struct verify_node * a = va;
191    const tr_torrent * b = vb;
192    return a->torrent - b;
193}
194
195void
196tr_verifyRemove( tr_torrent * tor )
197{
198    tr_lock * lock = getVerifyLock( );
199    tr_lockLock( lock );
200
201    if( tor == currentNode.torrent )
202    {
203        stopCurrent = TRUE;
204        while( stopCurrent )
205        {
206            tr_lockUnlock( lock );
207            tr_wait( 100 );
208            tr_lockLock( lock );
209        }
210    }
211    else
212    {
213        tr_free( tr_list_remove( &verifyList, tor, compareVerifyByTorrent ) );
214        tor->verifyState = TR_VERIFY_NONE;
215    }
216
217    tr_lockUnlock( lock );
218}
Note: See TracBrowser for help on using the repository browser.