]> git.pld-linux.org Git - packages/lftp.git/blob - lftp-git.patch
- rel 2; fixes bug 121 (ls "with spaces")
[packages/lftp.git] / lftp-git.patch
1 diff --git a/doc/lftp.1 b/doc/lftp.1
2 index 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
23 diff --git a/po/pl.po b/po/pl.po
24 index 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"
137 diff --git a/src/FileSet.cc b/src/FileSet.cc
138 index 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()
163 diff --git a/src/FileSet.h b/src/FileSet.h
164 index 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();
175 diff --git a/src/Fish.cc b/src/Fish.cc
176 index 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  
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)
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  
252 diff --git a/src/PollVec.cc b/src/PollVec.cc
253 index 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  
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
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  }
345 diff --git a/src/ProcWait.h b/src/ProcWait.h
346 index 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;
371 diff --git a/src/Ref.h b/src/Ref.h
372 index 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
398 diff --git a/src/SFtp.cc b/src/SFtp.cc
399 index 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;
427 diff --git a/src/Torrent.cc b/src/Torrent.cc
428 index 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     }
760 diff --git a/src/Torrent.h b/src/Torrent.h
761 index 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);
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)
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},
1064 diff --git a/src/xmap.cc b/src/xmap.cc
1065 index 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--;
1076 diff --git a/src/xstring.h b/src/xstring.h
1077 index 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.135875 seconds and 3 git commands to generate.