[packages/lftp] - rel 2; fixes from git
arekm
arekm at pld-linux.org
Wed Aug 6 18:29:02 CEST 2014
commit 93dfd0ea2d63693d69604a96615ee24f639064e8
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date: Wed Aug 6 18:28:59 2014 +0200
- rel 2; fixes from git
lftp-git.patch | 1089 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lftp.spec | 6 +-
2 files changed, 1093 insertions(+), 2 deletions(-)
---
diff --git a/lftp.spec b/lftp.spec
index f24362c..80a4a1c 100644
--- a/lftp.spec
+++ b/lftp.spec
@@ -23,7 +23,7 @@ Summary(pt_BR.UTF-8): Sofisticado programa de transferência de arquivos (client
Summary(zh_CN.UTF-8): lftp 客户端程序
Name: lftp
Version: 4.5.3
-Release: 1
+Release: 2
License: GPL v3+
Group: Applications/Networking
Source0: http://lftp.yar.ru/ftp/%{name}-%{version}.tar.xz
@@ -32,6 +32,7 @@ Source1: http://www.mif.pg.gda.pl/homepages/ankry/man-PLD/%{name}-man-pages.tar.
# Source1-md5: cdad8fb5342eebd9916eccefc98a855b
Source2: %{name}.desktop
Source3: %{name}-icon.png
+Patch100: %{name}-git.patch
Patch0: %{name}-makefile.patch
Patch1: %{name}-m4.patch
Patch2: aliases.patch
@@ -90,10 +91,11 @@ o arquivo FEATURES para uma lista mais detalhada.
%prep
%setup -q
+%patch100 -p1
%patch0 -p1
%patch1 -p1
%patch2 -p1
-%patch3 -p1
+#%patch3 -p1
%patch4 -p1
%patch5 -p1
diff --git a/lftp-git.patch b/lftp-git.patch
new file mode 100644
index 0000000..6da8277
--- /dev/null
+++ b/lftp-git.patch
@@ -0,0 +1,1089 @@
+diff --git a/doc/lftp.1 b/doc/lftp.1
+index d5d408f..9222795 100644
+--- a/doc/lftp.1
++++ b/doc/lftp.1
+@@ -1748,10 +1748,15 @@ is applied. It is never used if mirror:exclude-regex is empty.
+ .BR mirror:no-empty-dirs " (boolean)"
+ when true, mirror doesn't create empty directories (like \-\-no\-empty\-dirs option).
+ .TP
++.BR mirror:sort-by " (string)"
++specifies order of file transfers. Valid values are: name, name-desc, size, size-desc,
++date, date-desc. When the value is name or name-desc, then mirror:order setting also
++affects the order or transfers.
++.TP
+ .BR mirror:order " (list of patterns)"
+-specifies order of file transfers. E.g. setting this to "*.sfv *.sum" makes mirror to
++specifies order of file transfers when sorting by name. E.g. setting this to "*.sfv *.sum" makes mirror to
+ transfer files matching *.sfv first, then ones matching *.sum and then all other
+-files. To process directories after other files, add "*/" to end of pattern list.
++files. To process directories after other files, add "*/" to the end of pattern list.
+ .TP
+ .BR mirror:parallel-directories " (boolean)"
+ if true, mirror will start processing of several directories in parallel
+diff --git a/po/pl.po b/po/pl.po
+index d569428..89e8b11 100644
+--- a/po/pl.po
++++ b/po/pl.po
+@@ -7,10 +7,10 @@
+ #
+ msgid ""
+ msgstr ""
+-"Project-Id-Version: lftp 4.4.16\n"
++"Project-Id-Version: lftp 4.5.3\n"
+ "Report-Msgid-Bugs-To: lftp-bugs at lftp.yar.ru\n"
+ "POT-Creation-Date: 2014-07-06 16:15+0400\n"
+-"PO-Revision-Date: 2014-05-18 06:54+0200\n"
++"PO-Revision-Date: 2014-07-13 14:15+0200\n"
+ "Last-Translator: Jakub Bogusz <qboosh at pld-linux.org>\n"
+ "Language-Team: Polish <translation-team-pl at lists.sourceforge.net>\n"
+ "Language: pl\n"
+@@ -1152,12 +1152,10 @@ msgstr ""
+ "uczyni dopełnianie nazw plików nie rozpoznającym wielkości liter.\n"
+
+ #: src/commands.cc:216
+-#, fuzzy
+ msgid "debug [OPTS] [<level>|off]"
+-msgstr "debug [<poziom>|off] [-o <plik>]"
++msgstr "debug [OPCJE] [<poziom>|off]"
+
+ #: src/commands.cc:217
+-#, fuzzy
+ msgid ""
+ "Set debug level to given value or turn debug off completely.\n"
+ " -o <file> redirect debug output to the file\n"
+@@ -1165,8 +1163,11 @@ msgid ""
+ " -p show PID\n"
+ " -t show timestamps\n"
+ msgstr ""
+-"Ustaw poziom debugowania na daną wartość lub wyłącz zupełnie.\n"
+-" -o <plik> przekieruj wyjście debugowania do pliku.\n"
++"Ustaw poziom diagnostyki na daną wartość lub wyłącz zupełnie.\n"
++" -o <plik> przekieruj wyjście diagnostyki do pliku.\n"
++" -c wypisuj kontekst komunikatu\n"
++" -p wypisuj PID\n"
++" -t wypisuj znaczniki czasu\n"
+
+ #: src/commands.cc:222
+ msgid "du [options] <dirs>"
+@@ -1477,12 +1478,10 @@ msgstr ""
+ "podano nazw obu katalogów, to będą użyte bieżące katalogi lokalny i zdalny.\n"
+
+ #: src/commands.cc:339
+-#, fuzzy
+ msgid "mkdir [OPTS] <dirs>"
+-msgstr "mkdir [-p] <katalogi>"
++msgstr "mkdir [OPCJE] <katalogi>"
+
+ #: src/commands.cc:340
+-#, fuzzy
+ msgid ""
+ "Make remote directories\n"
+ " -p make all levels of path\n"
+@@ -1490,6 +1489,7 @@ msgid ""
+ msgstr ""
+ "Utwórz zdalne katalogi\n"
+ " -p tworzy wszystkie poziomy ścieżki\n"
++" -f ciche działanie, bez komunikatów\n"
+
+ #: src/commands.cc:343
+ msgid "module name [args]"
+@@ -2378,9 +2378,9 @@ msgid "unsupported network protocol"
+ msgstr "protokół nie jest obsługiwany"
+
+ #: src/ftpclass.cc:2133 src/ftpclass.cc:2228
+-#, fuzzy, c-format
++#, c-format
+ msgid "Data socket error (%s) - reconnecting"
+-msgstr "Błąd połączenia (%s) - powtórne łączenie"
++msgstr "Błąd gniazda danych (%s) - powtórne łączenie"
+
+ #: src/ftpclass.cc:2161
+ #, c-format
+@@ -2700,13 +2700,12 @@ msgid "peer unexpectedly closed connection after %s"
+ msgstr "druga strona nieoczekiwanie zamknęła połączenie po %s"
+
+ #: src/Torrent.cc:2903 src/Torrent.cc:3020
+-#, fuzzy
+ msgid "peer unexpectedly closed connection"
+-msgstr "druga strona nieoczekiwanie zamknęła połączenie po %s"
++msgstr "druga strona nieoczekiwanie zamknęła połączenie"
+
+ #: src/Torrent.cc:2905 src/Torrent.cc:2906
+ msgid "peer closed connection (before handshake)"
+-msgstr "druga strona zamknęła połączenie (przed jego ustanowieniem)"
++msgstr "druga strona zamknęła połączenie (przed przywitaniem)"
+
+ #: src/Torrent.cc:2909 src/Torrent.cc:3022 src/Torrent.cc:3023
+ msgid "invalid peer response format"
+@@ -2732,15 +2731,15 @@ msgstr "Przyjęto połączenie od [%s]:%d"
+ #: src/Torrent.cc:3552
+ #, c-format
+ msgid "peer sent unknown info_hash=%s in handshake"
+-msgstr ""
++msgstr "druga strona wysłała nieznane info_hash=%s przy przywitaniu"
+
+ #: src/Torrent.cc:3576
+ msgid "peer handshake timeout"
+-msgstr "upłynął limit czasu nawiązywania połączenia z drugą stroną"
++msgstr "upłynął limit czasu przywitania z drugą stroną"
+
+ #: src/Torrent.cc:3588
+ msgid "peer short handshake"
+-msgstr "nawiązanie połączenia z drugą stroną zostało ucięte"
++msgstr "przywitanie z drugą stroną zostało ucięte"
+
+ #: src/Torrent.cc:3590
+ msgid "peer closed just accepted connection"
+diff --git a/src/FileSet.cc b/src/FileSet.cc
+index 389578a..6380a68 100644
+--- a/src/FileSet.cc
++++ b/src/FileSet.cc
+@@ -232,6 +232,21 @@ void FileSet::Sort(sort_e newsort, bool casefold, bool reverse)
+ }
+ }
+
++// reverse current sort order
++void FileSet::ReverseSort()
++{
++ if(!sorted) {
++ Sort(BYNAME,false,true);
++ return;
++ }
++ int i=0;
++ int j=sorted.length()-1;
++ while(i<j) {
++ sorted[i]=replace_value(sorted[j],sorted[i]);
++ ++i,--j;
++ }
++}
++
+ /* Remove the current sort, allowing new entries to be added.
+ * (Nothing uses this ... */
+ void FileSet::Unsort()
+diff --git a/src/FileSet.h b/src/FileSet.h
+index 7c3ac2a..155536f 100644
+--- a/src/FileSet.h
++++ b/src/FileSet.h
+@@ -180,6 +180,7 @@ public:
+ void Sort(sort_e newsort, bool casefold=false, bool reverse=false);
+ void Unsort();
+ void SortByPatternList(const char *list_c);
++ void ReverseSort();
+
+ void Exclude(const char *prefix,const PatternSet *x);
+ void ExcludeDots();
+diff --git a/src/Fish.cc b/src/Fish.cc
+index d172a20..29ba4c6 100644
+--- a/src/Fish.cc
++++ b/src/Fish.cc
+@@ -98,6 +98,15 @@ int Fish::Do()
+ timeout_timer.Reset(send_buf->EventTime());
+ if(recv_buf)
+ timeout_timer.Reset(recv_buf->EventTime());
++ if(pty_send_buf)
++ timeout_timer.Reset(pty_send_buf->EventTime());
++ if(pty_recv_buf)
++ timeout_timer.Reset(pty_recv_buf->EventTime());
++
++ // check for timeout only if there should be connection activity.
++ if(state!=DISCONNECTED && (state!=CONNECTED || !RespQueueIsEmpty())
++ && mode!=CLOSED && CheckTimeout())
++ return MOVED;
+
+ if((state==FILE_RECV || state==FILE_SEND)
+ && rate_limit==0)
+@@ -275,14 +284,6 @@ int Fish::Do()
+ case DONE:
+ break;
+ }
+- if(m==MOVED)
+- return MOVED;
+- if(send_buf)
+- timeout_timer.Reset(send_buf->EventTime());
+- if(recv_buf)
+- timeout_timer.Reset(recv_buf->EventTime());
+- if(CheckTimeout())
+- return MOVED;
+ return m;
+ }
+
+diff --git a/src/MirrorJob.cc b/src/MirrorJob.cc
+index a19ff8e..eb148f1 100644
+--- a/src/MirrorJob.cc
++++ b/src/MirrorJob.cc
+@@ -589,10 +589,16 @@ void MirrorJob::InitSets(const FileSet *source,const FileSet *dest)
+ if(!(flags&DELETE))
+ to_transfer->SubtractAny(to_rm_mismatched);
+
+- to_transfer->SortByPatternList(ResMgr::Query("mirror:order",0));
+- to_transfer->CountBytes(&bytes_to_transfer);
+- if(parent_mirror)
+- parent_mirror->AddBytesToTransfer(bytes_to_transfer);
++ const char *sort_by=ResMgr::Query("mirror:sort-by",0);
++ bool desc=strstr(sort_by,"-desc");
++ if(!strncmp(sort_by,"name",4))
++ to_transfer->SortByPatternList(ResMgr::Query("mirror:order",0));
++ else if(!strncmp(sort_by,"date",4))
++ to_transfer->Sort(FileSet::BYDATE);
++ else if(!strncmp(sort_by,"size",4))
++ to_transfer->Sort(FileSet::BYSIZE,false,true);
++ if(desc)
++ to_transfer->ReverseSort();
+
+ int dir_count=0;
+ to_transfer->Count(&dir_count,NULL,NULL,NULL);
+@@ -851,10 +857,16 @@ int MirrorJob::Do()
+ stats.dirs++;
+
+ InitSets(source_set,target_set);
++
++ to_transfer->CountBytes(&bytes_to_transfer);
++ if(parent_mirror)
++ parent_mirror->AddBytesToTransfer(bytes_to_transfer);
++
+ to_rm->Count(&stats.del_dirs,&stats.del_files,&stats.del_symlinks,&stats.del_files);
+ to_rm->rewind();
+ to_rm_mismatched->Count(&stats.del_dirs,&stats.del_files,&stats.del_symlinks,&stats.del_files);
+ to_rm_mismatched->rewind();
++
+ set_state(TARGET_REMOVE_OLD_FIRST);
+ goto TARGET_REMOVE_OLD_FIRST_label;
+
+diff --git a/src/PollVec.cc b/src/PollVec.cc
+index a18b517..e1d72fb 100644
+--- a/src/PollVec.cc
++++ b/src/PollVec.cc
+@@ -31,7 +31,7 @@ static inline bool operator<(const timeval& a,const timeval& b)
+ void PollVec::AddTimeoutU(unsigned t)
+ {
+ struct timeval new_timeout={t/1000000,t%1000000};
+- if(new_timeout<tv_timeout)
++ if(tv_timeout.tv_sec<0 || new_timeout<tv_timeout)
+ SetTimeout(new_timeout);
+ }
+
+diff --git a/src/ProcWait.cc b/src/ProcWait.cc
+index 0a065ad..d3dfec4 100644
+--- a/src/ProcWait.cc
++++ b/src/ProcWait.cc
+@@ -24,7 +24,14 @@
+ #include "ProcWait.h"
+ #include "SignalHook.h"
+
+-ProcWait *ProcWait::chain=0;
++xmap<ProcWait*> ProcWait::all_proc;
++
++const xstring& ProcWait::proc_key(pid_t p)
++{
++ static xstring tmp_key;
++ tmp_key.nset((const char*)&p,sizeof(p));
++ return tmp_key;
++}
+
+ int ProcWait::Do()
+ {
+@@ -100,27 +107,19 @@ int ProcWait::Kill(int sig)
+ }
+
+ ProcWait::ProcWait(pid_t p)
++ : pid(p)
+ {
+ auto_die=false;
+- pid=p;
+ status=RUNNING;
+ term_info=-1;
+ saved_errno=0;
+
+- next=chain;
+- chain=this;
++ all_proc.add(proc_key(pid),this);
+ }
+
+ ProcWait::~ProcWait()
+ {
+- for(ProcWait **scan=&chain; *scan; scan=&(*scan)->next)
+- {
+- if(*scan==this)
+- {
+- *scan=next;
+- return;
+- }
+- }
++ all_proc.remove(proc_key(pid));
+ }
+
+ void ProcWait::SIGCHLD_handler(int sig)
+@@ -130,16 +129,9 @@ void ProcWait::SIGCHLD_handler(int sig)
+ pid_t pp=waitpid(-1,&info,WUNTRACED|WNOHANG);
+ if(pp==-1)
+ return;
+- for(ProcWait *scan=chain; scan; scan=scan->next)
+- {
+- if(scan->pid==pp)
+- {
+- scan->handle_info(info);
+- return;
+- }
+- }
+- // no WaitProc for the pid. Probably the process died too fast,
+- // but next waitpid should take care of it.
++ ProcWait *w=all_proc.lookup(proc_key(pp));
++ if(w && w->handle_info(info))
++ w->Timeout(0);
+ }
+
+ void ProcWait::Signal(bool yes)
+@@ -156,6 +148,6 @@ void ProcWait::Signal(bool yes)
+ void ProcWait::DeleteAll()
+ {
+ Signal(false);
+- for(ProcWait *scan=chain; scan; scan=scan->next)
+- Delete(scan);
++ for(ProcWait *w=all_proc.each_begin(); w; w=all_proc.each_next())
++ Delete(w);
+ }
+diff --git a/src/ProcWait.h b/src/ProcWait.h
+index d6f0bad..651bc21 100644
+--- a/src/ProcWait.h
++++ b/src/ProcWait.h
+@@ -23,6 +23,7 @@
+ #include <sys/types.h>
+ #include <signal.h>
+ #include "SMTask.h"
++#include "xmap.h"
+
+ class ProcWait : public SMTask
+ {
+@@ -35,10 +36,10 @@ public:
+ };
+
+ protected:
+- static ProcWait *chain;
+- ProcWait *next;
++ static xmap<ProcWait*> all_proc;
++ static const xstring& proc_key(pid_t p); // make key for xmap
+
+- pid_t pid;
++ const pid_t pid;
+ State status;
+ int term_info;
+ int saved_errno;
+diff --git a/src/Ref.h b/src/Ref.h
+index 8731089..c96ee96 100644
+--- a/src/Ref.h
++++ b/src/Ref.h
+@@ -51,4 +51,22 @@ public:
+
+ template<typename T> const Ref<T> Ref<T>::null;
+
++template<typename T> class RefToArray : public Ref<T>
++{
++ RefToArray<T>(const RefToArray<T>&); // disable cloning
++ void operator=(const RefToArray<T>&); // and assignment
++
++public:
++ RefToArray<T>() {}
++ RefToArray<T>(T *p) : Ref<T>(p) {}
++ ~RefToArray<T>() { delete[] Ref<T>::ptr; Ref<T>::ptr=0; }
++ void operator=(T *p) { delete[] Ref<T>::ptr; Ref<T>::ptr=p; }
++ T& operator[](unsigned i) const { return Ref<T>::ptr[i]; }
++
++ static const RefToArray<T> null;
++};
++
++template<typename T> const RefToArray<T> RefToArray<T>::null;
++
++
+ #endif
+diff --git a/src/SFtp.cc b/src/SFtp.cc
+index 8e6d0d5..3225701 100644
+--- a/src/SFtp.cc
++++ b/src/SFtp.cc
+@@ -915,11 +915,7 @@ void SFtp::HandleExpect(Expect *e)
+ for(int i=0; i<r->GetCount(); i++)
+ {
+ const NameAttrs *a=r->GetNameAttrs(i);
+- if(!file_set)
+- file_set=new FileSet;
+ FileInfo *info=MakeFileInfo(a);
+- if(info)
+- file_set->Add(info);
+ if(mode==LIST)
+ {
+ file_buf->Put(a->name);
+@@ -941,6 +937,12 @@ void SFtp::HandleExpect(Expect *e)
+ file_buf->Put("\n");
+ }
+ }
++ if(info)
++ {
++ if(!file_set)
++ file_set=new FileSet;
++ file_set->Add(info);
++ }
+ }
+ if(r->Eof())
+ goto eof;
+diff --git a/src/Torrent.cc b/src/Torrent.cc
+index ffe6433..270bbd6 100644
+--- a/src/Torrent.cc
++++ b/src/Torrent.cc
+@@ -278,6 +278,10 @@ Torrent::Torrent(const char *mf,const char *c,const char *od)
+ dht_announce_timer.Stop();
+ }
+
++Torrent::~Torrent()
++{
++}
++
+ bool Torrent::TrackersDone() const
+ {
+ if(shutting_down && shutting_down_timer.Stopped())
+@@ -318,6 +322,8 @@ void Torrent::PrepareToDie()
+ RemoveTorrent(this);
+ if(GetTorrentsCount()==0) {
+ StopListener();
++ StopDHT();
++ StopListenerUDP();
+ fd_cache=0;
+ black_list=0;
+ }
+@@ -348,9 +354,7 @@ double Torrent::GetRatio() const
+
+ void Torrent::SetDownloader(unsigned piece,unsigned block,const TorrentPeer *o,const TorrentPeer *n)
+ {
+- const TorrentPeer*& downloader=piece_info[piece]->downloader[block];
+- if(downloader==o)
+- downloader=n;
++ piece_info[piece].set_downloader(block,o,n,BlocksInPiece(piece));
+ }
+
+ BeNode *Torrent::Lookup(xmap_p<BeNode>& dict,const char *name,BeNode::be_type_t type)
+@@ -421,25 +425,18 @@ void Torrent::ValidatePiece(unsigned p)
+ complete_pieces--;
+ my_bitfield->set_bit(p,0);
+ }
+- piece_info[p]->block_map.clear();
++ SetBlocksAbsent(p);
+ } else {
+ LogNote(11,"piece %u ok",p);
+ if(!my_bitfield->get_bit(p)) {
+ total_left-=PieceLength(p);
+ complete_pieces++;
+ my_bitfield->set_bit(p,1);
++ piece_info[p].free_block_map();
+ }
+ }
+ }
+
+-bool TorrentPiece::has_a_downloader() const
+-{
+- for(int i=0; i<downloader.count(); i++)
+- if(downloader[i])
+- return true;
+- return false;
+-}
+-
+ template<typename T>
+ static inline int cmp(T a,T b)
+ {
+@@ -453,8 +450,8 @@ static inline int cmp(T a,T b)
+ static Torrent *cmp_torrent;
+ int Torrent::PiecesNeededCmp(const unsigned *a,const unsigned *b)
+ {
+- int ra=cmp_torrent->piece_info[*a]->sources_count;
+- int rb=cmp_torrent->piece_info[*b]->sources_count;
++ int ra=cmp_torrent->piece_info[*a].get_sources_count();
++ int rb=cmp_torrent->piece_info[*b].get_sources_count();
+ int c=cmp(ra,rb);
+ if(c) return c;
+ return cmp(*a,*b);
+@@ -721,7 +718,7 @@ void Torrent::SetMetadata(const xstring& md)
+ }
+
+ BeNode *b_piece_length=Lookup(info,"piece length",BeNode::BE_INT);
+- if(!b_piece_length)
++ if(!b_piece_length || b_piece_length->num<1024 || b_piece_length->num>INT_MAX/4)
+ return;
+ piece_length=b_piece_length->num;
+ LogNote(4,"Piece length is %u",piece_length);
+@@ -744,7 +741,7 @@ void Torrent::SetMetadata(const xstring& md)
+ if(!files) {
+ single_file=true;
+ BeNode *length=Lookup(info,"length",BeNode::BE_INT);
+- if(!length)
++ if(!length || length->num<0)
+ return;
+ total_length=length->num;
+ } else {
+@@ -764,9 +761,12 @@ void Torrent::SetMetadata(const xstring& md)
+ return;
+ if(!Lookup(files->list[i]->dict,"path",BeNode::BE_LIST))
+ return;
++ if(f->num<0)
++ return;
+ total_length+=f->num;
+ }
+ }
++ this->files=new TorrentFiles(files,this);
+ LogNote(4,"Total length is %llu",total_length);
+ total_left=total_length;
+
+@@ -800,16 +800,18 @@ void Torrent::SetMetadata(const xstring& md)
+ SaveMetadata();
+
+ my_bitfield=new BitField(total_pieces);
+- for(unsigned p=0; p<total_pieces; p++)
+- piece_info.append(new TorrentPiece(BlocksInPiece(p)));
++
++ blocks_in_piece=(piece_length+BLOCK_SIZE-1)/BLOCK_SIZE;
++ blocks_in_last_piece=(last_piece_length+BLOCK_SIZE-1)/BLOCK_SIZE;
++
++ piece_info=new TorrentPiece[total_pieces]();
+
+ if(!force_valid) {
+ validate_index=0;
+ validating=true;
+ recv_rate.Reset();
+ } else {
+- for(unsigned i=0; i<total_pieces; i++)
+- my_bitfield->set_bit(i,1);
++ my_bitfield->set_range(0,total_pieces,1);
+ complete_pieces=total_pieces;
+ total_left=0;
+ complete=true;
+@@ -927,7 +929,7 @@ void Torrent::CalcPiecesStats()
+ for(unsigned i=0; i<total_pieces; i++) {
+ if(my_bitfield->get_bit(i))
+ continue;
+- unsigned sc=piece_info[i]->sources_count;
++ unsigned sc=piece_info[i].get_sources_count();
+ if(min_piece_sources>sc)
+ min_piece_sources=sc;
+ if(sc==0)
+@@ -945,12 +947,13 @@ void Torrent::RebuildPiecesNeeded()
+ bool enter_end_game=true;
+ for(unsigned i=0; i<total_pieces; i++) {
+ if(!my_bitfield->get_bit(i)) {
+- if(!piece_info[i]->has_a_downloader())
++ if(!piece_info[i].has_a_downloader())
+ enter_end_game=false;
+- if(piece_info[i]->sources_count==0)
++ if(piece_info[i].has_no_sources())
+ continue;
+ pieces_needed.append(i);
+ }
++ piece_info[i].cleanup();
+ }
+ if(!end_game && enter_end_game) {
+ LogNote(1,"entering End Game mode");
+@@ -1084,6 +1087,8 @@ int Torrent::Do()
+ a.sa.sa_family=AF_INET6;
+ if(inet_pton(AF_INET6,b_ip->str,&a.in6.sin6_addr)<=0)
+ continue;
++ if(b_port->num<=0 || b_port->num>=0x10000)
++ continue;
+ a.set_port(b_port->num);
+ dht_ipv6->SendPing(a);
+ } else
+@@ -1092,6 +1097,8 @@ int Torrent::Do()
+ a.sa.sa_family=AF_INET;
+ if(!inet_aton(b_ip->str,&a.in.sin_addr))
+ continue;
++ if(b_port->num<=0 || b_port->num>=0x10000)
++ continue;
+ a.set_port(b_port->num);
+ dht->SendPing(a);
+ }
+@@ -1249,24 +1256,51 @@ const char *Torrent::MakePath(BeNode *p) const
+ }
+ const char *Torrent::FindFileByPosition(unsigned piece,unsigned begin,off_t *f_pos,off_t *f_tail) const
+ {
+- const BeNode *files=info->lookup("files",BeNode::BE_LIST);
+ off_t target_pos=(off_t)piece*piece_length+begin;
++ TorrentFile *file=files->FindByPosition(target_pos);
++ if(!file)
++ return 0;
++
++ *f_pos=target_pos-file->pos;
++ *f_tail=file->length-*f_pos;
++
++ return file->path;
++}
++
++TorrentFiles::TorrentFiles(const BeNode *files,const Torrent *t)
++{
+ if(!files) {
+- *f_pos=target_pos;
+- *f_tail=total_length-target_pos;
+- return name;
++ grow_space(1);
++ set_length(1);
++ file(0)->set(t->GetName(),0,t->TotalLength());
+ } else {
++ int count=files->list.length();
++ grow_space(count);
++ set_length(count);
+ off_t scan_pos=0;
+- for(int i=0; i<files->list.length(); i++) {
+- off_t file_length=files->list[i]->lookup_int("length");
+- if(scan_pos<=target_pos && scan_pos+file_length>target_pos) {
+- *f_pos=target_pos-scan_pos;
+- *f_tail=file_length-*f_pos;
+- return MakePath(files->list[i]);
+- }
++ for(int i=0; i<count; i++) {
++ BeNode *node=files->list[i];
++ off_t file_length=node->lookup_int("length");
++ file(i)->set(t->MakePath(node),scan_pos,file_length);
+ scan_pos+=file_length;
+ }
+ }
++ qsort(pos_cmp);
++}
++TorrentFile *TorrentFiles::FindByPosition(off_t pos)
++{
++ int i=0;
++ int j=length()-1;
++ while(i<=j) {
++ // invariant: the target element is in the range [i,j]
++ int m=(i+j)/2;
++ if(file(m)->contains_pos(pos))
++ return file(m);
++ if(file(m)->pos>pos)
++ j=m-1;
++ else
++ i=m+1;
++ }
+ return 0;
+ }
+
+@@ -1485,9 +1519,9 @@ void Torrent::StoreBlock(unsigned piece,unsigned begin,unsigned len,const char *
+ }
+
+ while(bc-->0) {
+- piece_info[piece]->block_map.set_bit(b++,1);
++ SetBlockPresent(piece,b++);
+ }
+- if(piece_info[piece]->block_map.has_all_set() && !my_bitfield->get_bit(piece)) {
++ if(AllBlocksPresent(piece) && !my_bitfield->get_bit(piece)) {
+ ValidatePiece(piece);
+ if(!my_bitfield->get_bit(piece)) {
+ LogError(0,"new piece %u digest mismatch",piece);
+@@ -2021,12 +2055,12 @@ int TorrentPeer::SendDataRequests(unsigned p)
+ unsigned blocks=parent->BlocksInPiece(p);
+ unsigned bytes_allowed=BytesAllowed(RateLimit::GET);
+ for(unsigned b=0; b<blocks; b++) {
+- if(parent->piece_info[p]->block_map.get_bit(b))
++ if(parent->BlockPresent(p,b))
+ continue;
+- if(parent->piece_info[p]->downloader[b]) {
++ if(parent->piece_info[p].downloader_for(b)) {
+ if(!parent->end_game)
+ continue;
+- if(parent->piece_info[p]->downloader[b]==this)
++ if(parent->piece_info[p].downloader_for(b)==this)
+ continue;
+ if(FindRequest(p,b*Torrent::BLOCK_SIZE)>=0)
+ continue;
+@@ -2118,8 +2152,7 @@ void TorrentPeer::SendDataRequests()
+ if(parent->my_bitfield->get_bit(p))
+ continue;
+ // add some randomness, so that different instances don't synchronize
+- if(!parent->piece_info[p]->block_map.has_any_set()
+- && random()/13%16==0)
++ if(parent->AllBlocksAbsent(p) && random()/13%16==0)
+ continue;
+ if(SendDataRequests(p)>0)
+ return;
+@@ -2233,7 +2266,7 @@ unsigned TorrentPeer::GetLastPiece() const
+ unsigned p=last_piece;
+ // continue if have any blocks already
+ if(p!=NO_PIECE && !parent->my_bitfield->get_bit(p)
+- && parent->piece_info[p]->block_map.has_any_set()
++ && parent->AnyBlocksPresent(p)
+ && peer_bitfield->get_bit(p))
+ return p;
+ p=parent->last_piece;
+@@ -2302,11 +2335,11 @@ void TorrentPeer::SetPieceHaving(unsigned p,bool have)
+ int diff = (have - peer_bitfield->get_bit(p));
+ if(!diff)
+ return;
+- parent->piece_info[p]->sources_count+=diff;
++ parent->piece_info[p].add_sources_count(diff);
+ peer_complete_pieces+=diff;
+ peer_bitfield->set_bit(p,have);
+
+- if(parent->piece_info[p]->sources_count==0)
++ if(parent->piece_info[p].get_sources_count()==0)
+ parent->SetPieceNotWanted(p);
+ if(have && send_buf && !am_interested && !parent->my_bitfield->get_bit(p)
+ && parent->NeedMoreUploaders()) {
+@@ -2641,7 +2674,7 @@ void TorrentPeer::HandleExtendedMessage(PacketExtended *pp)
+ return;
+ }
+ BeNode *piece=pp->data->lookup("piece",BeNode::BE_INT);
+- if(!piece) {
++ if(!piece || piece->num<0 || piece->num>=INT_MAX/Torrent::BLOCK_SIZE) {
+ SetError("ut_metadata piece bad or missing");
+ return;
+ }
+@@ -2692,6 +2725,9 @@ void TorrentPeer::HandleExtendedMessage(PacketExtended *pp)
+ }
+ case UT_METADATA_REJECT:
+ break;
++ default:
++ SetError("ut_metadata msg_type invalid value");
++ return;
+ }
+ } else if(pp->code==MSG_EXT_PEX) {
+ if(!pex.recv_timer.Stopped())
+@@ -3322,14 +3358,16 @@ bool BitField::has_all_set(int from,int to) const {
+ return false;
+ return true;
+ }
+-
++void BitField::set_range(int from,int to,bool value) {
++ for(int i=from; i<to; i++)
++ set_bit(i,value);
++}
+
+ void TorrentBlackList::check_expire()
+ {
+ for(Timer *e=bl.each_begin(); e; e=bl.each_next()) {
+ if(e->Stopped()) {
+ Log::global->Format(4,"---- black-delisting peer %s\n",bl.each_key().get());
+- delete e;
+ bl.remove(bl.each_key());
+ }
+ }
+diff --git a/src/Torrent.h b/src/Torrent.h
+index a9943c6..ef5d75c 100644
+--- a/src/Torrent.h
++++ b/src/Torrent.h
+@@ -53,20 +53,105 @@ public:
+ int get_bit_length() const { return bit_length; }
+ void set_bit_length(int b) { bit_length=b; set_length((b+7)/8); }
+ void clear() { memset(buf,0,length()); }
++ void set_range(int from,int to,bool value);
+ };
+
+-struct TorrentPiece
++class TorrentPiece
+ {
+ unsigned sources_count; // how many peers have the piece
++ unsigned downloader_count; // how many downloaders of the piece are there
++ RefToArray<const TorrentPeer*> downloader; // which peers download the blocks
++ Ref<BitField> block_map; // which blocks are present.
+
+- BitField block_map; // which blocks are present
+- xarray<const TorrentPeer*> downloader; // which peers download the blocks
++public:
++ TorrentPiece() : sources_count(0), downloader_count(0) {}
++ ~TorrentPiece() {}
++
++ unsigned get_sources_count() const { return sources_count; }
++ void add_sources_count(int diff) { sources_count+=diff; }
++ bool has_no_sources() const { return sources_count==0; }
++
++ bool has_a_downloader() const { return downloader_count>0; }
++ void set_downloader(unsigned block,const TorrentPeer *o,const TorrentPeer *n,unsigned blk_count) {
++ if(!downloader) {
++ if(o || !n)
++ return;
++ downloader=new const TorrentPeer*[blk_count]();
++ }
++ const TorrentPeer*& d=downloader[block];
++ if(d==o) {
++ d=n;
++ downloader_count+=(n!=0)-(o!=0);
++ }
++ }
++ void cleanup() {
++ if(downloader_count==0 && downloader)
++ downloader=0;
++ }
++ const TorrentPeer *downloader_for(unsigned block) {
++ return downloader ? downloader[block] : 0;
++ }
+
+- TorrentPiece(unsigned b)
+- : sources_count(0), block_map(b)
+- { downloader.allocate(b,0); }
++ void set_block_present(unsigned block,unsigned blk_count) {
++ if(!block_map)
++ block_map=new BitField(blk_count);
++ block_map->set_bit(block,1);
++ }
++ void set_blocks_absent() {
++ block_map=0;
++ }
++ void free_block_map() {
++ block_map=0;
++ }
++ bool block_present(unsigned block) const {
++ return block_map && block_map->get_bit(block);
++ }
++ bool all_blocks_present(unsigned blk_count) const {
++ return block_map && block_map->has_all_set(0,blk_count);
++ }
++ bool any_blocks_present() const {
++ return block_map; // it's allocated when setting any bit
++ }
++};
++
++struct TorrentFile
++{
++ char *path;
++ off_t pos;
++ off_t length;
++ void set(const char *n,off_t p,off_t l) {
++ path=xstrdup(n);
++ pos=p;
++ length=l;
++ }
++ void unset() {
++ xfree(path); path=0;
++ }
++ bool contains_pos(off_t p) const {
++ return p>=pos && p<pos+length;
++ }
++};
+
+- bool has_a_downloader() const;
++class TorrentFiles : public xarray<TorrentFile>
++{
++ static int pos_cmp(const TorrentFile *a, const TorrentFile *b) {
++ if(a->pos < b->pos)
++ return -1;
++ if(a->pos > b->pos)
++ return 1;
++ // we want zero-sized files to placed before non-zero ones.
++ if(a->length != b->length)
++ return a->length < b->length ? -1 : 1;
++ return 0;
++ }
++public:
++ TorrentFile *file(int i) { return get_non_const()+i; }
++ TorrentFiles(const BeNode *f_node,const Torrent *t);
++ ~TorrentFiles() {
++ for(int i=0; i<length(); i++)
++ file(i)->unset();
++ }
++ TorrentFile *FindByPosition(off_t p);
+ };
+
+ class TorrentListener : public SMTask, protected ProtoLog, protected Networker
+@@ -99,6 +184,7 @@ class Torrent : public SMTask, protected ProtoLog, public ResClient
+ friend class TorrentPeer;
+ friend class TorrentDispatcher;
+ friend class TorrentListener;
++ friend class TorrentFiles;
+ friend class DHT;
+
+ bool shutting_down;
+@@ -171,6 +257,7 @@ class Torrent : public SMTask, protected ProtoLog, public ResClient
+ xstring info_hash;
+ const xstring *pieces;
+ xstring name;
++ Ref<TorrentFiles> files;
+
+ Ref<DirectedBuffer> recv_translate;
+ Ref<DirectedBuffer> recv_translate_utf8;
+@@ -214,11 +301,32 @@ class Torrent : public SMTask, protected ProtoLog, public ResClient
+ BeNode *Lookup(Ref<BeNode>& d,const char *name,BeNode::be_type_t type) { return Lookup(d->dict,name,type); }
+
+ TaskRefArray<TorrentPeer> peers;
+- RefArray<TorrentPiece> piece_info;
+ static int PeersCompareActivity(const SMTaskRef<TorrentPeer> *p1,const SMTaskRef<TorrentPeer> *p2);
+ static int PeersCompareRecvRate(const SMTaskRef<TorrentPeer> *p1,const SMTaskRef<TorrentPeer> *p2);
+ static int PeersCompareSendRate(const SMTaskRef<TorrentPeer> *p1,const SMTaskRef<TorrentPeer> *p2);
+
++ RefToArray<TorrentPiece> piece_info;
++ unsigned blocks_in_piece;
++ unsigned blocks_in_last_piece;
++ bool BlockPresent(unsigned piece,unsigned block) const {
++ return piece_info[piece].block_present(block);
++ }
++ bool AllBlocksPresent(unsigned piece) const {
++ return piece_info[piece].all_blocks_present(BlocksInPiece(piece));
++ }
++ bool AnyBlocksPresent(unsigned piece) const {
++ return piece_info[piece].any_blocks_present();
++ }
++ bool AllBlocksAbsent(unsigned piece) const {
++ return !AnyBlocksPresent(piece);
++ }
++ void SetBlocksAbsent(unsigned piece) {
++ piece_info[piece].set_blocks_absent();
++ }
++ void SetBlockPresent(unsigned piece,unsigned block) {
++ piece_info[piece].set_block_present(block,BlocksInPiece(piece));
++ }
++
+ void RebuildPiecesNeeded();
+ Timer pieces_needed_rebuild_timer;
+ xarray<unsigned> pieces_needed;
+@@ -296,6 +404,7 @@ public:
+ static void ClassInit();
+
+ Torrent(const char *mf,const char *cwd,const char *output_dir);
++ ~Torrent();
+
+ int Do();
+ int Done() const;
+@@ -315,7 +424,7 @@ public:
+ static void SHA1(const xstring& str,xstring& buf);
+ void ValidatePiece(unsigned p);
+ unsigned PieceLength(unsigned p) const { return p==total_pieces-1 ? last_piece_length : piece_length; }
+- unsigned BlocksInPiece(unsigned p) const { return (PieceLength(p)+BLOCK_SIZE-1)/BLOCK_SIZE; }
++ unsigned BlocksInPiece(unsigned p) const { return p==total_pieces-1 ? blocks_in_last_piece : blocks_in_piece; }
+
+ const TaskRefArray<TorrentPeer>& GetPeers() const { return peers; }
+ void AddPeer(TorrentPeer *);
+@@ -772,7 +881,7 @@ public:
+
+ class TorrentBlackList
+ {
+- xmap<Timer*> bl;
++ xmap_p<Timer> bl;
+ void check_expire();
+ public:
+ bool Listed(const sockaddr_u &a);
+diff --git a/src/resource.cc b/src/resource.cc
+index 4aa071a..e4707e7 100644
+--- a/src/resource.cc
++++ b/src/resource.cc
+@@ -57,13 +57,39 @@ static const char *FtpProxyValidate(xstring_c *p)
+ return 0;
+ }
+
++static const char *SetValidate(xstring_c& s,const char *const *set,const char *name)
++{
++ const char *const *scan;
++ for(scan=set; *scan; scan++)
++ if(s.eq(*scan))
++ return 0;
++
++ xstring &j=xstring::get_tmp();
++ if(name)
++ j.setf(_("%s must be one of: "),name);
++ else
++ j.set(_("must be one of: "));
++ bool had_empty=false;
++ for(scan=set; *scan; scan++) {
++ if(!**scan) {
++ had_empty=true;
++ continue;
++ }
++ if(scan>set)
++ j.append(", ");
++ j.append(*scan);
++ }
++ if(had_empty)
++ j.append(_(", or empty"));
++ return j;
++}
++
+ static const char *FtpProxyAuthTypeValidate(xstring_c *s)
+ {
+- if(s->ne("user") && s->ne("joined") && s->ne("joined-acct")
+- && s->ne("open") && s->ne("proxy-user at host"))
+- // for translator: `user', `joined', `joined-acct', `open' are literals.
+- return _("ftp:proxy-auth-type must be one of: user, joined, joined-acct, open, proxy-user at host");
+- return 0;
++ static const char *const valid_set[]={
++ "user", "joined", "joined-acct", "open", "proxy-user at host", 0
++ };
++ return SetValidate(*s,valid_set,"ftp:proxy-auth-type");
+ }
+
+ static const char *HttpProxyValidate(xstring_c *p)
+@@ -130,6 +156,14 @@ const char *OrderValidate(xstring_c *s)
+ return 0;
+ }
+
++static const char *SortByValidate(xstring_c *s)
++{
++ static const char * const valid_set[]={
++ "name", "name-desc", "size", "size-desc", "date", "date-desc", 0
++ };
++ return SetValidate(*s,valid_set,"mirror:order-by");
++}
++
+ #if USE_SSL
+ static
+ const char *AuthArgValidate(xstring_c *s)
+@@ -137,30 +171,21 @@ const char *AuthArgValidate(xstring_c *s)
+ for(char *i=s->get_non_const(); *i; i++)
+ *i=to_ascii_upper(*i);
+
+- if(strcmp(*s,"SSL")
+- && strcmp(*s,"TLS")
+- && strcmp(*s,"TLS-P")
+- && strcmp(*s,"TLS-C"))
+- return _("ftp:ssl-auth must be one of: SSL, TLS, TLS-P, TLS-C");
+-
+- return 0;
++ const char *const valid_set[]={
++ "SSL", "TLS", "TLS-P", "TLS-C", 0
++ };
++ return SetValidate(*s,valid_set,"ftp:ssl-auth");
+ }
+ static
+ const char *ProtValidate(xstring_c *s)
+ {
+- if(!**s)
+- return 0;
+-
+ for(char *i=s->get_non_const(); *i; i++)
+ *i=to_ascii_upper(*i);
+
+- if(strcmp(*s,"P")
+- && strcmp(*s,"C")
+- && strcmp(*s,"S")
+- && strcmp(*s,"E"))
+- return _("must be one of: C, S, E, P, or empty");
+-
+- return 0;
++ const char *const valid_set[]={
++ "C", "S", "E", "P", "", 0
++ };
++ return SetValidate(*s,valid_set,"ftps:initial-prot");
+ }
+ #endif
+
+@@ -300,6 +325,7 @@ static ResType lftp_vars[] = {
+ {"net:connection-limit", "0", ResMgr::UNumberValidate,0},
+ {"net:connection-takeover", "yes", ResMgr::BoolValidate,0},
+
++ {"mirror:sort-by", "name", SortByValidate,ResMgr::NoClosure},
+ {"mirror:order", "*.sfv *.sig *.md5* *.sum * */", 0,ResMgr::NoClosure},
+ {"mirror:parallel-directories", "yes", ResMgr::BoolValidate,ResMgr::NoClosure},
+ {"mirror:parallel-transfer-count", "1",ResMgr::UNumberValidate,ResMgr::NoClosure},
+diff --git a/src/xmap.cc b/src/xmap.cc
+index 4bc9a86..2276bce 100644
+--- a/src/xmap.cc
++++ b/src/xmap.cc
+@@ -136,6 +136,7 @@ void _xmap::_remove(entry **ep)
+ if(!ep || !*ep)
+ return;
+ entry *e=*ep;
++ e->key.unset();
+ *ep=e->next;
+ xfree(e);
+ entry_count--;
+diff --git a/src/xstring.h b/src/xstring.h
+index 264baf6..4a284ee 100644
+--- a/src/xstring.h
++++ b/src/xstring.h
+@@ -222,7 +222,8 @@ public:
+ static xstring& cat(const char *first,...) ATTRIBUTE_SENTINEL;
+ static xstring& join(const char *sep,int n,...);
+
+- void truncate(size_t n=0);
++ void truncate() { set_length(0); }
++ void truncate(size_t n);
+ void truncate_at(char c);
+ /* set_length can be used to extend the string, e.g. after modification
+ with get_space+get_non_const. */
================================================================
---- gitweb:
http://git.pld-linux.org/gitweb.cgi/packages/lftp.git/commitdiff/93dfd0ea2d63693d69604a96615ee24f639064e8
More information about the pld-cvs-commit
mailing list