]> granicus.if.org Git - transmission/blob - libtransmission/torrent.c
Update to Uncrustify 0.68.1
[transmission] / libtransmission / torrent.c
1 /*
2  * This file Copyright (C) 2009-2017 Mnemosyne LLC
3  *
4  * It may be used under the GNU GPL versions 2 or 3
5  * or any future license endorsed by Mnemosyne LLC.
6  *
7  */
8
9 #include <errno.h> /* EINVAL */
10 #include <signal.h> /* signal() */
11
12 #ifndef _WIN32
13 #include <sys/wait.h> /* wait() */
14 #include <unistd.h> /* fork(), execvp(), _exit() */
15 #else
16 #include <windows.h> /* CreateProcess(), GetLastError() */
17 #endif
18
19 #include <math.h>
20 #include <stdarg.h>
21 #include <string.h> /* memcmp */
22 #include <stdlib.h> /* qsort */
23 #include <limits.h> /* INT_MAX */
24
25 #include <event2/util.h> /* evutil_vsnprintf() */
26
27 #include "transmission.h"
28 #include "announcer.h"
29 #include "bandwidth.h"
30 #include "cache.h"
31 #include "completion.h"
32 #include "crypto-utils.h" /* for tr_sha1 */
33 #include "error.h"
34 #include "fdlimit.h" /* tr_fdTorrentClose */
35 #include "file.h"
36 #include "inout.h" /* tr_ioTestPiece() */
37 #include "log.h"
38 #include "magnet.h"
39 #include "metainfo.h"
40 #include "peer-common.h" /* MAX_BLOCK_SIZE */
41 #include "peer-mgr.h"
42 #include "platform.h" /* TR_PATH_DELIMITER_STR */
43 #include "ptrarray.h"
44 #include "resume.h"
45 #include "session.h"
46 #include "subprocess.h"
47 #include "torrent.h"
48 #include "torrent-magnet.h"
49 #include "tr-assert.h"
50 #include "trevent.h" /* tr_runInEventThread() */
51 #include "utils.h"
52 #include "variant.h"
53 #include "verify.h"
54 #include "version.h"
55
56 /***
57 ****
58 ***/
59
60 #define tr_deeplog_tor(tor, ...) tr_logAddDeepNamed(tr_torrentName(tor), __VA_ARGS__)
61
62 /***
63 ****
64 ***/
65
66 char const* tr_torrentName(tr_torrent const* tor)
67 {
68     return tor != NULL ? tor->info.name : "";
69 }
70
71 int tr_torrentId(tr_torrent const* tor)
72 {
73     return tor != NULL ? tor->uniqueId : -1;
74 }
75
76 tr_torrent* tr_torrentFindFromId(tr_session* session, int id)
77 {
78     tr_torrent* tor = NULL;
79
80     while ((tor = tr_torrentNext(session, tor)) != NULL)
81     {
82         if (tor->uniqueId == id)
83         {
84             return tor;
85         }
86     }
87
88     return NULL;
89 }
90
91 tr_torrent* tr_torrentFindFromHashString(tr_session* session, char const* str)
92 {
93     tr_torrent* tor = NULL;
94
95     while ((tor = tr_torrentNext(session, tor)) != NULL)
96     {
97         if (!evutil_ascii_strcasecmp(str, tor->info.hashString))
98         {
99             return tor;
100         }
101     }
102
103     return NULL;
104 }
105
106 tr_torrent* tr_torrentFindFromHash(tr_session* session, uint8_t const* torrentHash)
107 {
108     tr_torrent* tor = NULL;
109
110     while ((tor = tr_torrentNext(session, tor)) != NULL)
111     {
112         if (*tor->info.hash == *torrentHash)
113         {
114             if (memcmp(tor->info.hash, torrentHash, SHA_DIGEST_LENGTH) == 0)
115             {
116                 return tor;
117             }
118         }
119     }
120
121     return NULL;
122 }
123
124 tr_torrent* tr_torrentFindFromMagnetLink(tr_session* session, char const* magnet)
125 {
126     tr_magnet_info* info;
127     tr_torrent* tor = NULL;
128
129     if ((info = tr_magnetParse(magnet)) != NULL)
130     {
131         tor = tr_torrentFindFromHash(session, info->hash);
132         tr_magnetFree(info);
133     }
134
135     return tor;
136 }
137
138 tr_torrent* tr_torrentFindFromObfuscatedHash(tr_session* session, uint8_t const* obfuscatedTorrentHash)
139 {
140     tr_torrent* tor = NULL;
141
142     while ((tor = tr_torrentNext(session, tor)) != NULL)
143     {
144         if (memcmp(tor->obfuscatedHash, obfuscatedTorrentHash, SHA_DIGEST_LENGTH) == 0)
145         {
146             return tor;
147         }
148     }
149
150     return NULL;
151 }
152
153 bool tr_torrentIsPieceTransferAllowed(tr_torrent const* tor, tr_direction direction)
154 {
155     TR_ASSERT(tr_isTorrent(tor));
156     TR_ASSERT(tr_isDirection(direction));
157
158     bool allowed = true;
159
160     if (tr_torrentUsesSpeedLimit(tor, direction))
161     {
162         if (tr_torrentGetSpeedLimit_Bps(tor, direction) <= 0)
163         {
164             allowed = false;
165         }
166     }
167
168     if (tr_torrentUsesSessionLimits(tor))
169     {
170         unsigned int limit;
171
172         if (tr_sessionGetActiveSpeedLimit_Bps(tor->session, direction, &limit))
173         {
174             if (limit <= 0)
175             {
176                 allowed = false;
177             }
178         }
179     }
180
181     return allowed;
182 }
183
184 /***
185 ****
186 ***/
187
188 static void tr_torrentUnsetPeerId(tr_torrent* tor)
189 {
190     /* triggers a rebuild next time tr_torrentGetPeerId() is called */
191     *tor->peer_id = '\0';
192 }
193
194 static int peerIdTTL(tr_torrent const* tor)
195 {
196     int ttl;
197
198     if (tor->peer_id_creation_time == 0)
199     {
200         ttl = 0;
201     }
202     else
203     {
204         ttl = (int)difftime(tor->peer_id_creation_time + tor->session->peer_id_ttl_hours * 3600, tr_time());
205     }
206
207     return ttl;
208 }
209
210 unsigned char const* tr_torrentGetPeerId(tr_torrent* tor)
211 {
212     bool needs_new_peer_id = false;
213
214     if (*tor->peer_id == '\0')
215     {
216         needs_new_peer_id = true;
217     }
218
219     if (!needs_new_peer_id)
220     {
221         if (!tr_torrentIsPrivate(tor))
222         {
223             if (peerIdTTL(tor) <= 0)
224             {
225                 needs_new_peer_id = true;
226             }
227         }
228     }
229
230     if (needs_new_peer_id)
231     {
232         tr_peerIdInit(tor->peer_id);
233         tor->peer_id_creation_time = tr_time();
234     }
235
236     return tor->peer_id;
237 }
238 /***
239 ****  PER-TORRENT UL / DL SPEEDS
240 ***/
241
242 void tr_torrentSetSpeedLimit_Bps(tr_torrent* tor, tr_direction dir, unsigned int Bps)
243 {
244     TR_ASSERT(tr_isTorrent(tor));
245     TR_ASSERT(tr_isDirection(dir));
246
247     if (tr_bandwidthSetDesiredSpeed_Bps(&tor->bandwidth, dir, Bps))
248     {
249         tr_torrentSetDirty(tor);
250     }
251 }
252
253 void tr_torrentSetSpeedLimit_KBps(tr_torrent* tor, tr_direction dir, unsigned int KBps)
254 {
255     tr_torrentSetSpeedLimit_Bps(tor, dir, toSpeedBytes(KBps));
256 }
257
258 unsigned int tr_torrentGetSpeedLimit_Bps(tr_torrent const* tor, tr_direction dir)
259 {
260     TR_ASSERT(tr_isTorrent(tor));
261     TR_ASSERT(tr_isDirection(dir));
262
263     return tr_bandwidthGetDesiredSpeed_Bps(&tor->bandwidth, dir);
264 }
265
266 unsigned int tr_torrentGetSpeedLimit_KBps(tr_torrent const* tor, tr_direction dir)
267 {
268     TR_ASSERT(tr_isTorrent(tor));
269     TR_ASSERT(tr_isDirection(dir));
270
271     return toSpeedKBps(tr_torrentGetSpeedLimit_Bps(tor, dir));
272 }
273
274 void tr_torrentUseSpeedLimit(tr_torrent* tor, tr_direction dir, bool do_use)
275 {
276     TR_ASSERT(tr_isTorrent(tor));
277     TR_ASSERT(tr_isDirection(dir));
278
279     if (tr_bandwidthSetLimited(&tor->bandwidth, dir, do_use))
280     {
281         tr_torrentSetDirty(tor);
282     }
283 }
284
285 bool tr_torrentUsesSpeedLimit(tr_torrent const* tor, tr_direction dir)
286 {
287     TR_ASSERT(tr_isTorrent(tor));
288
289     return tr_bandwidthIsLimited(&tor->bandwidth, dir);
290 }
291
292 void tr_torrentUseSessionLimits(tr_torrent* tor, bool doUse)
293 {
294     TR_ASSERT(tr_isTorrent(tor));
295
296     bool changed;
297
298     changed = tr_bandwidthHonorParentLimits(&tor->bandwidth, TR_UP, doUse);
299     changed |= tr_bandwidthHonorParentLimits(&tor->bandwidth, TR_DOWN, doUse);
300
301     if (changed)
302     {
303         tr_torrentSetDirty(tor);
304     }
305 }
306
307 bool tr_torrentUsesSessionLimits(tr_torrent const* tor)
308 {
309     TR_ASSERT(tr_isTorrent(tor));
310
311     return tr_bandwidthAreParentLimitsHonored(&tor->bandwidth, TR_UP);
312 }
313
314 /***
315 ****
316 ***/
317
318 void tr_torrentSetRatioMode(tr_torrent* tor, tr_ratiolimit mode)
319 {
320     TR_ASSERT(tr_isTorrent(tor));
321     TR_ASSERT(mode == TR_RATIOLIMIT_GLOBAL || mode == TR_RATIOLIMIT_SINGLE || mode == TR_RATIOLIMIT_UNLIMITED);
322
323     if (mode != tor->ratioLimitMode)
324     {
325         tor->ratioLimitMode = mode;
326
327         tr_torrentSetDirty(tor);
328     }
329 }
330
331 tr_ratiolimit tr_torrentGetRatioMode(tr_torrent const* tor)
332 {
333     TR_ASSERT(tr_isTorrent(tor));
334
335     return tor->ratioLimitMode;
336 }
337
338 void tr_torrentSetRatioLimit(tr_torrent* tor, double desiredRatio)
339 {
340     TR_ASSERT(tr_isTorrent(tor));
341
342     if ((int)(desiredRatio * 100.0) != (int)(tor->desiredRatio * 100.0))
343     {
344         tor->desiredRatio = desiredRatio;
345
346         tr_torrentSetDirty(tor);
347     }
348 }
349
350 double tr_torrentGetRatioLimit(tr_torrent const* tor)
351 {
352     TR_ASSERT(tr_isTorrent(tor));
353
354     return tor->desiredRatio;
355 }
356
357 bool tr_torrentGetSeedRatio(tr_torrent const* tor, double* ratio)
358 {
359     TR_ASSERT(tr_isTorrent(tor));
360
361     bool isLimited;
362
363     switch (tr_torrentGetRatioMode(tor))
364     {
365     case TR_RATIOLIMIT_SINGLE:
366         isLimited = true;
367
368         if (ratio != NULL)
369         {
370             *ratio = tr_torrentGetRatioLimit(tor);
371         }
372
373         break;
374
375     case TR_RATIOLIMIT_GLOBAL:
376         isLimited = tr_sessionIsRatioLimited(tor->session);
377
378         if (isLimited && ratio != NULL)
379         {
380             *ratio = tr_sessionGetRatioLimit(tor->session);
381         }
382
383         break;
384
385     default: /* TR_RATIOLIMIT_UNLIMITED */
386         isLimited = false;
387         break;
388     }
389
390     return isLimited;
391 }
392
393 /* returns true if the seed ratio applies --
394  * it applies if the torrent's a seed AND it has a seed ratio set */
395 static bool tr_torrentGetSeedRatioBytes(tr_torrent const* tor, uint64_t* setmeLeft, uint64_t* setmeGoal)
396 {
397     TR_ASSERT(tr_isTorrent(tor));
398
399     double seedRatio;
400     bool seedRatioApplies = false;
401
402     if (tr_torrentGetSeedRatio(tor, &seedRatio))
403     {
404         uint64_t const u = tor->uploadedCur + tor->uploadedPrev;
405         uint64_t const d = tor->downloadedCur + tor->downloadedPrev;
406         uint64_t const baseline = d != 0 ? d : tr_cpSizeWhenDone(&tor->completion);
407         uint64_t const goal = baseline * seedRatio;
408
409         if (setmeLeft != NULL)
410         {
411             *setmeLeft = goal > u ? goal - u : 0;
412         }
413
414         if (setmeGoal != NULL)
415         {
416             *setmeGoal = goal;
417         }
418
419         seedRatioApplies = tr_torrentIsSeed(tor);
420     }
421
422     return seedRatioApplies;
423 }
424
425 static bool tr_torrentIsSeedRatioDone(tr_torrent const* tor)
426 {
427     uint64_t bytesLeft;
428     return tr_torrentGetSeedRatioBytes(tor, &bytesLeft, NULL) && bytesLeft == 0;
429 }
430
431 /***
432 ****
433 ***/
434
435 void tr_torrentSetIdleMode(tr_torrent* tor, tr_idlelimit mode)
436 {
437     TR_ASSERT(tr_isTorrent(tor));
438     TR_ASSERT(mode == TR_IDLELIMIT_GLOBAL || mode == TR_IDLELIMIT_SINGLE || mode == TR_IDLELIMIT_UNLIMITED);
439
440     if (mode != tor->idleLimitMode)
441     {
442         tor->idleLimitMode = mode;
443
444         tr_torrentSetDirty(tor);
445     }
446 }
447
448 tr_idlelimit tr_torrentGetIdleMode(tr_torrent const* tor)
449 {
450     TR_ASSERT(tr_isTorrent(tor));
451
452     return tor->idleLimitMode;
453 }
454
455 void tr_torrentSetIdleLimit(tr_torrent* tor, uint16_t idleMinutes)
456 {
457     TR_ASSERT(tr_isTorrent(tor));
458
459     if (idleMinutes > 0)
460     {
461         tor->idleLimitMinutes = idleMinutes;
462
463         tr_torrentSetDirty(tor);
464     }
465 }
466
467 uint16_t tr_torrentGetIdleLimit(tr_torrent const* tor)
468 {
469     TR_ASSERT(tr_isTorrent(tor));
470
471     return tor->idleLimitMinutes;
472 }
473
474 bool tr_torrentGetSeedIdle(tr_torrent const* tor, uint16_t* idleMinutes)
475 {
476     bool isLimited;
477
478     switch (tr_torrentGetIdleMode(tor))
479     {
480     case TR_IDLELIMIT_SINGLE:
481         isLimited = true;
482
483         if (idleMinutes != NULL)
484         {
485             *idleMinutes = tr_torrentGetIdleLimit(tor);
486         }
487
488         break;
489
490     case TR_IDLELIMIT_GLOBAL:
491         isLimited = tr_sessionIsIdleLimited(tor->session);
492
493         if (isLimited && idleMinutes != NULL)
494         {
495             *idleMinutes = tr_sessionGetIdleLimit(tor->session);
496         }
497
498         break;
499
500     default: /* TR_IDLELIMIT_UNLIMITED */
501         isLimited = false;
502         break;
503     }
504
505     return isLimited;
506 }
507
508 static bool tr_torrentIsSeedIdleLimitDone(tr_torrent* tor)
509 {
510     uint16_t idleMinutes;
511     return tr_torrentGetSeedIdle(tor, &idleMinutes) &&
512         difftime(tr_time(), MAX(tor->startDate, tor->activityDate)) >= idleMinutes * 60u;
513 }
514
515 /***
516 ****
517 ***/
518
519 void tr_torrentCheckSeedLimit(tr_torrent* tor)
520 {
521     TR_ASSERT(tr_isTorrent(tor));
522
523     if (!tor->isRunning || tor->isStopping || !tr_torrentIsSeed(tor))
524     {
525         return;
526     }
527
528     /* if we're seeding and reach our seed ratio limit, stop the torrent */
529     if (tr_torrentIsSeedRatioDone(tor))
530     {
531         tr_logAddTorInfo(tor, "%s", "Seed ratio reached; pausing torrent");
532
533         tor->isStopping = true;
534
535         /* maybe notify the client */
536         if (tor->ratio_limit_hit_func != NULL)
537         {
538             (*tor->ratio_limit_hit_func)(tor, tor->ratio_limit_hit_func_user_data);
539         }
540     }
541     /* if we're seeding and reach our inactiviy limit, stop the torrent */
542     else if (tr_torrentIsSeedIdleLimitDone(tor))
543     {
544         tr_logAddTorInfo(tor, "%s", "Seeding idle limit reached; pausing torrent");
545
546         tor->isStopping = true;
547         tor->finishedSeedingByIdle = true;
548
549         /* maybe notify the client */
550         if (tor->idle_limit_hit_func != NULL)
551         {
552             (*tor->idle_limit_hit_func)(tor, tor->idle_limit_hit_func_user_data);
553         }
554     }
555 }
556
557 /***
558 ****
559 ***/
560
561 void tr_torrentSetLocalError(tr_torrent* tor, char const* fmt, ...)
562 {
563     TR_ASSERT(tr_isTorrent(tor));
564
565     va_list ap;
566
567     va_start(ap, fmt);
568     tor->error = TR_STAT_LOCAL_ERROR;
569     tor->errorTracker[0] = '\0';
570     evutil_vsnprintf(tor->errorString, sizeof(tor->errorString), fmt, ap);
571     va_end(ap);
572
573     tr_logAddTorErr(tor, "%s", tor->errorString);
574
575     if (tor->isRunning)
576     {
577         tor->isStopping = true;
578     }
579 }
580
581 static void tr_torrentClearError(tr_torrent* tor)
582 {
583     tor->error = TR_STAT_OK;
584     tor->errorString[0] = '\0';
585     tor->errorTracker[0] = '\0';
586 }
587
588 static void onTrackerResponse(tr_torrent* tor, tr_tracker_event const* event, void* unused UNUSED)
589 {
590     switch (event->messageType)
591     {
592     case TR_TRACKER_PEERS:
593         {
594             int8_t const seedProbability = event->seedProbability;
595             bool const allAreSeeds = seedProbability == 100;
596
597             if (allAreSeeds)
598             {
599                 tr_logAddTorDbg(tor, "Got %zu seeds from tracker", event->pexCount);
600             }
601             else
602             {
603                 tr_logAddTorDbg(tor, "Got %zu peers from tracker", event->pexCount);
604             }
605
606             for (size_t i = 0; i < event->pexCount; ++i)
607             {
608                 tr_peerMgrAddPex(tor, TR_PEER_FROM_TRACKER, &event->pex[i], seedProbability);
609             }
610
611             break;
612         }
613
614     case TR_TRACKER_WARNING:
615         tr_logAddTorErr(tor, _("Tracker warning: \"%s\""), event->text);
616         tor->error = TR_STAT_TRACKER_WARNING;
617         tr_strlcpy(tor->errorTracker, event->tracker, sizeof(tor->errorTracker));
618         tr_strlcpy(tor->errorString, event->text, sizeof(tor->errorString));
619         break;
620
621     case TR_TRACKER_ERROR:
622         tr_logAddTorErr(tor, _("Tracker error: \"%s\""), event->text);
623         tor->error = TR_STAT_TRACKER_ERROR;
624         tr_strlcpy(tor->errorTracker, event->tracker, sizeof(tor->errorTracker));
625         tr_strlcpy(tor->errorString, event->text, sizeof(tor->errorString));
626         break;
627
628     case TR_TRACKER_ERROR_CLEAR:
629         if (tor->error != TR_STAT_LOCAL_ERROR)
630         {
631             tr_torrentClearError(tor);
632         }
633
634         break;
635     }
636 }
637
638 /***
639 ****
640 ****  TORRENT INSTANTIATION
641 ****
642 ***/
643
644 static tr_piece_index_t getBytePiece(tr_info const* info, uint64_t byteOffset)
645 {
646     TR_ASSERT(info != NULL);
647     TR_ASSERT(info->pieceSize != 0);
648
649     tr_piece_index_t piece = byteOffset / info->pieceSize;
650
651     /* handle 0-byte files at the end of a torrent */
652     if (byteOffset == info->totalSize)
653     {
654         piece = info->pieceCount - 1;
655     }
656
657     return piece;
658 }
659
660 static void initFilePieces(tr_info* info, tr_file_index_t fileIndex)
661 {
662     TR_ASSERT(info != NULL);
663     TR_ASSERT(fileIndex < info->fileCount);
664
665     tr_file* file = &info->files[fileIndex];
666     uint64_t firstByte = file->offset;
667     uint64_t lastByte = firstByte + (file->length != 0 ? file->length - 1 : 0);
668
669     file->firstPiece = getBytePiece(info, firstByte);
670     file->lastPiece = getBytePiece(info, lastByte);
671 }
672
673 static bool pieceHasFile(tr_piece_index_t piece, tr_file const* file)
674 {
675     return file->firstPiece <= piece && piece <= file->lastPiece;
676 }
677
678 static tr_priority_t calculatePiecePriority(tr_torrent const* tor, tr_piece_index_t piece, int fileHint)
679 {
680     tr_file_index_t firstFileIndex;
681     tr_priority_t priority = TR_PRI_LOW;
682
683     /* find the first file that has data in this piece */
684     if (fileHint >= 0)
685     {
686         firstFileIndex = fileHint;
687
688         while (firstFileIndex > 0 && pieceHasFile(piece, &tor->info.files[firstFileIndex - 1]))
689         {
690             --firstFileIndex;
691         }
692     }
693     else
694     {
695         firstFileIndex = 0;
696
697         for (tr_file_index_t i = 0; i < tor->info.fileCount; ++i, ++firstFileIndex)
698         {
699             if (pieceHasFile(piece, &tor->info.files[i]))
700             {
701                 break;
702             }
703         }
704     }
705
706     /* the piece's priority is the max of the priorities
707      * of all the files in that piece */
708     for (tr_file_index_t i = firstFileIndex; i < tor->info.fileCount; ++i)
709     {
710         tr_file const* file = &tor->info.files[i];
711
712         if (!pieceHasFile(piece, file))
713         {
714             break;
715         }
716
717         priority = MAX(priority, file->priority);
718
719         /* when dealing with multimedia files, getting the first and
720            last pieces can sometimes allow you to preview it a bit
721            before it's fully downloaded... */
722         if (file->priority >= TR_PRI_NORMAL)
723         {
724             if (file->firstPiece == piece || file->lastPiece == piece)
725             {
726                 priority = TR_PRI_HIGH;
727             }
728         }
729     }
730
731     return priority;
732 }
733
734 static void tr_torrentInitFilePieces(tr_torrent* tor)
735 {
736     uint64_t offset = 0;
737     tr_info* inf = &tor->info;
738
739     /* assign the file offsets */
740     for (tr_file_index_t f = 0; f < inf->fileCount; ++f)
741     {
742         inf->files[f].offset = offset;
743         offset += inf->files[f].length;
744         initFilePieces(inf, f);
745     }
746
747     /* build the array of first-file hints to give calculatePiecePriority */
748     int* firstFiles = tr_new(int, inf->pieceCount);
749     tr_file_index_t f = 0;
750
751     for (tr_piece_index_t p = 0; p < inf->pieceCount; ++p)
752     {
753         while (inf->files[f].lastPiece < p)
754         {
755             ++f;
756         }
757
758         firstFiles[p] = f;
759     }
760
761 #if 0
762
763     /* test to confirm the first-file hints are correct */
764     for (tr_piece_index_t p = 0; p < inf->pieceCount; ++p)
765     {
766         tr_file_index_t f = firstFiles[p];
767
768         TR_ASSERT(inf->files[f].firstPiece <= p);
769         TR_ASSERT(inf->files[f].lastPiece >= p);
770
771         if (f > 0)
772         {
773             TR_ASSERT(inf->files[f - 1].lastPiece < p);
774         }
775
776         f = 0;
777
778         for (tr_file_index_t i = 0; i < inf->fileCount; ++i, ++f)
779         {
780             if (pieceHasFile(p, &inf->files[i]))
781             {
782                 break;
783             }
784         }
785
786         TR_ASSERT((int)f == firstFiles[p]);
787     }
788
789 #endif
790
791     for (tr_piece_index_t p = 0; p < inf->pieceCount; ++p)
792     {
793         inf->pieces[p].priority = calculatePiecePriority(tor, p, firstFiles[p]);
794     }
795
796     tr_free(firstFiles);
797 }
798
799 static void torrentStart(tr_torrent* tor, bool bypass_queue);
800
801 /**
802  * Decide on a block size. Constraints:
803  * (1) most clients decline requests over 16 KiB
804  * (2) pieceSize must be a multiple of block size
805  */
806 uint32_t tr_getBlockSize(uint32_t pieceSize)
807 {
808     uint32_t b = pieceSize;
809
810     while (b > MAX_BLOCK_SIZE)
811     {
812         b /= 2u;
813     }
814
815     if (b == 0 || pieceSize % b != 0) /* not cleanly divisible */
816     {
817         return 0;
818     }
819
820     return b;
821 }
822
823 static void refreshCurrentDir(tr_torrent* tor);
824
825 static void torrentInitFromInfo(tr_torrent* tor)
826 {
827     uint64_t t;
828     tr_info* info = &tor->info;
829
830     tor->blockSize = tr_getBlockSize(info->pieceSize);
831
832     if (info->pieceSize != 0)
833     {
834         tor->lastPieceSize = (uint32_t)(info->totalSize % info->pieceSize);
835     }
836
837     if (tor->lastPieceSize == 0)
838     {
839         tor->lastPieceSize = info->pieceSize;
840     }
841
842     if (tor->blockSize != 0)
843     {
844         tor->lastBlockSize = info->totalSize % tor->blockSize;
845     }
846
847     if (tor->lastBlockSize == 0)
848     {
849         tor->lastBlockSize = tor->blockSize;
850     }
851
852     tor->blockCount = tor->blockSize != 0 ? (info->totalSize + tor->blockSize - 1) / tor->blockSize : 0;
853     tor->blockCountInPiece = tor->blockSize != 0 ? info->pieceSize / tor->blockSize : 0;
854     tor->blockCountInLastPiece = tor->blockSize != 0 ? (tor->lastPieceSize + tor->blockSize - 1) / tor->blockSize : 0;
855
856     /* check our work */
857     if (tor->blockSize != 0)
858     {
859         TR_ASSERT(info->pieceSize % tor->blockSize == 0);
860     }
861
862     t = info->pieceCount - 1;
863     t *= info->pieceSize;
864     t += tor->lastPieceSize;
865     TR_ASSERT(t == info->totalSize);
866
867     t = tor->blockCount - 1;
868     t *= tor->blockSize;
869     t += tor->lastBlockSize;
870     TR_ASSERT(t == info->totalSize);
871
872     t = info->pieceCount - 1;
873     t *= tor->blockCountInPiece;
874     t += tor->blockCountInLastPiece;
875     TR_ASSERT(t == (uint64_t)tor->blockCount);
876
877     tr_cpConstruct(&tor->completion, tor);
878
879     tr_torrentInitFilePieces(tor);
880
881     tor->completeness = tr_cpGetStatus(&tor->completion);
882 }
883
884 static void tr_torrentFireMetadataCompleted(tr_torrent* tor);
885
886 void tr_torrentGotNewInfoDict(tr_torrent* tor)
887 {
888     torrentInitFromInfo(tor);
889
890     tr_peerMgrOnTorrentGotMetainfo(tor);
891
892     tr_torrentFireMetadataCompleted(tor);
893 }
894
895 static bool hasAnyLocalData(tr_torrent const* tor)
896 {
897     for (tr_file_index_t i = 0; i < tor->info.fileCount; ++i)
898     {
899         if (tr_torrentFindFile2(tor, i, NULL, NULL, NULL))
900         {
901             return true;
902         }
903     }
904
905     return false;
906 }
907
908 static bool setLocalErrorIfFilesDisappeared(tr_torrent* tor)
909 {
910     bool const disappeared = tr_torrentHaveTotal(tor) > 0 && !hasAnyLocalData(tor);
911
912     if (disappeared)
913     {
914         tr_deeplog_tor(tor, "%s", "[LAZY] uh oh, the files disappeared");
915         tr_torrentSetLocalError(tor, "%s", _("No data found! Ensure your drives are connected or use \"Set Location\". "
916             "To re-download, remove the torrent and re-add it."));
917     }
918
919     return disappeared;
920 }
921
922 static void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
923 {
924     tr_session* session = tr_ctorGetSession(ctor);
925
926     TR_ASSERT(session != NULL);
927
928     tr_sessionLock(session);
929
930     bool doStart;
931     uint64_t loaded;
932     char const* dir;
933     bool isNewTorrent;
934     static int nextUniqueId = 1;
935
936     tor->session = session;
937     tor->uniqueId = nextUniqueId++;
938     tor->magicNumber = TORRENT_MAGIC_NUMBER;
939     tor->queuePosition = session->torrentCount;
940
941     tr_sha1(tor->obfuscatedHash, "req2", 4, tor->info.hash, SHA_DIGEST_LENGTH, NULL);
942
943     if (tr_ctorGetDownloadDir(ctor, TR_FORCE, &dir) || tr_ctorGetDownloadDir(ctor, TR_FALLBACK, &dir))
944     {
945         tor->downloadDir = tr_strdup(dir);
946     }
947
948     if (!tr_ctorGetIncompleteDir(ctor, &dir))
949     {
950         dir = tr_sessionGetIncompleteDir(session);
951     }
952
953     if (tr_sessionIsIncompleteDirEnabled(session))
954     {
955         tor->incompleteDir = tr_strdup(dir);
956     }
957
958     tr_bandwidthConstruct(&tor->bandwidth, session, &session->bandwidth);
959
960     tor->bandwidth.priority = tr_ctorGetBandwidthPriority(ctor);
961     tor->error = TR_STAT_OK;
962     tor->finishedSeedingByIdle = false;
963
964     tr_peerMgrAddTorrent(session->peerMgr, tor);
965
966     TR_ASSERT(tor->downloadedCur == 0);
967     TR_ASSERT(tor->uploadedCur == 0);
968
969     tr_torrentSetAddedDate(tor, tr_time()); /* this is a default value to be overwritten by the resume file */
970
971     torrentInitFromInfo(tor);
972
973     bool didRenameResumeFileToHashOnlyName = false;
974     loaded = tr_torrentLoadResume(tor, ~0, ctor, &didRenameResumeFileToHashOnlyName);
975
976     if (didRenameResumeFileToHashOnlyName)
977     {
978         /* Rename torrent file as well */
979         tr_metainfoMigrateFile(session, &tor->info, TR_METAINFO_BASENAME_NAME_AND_PARTIAL_HASH, TR_METAINFO_BASENAME_HASH);
980     }
981
982     tor->completeness = tr_cpGetStatus(&tor->completion);
983     setLocalErrorIfFilesDisappeared(tor);
984
985     tr_ctorInitTorrentPriorities(ctor, tor);
986     tr_ctorInitTorrentWanted(ctor, tor);
987
988     refreshCurrentDir(tor);
989
990     doStart = tor->isRunning;
991     tor->isRunning = false;
992
993     if ((loaded & TR_FR_SPEEDLIMIT) == 0)
994     {
995         tr_torrentUseSpeedLimit(tor, TR_UP, false);
996         tr_torrentSetSpeedLimit_Bps(tor, TR_UP, tr_sessionGetSpeedLimit_Bps(tor->session, TR_UP));
997         tr_torrentUseSpeedLimit(tor, TR_DOWN, false);
998         tr_torrentSetSpeedLimit_Bps(tor, TR_DOWN, tr_sessionGetSpeedLimit_Bps(tor->session, TR_DOWN));
999         tr_torrentUseSessionLimits(tor, true);
1000     }
1001
1002     if ((loaded & TR_FR_RATIOLIMIT) == 0)
1003     {
1004         tr_torrentSetRatioMode(tor, TR_RATIOLIMIT_GLOBAL);
1005         tr_torrentSetRatioLimit(tor, tr_sessionGetRatioLimit(tor->session));
1006     }
1007
1008     if ((loaded & TR_FR_IDLELIMIT) == 0)
1009     {
1010         tr_torrentSetIdleMode(tor, TR_IDLELIMIT_GLOBAL);
1011         tr_torrentSetIdleLimit(tor, tr_sessionGetIdleLimit(tor->session));
1012     }
1013
1014     /* add the torrent to tr_session.torrentList */
1015     session->torrentCount++;
1016
1017     if (session->torrentList == NULL)
1018     {
1019         session->torrentList = tor;
1020     }
1021     else
1022     {
1023         tr_torrent* it = session->torrentList;
1024
1025         while (it->next != NULL)
1026         {
1027             it = it->next;
1028         }
1029
1030         it->next = tor;
1031     }
1032
1033     /* if we don't have a local .torrent file already, assume the torrent is new */
1034     isNewTorrent = !tr_sys_path_exists(tor->info.torrent, NULL);
1035
1036     /* maybe save our own copy of the metainfo */
1037     if (tr_ctorGetSave(ctor))
1038     {
1039         tr_variant const* val;
1040
1041         if (tr_ctorGetMetainfo(ctor, &val))
1042         {
1043             char const* path = tor->info.torrent;
1044             int const err = tr_variantToFile(val, TR_VARIANT_FMT_BENC, path);
1045
1046             if (err != 0)
1047             {
1048                 tr_torrentSetLocalError(tor, "Unable to save torrent file: %s", tr_strerror(err));
1049             }
1050
1051             tr_sessionSetTorrentFile(tor->session, tor->info.hashString, path);
1052         }
1053     }
1054
1055     tor->tiers = tr_announcerAddTorrent(tor, onTrackerResponse, NULL);
1056
1057     if (isNewTorrent)
1058     {
1059         tor->startAfterVerify = doStart;
1060         tr_torrentVerify(tor, NULL, NULL);
1061     }
1062     else if (doStart)
1063     {
1064         tr_torrentStart(tor);
1065     }
1066
1067     tr_sessionUnlock(session);
1068 }
1069
1070 static tr_parse_result torrentParseImpl(tr_ctor const* ctor, tr_info* setmeInfo, bool* setmeHasInfo, size_t* dictLength,
1071     int* setme_duplicate_id)
1072 {
1073     bool doFree;
1074     bool didParse;
1075     bool hasInfo = false;
1076     tr_info tmp;
1077     tr_variant const* metainfo;
1078     tr_session* session = tr_ctorGetSession(ctor);
1079     tr_parse_result result = TR_PARSE_OK;
1080
1081     if (setmeInfo == NULL)
1082     {
1083         setmeInfo = &tmp;
1084     }
1085
1086     memset(setmeInfo, 0, sizeof(tr_info));
1087
1088     if (!tr_ctorGetMetainfo(ctor, &metainfo))
1089     {
1090         return TR_PARSE_ERR;
1091     }
1092
1093     didParse = tr_metainfoParse(session, metainfo, setmeInfo, &hasInfo, dictLength);
1094     doFree = didParse && (setmeInfo == &tmp);
1095
1096     if (!didParse)
1097     {
1098         result = TR_PARSE_ERR;
1099     }
1100
1101     if (didParse && hasInfo && !tr_getBlockSize(setmeInfo->pieceSize))
1102     {
1103         result = TR_PARSE_ERR;
1104     }
1105
1106     if (didParse && session != NULL && result == TR_PARSE_OK)
1107     {
1108         tr_torrent const* const tor = tr_torrentFindFromHash(session, setmeInfo->hash);
1109
1110         if (tor != NULL)
1111         {
1112             result = TR_PARSE_DUPLICATE;
1113
1114             if (setme_duplicate_id != NULL)
1115             {
1116                 *setme_duplicate_id = tr_torrentId(tor);
1117             }
1118         }
1119     }
1120
1121     if (doFree)
1122     {
1123         tr_metainfoFree(setmeInfo);
1124     }
1125
1126     if (setmeHasInfo != NULL)
1127     {
1128         *setmeHasInfo = hasInfo;
1129     }
1130
1131     return result;
1132 }
1133
1134 tr_parse_result tr_torrentParse(tr_ctor const* ctor, tr_info* setmeInfo)
1135 {
1136     return torrentParseImpl(ctor, setmeInfo, NULL, NULL, NULL);
1137 }
1138
1139 tr_torrent* tr_torrentNew(tr_ctor const* ctor, int* setme_error, int* setme_duplicate_id)
1140 {
1141     TR_ASSERT(ctor != NULL);
1142     TR_ASSERT(tr_isSession(tr_ctorGetSession(ctor)));
1143
1144     size_t len;
1145     bool hasInfo;
1146     tr_info tmpInfo;
1147     tr_parse_result r;
1148     tr_torrent* tor = NULL;
1149
1150     r = torrentParseImpl(ctor, &tmpInfo, &hasInfo, &len, setme_duplicate_id);
1151
1152     if (r == TR_PARSE_OK)
1153     {
1154         tor = tr_new0(tr_torrent, 1);
1155         tor->info = tmpInfo;
1156
1157         if (hasInfo)
1158         {
1159             tor->infoDictLength = len;
1160         }
1161
1162         torrentInit(tor, ctor);
1163     }
1164     else
1165     {
1166         if (r == TR_PARSE_DUPLICATE)
1167         {
1168             tr_metainfoFree(&tmpInfo);
1169         }
1170
1171         if (setme_error != NULL)
1172         {
1173             *setme_error = r;
1174         }
1175     }
1176
1177     return tor;
1178 }
1179
1180 /**
1181 ***
1182 **/
1183
1184 void tr_torrentSetDownloadDir(tr_torrent* tor, char const* path)
1185 {
1186     TR_ASSERT(tr_isTorrent(tor));
1187
1188     if (path == NULL || tor->downloadDir == NULL || strcmp(path, tor->downloadDir) != 0)
1189     {
1190         tr_free(tor->downloadDir);
1191         tor->downloadDir = tr_strdup(path);
1192         tr_torrentSetDirty(tor);
1193     }
1194
1195     refreshCurrentDir(tor);
1196 }
1197
1198 char const* tr_torrentGetDownloadDir(tr_torrent const* tor)
1199 {
1200     TR_ASSERT(tr_isTorrent(tor));
1201
1202     return tor->downloadDir;
1203 }
1204
1205 char const* tr_torrentGetCurrentDir(tr_torrent const* tor)
1206 {
1207     TR_ASSERT(tr_isTorrent(tor));
1208
1209     return tor->currentDir;
1210 }
1211
1212 void tr_torrentChangeMyPort(tr_torrent* tor)
1213 {
1214     TR_ASSERT(tr_isTorrent(tor));
1215
1216     if (tor->isRunning)
1217     {
1218         tr_announcerChangeMyPort(tor);
1219     }
1220 }
1221
1222 static inline void tr_torrentManualUpdateImpl(void* vtor)
1223 {
1224     tr_torrent* tor = vtor;
1225
1226     TR_ASSERT(tr_isTorrent(tor));
1227
1228     if (tor->isRunning)
1229     {
1230         tr_announcerManualAnnounce(tor);
1231     }
1232 }
1233
1234 void tr_torrentManualUpdate(tr_torrent* tor)
1235 {
1236     TR_ASSERT(tr_isTorrent(tor));
1237
1238     tr_runInEventThread(tor->session, tr_torrentManualUpdateImpl, tor);
1239 }
1240
1241 bool tr_torrentCanManualUpdate(tr_torrent const* tor)
1242 {
1243     return tr_isTorrent(tor) && tor->isRunning && tr_announcerCanManualAnnounce(tor);
1244 }
1245
1246 tr_info const* tr_torrentInfo(tr_torrent const* tor)
1247 {
1248     return tr_isTorrent(tor) ? &tor->info : NULL;
1249 }
1250
1251 tr_stat const* tr_torrentStatCached(tr_torrent* tor)
1252 {
1253     time_t const now = tr_time();
1254
1255     return (tr_isTorrent(tor) && now == tor->lastStatTime) ? &tor->stats : tr_torrentStat(tor);
1256 }
1257
1258 void tr_torrentSetVerifyState(tr_torrent* tor, tr_verify_state state)
1259 {
1260     TR_ASSERT(tr_isTorrent(tor));
1261     TR_ASSERT(state == TR_VERIFY_NONE || state == TR_VERIFY_WAIT || state == TR_VERIFY_NOW);
1262
1263     tor->verifyState = state;
1264     tor->anyDate = tr_time();
1265 }
1266
1267 tr_torrent_activity tr_torrentGetActivity(tr_torrent const* tor)
1268 {
1269     tr_torrent_activity ret = TR_STATUS_STOPPED;
1270
1271     bool const is_seed = tr_torrentIsSeed(tor);
1272
1273     if (tor->verifyState == TR_VERIFY_NOW)
1274     {
1275         ret = TR_STATUS_CHECK;
1276     }
1277     else if (tor->verifyState == TR_VERIFY_WAIT)
1278     {
1279         ret = TR_STATUS_CHECK_WAIT;
1280     }
1281     else if (tor->isRunning)
1282     {
1283         ret = is_seed ? TR_STATUS_SEED : TR_STATUS_DOWNLOAD;
1284     }
1285     else if (tr_torrentIsQueued(tor))
1286     {
1287         if (is_seed && tr_sessionGetQueueEnabled(tor->session, TR_UP))
1288         {
1289             ret = TR_STATUS_SEED_WAIT;
1290         }
1291         else if (!is_seed && tr_sessionGetQueueEnabled(tor->session, TR_DOWN))
1292         {
1293             ret = TR_STATUS_DOWNLOAD_WAIT;
1294         }
1295     }
1296
1297     return ret;
1298 }
1299
1300 static time_t torrentGetIdleSecs(tr_torrent const* tor)
1301 {
1302     int idle_secs;
1303     tr_torrent_activity const activity = tr_torrentGetActivity(tor);
1304
1305     if ((activity == TR_STATUS_DOWNLOAD || activity == TR_STATUS_SEED) && tor->startDate != 0)
1306     {
1307         idle_secs = difftime(tr_time(), MAX(tor->startDate, tor->activityDate));
1308     }
1309     else
1310     {
1311         idle_secs = -1;
1312     }
1313
1314     return idle_secs;
1315 }
1316
1317 bool tr_torrentIsStalled(tr_torrent const* tor)
1318 {
1319     return tr_sessionGetQueueStalledEnabled(tor->session) &&
1320         torrentGetIdleSecs(tor) > tr_sessionGetQueueStalledMinutes(tor->session) * 60;
1321 }
1322
1323 static double getVerifyProgress(tr_torrent const* tor)
1324 {
1325     double d = 0;
1326
1327     if (tr_torrentHasMetadata(tor))
1328     {
1329         tr_piece_index_t checked = 0;
1330
1331         for (tr_piece_index_t i = 0; i < tor->info.pieceCount; ++i)
1332         {
1333             if (tor->info.pieces[i].timeChecked != 0)
1334             {
1335                 ++checked;
1336             }
1337         }
1338
1339         d = checked / (double)tor->info.pieceCount;
1340     }
1341
1342     return d;
1343 }
1344
1345 tr_stat const* tr_torrentStat(tr_torrent* tor)
1346 {
1347     TR_ASSERT(tr_isTorrent(tor));
1348
1349     uint64_t const now = tr_time_msec();
1350
1351     tr_stat* s;
1352     uint64_t seedRatioBytesLeft;
1353     uint64_t seedRatioBytesGoal;
1354     bool seedRatioApplies;
1355     uint16_t seedIdleMinutes;
1356     unsigned int pieceUploadSpeed_Bps;
1357     unsigned int pieceDownloadSpeed_Bps;
1358     struct tr_swarm_stats swarm_stats;
1359
1360     tor->lastStatTime = tr_time();
1361
1362     if (tor->swarm != NULL)
1363     {
1364         tr_swarmGetStats(tor->swarm, &swarm_stats);
1365     }
1366     else
1367     {
1368         swarm_stats = TR_SWARM_STATS_INIT;
1369     }
1370
1371     s = &tor->stats;
1372     s->id = tor->uniqueId;
1373     s->activity = tr_torrentGetActivity(tor);
1374     s->error = tor->error;
1375     s->queuePosition = tor->queuePosition;
1376     s->isStalled = tr_torrentIsStalled(tor);
1377     tr_strlcpy(s->errorString, tor->errorString, sizeof(s->errorString));
1378
1379     s->manualAnnounceTime = tr_announcerNextManualAnnounce(tor);
1380     s->peersConnected = swarm_stats.peerCount;
1381     s->peersSendingToUs = swarm_stats.activePeerCount[TR_DOWN];
1382     s->peersGettingFromUs = swarm_stats.activePeerCount[TR_UP];
1383     s->webseedsSendingToUs = swarm_stats.activeWebseedCount;
1384
1385     for (int i = 0; i < TR_PEER_FROM__MAX; i++)
1386     {
1387         s->peersFrom[i] = swarm_stats.peerFromCount[i];
1388     }
1389
1390     s->rawUploadSpeed_KBps = toSpeedKBps(tr_bandwidthGetRawSpeed_Bps(&tor->bandwidth, now, TR_UP));
1391     s->rawDownloadSpeed_KBps = toSpeedKBps(tr_bandwidthGetRawSpeed_Bps(&tor->bandwidth, now, TR_DOWN));
1392     pieceUploadSpeed_Bps = tr_bandwidthGetPieceSpeed_Bps(&tor->bandwidth, now, TR_UP);
1393     pieceDownloadSpeed_Bps = tr_bandwidthGetPieceSpeed_Bps(&tor->bandwidth, now, TR_DOWN);
1394     s->pieceUploadSpeed_KBps = toSpeedKBps(pieceUploadSpeed_Bps);
1395     s->pieceDownloadSpeed_KBps = toSpeedKBps(pieceDownloadSpeed_Bps);
1396
1397     s->percentComplete = tr_cpPercentComplete(&tor->completion);
1398     s->metadataPercentComplete = tr_torrentGetMetadataPercent(tor);
1399
1400     s->percentDone = tr_cpPercentDone(&tor->completion);
1401     s->leftUntilDone = tr_torrentGetLeftUntilDone(tor);
1402     s->sizeWhenDone = tr_cpSizeWhenDone(&tor->completion);
1403     s->recheckProgress = s->activity == TR_STATUS_CHECK ? getVerifyProgress(tor) : 0;
1404     s->activityDate = tor->activityDate;
1405     s->addedDate = tor->addedDate;
1406     s->doneDate = tor->doneDate;
1407     s->startDate = tor->startDate;
1408     s->secondsSeeding = tor->secondsSeeding;
1409     s->secondsDownloading = tor->secondsDownloading;
1410     s->idleSecs = torrentGetIdleSecs(tor);
1411
1412     s->corruptEver = tor->corruptCur + tor->corruptPrev;
1413     s->downloadedEver = tor->downloadedCur + tor->downloadedPrev;
1414     s->uploadedEver = tor->uploadedCur + tor->uploadedPrev;
1415     s->haveValid = tr_cpHaveValid(&tor->completion);
1416     s->haveUnchecked = tr_torrentHaveTotal(tor) - s->haveValid;
1417     s->desiredAvailable = tr_peerMgrGetDesiredAvailable(tor);
1418
1419     s->ratio = tr_getRatio(s->uploadedEver, s->downloadedEver ? s->downloadedEver : s->haveValid);
1420
1421     seedRatioApplies = tr_torrentGetSeedRatioBytes(tor, &seedRatioBytesLeft, &seedRatioBytesGoal);
1422
1423     switch (s->activity)
1424     {
1425     /* etaXLSpeed exists because if we use the piece speed directly,
1426      * brief fluctuations cause the ETA to jump all over the place.
1427      * so, etaXLSpeed is a smoothed-out version of the piece speed
1428      * to dampen the effect of fluctuations */
1429     case TR_STATUS_DOWNLOAD:
1430         if (tor->etaDLSpeedCalculatedAt + 800 < now)
1431         {
1432             tor->etaDLSpeed_Bps = tor->etaDLSpeedCalculatedAt + 4000 < now ?
1433                 pieceDownloadSpeed_Bps : /* if no recent previous speed, no need to smooth */
1434                 (tor->etaDLSpeed_Bps * 4.0 + pieceDownloadSpeed_Bps) / 5.0; /* smooth across 5 readings */
1435             tor->etaDLSpeedCalculatedAt = now;
1436         }
1437
1438         if (s->leftUntilDone > s->desiredAvailable && tor->info.webseedCount < 1)
1439         {
1440             s->eta = TR_ETA_NOT_AVAIL;
1441         }
1442         else if (tor->etaDLSpeed_Bps == 0)
1443         {
1444             s->eta = TR_ETA_UNKNOWN;
1445         }
1446         else
1447         {
1448             s->eta = s->leftUntilDone / tor->etaDLSpeed_Bps;
1449         }
1450
1451         s->etaIdle = TR_ETA_NOT_AVAIL;
1452         break;
1453
1454     case TR_STATUS_SEED:
1455         if (!seedRatioApplies)
1456         {
1457             s->eta = TR_ETA_NOT_AVAIL;
1458         }
1459         else
1460         {
1461             if (tor->etaULSpeedCalculatedAt + 800 < now)
1462             {
1463                 tor->etaULSpeed_Bps = tor->etaULSpeedCalculatedAt + 4000 < now ?
1464                     pieceUploadSpeed_Bps : /* if no recent previous speed, no need to smooth */
1465                     (tor->etaULSpeed_Bps * 4.0 + pieceUploadSpeed_Bps) / 5.0; /* smooth across 5 readings */
1466                 tor->etaULSpeedCalculatedAt = now;
1467             }
1468
1469             if (tor->etaULSpeed_Bps == 0)
1470             {
1471                 s->eta = TR_ETA_UNKNOWN;
1472             }
1473             else
1474             {
1475                 s->eta = seedRatioBytesLeft / tor->etaULSpeed_Bps;
1476             }
1477         }
1478
1479         if (tor->etaULSpeed_Bps < 1 && tr_torrentGetSeedIdle(tor, &seedIdleMinutes))
1480         {
1481             s->etaIdle = seedIdleMinutes * 60 - s->idleSecs;
1482         }
1483         else
1484         {
1485             s->etaIdle = TR_ETA_NOT_AVAIL;
1486         }
1487
1488         break;
1489
1490     default:
1491         s->eta = TR_ETA_NOT_AVAIL;
1492         s->etaIdle = TR_ETA_NOT_AVAIL;
1493         break;
1494     }
1495
1496     /* s->haveValid is here to make sure a torrent isn't marked 'finished'
1497      * when the user hits "uncheck all" prior to starting the torrent... */
1498     s->finished = tor->finishedSeedingByIdle || (seedRatioApplies && seedRatioBytesLeft == 0 && s->haveValid != 0);
1499
1500     if (!seedRatioApplies || s->finished)
1501     {
1502         s->seedRatioPercentDone = 1;
1503     }
1504     else if (seedRatioBytesGoal == 0) /* impossible? safeguard for div by zero */
1505     {
1506         s->seedRatioPercentDone = 0;
1507     }
1508     else
1509     {
1510         s->seedRatioPercentDone = (double)(seedRatioBytesGoal - seedRatioBytesLeft) / seedRatioBytesGoal;
1511     }
1512
1513     /* test some of the constraints */
1514     TR_ASSERT(s->sizeWhenDone <= tor->info.totalSize);
1515     TR_ASSERT(s->leftUntilDone <= s->sizeWhenDone);
1516     TR_ASSERT(s->desiredAvailable <= s->leftUntilDone);
1517
1518     return s;
1519 }
1520
1521 /***
1522 ****
1523 ***/
1524
1525 static uint64_t countFileBytesCompleted(tr_torrent const* tor, tr_file_index_t index)
1526 {
1527     uint64_t total = 0;
1528     tr_file const* f = &tor->info.files[index];
1529
1530     if (f->length != 0)
1531     {
1532         tr_block_index_t first;
1533         tr_block_index_t last;
1534         tr_torGetFileBlockRange(tor, index, &first, &last);
1535
1536         if (first == last)
1537         {
1538             if (tr_torrentBlockIsComplete(tor, first))
1539             {
1540                 total = f->length;
1541             }
1542         }
1543         else
1544         {
1545             /* the first block */
1546             if (tr_torrentBlockIsComplete(tor, first))
1547             {
1548                 total += tor->blockSize - f->offset % tor->blockSize;
1549             }
1550
1551             /* the middle blocks */
1552             if (first + 1 < last)
1553             {
1554                 uint64_t u = tr_bitfieldCountRange(&tor->completion.blockBitfield, first + 1, last);
1555                 u *= tor->blockSize;
1556                 total += u;
1557             }
1558
1559             /* the last block */
1560             if (tr_torrentBlockIsComplete(tor, last))
1561             {
1562                 total += f->offset + f->length - (uint64_t)tor->blockSize * last;
1563             }
1564         }
1565     }
1566
1567     return total;
1568 }
1569
1570 tr_file_stat* tr_torrentFiles(tr_torrent const* tor, tr_file_index_t* fileCount)
1571 {
1572     TR_ASSERT(tr_isTorrent(tor));
1573
1574     tr_file_index_t const n = tor->info.fileCount;
1575     tr_file_stat* files = tr_new0(tr_file_stat, n);
1576     tr_file_stat* walk = files;
1577     bool const isSeed = tor->completeness == TR_SEED;
1578
1579     for (tr_file_index_t i = 0; i < n; ++i, ++walk)
1580     {
1581         uint64_t const b = isSeed ? tor->info.files[i].length : countFileBytesCompleted(tor, i);
1582         walk->bytesCompleted = b;
1583         walk->progress = tor->info.files[i].length > 0 ? (float)b / tor->info.files[i].length : 1.0f;
1584     }
1585
1586     if (fileCount != NULL)
1587     {
1588         *fileCount = n;
1589     }
1590
1591     return files;
1592 }
1593
1594 void tr_torrentFilesFree(tr_file_stat* files, tr_file_index_t fileCount UNUSED)
1595 {
1596     tr_free(files);
1597 }
1598
1599 /***
1600 ****
1601 ***/
1602
1603 double* tr_torrentWebSpeeds_KBps(tr_torrent const* tor)
1604 {
1605     TR_ASSERT(tr_isTorrent(tor));
1606
1607     return tr_peerMgrWebSpeeds_KBps(tor);
1608 }
1609
1610 tr_peer_stat* tr_torrentPeers(tr_torrent const* tor, int* peerCount)
1611 {
1612     TR_ASSERT(tr_isTorrent(tor));
1613
1614     return tr_peerMgrPeerStats(tor, peerCount);
1615 }
1616
1617 void tr_torrentPeersFree(tr_peer_stat* peers, int peerCount UNUSED)
1618 {
1619     tr_free(peers);
1620 }
1621
1622 tr_tracker_stat* tr_torrentTrackers(tr_torrent const* tor, int* setmeTrackerCount)
1623 {
1624     TR_ASSERT(tr_isTorrent(tor));
1625
1626     return tr_announcerStats(tor, setmeTrackerCount);
1627 }
1628
1629 void tr_torrentTrackersFree(tr_tracker_stat* trackers, int trackerCount)
1630 {
1631     tr_announcerStatsFree(trackers, trackerCount);
1632 }
1633
1634 void tr_torrentAvailability(tr_torrent const* tor, int8_t* tab, int size)
1635 {
1636     TR_ASSERT(tr_isTorrent(tor));
1637
1638     if (tab != NULL && size > 0)
1639     {
1640         tr_peerMgrTorrentAvailability(tor, tab, size);
1641     }
1642 }
1643
1644 void tr_torrentAmountFinished(tr_torrent const* tor, float* tab, int size)
1645 {
1646     tr_cpGetAmountDone(&tor->completion, tab, size);
1647 }
1648
1649 static void tr_torrentResetTransferStats(tr_torrent* tor)
1650 {
1651     tr_torrentLock(tor);
1652
1653     tor->downloadedPrev += tor->downloadedCur;
1654     tor->downloadedCur = 0;
1655     tor->uploadedPrev += tor->uploadedCur;
1656     tor->uploadedCur = 0;
1657     tor->corruptPrev += tor->corruptCur;
1658     tor->corruptCur = 0;
1659
1660     tr_torrentSetDirty(tor);
1661
1662     tr_torrentUnlock(tor);
1663 }
1664
1665 void tr_torrentSetHasPiece(tr_torrent* tor, tr_piece_index_t pieceIndex, bool has)
1666 {
1667     TR_ASSERT(tr_isTorrent(tor));
1668     TR_ASSERT(pieceIndex < tor->info.pieceCount);
1669
1670     if (has)
1671     {
1672         tr_cpPieceAdd(&tor->completion, pieceIndex);
1673     }
1674     else
1675     {
1676         tr_cpPieceRem(&tor->completion, pieceIndex);
1677     }
1678 }
1679
1680 /***
1681 ****
1682 ***/
1683
1684 #ifdef TR_ENABLE_ASSERTS
1685 static bool queueIsSequenced(tr_session*);
1686 #endif
1687
1688 static void freeTorrent(tr_torrent* tor)
1689 {
1690     TR_ASSERT(!tor->isRunning);
1691
1692     tr_session* session = tor->session;
1693     tr_info* inf = &tor->info;
1694     time_t const now = tr_time();
1695
1696     tr_sessionLock(session);
1697
1698     tr_peerMgrRemoveTorrent(tor);
1699
1700     tr_announcerRemoveTorrent(session->announcer, tor);
1701
1702     tr_cpDestruct(&tor->completion);
1703
1704     tr_free(tor->downloadDir);
1705     tr_free(tor->incompleteDir);
1706
1707     if (tor == session->torrentList)
1708     {
1709         session->torrentList = tor->next;
1710     }
1711     else
1712     {
1713         for (tr_torrent* t = session->torrentList; t != NULL; t = t->next)
1714         {
1715             if (t->next == tor)
1716             {
1717                 t->next = tor->next;
1718                 break;
1719             }
1720         }
1721     }
1722
1723     /* decrement the torrent count */
1724     TR_ASSERT(session->torrentCount >= 1);
1725     session->torrentCount--;
1726
1727     /* resequence the queue positions */
1728     tr_torrent* t = NULL;
1729
1730     while ((t = tr_torrentNext(session, t)) != NULL)
1731     {
1732         if (t->queuePosition > tor->queuePosition)
1733         {
1734             t->queuePosition--;
1735             t->anyDate = now;
1736         }
1737     }
1738
1739     TR_ASSERT(queueIsSequenced(session));
1740
1741     tr_bandwidthDestruct(&tor->bandwidth);
1742
1743     tr_metainfoFree(inf);
1744     memset(tor, ~0, sizeof(tr_torrent));
1745     tr_free(tor);
1746
1747     tr_sessionUnlock(session);
1748 }
1749
1750 /**
1751 ***  Start/Stop Callback
1752 **/
1753
1754 static void torrentSetQueued(tr_torrent* tor, bool queued);
1755
1756 static void torrentStartImpl(void* vtor)
1757 {
1758     tr_torrent* tor = vtor;
1759
1760     TR_ASSERT(tr_isTorrent(tor));
1761
1762     tr_sessionLock(tor->session);
1763
1764     tr_torrentRecheckCompleteness(tor);
1765     torrentSetQueued(tor, false);
1766
1767     time_t const now = tr_time();
1768
1769     tor->isRunning = true;
1770     tor->completeness = tr_cpGetStatus(&tor->completion);
1771     tor->startDate = now;
1772     tor->anyDate = now;
1773     tr_torrentClearError(tor);
1774     tor->finishedSeedingByIdle = false;
1775
1776     tr_torrentResetTransferStats(tor);
1777     tr_announcerTorrentStarted(tor);
1778     tor->dhtAnnounceAt = now + tr_rand_int_weak(20);
1779     tor->dhtAnnounce6At = now + tr_rand_int_weak(20);
1780     tor->lpdAnnounceAt = now;
1781     tr_peerMgrStartTorrent(tor);
1782
1783     tr_sessionUnlock(tor->session);
1784 }
1785
1786 uint64_t tr_torrentGetCurrentSizeOnDisk(tr_torrent const* tor)
1787 {
1788     uint64_t byte_count = 0;
1789     tr_file_index_t const n = tor->info.fileCount;
1790
1791     for (tr_file_index_t i = 0; i < n; ++i)
1792     {
1793         tr_sys_path_info info;
1794         char* filename = tr_torrentFindFile(tor, i);
1795
1796         if (filename != NULL && tr_sys_path_get_info(filename, 0, &info, NULL))
1797         {
1798             byte_count += info.size;
1799         }
1800
1801         tr_free(filename);
1802     }
1803
1804     return byte_count;
1805 }
1806
1807 static bool torrentShouldQueue(tr_torrent const* tor)
1808 {
1809     tr_direction const dir = tr_torrentGetQueueDirection(tor);
1810
1811     return tr_sessionCountQueueFreeSlots(tor->session, dir) == 0;
1812 }
1813
1814 static void torrentStart(tr_torrent* tor, bool bypass_queue)
1815 {
1816     switch (tr_torrentGetActivity(tor))
1817     {
1818     case TR_STATUS_SEED:
1819     case TR_STATUS_DOWNLOAD:
1820         return; /* already started */
1821         break;
1822
1823     case TR_STATUS_SEED_WAIT:
1824     case TR_STATUS_DOWNLOAD_WAIT:
1825         if (!bypass_queue)
1826         {
1827             return; /* already queued */
1828         }
1829
1830         break;
1831
1832     case TR_STATUS_CHECK:
1833     case TR_STATUS_CHECK_WAIT:
1834         /* verifying right now... wait until that's done so
1835          * we'll know what completeness to use/announce */
1836         tor->startAfterVerify = true;
1837         return;
1838         break;
1839
1840     case TR_STATUS_STOPPED:
1841         if (!bypass_queue && torrentShouldQueue(tor))
1842         {
1843             torrentSetQueued(tor, true);
1844             return;
1845         }
1846
1847         break;
1848     }
1849
1850     /* don't allow the torrent to be started if the files disappeared */
1851     if (setLocalErrorIfFilesDisappeared(tor))
1852     {
1853         return;
1854     }
1855
1856     /* otherwise, start it now... */
1857     tr_sessionLock(tor->session);
1858
1859     /* allow finished torrents to be resumed */
1860     if (tr_torrentIsSeedRatioDone(tor))
1861     {
1862         tr_logAddTorInfo(tor, "%s", _("Restarted manually -- disabling its seed ratio"));
1863         tr_torrentSetRatioMode(tor, TR_RATIOLIMIT_UNLIMITED);
1864     }
1865
1866     /* corresponds to the peer_id sent as a tracker request parameter.
1867      * one tracker admin says: "When the same torrent is opened and
1868      * closed and opened again without quitting Transmission ...
1869      * change the peerid. It would help sometimes if a stopped event
1870      * was missed to ensure that we didn't think someone was cheating. */
1871     tr_torrentUnsetPeerId(tor);
1872     tor->isRunning = true;
1873     tr_torrentSetDirty(tor);
1874     tr_runInEventThread(tor->session, torrentStartImpl, tor);
1875
1876     tr_sessionUnlock(tor->session);
1877 }
1878
1879 void tr_torrentStart(tr_torrent* tor)
1880 {
1881     if (tr_isTorrent(tor))
1882     {
1883         torrentStart(tor, false);
1884     }
1885 }
1886
1887 void tr_torrentStartNow(tr_torrent* tor)
1888 {
1889     if (tr_isTorrent(tor))
1890     {
1891         torrentStart(tor, true);
1892     }
1893 }
1894
1895 struct verify_data
1896 {
1897     bool aborted;
1898     tr_torrent* tor;
1899     tr_verify_done_func callback_func;
1900     void* callback_data;
1901 };
1902
1903 static void onVerifyDoneThreadFunc(void* vdata)
1904 {
1905     struct verify_data* data = vdata;
1906     tr_torrent* tor = data->tor;
1907
1908     if (tor->isDeleting)
1909     {
1910         goto cleanup;
1911     }
1912
1913     if (!data->aborted)
1914     {
1915         tr_torrentRecheckCompleteness(tor);
1916     }
1917
1918     if (data->callback_func != NULL)
1919     {
1920         (*data->callback_func)(tor, data->aborted, data->callback_data);
1921     }
1922
1923     if (!data->aborted && tor->startAfterVerify)
1924     {
1925         tor->startAfterVerify = false;
1926         torrentStart(tor, false);
1927     }
1928
1929 cleanup:
1930     tr_free(data);
1931 }
1932
1933 static void onVerifyDone(tr_torrent* tor, bool aborted, void* vdata)
1934 {
1935     struct verify_data* data = vdata;
1936
1937     TR_ASSERT(data->tor == tor);
1938
1939     if (tor->isDeleting)
1940     {
1941         tr_free(data);
1942         return;
1943     }
1944
1945     data->aborted = aborted;
1946     tr_runInEventThread(tor->session, onVerifyDoneThreadFunc, data);
1947 }
1948
1949 static void verifyTorrent(void* vdata)
1950 {
1951     bool startAfter;
1952     struct verify_data* data = vdata;
1953     tr_torrent* tor = data->tor;
1954     tr_sessionLock(tor->session);
1955
1956     if (tor->isDeleting)
1957     {
1958         tr_free(data);
1959         goto unlock;
1960     }
1961
1962     /* if the torrent's already being verified, stop it */
1963     tr_verifyRemove(tor);
1964
1965     startAfter = (tor->isRunning || tor->startAfterVerify) && !tor->isStopping;
1966
1967     if (tor->isRunning)
1968     {
1969         tr_torrentStop(tor);
1970     }
1971
1972     tor->startAfterVerify = startAfter;
1973
1974     if (setLocalErrorIfFilesDisappeared(tor))
1975     {
1976         tor->startAfterVerify = false;
1977     }
1978     else
1979     {
1980         tr_verifyAdd(tor, onVerifyDone, data);
1981     }
1982
1983 unlock:
1984     tr_sessionUnlock(tor->session);
1985 }
1986
1987 void tr_torrentVerify(tr_torrent* tor, tr_verify_done_func callback_func, void* callback_data)
1988 {
1989     struct verify_data* data;
1990
1991     data = tr_new(struct verify_data, 1);
1992     data->tor = tor;
1993     data->aborted = false;
1994     data->callback_func = callback_func;
1995     data->callback_data = callback_data;
1996     tr_runInEventThread(tor->session, verifyTorrent, data);
1997 }
1998
1999 void tr_torrentSave(tr_torrent* tor)
2000 {
2001     TR_ASSERT(tr_isTorrent(tor));
2002
2003     if (tor->isDirty)
2004     {
2005         tor->isDirty = false;
2006         tr_torrentSaveResume(tor);
2007     }
2008 }
2009
2010 static void stopTorrent(void* vtor)
2011 {
2012     tr_torrent* tor = vtor;
2013
2014     TR_ASSERT(tr_isTorrent(tor));
2015
2016     tr_logAddTorInfo(tor, "%s", "Pausing");
2017
2018     tr_torrentLock(tor);
2019
2020     tr_verifyRemove(tor);
2021     tr_peerMgrStopTorrent(tor);
2022     tr_announcerTorrentStopped(tor);
2023     tr_cacheFlushTorrent(tor->session->cache, tor);
2024
2025     tr_fdTorrentClose(tor->session, tor->uniqueId);
2026
2027     if (!tor->isDeleting)
2028     {
2029         tr_torrentSave(tor);
2030     }
2031
2032     torrentSetQueued(tor, false);
2033
2034     tr_torrentUnlock(tor);
2035
2036     if (tor->magnetVerify)
2037     {
2038         tor->magnetVerify = false;
2039         tr_logAddTorInfo(tor, "%s", "Magnet Verify");
2040         refreshCurrentDir(tor);
2041         tr_torrentVerify(tor, NULL, NULL);
2042     }
2043 }
2044
2045 void tr_torrentStop(tr_torrent* tor)
2046 {
2047     TR_ASSERT(tr_isTorrent(tor));
2048
2049     if (tr_isTorrent(tor))
2050     {
2051         tr_sessionLock(tor->session);
2052
2053         tor->isRunning = false;
2054         tor->isStopping = false;
2055         tr_torrentSetDirty(tor);
2056         tr_runInEventThread(tor->session, stopTorrent, tor);
2057
2058         tr_sessionUnlock(tor->session);
2059     }
2060 }
2061
2062 static void closeTorrent(void* vtor)
2063 {
2064     tr_torrent* tor = vtor;
2065
2066     TR_ASSERT(tr_isTorrent(tor));
2067
2068     tr_variant* d = tr_variantListAddDict(&tor->session->removedTorrents, 2);
2069     tr_variantDictAddInt(d, TR_KEY_id, tor->uniqueId);
2070     tr_variantDictAddInt(d, TR_KEY_date, tr_time());
2071
2072     tr_logAddTorInfo(tor, "%s", _("Removing torrent"));
2073
2074     tor->magnetVerify = false;
2075     stopTorrent(tor);
2076
2077     if (tor->isDeleting)
2078     {
2079         tr_metainfoRemoveSaved(tor->session, &tor->info);
2080         tr_torrentRemoveResume(tor);
2081     }
2082
2083     tor->isRunning = false;
2084     freeTorrent(tor);
2085 }
2086
2087 void tr_torrentFree(tr_torrent* tor)
2088 {
2089     if (tr_isTorrent(tor))
2090     {
2091         tr_session* session = tor->session;
2092
2093         TR_ASSERT(tr_isSession(session));
2094
2095         tr_sessionLock(session);
2096
2097         tr_torrentClearCompletenessCallback(tor);
2098         tr_runInEventThread(session, closeTorrent, tor);
2099
2100         tr_sessionUnlock(session);
2101     }
2102 }
2103
2104 struct remove_data
2105 {
2106     tr_torrent* tor;
2107     bool deleteFlag;
2108     tr_fileFunc deleteFunc;
2109 };
2110
2111 static void tr_torrentDeleteLocalData(tr_torrent*, tr_fileFunc);
2112
2113 static void removeTorrent(void* vdata)
2114 {
2115     struct remove_data* data = vdata;
2116     tr_session* session = data->tor->session;
2117     tr_sessionLock(session);
2118
2119     if (data->deleteFlag)
2120     {
2121         tr_torrentDeleteLocalData(data->tor, data->deleteFunc);
2122     }
2123
2124     tr_torrentClearCompletenessCallback(data->tor);
2125     closeTorrent(data->tor);
2126     tr_free(data);
2127
2128     tr_sessionUnlock(session);
2129 }
2130
2131 void tr_torrentRemove(tr_torrent* tor, bool deleteFlag, tr_fileFunc deleteFunc)
2132 {
2133     TR_ASSERT(tr_isTorrent(tor));
2134
2135     tor->isDeleting = true;
2136
2137     struct remove_data* data = tr_new0(struct remove_data, 1);
2138     data->tor = tor;
2139     data->deleteFlag = deleteFlag;
2140     data->deleteFunc = deleteFunc;
2141     tr_runInEventThread(tor->session, removeTorrent, data);
2142 }
2143
2144 /**
2145 ***  Completeness
2146 **/
2147
2148 static char const* getCompletionString(int type)
2149 {
2150     switch (type)
2151     {
2152     case TR_PARTIAL_SEED:
2153         /* Translators: this is a minor point that's safe to skip over, but FYI:
2154            "Complete" and "Done" are specific, different terms in Transmission:
2155            "Complete" means we've downloaded every file in the torrent.
2156            "Done" means we're done downloading the files we wanted, but NOT all
2157            that exist */
2158         return _("Done");
2159
2160     case TR_SEED:
2161         return _("Complete");
2162
2163     default:
2164         return _("Incomplete");
2165     }
2166 }
2167
2168 static void fireCompletenessChange(tr_torrent* tor, tr_completeness status, bool wasRunning)
2169 {
2170     TR_ASSERT(status == TR_LEECH || status == TR_SEED || status == TR_PARTIAL_SEED);
2171
2172     if (tor->completeness_func != NULL)
2173     {
2174         (*tor->completeness_func)(tor, status, wasRunning, tor->completeness_func_user_data);
2175     }
2176 }
2177
2178 void tr_torrentSetCompletenessCallback(tr_torrent* tor, tr_torrent_completeness_func func, void* user_data)
2179 {
2180     TR_ASSERT(tr_isTorrent(tor));
2181
2182     tor->completeness_func = func;
2183     tor->completeness_func_user_data = user_data;
2184 }
2185
2186 void tr_torrentClearCompletenessCallback(tr_torrent* torrent)
2187 {
2188     tr_torrentSetCompletenessCallback(torrent, NULL, NULL);
2189 }
2190
2191 void tr_torrentSetRatioLimitHitCallback(tr_torrent* tor, tr_torrent_ratio_limit_hit_func func, void* user_data)
2192 {
2193     TR_ASSERT(tr_isTorrent(tor));
2194
2195     tor->ratio_limit_hit_func = func;
2196     tor->ratio_limit_hit_func_user_data = user_data;
2197 }
2198
2199 void tr_torrentClearRatioLimitHitCallback(tr_torrent* torrent)
2200 {
2201     tr_torrentSetRatioLimitHitCallback(torrent, NULL, NULL);
2202 }
2203
2204 void tr_torrentSetIdleLimitHitCallback(tr_torrent* tor, tr_torrent_idle_limit_hit_func func, void* user_data)
2205 {
2206     TR_ASSERT(tr_isTorrent(tor));
2207
2208     tor->idle_limit_hit_func = func;
2209     tor->idle_limit_hit_func_user_data = user_data;
2210 }
2211
2212 void tr_torrentClearIdleLimitHitCallback(tr_torrent* torrent)
2213 {
2214     tr_torrentSetIdleLimitHitCallback(torrent, NULL, NULL);
2215 }
2216
2217 static void get_local_time_str(char* const buffer, size_t const buffer_len)
2218 {
2219     time_t const now = tr_time();
2220
2221     tr_strlcpy(buffer, ctime(&now), buffer_len);
2222
2223     char* newline_pos = strchr(buffer, '\n');
2224
2225     /* ctime() includes '\n', but it's better to be safe */
2226     if (newline_pos != NULL)
2227     {
2228         *newline_pos = '\0';
2229     }
2230 }
2231
2232 static void torrentCallScript(tr_torrent const* tor, char const* script)
2233 {
2234     if (script == NULL || *script == '\0')
2235     {
2236         return;
2237     }
2238
2239     char time_str[32];
2240     get_local_time_str(time_str, TR_N_ELEMENTS(time_str));
2241
2242     char* const torrent_dir = tr_sys_path_native_separators(tr_strdup(tor->currentDir));
2243
2244     char* const cmd[] =
2245     {
2246         tr_strdup(script),
2247         NULL
2248     };
2249
2250     char* const env[] =
2251     {
2252         tr_strdup_printf("TR_APP_VERSION=%s", SHORT_VERSION_STRING),
2253         tr_strdup_printf("TR_TIME_LOCALTIME=%s", time_str),
2254         tr_strdup_printf("TR_TORRENT_DIR=%s", torrent_dir),
2255         tr_strdup_printf("TR_TORRENT_HASH=%s", tor->info.hashString),
2256         tr_strdup_printf("TR_TORRENT_ID=%d", tr_torrentId(tor)),
2257         tr_strdup_printf("TR_TORRENT_NAME=%s", tr_torrentName(tor)),
2258         NULL
2259     };
2260
2261     tr_logAddTorInfo(tor, "Calling script \"%s\"", script);
2262
2263     tr_error* error = NULL;
2264
2265     if (!tr_spawn_async(cmd, env, TR_IF_WIN32("\\", "/"), &error))
2266     {
2267         tr_logAddTorErr(tor, "Error executing script \"%s\" (%d): %s", script, error->code, error->message);
2268         tr_error_free(error);
2269     }
2270
2271     tr_free_ptrv((void* const*)env);
2272     tr_free_ptrv((void* const*)cmd);
2273     tr_free(torrent_dir);
2274 }
2275
2276 void tr_torrentRecheckCompleteness(tr_torrent* tor)
2277 {
2278     tr_completeness completeness;
2279
2280     tr_torrentLock(tor);
2281
2282     completeness = tr_cpGetStatus(&tor->completion);
2283
2284     if (completeness != tor->completeness)
2285     {
2286         bool const recentChange = tor->downloadedCur != 0;
2287         bool const wasLeeching = !tr_torrentIsSeed(tor);
2288         bool const wasRunning = tor->isRunning;
2289
2290         if (recentChange)
2291         {
2292             tr_logAddTorInfo(tor, _("State changed from \"%1$s\" to \"%2$s\""), getCompletionString(tor->completeness),
2293                 getCompletionString(completeness));
2294         }
2295
2296         tor->completeness = completeness;
2297         tr_fdTorrentClose(tor->session, tor->uniqueId);
2298
2299         if (tr_torrentIsSeed(tor))
2300         {
2301             if (recentChange)
2302             {
2303                 tr_announcerTorrentCompleted(tor);
2304                 tor->doneDate = tor->anyDate = tr_time();
2305             }
2306
2307             if (wasLeeching && wasRunning)
2308             {
2309                 /* clear interested flag on all peers */
2310                 tr_peerMgrClearInterest(tor);
2311             }
2312
2313             if (tor->currentDir == tor->incompleteDir)
2314             {
2315                 tr_torrentSetLocation(tor, tor->downloadDir, true, NULL, NULL);
2316             }
2317         }
2318
2319         fireCompletenessChange(tor, completeness, wasRunning);
2320
2321         if (tr_torrentIsSeed(tor) && wasLeeching && wasRunning)
2322         {
2323             /* if completeness was TR_LEECH, the seed limit check
2324                will have been skipped in bandwidthPulse */
2325             tr_torrentCheckSeedLimit(tor);
2326         }
2327
2328         tr_torrentSetDirty(tor);
2329
2330         if (tr_torrentIsSeed(tor) && tr_sessionIsTorrentDoneScriptEnabled(tor->session))
2331         {
2332             tr_torrentSave(tor);
2333
2334             torrentCallScript(tor, tr_sessionGetTorrentDoneScript(tor->session));
2335         }
2336     }
2337
2338     tr_torrentUnlock(tor);
2339 }
2340
2341 /***
2342 ****
2343 ***/
2344
2345 static void tr_torrentFireMetadataCompleted(tr_torrent* tor)
2346 {
2347     TR_ASSERT(tr_isTorrent(tor));
2348
2349     if (tor->metadata_func != NULL)
2350     {
2351         (*tor->metadata_func)(tor, tor->metadata_func_user_data);
2352     }
2353 }
2354
2355 void tr_torrentSetMetadataCallback(tr_torrent* tor, tr_torrent_metadata_func func, void* user_data)
2356 {
2357     TR_ASSERT(tr_isTorrent(tor));
2358
2359     tor->metadata_func = func;
2360     tor->metadata_func_user_data = user_data;
2361 }
2362
2363 /**
2364 ***  File priorities
2365 **/
2366
2367 void tr_torrentInitFilePriority(tr_torrent* tor, tr_file_index_t fileIndex, tr_priority_t priority)
2368 {
2369     TR_ASSERT(tr_isTorrent(tor));
2370     TR_ASSERT(fileIndex < tor->info.fileCount);
2371     TR_ASSERT(tr_isPriority(priority));
2372
2373     tr_file* file = &tor->info.files[fileIndex];
2374
2375     file->priority = priority;
2376
2377     for (tr_piece_index_t i = file->firstPiece; i <= file->lastPiece; ++i)
2378     {
2379         tor->info.pieces[i].priority = calculatePiecePriority(tor, i, fileIndex);
2380     }
2381 }
2382
2383 void tr_torrentSetFilePriorities(tr_torrent* tor, tr_file_index_t const* files, tr_file_index_t fileCount,
2384     tr_priority_t priority)
2385 {
2386     TR_ASSERT(tr_isTorrent(tor));
2387
2388     tr_torrentLock(tor);
2389
2390     for (tr_file_index_t i = 0; i < fileCount; ++i)
2391     {
2392         if (files[i] < tor->info.fileCount)
2393         {
2394             tr_torrentInitFilePriority(tor, files[i], priority);
2395         }
2396     }
2397
2398     tr_torrentSetDirty(tor);
2399     tr_peerMgrRebuildRequests(tor);
2400
2401     tr_torrentUnlock(tor);
2402 }
2403
2404 tr_priority_t* tr_torrentGetFilePriorities(tr_torrent const* tor)
2405 {
2406     TR_ASSERT(tr_isTorrent(tor));
2407
2408     tr_priority_t* p = tr_new0(tr_priority_t, tor->info.fileCount);
2409
2410     for (tr_file_index_t i = 0; i < tor->info.fileCount; ++i)
2411     {
2412         p[i] = tor->info.files[i].priority;
2413     }
2414
2415     return p;
2416 }
2417
2418 /**
2419 ***  File DND
2420 **/
2421
2422 static void setFileDND(tr_torrent* tor, tr_file_index_t fileIndex, int doDownload)
2423 {
2424     int8_t const dnd = !doDownload;
2425     tr_piece_index_t firstPiece;
2426     int8_t firstPieceDND;
2427     tr_piece_index_t lastPiece;
2428     int8_t lastPieceDND;
2429     tr_file* file = &tor->info.files[fileIndex];
2430
2431     file->dnd = dnd;
2432     firstPiece = file->firstPiece;
2433     lastPiece = file->lastPiece;
2434
2435     /* can't set the first piece to DND unless
2436        every file using that piece is DND */
2437     firstPieceDND = dnd;
2438
2439     if (fileIndex > 0)
2440     {
2441         for (tr_file_index_t i = fileIndex - 1; firstPieceDND; --i)
2442         {
2443             if (tor->info.files[i].lastPiece != firstPiece)
2444             {
2445                 break;
2446             }
2447
2448             firstPieceDND = tor->info.files[i].dnd;
2449
2450             if (i == 0)
2451             {
2452                 break;
2453             }
2454         }
2455     }
2456
2457     /* can't set the last piece to DND unless
2458        every file using that piece is DND */
2459     lastPieceDND = dnd;
2460
2461     for (tr_file_index_t i = fileIndex + 1; lastPieceDND && i < tor->info.fileCount; ++i)
2462     {
2463         if (tor->info.files[i].firstPiece != lastPiece)
2464         {
2465             break;
2466         }
2467
2468         lastPieceDND = tor->info.files[i].dnd;
2469     }
2470
2471     if (firstPiece == lastPiece)
2472     {
2473         tor->info.pieces[firstPiece].dnd = firstPieceDND && lastPieceDND;
2474     }
2475     else
2476     {
2477         tor->info.pieces[firstPiece].dnd = firstPieceDND;
2478         tor->info.pieces[lastPiece].dnd = lastPieceDND;
2479
2480         for (tr_piece_index_t pp = firstPiece + 1; pp < lastPiece; ++pp)
2481         {
2482             tor->info.pieces[pp].dnd = dnd;
2483         }
2484     }
2485 }
2486
2487 void tr_torrentInitFileDLs(tr_torrent* tor, tr_file_index_t const* files, tr_file_index_t fileCount, bool doDownload)
2488 {
2489
2490     TR_ASSERT(tr_isTorrent(tor));
2491
2492     tr_torrentLock(tor);
2493
2494     for (tr_file_index_t i = 0; i < fileCount; ++i)
2495     {
2496         if (files[i] < tor->info.fileCount)
2497         {
2498             setFileDND(tor, files[i], doDownload);
2499         }
2500     }
2501
2502     tr_cpInvalidateDND(&tor->completion);
2503
2504     tr_torrentUnlock(tor);
2505 }
2506
2507 void tr_torrentSetFileDLs(tr_torrent* tor, tr_file_index_t const* files, tr_file_index_t fileCount, bool doDownload)
2508 {
2509     TR_ASSERT(tr_isTorrent(tor));
2510
2511     tr_torrentLock(tor);
2512
2513     tr_torrentInitFileDLs(tor, files, fileCount, doDownload);
2514     tr_torrentSetDirty(tor);
2515     tr_torrentRecheckCompleteness(tor);
2516     tr_peerMgrRebuildRequests(tor);
2517
2518     tr_torrentUnlock(tor);
2519 }
2520
2521 /***
2522 ****
2523 ***/
2524
2525 tr_priority_t tr_torrentGetPriority(tr_torrent const* tor)
2526 {
2527     TR_ASSERT(tr_isTorrent(tor));
2528
2529     return tor->bandwidth.priority;
2530 }
2531
2532 void tr_torrentSetPriority(tr_torrent* tor, tr_priority_t priority)
2533 {
2534     TR_ASSERT(tr_isTorrent(tor));
2535     TR_ASSERT(tr_isPriority(priority));
2536
2537     if (tor->bandwidth.priority != priority)
2538     {
2539         tor->bandwidth.priority = priority;
2540
2541         tr_torrentSetDirty(tor);
2542     }
2543 }
2544
2545 /***
2546 ****
2547 ***/
2548
2549 void tr_torrentSetPeerLimit(tr_torrent* tor, uint16_t maxConnectedPeers)
2550 {
2551     TR_ASSERT(tr_isTorrent(tor));
2552
2553     if (tor->maxConnectedPeers != maxConnectedPeers)
2554     {
2555         tor->maxConnectedPeers = maxConnectedPeers;
2556
2557         tr_torrentSetDirty(tor);
2558     }
2559 }
2560
2561 uint16_t tr_torrentGetPeerLimit(tr_torrent const* tor)
2562 {
2563     TR_ASSERT(tr_isTorrent(tor));
2564
2565     return tor->maxConnectedPeers;
2566 }
2567
2568 /***
2569 ****
2570 ***/
2571
2572 void tr_torrentGetBlockLocation(tr_torrent const* tor, tr_block_index_t block, tr_piece_index_t* piece, uint32_t* offset,
2573     uint32_t* length)
2574 {
2575     uint64_t pos = block;
2576     pos *= tor->blockSize;
2577     *piece = pos / tor->info.pieceSize;
2578     *offset = pos - *piece * tor->info.pieceSize;
2579     *length = tr_torBlockCountBytes(tor, block);
2580 }
2581
2582 tr_block_index_t _tr_block(tr_torrent const* tor, tr_piece_index_t index, uint32_t offset)
2583 {
2584     TR_ASSERT(tr_isTorrent(tor));
2585
2586     tr_block_index_t ret;
2587
2588     ret = index;
2589     ret *= tor->info.pieceSize / tor->blockSize;
2590     ret += offset / tor->blockSize;
2591     return ret;
2592 }
2593
2594 bool tr_torrentReqIsValid(tr_torrent const* tor, tr_piece_index_t index, uint32_t offset, uint32_t length)
2595 {
2596     TR_ASSERT(tr_isTorrent(tor));
2597
2598     int err = 0;
2599
2600     if (index >= tor->info.pieceCount)
2601     {
2602         err = 1;
2603     }
2604     else if (length < 1)
2605     {
2606         err = 2;
2607     }
2608     else if (offset + length > tr_torPieceCountBytes(tor, index))
2609     {
2610         err = 3;
2611     }
2612     else if (length > MAX_BLOCK_SIZE)
2613     {
2614         err = 4;
2615     }
2616     else if (tr_pieceOffset(tor, index, offset, length) > tor->info.totalSize)
2617     {
2618         err = 5;
2619     }
2620
2621     if (err != 0)
2622     {
2623         tr_logAddTorDbg(tor, "index %lu offset %lu length %lu err %d\n", (unsigned long)index, (unsigned long)offset,
2624             (unsigned long)length, err);
2625     }
2626
2627     return err == 0;
2628 }
2629
2630 uint64_t tr_pieceOffset(tr_torrent const* tor, tr_piece_index_t index, uint32_t offset, uint32_t length)
2631 {
2632     TR_ASSERT(tr_isTorrent(tor));
2633
2634     uint64_t ret;
2635
2636     ret = tor->info.pieceSize;
2637     ret *= index;
2638     ret += offset;
2639     ret += length;
2640     return ret;
2641 }
2642
2643 void tr_torGetFileBlockRange(tr_torrent const* tor, tr_file_index_t const file, tr_block_index_t* first, tr_block_index_t* last)
2644 {
2645     tr_file const* f = &tor->info.files[file];
2646     uint64_t offset = f->offset;
2647
2648     *first = offset / tor->blockSize;
2649
2650     if (f->length == 0)
2651     {
2652         *last = *first;
2653     }
2654     else
2655     {
2656         offset += f->length - 1;
2657         *last = offset / tor->blockSize;
2658     }
2659 }
2660
2661 void tr_torGetPieceBlockRange(tr_torrent const* tor, tr_piece_index_t const piece, tr_block_index_t* first,
2662     tr_block_index_t* last)
2663 {
2664     uint64_t offset = tor->info.pieceSize;
2665     offset *= piece;
2666     *first = offset / tor->blockSize;
2667     offset += tr_torPieceCountBytes(tor, piece) - 1;
2668     *last = offset / tor->blockSize;
2669 }
2670
2671 /***
2672 ****
2673 ***/
2674
2675 void tr_torrentSetPieceChecked(tr_torrent* tor, tr_piece_index_t pieceIndex)
2676 {
2677     TR_ASSERT(tr_isTorrent(tor));
2678     TR_ASSERT(pieceIndex < tor->info.pieceCount);
2679
2680     tor->info.pieces[pieceIndex].timeChecked = tr_time();
2681 }
2682
2683 void tr_torrentSetChecked(tr_torrent* tor, time_t when)
2684 {
2685     TR_ASSERT(tr_isTorrent(tor));
2686
2687     for (tr_piece_index_t i = 0; i < tor->info.pieceCount; ++i)
2688     {
2689         tor->info.pieces[i].timeChecked = when;
2690     }
2691 }
2692
2693 bool tr_torrentCheckPiece(tr_torrent* tor, tr_piece_index_t pieceIndex)
2694 {
2695     bool const pass = tr_ioTestPiece(tor, pieceIndex);
2696
2697     tr_deeplog_tor(tor, "[LAZY] tr_torrentCheckPiece tested piece %zu, pass==%d", (size_t)pieceIndex, (int)pass);
2698     tr_torrentSetHasPiece(tor, pieceIndex, pass);
2699     tr_torrentSetPieceChecked(tor, pieceIndex);
2700     tor->anyDate = tr_time();
2701     tr_torrentSetDirty(tor);
2702
2703     return pass;
2704 }
2705
2706 time_t tr_torrentGetFileMTime(tr_torrent const* tor, tr_file_index_t i)
2707 {
2708     time_t mtime = 0;
2709
2710     if (!tr_fdFileGetCachedMTime(tor->session, tor->uniqueId, i, &mtime))
2711     {
2712         tr_torrentFindFile2(tor, i, NULL, NULL, &mtime);
2713     }
2714
2715     return mtime;
2716 }
2717
2718 bool tr_torrentPieceNeedsCheck(tr_torrent const* tor, tr_piece_index_t p)
2719 {
2720     uint64_t unused;
2721     tr_file_index_t f;
2722     tr_info const* inf = tr_torrentInfo(tor);
2723
2724     /* if we've never checked this piece, then it needs to be checked */
2725     if (inf->pieces[p].timeChecked == 0)
2726     {
2727         return true;
2728     }
2729
2730     /* If we think we've completed one of the files in this piece,
2731      * but it's been modified since we last checked it,
2732      * then it needs to be rechecked */
2733     tr_ioFindFileLocation(tor, p, 0, &f, &unused);
2734
2735     for (tr_file_index_t i = f; i < inf->fileCount && pieceHasFile(p, &inf->files[i]); ++i)
2736     {
2737         if (tr_cpFileIsComplete(&tor->completion, i))
2738         {
2739             if (tr_torrentGetFileMTime(tor, i) > inf->pieces[p].timeChecked)
2740             {
2741                 return true;
2742             }
2743         }
2744     }
2745
2746     return false;
2747 }
2748
2749 /***
2750 ****
2751 ***/
2752
2753 static int compareTrackerByTier(void const* va, void const* vb)
2754 {
2755     tr_tracker_info const* a = va;
2756     tr_tracker_info const* b = vb;
2757
2758     /* sort by tier */
2759     if (a->tier != b->tier)
2760     {
2761         return a->tier - b->tier;
2762     }
2763
2764     /* get the effects of a stable sort by comparing the two elements' addresses */
2765     return a - b;
2766 }
2767
2768 bool tr_torrentSetAnnounceList(tr_torrent* tor, tr_tracker_info const* trackers_in, int trackerCount)
2769 {
2770     TR_ASSERT(tr_isTorrent(tor));
2771
2772     tr_torrentLock(tor);
2773
2774     tr_variant metainfo;
2775     bool ok = true;
2776     tr_tracker_info* trackers;
2777
2778     /* ensure the trackers' tiers are in ascending order */
2779     trackers = tr_memdup(trackers_in, sizeof(tr_tracker_info) * trackerCount);
2780     qsort(trackers, trackerCount, sizeof(tr_tracker_info), compareTrackerByTier);
2781
2782     /* look for bad URLs */
2783     for (int i = 0; ok && i < trackerCount; ++i)
2784     {
2785         if (!tr_urlIsValidTracker(trackers[i].announce))
2786         {
2787             ok = false;
2788         }
2789     }
2790
2791     /* save to the .torrent file */
2792     if (ok && tr_variantFromFile(&metainfo, TR_VARIANT_FMT_BENC, tor->info.torrent, NULL))
2793     {
2794         bool hasInfo;
2795         tr_info tmpInfo;
2796
2797         /* remove the old fields */
2798         tr_variantDictRemove(&metainfo, TR_KEY_announce);
2799         tr_variantDictRemove(&metainfo, TR_KEY_announce_list);
2800
2801         /* add the new fields */
2802         if (trackerCount > 0)
2803         {
2804             tr_variantDictAddStr(&metainfo, TR_KEY_announce, trackers[0].announce);
2805         }
2806
2807         if (trackerCount > 1)
2808         {
2809             int prevTier = -1;
2810             tr_variant* tier = NULL;
2811             tr_variant* announceList = tr_variantDictAddList(&metainfo, TR_KEY_announce_list, 0);
2812
2813             for (int i = 0; i < trackerCount; ++i)
2814             {
2815                 if (prevTier != trackers[i].tier)
2816                 {
2817                     prevTier = trackers[i].tier;
2818                     tier = tr_variantListAddList(announceList, 0);
2819                 }
2820
2821                 tr_variantListAddStr(tier, trackers[i].announce);
2822             }
2823         }
2824
2825         /* try to parse it back again, to make sure it's good */
2826         memset(&tmpInfo, 0, sizeof(tr_info));
2827
2828         if (tr_metainfoParse(tor->session, &metainfo, &tmpInfo, &hasInfo, &tor->infoDictLength))
2829         {
2830             /* it's good, so keep these new trackers and free the old ones */
2831
2832             tr_info swap;
2833             swap.trackers = tor->info.trackers;
2834             swap.trackerCount = tor->info.trackerCount;
2835             tor->info.trackers = tmpInfo.trackers;
2836             tor->info.trackerCount = tmpInfo.trackerCount;
2837             tmpInfo.trackers = swap.trackers;
2838             tmpInfo.trackerCount = swap.trackerCount;
2839
2840             tr_metainfoFree(&tmpInfo);
2841             tr_variantToFile(&metainfo, TR_VARIANT_FMT_BENC, tor->info.torrent);
2842         }
2843
2844         /* cleanup */
2845         tr_variantFree(&metainfo);
2846
2847         /* if we had a tracker-related error on this torrent,
2848          * and that tracker's been removed,
2849          * then clear the error */
2850         if (tor->error == TR_STAT_TRACKER_WARNING || tor->error == TR_STAT_TRACKER_ERROR)
2851         {
2852             bool clear = true;
2853
2854             for (int i = 0; clear && i < trackerCount; ++i)
2855             {
2856                 if (strcmp(trackers[i].announce, tor->errorTracker) == 0)
2857                 {
2858                     clear = false;
2859                 }
2860             }
2861
2862             if (clear)
2863             {
2864                 tr_torrentClearError(tor);
2865             }
2866         }
2867
2868         /* tell the announcer to reload this torrent's tracker list */
2869         tr_announcerResetTorrent(tor->session->announcer, tor);
2870     }
2871
2872     tr_torrentUnlock(tor);
2873
2874     tr_free(trackers);
2875     return ok;
2876 }
2877
2878 /**
2879 ***
2880 **/
2881
2882 void tr_torrentSetAddedDate(tr_torrent* tor, time_t t)
2883 {
2884     TR_ASSERT(tr_isTorrent(tor));
2885
2886     tor->addedDate = t;
2887     tor->anyDate = MAX(tor->anyDate, tor->addedDate);
2888 }
2889
2890 void tr_torrentSetActivityDate(tr_torrent* tor, time_t t)
2891 {
2892     TR_ASSERT(tr_isTorrent(tor));
2893
2894     tor->activityDate = t;
2895     tor->anyDate = MAX(tor->anyDate, tor->activityDate);
2896 }
2897
2898 void tr_torrentSetDoneDate(tr_torrent* tor, time_t t)
2899 {
2900     TR_ASSERT(tr_isTorrent(tor));
2901
2902     tor->doneDate = t;
2903     tor->anyDate = MAX(tor->anyDate, tor->doneDate);
2904 }
2905
2906 /**
2907 ***
2908 **/
2909
2910 uint64_t tr_torrentGetBytesLeftToAllocate(tr_torrent const* tor)
2911 {
2912     TR_ASSERT(tr_isTorrent(tor));
2913
2914     uint64_t bytesLeft = 0;
2915
2916     for (tr_file_index_t i = 0; i < tor->info.fileCount; ++i)
2917     {
2918         if (!tor->info.files[i].dnd)
2919         {
2920             tr_sys_path_info info;
2921             uint64_t const length = tor->info.files[i].length;
2922             char* path = tr_torrentFindFile(tor, i);
2923
2924             bytesLeft += length;
2925
2926             if (path != NULL && tr_sys_path_get_info(path, 0, &info, NULL) && info.type == TR_SYS_PATH_IS_FILE &&
2927                 info.size <= length)
2928             {
2929                 bytesLeft -= info.size;
2930             }
2931
2932             tr_free(path);
2933         }
2934     }
2935
2936     return bytesLeft;
2937 }
2938
2939 /****
2940 *****  Removing the torrent's local data
2941 ****/
2942
2943 static bool isJunkFile(char const* base)
2944 {
2945     static char const* files[] =
2946     {
2947         ".DS_Store",
2948         "desktop.ini",
2949         "Thumbs.db"
2950     };
2951
2952     for (size_t i = 0; i < TR_N_ELEMENTS(files); ++i)
2953     {
2954         if (strcmp(base, files[i]) == 0)
2955         {
2956             return true;
2957         }
2958     }
2959
2960 #ifdef __APPLE__
2961
2962     /* check for resource forks. <http://support.apple.com/kb/TA20578> */
2963     if (memcmp(base, "._", 2) == 0)
2964     {
2965         return true;
2966     }
2967
2968 #endif
2969
2970     return false;
2971 }
2972
2973 static void removeEmptyFoldersAndJunkFiles(char const* folder)
2974 {
2975     tr_sys_dir_t odir;
2976
2977     if ((odir = tr_sys_dir_open(folder, NULL)) != TR_BAD_SYS_DIR)
2978     {
2979         char const* name;
2980
2981         while ((name = tr_sys_dir_read_name(odir, NULL)) != NULL)
2982         {
2983             if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
2984             {
2985                 tr_sys_path_info info;
2986                 char* filename = tr_buildPath(folder, name, NULL);
2987
2988                 if (tr_sys_path_get_info(filename, 0, &info, NULL) && info.type == TR_SYS_PATH_IS_DIRECTORY)
2989                 {
2990                     removeEmptyFoldersAndJunkFiles(filename);
2991                 }
2992                 else if (isJunkFile(name))
2993                 {
2994                     tr_sys_path_remove(filename, NULL);
2995                 }
2996
2997                 tr_free(filename);
2998             }
2999         }
3000
3001         tr_sys_path_remove(folder, NULL);
3002         tr_sys_dir_close(odir, NULL);
3003     }
3004 }
3005
3006 /**
3007  * This convoluted code does something (seemingly) simple:
3008  * remove the torrent's local files.
3009  *
3010  * Fun complications:
3011  * 1. Try to preserve the directory hierarchy in the recycle bin.
3012  * 2. If there are nontorrent files, don't delete them...
3013  * 3. ...unless the other files are "junk", such as .DS_Store
3014  */
3015 static void deleteLocalData(tr_torrent* tor, tr_fileFunc func)
3016 {
3017     char* base;
3018     tr_sys_dir_t odir;
3019     char* tmpdir = NULL;
3020     tr_ptrArray files = TR_PTR_ARRAY_INIT;
3021     tr_ptrArray folders = TR_PTR_ARRAY_INIT;
3022     PtrArrayCompareFunc vstrcmp = (PtrArrayCompareFunc)strcmp;
3023     char const* const top = tor->currentDir;
3024
3025     /* don't try to delete local data if the directory's gone missing */
3026     if (!tr_sys_path_exists(top, NULL))
3027     {
3028         return;
3029     }
3030
3031     /* if it's a magnet link, there's nothing to move... */
3032     if (!tr_torrentHasMetadata(tor))
3033     {
3034         return;
3035     }
3036
3037     /***
3038     ****  Move the local data to a new tmpdir
3039     ***/
3040
3041     base = tr_strdup_printf("%s__XXXXXX", tr_torrentName(tor));
3042     tmpdir = tr_buildPath(top, base, NULL);
3043     tr_sys_dir_create_temp(tmpdir, NULL);
3044     tr_free(base);
3045
3046     for (tr_file_index_t f = 0; f < tor->info.fileCount; ++f)
3047     {
3048         char* filename;
3049
3050         /* try to find the file, looking in the partial and download dirs */
3051         filename = tr_buildPath(top, tor->info.files[f].name, NULL);
3052
3053         if (!tr_sys_path_exists(filename, NULL))
3054         {
3055             char* partial = tr_torrentBuildPartial(tor, f);
3056             tr_free(filename);
3057             filename = tr_buildPath(top, partial, NULL);
3058             tr_free(partial);
3059
3060             if (!tr_sys_path_exists(filename, NULL))
3061             {
3062                 tr_free(filename);
3063                 filename = NULL;
3064             }
3065         }
3066
3067         /* if we found the file, move it */
3068         if (filename != NULL)
3069         {
3070             char* target = tr_buildPath(tmpdir, tor->info.files[f].name, NULL);
3071             tr_moveFile(filename, target, NULL);
3072             tr_ptrArrayAppend(&files, target);
3073             tr_free(filename);
3074         }
3075     }
3076
3077     /***
3078     ****  Remove tmpdir.
3079     ****
3080     ****  Try deleting the top-level files & folders to preserve
3081     ****  the directory hierarchy in the recycle bin.
3082     ****  If case that fails -- for example, rmdir () doesn't
3083     ****  delete nonempty folders -- go from the bottom up too.
3084     ***/
3085
3086     /* try deleting the local data's top-level files & folders */
3087     if ((odir = tr_sys_dir_open(tmpdir, NULL)) != TR_BAD_SYS_DIR)
3088     {
3089         char const* name;
3090
3091         while ((name = tr_sys_dir_read_name(odir, NULL)) != NULL)
3092         {
3093             if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
3094             {
3095                 char* file = tr_buildPath(tmpdir, name, NULL);
3096                 (*func)(file, NULL);
3097                 tr_free(file);
3098             }
3099         }
3100
3101         tr_sys_dir_close(odir, NULL);
3102     }
3103
3104     /* go from the bottom up */
3105     for (int i = 0, n = tr_ptrArraySize(&files); i < n; ++i)
3106     {
3107         char* walk = tr_strdup(tr_ptrArrayNth(&files, i));
3108
3109         while (tr_sys_path_exists(walk, NULL) && !tr_sys_path_is_same(tmpdir, walk, NULL))
3110         {
3111             char* tmp = tr_sys_path_dirname(walk, NULL);
3112             (*func)(walk, NULL);
3113             tr_free(walk);
3114             walk = tmp;
3115         }
3116
3117         tr_free(walk);
3118     }
3119
3120     /***
3121     ****  The local data has been removed.
3122     ****  What's left in top are empty folders, junk, and user-generated files.
3123     ****  Remove the first two categories and leave the third.
3124     ***/
3125
3126     /* build a list of 'top's child directories that belong to this torrent */
3127     for (tr_file_index_t f = 0; f < tor->info.fileCount; ++f)
3128     {
3129         char* dir;
3130         char* filename;
3131
3132         /* get the directory that this file goes in... */
3133         filename = tr_buildPath(top, tor->info.files[f].name, NULL);
3134         dir = tr_sys_path_dirname(filename, NULL);
3135         tr_free(filename);
3136
3137         if (dir == NULL)
3138         {
3139             continue;
3140         }
3141
3142         /* walk up the directory tree until we reach 'top' */
3143         if (!tr_sys_path_is_same(top, dir, NULL) && strcmp(top, dir) != 0)
3144         {
3145             for (;;)
3146             {
3147                 char* parent = tr_sys_path_dirname(dir, NULL);
3148
3149                 if (tr_sys_path_is_same(top, parent, NULL) || strcmp(top, parent) == 0)
3150                 {
3151                     if (tr_ptrArrayFindSorted(&folders, dir, vstrcmp) == NULL)
3152                     {
3153                         tr_ptrArrayInsertSorted(&folders, tr_strdup(dir), vstrcmp);
3154                     }
3155
3156                     tr_free(parent);
3157                     break;
3158                 }
3159
3160                 /* walk upwards to parent */
3161                 tr_free(dir);
3162                 dir = parent;
3163             }
3164         }
3165
3166         tr_free(dir);
3167     }
3168
3169     for (int i = 0, n = tr_ptrArraySize(&folders); i < n; ++i)
3170     {
3171         removeEmptyFoldersAndJunkFiles(tr_ptrArrayNth(&folders, i));
3172     }
3173
3174     /* cleanup */
3175     tr_sys_path_remove(tmpdir, NULL);
3176     tr_free(tmpdir);
3177     tr_ptrArrayDestruct(&folders, tr_free);
3178     tr_ptrArrayDestruct(&files, tr_free);
3179 }
3180
3181 static void tr_torrentDeleteLocalData(tr_torrent* tor, tr_fileFunc func)
3182 {
3183     TR_ASSERT(tr_isTorrent(tor));
3184
3185     if (func == NULL)
3186     {
3187         func = tr_sys_path_remove;
3188     }
3189
3190     /* close all the files because we're about to delete them */
3191     tr_cacheFlushTorrent(tor->session->cache, tor);
3192     tr_fdTorrentClose(tor->session, tor->uniqueId);
3193
3194     deleteLocalData(tor, func);
3195 }
3196
3197 /***
3198 ****
3199 ***/
3200
3201 struct LocationData
3202 {
3203     bool move_from_old_location;
3204     int volatile* setme_state;
3205     double volatile* setme_progress;
3206     char* location;
3207     tr_torrent* tor;
3208 };
3209
3210 static void setLocation(void* vdata)
3211 {
3212     struct LocationData* data = vdata;
3213     tr_torrent* tor = data->tor;
3214
3215     TR_ASSERT(tr_isTorrent(tor));
3216
3217     tr_torrentLock(tor);
3218
3219     bool err = false;
3220     bool const do_move = data->move_from_old_location;
3221     char const* location = data->location;
3222     double bytesHandled = 0;
3223
3224     tr_logAddDebug("Moving \"%s\" location from currentDir \"%s\" to \"%s\"", tr_torrentName(tor), tor->currentDir, location);
3225
3226     tr_sys_dir_create(location, TR_SYS_DIR_CREATE_PARENTS, 0777, NULL);
3227
3228     if (!tr_sys_path_is_same(location, tor->currentDir, NULL))
3229     {
3230         /* bad idea to move files while they're being verified... */
3231         tr_verifyRemove(tor);
3232
3233         /* try to move the files.
3234          * FIXME: there are still all kinds of nasty cases, like what
3235          * if the target directory runs out of space halfway through... */
3236         for (tr_file_index_t i = 0; !err && i < tor->info.fileCount; ++i)
3237         {
3238             char* sub;
3239             char const* oldbase;
3240             tr_file const* f = &tor->info.files[i];
3241
3242             if (tr_torrentFindFile2(tor, i, &oldbase, &sub, NULL))
3243             {
3244                 char* oldpath = tr_buildPath(oldbase, sub, NULL);
3245                 char* newpath = tr_buildPath(location, sub, NULL);
3246
3247                 tr_logAddDebug("Found file #%d: %s", (int)i, oldpath);
3248
3249                 if (do_move && !tr_sys_path_is_same(oldpath, newpath, NULL))
3250                 {
3251                     tr_error* error = NULL;
3252
3253                     tr_logAddTorInfo(tor, "moving \"%s\" to \"%s\"", oldpath, newpath);
3254
3255                     if (!tr_moveFile(oldpath, newpath, &error))
3256                     {
3257                         err = true;
3258                         tr_logAddTorErr(tor, "error moving \"%s\" to \"%s\": %s", oldpath, newpath, error->message);
3259                         tr_error_free(error);
3260                     }
3261                 }
3262
3263                 tr_free(newpath);
3264                 tr_free(oldpath);
3265                 tr_free(sub);
3266             }
3267
3268             if (data->setme_progress != NULL)
3269             {
3270                 bytesHandled += f->length;
3271                 *data->setme_progress = bytesHandled / tor->info.totalSize;
3272             }
3273         }
3274
3275         if (!err && do_move)
3276         {
3277             /* blow away the leftover subdirectories in the old location */
3278             tr_torrentDeleteLocalData(tor, tr_sys_path_remove);
3279         }
3280     }
3281
3282     if (!err)
3283     {
3284         /* set the new location and reverify */
3285         tr_torrentSetDownloadDir(tor, location);
3286
3287         if (do_move)
3288         {
3289             tr_free(tor->incompleteDir);
3290             tor->incompleteDir = NULL;
3291             tor->currentDir = tor->downloadDir;
3292         }
3293     }
3294
3295     if (data->setme_state != NULL)
3296     {
3297         *data->setme_state = err ? TR_LOC_ERROR : TR_LOC_DONE;
3298     }
3299
3300     /* cleanup */
3301     tr_torrentUnlock(tor);
3302     tr_free(data->location);
3303     tr_free(data);
3304 }
3305
3306 void tr_torrentSetLocation(tr_torrent* tor, char const* location, bool move_from_old_location, double volatile* setme_progress,
3307     int volatile* setme_state)
3308 {
3309     TR_ASSERT(tr_isTorrent(tor));
3310
3311     if (setme_state != NULL)
3312     {
3313         *setme_state = TR_LOC_MOVING;
3314     }
3315
3316     if (setme_progress != NULL)
3317     {
3318         *setme_progress = 0;
3319     }
3320
3321     /* run this in the libtransmission thread */
3322     struct LocationData* data = tr_new(struct LocationData, 1);
3323     data->tor = tor;
3324     data->location = tr_strdup(location);
3325     data->move_from_old_location = move_from_old_location;
3326     data->setme_state = setme_state;
3327     data->setme_progress = setme_progress;
3328     tr_runInEventThread(tor->session, setLocation, data);
3329 }
3330
3331 /***
3332 ****
3333 ***/
3334
3335 static void tr_torrentFileCompleted(tr_torrent* tor, tr_file_index_t fileIndex)
3336 {
3337     char* sub;
3338     char const* base;
3339     tr_info const* inf = &tor->info;
3340     tr_file const* f = &inf->files[fileIndex];
3341     time_t const now = tr_time();
3342
3343     /* close the file so that we can reopen in read-only mode as needed */
3344     tr_cacheFlushFile(tor->session->cache, tor, fileIndex);
3345     tr_fdFileClose(tor->session, tor, fileIndex);
3346
3347     /* now that the file is complete and closed, we can start watching its
3348      * mtime timestamp for changes to know if we need to reverify pieces */
3349     for (tr_piece_index_t i = f->firstPiece; i <= f->lastPiece; ++i)
3350     {
3351         inf->pieces[i].timeChecked = now;
3352     }
3353
3354     /* if the torrent's current filename isn't the same as the one in the
3355      * metadata -- for example, if it had the ".part" suffix appended to
3356      * it until now -- then rename it to match the one in the metadata */
3357     if (tr_torrentFindFile2(tor, fileIndex, &base, &sub, NULL))
3358     {
3359         if (strcmp(sub, f->name) != 0)
3360         {
3361             char* oldpath = tr_buildPath(base, sub, NULL);
3362             char* newpath = tr_buildPath(base, f->name, NULL);
3363             tr_error* error = NULL;
3364
3365             if (!tr_sys_path_rename(oldpath, newpath, &error))
3366             {
3367                 tr_logAddTorErr(tor, "Error moving \"%s\" to \"%s\": %s", oldpath, newpath, error->message);
3368                 tr_error_free(error);
3369             }
3370
3371             tr_free(newpath);
3372             tr_free(oldpath);
3373         }
3374
3375         tr_free(sub);
3376     }
3377 }
3378
3379 static void tr_torrentPieceCompleted(tr_torrent* tor, tr_piece_index_t pieceIndex)
3380 {
3381     tr_peerMgrPieceCompleted(tor, pieceIndex);
3382
3383     /* if this piece completes any file, invoke the fileCompleted func for it */
3384     for (tr_file_index_t i = 0; i < tor->info.fileCount; ++i)
3385     {
3386         tr_file const* file = &tor->info.files[i];
3387
3388         if (file->firstPiece <= pieceIndex && pieceIndex <= file->lastPiece)
3389         {
3390             if (tr_cpFileIsComplete(&tor->completion, i))
3391             {
3392                 tr_torrentFileCompleted(tor, i);
3393             }
3394         }
3395     }
3396 }
3397
3398 void tr_torrentGotBlock(tr_torrent* tor, tr_block_index_t block)
3399 {
3400     TR_ASSERT(tr_isTorrent(tor));
3401     TR_ASSERT(tr_amInEventThread(tor->session));
3402
3403     bool const block_is_new = !tr_torrentBlockIsComplete(tor, block);
3404
3405     if (block_is_new)
3406     {
3407         tr_piece_index_t p;
3408
3409         tr_cpBlockAdd(&tor->completion, block);
3410         tr_torrentSetDirty(tor);
3411
3412         p = tr_torBlockPiece(tor, block);
3413
3414         if (tr_torrentPieceIsComplete(tor, p))
3415         {
3416             tr_logAddTorDbg(tor, "[LAZY] checking just-completed piece %zu", (size_t)p);
3417
3418             if (tr_torrentCheckPiece(tor, p))
3419             {
3420                 tr_torrentPieceCompleted(tor, p);
3421             }
3422             else
3423             {
3424                 uint32_t const n = tr_torPieceCountBytes(tor, p);
3425                 tr_logAddTorErr(tor, _("Piece %" PRIu32 ", which was just downloaded, failed its checksum test"), p);
3426                 tor->corruptCur += n;
3427                 tor->downloadedCur -= MIN(tor->downloadedCur, n);
3428                 tr_peerMgrGotBadPiece(tor, p);
3429             }
3430         }
3431     }
3432     else
3433     {
3434         uint32_t const n = tr_torBlockCountBytes(tor, block);
3435         tor->downloadedCur -= MIN(tor->downloadedCur, n);
3436         tr_logAddTorDbg(tor, "we have this block already...");
3437     }
3438 }
3439
3440 /***
3441 ****
3442 ***/
3443
3444 bool tr_torrentFindFile2(tr_torrent const* tor, tr_file_index_t fileNum, char const** base, char** subpath, time_t* mtime)
3445 {
3446     TR_ASSERT(tr_isTorrent(tor));
3447     TR_ASSERT(fileNum < tor->info.fileCount);
3448
3449     char* part = NULL;
3450     tr_file const* file;
3451     char const* b = NULL;
3452     char const* s = NULL;
3453     tr_sys_path_info file_info;
3454
3455     file = &tor->info.files[fileNum];
3456
3457     /* look in the download dir... */
3458     if (b == NULL)
3459     {
3460         char* filename = tr_buildPath(tor->downloadDir, file->name, NULL);
3461
3462         if (tr_sys_path_get_info(filename, 0, &file_info, NULL))
3463         {
3464             b = tor->downloadDir;
3465             s = file->name;
3466         }
3467
3468         tr_free(filename);
3469     }
3470
3471     /* look in the incomplete dir... */
3472     if (b == NULL && tor->incompleteDir != NULL)
3473     {
3474         char* filename = tr_buildPath(tor->incompleteDir, file->name, NULL);
3475
3476         if (tr_sys_path_get_info(filename, 0, &file_info, NULL))
3477         {
3478             b = tor->incompleteDir;
3479             s = file->name;
3480         }
3481
3482         tr_free(filename);
3483     }
3484
3485     if (b == NULL)
3486     {
3487         part = tr_torrentBuildPartial(tor, fileNum);
3488     }
3489
3490     /* look for a .part file in the incomplete dir... */
3491     if (b == NULL && tor->incompleteDir != NULL)
3492     {
3493         char* filename = tr_buildPath(tor->incompleteDir, part, NULL);
3494
3495         if (tr_sys_path_get_info(filename, 0, &file_info, NULL))
3496         {
3497             b = tor->incompleteDir;
3498             s = part;
3499         }
3500
3501         tr_free(filename);
3502     }
3503
3504     /* look for a .part file in the download dir... */
3505     if (b == NULL)
3506     {
3507         char* filename = tr_buildPath(tor->downloadDir, part, NULL);
3508
3509         if (tr_sys_path_get_info(filename, 0, &file_info, NULL))
3510         {
3511             b = tor->downloadDir;
3512             s = part;
3513         }
3514
3515         tr_free(filename);
3516     }
3517
3518     /* return the results */
3519     if (base != NULL)
3520     {
3521         *base = b;
3522     }
3523
3524     if (subpath != NULL)
3525     {
3526         *subpath = tr_strdup(s);
3527     }
3528
3529     if (mtime != NULL)
3530     {
3531         *mtime = file_info.last_modified_at;
3532     }
3533
3534     /* cleanup */
3535     tr_free(part);
3536     return b != NULL;
3537 }
3538
3539 char* tr_torrentFindFile(tr_torrent const* tor, tr_file_index_t fileNum)
3540 {
3541     char* subpath;
3542     char* ret = NULL;
3543     char const* base;
3544
3545     if (tr_torrentFindFile2(tor, fileNum, &base, &subpath, NULL))
3546     {
3547         ret = tr_buildPath(base, subpath, NULL);
3548         tr_free(subpath);
3549     }
3550
3551     return ret;
3552 }
3553
3554 /* Decide whether we should be looking for files in downloadDir or incompleteDir. */
3555 static void refreshCurrentDir(tr_torrent* tor)
3556 {
3557     char const* dir = NULL;
3558
3559     if (tor->incompleteDir == NULL)
3560     {
3561         dir = tor->downloadDir;
3562     }
3563     else if (!tr_torrentHasMetadata(tor)) /* no files to find */
3564     {
3565         dir = tor->incompleteDir;
3566     }
3567     else if (!tr_torrentFindFile2(tor, 0, &dir, NULL, NULL))
3568     {
3569         dir = tor->incompleteDir;
3570     }
3571
3572     TR_ASSERT(dir != NULL);
3573     TR_ASSERT(dir == tor->downloadDir || dir == tor->incompleteDir);
3574
3575     tor->currentDir = dir;
3576 }
3577
3578 char* tr_torrentBuildPartial(tr_torrent const* tor, tr_file_index_t fileNum)
3579 {
3580     return tr_strdup_printf("%s.part", tor->info.files[fileNum].name);
3581 }
3582
3583 /***
3584 ****
3585 ***/
3586
3587 static int compareTorrentByQueuePosition(void const* va, void const* vb)
3588 {
3589     tr_torrent const* a = *(tr_torrent const* const*)va;
3590     tr_torrent const* b = *(tr_torrent const* const*)vb;
3591
3592     return a->queuePosition - b->queuePosition;
3593 }
3594
3595 #ifdef TR_ENABLE_ASSERTS
3596
3597 static bool queueIsSequenced(tr_session* session)
3598 {
3599     int n;
3600     bool is_sequenced;
3601     tr_torrent** torrents;
3602
3603     n = 0;
3604     torrents = tr_sessionGetTorrents(session, &n);
3605     qsort(torrents, n, sizeof(tr_torrent*), compareTorrentByQueuePosition);
3606
3607 #if 0
3608
3609     fprintf(stderr, "%s", "queue: ");
3610
3611     for (int i = 0; i < n; ++i)
3612     {
3613         fprintf(stderr, "%d ", tmp[i]->queuePosition);
3614     }
3615
3616     fputc('\n', stderr);
3617
3618 #endif
3619
3620     /* test them */
3621     is_sequenced = true;
3622
3623     for (int i = 0; is_sequenced && i < n; ++i)
3624     {
3625         is_sequenced = torrents[i]->queuePosition == i;
3626     }
3627
3628     tr_free(torrents);
3629     return is_sequenced;
3630 }
3631
3632 #endif
3633
3634 int tr_torrentGetQueuePosition(tr_torrent const* tor)
3635 {
3636     return tor->queuePosition;
3637 }
3638
3639 void tr_torrentSetQueuePosition(tr_torrent* tor, int pos)
3640 {
3641     int back = -1;
3642     tr_torrent* walk;
3643     int const old_pos = tor->queuePosition;
3644     time_t const now = tr_time();
3645
3646     if (pos < 0)
3647     {
3648         pos = 0;
3649     }
3650
3651     tor->queuePosition = -1;
3652
3653     walk = NULL;
3654
3655     while ((walk = tr_torrentNext(tor->session, walk)) != NULL)
3656     {
3657         if (old_pos < pos)
3658         {
3659             if (old_pos <= walk->queuePosition && walk->queuePosition <= pos)
3660             {
3661                 walk->queuePosition--;
3662                 walk->anyDate = now;
3663             }
3664         }
3665
3666         if (old_pos > pos)
3667         {
3668             if (pos <= walk->queuePosition && walk->queuePosition < old_pos)
3669             {
3670                 walk->queuePosition++;
3671                 walk->anyDate = now;
3672             }
3673         }
3674
3675         if (back < walk->queuePosition)
3676         {
3677             back = walk->queuePosition;
3678         }
3679     }
3680
3681     tor->queuePosition = MIN(pos, back + 1);
3682     tor->anyDate = now;
3683
3684     TR_ASSERT(queueIsSequenced(tor->session));
3685 }
3686
3687 void tr_torrentsQueueMoveTop(tr_torrent** torrents_in, int n)
3688 {
3689     tr_torrent** torrents = tr_memdup(torrents_in, sizeof(tr_torrent*) * n);
3690     qsort(torrents, n, sizeof(tr_torrent*), compareTorrentByQueuePosition);
3691
3692     for (int i = n - 1; i >= 0; --i)
3693     {
3694         tr_torrentSetQueuePosition(torrents[i], 0);
3695     }
3696
3697     tr_free(torrents);
3698 }
3699
3700 void tr_torrentsQueueMoveUp(tr_torrent** torrents_in, int n)
3701 {
3702     tr_torrent** torrents;
3703
3704     torrents = tr_memdup(torrents_in, sizeof(tr_torrent*) * n);
3705     qsort(torrents, n, sizeof(tr_torrent*), compareTorrentByQueuePosition);
3706
3707     for (int i = 0; i < n; ++i)
3708     {
3709         tr_torrentSetQueuePosition(torrents[i], torrents[i]->queuePosition - 1);
3710     }
3711
3712     tr_free(torrents);
3713 }
3714
3715 void tr_torrentsQueueMoveDown(tr_torrent** torrents_in, int n)
3716 {
3717     tr_torrent** torrents;
3718
3719     torrents = tr_memdup(torrents_in, sizeof(tr_torrent*) * n);
3720     qsort(torrents, n, sizeof(tr_torrent*), compareTorrentByQueuePosition);
3721
3722     for (int i = n - 1; i >= 0; --i)
3723     {
3724         tr_torrentSetQueuePosition(torrents[i], torrents[i]->queuePosition + 1);
3725     }
3726
3727     tr_free(torrents);
3728 }
3729
3730 void tr_torrentsQueueMoveBottom(tr_torrent** torrents_in, int n)
3731 {
3732     tr_torrent** torrents;
3733
3734     torrents = tr_memdup(torrents_in, sizeof(tr_torrent*) * n);
3735     qsort(torrents, n, sizeof(tr_torrent*), compareTorrentByQueuePosition);
3736
3737     for (int i = 0; i < n; ++i)
3738     {
3739         tr_torrentSetQueuePosition(torrents[i], INT_MAX);
3740     }
3741
3742     tr_free(torrents);
3743 }
3744
3745 static void torrentSetQueued(tr_torrent* tor, bool queued)
3746 {
3747     TR_ASSERT(tr_isTorrent(tor));
3748
3749     if (tr_torrentIsQueued(tor) != queued)
3750     {
3751         tor->isQueued = queued;
3752         tor->anyDate = tr_time();
3753         tr_torrentSetDirty(tor);
3754     }
3755 }
3756
3757 void tr_torrentSetQueueStartCallback(tr_torrent* torrent, void (* callback)(tr_torrent*, void*), void* user_data)
3758 {
3759     torrent->queue_started_callback = callback;
3760     torrent->queue_started_user_data = user_data;
3761 }
3762
3763 /***
3764 ****
3765 ****  RENAME
3766 ****
3767 ***/
3768
3769 static bool renameArgsAreValid(char const* oldpath, char const* newname)
3770 {
3771     return oldpath != NULL && *oldpath != '\0' && newname != NULL && *newname != '\0' && strcmp(newname, ".") != 0 &&
3772         strcmp(newname, "..") != 0 && strchr(newname, TR_PATH_DELIMITER) == NULL;
3773 }
3774
3775 static tr_file_index_t* renameFindAffectedFiles(tr_torrent* tor, char const* oldpath, size_t* setme_n)
3776 {
3777     size_t n;
3778     size_t oldpath_len;
3779     tr_file_index_t* indices = tr_new0(tr_file_index_t, tor->info.fileCount);
3780
3781     n = 0;
3782     oldpath_len = strlen(oldpath);
3783
3784     for (tr_file_index_t i = 0; i < tor->info.fileCount; ++i)
3785     {
3786         char const* name = tor->info.files[i].name;
3787         size_t const len = strlen(name);
3788
3789         if ((len == oldpath_len || (len > oldpath_len && name[oldpath_len] == '/')) && memcmp(oldpath, name, oldpath_len) == 0)
3790         {
3791             indices[n++] = i;
3792         }
3793     }
3794
3795     *setme_n = n;
3796     return indices;
3797 }
3798
3799 static int renamePath(tr_torrent* tor, char const* oldpath, char const* newname)
3800 {
3801     char* src;
3802     char const* base;
3803     int err = 0;
3804
3805     if (!tr_torrentIsSeed(tor) && tor->incompleteDir != NULL)
3806     {
3807         base = tor->incompleteDir;
3808     }
3809     else
3810     {
3811         base = tor->downloadDir;
3812     }
3813
3814     src = tr_buildPath(base, oldpath, NULL);
3815
3816     if (!tr_sys_path_exists(src, NULL)) /* check for it as a partial */
3817     {
3818         char* tmp = tr_strdup_printf("%s.part", src);
3819         tr_free(src);
3820         src = tmp;
3821     }
3822
3823     if (tr_sys_path_exists(src, NULL))
3824     {
3825         int tmp;
3826         bool tgt_exists;
3827         char* parent = tr_sys_path_dirname(src, NULL);
3828         char* tgt;
3829
3830         if (tr_str_has_suffix(src, ".part"))
3831         {
3832             tgt = tr_strdup_printf("%s" TR_PATH_DELIMITER_STR "%s.part", parent, newname);
3833         }
3834         else
3835         {
3836             tgt = tr_buildPath(parent, newname, NULL);
3837         }
3838
3839         tmp = errno;
3840         tgt_exists = tr_sys_path_exists(tgt, NULL);
3841         errno = tmp;
3842
3843         if (!tgt_exists)
3844         {
3845             tr_error* error = NULL;
3846
3847             tmp = errno;
3848
3849             if (!tr_sys_path_rename(src, tgt, &error))
3850             {
3851                 err = error->code;
3852                 tr_error_free(error);
3853             }
3854
3855             errno = tmp;
3856         }
3857
3858         tr_free(tgt);
3859         tr_free(parent);
3860     }
3861
3862     tr_free(src);
3863
3864     return err;
3865 }
3866
3867 static void renameTorrentFileString(tr_torrent* tor, char const* oldpath, char const* newname, tr_file_index_t fileIndex)
3868 {
3869     char* name;
3870     tr_file* file = &tor->info.files[fileIndex];
3871     size_t const oldpath_len = strlen(oldpath);
3872
3873     if (strchr(oldpath, TR_PATH_DELIMITER) == NULL)
3874     {
3875         if (oldpath_len >= strlen(file->name))
3876         {
3877             name = tr_buildPath(newname, NULL);
3878         }
3879         else
3880         {
3881             name = tr_buildPath(newname, file->name + oldpath_len + 1, NULL);
3882         }
3883     }
3884     else
3885     {
3886         char* tmp = tr_sys_path_dirname(oldpath, NULL);
3887
3888         if (tmp == NULL)
3889         {
3890             return;
3891         }
3892
3893         if (oldpath_len >= strlen(file->name))
3894         {
3895             name = tr_buildPath(tmp, newname, NULL);
3896         }
3897         else
3898         {
3899             name = tr_buildPath(tmp, newname, file->name + oldpath_len + 1, NULL);
3900         }
3901
3902         tr_free(tmp);
3903     }
3904
3905     if (strcmp(file->name, name) == 0)
3906     {
3907         tr_free(name);
3908     }
3909     else
3910     {
3911         tr_free(file->name);
3912         file->name = name;
3913         file->is_renamed = true;
3914     }
3915 }
3916
3917 struct rename_data
3918 {
3919     tr_torrent* tor;
3920     char* oldpath;
3921     char* newname;
3922     tr_torrent_rename_done_func callback;
3923     void* callback_user_data;
3924 };
3925
3926 static void torrentRenamePath(void* vdata)
3927 {
3928     struct rename_data* data = vdata;
3929     tr_torrent* const tor = data->tor;
3930
3931     TR_ASSERT(tr_isTorrent(tor));
3932
3933     /***
3934     ****
3935     ***/
3936
3937     int error = 0;
3938     char const* const oldpath = data->oldpath;
3939     char const* const newname = data->newname;
3940
3941     if (!renameArgsAreValid(oldpath, newname))
3942     {
3943         error = EINVAL;
3944     }
3945     else
3946     {
3947         size_t n;
3948         tr_file_index_t* file_indices;
3949
3950         file_indices = renameFindAffectedFiles(tor, oldpath, &n);
3951
3952         if (n == 0)
3953         {
3954             error = EINVAL;
3955         }
3956         else
3957         {
3958             error = renamePath(tor, oldpath, newname);
3959
3960             if (error == 0)
3961             {
3962                 /* update tr_info.files */
3963                 for (size_t i = 0; i < n; ++i)
3964                 {
3965                     renameTorrentFileString(tor, oldpath, newname, file_indices[i]);
3966                 }
3967
3968                 /* update tr_info.name if user changed the toplevel */
3969                 if (n == tor->info.fileCount && strchr(oldpath, '/') == NULL)
3970                 {
3971                     tr_free(tor->info.name);
3972                     tor->info.name = tr_strdup(newname);
3973                 }
3974
3975                 tr_torrentSetDirty(tor);
3976             }
3977         }
3978
3979         tr_free(file_indices);
3980     }
3981
3982     /***
3983     ****
3984     ***/
3985
3986     tor->anyDate = tr_time();
3987
3988     /* callback */
3989     if (data->callback != NULL)
3990     {
3991         (*data->callback)(tor, data->oldpath, data->newname, error, data->callback_user_data);
3992     }
3993
3994     /* cleanup */
3995     tr_free(data->oldpath);
3996     tr_free(data->newname);
3997     tr_free(data);
3998 }
3999
4000 void tr_torrentRenamePath(tr_torrent* tor, char const* oldpath, char const* newname, tr_torrent_rename_done_func callback,
4001     void* callback_user_data)
4002 {
4003     struct rename_data* data;
4004
4005     data = tr_new0(struct rename_data, 1);
4006     data->tor = tor;
4007     data->oldpath = tr_strdup(oldpath);
4008     data->newname = tr_strdup(newname);
4009     data->callback = callback;
4010     data->callback_user_data = callback_user_data;
4011
4012     tr_runInEventThread(tor->session, torrentRenamePath, data);
4013 }