source: trunk/libtransmission/verify.c @ 5843

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

RPC/IPC redesign

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