Transmission: update to 2.82
[tomato.git] / release / src / router / transmission / libtransmission / torrent.c
blobe5d96c9d911c4f67cd1cc44c902fcbcb47d14aa3
1 /*
2 * This file Copyright (C) Mnemosyne LLC
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.
10 * $Id: torrent.c 14156 2013-08-05 13:07:23Z jordan $
13 #include <signal.h> /* signal () */
14 #include <sys/types.h> /* stat */
15 #include <sys/stat.h> /* stat */
16 #ifndef WIN32
17 #include <sys/wait.h> /* wait () */
18 #else
19 #include <process.h>
20 #endif
21 #include <unistd.h> /* stat */
22 #include <dirent.h>
24 #include <assert.h>
25 #include <math.h>
26 #include <stdarg.h>
27 #include <string.h> /* memcmp */
28 #include <stdlib.h> /* qsort */
30 #include <event2/util.h> /* evutil_vsnprintf () */
32 #include "transmission.h"
33 #include "announcer.h"
34 #include "bandwidth.h"
35 #include "cache.h"
36 #include "completion.h"
37 #include "crypto.h" /* for tr_sha1 */
38 #include "resume.h"
39 #include "fdlimit.h" /* tr_fdTorrentClose */
40 #include "inout.h" /* tr_ioTestPiece () */
41 #include "log.h"
42 #include "magnet.h"
43 #include "metainfo.h"
44 #include "peer-common.h" /* MAX_BLOCK_SIZE */
45 #include "peer-mgr.h"
46 #include "platform.h" /* TR_PATH_DELIMITER_STR */
47 #include "ptrarray.h"
48 #include "session.h"
49 #include "torrent.h"
50 #include "torrent-magnet.h"
51 #include "trevent.h" /* tr_runInEventThread () */
52 #include "utils.h"
53 #include "variant.h"
54 #include "verify.h"
55 #include "version.h"
57 /***
58 ****
59 ***/
61 #define tr_deeplog_tor(tor, ...) \
62 do \
63 { \
64 if (tr_logGetDeepEnabled ()) \
65 tr_logAddDeep (__FILE__, __LINE__, tr_torrentName (tor), __VA_ARGS__); \
66 } \
67 while (0)
69 /***
70 ****
71 ***/
73 const char *
74 tr_torrentName (const tr_torrent * tor)
76 return tor ? tor->info.name : "";
79 int
80 tr_torrentId (const tr_torrent * tor)
82 return tor ? tor->uniqueId : -1;
85 tr_torrent*
86 tr_torrentFindFromId (tr_session * session, int id)
88 tr_torrent * tor = NULL;
90 while ((tor = tr_torrentNext (session, tor)))
91 if (tor->uniqueId == id)
92 return tor;
94 return NULL;
97 tr_torrent*
98 tr_torrentFindFromHashString (tr_session * session, const char * str)
100 tr_torrent * tor = NULL;
102 while ((tor = tr_torrentNext (session, tor)))
103 if (!evutil_ascii_strcasecmp (str, tor->info.hashString))
104 return tor;
106 return NULL;
109 tr_torrent*
110 tr_torrentFindFromHash (tr_session * session, const uint8_t * torrentHash)
112 tr_torrent * tor = NULL;
114 while ((tor = tr_torrentNext (session, tor)))
115 if (*tor->info.hash == *torrentHash)
116 if (!memcmp (tor->info.hash, torrentHash, SHA_DIGEST_LENGTH))
117 return tor;
119 return NULL;
122 tr_torrent*
123 tr_torrentFindFromMagnetLink (tr_session * session, const char * magnet)
125 tr_magnet_info * info;
126 tr_torrent * tor = NULL;
128 if ((info = tr_magnetParse (magnet)))
130 tor = tr_torrentFindFromHash (session, info->hash);
131 tr_magnetFree (info);
134 return tor;
137 tr_torrent*
138 tr_torrentFindFromObfuscatedHash (tr_session * session,
139 const uint8_t * obfuscatedTorrentHash)
141 tr_torrent * tor = NULL;
143 while ((tor = tr_torrentNext (session, tor)))
144 if (!memcmp (tor->obfuscatedHash, obfuscatedTorrentHash, SHA_DIGEST_LENGTH))
145 return tor;
147 return NULL;
150 bool
151 tr_torrentIsPieceTransferAllowed (const tr_torrent * tor,
152 tr_direction direction)
154 bool allowed = true;
155 unsigned int limit;
157 assert (tr_isTorrent (tor));
158 assert (tr_isDirection (direction));
160 if (tr_torrentUsesSpeedLimit (tor, direction))
161 if (tr_torrentGetSpeedLimit_Bps (tor, direction) <= 0)
162 allowed = false;
164 if (tr_torrentUsesSessionLimits (tor))
165 if (tr_sessionGetActiveSpeedLimit_Bps (tor->session, direction, &limit))
166 if (limit <= 0)
167 allowed = false;
169 return allowed;
172 /***
173 ****
174 ***/
176 static void
177 tr_torrentUnsetPeerId (tr_torrent * tor)
179 /* triggers a rebuild next time tr_torrentGetPeerId() is called */
180 *tor->peer_id = '\0';
183 static int
184 peerIdTTL (const tr_torrent * tor)
186 int ttl;
188 if (!tor->peer_id_creation_time)
189 ttl = 0;
190 else
191 ttl = (int)difftime(tor->peer_id_creation_time+(tor->session->peer_id_ttl_hours*3600), tr_time());
193 return ttl;
196 const unsigned char *
197 tr_torrentGetPeerId (tr_torrent * tor)
199 bool needs_new_peer_id = false;
201 if (!*tor->peer_id)
202 needs_new_peer_id = true;
204 if (!needs_new_peer_id)
205 if (!tr_torrentIsPrivate (tor))
206 if (peerIdTTL (tor) <= 0)
207 needs_new_peer_id = true;
209 if (needs_new_peer_id)
211 tr_peerIdInit (tor->peer_id);
212 tor->peer_id_creation_time = tr_time ();
215 return tor->peer_id;
217 /***
218 **** PER-TORRENT UL / DL SPEEDS
219 ***/
221 void
222 tr_torrentSetSpeedLimit_Bps (tr_torrent * tor, tr_direction dir, unsigned int Bps)
224 assert (tr_isTorrent (tor));
225 assert (tr_isDirection (dir));
227 if (tr_bandwidthSetDesiredSpeed_Bps (&tor->bandwidth, dir, Bps))
228 tr_torrentSetDirty (tor);
230 void
231 tr_torrentSetSpeedLimit_KBps (tr_torrent * tor, tr_direction dir, unsigned int KBps)
233 tr_torrentSetSpeedLimit_Bps (tor, dir, toSpeedBytes (KBps));
236 unsigned int
237 tr_torrentGetSpeedLimit_Bps (const tr_torrent * tor, tr_direction dir)
239 assert (tr_isTorrent (tor));
240 assert (tr_isDirection (dir));
242 return tr_bandwidthGetDesiredSpeed_Bps (&tor->bandwidth, dir);
244 unsigned int
245 tr_torrentGetSpeedLimit_KBps (const tr_torrent * tor, tr_direction dir)
247 assert (tr_isTorrent (tor));
248 assert (tr_isDirection (dir));
250 return toSpeedKBps (tr_torrentGetSpeedLimit_Bps (tor, dir));
253 void
254 tr_torrentUseSpeedLimit (tr_torrent * tor, tr_direction dir, bool do_use)
256 assert (tr_isTorrent (tor));
257 assert (tr_isDirection (dir));
259 if (tr_bandwidthSetLimited (&tor->bandwidth, dir, do_use))
260 tr_torrentSetDirty (tor);
263 bool
264 tr_torrentUsesSpeedLimit (const tr_torrent * tor, tr_direction dir)
266 assert (tr_isTorrent (tor));
268 return tr_bandwidthIsLimited (&tor->bandwidth, dir);
271 void
272 tr_torrentUseSessionLimits (tr_torrent * tor, bool doUse)
274 bool changed;
276 assert (tr_isTorrent (tor));
278 changed = tr_bandwidthHonorParentLimits (&tor->bandwidth, TR_UP, doUse);
279 changed |= tr_bandwidthHonorParentLimits (&tor->bandwidth, TR_DOWN, doUse);
281 if (changed)
282 tr_torrentSetDirty (tor);
285 bool
286 tr_torrentUsesSessionLimits (const tr_torrent * tor)
288 assert (tr_isTorrent (tor));
290 return tr_bandwidthAreParentLimitsHonored (&tor->bandwidth, TR_UP);
293 /***
294 ****
295 ***/
297 void
298 tr_torrentSetRatioMode (tr_torrent * tor, tr_ratiolimit mode)
300 assert (tr_isTorrent (tor));
301 assert (mode==TR_RATIOLIMIT_GLOBAL || mode==TR_RATIOLIMIT_SINGLE || mode==TR_RATIOLIMIT_UNLIMITED);
303 if (mode != tor->ratioLimitMode)
305 tor->ratioLimitMode = mode;
307 tr_torrentSetDirty (tor);
311 tr_ratiolimit
312 tr_torrentGetRatioMode (const tr_torrent * tor)
314 assert (tr_isTorrent (tor));
316 return tor->ratioLimitMode;
319 void
320 tr_torrentSetRatioLimit (tr_torrent * tor, double desiredRatio)
322 assert (tr_isTorrent (tor));
324 if ((int)(desiredRatio*100.0) != (int)(tor->desiredRatio*100.0))
326 tor->desiredRatio = desiredRatio;
328 tr_torrentSetDirty (tor);
332 double
333 tr_torrentGetRatioLimit (const tr_torrent * tor)
335 assert (tr_isTorrent (tor));
337 return tor->desiredRatio;
340 bool
341 tr_torrentGetSeedRatio (const tr_torrent * tor, double * ratio)
343 bool isLimited;
345 assert (tr_isTorrent (tor));
347 switch (tr_torrentGetRatioMode (tor))
349 case TR_RATIOLIMIT_SINGLE:
350 isLimited = true;
351 if (ratio)
352 *ratio = tr_torrentGetRatioLimit (tor);
353 break;
355 case TR_RATIOLIMIT_GLOBAL:
356 isLimited = tr_sessionIsRatioLimited (tor->session);
357 if (isLimited && ratio)
358 *ratio = tr_sessionGetRatioLimit (tor->session);
359 break;
361 default: /* TR_RATIOLIMIT_UNLIMITED */
362 isLimited = false;
363 break;
366 return isLimited;
369 /* returns true if the seed ratio applies --
370 * it applies if the torrent's a seed AND it has a seed ratio set */
371 static bool
372 tr_torrentGetSeedRatioBytes (const tr_torrent * tor,
373 uint64_t * setmeLeft,
374 uint64_t * setmeGoal)
376 double seedRatio;
377 bool seedRatioApplies = false;
379 assert (tr_isTorrent (tor));
381 if (tr_torrentGetSeedRatio (tor, &seedRatio))
383 const uint64_t u = tor->uploadedCur + tor->uploadedPrev;
384 const uint64_t d = tor->downloadedCur + tor->downloadedPrev;
385 const uint64_t baseline = d ? d : tr_cpSizeWhenDone (&tor->completion);
386 const uint64_t goal = baseline * seedRatio;
387 if (setmeLeft) *setmeLeft = goal > u ? goal - u : 0;
388 if (setmeGoal) *setmeGoal = goal;
389 seedRatioApplies = tr_torrentIsSeed (tor);
392 return seedRatioApplies;
395 static bool
396 tr_torrentIsSeedRatioDone (const tr_torrent * tor)
398 uint64_t bytesLeft;
399 return tr_torrentGetSeedRatioBytes (tor, &bytesLeft, NULL) && !bytesLeft;
402 /***
403 ****
404 ***/
406 void
407 tr_torrentSetIdleMode (tr_torrent * tor, tr_idlelimit mode)
409 assert (tr_isTorrent (tor));
410 assert (mode==TR_IDLELIMIT_GLOBAL || mode==TR_IDLELIMIT_SINGLE || mode==TR_IDLELIMIT_UNLIMITED);
412 if (mode != tor->idleLimitMode)
414 tor->idleLimitMode = mode;
416 tr_torrentSetDirty (tor);
420 tr_idlelimit
421 tr_torrentGetIdleMode (const tr_torrent * tor)
423 assert (tr_isTorrent (tor));
425 return tor->idleLimitMode;
428 void
429 tr_torrentSetIdleLimit (tr_torrent * tor, uint16_t idleMinutes)
431 assert (tr_isTorrent (tor));
433 if (idleMinutes > 0)
435 tor->idleLimitMinutes = idleMinutes;
437 tr_torrentSetDirty (tor);
441 uint16_t
442 tr_torrentGetIdleLimit (const tr_torrent * tor)
444 assert (tr_isTorrent (tor));
446 return tor->idleLimitMinutes;
449 bool
450 tr_torrentGetSeedIdle (const tr_torrent * tor, uint16_t * idleMinutes)
452 bool isLimited;
454 switch (tr_torrentGetIdleMode (tor))
456 case TR_IDLELIMIT_SINGLE:
457 isLimited = true;
458 if (idleMinutes != NULL)
459 *idleMinutes = tr_torrentGetIdleLimit (tor);
460 break;
462 case TR_IDLELIMIT_GLOBAL:
463 isLimited = tr_sessionIsIdleLimited (tor->session);
464 if (isLimited && idleMinutes)
465 *idleMinutes = tr_sessionGetIdleLimit (tor->session);
466 break;
468 default: /* TR_IDLELIMIT_UNLIMITED */
469 isLimited = false;
470 break;
473 return isLimited;
476 static bool
477 tr_torrentIsSeedIdleLimitDone (tr_torrent * tor)
479 uint16_t idleMinutes;
480 return tr_torrentGetSeedIdle (tor, &idleMinutes)
481 && difftime (tr_time (), MAX (tor->startDate, tor->activityDate)) >= idleMinutes * 60u;
484 /***
485 ****
486 ***/
488 void
489 tr_torrentCheckSeedLimit (tr_torrent * tor)
491 assert (tr_isTorrent (tor));
493 if (!tor->isRunning || tor->isStopping || !tr_torrentIsSeed (tor))
494 return;
496 /* if we're seeding and reach our seed ratio limit, stop the torrent */
497 if (tr_torrentIsSeedRatioDone (tor))
499 tr_logAddTorInfo (tor, "%s", "Seed ratio reached; pausing torrent");
501 tor->isStopping = true;
503 /* maybe notify the client */
504 if (tor->ratio_limit_hit_func != NULL)
505 tor->ratio_limit_hit_func (tor, tor->ratio_limit_hit_func_user_data);
507 /* if we're seeding and reach our inactiviy limit, stop the torrent */
508 else if (tr_torrentIsSeedIdleLimitDone (tor))
510 tr_logAddTorInfo (tor, "%s", "Seeding idle limit reached; pausing torrent");
512 tor->isStopping = true;
513 tor->finishedSeedingByIdle = true;
515 /* maybe notify the client */
516 if (tor->idle_limit_hit_func != NULL)
517 tor->idle_limit_hit_func (tor, tor->idle_limit_hit_func_user_data);
521 /***
522 ****
523 ***/
525 void
526 tr_torrentSetLocalError (tr_torrent * tor, const char * fmt, ...)
528 va_list ap;
530 assert (tr_isTorrent (tor));
532 va_start (ap, fmt);
533 tor->error = TR_STAT_LOCAL_ERROR;
534 tor->errorTracker[0] = '\0';
535 evutil_vsnprintf (tor->errorString, sizeof (tor->errorString), fmt, ap);
536 va_end (ap);
538 tr_logAddTorErr (tor, "%s", tor->errorString);
540 if (tor->isRunning)
541 tor->isStopping = true;
544 static void
545 tr_torrentClearError (tr_torrent * tor)
547 tor->error = TR_STAT_OK;
548 tor->errorString[0] = '\0';
549 tor->errorTracker[0] = '\0';
552 static void
553 onTrackerResponse (tr_torrent * tor, const tr_tracker_event * event, void * unused UNUSED)
555 switch (event->messageType)
557 case TR_TRACKER_PEERS:
559 size_t i;
560 const int8_t seedProbability = event->seedProbability;
561 const bool allAreSeeds = seedProbability == 100;
563 if (allAreSeeds)
564 tr_logAddTorDbg (tor, "Got %zu seeds from tracker", event->pexCount);
565 else
566 tr_logAddTorDbg (tor, "Got %zu peers from tracker", event->pexCount);
568 for (i = 0; i < event->pexCount; ++i)
569 tr_peerMgrAddPex (tor, TR_PEER_FROM_TRACKER, &event->pex[i], seedProbability);
571 break;
574 case TR_TRACKER_WARNING:
575 tr_logAddTorErr (tor, _("Tracker warning: \"%s\""), event->text);
576 tor->error = TR_STAT_TRACKER_WARNING;
577 tr_strlcpy (tor->errorTracker, event->tracker, sizeof (tor->errorTracker));
578 tr_strlcpy (tor->errorString, event->text, sizeof (tor->errorString));
579 break;
581 case TR_TRACKER_ERROR:
582 tr_logAddTorErr (tor, _("Tracker error: \"%s\""), event->text);
583 tor->error = TR_STAT_TRACKER_ERROR;
584 tr_strlcpy (tor->errorTracker, event->tracker, sizeof (tor->errorTracker));
585 tr_strlcpy (tor->errorString, event->text, sizeof (tor->errorString));
586 break;
588 case TR_TRACKER_ERROR_CLEAR:
589 if (tor->error != TR_STAT_LOCAL_ERROR)
590 tr_torrentClearError (tor);
591 break;
595 /***
596 ****
597 **** TORRENT INSTANTIATION
598 ****
599 ***/
601 static tr_piece_index_t
602 getBytePiece (const tr_info * info, uint64_t byteOffset)
604 tr_piece_index_t piece;
606 assert (info);
607 assert (info->pieceSize != 0);
609 piece = byteOffset / info->pieceSize;
611 /* handle 0-byte files at the end of a torrent */
612 if (byteOffset == info->totalSize)
613 piece = info->pieceCount - 1;
615 return piece;
618 static void
619 initFilePieces (tr_info * info,
620 tr_file_index_t fileIndex)
622 tr_file * file;
623 uint64_t firstByte, lastByte;
625 assert (info);
626 assert (fileIndex < info->fileCount);
628 file = &info->files[fileIndex];
629 firstByte = file->offset;
630 lastByte = firstByte + (file->length ? file->length - 1 : 0);
631 file->firstPiece = getBytePiece (info, firstByte);
632 file->lastPiece = getBytePiece (info, lastByte);
635 static int
636 pieceHasFile (tr_piece_index_t piece,
637 const tr_file * file)
639 return (file->firstPiece <= piece) && (piece <= file->lastPiece);
642 static tr_priority_t
643 calculatePiecePriority (const tr_torrent * tor,
644 tr_piece_index_t piece,
645 int fileHint)
647 tr_file_index_t i;
648 tr_priority_t priority = TR_PRI_LOW;
650 /* find the first file that has data in this piece */
651 if (fileHint >= 0)
653 i = fileHint;
654 while (i > 0 && pieceHasFile (piece, &tor->info.files[i - 1]))
655 --i;
657 else
659 for (i=0; i<tor->info.fileCount; ++i)
660 if (pieceHasFile (piece, &tor->info.files[i]))
661 break;
664 /* the piece's priority is the max of the priorities
665 * of all the files in that piece */
666 for (; i<tor->info.fileCount; ++i)
668 const tr_file * file = &tor->info.files[i];
670 if (!pieceHasFile (piece, file))
671 break;
673 priority = MAX (priority, file->priority);
675 /* when dealing with multimedia files, getting the first and
676 last pieces can sometimes allow you to preview it a bit
677 before it's fully downloaded... */
678 if (file->priority >= TR_PRI_NORMAL)
679 if (file->firstPiece == piece || file->lastPiece == piece)
680 priority = TR_PRI_HIGH;
683 return priority;
686 static void
687 tr_torrentInitFilePieces (tr_torrent * tor)
689 int * firstFiles;
690 tr_file_index_t f;
691 tr_piece_index_t p;
692 uint64_t offset = 0;
693 tr_info * inf = &tor->info;
695 /* assign the file offsets */
696 for (f=0; f<inf->fileCount; ++f)
698 inf->files[f].offset = offset;
699 offset += inf->files[f].length;
700 initFilePieces (inf, f);
703 /* build the array of first-file hints to give calculatePiecePriority */
704 firstFiles = tr_new (int, inf->pieceCount);
705 for (p=f=0; p<inf->pieceCount; ++p)
707 while (inf->files[f].lastPiece < p)
708 ++f;
709 firstFiles[p] = f;
712 #if 0
713 /* test to confirm the first-file hints are correct */
714 for (p=0; p<inf->pieceCount; ++p)
716 f = firstFiles[p];
717 assert (inf->files[f].firstPiece <= p);
718 assert (inf->files[f].lastPiece >= p);
719 if (f > 0)
720 assert (inf->files[f-1].lastPiece < p);
722 for (f=0; f<inf->fileCount; ++f)
723 if (pieceHasFile (p, &inf->files[f]))
724 break;
726 assert ((int)f == firstFiles[p]);
728 #endif
730 for (p=0; p<inf->pieceCount; ++p)
731 inf->pieces[p].priority = calculatePiecePriority (tor, p, firstFiles[p]);
733 tr_free (firstFiles);
736 static void torrentStart (tr_torrent * tor, bool bypass_queue);
739 * Decide on a block size. Constraints:
740 * (1) most clients decline requests over 16 KiB
741 * (2) pieceSize must be a multiple of block size
743 uint32_t
744 tr_getBlockSize (uint32_t pieceSize)
746 uint32_t b = pieceSize;
748 while (b > MAX_BLOCK_SIZE)
749 b /= 2u;
751 if (!b || (pieceSize % b)) /* not cleanly divisible */
752 return 0;
754 return b;
757 static void refreshCurrentDir (tr_torrent * tor);
759 static void
760 torrentInitFromInfo (tr_torrent * tor)
762 uint64_t t;
763 tr_info * info = &tor->info;
765 tor->blockSize = tr_getBlockSize (info->pieceSize);
767 if (info->pieceSize)
768 tor->lastPieceSize = (uint32_t)(info->totalSize % info->pieceSize);
770 if (!tor->lastPieceSize)
771 tor->lastPieceSize = info->pieceSize;
773 if (tor->blockSize)
774 tor->lastBlockSize = info->totalSize % tor->blockSize;
776 if (!tor->lastBlockSize)
777 tor->lastBlockSize = tor->blockSize;
779 tor->blockCount = tor->blockSize
780 ? (info->totalSize + tor->blockSize - 1) / tor->blockSize
781 : 0;
783 tor->blockCountInPiece = tor->blockSize
784 ? info->pieceSize / tor->blockSize
785 : 0;
787 tor->blockCountInLastPiece = tor->blockSize
788 ? (tor->lastPieceSize + tor->blockSize - 1) / tor->blockSize
789 : 0;
791 /* check our work */
792 if (tor->blockSize != 0)
793 assert ((info->pieceSize % tor->blockSize) == 0);
794 t = info->pieceCount - 1;
795 t *= info->pieceSize;
796 t += tor->lastPieceSize;
797 assert (t == info->totalSize);
798 t = tor->blockCount - 1;
799 t *= tor->blockSize;
800 t += tor->lastBlockSize;
801 assert (t == info->totalSize);
802 t = info->pieceCount - 1;
803 t *= tor->blockCountInPiece;
804 t += tor->blockCountInLastPiece;
805 assert (t == (uint64_t)tor->blockCount);
807 tr_cpConstruct (&tor->completion, tor);
809 tr_torrentInitFilePieces (tor);
811 tor->completeness = tr_cpGetStatus (&tor->completion);
814 static void tr_torrentFireMetadataCompleted (tr_torrent * tor);
816 void
817 tr_torrentGotNewInfoDict (tr_torrent * tor)
819 torrentInitFromInfo (tor);
821 tr_peerMgrOnTorrentGotMetainfo (tor);
823 tr_torrentFireMetadataCompleted (tor);
826 static bool
827 hasAnyLocalData (const tr_torrent * tor)
829 tr_file_index_t i;
831 for (i=0; i<tor->info.fileCount; ++i)
832 if (tr_torrentFindFile2 (tor, i, NULL, NULL, NULL))
833 return true;
835 return false;
838 static bool
839 setLocalErrorIfFilesDisappeared (tr_torrent * tor)
841 const bool disappeared = (tr_cpHaveTotal (&tor->completion) > 0) && !hasAnyLocalData (tor);
843 if (disappeared)
845 tr_deeplog_tor (tor, "%s", "[LAZY] uh oh, the files disappeared");
846 tr_torrentSetLocalError (tor, "%s", _("No data found! Ensure your drives are connected or use \"Set Location\". To re-download, remove the torrent and re-add it."));
849 return disappeared;
852 static void
853 torrentInit (tr_torrent * tor, const tr_ctor * ctor)
855 int doStart;
856 uint64_t loaded;
857 const char * dir;
858 bool isNewTorrent;
859 struct stat st;
860 tr_session * session = tr_ctorGetSession (ctor);
861 static int nextUniqueId = 1;
863 assert (session != NULL);
865 tr_sessionLock (session);
867 tor->session = session;
868 tor->uniqueId = nextUniqueId++;
869 tor->magicNumber = TORRENT_MAGIC_NUMBER;
870 tor->queuePosition = session->torrentCount;
872 tr_sha1 (tor->obfuscatedHash, "req2", 4,
873 tor->info.hash, SHA_DIGEST_LENGTH,
874 NULL);
876 if (!tr_ctorGetDownloadDir (ctor, TR_FORCE, &dir) ||
877 !tr_ctorGetDownloadDir (ctor, TR_FALLBACK, &dir))
878 tor->downloadDir = tr_strdup (dir);
880 if (tr_ctorGetIncompleteDir (ctor, &dir))
881 dir = tr_sessionGetIncompleteDir (session);
882 if (tr_sessionIsIncompleteDirEnabled (session))
883 tor->incompleteDir = tr_strdup (dir);
885 tr_bandwidthConstruct (&tor->bandwidth, session, &session->bandwidth);
887 tor->bandwidth.priority = tr_ctorGetBandwidthPriority (ctor);
889 tor->error = TR_STAT_OK;
891 tor->finishedSeedingByIdle = false;
893 tr_peerMgrAddTorrent (session->peerMgr, tor);
895 assert (!tor->downloadedCur);
896 assert (!tor->uploadedCur);
898 tr_torrentSetAddedDate (tor, tr_time ()); /* this is a default value to be
899 overwritten by the resume file */
901 torrentInitFromInfo (tor);
902 loaded = tr_torrentLoadResume (tor, ~0, ctor);
903 tor->completeness = tr_cpGetStatus (&tor->completion);
904 setLocalErrorIfFilesDisappeared (tor);
906 tr_ctorInitTorrentPriorities (ctor, tor);
907 tr_ctorInitTorrentWanted (ctor, tor);
909 refreshCurrentDir (tor);
911 doStart = tor->isRunning;
912 tor->isRunning = 0;
914 if (!(loaded & TR_FR_SPEEDLIMIT))
916 tr_torrentUseSpeedLimit (tor, TR_UP, false);
917 tr_torrentSetSpeedLimit_Bps (tor, TR_UP, tr_sessionGetSpeedLimit_Bps (tor->session, TR_UP));
918 tr_torrentUseSpeedLimit (tor, TR_DOWN, false);
919 tr_torrentSetSpeedLimit_Bps (tor, TR_DOWN, tr_sessionGetSpeedLimit_Bps (tor->session, TR_DOWN));
920 tr_torrentUseSessionLimits (tor, true);
923 if (!(loaded & TR_FR_RATIOLIMIT))
925 tr_torrentSetRatioMode (tor, TR_RATIOLIMIT_GLOBAL);
926 tr_torrentSetRatioLimit (tor, tr_sessionGetRatioLimit (tor->session));
929 if (!(loaded & TR_FR_IDLELIMIT))
931 tr_torrentSetIdleMode (tor, TR_IDLELIMIT_GLOBAL);
932 tr_torrentSetIdleLimit (tor, tr_sessionGetIdleLimit (tor->session));
935 /* add the torrent to tr_session.torrentList */
936 session->torrentCount++;
937 if (session->torrentList == NULL)
939 session->torrentList = tor;
941 else
943 tr_torrent * it = session->torrentList;
944 while (it->next != NULL)
945 it = it->next;
946 it->next = tor;
949 /* if we don't have a local .torrent file already, assume the torrent is new */
950 isNewTorrent = stat (tor->info.torrent, &st);
952 /* maybe save our own copy of the metainfo */
953 if (tr_ctorGetSave (ctor))
955 const tr_variant * val;
956 if (!tr_ctorGetMetainfo (ctor, &val))
958 const char * path = tor->info.torrent;
959 const int err = tr_variantToFile (val, TR_VARIANT_FMT_BENC, path);
960 if (err)
961 tr_torrentSetLocalError (tor, "Unable to save torrent file: %s", tr_strerror (err));
962 tr_sessionSetTorrentFile (tor->session, tor->info.hashString, path);
966 tor->tiers = tr_announcerAddTorrent (tor, onTrackerResponse, NULL);
968 if (isNewTorrent)
970 tor->startAfterVerify = doStart;
971 tr_torrentVerify (tor, NULL, NULL);
973 else if (doStart)
975 tr_torrentStart (tor);
978 tr_sessionUnlock (session);
981 static tr_parse_result
982 torrentParseImpl (const tr_ctor * ctor,
983 tr_info * setmeInfo,
984 bool * setmeHasInfo,
985 int * dictLength,
986 int * setme_duplicate_id)
988 bool doFree;
989 bool didParse;
990 bool hasInfo = false;
991 tr_info tmp;
992 const tr_variant * metainfo;
993 tr_session * session = tr_ctorGetSession (ctor);
994 tr_parse_result result = TR_PARSE_OK;
996 if (setmeInfo == NULL)
997 setmeInfo = &tmp;
998 memset (setmeInfo, 0, sizeof (tr_info));
1000 if (tr_ctorGetMetainfo (ctor, &metainfo))
1001 return TR_PARSE_ERR;
1003 didParse = tr_metainfoParse (session, metainfo, setmeInfo,
1004 &hasInfo, dictLength);
1005 doFree = didParse && (setmeInfo == &tmp);
1007 if (!didParse)
1008 result = TR_PARSE_ERR;
1010 if (didParse && hasInfo && !tr_getBlockSize (setmeInfo->pieceSize))
1011 result = TR_PARSE_ERR;
1013 if (didParse && session && (result == TR_PARSE_OK))
1015 const tr_torrent * const tor = tr_torrentFindFromHash (session, setmeInfo->hash);
1017 if (tor != NULL)
1019 result = TR_PARSE_DUPLICATE;
1021 if (setme_duplicate_id != NULL)
1022 *setme_duplicate_id = tr_torrentId (tor);
1026 if (doFree)
1027 tr_metainfoFree (setmeInfo);
1029 if (setmeHasInfo != NULL)
1030 *setmeHasInfo = hasInfo;
1032 return result;
1035 tr_parse_result
1036 tr_torrentParse (const tr_ctor * ctor, tr_info * setmeInfo)
1038 return torrentParseImpl (ctor, setmeInfo, NULL, NULL, NULL);
1041 tr_torrent *
1042 tr_torrentNew (const tr_ctor * ctor, int * setme_error, int * setme_duplicate_id)
1044 int len;
1045 bool hasInfo;
1046 tr_info tmpInfo;
1047 tr_parse_result r;
1048 tr_torrent * tor = NULL;
1050 assert (ctor != NULL);
1051 assert (tr_isSession (tr_ctorGetSession (ctor)));
1053 r = torrentParseImpl (ctor, &tmpInfo, &hasInfo, &len, setme_duplicate_id);
1054 if (r == TR_PARSE_OK)
1056 tor = tr_new0 (tr_torrent, 1);
1057 tor->info = tmpInfo;
1059 if (hasInfo)
1060 tor->infoDictLength = len;
1062 torrentInit (tor, ctor);
1064 else
1066 if (r == TR_PARSE_DUPLICATE)
1067 tr_metainfoFree (&tmpInfo);
1069 if (setme_error != NULL)
1070 *setme_error = r;
1073 return tor;
1080 void
1081 tr_torrentSetDownloadDir (tr_torrent * tor, const char * path)
1083 assert (tr_isTorrent (tor));
1085 if (!path || !tor->downloadDir || strcmp (path, tor->downloadDir))
1087 tr_free (tor->downloadDir);
1088 tor->downloadDir = tr_strdup (path);
1089 tr_torrentSetDirty (tor);
1092 refreshCurrentDir (tor);
1095 const char*
1096 tr_torrentGetDownloadDir (const tr_torrent * tor)
1098 assert (tr_isTorrent (tor));
1100 return tor->downloadDir;
1103 const char *
1104 tr_torrentGetCurrentDir (const tr_torrent * tor)
1106 assert (tr_isTorrent (tor));
1108 return tor->currentDir;
1112 void
1113 tr_torrentChangeMyPort (tr_torrent * tor)
1115 assert (tr_isTorrent (tor));
1117 if (tor->isRunning)
1118 tr_announcerChangeMyPort (tor);
1121 static inline void
1122 tr_torrentManualUpdateImpl (void * vtor)
1124 tr_torrent * tor = vtor;
1126 assert (tr_isTorrent (tor));
1128 if (tor->isRunning)
1129 tr_announcerManualAnnounce (tor);
1132 void
1133 tr_torrentManualUpdate (tr_torrent * tor)
1135 assert (tr_isTorrent (tor));
1137 tr_runInEventThread (tor->session, tr_torrentManualUpdateImpl, tor);
1140 bool
1141 tr_torrentCanManualUpdate (const tr_torrent * tor)
1143 return (tr_isTorrent (tor))
1144 && (tor->isRunning)
1145 && (tr_announcerCanManualAnnounce (tor));
1148 const tr_info *
1149 tr_torrentInfo (const tr_torrent * tor)
1151 return tr_isTorrent (tor) ? &tor->info : NULL;
1154 const tr_stat *
1155 tr_torrentStatCached (tr_torrent * tor)
1157 const time_t now = tr_time ();
1159 return tr_isTorrent (tor) && (now == tor->lastStatTime)
1160 ? &tor->stats
1161 : tr_torrentStat (tor);
1164 void
1165 tr_torrentSetVerifyState (tr_torrent * tor, tr_verify_state state)
1167 assert (tr_isTorrent (tor));
1168 assert (state==TR_VERIFY_NONE || state==TR_VERIFY_WAIT || state==TR_VERIFY_NOW);
1170 tor->verifyState = state;
1171 tor->anyDate = tr_time ();
1174 tr_torrent_activity
1175 tr_torrentGetActivity (const tr_torrent * tor)
1177 tr_torrent_activity ret = TR_STATUS_STOPPED;
1179 const bool is_seed = tr_torrentIsSeed (tor);
1181 if (tor->verifyState == TR_VERIFY_NOW)
1183 ret = TR_STATUS_CHECK;
1185 else if (tor->verifyState == TR_VERIFY_WAIT)
1187 ret = TR_STATUS_CHECK_WAIT;
1189 else if (tor->isRunning)
1191 ret = is_seed ? TR_STATUS_SEED : TR_STATUS_DOWNLOAD;
1193 else if (tr_torrentIsQueued (tor))
1195 if (is_seed && tr_sessionGetQueueEnabled (tor->session, TR_UP))
1196 ret = TR_STATUS_SEED_WAIT;
1197 else if (!is_seed && tr_sessionGetQueueEnabled (tor->session, TR_DOWN))
1198 ret = TR_STATUS_DOWNLOAD_WAIT;
1201 return ret;
1204 static time_t
1205 torrentGetIdleSecs (const tr_torrent * tor)
1207 int idle_secs;
1208 const tr_torrent_activity activity = tr_torrentGetActivity (tor);
1210 if ((activity == TR_STATUS_DOWNLOAD || activity == TR_STATUS_SEED) && tor->startDate != 0)
1211 idle_secs = difftime (tr_time (), MAX (tor->startDate, tor->activityDate));
1212 else
1213 idle_secs = -1;
1215 return idle_secs;
1218 bool
1219 tr_torrentIsStalled (const tr_torrent * tor)
1221 return tr_sessionGetQueueStalledEnabled (tor->session)
1222 && (torrentGetIdleSecs (tor) > (tr_sessionGetQueueStalledMinutes (tor->session) * 60));
1226 static double
1227 getVerifyProgress (const tr_torrent * tor)
1229 double d = 0;
1231 if (tr_torrentHasMetadata (tor))
1233 tr_piece_index_t i, n;
1234 tr_piece_index_t checked = 0;
1236 for (i=0, n=tor->info.pieceCount; i!=n; ++i)
1237 if (tor->info.pieces[i].timeChecked)
1238 ++checked;
1240 d = checked / (double)tor->info.pieceCount;
1243 return d;
1246 const tr_stat *
1247 tr_torrentStat (tr_torrent * tor)
1249 tr_stat * s;
1250 uint64_t seedRatioBytesLeft;
1251 uint64_t seedRatioBytesGoal;
1252 bool seedRatioApplies;
1253 uint16_t seedIdleMinutes;
1254 const uint64_t now = tr_time_msec ();
1255 unsigned int pieceUploadSpeed_Bps;
1256 unsigned int pieceDownloadSpeed_Bps;
1257 struct tr_swarm_stats swarm_stats;
1258 int i;
1260 assert (tr_isTorrent (tor));
1262 tor->lastStatTime = tr_time ();
1264 if (tor->swarm != NULL)
1265 tr_swarmGetStats (tor->swarm, &swarm_stats);
1266 else
1267 swarm_stats = TR_SWARM_STATS_INIT;
1269 s = &tor->stats;
1270 s->id = tor->uniqueId;
1271 s->activity = tr_torrentGetActivity (tor);
1272 s->error = tor->error;
1273 s->queuePosition = tor->queuePosition;
1274 s->isStalled = tr_torrentIsStalled (tor);
1275 tr_strlcpy (s->errorString, tor->errorString, sizeof (s->errorString));
1277 s->manualAnnounceTime = tr_announcerNextManualAnnounce (tor);
1278 s->peersConnected = swarm_stats.peerCount;
1279 s->peersSendingToUs = swarm_stats.activePeerCount[TR_DOWN];
1280 s->peersGettingFromUs = swarm_stats.activePeerCount[TR_UP];
1281 s->webseedsSendingToUs = swarm_stats.activeWebseedCount;
1282 for (i=0; i<TR_PEER_FROM__MAX; i++)
1283 s->peersFrom[i] = swarm_stats.peerFromCount[i];
1285 s->rawUploadSpeed_KBps = toSpeedKBps (tr_bandwidthGetRawSpeed_Bps (&tor->bandwidth, now, TR_UP));
1286 s->rawDownloadSpeed_KBps = toSpeedKBps (tr_bandwidthGetRawSpeed_Bps (&tor->bandwidth, now, TR_DOWN));
1287 pieceUploadSpeed_Bps = tr_bandwidthGetPieceSpeed_Bps (&tor->bandwidth, now, TR_UP);
1288 pieceDownloadSpeed_Bps = tr_bandwidthGetPieceSpeed_Bps (&tor->bandwidth, now, TR_DOWN);
1289 s->pieceUploadSpeed_KBps = toSpeedKBps (pieceUploadSpeed_Bps);
1290 s->pieceDownloadSpeed_KBps = toSpeedKBps (pieceDownloadSpeed_Bps);
1292 s->percentComplete = tr_cpPercentComplete (&tor->completion);
1293 s->metadataPercentComplete = tr_torrentGetMetadataPercent (tor);
1295 s->percentDone = tr_cpPercentDone (&tor->completion);
1296 s->leftUntilDone = tr_cpLeftUntilDone (&tor->completion);
1297 s->sizeWhenDone = tr_cpSizeWhenDone (&tor->completion);
1298 s->recheckProgress = s->activity == TR_STATUS_CHECK ? getVerifyProgress (tor) : 0;
1299 s->activityDate = tor->activityDate;
1300 s->addedDate = tor->addedDate;
1301 s->doneDate = tor->doneDate;
1302 s->startDate = tor->startDate;
1303 s->secondsSeeding = tor->secondsSeeding;
1304 s->secondsDownloading = tor->secondsDownloading;
1305 s->idleSecs = torrentGetIdleSecs (tor);
1307 s->corruptEver = tor->corruptCur + tor->corruptPrev;
1308 s->downloadedEver = tor->downloadedCur + tor->downloadedPrev;
1309 s->uploadedEver = tor->uploadedCur + tor->uploadedPrev;
1310 s->haveValid = tr_cpHaveValid (&tor->completion);
1311 s->haveUnchecked = tr_cpHaveTotal (&tor->completion) - s->haveValid;
1312 s->desiredAvailable = tr_peerMgrGetDesiredAvailable (tor);
1314 s->ratio = tr_getRatio (s->uploadedEver,
1315 s->downloadedEver ? s->downloadedEver : s->haveValid);
1317 seedRatioApplies = tr_torrentGetSeedRatioBytes (tor, &seedRatioBytesLeft,
1318 &seedRatioBytesGoal);
1320 switch (s->activity)
1322 /* etaXLSpeed exists because if we use the piece speed directly,
1323 * brief fluctuations cause the ETA to jump all over the place.
1324 * so, etaXLSpeed is a smoothed-out version of the piece speed
1325 * to dampen the effect of fluctuations */
1326 case TR_STATUS_DOWNLOAD:
1327 if ((tor->etaDLSpeedCalculatedAt + 800) < now)
1329 tor->etaDLSpeedCalculatedAt = now;
1330 tor->etaDLSpeed_Bps = ((tor->etaDLSpeedCalculatedAt + 4000) < now)
1331 ? pieceDownloadSpeed_Bps /* if no recent previous speed, no need to smooth */
1332 : ((tor->etaDLSpeed_Bps*4.0) + pieceDownloadSpeed_Bps)/5.0; /* smooth across 5 readings */
1335 if ((s->leftUntilDone > s->desiredAvailable) && (tor->info.webseedCount < 1))
1336 s->eta = TR_ETA_NOT_AVAIL;
1337 else if (tor->etaDLSpeed_Bps == 0)
1338 s->eta = TR_ETA_UNKNOWN;
1339 else
1340 s->eta = s->leftUntilDone / tor->etaDLSpeed_Bps;
1342 s->etaIdle = TR_ETA_NOT_AVAIL;
1343 break;
1345 case TR_STATUS_SEED:
1346 if (!seedRatioApplies)
1348 s->eta = TR_ETA_NOT_AVAIL;
1350 else
1352 if ((tor->etaULSpeedCalculatedAt + 800) < now)
1354 tor->etaULSpeedCalculatedAt = now;
1355 tor->etaULSpeed_Bps = ((tor->etaULSpeedCalculatedAt + 4000) < now)
1356 ? pieceUploadSpeed_Bps /* if no recent previous speed, no need to smooth */
1357 : ((tor->etaULSpeed_Bps*4.0) + pieceUploadSpeed_Bps)/5.0; /* smooth across 5 readings */
1360 if (tor->etaULSpeed_Bps == 0)
1361 s->eta = TR_ETA_UNKNOWN;
1362 else
1363 s->eta = seedRatioBytesLeft / tor->etaULSpeed_Bps;
1366 if (tor->etaULSpeed_Bps < 1 && tr_torrentGetSeedIdle (tor, &seedIdleMinutes))
1367 s->etaIdle = seedIdleMinutes * 60 - s->idleSecs;
1368 else
1369 s->etaIdle = TR_ETA_NOT_AVAIL;
1370 break;
1372 default:
1373 s->eta = TR_ETA_NOT_AVAIL;
1374 s->etaIdle = TR_ETA_NOT_AVAIL;
1375 break;
1378 /* s->haveValid is here to make sure a torrent isn't marked 'finished'
1379 * when the user hits "uncheck all" prior to starting the torrent... */
1380 s->finished = tor->finishedSeedingByIdle || (seedRatioApplies && !seedRatioBytesLeft && s->haveValid);
1382 if (!seedRatioApplies || s->finished)
1383 s->seedRatioPercentDone = 1;
1384 else if (!seedRatioBytesGoal) /* impossible? safeguard for div by zero */
1385 s->seedRatioPercentDone = 0;
1386 else
1387 s->seedRatioPercentDone = (double)(seedRatioBytesGoal - seedRatioBytesLeft) / seedRatioBytesGoal;
1389 /* test some of the constraints */
1390 assert (s->sizeWhenDone <= tor->info.totalSize);
1391 assert (s->leftUntilDone <= s->sizeWhenDone);
1392 assert (s->desiredAvailable <= s->leftUntilDone);
1394 return s;
1397 /***
1398 ****
1399 ***/
1401 static uint64_t
1402 countFileBytesCompleted (const tr_torrent * tor, tr_file_index_t index)
1404 uint64_t total = 0;
1405 const tr_file * f = &tor->info.files[index];
1407 if (f->length)
1409 tr_block_index_t first;
1410 tr_block_index_t last;
1411 tr_torGetFileBlockRange (tor, index, &first, &last);
1413 if (first == last)
1415 if (tr_cpBlockIsComplete (&tor->completion, first))
1416 total = f->length;
1418 else
1420 /* the first block */
1421 if (tr_cpBlockIsComplete (&tor->completion, first))
1422 total += tor->blockSize - (f->offset % tor->blockSize);
1424 /* the middle blocks */
1425 if (first + 1 < last)
1427 uint64_t u = tr_bitfieldCountRange (&tor->completion.blockBitfield, first+1, last);
1428 u *= tor->blockSize;
1429 total += u;
1432 /* the last block */
1433 if (tr_cpBlockIsComplete (&tor->completion, last))
1434 total += (f->offset + f->length) - ((uint64_t)tor->blockSize * last);
1438 return total;
1441 tr_file_stat *
1442 tr_torrentFiles (const tr_torrent * tor,
1443 tr_file_index_t * fileCount)
1445 tr_file_index_t i;
1446 const tr_file_index_t n = tor->info.fileCount;
1447 tr_file_stat * files = tr_new0 (tr_file_stat, n);
1448 tr_file_stat * walk = files;
1449 const bool isSeed = tor->completeness == TR_SEED;
1451 assert (tr_isTorrent (tor));
1453 for (i=0; i<n; ++i, ++walk)
1455 const uint64_t b = isSeed ? tor->info.files[i].length : countFileBytesCompleted (tor, i);
1456 walk->bytesCompleted = b;
1457 walk->progress = tor->info.files[i].length > 0 ? ((float)b / tor->info.files[i].length) : 1.0f;
1460 if (fileCount != NULL)
1461 *fileCount = n;
1463 return files;
1466 void
1467 tr_torrentFilesFree (tr_file_stat * files,
1468 tr_file_index_t fileCount UNUSED)
1470 tr_free (files);
1473 /***
1474 ****
1475 ***/
1477 double*
1478 tr_torrentWebSpeeds_KBps (const tr_torrent * tor)
1480 assert (tr_isTorrent (tor));
1482 return tr_peerMgrWebSpeeds_KBps (tor);
1485 tr_peer_stat *
1486 tr_torrentPeers (const tr_torrent * tor, int * peerCount)
1488 assert (tr_isTorrent (tor));
1490 return tr_peerMgrPeerStats (tor, peerCount);
1493 void
1494 tr_torrentPeersFree (tr_peer_stat * peers, int peerCount UNUSED)
1496 tr_free (peers);
1499 tr_tracker_stat *
1500 tr_torrentTrackers (const tr_torrent * tor, int * setmeTrackerCount)
1502 assert (tr_isTorrent (tor));
1504 return tr_announcerStats (tor, setmeTrackerCount);
1507 void
1508 tr_torrentTrackersFree (tr_tracker_stat * trackers, int trackerCount)
1510 tr_announcerStatsFree (trackers, trackerCount);
1513 void
1514 tr_torrentAvailability (const tr_torrent * tor, int8_t * tab, int size)
1516 assert (tr_isTorrent (tor));
1518 if ((tab != NULL) && (size > 0))
1519 tr_peerMgrTorrentAvailability (tor, tab, size);
1522 void
1523 tr_torrentAmountFinished (const tr_torrent * tor, float * tab, int size)
1525 tr_cpGetAmountDone (&tor->completion, tab, size);
1528 static void
1529 tr_torrentResetTransferStats (tr_torrent * tor)
1531 tr_torrentLock (tor);
1533 tor->downloadedPrev += tor->downloadedCur;
1534 tor->downloadedCur = 0;
1535 tor->uploadedPrev += tor->uploadedCur;
1536 tor->uploadedCur = 0;
1537 tor->corruptPrev += tor->corruptCur;
1538 tor->corruptCur = 0;
1540 tr_torrentSetDirty (tor);
1542 tr_torrentUnlock (tor);
1545 void
1546 tr_torrentSetHasPiece (tr_torrent * tor,
1547 tr_piece_index_t pieceIndex,
1548 bool has)
1550 assert (tr_isTorrent (tor));
1551 assert (pieceIndex < tor->info.pieceCount);
1553 if (has)
1554 tr_cpPieceAdd (&tor->completion, pieceIndex);
1555 else
1556 tr_cpPieceRem (&tor->completion, pieceIndex);
1559 /***
1560 ****
1561 ***/
1563 #ifndef NDEBUG
1564 static bool queueIsSequenced (tr_session *);
1565 #endif
1567 static void
1568 freeTorrent (tr_torrent * tor)
1570 tr_torrent * t;
1571 tr_session * session = tor->session;
1572 tr_info * inf = &tor->info;
1573 const time_t now = tr_time ();
1575 assert (!tor->isRunning);
1577 tr_sessionLock (session);
1579 tr_peerMgrRemoveTorrent (tor);
1581 tr_announcerRemoveTorrent (session->announcer, tor);
1583 tr_cpDestruct (&tor->completion);
1585 tr_free (tor->downloadDir);
1586 tr_free (tor->incompleteDir);
1588 if (tor == session->torrentList)
1590 session->torrentList = tor->next;
1592 else for (t = session->torrentList; t != NULL; t = t->next)
1594 if (t->next == tor)
1596 t->next = tor->next;
1597 break;
1601 /* decrement the torrent count */
1602 assert (session->torrentCount >= 1);
1603 session->torrentCount--;
1605 /* resequence the queue positions */
1606 t = NULL;
1607 while ((t = tr_torrentNext (session, t)))
1609 if (t->queuePosition > tor->queuePosition)
1611 t->queuePosition--;
1612 t->anyDate = now;
1615 assert (queueIsSequenced (session));
1617 tr_bandwidthDestruct (&tor->bandwidth);
1619 tr_metainfoFree (inf);
1620 memset (tor, ~0, sizeof (tr_torrent));
1621 tr_free (tor);
1623 tr_sessionUnlock (session);
1627 *** Start/Stop Callback
1630 static void torrentSetQueued (tr_torrent * tor, bool queued);
1632 static void
1633 torrentStartImpl (void * vtor)
1635 time_t now;
1636 tr_torrent * tor = vtor;
1638 assert (tr_isTorrent (tor));
1640 tr_sessionLock (tor->session);
1642 tr_torrentRecheckCompleteness (tor);
1643 torrentSetQueued (tor, false);
1645 now = tr_time ();
1646 tor->isRunning = true;
1647 tor->completeness = tr_cpGetStatus (&tor->completion);
1648 tor->startDate = tor->anyDate = now;
1649 tr_torrentClearError (tor);
1650 tor->finishedSeedingByIdle = false;
1652 tr_torrentResetTransferStats (tor);
1653 tr_announcerTorrentStarted (tor);
1654 tor->dhtAnnounceAt = now + tr_cryptoWeakRandInt (20);
1655 tor->dhtAnnounce6At = now + tr_cryptoWeakRandInt (20);
1656 tor->lpdAnnounceAt = now;
1657 tr_peerMgrStartTorrent (tor);
1659 tr_sessionUnlock (tor->session);
1662 uint64_t
1663 tr_torrentGetCurrentSizeOnDisk (const tr_torrent * tor)
1665 tr_file_index_t i;
1666 uint64_t byte_count = 0;
1667 const tr_file_index_t n = tor->info.fileCount;
1669 for (i=0; i<n; ++i)
1671 struct stat sb;
1672 char * filename = tr_torrentFindFile (tor, i);
1674 sb.st_size = 0;
1675 if (filename && !stat (filename, &sb))
1676 byte_count += sb.st_size;
1678 tr_free (filename);
1681 return byte_count;
1684 static bool
1685 torrentShouldQueue (const tr_torrent * tor)
1687 const tr_direction dir = tr_torrentGetQueueDirection (tor);
1689 return tr_sessionCountQueueFreeSlots (tor->session, dir) == 0;
1692 static void
1693 torrentStart (tr_torrent * tor, bool bypass_queue)
1695 switch (tr_torrentGetActivity (tor))
1697 case TR_STATUS_SEED:
1698 case TR_STATUS_DOWNLOAD:
1699 return; /* already started */
1700 break;
1702 case TR_STATUS_SEED_WAIT:
1703 case TR_STATUS_DOWNLOAD_WAIT:
1704 if (!bypass_queue)
1705 return; /* already queued */
1706 break;
1708 case TR_STATUS_CHECK:
1709 case TR_STATUS_CHECK_WAIT:
1710 /* verifying right now... wait until that's done so
1711 * we'll know what completeness to use/announce */
1712 tor->startAfterVerify = true;
1713 return;
1714 break;
1716 case TR_STATUS_STOPPED:
1717 if (!bypass_queue && torrentShouldQueue (tor))
1719 torrentSetQueued (tor, true);
1720 return;
1722 break;
1725 /* don't allow the torrent to be started if the files disappeared */
1726 if (setLocalErrorIfFilesDisappeared (tor))
1727 return;
1729 /* otherwise, start it now... */
1730 tr_sessionLock (tor->session);
1732 /* allow finished torrents to be resumed */
1733 if (tr_torrentIsSeedRatioDone (tor))
1735 tr_logAddTorInfo (tor, "%s", _("Restarted manually -- disabling its seed ratio"));
1736 tr_torrentSetRatioMode (tor, TR_RATIOLIMIT_UNLIMITED);
1739 /* corresponds to the peer_id sent as a tracker request parameter.
1740 * one tracker admin says: "When the same torrent is opened and
1741 * closed and opened again without quitting Transmission ...
1742 * change the peerid. It would help sometimes if a stopped event
1743 * was missed to ensure that we didn't think someone was cheating. */
1744 tr_torrentUnsetPeerId (tor);
1745 tor->isRunning = true;
1746 tr_torrentSetDirty (tor);
1747 tr_runInEventThread (tor->session, torrentStartImpl, tor);
1749 tr_sessionUnlock (tor->session);
1752 void
1753 tr_torrentStart (tr_torrent * tor)
1755 if (tr_isTorrent (tor))
1756 torrentStart (tor, false);
1759 void
1760 tr_torrentStartNow (tr_torrent * tor)
1762 if (tr_isTorrent (tor))
1763 torrentStart (tor, true);
1766 struct verify_data
1768 bool aborted;
1769 tr_torrent * tor;
1770 tr_verify_done_func callback_func;
1771 void * callback_data;
1774 static void
1775 onVerifyDoneThreadFunc (void * vdata)
1777 struct verify_data * data = vdata;
1778 tr_torrent * tor = data->tor;
1780 if (!data->aborted)
1781 tr_torrentRecheckCompleteness (tor);
1783 if (data->callback_func != NULL)
1784 (*data->callback_func)(tor, data->aborted, data->callback_data);
1786 if (!data->aborted && tor->startAfterVerify)
1788 tor->startAfterVerify = false;
1789 torrentStart (tor, false);
1792 tr_free (data);
1795 static void
1796 onVerifyDone (tr_torrent * tor, bool aborted, void * vdata)
1798 struct verify_data * data = vdata;
1799 assert (data->tor == tor);
1800 data->aborted = aborted;
1801 tr_runInEventThread (tor->session, onVerifyDoneThreadFunc, data);
1804 static void
1805 verifyTorrent (void * vdata)
1807 bool startAfter;
1808 struct verify_data * data = vdata;
1809 tr_torrent * tor = data->tor;
1810 tr_sessionLock (tor->session);
1812 /* if the torrent's already being verified, stop it */
1813 tr_verifyRemove (tor);
1815 startAfter = (tor->isRunning || tor->startAfterVerify) && !tor->isStopping;
1816 if (tor->isRunning)
1817 tr_torrentStop (tor);
1818 tor->startAfterVerify = startAfter;
1820 if (setLocalErrorIfFilesDisappeared (tor))
1821 tor->startAfterVerify = false;
1822 else
1823 tr_verifyAdd (tor, onVerifyDone, data);
1825 tr_sessionUnlock (tor->session);
1828 void
1829 tr_torrentVerify (tr_torrent * tor,
1830 tr_verify_done_func callback_func,
1831 void * callback_data)
1833 struct verify_data * data;
1835 data = tr_new (struct verify_data, 1);
1836 data->tor = tor;
1837 data->aborted = false;
1838 data->callback_func = callback_func;
1839 data->callback_data = callback_data;
1840 tr_runInEventThread (tor->session, verifyTorrent, data);
1843 void
1844 tr_torrentSave (tr_torrent * tor)
1846 assert (tr_isTorrent (tor));
1848 if (tor->isDirty)
1850 tor->isDirty = false;
1851 tr_torrentSaveResume (tor);
1855 static void
1856 stopTorrent (void * vtor)
1858 tr_torrent * tor = vtor;
1859 tr_logAddTorInfo (tor, "%s", "Pausing");
1861 assert (tr_isTorrent (tor));
1863 tr_torrentLock (tor);
1865 tr_verifyRemove (tor);
1866 torrentSetQueued (tor, false);
1867 tr_peerMgrStopTorrent (tor);
1868 tr_announcerTorrentStopped (tor);
1869 tr_cacheFlushTorrent (tor->session->cache, tor);
1871 tr_fdTorrentClose (tor->session, tor->uniqueId);
1873 if (!tor->isDeleting)
1874 tr_torrentSave (tor);
1876 tr_torrentUnlock (tor);
1879 void
1880 tr_torrentStop (tr_torrent * tor)
1882 assert (tr_isTorrent (tor));
1884 if (tr_isTorrent (tor))
1886 tr_sessionLock (tor->session);
1888 tor->isRunning = 0;
1889 tor->isStopping = 0;
1890 tr_torrentSetDirty (tor);
1891 tr_runInEventThread (tor->session, stopTorrent, tor);
1893 tr_sessionUnlock (tor->session);
1897 static void
1898 closeTorrent (void * vtor)
1900 tr_variant * d;
1901 tr_torrent * tor = vtor;
1903 assert (tr_isTorrent (tor));
1905 d = tr_variantListAddDict (&tor->session->removedTorrents, 2);
1906 tr_variantDictAddInt (d, TR_KEY_id, tor->uniqueId);
1907 tr_variantDictAddInt (d, TR_KEY_date, tr_time ());
1909 tr_logAddTorInfo (tor, "%s", _("Removing torrent"));
1911 stopTorrent (tor);
1913 if (tor->isDeleting)
1915 tr_metainfoRemoveSaved (tor->session, &tor->info);
1916 tr_torrentRemoveResume (tor);
1919 tor->isRunning = 0;
1920 freeTorrent (tor);
1923 void
1924 tr_torrentFree (tr_torrent * tor)
1926 if (tr_isTorrent (tor))
1928 tr_session * session = tor->session;
1929 assert (tr_isSession (session));
1930 tr_sessionLock (session);
1932 tr_torrentClearCompletenessCallback (tor);
1933 tr_runInEventThread (session, closeTorrent, tor);
1935 tr_sessionUnlock (session);
1939 struct remove_data
1941 tr_torrent * tor;
1942 bool deleteFlag;
1943 tr_fileFunc * deleteFunc;
1946 static void tr_torrentDeleteLocalData (tr_torrent *, tr_fileFunc);
1948 static void
1949 removeTorrent (void * vdata)
1951 struct remove_data * data = vdata;
1952 tr_session * session = data->tor->session;
1953 tr_sessionLock (session);
1955 if (data->deleteFlag)
1956 tr_torrentDeleteLocalData (data->tor, data->deleteFunc);
1958 tr_torrentClearCompletenessCallback (data->tor);
1959 closeTorrent (data->tor);
1960 tr_free (data);
1962 tr_sessionUnlock (session);
1965 void
1966 tr_torrentRemove (tr_torrent * tor,
1967 bool deleteFlag,
1968 tr_fileFunc deleteFunc)
1970 struct remove_data * data;
1972 assert (tr_isTorrent (tor));
1973 tor->isDeleting = 1;
1975 data = tr_new0 (struct remove_data, 1);
1976 data->tor = tor;
1977 data->deleteFlag = deleteFlag;
1978 data->deleteFunc = deleteFunc;
1979 tr_runInEventThread (tor->session, removeTorrent, data);
1983 *** Completeness
1986 static const char *
1987 getCompletionString (int type)
1989 switch (type)
1991 /* Translators: this is a minor point that's safe to skip over, but FYI:
1992 "Complete" and "Done" are specific, different terms in Transmission:
1993 "Complete" means we've downloaded every file in the torrent.
1994 "Done" means we're done downloading the files we wanted, but NOT all
1995 that exist */
1996 case TR_PARTIAL_SEED:
1997 return _("Done");
1999 case TR_SEED:
2000 return _("Complete");
2002 default:
2003 return _("Incomplete");
2007 static void
2008 fireCompletenessChange (tr_torrent * tor,
2009 tr_completeness status,
2010 bool wasRunning)
2012 assert ((status == TR_LEECH)
2013 || (status == TR_SEED)
2014 || (status == TR_PARTIAL_SEED));
2016 if (tor->completeness_func)
2017 tor->completeness_func (tor, status, wasRunning,
2018 tor->completeness_func_user_data);
2021 void
2022 tr_torrentSetCompletenessCallback (tr_torrent * tor,
2023 tr_torrent_completeness_func func,
2024 void * user_data)
2026 assert (tr_isTorrent (tor));
2028 tor->completeness_func = func;
2029 tor->completeness_func_user_data = user_data;
2032 void
2033 tr_torrentClearCompletenessCallback (tr_torrent * torrent)
2035 tr_torrentSetCompletenessCallback (torrent, NULL, NULL);
2038 void
2039 tr_torrentSetRatioLimitHitCallback (tr_torrent * tor,
2040 tr_torrent_ratio_limit_hit_func func,
2041 void * user_data)
2043 assert (tr_isTorrent (tor));
2045 tor->ratio_limit_hit_func = func;
2046 tor->ratio_limit_hit_func_user_data = user_data;
2049 void
2050 tr_torrentClearRatioLimitHitCallback (tr_torrent * torrent)
2052 tr_torrentSetRatioLimitHitCallback (torrent, NULL, NULL);
2055 void
2056 tr_torrentSetIdleLimitHitCallback (tr_torrent * tor,
2057 tr_torrent_idle_limit_hit_func func,
2058 void * user_data)
2060 assert (tr_isTorrent (tor));
2062 tor->idle_limit_hit_func = func;
2063 tor->idle_limit_hit_func_user_data = user_data;
2066 void
2067 tr_torrentClearIdleLimitHitCallback (tr_torrent * torrent)
2069 tr_torrentSetIdleLimitHitCallback (torrent, NULL, NULL);
2072 static void
2073 onSigCHLD (int i UNUSED)
2075 #ifdef WIN32
2077 _cwait (NULL, -1, WAIT_CHILD);
2079 #else
2081 int rc;
2083 rc = waitpid (-1, NULL, WNOHANG);
2084 while (rc>0 || (rc==-1 && errno==EINTR));
2086 #endif
2089 static void
2090 torrentCallScript (const tr_torrent * tor, const char * script)
2092 char timeStr[128];
2093 const time_t now = tr_time ();
2095 tr_strlcpy (timeStr, ctime (&now), sizeof (timeStr));
2096 *strchr (timeStr,'\n') = '\0';
2098 if (script && *script)
2100 int i;
2101 char * cmd[] = { tr_strdup (script), NULL };
2102 char * env[] = {
2103 tr_strdup_printf ("TR_APP_VERSION=%s", SHORT_VERSION_STRING),
2104 tr_strdup_printf ("TR_TIME_LOCALTIME=%s", timeStr),
2105 tr_strdup_printf ("TR_TORRENT_DIR=%s", tor->currentDir),
2106 tr_strdup_printf ("TR_TORRENT_ID=%d", tr_torrentId (tor)),
2107 tr_strdup_printf ("TR_TORRENT_HASH=%s", tor->info.hashString),
2108 tr_strdup_printf ("TR_TORRENT_NAME=%s", tr_torrentName (tor)),
2109 NULL };
2111 tr_logAddTorInfo (tor, "Calling script \"%s\"", script);
2113 #ifdef WIN32
2114 if (_spawnvpe (_P_NOWAIT, script, (const char*)cmd, env) == -1)
2115 tr_logAddTorErr (tor, "error executing script \"%s\": %s", cmd[0], tr_strerror (errno));
2116 #else
2117 signal (SIGCHLD, onSigCHLD);
2119 if (!fork ())
2121 for (i=0; env[i]; ++i)
2122 putenv (env[i]);
2124 if (execvp (script, cmd) == -1)
2125 tr_logAddTorErr (tor, "error executing script \"%s\": %s", cmd[0], tr_strerror (errno));
2127 _exit (0);
2129 #endif
2131 for (i=0; cmd[i]; ++i) tr_free (cmd[i]);
2132 for (i=0; env[i]; ++i) tr_free (env[i]);
2136 void
2137 tr_torrentRecheckCompleteness (tr_torrent * tor)
2139 tr_completeness completeness;
2141 tr_torrentLock (tor);
2143 completeness = tr_cpGetStatus (&tor->completion);
2144 if (completeness != tor->completeness)
2146 const bool recentChange = tor->downloadedCur != 0;
2147 const bool wasLeeching = !tr_torrentIsSeed (tor);
2148 const bool wasRunning = tor->isRunning;
2150 if (recentChange)
2151 tr_logAddTorInfo (tor, _("State changed from \"%1$s\" to \"%2$s\""),
2152 getCompletionString (tor->completeness),
2153 getCompletionString (completeness));
2155 tor->completeness = completeness;
2156 tr_fdTorrentClose (tor->session, tor->uniqueId);
2158 if (tr_torrentIsSeed (tor))
2160 if (recentChange)
2162 tr_announcerTorrentCompleted (tor);
2163 tor->doneDate = tor->anyDate = tr_time ();
2166 if (wasLeeching && wasRunning)
2168 /* clear interested flag on all peers */
2169 tr_peerMgrClearInterest (tor);
2172 if (tor->currentDir == tor->incompleteDir)
2173 tr_torrentSetLocation (tor, tor->downloadDir, true, NULL, NULL);
2176 fireCompletenessChange (tor, completeness, wasRunning);
2178 if (tr_torrentIsSeed (tor))
2180 if (wasLeeching && wasRunning)
2182 /* if completeness was TR_LEECH then the seed limit check will have been skipped in bandwidthPulse */
2183 tr_torrentCheckSeedLimit (tor);
2186 if (tr_sessionIsTorrentDoneScriptEnabled (tor->session))
2187 torrentCallScript (tor, tr_sessionGetTorrentDoneScript (tor->session));
2190 tr_torrentSetDirty (tor);
2193 tr_torrentUnlock (tor);
2196 /***
2197 ****
2198 ***/
2200 static void
2201 tr_torrentFireMetadataCompleted (tr_torrent * tor)
2203 assert (tr_isTorrent (tor));
2205 if (tor->metadata_func != NULL)
2206 tor->metadata_func (tor, tor->metadata_func_user_data);
2209 void
2210 tr_torrentSetMetadataCallback (tr_torrent * tor,
2211 tr_torrent_metadata_func func,
2212 void * user_data)
2214 assert (tr_isTorrent (tor));
2216 tor->metadata_func = func;
2217 tor->metadata_func_user_data = user_data;
2222 *** File priorities
2225 void
2226 tr_torrentInitFilePriority (tr_torrent * tor,
2227 tr_file_index_t fileIndex,
2228 tr_priority_t priority)
2230 tr_file * file;
2231 tr_piece_index_t i;
2233 assert (tr_isTorrent (tor));
2234 assert (fileIndex < tor->info.fileCount);
2235 assert (tr_isPriority (priority));
2237 file = &tor->info.files[fileIndex];
2238 file->priority = priority;
2239 for (i=file->firstPiece; i<=file->lastPiece; ++i)
2240 tor->info.pieces[i].priority = calculatePiecePriority (tor, i, fileIndex);
2243 void
2244 tr_torrentSetFilePriorities (tr_torrent * tor,
2245 const tr_file_index_t * files,
2246 tr_file_index_t fileCount,
2247 tr_priority_t priority)
2249 tr_file_index_t i;
2250 assert (tr_isTorrent (tor));
2251 tr_torrentLock (tor);
2253 for (i=0; i<fileCount; ++i)
2254 if (files[i] < tor->info.fileCount)
2255 tr_torrentInitFilePriority (tor, files[i], priority);
2256 tr_torrentSetDirty (tor);
2257 tr_peerMgrRebuildRequests (tor);
2259 tr_torrentUnlock (tor);
2262 tr_priority_t*
2263 tr_torrentGetFilePriorities (const tr_torrent * tor)
2265 tr_file_index_t i;
2266 tr_priority_t * p;
2268 assert (tr_isTorrent (tor));
2270 p = tr_new0 (tr_priority_t, tor->info.fileCount);
2272 for (i=0; i<tor->info.fileCount; ++i)
2273 p[i] = tor->info.files[i].priority;
2275 return p;
2279 *** File DND
2282 static void
2283 setFileDND (tr_torrent * tor, tr_file_index_t fileIndex, int doDownload)
2285 const int8_t dnd = !doDownload;
2286 tr_piece_index_t firstPiece;
2287 int8_t firstPieceDND;
2288 tr_piece_index_t lastPiece;
2289 int8_t lastPieceDND;
2290 tr_file_index_t i;
2291 tr_file * file = &tor->info.files[fileIndex];
2293 file->dnd = dnd;
2294 firstPiece = file->firstPiece;
2295 lastPiece = file->lastPiece;
2297 /* can't set the first piece to DND unless
2298 every file using that piece is DND */
2299 firstPieceDND = dnd;
2300 if (fileIndex > 0)
2302 for (i=fileIndex-1; firstPieceDND; --i)
2304 if (tor->info.files[i].lastPiece != firstPiece)
2305 break;
2307 firstPieceDND = tor->info.files[i].dnd;
2308 if (!i)
2309 break;
2313 /* can't set the last piece to DND unless
2314 every file using that piece is DND */
2315 lastPieceDND = dnd;
2316 for (i=fileIndex+1; lastPieceDND && i<tor->info.fileCount; ++i)
2318 if (tor->info.files[i].firstPiece != lastPiece)
2319 break;
2320 lastPieceDND = tor->info.files[i].dnd;
2323 if (firstPiece == lastPiece)
2325 tor->info.pieces[firstPiece].dnd = firstPieceDND && lastPieceDND;
2327 else
2329 tr_piece_index_t pp;
2330 tor->info.pieces[firstPiece].dnd = firstPieceDND;
2331 tor->info.pieces[lastPiece].dnd = lastPieceDND;
2332 for (pp=firstPiece+1; pp<lastPiece; ++pp)
2333 tor->info.pieces[pp].dnd = dnd;
2337 void
2338 tr_torrentInitFileDLs (tr_torrent * tor,
2339 const tr_file_index_t * files,
2340 tr_file_index_t fileCount,
2341 bool doDownload)
2343 tr_file_index_t i;
2345 assert (tr_isTorrent (tor));
2347 tr_torrentLock (tor);
2349 for (i=0; i<fileCount; ++i)
2350 if (files[i] < tor->info.fileCount)
2351 setFileDND (tor, files[i], doDownload);
2353 tr_cpInvalidateDND (&tor->completion);
2355 tr_torrentUnlock (tor);
2358 void
2359 tr_torrentSetFileDLs (tr_torrent * tor,
2360 const tr_file_index_t * files,
2361 tr_file_index_t fileCount,
2362 bool doDownload)
2364 assert (tr_isTorrent (tor));
2365 tr_torrentLock (tor);
2367 tr_torrentInitFileDLs (tor, files, fileCount, doDownload);
2368 tr_torrentSetDirty (tor);
2369 tr_torrentRecheckCompleteness (tor);
2370 tr_peerMgrRebuildRequests (tor);
2372 tr_torrentUnlock (tor);
2375 /***
2376 ****
2377 ***/
2379 tr_priority_t
2380 tr_torrentGetPriority (const tr_torrent * tor)
2382 assert (tr_isTorrent (tor));
2384 return tor->bandwidth.priority;
2387 void
2388 tr_torrentSetPriority (tr_torrent * tor, tr_priority_t priority)
2390 assert (tr_isTorrent (tor));
2391 assert (tr_isPriority (priority));
2393 if (tor->bandwidth.priority != priority)
2395 tor->bandwidth.priority = priority;
2397 tr_torrentSetDirty (tor);
2401 /***
2402 ****
2403 ***/
2405 void
2406 tr_torrentSetPeerLimit (tr_torrent * tor,
2407 uint16_t maxConnectedPeers)
2409 assert (tr_isTorrent (tor));
2411 if (tor->maxConnectedPeers != maxConnectedPeers)
2413 tor->maxConnectedPeers = maxConnectedPeers;
2415 tr_torrentSetDirty (tor);
2419 uint16_t
2420 tr_torrentGetPeerLimit (const tr_torrent * tor)
2422 assert (tr_isTorrent (tor));
2424 return tor->maxConnectedPeers;
2427 /***
2428 ****
2429 ***/
2431 void
2432 tr_torrentGetBlockLocation (const tr_torrent * tor,
2433 tr_block_index_t block,
2434 tr_piece_index_t * piece,
2435 uint32_t * offset,
2436 uint32_t * length)
2438 uint64_t pos = block;
2439 pos *= tor->blockSize;
2440 *piece = pos / tor->info.pieceSize;
2441 *offset = pos - (*piece * tor->info.pieceSize);
2442 *length = tr_torBlockCountBytes (tor, block);
2446 tr_block_index_t
2447 _tr_block (const tr_torrent * tor,
2448 tr_piece_index_t index,
2449 uint32_t offset)
2451 tr_block_index_t ret;
2453 assert (tr_isTorrent (tor));
2455 ret = index;
2456 ret *= (tor->info.pieceSize / tor->blockSize);
2457 ret += offset / tor->blockSize;
2458 return ret;
2461 bool
2462 tr_torrentReqIsValid (const tr_torrent * tor,
2463 tr_piece_index_t index,
2464 uint32_t offset,
2465 uint32_t length)
2467 int err = 0;
2469 assert (tr_isTorrent (tor));
2471 if (index >= tor->info.pieceCount)
2472 err = 1;
2473 else if (length < 1)
2474 err = 2;
2475 else if ((offset + length) > tr_torPieceCountBytes (tor, index))
2476 err = 3;
2477 else if (length > MAX_BLOCK_SIZE)
2478 err = 4;
2479 else if (tr_pieceOffset (tor, index, offset, length) > tor->info.totalSize)
2480 err = 5;
2482 if (err)
2483 tr_logAddTorDbg (tor, "index %lu offset %lu length %lu err %d\n",
2484 (unsigned long)index,
2485 (unsigned long)offset,
2486 (unsigned long)length,
2487 err);
2489 return !err;
2492 uint64_t
2493 tr_pieceOffset (const tr_torrent * tor,
2494 tr_piece_index_t index,
2495 uint32_t offset,
2496 uint32_t length)
2498 uint64_t ret;
2500 assert (tr_isTorrent (tor));
2502 ret = tor->info.pieceSize;
2503 ret *= index;
2504 ret += offset;
2505 ret += length;
2506 return ret;
2509 void
2510 tr_torGetFileBlockRange (const tr_torrent * tor,
2511 const tr_file_index_t file,
2512 tr_block_index_t * first,
2513 tr_block_index_t * last)
2515 const tr_file * f = &tor->info.files[file];
2516 uint64_t offset = f->offset;
2518 *first = offset / tor->blockSize;
2520 if (!f->length)
2522 *last = *first;
2524 else
2526 offset += f->length - 1;
2527 *last = offset / tor->blockSize;
2531 void
2532 tr_torGetPieceBlockRange (const tr_torrent * tor,
2533 const tr_piece_index_t piece,
2534 tr_block_index_t * first,
2535 tr_block_index_t * last)
2537 uint64_t offset = tor->info.pieceSize;
2538 offset *= piece;
2539 *first = offset / tor->blockSize;
2540 offset += (tr_torPieceCountBytes (tor, piece) - 1);
2541 *last = offset / tor->blockSize;
2545 /***
2546 ****
2547 ***/
2549 void
2550 tr_torrentSetPieceChecked (tr_torrent * tor, tr_piece_index_t pieceIndex)
2552 assert (tr_isTorrent (tor));
2553 assert (pieceIndex < tor->info.pieceCount);
2555 tor->info.pieces[pieceIndex].timeChecked = tr_time ();
2558 void
2559 tr_torrentSetChecked (tr_torrent * tor, time_t when)
2561 tr_piece_index_t i, n;
2563 assert (tr_isTorrent (tor));
2565 for (i=0, n=tor->info.pieceCount; i!=n; ++i)
2566 tor->info.pieces[i].timeChecked = when;
2569 bool
2570 tr_torrentCheckPiece (tr_torrent * tor, tr_piece_index_t pieceIndex)
2572 const bool pass = tr_ioTestPiece (tor, pieceIndex);
2574 tr_deeplog_tor (tor, "[LAZY] tr_torrentCheckPiece tested piece %zu, pass==%d", (size_t)pieceIndex, (int)pass);
2575 tr_torrentSetHasPiece (tor, pieceIndex, pass);
2576 tr_torrentSetPieceChecked (tor, pieceIndex);
2577 tor->anyDate = tr_time ();
2578 tr_torrentSetDirty (tor);
2580 return pass;
2583 time_t
2584 tr_torrentGetFileMTime (const tr_torrent * tor, tr_file_index_t i)
2586 time_t mtime = 0;
2588 if (!tr_fdFileGetCachedMTime (tor->session, tor->uniqueId, i, &mtime))
2589 tr_torrentFindFile2 (tor, i, NULL, NULL, &mtime);
2591 return mtime;
2594 bool
2595 tr_torrentPieceNeedsCheck (const tr_torrent * tor, tr_piece_index_t p)
2597 uint64_t unused;
2598 tr_file_index_t f;
2599 const tr_info * inf = tr_torrentInfo (tor);
2601 /* if we've never checked this piece, then it needs to be checked */
2602 if (!inf->pieces[p].timeChecked)
2603 return true;
2605 /* If we think we've completed one of the files in this piece,
2606 * but it's been modified since we last checked it,
2607 * then it needs to be rechecked */
2608 tr_ioFindFileLocation (tor, p, 0, &f, &unused);
2609 for (; f < inf->fileCount && pieceHasFile (p, &inf->files[f]); ++f)
2610 if (tr_cpFileIsComplete (&tor->completion, f))
2611 if (tr_torrentGetFileMTime (tor, f) > inf->pieces[p].timeChecked)
2612 return true;
2614 return false;
2617 /***
2618 ****
2619 ***/
2621 static int
2622 compareTrackerByTier (const void * va, const void * vb)
2624 const tr_tracker_info * a = va;
2625 const tr_tracker_info * b = vb;
2627 /* sort by tier */
2628 if (a->tier != b->tier)
2629 return a->tier - b->tier;
2631 /* get the effects of a stable sort by comparing the two elements' addresses */
2632 return a - b;
2635 bool
2636 tr_torrentSetAnnounceList (tr_torrent * tor,
2637 const tr_tracker_info * trackers_in,
2638 int trackerCount)
2640 int i;
2641 tr_variant metainfo;
2642 bool ok = true;
2643 tr_tracker_info * trackers;
2645 tr_torrentLock (tor);
2647 assert (tr_isTorrent (tor));
2649 /* ensure the trackers' tiers are in ascending order */
2650 trackers = tr_memdup (trackers_in, sizeof (tr_tracker_info) * trackerCount);
2651 qsort (trackers, trackerCount, sizeof (tr_tracker_info), compareTrackerByTier);
2653 /* look for bad URLs */
2654 for (i=0; ok && i<trackerCount; ++i)
2655 if (!tr_urlIsValidTracker (trackers[i].announce))
2656 ok = false;
2658 /* save to the .torrent file */
2659 if (ok && !tr_variantFromFile (&metainfo, TR_VARIANT_FMT_BENC, tor->info.torrent))
2661 bool hasInfo;
2662 tr_info tmpInfo;
2664 /* remove the old fields */
2665 tr_variantDictRemove (&metainfo, TR_KEY_announce);
2666 tr_variantDictRemove (&metainfo, TR_KEY_announce_list);
2668 /* add the new fields */
2669 if (trackerCount > 0)
2671 tr_variantDictAddStr (&metainfo, TR_KEY_announce, trackers[0].announce);
2673 if (trackerCount > 1)
2675 int i;
2676 int prevTier = -1;
2677 tr_variant * tier = NULL;
2678 tr_variant * announceList = tr_variantDictAddList (&metainfo, TR_KEY_announce_list, 0);
2680 for (i=0; i<trackerCount; ++i)
2682 if (prevTier != trackers[i].tier)
2684 prevTier = trackers[i].tier;
2685 tier = tr_variantListAddList (announceList, 0);
2688 tr_variantListAddStr (tier, trackers[i].announce);
2692 /* try to parse it back again, to make sure it's good */
2693 memset (&tmpInfo, 0, sizeof (tr_info));
2694 if (tr_metainfoParse (tor->session, &metainfo, &tmpInfo,
2695 &hasInfo, &tor->infoDictLength))
2697 /* it's good, so keep these new trackers and free the old ones */
2699 tr_info swap;
2700 swap.trackers = tor->info.trackers;
2701 swap.trackerCount = tor->info.trackerCount;
2702 tor->info.trackers = tmpInfo.trackers;
2703 tor->info.trackerCount = tmpInfo.trackerCount;
2704 tmpInfo.trackers = swap.trackers;
2705 tmpInfo.trackerCount = swap.trackerCount;
2707 tr_metainfoFree (&tmpInfo);
2708 tr_variantToFile (&metainfo, TR_VARIANT_FMT_BENC, tor->info.torrent);
2711 /* cleanup */
2712 tr_variantFree (&metainfo);
2714 /* if we had a tracker-related error on this torrent,
2715 * and that tracker's been removed,
2716 * then clear the error */
2717 if ((tor->error == TR_STAT_TRACKER_WARNING)
2718 || (tor->error == TR_STAT_TRACKER_ERROR))
2720 bool clear = true;
2722 for (i=0; clear && i<trackerCount; ++i)
2723 if (!strcmp (trackers[i].announce, tor->errorTracker))
2724 clear = false;
2726 if (clear)
2727 tr_torrentClearError (tor);
2730 /* tell the announcer to reload this torrent's tracker list */
2731 tr_announcerResetTorrent (tor->session->announcer, tor);
2734 tr_torrentUnlock (tor);
2736 tr_free (trackers);
2737 return ok;
2744 void
2745 tr_torrentSetAddedDate (tr_torrent * tor,
2746 time_t t)
2748 assert (tr_isTorrent (tor));
2750 tor->addedDate = t;
2751 tor->anyDate = MAX (tor->anyDate, tor->addedDate);
2754 void
2755 tr_torrentSetActivityDate (tr_torrent * tor, time_t t)
2757 assert (tr_isTorrent (tor));
2759 tor->activityDate = t;
2760 tor->anyDate = MAX (tor->anyDate, tor->activityDate);
2763 void
2764 tr_torrentSetDoneDate (tr_torrent * tor,
2765 time_t t)
2767 assert (tr_isTorrent (tor));
2769 tor->doneDate = t;
2770 tor->anyDate = MAX (tor->anyDate, tor->doneDate);
2777 uint64_t
2778 tr_torrentGetBytesLeftToAllocate (const tr_torrent * tor)
2780 tr_file_index_t i;
2781 uint64_t bytesLeft = 0;
2783 assert (tr_isTorrent (tor));
2785 for (i=0; i<tor->info.fileCount; ++i)
2787 if (!tor->info.files[i].dnd)
2789 struct stat sb;
2790 const uint64_t length = tor->info.files[i].length;
2791 char * path = tr_torrentFindFile (tor, i);
2793 bytesLeft += length;
2795 if ((path != NULL) && !stat (path, &sb)
2796 && S_ISREG (sb.st_mode)
2797 && ((uint64_t)sb.st_size <= length))
2798 bytesLeft -= sb.st_size;
2800 tr_free (path);
2804 return bytesLeft;
2807 /****
2808 ***** Removing the torrent's local data
2809 ****/
2811 static bool
2812 isJunkFile (const char * base)
2814 int i;
2815 static const char * files[] = { ".DS_Store", "desktop.ini", "Thumbs.db" };
2816 static const int file_count = sizeof (files) / sizeof (files[0]);
2818 for (i=0; i<file_count; ++i)
2819 if (!strcmp (base, files[i]))
2820 return true;
2822 #ifdef SYS_DARWIN
2823 /* check for resource forks. <http://support.apple.com/kb/TA20578> */
2824 if (!memcmp (base, "._", 2))
2825 return true;
2826 #endif
2828 return false;
2831 static void
2832 removeEmptyFoldersAndJunkFiles (const char * folder)
2834 DIR * odir;
2836 if ((odir = opendir (folder)))
2838 struct dirent * d;
2839 while ((d = readdir (odir)))
2841 if (strcmp (d->d_name, ".") && strcmp (d->d_name, ".."))
2843 struct stat sb;
2844 char * filename = tr_buildPath (folder, d->d_name, NULL);
2846 if (!stat (filename, &sb) && S_ISDIR (sb.st_mode))
2847 removeEmptyFoldersAndJunkFiles (filename);
2848 else if (isJunkFile (d->d_name))
2849 tr_remove (filename);
2851 tr_free (filename);
2855 tr_remove (folder);
2856 closedir (odir);
2861 * This convoluted code does something (seemingly) simple:
2862 * remove the torrent's local files.
2864 * Fun complications:
2865 * 1. Try to preserve the directory hierarchy in the recycle bin.
2866 * 2. If there are nontorrent files, don't delete them...
2867 * 3. ...unless the other files are "junk", such as .DS_Store
2869 static void
2870 deleteLocalData (tr_torrent * tor, tr_fileFunc func)
2872 int i, n;
2873 tr_file_index_t f;
2874 char * base;
2875 DIR * odir;
2876 char * tmpdir = NULL;
2877 tr_ptrArray files = TR_PTR_ARRAY_INIT;
2878 tr_ptrArray folders = TR_PTR_ARRAY_INIT;
2879 const void * const vstrcmp = strcmp;
2880 const char * const top = tor->currentDir;
2882 /* if it's a magnet link, there's nothing to move... */
2883 if (!tr_torrentHasMetadata (tor))
2884 return;
2886 /***
2887 **** Move the local data to a new tmpdir
2888 ***/
2890 base = tr_strdup_printf ("%s__XXXXXX", tr_torrentName (tor));
2891 tmpdir = tr_buildPath (top, base, NULL);
2892 tr_mkdtemp (tmpdir);
2893 tr_free (base);
2895 for (f=0; f<tor->info.fileCount; ++f)
2897 char * filename;
2899 /* try to find the file, looking in the partial and download dirs */
2900 filename = tr_buildPath (top, tor->info.files[f].name, NULL);
2901 if (!tr_fileExists (filename, NULL))
2903 char * partial = tr_torrentBuildPartial (tor, f);
2904 tr_free (filename);
2905 filename = tr_buildPath (top, partial, NULL);
2906 tr_free (partial);
2907 if (!tr_fileExists (filename, NULL))
2909 tr_free (filename);
2910 filename = NULL;
2914 /* if we found the file, move it */
2915 if (filename != NULL)
2917 char * target = tr_buildPath (tmpdir, tor->info.files[f].name, NULL);
2918 tr_moveFile (filename, target, NULL);
2919 tr_ptrArrayAppend (&files, target);
2920 tr_free (filename);
2924 /***
2925 **** Remove tmpdir.
2926 ****
2927 **** Try deleting the top-level files & folders to preserve
2928 **** the directory hierarchy in the recycle bin.
2929 **** If case that fails -- for example, rmdir () doesn't
2930 **** delete nonempty folders -- go from the bottom up too.
2931 ***/
2933 /* try deleting the local data's top-level files & folders */
2934 if ((odir = opendir (tmpdir)))
2936 struct dirent * d;
2937 while ((d = readdir (odir)))
2939 if (strcmp (d->d_name, ".") && strcmp (d->d_name, ".."))
2941 char * file = tr_buildPath (tmpdir, d->d_name, NULL);
2942 func (file);
2943 tr_free (file);
2946 closedir (odir);
2949 /* go from the bottom up */
2950 for (i=0, n=tr_ptrArraySize (&files); i<n; ++i)
2952 char * walk = tr_strdup (tr_ptrArrayNth (&files, i));
2953 while (tr_fileExists (walk, NULL) && !tr_is_same_file (tmpdir, walk))
2955 char * tmp = tr_dirname (walk);
2956 func (walk);
2957 tr_free (walk);
2958 walk = tmp;
2960 tr_free (walk);
2963 /***
2964 **** The local data has been removed.
2965 **** What's left in top are empty folders, junk, and user-generated files.
2966 **** Remove the first two categories and leave the third.
2967 ***/
2969 /* build a list of 'top's child directories that belong to this torrent */
2970 for (f=0; f<tor->info.fileCount; ++f)
2972 char * dir;
2973 char * filename;
2975 /* get the directory that this file goes in... */
2976 filename = tr_buildPath (top, tor->info.files[f].name, NULL);
2977 dir = tr_dirname (filename);
2978 tr_free (filename);
2980 /* walk up the directory tree until we reach 'top' */
2981 if (!tr_is_same_file (top, dir) && strcmp (top, dir))
2983 for (;;)
2985 char * parent = tr_dirname (dir);
2986 if (tr_is_same_file (top, parent) || !strcmp (top, parent))
2988 if (tr_ptrArrayFindSorted (&folders, dir, vstrcmp) == NULL)
2989 tr_ptrArrayInsertSorted (&folders, tr_strdup(dir), vstrcmp);
2990 tr_free (parent);
2991 break;
2994 /* walk upwards to parent */
2995 tr_free (dir);
2996 dir = parent;
3000 tr_free (dir);
3003 for (i=0, n=tr_ptrArraySize (&folders); i<n; ++i)
3004 removeEmptyFoldersAndJunkFiles (tr_ptrArrayNth (&folders, i));
3006 /* cleanup */
3007 tr_remove (tmpdir);
3008 tr_free (tmpdir);
3009 tr_ptrArrayDestruct (&folders, tr_free);
3010 tr_ptrArrayDestruct (&files, tr_free);
3013 static void
3014 tr_torrentDeleteLocalData (tr_torrent * tor, tr_fileFunc func)
3016 assert (tr_isTorrent (tor));
3018 if (func == NULL)
3019 func = remove;
3021 /* close all the files because we're about to delete them */
3022 tr_cacheFlushTorrent (tor->session->cache, tor);
3023 tr_fdTorrentClose (tor->session, tor->uniqueId);
3025 deleteLocalData (tor, func);
3028 /***
3029 ****
3030 ***/
3032 struct LocationData
3034 bool move_from_old_location;
3035 volatile int * setme_state;
3036 volatile double * setme_progress;
3037 char * location;
3038 tr_torrent * tor;
3041 static void
3042 setLocation (void * vdata)
3044 bool err = false;
3045 struct LocationData * data = vdata;
3046 tr_torrent * tor = data->tor;
3047 const bool do_move = data->move_from_old_location;
3048 const char * location = data->location;
3049 double bytesHandled = 0;
3050 tr_torrentLock (tor);
3052 assert (tr_isTorrent (tor));
3054 tr_logAddDebug ("Moving \"%s\" location from currentDir \"%s\" to \"%s\"",
3055 tr_torrentName (tor), tor->currentDir, location);
3057 tr_mkdirp (location, 0777);
3059 if (!tr_is_same_file (location, tor->currentDir))
3061 tr_file_index_t i;
3063 /* bad idea to move files while they're being verified... */
3064 tr_verifyRemove (tor);
3066 /* try to move the files.
3067 * FIXME: there are still all kinds of nasty cases, like what
3068 * if the target directory runs out of space halfway through... */
3069 for (i=0; !err && i<tor->info.fileCount; ++i)
3071 char * sub;
3072 const char * oldbase;
3073 const tr_file * f = &tor->info.files[i];
3075 if (tr_torrentFindFile2 (tor, i, &oldbase, &sub, NULL))
3077 char * oldpath = tr_buildPath (oldbase, sub, NULL);
3078 char * newpath = tr_buildPath (location, sub, NULL);
3080 tr_logAddDebug ("Found file #%d: %s", (int)i, oldpath);
3082 if (do_move && !tr_is_same_file (oldpath, newpath))
3084 bool renamed = false;
3085 errno = 0;
3086 tr_logAddTorInfo (tor, "moving \"%s\" to \"%s\"", oldpath, newpath);
3087 if (tr_moveFile (oldpath, newpath, &renamed))
3089 err = true;
3090 tr_logAddTorErr (tor, "error moving \"%s\" to \"%s\": %s",
3091 oldpath, newpath, tr_strerror (errno));
3095 tr_free (newpath);
3096 tr_free (oldpath);
3097 tr_free (sub);
3100 if (data->setme_progress != NULL)
3102 bytesHandled += f->length;
3103 *data->setme_progress = bytesHandled / tor->info.totalSize;
3107 if (!err)
3109 /* blow away the leftover subdirectories in the old location */
3110 if (do_move)
3111 tr_torrentDeleteLocalData (tor, remove);
3113 /* set the new location and reverify */
3114 tr_torrentSetDownloadDir (tor, location);
3118 if (!err && do_move)
3120 tr_free (tor->incompleteDir);
3121 tor->incompleteDir = NULL;
3122 tor->currentDir = tor->downloadDir;
3125 if (data->setme_state != NULL)
3126 *data->setme_state = err ? TR_LOC_ERROR : TR_LOC_DONE;
3128 /* cleanup */
3129 tr_torrentUnlock (tor);
3130 tr_free (data->location);
3131 tr_free (data);
3134 void
3135 tr_torrentSetLocation (tr_torrent * tor,
3136 const char * location,
3137 bool move_from_old_location,
3138 volatile double * setme_progress,
3139 volatile int * setme_state)
3141 struct LocationData * data;
3143 assert (tr_isTorrent (tor));
3145 if (setme_state != NULL)
3146 *setme_state = TR_LOC_MOVING;
3148 if (setme_progress != NULL)
3149 *setme_progress = 0;
3151 /* run this in the libtransmission thread */
3152 data = tr_new (struct LocationData, 1);
3153 data->tor = tor;
3154 data->location = tr_strdup (location);
3155 data->move_from_old_location = move_from_old_location;
3156 data->setme_state = setme_state;
3157 data->setme_progress = setme_progress;
3158 tr_runInEventThread (tor->session, setLocation, data);
3161 /***
3162 ****
3163 ***/
3165 static void
3166 tr_torrentFileCompleted (tr_torrent * tor, tr_file_index_t fileIndex)
3168 char * sub;
3169 const char * base;
3170 const tr_info * inf = &tor->info;
3171 const tr_file * f = &inf->files[fileIndex];
3172 tr_piece * p;
3173 const tr_piece * pend;
3174 const time_t now = tr_time ();
3176 /* close the file so that we can reopen in read-only mode as needed */
3177 tr_cacheFlushFile (tor->session->cache, tor, fileIndex);
3178 tr_fdFileClose (tor->session, tor, fileIndex);
3180 /* now that the file is complete and closed, we can start watching its
3181 * mtime timestamp for changes to know if we need to reverify pieces */
3182 for (p=&inf->pieces[f->firstPiece], pend=&inf->pieces[f->lastPiece]; p!=pend; ++p)
3183 p->timeChecked = now;
3185 /* if the torrent's current filename isn't the same as the one in the
3186 * metadata -- for example, if it had the ".part" suffix appended to
3187 * it until now -- then rename it to match the one in the metadata */
3188 if (tr_torrentFindFile2 (tor, fileIndex, &base, &sub, NULL))
3190 if (strcmp (sub, f->name))
3192 char * oldpath = tr_buildPath (base, sub, NULL);
3193 char * newpath = tr_buildPath (base, f->name, NULL);
3195 if (tr_rename (oldpath, newpath))
3196 tr_logAddTorErr (tor, "Error moving \"%s\" to \"%s\": %s", oldpath, newpath, tr_strerror (errno));
3198 tr_free (newpath);
3199 tr_free (oldpath);
3202 tr_free (sub);
3206 static void
3207 tr_torrentPieceCompleted (tr_torrent * tor, tr_piece_index_t pieceIndex)
3209 tr_file_index_t i;
3211 tr_peerMgrPieceCompleted (tor, pieceIndex);
3213 /* if this piece completes any file, invoke the fileCompleted func for it */
3214 for (i=0; i<tor->info.fileCount; ++i)
3216 const tr_file * file = &tor->info.files[i];
3218 if ((file->firstPiece <= pieceIndex) && (pieceIndex <= file->lastPiece))
3219 if (tr_cpFileIsComplete (&tor->completion, i))
3220 tr_torrentFileCompleted (tor, i);
3224 void
3225 tr_torrentGotBlock (tr_torrent * tor, tr_block_index_t block)
3227 const bool block_is_new = !tr_cpBlockIsComplete (&tor->completion, block);
3229 assert (tr_isTorrent (tor));
3230 assert (tr_amInEventThread (tor->session));
3232 if (block_is_new)
3234 tr_piece_index_t p;
3236 tr_cpBlockAdd (&tor->completion, block);
3237 tr_torrentSetDirty (tor);
3239 p = tr_torBlockPiece (tor, block);
3240 if (tr_cpPieceIsComplete (&tor->completion, p))
3242 tr_logAddTorDbg (tor, "[LAZY] checking just-completed piece %zu", (size_t)p);
3244 if (tr_torrentCheckPiece (tor, p))
3246 tr_torrentPieceCompleted (tor, p);
3248 else
3250 const uint32_t n = tr_torPieceCountBytes (tor, p);
3251 tr_logAddTorErr (tor, _("Piece %"PRIu32", which was just downloaded, failed its checksum test"), p);
3252 tor->corruptCur += n;
3253 tor->downloadedCur -= MIN (tor->downloadedCur, n);
3254 tr_peerMgrGotBadPiece (tor, p);
3258 else
3260 const uint32_t n = tr_torBlockCountBytes (tor, block);
3261 tor->downloadedCur -= MIN (tor->downloadedCur, n);
3262 tr_logAddTorDbg (tor, "we have this block already...");
3266 /***
3267 ****
3268 ***/
3270 bool
3271 tr_torrentFindFile2 (const tr_torrent * tor, tr_file_index_t fileNum,
3272 const char ** base, char ** subpath, time_t * mtime)
3274 char * part = NULL;
3275 const tr_file * file;
3276 const char * b = NULL;
3277 const char * s = NULL;
3279 assert (tr_isTorrent (tor));
3280 assert (fileNum < tor->info.fileCount);
3282 file = &tor->info.files[fileNum];
3284 /* look in the download dir... */
3285 if (b == NULL)
3287 char * filename = tr_buildPath (tor->downloadDir, file->name, NULL);
3288 if (tr_fileExists (filename, mtime))
3290 b = tor->downloadDir;
3291 s = file->name;
3293 tr_free (filename);
3296 /* look in the incomplete dir... */
3297 if ((b == NULL) && (tor->incompleteDir != NULL))
3299 char * filename = tr_buildPath (tor->incompleteDir, file->name, NULL);
3300 if (tr_fileExists (filename, mtime))
3302 b = tor->incompleteDir;
3303 s = file->name;
3305 tr_free (filename);
3308 if (b == NULL)
3309 part = tr_torrentBuildPartial (tor, fileNum);
3311 /* look for a .part file in the incomplete dir... */
3312 if ((b == NULL) && (tor->incompleteDir != NULL))
3314 char * filename = tr_buildPath (tor->incompleteDir, part, NULL);
3315 if (tr_fileExists (filename, mtime))
3317 b = tor->incompleteDir;
3318 s = part;
3320 tr_free (filename);
3323 /* look for a .part file in the download dir... */
3324 if (b == NULL)
3326 char * filename = tr_buildPath (tor->downloadDir, part, NULL);
3327 if (tr_fileExists (filename, mtime))
3329 b = tor->downloadDir;
3330 s = part;
3332 tr_free (filename);
3335 /* return the results */
3336 if (base != NULL)
3337 *base = b;
3338 if (subpath != NULL)
3339 *subpath = tr_strdup (s);
3341 /* cleanup */
3342 tr_free (part);
3343 return b != NULL;
3346 char*
3347 tr_torrentFindFile (const tr_torrent * tor, tr_file_index_t fileNum)
3349 char * subpath;
3350 char * ret = NULL;
3351 const char * base;
3353 if (tr_torrentFindFile2 (tor, fileNum, &base, &subpath, NULL))
3355 ret = tr_buildPath (base, subpath, NULL);
3356 tr_free (subpath);
3359 return ret;
3362 /* Decide whether we should be looking for files in downloadDir or incompleteDir. */
3363 static void
3364 refreshCurrentDir (tr_torrent * tor)
3366 const char * dir = NULL;
3368 if (tor->incompleteDir == NULL)
3369 dir = tor->downloadDir;
3370 else if (!tr_torrentHasMetadata (tor)) /* no files to find */
3371 dir = tor->incompleteDir;
3372 else if (!tr_torrentFindFile2 (tor, 0, &dir, NULL, NULL))
3373 dir = tor->incompleteDir;
3375 assert (dir != NULL);
3376 assert ((dir == tor->downloadDir) || (dir == tor->incompleteDir));
3377 tor->currentDir = dir;
3380 char*
3381 tr_torrentBuildPartial (const tr_torrent * tor, tr_file_index_t fileNum)
3383 return tr_strdup_printf ("%s.part", tor->info.files[fileNum].name);
3386 /***
3387 ****
3388 ***/
3390 static int
3391 compareTorrentByQueuePosition (const void * va, const void * vb)
3393 const tr_torrent * a = * (const tr_torrent **) va;
3394 const tr_torrent * b = * (const tr_torrent **) vb;
3396 return a->queuePosition - b->queuePosition;
3399 #ifndef NDEBUG
3400 static bool
3401 queueIsSequenced (tr_session * session)
3403 int i;
3404 int n;
3405 bool is_sequenced;
3406 tr_torrent ** torrents;
3408 n = 0;
3409 torrents = tr_sessionGetTorrents (session, &n);
3410 qsort (torrents, n, sizeof (tr_torrent *), compareTorrentByQueuePosition);
3412 #if 0
3413 fprintf (stderr, "%s", "queue: ");
3414 for (i=0; i<n; ++i)
3415 fprintf (stderr, "%d ", tmp[i]->queuePosition);
3416 fputc ('\n', stderr);
3417 #endif
3419 /* test them */
3420 is_sequenced = true;
3421 for (i=0; is_sequenced && i<n; ++i)
3422 if (torrents[i]->queuePosition != i)
3423 is_sequenced = false;
3425 tr_free (torrents);
3426 return is_sequenced;
3428 #endif
3431 tr_torrentGetQueuePosition (const tr_torrent * tor)
3433 return tor->queuePosition;
3436 void
3437 tr_torrentSetQueuePosition (tr_torrent * tor, int pos)
3439 int back = -1;
3440 tr_torrent * walk;
3441 const int old_pos = tor->queuePosition;
3442 const time_t now = tr_time ();
3444 if (pos < 0)
3445 pos = 0;
3447 tor->queuePosition = -1;
3449 walk = NULL;
3450 while ((walk = tr_torrentNext (tor->session, walk)))
3452 if (old_pos < pos)
3454 if ((old_pos <= walk->queuePosition) && (walk->queuePosition <= pos))
3456 walk->queuePosition--;
3457 walk->anyDate = now;
3461 if (old_pos > pos)
3463 if ((pos <= walk->queuePosition) && (walk->queuePosition < old_pos))
3465 walk->queuePosition++;
3466 walk->anyDate = now;
3470 if (back < walk->queuePosition)
3472 back = walk->queuePosition;
3476 tor->queuePosition = MIN (pos, (back+1));
3477 tor->anyDate = now;
3479 assert (queueIsSequenced (tor->session));
3482 void
3483 tr_torrentsQueueMoveTop (tr_torrent ** torrents_in, int n)
3485 int i;
3486 tr_torrent ** torrents = tr_memdup (torrents_in, sizeof (tr_torrent *) * n);
3487 qsort (torrents, n, sizeof (tr_torrent *), compareTorrentByQueuePosition);
3488 for (i=n-1; i>=0; --i)
3489 tr_torrentSetQueuePosition (torrents[i], 0);
3490 tr_free (torrents);
3493 void
3494 tr_torrentsQueueMoveUp (tr_torrent ** torrents_in, int n)
3496 int i;
3497 tr_torrent ** torrents;
3499 torrents = tr_memdup (torrents_in, sizeof (tr_torrent *) * n);
3500 qsort (torrents, n, sizeof (tr_torrent *), compareTorrentByQueuePosition);
3501 for (i=0; i<n; ++i)
3502 tr_torrentSetQueuePosition (torrents[i], torrents[i]->queuePosition - 1);
3504 tr_free (torrents);
3507 void
3508 tr_torrentsQueueMoveDown (tr_torrent ** torrents_in, int n)
3510 int i;
3511 tr_torrent ** torrents;
3513 torrents = tr_memdup (torrents_in, sizeof (tr_torrent *) * n);
3514 qsort (torrents, n, sizeof (tr_torrent *), compareTorrentByQueuePosition);
3515 for (i=n-1; i>=0; --i)
3516 tr_torrentSetQueuePosition (torrents[i], torrents[i]->queuePosition + 1);
3518 tr_free (torrents);
3521 void
3522 tr_torrentsQueueMoveBottom (tr_torrent ** torrents_in, int n)
3524 int i;
3525 tr_torrent ** torrents;
3527 torrents = tr_memdup (torrents_in, sizeof (tr_torrent *) * n);
3528 qsort (torrents, n, sizeof (tr_torrent *), compareTorrentByQueuePosition);
3529 for (i=0; i<n; ++i)
3530 tr_torrentSetQueuePosition (torrents[i], INT_MAX);
3532 tr_free (torrents);
3535 static void
3536 torrentSetQueued (tr_torrent * tor, bool queued)
3538 assert (tr_isTorrent (tor));
3539 assert (tr_isBool (queued));
3541 if (tr_torrentIsQueued (tor) != queued)
3543 tor->isQueued = queued;
3544 tor->anyDate = tr_time ();
3548 void
3549 tr_torrentSetQueueStartCallback (tr_torrent * torrent, void (*callback)(tr_torrent *, void *), void * user_data)
3551 torrent->queue_started_callback = callback;
3552 torrent->queue_started_user_data = user_data;
3556 /***
3557 ****
3558 **** RENAME
3559 ****
3560 ***/
3562 static bool
3563 renameArgsAreValid (const char * oldpath, const char * newname)
3565 return (oldpath && *oldpath)
3566 && (newname && *newname)
3567 && (strcmp (newname, "."))
3568 && (strcmp (newname, ".."))
3569 && (strchr (newname, TR_PATH_DELIMITER) == NULL);
3572 static tr_file_index_t *
3573 renameFindAffectedFiles (tr_torrent * tor, const char * oldpath, size_t * setme_n)
3575 size_t n;
3576 size_t oldpath_len;
3577 tr_file_index_t i;
3578 tr_file_index_t * indices = tr_new0 (tr_file_index_t, tor->info.fileCount);
3580 n = 0;
3581 oldpath_len = strlen (oldpath);
3582 for (i=0; i!=tor->info.fileCount; ++i)
3584 const char * name = tor->info.files[i].name;
3585 const size_t len = strlen (name);
3586 if ((len >= oldpath_len) && !memcmp (oldpath, name, oldpath_len))
3587 indices[n++] = i;
3590 *setme_n = n;
3591 return indices;
3594 static int
3595 renamePath (tr_torrent * tor,
3596 const char * oldpath,
3597 const char * newname)
3599 char * src;
3600 const char * base;
3601 int error = 0;
3603 if (!tr_torrentIsSeed(tor) && (tor->incompleteDir != NULL))
3604 base = tor->incompleteDir;
3605 else
3606 base = tor->downloadDir;
3608 src = tr_buildPath (base, oldpath, NULL);
3609 if (!tr_fileExists (src, NULL)) /* check for it as a partial */
3611 char * tmp = tr_strdup_printf ("%s.part", src);
3612 tr_free (src);
3613 src = tmp;
3616 if (tr_fileExists (src, NULL))
3618 int tmp;
3619 bool tgt_exists;
3620 char * parent = tr_dirname (src);
3621 char * tgt;
3623 if (tr_str_has_suffix (src, ".part"))
3624 tgt = tr_strdup_printf ("%s" TR_PATH_DELIMITER_STR "%s.part", parent, newname);
3625 else
3626 tgt = tr_buildPath (parent, newname, NULL);
3628 tmp = errno;
3629 tgt_exists = tr_fileExists (tgt, NULL);
3630 errno = tmp;
3632 if (!tgt_exists)
3634 int rv;
3636 tmp = errno;
3637 rv = tr_rename (src, tgt);
3638 if (rv != 0)
3639 error = errno;
3640 errno = tmp;
3643 tr_free (tgt);
3644 tr_free (parent);
3647 tr_free (src);
3649 return error;
3652 static void
3653 renameTorrentFileString (tr_torrent * tor,
3654 const char * oldpath,
3655 const char * newname,
3656 tr_file_index_t fileIndex)
3658 char * name;
3659 tr_file * file = &tor->info.files[fileIndex];
3660 const size_t oldpath_len = strlen (oldpath);
3662 if (strchr (oldpath, TR_PATH_DELIMITER) == NULL)
3664 if (oldpath_len >= strlen(file->name))
3665 name = tr_buildPath (newname, NULL);
3666 else
3667 name = tr_buildPath (newname, file->name + oldpath_len + 1, NULL);
3669 else
3671 char * tmp = tr_dirname (oldpath);
3673 if (oldpath_len >= strlen(file->name))
3674 name = tr_buildPath (tmp, newname, NULL);
3675 else
3676 name = tr_buildPath (tmp, newname, file->name + oldpath_len + 1, NULL);
3678 tr_free (tmp);
3681 if (!strcmp (file->name, name))
3683 tr_free (name);
3685 else
3687 tr_free (file->name);
3688 file->name = name;
3689 file->is_renamed = true;
3693 struct rename_data
3695 tr_torrent * tor;
3696 char * oldpath;
3697 char * newname;
3698 tr_torrent_rename_done_func * callback;
3699 void * callback_user_data;
3702 static void
3703 torrentRenamePath (void * vdata)
3705 int error = 0;
3706 struct rename_data * data = vdata;
3707 tr_torrent * const tor = data->tor;
3708 const char * const oldpath = data->oldpath;
3709 const char * const newname = data->newname;
3711 /***
3712 ****
3713 ***/
3715 assert (tr_isTorrent (tor));
3717 if (!renameArgsAreValid (oldpath, newname))
3719 error = EINVAL;
3721 else
3723 size_t n;
3724 tr_file_index_t * file_indices;
3726 file_indices = renameFindAffectedFiles (tor, oldpath, &n);
3727 if (n == 0)
3729 errno = EINVAL;
3731 else
3733 size_t i;
3735 error = renamePath (tor, oldpath, newname);
3737 if (!error)
3739 /* update tr_info.files */
3740 for (i=0; i<n; ++i)
3741 renameTorrentFileString(tor, oldpath, newname, file_indices[i]);
3743 /* update tr_info.name if user changed the toplevel */
3744 if ((n == tor->info.fileCount) && (strchr(oldpath,'/')==NULL))
3746 tr_free (tor->info.name);
3747 tor->info.name = tr_strdup (newname);
3750 tr_torrentSetDirty (tor);
3754 tr_free (file_indices);
3758 /***
3759 ****
3760 ***/
3762 tor->anyDate = tr_time ();
3764 /* callback */
3765 if (data->callback != NULL)
3766 (*data->callback)(tor, data->oldpath, data->newname, error, data->callback_user_data);
3768 /* cleanup */
3769 tr_free (data->oldpath);
3770 tr_free (data->newname);
3771 tr_free (data);
3774 void
3775 tr_torrentRenamePath (tr_torrent * tor,
3776 const char * oldpath,
3777 const char * newname,
3778 tr_torrent_rename_done_func callback,
3779 void * callback_user_data)
3781 struct rename_data * data;
3783 data = tr_new0 (struct rename_data, 1);
3784 data->tor = tor;
3785 data->oldpath = tr_strdup (oldpath);
3786 data->newname = tr_strdup (newname);
3787 data->callback = callback;
3788 data->callback_user_data = callback_user_data;
3790 tr_runInEventThread (tor->session, torrentRenamePath, data);