]> git.pld-linux.org Git - packages/lftp.git/blame - lftp-git.patch
- updated pl.po-update patch
[packages/lftp.git] / lftp-git.patch
CommitLineData
93dfd0ea
AM
1diff --git a/doc/lftp.1 b/doc/lftp.1
2index d5d408f..9222795 100644
3--- a/doc/lftp.1
4+++ b/doc/lftp.1
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).
8 .TP
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.
13+.TP
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.
20 .TP
21 .BR mirror:parallel-directories " (boolean)"
22 if true, mirror will start processing of several directories in parallel
23diff --git a/po/pl.po b/po/pl.po
24index d569428..89e8b11 100644
25--- a/po/pl.po
26+++ b/po/pl.po
27@@ -7,10 +7,10 @@
28 #
29 msgid ""
30 msgstr ""
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"
39 "Language: pl\n"
40@@ -1152,12 +1152,10 @@ msgstr ""
41 "uczyni dopełnianie nazw plików nie rozpoznającym wielkości liter.\n"
42
43 #: src/commands.cc:216
44-#, fuzzy
45 msgid "debug [OPTS] [<level>|off]"
46-msgstr "debug [<poziom>|off] [-o <plik>]"
47+msgstr "debug [OPCJE] [<poziom>|off]"
48
49 #: src/commands.cc:217
50-#, fuzzy
51 msgid ""
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 ""
55 " -p show PID\n"
56 " -t show timestamps\n"
57 msgstr ""
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"
63+" -p wypisuj PID\n"
64+" -t wypisuj znaczniki czasu\n"
65
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"
70
71 #: src/commands.cc:339
72-#, fuzzy
73 msgid "mkdir [OPTS] <dirs>"
74-msgstr "mkdir [-p] <katalogi>"
75+msgstr "mkdir [OPCJE] <katalogi>"
76
77 #: src/commands.cc:340
78-#, fuzzy
79 msgid ""
80 "Make remote directories\n"
81 " -p make all levels of path\n"
82@@ -1490,6 +1489,7 @@ msgid ""
83 msgstr ""
84 "Utwórz zdalne katalogi\n"
85 " -p tworzy wszystkie poziomy ścieżki\n"
86+" -f ciche działanie, bez komunikatów\n"
87
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"
92
93 #: src/ftpclass.cc:2133 src/ftpclass.cc:2228
94-#, fuzzy, c-format
95+#, c-format
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"
99
100 #: src/ftpclass.cc:2161
101 #, c-format
102@@ -2700,13 +2700,12 @@ msgid "peer unexpectedly closed connection after %s"
103 msgstr "druga strona nieoczekiwanie zamknęła połączenie po %s"
104
105 #: src/Torrent.cc:2903 src/Torrent.cc:3020
106-#, fuzzy
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"
110
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)"
115
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
120 #, c-format
121 msgid "peer sent unknown info_hash=%s in handshake"
122-msgstr ""
123+msgstr "druga strona wysłała nieznane info_hash=%s przy przywitaniu"
124
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ą"
129
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"
134
135 #: src/Torrent.cc:3590
136 msgid "peer closed just accepted connection"
137diff --git a/src/FileSet.cc b/src/FileSet.cc
138index 389578a..6380a68 100644
139--- a/src/FileSet.cc
140+++ b/src/FileSet.cc
141@@ -232,6 +232,21 @@ void FileSet::Sort(sort_e newsort, bool casefold, bool reverse)
142 }
143 }
144
145+// reverse current sort order
146+void FileSet::ReverseSort()
147+{
148+ if(!sorted) {
149+ Sort(BYNAME,false,true);
150+ return;
151+ }
152+ int i=0;
153+ int j=sorted.length()-1;
154+ while(i<j) {
155+ sorted[i]=replace_value(sorted[j],sorted[i]);
156+ ++i,--j;
157+ }
158+}
159+
160 /* Remove the current sort, allowing new entries to be added.
161 * (Nothing uses this ... */
162 void FileSet::Unsort()
163diff --git a/src/FileSet.h b/src/FileSet.h
164index 7c3ac2a..155536f 100644
165--- a/src/FileSet.h
166+++ b/src/FileSet.h
167@@ -180,6 +180,7 @@ public:
168 void Sort(sort_e newsort, bool casefold=false, bool reverse=false);
169 void Unsort();
170 void SortByPatternList(const char *list_c);
171+ void ReverseSort();
172
173 void Exclude(const char *prefix,const PatternSet *x);
174 void ExcludeDots();
175diff --git a/src/Fish.cc b/src/Fish.cc
176index d172a20..29ba4c6 100644
177--- a/src/Fish.cc
178+++ b/src/Fish.cc
179@@ -98,6 +98,15 @@ int Fish::Do()
180 timeout_timer.Reset(send_buf->EventTime());
181 if(recv_buf)
182 timeout_timer.Reset(recv_buf->EventTime());
183+ if(pty_send_buf)
184+ timeout_timer.Reset(pty_send_buf->EventTime());
185+ if(pty_recv_buf)
186+ timeout_timer.Reset(pty_recv_buf->EventTime());
187+
188+ // check for timeout only if there should be connection activity.
189+ if(state!=DISCONNECTED && (state!=CONNECTED || !RespQueueIsEmpty())
190+ && mode!=CLOSED && CheckTimeout())
191+ return MOVED;
192
193 if((state==FILE_RECV || state==FILE_SEND)
194 && rate_limit==0)
195@@ -275,14 +284,6 @@ int Fish::Do()
196 case DONE:
197 break;
198 }
199- if(m==MOVED)
200- return MOVED;
201- if(send_buf)
202- timeout_timer.Reset(send_buf->EventTime());
203- if(recv_buf)
204- timeout_timer.Reset(recv_buf->EventTime());
205- if(CheckTimeout())
206- return MOVED;
207 return m;
208 }
209
210diff --git a/src/MirrorJob.cc b/src/MirrorJob.cc
211index 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)
215 if(!(flags&DELETE))
216 to_transfer->SubtractAny(to_rm_mismatched);
217
218- to_transfer->SortByPatternList(ResMgr::Query("mirror:order",0));
219- to_transfer->CountBytes(&bytes_to_transfer);
220- if(parent_mirror)
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);
230+ if(desc)
231+ to_transfer->ReverseSort();
232
233 int dir_count=0;
234 to_transfer->Count(&dir_count,NULL,NULL,NULL);
235@@ -851,10 +857,16 @@ int MirrorJob::Do()
236 stats.dirs++;
237
238 InitSets(source_set,target_set);
239+
240+ to_transfer->CountBytes(&bytes_to_transfer);
241+ if(parent_mirror)
242+ parent_mirror->AddBytesToTransfer(bytes_to_transfer);
243+
244 to_rm->Count(&stats.del_dirs,&stats.del_files,&stats.del_symlinks,&stats.del_files);
245 to_rm->rewind();
246 to_rm_mismatched->Count(&stats.del_dirs,&stats.del_files,&stats.del_symlinks,&stats.del_files);
247 to_rm_mismatched->rewind();
248+
249 set_state(TARGET_REMOVE_OLD_FIRST);
250 goto TARGET_REMOVE_OLD_FIRST_label;
251
252diff --git a/src/PollVec.cc b/src/PollVec.cc
253index a18b517..e1d72fb 100644
254--- a/src/PollVec.cc
255+++ b/src/PollVec.cc
256@@ -31,7 +31,7 @@ static inline bool operator<(const timeval& a,const timeval& b)
257 void PollVec::AddTimeoutU(unsigned t)
258 {
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);
263 }
264
265diff --git a/src/ProcWait.cc b/src/ProcWait.cc
266index 0a065ad..d3dfec4 100644
267--- a/src/ProcWait.cc
268+++ b/src/ProcWait.cc
269@@ -24,7 +24,14 @@
270 #include "ProcWait.h"
271 #include "SignalHook.h"
272
273-ProcWait *ProcWait::chain=0;
274+xmap<ProcWait*> ProcWait::all_proc;
275+
276+const xstring& ProcWait::proc_key(pid_t p)
277+{
278+ static xstring tmp_key;
279+ tmp_key.nset((const char*)&p,sizeof(p));
280+ return tmp_key;
281+}
282
283 int ProcWait::Do()
284 {
285@@ -100,27 +107,19 @@ int ProcWait::Kill(int sig)
286 }
287
288 ProcWait::ProcWait(pid_t p)
289+ : pid(p)
290 {
291 auto_die=false;
292- pid=p;
293 status=RUNNING;
294 term_info=-1;
295 saved_errno=0;
296
297- next=chain;
298- chain=this;
299+ all_proc.add(proc_key(pid),this);
300 }
301
302 ProcWait::~ProcWait()
303 {
304- for(ProcWait **scan=&chain; *scan; scan=&(*scan)->next)
305- {
306- if(*scan==this)
307- {
308- *scan=next;
309- return;
310- }
311- }
312+ all_proc.remove(proc_key(pid));
313 }
314
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);
318 if(pp==-1)
319 return;
320- for(ProcWait *scan=chain; scan; scan=scan->next)
321- {
322- if(scan->pid==pp)
323- {
324- scan->handle_info(info);
325- return;
326- }
327- }
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))
332+ w->Timeout(0);
333 }
334
335 void ProcWait::Signal(bool yes)
336@@ -156,6 +148,6 @@ void ProcWait::Signal(bool yes)
337 void ProcWait::DeleteAll()
338 {
339 Signal(false);
340- for(ProcWait *scan=chain; scan; scan=scan->next)
341- Delete(scan);
342+ for(ProcWait *w=all_proc.each_begin(); w; w=all_proc.each_next())
343+ Delete(w);
344 }
345diff --git a/src/ProcWait.h b/src/ProcWait.h
346index d6f0bad..651bc21 100644
347--- a/src/ProcWait.h
348+++ b/src/ProcWait.h
349@@ -23,6 +23,7 @@
350 #include <sys/types.h>
351 #include <signal.h>
352 #include "SMTask.h"
353+#include "xmap.h"
354
355 class ProcWait : public SMTask
356 {
357@@ -35,10 +36,10 @@ public:
358 };
359
360 protected:
361- static ProcWait *chain;
362- ProcWait *next;
363+ static xmap<ProcWait*> all_proc;
364+ static const xstring& proc_key(pid_t p); // make key for xmap
365
366- pid_t pid;
367+ const pid_t pid;
368 State status;
369 int term_info;
370 int saved_errno;
371diff --git a/src/Ref.h b/src/Ref.h
372index 8731089..c96ee96 100644
373--- a/src/Ref.h
374+++ b/src/Ref.h
375@@ -51,4 +51,22 @@ public:
376
377 template<typename T> const Ref<T> Ref<T>::null;
378
379+template<typename T> class RefToArray : public Ref<T>
380+{
381+ RefToArray<T>(const RefToArray<T>&); // disable cloning
382+ void operator=(const RefToArray<T>&); // and assignment
383+
384+public:
385+ RefToArray<T>() {}
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]; }
390+
391+ static const RefToArray<T> null;
392+};
393+
394+template<typename T> const RefToArray<T> RefToArray<T>::null;
395+
396+
397 #endif
398diff --git a/src/SFtp.cc b/src/SFtp.cc
399index 8e6d0d5..3225701 100644
400--- a/src/SFtp.cc
401+++ b/src/SFtp.cc
402@@ -915,11 +915,7 @@ void SFtp::HandleExpect(Expect *e)
403 for(int i=0; i<r->GetCount(); i++)
404 {
405 const NameAttrs *a=r->GetNameAttrs(i);
406- if(!file_set)
407- file_set=new FileSet;
408 FileInfo *info=MakeFileInfo(a);
409- if(info)
410- file_set->Add(info);
411 if(mode==LIST)
412 {
413 file_buf->Put(a->name);
414@@ -941,6 +937,12 @@ void SFtp::HandleExpect(Expect *e)
415 file_buf->Put("\n");
416 }
417 }
418+ if(info)
419+ {
420+ if(!file_set)
421+ file_set=new FileSet;
422+ file_set->Add(info);
423+ }
424 }
425 if(r->Eof())
426 goto eof;
427diff --git a/src/Torrent.cc b/src/Torrent.cc
428index ffe6433..270bbd6 100644
429--- a/src/Torrent.cc
430+++ b/src/Torrent.cc
431@@ -278,6 +278,10 @@ Torrent::Torrent(const char *mf,const char *c,const char *od)
432 dht_announce_timer.Stop();
433 }
434
435+Torrent::~Torrent()
436+{
437+}
438+
439 bool Torrent::TrackersDone() const
440 {
441 if(shutting_down && shutting_down_timer.Stopped())
442@@ -318,6 +322,8 @@ void Torrent::PrepareToDie()
443 RemoveTorrent(this);
444 if(GetTorrentsCount()==0) {
445 StopListener();
446+ StopDHT();
447+ StopListenerUDP();
448 fd_cache=0;
449 black_list=0;
450 }
451@@ -348,9 +354,7 @@ double Torrent::GetRatio() const
452
453 void Torrent::SetDownloader(unsigned piece,unsigned block,const TorrentPeer *o,const TorrentPeer *n)
454 {
455- const TorrentPeer*& downloader=piece_info[piece]->downloader[block];
456- if(downloader==o)
457- downloader=n;
458+ piece_info[piece].set_downloader(block,o,n,BlocksInPiece(piece));
459 }
460
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)
463 complete_pieces--;
464 my_bitfield->set_bit(p,0);
465 }
466- piece_info[p]->block_map.clear();
467+ SetBlocksAbsent(p);
468 } else {
469 LogNote(11,"piece %u ok",p);
470 if(!my_bitfield->get_bit(p)) {
471 total_left-=PieceLength(p);
472 complete_pieces++;
473 my_bitfield->set_bit(p,1);
474+ piece_info[p].free_block_map();
475 }
476 }
477 }
478
479-bool TorrentPiece::has_a_downloader() const
480-{
481- for(int i=0; i<downloader.count(); i++)
482- if(downloader[i])
483- return true;
484- return false;
485-}
486-
487 template<typename T>
488 static inline int cmp(T a,T b)
489 {
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)
493 {
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();
498 int c=cmp(ra,rb);
499 if(c) return c;
500 return cmp(*a,*b);
501@@ -721,7 +718,7 @@ void Torrent::SetMetadata(const xstring& md)
502 }
503
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)
507 return;
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)
511 if(!files) {
512 single_file=true;
513 BeNode *length=Lookup(info,"length",BeNode::BE_INT);
514- if(!length)
515+ if(!length || length->num<0)
516 return;
517 total_length=length->num;
518 } else {
519@@ -764,9 +761,12 @@ void Torrent::SetMetadata(const xstring& md)
520 return;
521 if(!Lookup(files->list[i]->dict,"path",BeNode::BE_LIST))
522 return;
523+ if(f->num<0)
524+ return;
525 total_length+=f->num;
526 }
527 }
528+ this->files=new TorrentFiles(files,this);
529 LogNote(4,"Total length is %llu",total_length);
530 total_left=total_length;
531
532@@ -800,16 +800,18 @@ void Torrent::SetMetadata(const xstring& md)
533 SaveMetadata();
534
535 my_bitfield=new BitField(total_pieces);
536- for(unsigned p=0; p<total_pieces; p++)
537- piece_info.append(new TorrentPiece(BlocksInPiece(p)));
538+
539+ blocks_in_piece=(piece_length+BLOCK_SIZE-1)/BLOCK_SIZE;
540+ blocks_in_last_piece=(last_piece_length+BLOCK_SIZE-1)/BLOCK_SIZE;
541+
542+ piece_info=new TorrentPiece[total_pieces]();
543
544 if(!force_valid) {
545 validate_index=0;
546 validating=true;
547 recv_rate.Reset();
548 } else {
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;
553 total_left=0;
554 complete=true;
555@@ -927,7 +929,7 @@ void Torrent::CalcPiecesStats()
556 for(unsigned i=0; i<total_pieces; i++) {
557 if(my_bitfield->get_bit(i))
558 continue;
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;
563 if(sc==0)
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())
573 continue;
574 pieces_needed.append(i);
575 }
576+ piece_info[i].cleanup();
577 }
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)
583 continue;
584+ if(b_port->num<=0 || b_port->num>=0x10000)
585+ continue;
586 a.set_port(b_port->num);
587 dht_ipv6->SendPing(a);
588 } else
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))
592 continue;
593+ if(b_port->num<=0 || b_port->num>=0x10000)
594+ continue;
595 a.set_port(b_port->num);
596 dht->SendPing(a);
597 }
598@@ -1249,24 +1256,51 @@ const char *Torrent::MakePath(BeNode *p) const
599 }
600 const char *Torrent::FindFileByPosition(unsigned piece,unsigned begin,off_t *f_pos,off_t *f_tail) const
601 {
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);
605+ if(!file)
606+ return 0;
607+
608+ *f_pos=target_pos-file->pos;
609+ *f_tail=file->length-*f_pos;
610+
611+ return file->path;
612+}
613+
614+TorrentFiles::TorrentFiles(const BeNode *files,const Torrent *t)
615+{
616 if(!files) {
617- *f_pos=target_pos;
618- *f_tail=total_length-target_pos;
619- return name;
620+ grow_space(1);
621+ set_length(1);
622+ file(0)->set(t->GetName(),0,t->TotalLength());
623 } else {
624+ int count=files->list.length();
625+ grow_space(count);
626+ set_length(count);
627 off_t scan_pos=0;
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]);
634- }
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;
640 }
641 }
642+ qsort(pos_cmp);
643+}
644+TorrentFile *TorrentFiles::FindByPosition(off_t pos)
645+{
646+ int i=0;
647+ int j=length()-1;
648+ while(i<=j) {
649+ // invariant: the target element is in the range [i,j]
650+ int m=(i+j)/2;
651+ if(file(m)->contains_pos(pos))
652+ return file(m);
653+ if(file(m)->pos>pos)
654+ j=m-1;
655+ else
656+ i=m+1;
657+ }
658 return 0;
659 }
660
661@@ -1485,9 +1519,9 @@ void Torrent::StoreBlock(unsigned piece,unsigned begin,unsigned len,const char *
662 }
663
664 while(bc-->0) {
665- piece_info[piece]->block_map.set_bit(b++,1);
666+ SetBlockPresent(piece,b++);
667 }
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))
679 continue;
680- if(parent->piece_info[p]->downloader[b]) {
681+ if(parent->piece_info[p].downloader_for(b)) {
682 if(!parent->end_game)
683 continue;
684- if(parent->piece_info[p]->downloader[b]==this)
685+ if(parent->piece_info[p].downloader_for(b)==this)
686 continue;
687 if(FindRequest(p,b*Torrent::BLOCK_SIZE)>=0)
688 continue;
689@@ -2118,8 +2152,7 @@ void TorrentPeer::SendDataRequests()
690 if(parent->my_bitfield->get_bit(p))
691 continue;
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)
696 continue;
697 if(SendDataRequests(p)>0)
698 return;
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))
706 return 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));
710 if(!diff)
711 return;
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);
716
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)
723 return;
724 }
725 BeNode *piece=pp->data->lookup("piece",BeNode::BE_INT);
726- if(!piece) {
727+ if(!piece || piece->num<0 || piece->num>=INT_MAX/Torrent::BLOCK_SIZE) {
728 SetError("ut_metadata piece bad or missing");
729 return;
730 }
731@@ -2692,6 +2725,9 @@ void TorrentPeer::HandleExtendedMessage(PacketExtended *pp)
732 }
733 case UT_METADATA_REJECT:
734 break;
735+ default:
736+ SetError("ut_metadata msg_type invalid value");
737+ return;
738 }
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 {
742 return false;
743 return true;
744 }
745-
746+void BitField::set_range(int from,int to,bool value) {
747+ for(int i=from; i<to; i++)
748+ set_bit(i,value);
749+}
750
751 void TorrentBlackList::check_expire()
752 {
753 for(Timer *e=bl.each_begin(); e; e=bl.each_next()) {
754 if(e->Stopped()) {
755 Log::global->Format(4,"---- black-delisting peer %s\n",bl.each_key().get());
756- delete e;
757 bl.remove(bl.each_key());
758 }
759 }
760diff --git a/src/Torrent.h b/src/Torrent.h
761index a9943c6..ef5d75c 100644
762--- a/src/Torrent.h
763+++ b/src/Torrent.h
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);
769 };
770
771-struct TorrentPiece
772+class TorrentPiece
773 {
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.
778
779- BitField block_map; // which blocks are present
780- xarray<const TorrentPeer*> downloader; // which peers download the blocks
781+public:
782+ TorrentPiece() : sources_count(0), downloader_count(0) {}
783+ ~TorrentPiece() {}
784+
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; }
788+
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) {
791+ if(!downloader) {
792+ if(o || !n)
793+ return;
794+ downloader=new const TorrentPeer*[blk_count]();
795+ }
796+ const TorrentPeer*& d=downloader[block];
797+ if(d==o) {
798+ d=n;
799+ downloader_count+=(n!=0)-(o!=0);
800+ }
801+ }
802+ void cleanup() {
803+ if(downloader_count==0 && downloader)
804+ downloader=0;
805+ }
806+ const TorrentPeer *downloader_for(unsigned block) {
807+ return downloader ? downloader[block] : 0;
808+ }
809
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) {
814+ if(!block_map)
815+ block_map=new BitField(blk_count);
816+ block_map->set_bit(block,1);
817+ }
818+ void set_blocks_absent() {
819+ block_map=0;
820+ }
821+ void free_block_map() {
822+ block_map=0;
823+ }
824+ bool block_present(unsigned block) const {
825+ return block_map && block_map->get_bit(block);
826+ }
827+ bool all_blocks_present(unsigned blk_count) const {
828+ return block_map && block_map->has_all_set(0,blk_count);
829+ }
830+ bool any_blocks_present() const {
831+ return block_map; // it's allocated when setting any bit
832+ }
833+};
834+
835+struct TorrentFile
836+{
837+ char *path;
838+ off_t pos;
839+ off_t length;
840+ void set(const char *n,off_t p,off_t l) {
841+ path=xstrdup(n);
842+ pos=p;
843+ length=l;
844+ }
845+ void unset() {
846+ xfree(path); path=0;
847+ }
848+ bool contains_pos(off_t p) const {
849+ return p>=pos && p<pos+length;
850+ }
851+};
852
853- bool has_a_downloader() const;
854+class TorrentFiles : public xarray<TorrentFile>
855+{
856+ static int pos_cmp(const TorrentFile *a, const TorrentFile *b) {
857+ if(a->pos < b->pos)
858+ return -1;
859+ if(a->pos > b->pos)
860+ return 1;
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;
864+ return 0;
865+ }
866+public:
867+ TorrentFile *file(int i) { return get_non_const()+i; }
868+ TorrentFiles(const BeNode *f_node,const Torrent *t);
869+ ~TorrentFiles() {
870+ for(int i=0; i<length(); i++)
871+ file(i)->unset();
872+ }
873+ TorrentFile *FindByPosition(off_t p);
874 };
875
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;
882 friend class DHT;
883
884 bool shutting_down;
885@@ -171,6 +257,7 @@ class Torrent : public SMTask, protected ProtoLog, public ResClient
886 xstring info_hash;
887 const xstring *pieces;
888 xstring name;
889+ Ref<TorrentFiles> files;
890
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); }
895
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);
901
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);
907+ }
908+ bool AllBlocksPresent(unsigned piece) const {
909+ return piece_info[piece].all_blocks_present(BlocksInPiece(piece));
910+ }
911+ bool AnyBlocksPresent(unsigned piece) const {
912+ return piece_info[piece].any_blocks_present();
913+ }
914+ bool AllBlocksAbsent(unsigned piece) const {
915+ return !AnyBlocksPresent(piece);
916+ }
917+ void SetBlocksAbsent(unsigned piece) {
918+ piece_info[piece].set_blocks_absent();
919+ }
920+ void SetBlockPresent(unsigned piece,unsigned block) {
921+ piece_info[piece].set_block_present(block,BlocksInPiece(piece));
922+ }
923+
924 void RebuildPiecesNeeded();
925 Timer pieces_needed_rebuild_timer;
926 xarray<unsigned> pieces_needed;
927@@ -296,6 +404,7 @@ public:
928 static void ClassInit();
929
930 Torrent(const char *mf,const char *cwd,const char *output_dir);
931+ ~Torrent();
932
933 int Do();
934 int Done() const;
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; }
941
942 const TaskRefArray<TorrentPeer>& GetPeers() const { return peers; }
943 void AddPeer(TorrentPeer *);
944@@ -772,7 +881,7 @@ public:
945
946 class TorrentBlackList
947 {
948- xmap<Timer*> bl;
949+ xmap_p<Timer> bl;
950 void check_expire();
951 public:
952 bool Listed(const sockaddr_u &a);
953diff --git a/src/resource.cc b/src/resource.cc
954index 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)
958 return 0;
959 }
960
961+static const char *SetValidate(xstring_c& s,const char *const *set,const char *name)
962+{
963+ const char *const *scan;
964+ for(scan=set; *scan; scan++)
965+ if(s.eq(*scan))
966+ return 0;
967+
968+ xstring &j=xstring::get_tmp();
969+ if(name)
970+ j.setf(_("%s must be one of: "),name);
971+ else
972+ j.set(_("must be one of: "));
973+ bool had_empty=false;
974+ for(scan=set; *scan; scan++) {
975+ if(!**scan) {
976+ had_empty=true;
977+ continue;
978+ }
979+ if(scan>set)
980+ j.append(", ");
981+ j.append(*scan);
982+ }
983+ if(had_empty)
984+ j.append(_(", or empty"));
985+ return j;
986+}
987+
988 static const char *FtpProxyAuthTypeValidate(xstring_c *s)
989 {
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");
994- return 0;
995+ static const char *const valid_set[]={
996+ "user", "joined", "joined-acct", "open", "proxy-user@host", 0
997+ };
998+ return SetValidate(*s,valid_set,"ftp:proxy-auth-type");
999 }
1000
1001 static const char *HttpProxyValidate(xstring_c *p)
1002@@ -130,6 +156,14 @@ const char *OrderValidate(xstring_c *s)
1003 return 0;
1004 }
1005
1006+static const char *SortByValidate(xstring_c *s)
1007+{
1008+ static const char * const valid_set[]={
1009+ "name", "name-desc", "size", "size-desc", "date", "date-desc", 0
1010+ };
1011+ return SetValidate(*s,valid_set,"mirror:order-by");
1012+}
1013+
1014 #if USE_SSL
1015 static
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);
1020
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");
1026-
1027- return 0;
1028+ const char *const valid_set[]={
1029+ "SSL", "TLS", "TLS-P", "TLS-C", 0
1030+ };
1031+ return SetValidate(*s,valid_set,"ftp:ssl-auth");
1032 }
1033 static
1034 const char *ProtValidate(xstring_c *s)
1035 {
1036- if(!**s)
1037- return 0;
1038-
1039 for(char *i=s->get_non_const(); *i; i++)
1040 *i=to_ascii_upper(*i);
1041
1042- if(strcmp(*s,"P")
1043- && strcmp(*s,"C")
1044- && strcmp(*s,"S")
1045- && strcmp(*s,"E"))
1046- return _("must be one of: C, S, E, P, or empty");
1047-
1048- return 0;
1049+ const char *const valid_set[]={
1050+ "C", "S", "E", "P", "", 0
1051+ };
1052+ return SetValidate(*s,valid_set,"ftps:initial-prot");
1053 }
1054 #endif
1055
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},
1059
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},
1064diff --git a/src/xmap.cc b/src/xmap.cc
1065index 4bc9a86..2276bce 100644
1066--- a/src/xmap.cc
1067+++ b/src/xmap.cc
1068@@ -136,6 +136,7 @@ void _xmap::_remove(entry **ep)
1069 if(!ep || !*ep)
1070 return;
1071 entry *e=*ep;
1072+ e->key.unset();
1073 *ep=e->next;
1074 xfree(e);
1075 entry_count--;
1076diff --git a/src/xstring.h b/src/xstring.h
1077index 264baf6..4a284ee 100644
1078--- a/src/xstring.h
1079+++ b/src/xstring.h
1080@@ -222,7 +222,8 @@ public:
1081 static xstring& cat(const char *first,...) ATTRIBUTE_SENTINEL;
1082 static xstring& join(const char *sep,int n,...);
1083
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. */
This page took 0.160617 seconds and 4 git commands to generate.