transmission 2.83
[tomato.git] / release / src-rt-6.x.4708 / router / transmission / libtransmission / verify.c
bloba698500b7edb00766d937cf12fa7a9ced98280f7
1 /*
2 * This file Copyright (C) 2007-2014 Mnemosyne LLC
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
7 * $Id: verify.c 14241 2014-01-21 03:10:30Z jordan $
8 */
10 #include <string.h> /* memcmp () */
11 #include <stdlib.h> /* free () */
13 #ifdef HAVE_POSIX_FADVISE
14 #define _XOPEN_SOURCE 600
15 #include <fcntl.h> /* posix_fadvise () */
16 #endif
18 #include <openssl/sha.h>
20 #include "transmission.h"
21 #include "completion.h"
22 #include "fdlimit.h"
23 #include "list.h"
24 #include "log.h"
25 #include "platform.h" /* tr_lock () */
26 #include "torrent.h"
27 #include "utils.h" /* tr_valloc (), tr_free () */
28 #include "verify.h"
30 /***
31 ****
32 ***/
34 enum
36 MSEC_TO_SLEEP_PER_SECOND_DURING_VERIFY = 100
39 static bool
40 verifyTorrent (tr_torrent * tor, bool * stopFlag)
42 time_t end;
43 SHA_CTX sha;
44 int fd = -1;
45 int64_t filePos = 0;
46 bool changed = 0;
47 bool hadPiece = 0;
48 time_t lastSleptAt = 0;
49 uint32_t piecePos = 0;
50 tr_file_index_t fileIndex = 0;
51 tr_file_index_t prevFileIndex = !fileIndex;
52 tr_piece_index_t pieceIndex = 0;
53 const time_t begin = tr_time ();
54 const size_t buflen = 1024 * 128; /* 128 KiB buffer */
55 uint8_t * buffer = tr_valloc (buflen);
57 SHA1_Init (&sha);
59 tr_logAddTorDbg (tor, "%s", "verifying torrent...");
60 tr_torrentSetChecked (tor, 0);
61 while (!*stopFlag && (pieceIndex < tor->info.pieceCount))
63 uint32_t leftInPiece;
64 uint32_t bytesThisPass;
65 uint64_t leftInFile;
66 const tr_file * file = &tor->info.files[fileIndex];
68 /* if we're starting a new piece... */
69 if (piecePos == 0)
70 hadPiece = tr_torrentPieceIsComplete (tor, pieceIndex);
72 /* if we're starting a new file... */
73 if (!filePos && (fd<0) && (fileIndex!=prevFileIndex))
75 char * filename = tr_torrentFindFile (tor, fileIndex);
76 fd = filename == NULL ? -1 : tr_open_file_for_scanning (filename);
77 tr_free (filename);
78 prevFileIndex = fileIndex;
81 /* figure out how much we can read this pass */
82 leftInPiece = tr_torPieceCountBytes (tor, pieceIndex) - piecePos;
83 leftInFile = file->length - filePos;
84 bytesThisPass = MIN (leftInFile, leftInPiece);
85 bytesThisPass = MIN (bytesThisPass, buflen);
87 /* read a bit */
88 if (fd >= 0)
90 const ssize_t numRead = tr_pread (fd, buffer, bytesThisPass, filePos);
91 if (numRead > 0)
93 bytesThisPass = (uint32_t)numRead;
94 SHA1_Update (&sha, buffer, bytesThisPass);
95 #if defined HAVE_POSIX_FADVISE && defined POSIX_FADV_DONTNEED
96 posix_fadvise (fd, filePos, bytesThisPass, POSIX_FADV_DONTNEED);
97 #endif
101 /* move our offsets */
102 leftInPiece -= bytesThisPass;
103 leftInFile -= bytesThisPass;
104 piecePos += bytesThisPass;
105 filePos += bytesThisPass;
107 /* if we're finishing a piece... */
108 if (leftInPiece == 0)
110 time_t now;
111 bool hasPiece;
112 uint8_t hash[SHA_DIGEST_LENGTH];
114 SHA1_Final (hash, &sha);
115 hasPiece = !memcmp (hash, tor->info.pieces[pieceIndex].hash, SHA_DIGEST_LENGTH);
117 if (hasPiece || hadPiece)
119 tr_torrentSetHasPiece (tor, pieceIndex, hasPiece);
120 changed |= hasPiece != hadPiece;
123 tr_torrentSetPieceChecked (tor, pieceIndex);
124 now = tr_time ();
125 tor->anyDate = now;
127 /* sleeping even just a few msec per second goes a long
128 * way towards reducing IO load... */
129 if (lastSleptAt != now)
131 lastSleptAt = now;
132 tr_wait_msec (MSEC_TO_SLEEP_PER_SECOND_DURING_VERIFY);
135 SHA1_Init (&sha);
136 pieceIndex++;
137 piecePos = 0;
140 /* if we're finishing a file... */
141 if (leftInFile == 0)
143 if (fd >= 0)
145 tr_close_file (fd);
146 fd = -1;
148 fileIndex++;
149 filePos = 0;
153 /* cleanup */
154 if (fd >= 0)
155 tr_close_file (fd);
156 free (buffer);
158 /* stopwatch */
159 end = tr_time ();
160 tr_logAddTorDbg (tor, "Verification is done. It took %d seconds to verify %"PRIu64" bytes (%"PRIu64" bytes per second)",
161 (int)(end-begin), tor->info.totalSize,
162 (uint64_t)(tor->info.totalSize/ (1+ (end-begin))));
164 return changed;
167 /***
168 ****
169 ***/
171 struct verify_node
173 tr_torrent * torrent;
174 tr_verify_done_func callback_func;
175 void * callback_data;
176 uint64_t current_size;
179 static struct verify_node currentNode;
180 static tr_list * verifyList = NULL;
181 static tr_thread * verifyThread = NULL;
182 static bool stopCurrent = false;
184 static tr_lock*
185 getVerifyLock (void)
187 static tr_lock * lock = NULL;
189 if (lock == NULL)
190 lock = tr_lockNew ();
192 return lock;
195 static void
196 verifyThreadFunc (void * unused UNUSED)
198 for (;;)
200 int changed = 0;
201 tr_torrent * tor;
202 struct verify_node * node;
204 tr_lockLock (getVerifyLock ());
205 stopCurrent = false;
206 node = (struct verify_node*) verifyList ? verifyList->data : NULL;
207 if (node == NULL)
209 currentNode.torrent = NULL;
210 break;
213 currentNode = *node;
214 tor = currentNode.torrent;
215 tr_list_remove_data (&verifyList, node);
216 tr_free (node);
217 tr_lockUnlock (getVerifyLock ());
219 tr_logAddTorInfo (tor, "%s", _("Verifying torrent"));
220 tr_torrentSetVerifyState (tor, TR_VERIFY_NOW);
221 changed = verifyTorrent (tor, &stopCurrent);
222 tr_torrentSetVerifyState (tor, TR_VERIFY_NONE);
223 assert (tr_isTorrent (tor));
225 if (!stopCurrent && changed)
226 tr_torrentSetDirty (tor);
228 if (currentNode.callback_func)
229 (*currentNode.callback_func)(tor, stopCurrent, currentNode.callback_data);
232 verifyThread = NULL;
233 tr_lockUnlock (getVerifyLock ());
236 static int
237 compareVerifyByPriorityAndSize (const void * va, const void * vb)
239 const struct verify_node * a = va;
240 const struct verify_node * b = vb;
242 /* higher priority comes before lower priority */
243 const tr_priority_t pa = tr_torrentGetPriority (a->torrent);
244 const tr_priority_t pb = tr_torrentGetPriority (b->torrent);
245 if (pa != pb)
246 return pa > pb ? -1 : 1;
248 /* smaller torrents come before larger ones because they verify faster */
249 if (a->current_size < b->current_size)
250 return -1;
251 if (a->current_size > b->current_size)
252 return 1;
253 return 0;
256 void
257 tr_verifyAdd (tr_torrent * tor,
258 tr_verify_done_func callback_func,
259 void * callback_data)
261 struct verify_node * node;
263 assert (tr_isTorrent (tor));
264 tr_logAddTorInfo (tor, "%s", _("Queued for verification"));
266 node = tr_new (struct verify_node, 1);
267 node->torrent = tor;
268 node->callback_func = callback_func;
269 node->callback_data = callback_data;
270 node->current_size = tr_torrentGetCurrentSizeOnDisk (tor);
272 tr_lockLock (getVerifyLock ());
273 tr_torrentSetVerifyState (tor, TR_VERIFY_WAIT);
274 tr_list_insert_sorted (&verifyList, node, compareVerifyByPriorityAndSize);
275 if (verifyThread == NULL)
276 verifyThread = tr_threadNew (verifyThreadFunc, NULL);
277 tr_lockUnlock (getVerifyLock ());
280 static int
281 compareVerifyByTorrent (const void * va, const void * vb)
283 const struct verify_node * a = va;
284 const tr_torrent * b = vb;
285 return a->torrent - b;
288 void
289 tr_verifyRemove (tr_torrent * tor)
291 tr_lock * lock = getVerifyLock ();
292 tr_lockLock (lock);
294 assert (tr_isTorrent (tor));
296 if (tor == currentNode.torrent)
298 stopCurrent = true;
300 while (stopCurrent)
302 tr_lockUnlock (lock);
303 tr_wait_msec (100);
304 tr_lockLock (lock);
307 else
309 struct verify_node * node = tr_list_remove (&verifyList, tor, compareVerifyByTorrent);
311 tr_torrentSetVerifyState (tor, TR_VERIFY_NONE);
313 if (node != NULL)
315 if (node->callback_func != NULL)
316 (*node->callback_func)(tor, true, node->callback_data);
318 tr_free (node);
322 tr_lockUnlock (lock);
325 void
326 tr_verifyClose (tr_session * session UNUSED)
328 tr_lockLock (getVerifyLock ());
330 stopCurrent = true;
331 tr_list_free (&verifyList, tr_free);
333 tr_lockUnlock (getVerifyLock ());