1 diff --git a/doc/lftp.1 b/doc/lftp.1
2 index d5d408f..9222795 100644
5 @@ -1748,10 +1748,15 @@ is applied. It is never used if mirror:exclude-regex is empty.
6 .BR mirror:no-empty-dirs " (boolean)"
7 when true, mirror doesn't create empty directories (like \-\-no\-empty\-dirs option).
9 +.BR mirror:sort-by " (string)"
10 +specifies order of file transfers. Valid values are: name, name-desc, size, size-desc,
11 +date, date-desc. When the value is name or name-desc, then mirror:order setting also
12 +affects the order or transfers.
14 .BR mirror:order " (list of patterns)"
15 -specifies order of file transfers. E.g. setting this to "*.sfv *.sum" makes mirror to
16 +specifies order of file transfers when sorting by name. E.g. setting this to "*.sfv *.sum" makes mirror to
17 transfer files matching *.sfv first, then ones matching *.sum and then all other
18 -files. To process directories after other files, add "*/" to end of pattern list.
19 +files. To process directories after other files, add "*/" to the end of pattern list.
21 .BR mirror:parallel-directories " (boolean)"
22 if true, mirror will start processing of several directories in parallel
23 diff --git a/po/pl.po b/po/pl.po
24 index d569428..89e8b11 100644
31 -"Project-Id-Version: lftp 4.4.16\n"
32 +"Project-Id-Version: lftp 4.5.3\n"
33 "Report-Msgid-Bugs-To: lftp-bugs@lftp.yar.ru\n"
34 "POT-Creation-Date: 2014-07-06 16:15+0400\n"
35 -"PO-Revision-Date: 2014-05-18 06:54+0200\n"
36 +"PO-Revision-Date: 2014-07-13 14:15+0200\n"
37 "Last-Translator: Jakub Bogusz <qboosh@pld-linux.org>\n"
38 "Language-Team: Polish <translation-team-pl@lists.sourceforge.net>\n"
40 @@ -1152,12 +1152,10 @@ msgstr ""
41 "uczyni dopełnianie nazw plików nie rozpoznającym wielkości liter.\n"
43 #: src/commands.cc:216
45 msgid "debug [OPTS] [<level>|off]"
46 -msgstr "debug [<poziom>|off] [-o <plik>]"
47 +msgstr "debug [OPCJE] [<poziom>|off]"
49 #: src/commands.cc:217
52 "Set debug level to given value or turn debug off completely.\n"
53 " -o <file> redirect debug output to the file\n"
54 @@ -1165,8 +1163,11 @@ msgid ""
56 " -t show timestamps\n"
58 -"Ustaw poziom debugowania na daną wartość lub wyłącz zupełnie.\n"
59 -" -o <plik> przekieruj wyjście debugowania do pliku.\n"
60 +"Ustaw poziom diagnostyki na daną wartość lub wyłącz zupełnie.\n"
61 +" -o <plik> przekieruj wyjście diagnostyki do pliku.\n"
62 +" -c wypisuj kontekst komunikatu\n"
64 +" -t wypisuj znaczniki czasu\n"
66 #: src/commands.cc:222
67 msgid "du [options] <dirs>"
68 @@ -1477,12 +1478,10 @@ msgstr ""
69 "podano nazw obu katalogów, to będą użyte bieżące katalogi lokalny i zdalny.\n"
71 #: src/commands.cc:339
73 msgid "mkdir [OPTS] <dirs>"
74 -msgstr "mkdir [-p] <katalogi>"
75 +msgstr "mkdir [OPCJE] <katalogi>"
77 #: src/commands.cc:340
80 "Make remote directories\n"
81 " -p make all levels of path\n"
82 @@ -1490,6 +1489,7 @@ msgid ""
84 "Utwórz zdalne katalogi\n"
85 " -p tworzy wszystkie poziomy ścieżki\n"
86 +" -f ciche działanie, bez komunikatów\n"
88 #: src/commands.cc:343
89 msgid "module name [args]"
90 @@ -2378,9 +2378,9 @@ msgid "unsupported network protocol"
91 msgstr "protokół nie jest obsługiwany"
93 #: src/ftpclass.cc:2133 src/ftpclass.cc:2228
96 msgid "Data socket error (%s) - reconnecting"
97 -msgstr "Błąd połączenia (%s) - powtórne łączenie"
98 +msgstr "Błąd gniazda danych (%s) - powtórne łączenie"
100 #: src/ftpclass.cc:2161
102 @@ -2700,13 +2700,12 @@ msgid "peer unexpectedly closed connection after %s"
103 msgstr "druga strona nieoczekiwanie zamknęła połączenie po %s"
105 #: src/Torrent.cc:2903 src/Torrent.cc:3020
107 msgid "peer unexpectedly closed connection"
108 -msgstr "druga strona nieoczekiwanie zamknęła połączenie po %s"
109 +msgstr "druga strona nieoczekiwanie zamknęła połączenie"
111 #: src/Torrent.cc:2905 src/Torrent.cc:2906
112 msgid "peer closed connection (before handshake)"
113 -msgstr "druga strona zamknęła połączenie (przed jego ustanowieniem)"
114 +msgstr "druga strona zamknęła połączenie (przed przywitaniem)"
116 #: src/Torrent.cc:2909 src/Torrent.cc:3022 src/Torrent.cc:3023
117 msgid "invalid peer response format"
118 @@ -2732,15 +2731,15 @@ msgstr "Przyjęto połączenie od [%s]:%d"
119 #: src/Torrent.cc:3552
121 msgid "peer sent unknown info_hash=%s in handshake"
123 +msgstr "druga strona wysłała nieznane info_hash=%s przy przywitaniu"
125 #: src/Torrent.cc:3576
126 msgid "peer handshake timeout"
127 -msgstr "upłynął limit czasu nawiązywania połączenia z drugą stroną"
128 +msgstr "upłynął limit czasu przywitania z drugą stroną"
130 #: src/Torrent.cc:3588
131 msgid "peer short handshake"
132 -msgstr "nawiązanie połączenia z drugą stroną zostało ucięte"
133 +msgstr "przywitanie z drugą stroną zostało ucięte"
135 #: src/Torrent.cc:3590
136 msgid "peer closed just accepted connection"
137 diff --git a/src/FileSet.cc b/src/FileSet.cc
138 index 389578a..6380a68 100644
141 @@ -232,6 +232,21 @@ void FileSet::Sort(sort_e newsort, bool casefold, bool reverse)
145 +// reverse current sort order
146 +void FileSet::ReverseSort()
149 + Sort(BYNAME,false,true);
153 + int j=sorted.length()-1;
155 + sorted[i]=replace_value(sorted[j],sorted[i]);
160 /* Remove the current sort, allowing new entries to be added.
161 * (Nothing uses this ... */
162 void FileSet::Unsort()
163 diff --git a/src/FileSet.h b/src/FileSet.h
164 index 7c3ac2a..155536f 100644
167 @@ -180,6 +180,7 @@ public:
168 void Sort(sort_e newsort, bool casefold=false, bool reverse=false);
170 void SortByPatternList(const char *list_c);
171 + void ReverseSort();
173 void Exclude(const char *prefix,const PatternSet *x);
175 diff --git a/src/Fish.cc b/src/Fish.cc
176 index d172a20..29ba4c6 100644
179 @@ -98,6 +98,15 @@ int Fish::Do()
180 timeout_timer.Reset(send_buf->EventTime());
182 timeout_timer.Reset(recv_buf->EventTime());
184 + timeout_timer.Reset(pty_send_buf->EventTime());
186 + timeout_timer.Reset(pty_recv_buf->EventTime());
188 + // check for timeout only if there should be connection activity.
189 + if(state!=DISCONNECTED && (state!=CONNECTED || !RespQueueIsEmpty())
190 + && mode!=CLOSED && CheckTimeout())
193 if((state==FILE_RECV || state==FILE_SEND)
195 @@ -275,14 +284,6 @@ int Fish::Do()
202 - timeout_timer.Reset(send_buf->EventTime());
204 - timeout_timer.Reset(recv_buf->EventTime());
210 diff --git a/src/MirrorJob.cc b/src/MirrorJob.cc
211 index a19ff8e..eb148f1 100644
212 --- a/src/MirrorJob.cc
213 +++ b/src/MirrorJob.cc
214 @@ -589,10 +589,16 @@ void MirrorJob::InitSets(const FileSet *source,const FileSet *dest)
216 to_transfer->SubtractAny(to_rm_mismatched);
218 - to_transfer->SortByPatternList(ResMgr::Query("mirror:order",0));
219 - to_transfer->CountBytes(&bytes_to_transfer);
221 - parent_mirror->AddBytesToTransfer(bytes_to_transfer);
222 + const char *sort_by=ResMgr::Query("mirror:sort-by",0);
223 + bool desc=strstr(sort_by,"-desc");
224 + if(!strncmp(sort_by,"name",4))
225 + to_transfer->SortByPatternList(ResMgr::Query("mirror:order",0));
226 + else if(!strncmp(sort_by,"date",4))
227 + to_transfer->Sort(FileSet::BYDATE);
228 + else if(!strncmp(sort_by,"size",4))
229 + to_transfer->Sort(FileSet::BYSIZE,false,true);
231 + to_transfer->ReverseSort();
234 to_transfer->Count(&dir_count,NULL,NULL,NULL);
235 @@ -851,10 +857,16 @@ int MirrorJob::Do()
238 InitSets(source_set,target_set);
240 + to_transfer->CountBytes(&bytes_to_transfer);
242 + parent_mirror->AddBytesToTransfer(bytes_to_transfer);
244 to_rm->Count(&stats.del_dirs,&stats.del_files,&stats.del_symlinks,&stats.del_files);
246 to_rm_mismatched->Count(&stats.del_dirs,&stats.del_files,&stats.del_symlinks,&stats.del_files);
247 to_rm_mismatched->rewind();
249 set_state(TARGET_REMOVE_OLD_FIRST);
250 goto TARGET_REMOVE_OLD_FIRST_label;
252 diff --git a/src/PollVec.cc b/src/PollVec.cc
253 index a18b517..e1d72fb 100644
256 @@ -31,7 +31,7 @@ static inline bool operator<(const timeval& a,const timeval& b)
257 void PollVec::AddTimeoutU(unsigned t)
259 struct timeval new_timeout={t/1000000,t%1000000};
260 - if(new_timeout<tv_timeout)
261 + if(tv_timeout.tv_sec<0 || new_timeout<tv_timeout)
262 SetTimeout(new_timeout);
265 diff --git a/src/ProcWait.cc b/src/ProcWait.cc
266 index 0a065ad..d3dfec4 100644
267 --- a/src/ProcWait.cc
268 +++ b/src/ProcWait.cc
270 #include "ProcWait.h"
271 #include "SignalHook.h"
273 -ProcWait *ProcWait::chain=0;
274 +xmap<ProcWait*> ProcWait::all_proc;
276 +const xstring& ProcWait::proc_key(pid_t p)
278 + static xstring tmp_key;
279 + tmp_key.nset((const char*)&p,sizeof(p));
285 @@ -100,27 +107,19 @@ int ProcWait::Kill(int sig)
288 ProcWait::ProcWait(pid_t p)
299 + all_proc.add(proc_key(pid),this);
302 ProcWait::~ProcWait()
304 - for(ProcWait **scan=&chain; *scan; scan=&(*scan)->next)
312 + all_proc.remove(proc_key(pid));
315 void ProcWait::SIGCHLD_handler(int sig)
316 @@ -130,16 +129,9 @@ void ProcWait::SIGCHLD_handler(int sig)
317 pid_t pp=waitpid(-1,&info,WUNTRACED|WNOHANG);
320 - for(ProcWait *scan=chain; scan; scan=scan->next)
324 - scan->handle_info(info);
328 - // no WaitProc for the pid. Probably the process died too fast,
329 - // but next waitpid should take care of it.
330 + ProcWait *w=all_proc.lookup(proc_key(pp));
331 + if(w && w->handle_info(info))
335 void ProcWait::Signal(bool yes)
336 @@ -156,6 +148,6 @@ void ProcWait::Signal(bool yes)
337 void ProcWait::DeleteAll()
340 - for(ProcWait *scan=chain; scan; scan=scan->next)
342 + for(ProcWait *w=all_proc.each_begin(); w; w=all_proc.each_next())
345 diff --git a/src/ProcWait.h b/src/ProcWait.h
346 index d6f0bad..651bc21 100644
350 #include <sys/types.h>
355 class ProcWait : public SMTask
357 @@ -35,10 +36,10 @@ public:
361 - static ProcWait *chain;
363 + static xmap<ProcWait*> all_proc;
364 + static const xstring& proc_key(pid_t p); // make key for xmap
371 diff --git a/src/Ref.h b/src/Ref.h
372 index 8731089..c96ee96 100644
375 @@ -51,4 +51,22 @@ public:
377 template<typename T> const Ref<T> Ref<T>::null;
379 +template<typename T> class RefToArray : public Ref<T>
381 + RefToArray<T>(const RefToArray<T>&); // disable cloning
382 + void operator=(const RefToArray<T>&); // and assignment
386 + RefToArray<T>(T *p) : Ref<T>(p) {}
387 + ~RefToArray<T>() { delete[] Ref<T>::ptr; Ref<T>::ptr=0; }
388 + void operator=(T *p) { delete[] Ref<T>::ptr; Ref<T>::ptr=p; }
389 + T& operator[](unsigned i) const { return Ref<T>::ptr[i]; }
391 + static const RefToArray<T> null;
394 +template<typename T> const RefToArray<T> RefToArray<T>::null;
398 diff --git a/src/SFtp.cc b/src/SFtp.cc
399 index 8e6d0d5..3225701 100644
402 @@ -915,11 +915,7 @@ void SFtp::HandleExpect(Expect *e)
403 for(int i=0; i<r->GetCount(); i++)
405 const NameAttrs *a=r->GetNameAttrs(i);
407 - file_set=new FileSet;
408 FileInfo *info=MakeFileInfo(a);
410 - file_set->Add(info);
413 file_buf->Put(a->name);
414 @@ -941,6 +937,12 @@ void SFtp::HandleExpect(Expect *e)
421 + file_set=new FileSet;
422 + file_set->Add(info);
427 diff --git a/src/Torrent.cc b/src/Torrent.cc
428 index ffe6433..270bbd6 100644
431 @@ -278,6 +278,10 @@ Torrent::Torrent(const char *mf,const char *c,const char *od)
432 dht_announce_timer.Stop();
439 bool Torrent::TrackersDone() const
441 if(shutting_down && shutting_down_timer.Stopped())
442 @@ -318,6 +322,8 @@ void Torrent::PrepareToDie()
444 if(GetTorrentsCount()==0) {
451 @@ -348,9 +354,7 @@ double Torrent::GetRatio() const
453 void Torrent::SetDownloader(unsigned piece,unsigned block,const TorrentPeer *o,const TorrentPeer *n)
455 - const TorrentPeer*& downloader=piece_info[piece]->downloader[block];
458 + piece_info[piece].set_downloader(block,o,n,BlocksInPiece(piece));
461 BeNode *Torrent::Lookup(xmap_p<BeNode>& dict,const char *name,BeNode::be_type_t type)
462 @@ -421,25 +425,18 @@ void Torrent::ValidatePiece(unsigned p)
464 my_bitfield->set_bit(p,0);
466 - piece_info[p]->block_map.clear();
467 + SetBlocksAbsent(p);
469 LogNote(11,"piece %u ok",p);
470 if(!my_bitfield->get_bit(p)) {
471 total_left-=PieceLength(p);
473 my_bitfield->set_bit(p,1);
474 + piece_info[p].free_block_map();
479 -bool TorrentPiece::has_a_downloader() const
481 - for(int i=0; i<downloader.count(); i++)
488 static inline int cmp(T a,T b)
490 @@ -453,8 +450,8 @@ static inline int cmp(T a,T b)
491 static Torrent *cmp_torrent;
492 int Torrent::PiecesNeededCmp(const unsigned *a,const unsigned *b)
494 - int ra=cmp_torrent->piece_info[*a]->sources_count;
495 - int rb=cmp_torrent->piece_info[*b]->sources_count;
496 + int ra=cmp_torrent->piece_info[*a].get_sources_count();
497 + int rb=cmp_torrent->piece_info[*b].get_sources_count();
501 @@ -721,7 +718,7 @@ void Torrent::SetMetadata(const xstring& md)
504 BeNode *b_piece_length=Lookup(info,"piece length",BeNode::BE_INT);
505 - if(!b_piece_length)
506 + if(!b_piece_length || b_piece_length->num<1024 || b_piece_length->num>INT_MAX/4)
508 piece_length=b_piece_length->num;
509 LogNote(4,"Piece length is %u",piece_length);
510 @@ -744,7 +741,7 @@ void Torrent::SetMetadata(const xstring& md)
513 BeNode *length=Lookup(info,"length",BeNode::BE_INT);
515 + if(!length || length->num<0)
517 total_length=length->num;
519 @@ -764,9 +761,12 @@ void Torrent::SetMetadata(const xstring& md)
521 if(!Lookup(files->list[i]->dict,"path",BeNode::BE_LIST))
525 total_length+=f->num;
528 + this->files=new TorrentFiles(files,this);
529 LogNote(4,"Total length is %llu",total_length);
530 total_left=total_length;
532 @@ -800,16 +800,18 @@ void Torrent::SetMetadata(const xstring& md)
535 my_bitfield=new BitField(total_pieces);
536 - for(unsigned p=0; p<total_pieces; p++)
537 - piece_info.append(new TorrentPiece(BlocksInPiece(p)));
539 + blocks_in_piece=(piece_length+BLOCK_SIZE-1)/BLOCK_SIZE;
540 + blocks_in_last_piece=(last_piece_length+BLOCK_SIZE-1)/BLOCK_SIZE;
542 + piece_info=new TorrentPiece[total_pieces]();
549 - for(unsigned i=0; i<total_pieces; i++)
550 - my_bitfield->set_bit(i,1);
551 + my_bitfield->set_range(0,total_pieces,1);
552 complete_pieces=total_pieces;
555 @@ -927,7 +929,7 @@ void Torrent::CalcPiecesStats()
556 for(unsigned i=0; i<total_pieces; i++) {
557 if(my_bitfield->get_bit(i))
559 - unsigned sc=piece_info[i]->sources_count;
560 + unsigned sc=piece_info[i].get_sources_count();
561 if(min_piece_sources>sc)
562 min_piece_sources=sc;
564 @@ -945,12 +947,13 @@ void Torrent::RebuildPiecesNeeded()
565 bool enter_end_game=true;
566 for(unsigned i=0; i<total_pieces; i++) {
567 if(!my_bitfield->get_bit(i)) {
568 - if(!piece_info[i]->has_a_downloader())
569 + if(!piece_info[i].has_a_downloader())
570 enter_end_game=false;
571 - if(piece_info[i]->sources_count==0)
572 + if(piece_info[i].has_no_sources())
574 pieces_needed.append(i);
576 + piece_info[i].cleanup();
578 if(!end_game && enter_end_game) {
579 LogNote(1,"entering End Game mode");
580 @@ -1084,6 +1087,8 @@ int Torrent::Do()
581 a.sa.sa_family=AF_INET6;
582 if(inet_pton(AF_INET6,b_ip->str,&a.in6.sin6_addr)<=0)
584 + if(b_port->num<=0 || b_port->num>=0x10000)
586 a.set_port(b_port->num);
587 dht_ipv6->SendPing(a);
589 @@ -1092,6 +1097,8 @@ int Torrent::Do()
590 a.sa.sa_family=AF_INET;
591 if(!inet_aton(b_ip->str,&a.in.sin_addr))
593 + if(b_port->num<=0 || b_port->num>=0x10000)
595 a.set_port(b_port->num);
598 @@ -1249,24 +1256,51 @@ const char *Torrent::MakePath(BeNode *p) const
600 const char *Torrent::FindFileByPosition(unsigned piece,unsigned begin,off_t *f_pos,off_t *f_tail) const
602 - const BeNode *files=info->lookup("files",BeNode::BE_LIST);
603 off_t target_pos=(off_t)piece*piece_length+begin;
604 + TorrentFile *file=files->FindByPosition(target_pos);
608 + *f_pos=target_pos-file->pos;
609 + *f_tail=file->length-*f_pos;
614 +TorrentFiles::TorrentFiles(const BeNode *files,const Torrent *t)
618 - *f_tail=total_length-target_pos;
622 + file(0)->set(t->GetName(),0,t->TotalLength());
624 + int count=files->list.length();
628 - for(int i=0; i<files->list.length(); i++) {
629 - off_t file_length=files->list[i]->lookup_int("length");
630 - if(scan_pos<=target_pos && scan_pos+file_length>target_pos) {
631 - *f_pos=target_pos-scan_pos;
632 - *f_tail=file_length-*f_pos;
633 - return MakePath(files->list[i]);
635 + for(int i=0; i<count; i++) {
636 + BeNode *node=files->list[i];
637 + off_t file_length=node->lookup_int("length");
638 + file(i)->set(t->MakePath(node),scan_pos,file_length);
639 scan_pos+=file_length;
644 +TorrentFile *TorrentFiles::FindByPosition(off_t pos)
649 + // invariant: the target element is in the range [i,j]
651 + if(file(m)->contains_pos(pos))
653 + if(file(m)->pos>pos)
661 @@ -1485,9 +1519,9 @@ void Torrent::StoreBlock(unsigned piece,unsigned begin,unsigned len,const char *
665 - piece_info[piece]->block_map.set_bit(b++,1);
666 + SetBlockPresent(piece,b++);
668 - if(piece_info[piece]->block_map.has_all_set() && !my_bitfield->get_bit(piece)) {
669 + if(AllBlocksPresent(piece) && !my_bitfield->get_bit(piece)) {
670 ValidatePiece(piece);
671 if(!my_bitfield->get_bit(piece)) {
672 LogError(0,"new piece %u digest mismatch",piece);
673 @@ -2021,12 +2055,12 @@ int TorrentPeer::SendDataRequests(unsigned p)
674 unsigned blocks=parent->BlocksInPiece(p);
675 unsigned bytes_allowed=BytesAllowed(RateLimit::GET);
676 for(unsigned b=0; b<blocks; b++) {
677 - if(parent->piece_info[p]->block_map.get_bit(b))
678 + if(parent->BlockPresent(p,b))
680 - if(parent->piece_info[p]->downloader[b]) {
681 + if(parent->piece_info[p].downloader_for(b)) {
682 if(!parent->end_game)
684 - if(parent->piece_info[p]->downloader[b]==this)
685 + if(parent->piece_info[p].downloader_for(b)==this)
687 if(FindRequest(p,b*Torrent::BLOCK_SIZE)>=0)
689 @@ -2118,8 +2152,7 @@ void TorrentPeer::SendDataRequests()
690 if(parent->my_bitfield->get_bit(p))
692 // add some randomness, so that different instances don't synchronize
693 - if(!parent->piece_info[p]->block_map.has_any_set()
694 - && random()/13%16==0)
695 + if(parent->AllBlocksAbsent(p) && random()/13%16==0)
697 if(SendDataRequests(p)>0)
699 @@ -2233,7 +2266,7 @@ unsigned TorrentPeer::GetLastPiece() const
700 unsigned p=last_piece;
701 // continue if have any blocks already
702 if(p!=NO_PIECE && !parent->my_bitfield->get_bit(p)
703 - && parent->piece_info[p]->block_map.has_any_set()
704 + && parent->AnyBlocksPresent(p)
705 && peer_bitfield->get_bit(p))
707 p=parent->last_piece;
708 @@ -2302,11 +2335,11 @@ void TorrentPeer::SetPieceHaving(unsigned p,bool have)
709 int diff = (have - peer_bitfield->get_bit(p));
712 - parent->piece_info[p]->sources_count+=diff;
713 + parent->piece_info[p].add_sources_count(diff);
714 peer_complete_pieces+=diff;
715 peer_bitfield->set_bit(p,have);
717 - if(parent->piece_info[p]->sources_count==0)
718 + if(parent->piece_info[p].get_sources_count()==0)
719 parent->SetPieceNotWanted(p);
720 if(have && send_buf && !am_interested && !parent->my_bitfield->get_bit(p)
721 && parent->NeedMoreUploaders()) {
722 @@ -2641,7 +2674,7 @@ void TorrentPeer::HandleExtendedMessage(PacketExtended *pp)
725 BeNode *piece=pp->data->lookup("piece",BeNode::BE_INT);
727 + if(!piece || piece->num<0 || piece->num>=INT_MAX/Torrent::BLOCK_SIZE) {
728 SetError("ut_metadata piece bad or missing");
731 @@ -2692,6 +2725,9 @@ void TorrentPeer::HandleExtendedMessage(PacketExtended *pp)
733 case UT_METADATA_REJECT:
736 + SetError("ut_metadata msg_type invalid value");
739 } else if(pp->code==MSG_EXT_PEX) {
740 if(!pex.recv_timer.Stopped())
741 @@ -3322,14 +3358,16 @@ bool BitField::has_all_set(int from,int to) const {
746 +void BitField::set_range(int from,int to,bool value) {
747 + for(int i=from; i<to; i++)
751 void TorrentBlackList::check_expire()
753 for(Timer *e=bl.each_begin(); e; e=bl.each_next()) {
755 Log::global->Format(4,"---- black-delisting peer %s\n",bl.each_key().get());
757 bl.remove(bl.each_key());
760 diff --git a/src/Torrent.h b/src/Torrent.h
761 index a9943c6..ef5d75c 100644
764 @@ -53,20 +53,105 @@ public:
765 int get_bit_length() const { return bit_length; }
766 void set_bit_length(int b) { bit_length=b; set_length((b+7)/8); }
767 void clear() { memset(buf,0,length()); }
768 + void set_range(int from,int to,bool value);
774 unsigned sources_count; // how many peers have the piece
775 + unsigned downloader_count; // how many downloaders of the piece are there
776 + RefToArray<const TorrentPeer*> downloader; // which peers download the blocks
777 + Ref<BitField> block_map; // which blocks are present.
779 - BitField block_map; // which blocks are present
780 - xarray<const TorrentPeer*> downloader; // which peers download the blocks
782 + TorrentPiece() : sources_count(0), downloader_count(0) {}
785 + unsigned get_sources_count() const { return sources_count; }
786 + void add_sources_count(int diff) { sources_count+=diff; }
787 + bool has_no_sources() const { return sources_count==0; }
789 + bool has_a_downloader() const { return downloader_count>0; }
790 + void set_downloader(unsigned block,const TorrentPeer *o,const TorrentPeer *n,unsigned blk_count) {
794 + downloader=new const TorrentPeer*[blk_count]();
796 + const TorrentPeer*& d=downloader[block];
799 + downloader_count+=(n!=0)-(o!=0);
803 + if(downloader_count==0 && downloader)
806 + const TorrentPeer *downloader_for(unsigned block) {
807 + return downloader ? downloader[block] : 0;
810 - TorrentPiece(unsigned b)
811 - : sources_count(0), block_map(b)
812 - { downloader.allocate(b,0); }
813 + void set_block_present(unsigned block,unsigned blk_count) {
815 + block_map=new BitField(blk_count);
816 + block_map->set_bit(block,1);
818 + void set_blocks_absent() {
821 + void free_block_map() {
824 + bool block_present(unsigned block) const {
825 + return block_map && block_map->get_bit(block);
827 + bool all_blocks_present(unsigned blk_count) const {
828 + return block_map && block_map->has_all_set(0,blk_count);
830 + bool any_blocks_present() const {
831 + return block_map; // it's allocated when setting any bit
840 + void set(const char *n,off_t p,off_t l) {
846 + xfree(path); path=0;
848 + bool contains_pos(off_t p) const {
849 + return p>=pos && p<pos+length;
853 - bool has_a_downloader() const;
854 +class TorrentFiles : public xarray<TorrentFile>
856 + static int pos_cmp(const TorrentFile *a, const TorrentFile *b) {
857 + if(a->pos < b->pos)
859 + if(a->pos > b->pos)
861 + // we want zero-sized files to placed before non-zero ones.
862 + if(a->length != b->length)
863 + return a->length < b->length ? -1 : 1;
867 + TorrentFile *file(int i) { return get_non_const()+i; }
868 + TorrentFiles(const BeNode *f_node,const Torrent *t);
870 + for(int i=0; i<length(); i++)
873 + TorrentFile *FindByPosition(off_t p);
876 class TorrentListener : public SMTask, protected ProtoLog, protected Networker
877 @@ -99,6 +184,7 @@ class Torrent : public SMTask, protected ProtoLog, public ResClient
878 friend class TorrentPeer;
879 friend class TorrentDispatcher;
880 friend class TorrentListener;
881 + friend class TorrentFiles;
885 @@ -171,6 +257,7 @@ class Torrent : public SMTask, protected ProtoLog, public ResClient
887 const xstring *pieces;
889 + Ref<TorrentFiles> files;
891 Ref<DirectedBuffer> recv_translate;
892 Ref<DirectedBuffer> recv_translate_utf8;
893 @@ -214,11 +301,32 @@ class Torrent : public SMTask, protected ProtoLog, public ResClient
894 BeNode *Lookup(Ref<BeNode>& d,const char *name,BeNode::be_type_t type) { return Lookup(d->dict,name,type); }
896 TaskRefArray<TorrentPeer> peers;
897 - RefArray<TorrentPiece> piece_info;
898 static int PeersCompareActivity(const SMTaskRef<TorrentPeer> *p1,const SMTaskRef<TorrentPeer> *p2);
899 static int PeersCompareRecvRate(const SMTaskRef<TorrentPeer> *p1,const SMTaskRef<TorrentPeer> *p2);
900 static int PeersCompareSendRate(const SMTaskRef<TorrentPeer> *p1,const SMTaskRef<TorrentPeer> *p2);
902 + RefToArray<TorrentPiece> piece_info;
903 + unsigned blocks_in_piece;
904 + unsigned blocks_in_last_piece;
905 + bool BlockPresent(unsigned piece,unsigned block) const {
906 + return piece_info[piece].block_present(block);
908 + bool AllBlocksPresent(unsigned piece) const {
909 + return piece_info[piece].all_blocks_present(BlocksInPiece(piece));
911 + bool AnyBlocksPresent(unsigned piece) const {
912 + return piece_info[piece].any_blocks_present();
914 + bool AllBlocksAbsent(unsigned piece) const {
915 + return !AnyBlocksPresent(piece);
917 + void SetBlocksAbsent(unsigned piece) {
918 + piece_info[piece].set_blocks_absent();
920 + void SetBlockPresent(unsigned piece,unsigned block) {
921 + piece_info[piece].set_block_present(block,BlocksInPiece(piece));
924 void RebuildPiecesNeeded();
925 Timer pieces_needed_rebuild_timer;
926 xarray<unsigned> pieces_needed;
927 @@ -296,6 +404,7 @@ public:
928 static void ClassInit();
930 Torrent(const char *mf,const char *cwd,const char *output_dir);
935 @@ -315,7 +424,7 @@ public:
936 static void SHA1(const xstring& str,xstring& buf);
937 void ValidatePiece(unsigned p);
938 unsigned PieceLength(unsigned p) const { return p==total_pieces-1 ? last_piece_length : piece_length; }
939 - unsigned BlocksInPiece(unsigned p) const { return (PieceLength(p)+BLOCK_SIZE-1)/BLOCK_SIZE; }
940 + unsigned BlocksInPiece(unsigned p) const { return p==total_pieces-1 ? blocks_in_last_piece : blocks_in_piece; }
942 const TaskRefArray<TorrentPeer>& GetPeers() const { return peers; }
943 void AddPeer(TorrentPeer *);
944 @@ -772,7 +881,7 @@ public:
946 class TorrentBlackList
952 bool Listed(const sockaddr_u &a);
953 diff --git a/src/resource.cc b/src/resource.cc
954 index 4aa071a..e4707e7 100644
955 --- a/src/resource.cc
956 +++ b/src/resource.cc
957 @@ -57,13 +57,39 @@ static const char *FtpProxyValidate(xstring_c *p)
961 +static const char *SetValidate(xstring_c& s,const char *const *set,const char *name)
963 + const char *const *scan;
964 + for(scan=set; *scan; scan++)
968 + xstring &j=xstring::get_tmp();
970 + j.setf(_("%s must be one of: "),name);
972 + j.set(_("must be one of: "));
973 + bool had_empty=false;
974 + for(scan=set; *scan; scan++) {
984 + j.append(_(", or empty"));
988 static const char *FtpProxyAuthTypeValidate(xstring_c *s)
990 - if(s->ne("user") && s->ne("joined") && s->ne("joined-acct")
991 - && s->ne("open") && s->ne("proxy-user@host"))
992 - // for translator: `user', `joined', `joined-acct', `open' are literals.
993 - return _("ftp:proxy-auth-type must be one of: user, joined, joined-acct, open, proxy-user@host");
995 + static const char *const valid_set[]={
996 + "user", "joined", "joined-acct", "open", "proxy-user@host", 0
998 + return SetValidate(*s,valid_set,"ftp:proxy-auth-type");
1001 static const char *HttpProxyValidate(xstring_c *p)
1002 @@ -130,6 +156,14 @@ const char *OrderValidate(xstring_c *s)
1006 +static const char *SortByValidate(xstring_c *s)
1008 + static const char * const valid_set[]={
1009 + "name", "name-desc", "size", "size-desc", "date", "date-desc", 0
1011 + return SetValidate(*s,valid_set,"mirror:order-by");
1016 const char *AuthArgValidate(xstring_c *s)
1017 @@ -137,30 +171,21 @@ const char *AuthArgValidate(xstring_c *s)
1018 for(char *i=s->get_non_const(); *i; i++)
1019 *i=to_ascii_upper(*i);
1021 - if(strcmp(*s,"SSL")
1022 - && strcmp(*s,"TLS")
1023 - && strcmp(*s,"TLS-P")
1024 - && strcmp(*s,"TLS-C"))
1025 - return _("ftp:ssl-auth must be one of: SSL, TLS, TLS-P, TLS-C");
1028 + const char *const valid_set[]={
1029 + "SSL", "TLS", "TLS-P", "TLS-C", 0
1031 + return SetValidate(*s,valid_set,"ftp:ssl-auth");
1034 const char *ProtValidate(xstring_c *s)
1039 for(char *i=s->get_non_const(); *i; i++)
1040 *i=to_ascii_upper(*i);
1045 - && strcmp(*s,"E"))
1046 - return _("must be one of: C, S, E, P, or empty");
1049 + const char *const valid_set[]={
1050 + "C", "S", "E", "P", "", 0
1052 + return SetValidate(*s,valid_set,"ftps:initial-prot");
1056 @@ -300,6 +325,7 @@ static ResType lftp_vars[] = {
1057 {"net:connection-limit", "0", ResMgr::UNumberValidate,0},
1058 {"net:connection-takeover", "yes", ResMgr::BoolValidate,0},
1060 + {"mirror:sort-by", "name", SortByValidate,ResMgr::NoClosure},
1061 {"mirror:order", "*.sfv *.sig *.md5* *.sum * */", 0,ResMgr::NoClosure},
1062 {"mirror:parallel-directories", "yes", ResMgr::BoolValidate,ResMgr::NoClosure},
1063 {"mirror:parallel-transfer-count", "1",ResMgr::UNumberValidate,ResMgr::NoClosure},
1064 diff --git a/src/xmap.cc b/src/xmap.cc
1065 index 4bc9a86..2276bce 100644
1068 @@ -136,6 +136,7 @@ void _xmap::_remove(entry **ep)
1076 diff --git a/src/xstring.h b/src/xstring.h
1077 index 264baf6..4a284ee 100644
1080 @@ -222,7 +222,8 @@ public:
1081 static xstring& cat(const char *first,...) ATTRIBUTE_SENTINEL;
1082 static xstring& join(const char *sep,int n,...);
1084 - void truncate(size_t n=0);
1085 + void truncate() { set_length(0); }
1086 + void truncate(size_t n);
1087 void truncate_at(char c);
1088 /* set_length can be used to extend the string, e.g. after modification
1089 with get_space+get_non_const. */