source: trunk/libtransmission/verify.c @ 6838

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

(libT) eliminating tr_errno, part 1: make tr_ioTestPiece return an int instead of a tr_errno.

  • Property svn:keywords set to Date Rev Author Id
File size: 5.5 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 6838 2008-10-02 20:30:29Z 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 )
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*
52getVerifyLock( void )
53{
54    static tr_lock * lock = NULL;
55
56    if( lock == NULL )
57        lock = tr_lockNew( );
58    return lock;
59}
60
61static int
62checkFile( tr_torrent *    tor,
63           tr_file_index_t fileIndex,
64           int *           abortFlag )
65{
66    tr_piece_index_t i;
67    int              changed = FALSE;
68    int              nofile;
69    struct stat      sb;
70    char             path[MAX_PATH_LENGTH];
71    const tr_file *  file = &tor->info.files[fileIndex];
72
73    tr_buildPath ( path, sizeof( path ), tor->downloadDir, file->name, NULL );
74    nofile = stat( path, &sb ) || !S_ISREG( sb.st_mode );
75
76    for( i = file->firstPiece;
77         i <= file->lastPiece && i < tor->info.pieceCount && ( !*abortFlag );
78         ++i )
79    {
80        if( nofile )
81        {
82            tr_torrentSetHasPiece( tor, i, 0 );
83        }
84        else if( !tr_torrentIsPieceChecked( tor, i ) )
85        {
86            const int      wasComplete = tr_cpPieceIsComplete(
87                tor->completion, i );
88
89            if( tr_ioTestPiece( tor, i ) ) /* 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    return changed;
114}
115
116static void
117verifyThreadFunc( void * unused UNUSED )
118{
119    for( ; ; )
120    {
121        int                  changed = 0;
122        tr_file_index_t      i;
123        tr_torrent *         tor;
124        struct verify_node * node;
125
126        tr_lockLock( getVerifyLock( ) );
127        stopCurrent = FALSE;
128        node = (struct verify_node*) verifyList ? verifyList->data : NULL;
129        if( node == NULL )
130        {
131            currentNode.torrent = NULL;
132            break;
133        }
134
135        currentNode = *node;
136        tor = currentNode.torrent;
137        tr_list_remove_data( &verifyList, node );
138        tr_free( node );
139        tr_lockUnlock( getVerifyLock( ) );
140
141        tor->verifyState = TR_VERIFY_NOW;
142
143        tr_torinf( tor, _( "Verifying torrent" ) );
144        for( i = 0; i < tor->info.fileCount && !stopCurrent; ++i )
145            changed |= checkFile( tor, i, &stopCurrent );
146
147        tor->verifyState = TR_VERIFY_NONE;
148
149        if( !stopCurrent )
150        {
151            if( changed )
152                tr_torrentSaveResume( tor );
153            fireCheckDone( tor, currentNode.verify_done_cb );
154        }
155    }
156
157    verifyThread = NULL;
158    tr_lockUnlock( getVerifyLock( ) );
159}
160
161void
162tr_verifyAdd( tr_torrent *      tor,
163              tr_verify_done_cb verify_done_cb )
164{
165    const int uncheckedCount = tr_torrentCountUncheckedPieces( tor );
166
167    if( !uncheckedCount )
168    {
169        /* doesn't need to be checked... */
170        fireCheckDone( tor, verify_done_cb );
171    }
172    else
173    {
174        struct verify_node * node;
175
176        tr_torinf( tor, _( "Queued for verification" ) );
177
178        node = tr_new( struct verify_node, 1 );
179        node->torrent = tor;
180        node->verify_done_cb = verify_done_cb;
181
182        tr_lockLock( getVerifyLock( ) );
183        tor->verifyState = verifyList ? TR_VERIFY_WAIT : TR_VERIFY_NOW;
184        tr_list_append( &verifyList, node );
185        if( verifyThread == NULL )
186            verifyThread = tr_threadNew( verifyThreadFunc, NULL );
187        tr_lockUnlock( getVerifyLock( ) );
188    }
189}
190
191static int
192compareVerifyByTorrent( const void * va,
193                        const void * vb )
194{
195    const struct verify_node * a = va;
196    const tr_torrent *         b = vb;
197
198    return a->torrent - b;
199}
200
201void
202tr_verifyRemove( tr_torrent * tor )
203{
204    tr_lock * lock = getVerifyLock( );
205
206    tr_lockLock( lock );
207
208    if( tor == currentNode.torrent )
209    {
210        stopCurrent = TRUE;
211        while( stopCurrent )
212        {
213            tr_lockUnlock( lock );
214            tr_wait( 100 );
215            tr_lockLock( lock );
216        }
217    }
218    else
219    {
220        tr_free( tr_list_remove( &verifyList, tor, compareVerifyByTorrent ) );
221        tor->verifyState = TR_VERIFY_NONE;
222    }
223
224    tr_lockUnlock( lock );
225}
226
Note: See TracBrowser for help on using the repository browser.