source: trunk/libtransmission/verify.c @ 5042

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

modify "verify local data" to not lose the blocks in incomplete pieces

File size: 4.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: 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 int check = tr_ioTestPiece( tor, i );
94            tr_torrentSetHasPiece( tor, i, !check );
95            tr_torrentSetPieceChecked( tor, i, TRUE );
96        }
97    }
98}
99
100static void
101verifyThreadFunc( void * unused UNUSED )
102{
103    for( ;; )
104    {
105        int i;
106        tr_torrent * tor;
107        struct verify_node * node;
108
109        tr_lockLock( getVerifyLock( ) );
110        stopCurrent = FALSE;
111        node = (struct verify_node*) verifyList ? verifyList->data : NULL;
112        if( node == NULL ) {
113            currentNode.torrent = NULL;
114            break;
115        }
116
117        currentNode = *node;
118        tor = currentNode.torrent;
119        tr_list_remove_data( &verifyList, node );
120        tr_free( node );
121        tr_lockUnlock( getVerifyLock( ) );
122
123        tor->verifyState = TR_VERIFY_NOW;
124
125        tr_inf( "Verifying some pieces of \"%s\"", tor->info.name );
126        for( i=0; i<tor->info.fileCount && !stopCurrent; ++i )
127            checkFile( tor, i, &stopCurrent );
128
129        tor->verifyState = TR_VERIFY_NONE;
130
131        if( !stopCurrent )
132        {
133            tr_fastResumeSave( tor );
134            fireCheckDone( tor, currentNode.verify_done_cb );
135        }
136    }
137
138    verifyThread = NULL;
139    tr_lockUnlock( getVerifyLock( ) );
140}
141
142void
143tr_verifyAdd( tr_torrent          * tor,
144              tr_verify_done_cb    verify_done_cb )
145{
146    const int uncheckedCount = tr_torrentCountUncheckedPieces( tor );
147
148    if( !uncheckedCount )
149    {
150        /* doesn't need to be checked... */
151        verify_done_cb( tor );
152    }
153    else
154    {
155        struct verify_node * node;
156
157        tr_inf( "Queueing %s to verify %d local file pieces", tor->info.name, uncheckedCount );
158
159        node = tr_new( struct verify_node, 1 );
160        node->torrent = tor;
161        node->verify_done_cb = verify_done_cb;
162
163        tr_lockLock( getVerifyLock( ) );
164        tor->verifyState = verifyList ? TR_VERIFY_WAIT : TR_VERIFY_NOW;
165        tr_list_append( &verifyList, node );
166        if( verifyThread == NULL )
167            verifyThread = tr_threadNew( verifyThreadFunc, NULL, "verifyThreadFunc" );
168        tr_lockUnlock( getVerifyLock( ) );
169    }
170}
171
172static int
173compareVerifyByTorrent( const void * va, const void * vb )
174{
175    const struct verify_node * a = va;
176    const tr_torrent * b = vb;
177    return a->torrent - b;
178}
179
180void
181tr_verifyRemove( tr_torrent * tor )
182{
183    tr_lock * lock = getVerifyLock( );
184    tr_lockLock( lock );
185
186    if( tor == currentNode.torrent )
187    {
188        stopCurrent = TRUE;
189        while( stopCurrent )
190        {
191            tr_lockUnlock( lock );
192            tr_wait( 100 );
193            tr_lockLock( lock );
194        }
195    }
196    else
197    {
198        tr_free( tr_list_remove( &verifyList, tor, compareVerifyByTorrent ) );
199        tor->verifyState = TR_VERIFY_NONE;
200    }
201
202    tr_lockUnlock( lock );
203}
Note: See TracBrowser for help on using the repository browser.