|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2015 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8f70b4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8f70b4 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
8f70b4 |
* (at your option) any later version.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8f70b4 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8f70b4 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8f70b4 |
* GNU General Public License for more details.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8f70b4 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <config.h>
|
|
Packit |
8f70b4 |
#include <stddef.h>
|
|
Packit |
8f70b4 |
#include "Fish.h"
|
|
Packit |
8f70b4 |
#include "trio.h"
|
|
Packit |
8f70b4 |
#include <unistd.h>
|
|
Packit |
8f70b4 |
#include <errno.h>
|
|
Packit |
8f70b4 |
#include <stdarg.h>
|
|
Packit |
8f70b4 |
#include <assert.h>
|
|
Packit |
8f70b4 |
#include <time.h>
|
|
Packit |
8f70b4 |
#include "ascii_ctype.h"
|
|
Packit |
8f70b4 |
#include "LsCache.h"
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "log.h"
|
|
Packit |
8f70b4 |
#include "ArgV.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define super SSH_Access
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define max_buf 0x10000
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Fish::GetBetterConnection(int level)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(FA *fo=FirstSameSite(); fo!=0; fo=NextSameSite(fo))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Fish *o=(Fish*)fo; // we are sure it is Fish.
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!o->recv_buf)
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(o->state!=CONNECTED || o->mode!=CLOSED)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(level<2)
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
if(!connection_takeover || (o->priority>=priority && !o->IsSuspended()))
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
o->Disconnect();
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(level==0 && xstrcmp(real_cwd,o->real_cwd))
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// borrow the connection
|
|
Packit |
8f70b4 |
MoveConnectionHere(o);
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int Fish::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
int fd;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// check if idle time exceeded
|
|
Packit |
8f70b4 |
if(mode==CLOSED && send_buf && idle_timer.Stopped())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
LogNote(1,_("Closing idle connection"));
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(Error())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!hostname)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(send_buf && send_buf->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(state!=CONNECTING_1)
|
|
Packit |
8f70b4 |
m|=HandleReplies();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(Error())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(send_buf)
|
|
Packit |
8f70b4 |
timeout_timer.Reset(send_buf->EventTime());
|
|
Packit |
8f70b4 |
if(recv_buf)
|
|
Packit |
8f70b4 |
timeout_timer.Reset(recv_buf->EventTime());
|
|
Packit |
8f70b4 |
if(pty_send_buf)
|
|
Packit |
8f70b4 |
timeout_timer.Reset(pty_send_buf->EventTime());
|
|
Packit |
8f70b4 |
if(pty_recv_buf)
|
|
Packit |
8f70b4 |
timeout_timer.Reset(pty_recv_buf->EventTime());
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// check for timeout only if there should be connection activity.
|
|
Packit |
8f70b4 |
if(state!=DISCONNECTED && (state!=CONNECTED || !RespQueueIsEmpty())
|
|
Packit |
8f70b4 |
&& mode!=CLOSED && CheckTimeout())
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if((state==FILE_RECV || state==FILE_SEND)
|
|
Packit |
8f70b4 |
&& rate_limit==0)
|
|
Packit |
8f70b4 |
rate_limit=new RateLimit(hostname);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *charset;
|
|
Packit |
8f70b4 |
switch(state)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case DISCONNECTED:
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(mode==CLOSED)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(mode==CONNECT_VERIFY)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// walk through Fish classes and try to find identical idle session
|
|
Packit |
8f70b4 |
// first try "easy" cases of session take-over.
|
|
Packit |
8f70b4 |
for(int i=0; i<3; i++)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(i>=2 && (connection_limit==0 || connection_limit>CountConnections()))
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
GetBetterConnection(i);
|
|
Packit |
8f70b4 |
if(state!=DISCONNECTED)
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!ReconnectAllowed())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!NextTry())
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *shell=Query("shell",hostname);
|
|
Packit |
8f70b4 |
const char *init=xstring::cat("echo FISH:;",shell,NULL);
|
|
Packit |
8f70b4 |
const char *prog=Query("connect-program",hostname);
|
|
Packit |
8f70b4 |
if(!prog || !prog[0])
|
|
Packit |
8f70b4 |
prog="ssh -a -x";
|
|
Packit |
8f70b4 |
ArgV args;
|
|
Packit |
8f70b4 |
if(user)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
args.Add("-l");
|
|
Packit |
8f70b4 |
args.Add(user);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(portname)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
args.Add("-p");
|
|
Packit |
8f70b4 |
args.Add(portname);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
args.Add(hostname);
|
|
Packit |
8f70b4 |
args.Add(init);
|
|
Packit |
8f70b4 |
xstring_ca cmd_q(args.CombineShellQuoted(0));
|
|
Packit |
8f70b4 |
xstring& cmd_str=xstring::cat(prog," ",cmd_q.get(),NULL);
|
|
Packit |
8f70b4 |
LogNote(9,"%s (%s)\n",_("Running connect program"),cmd_str.get());
|
|
Packit |
8f70b4 |
ssh=new PtyShell(cmd_str);
|
|
Packit |
8f70b4 |
ssh->UsePipes();
|
|
Packit |
8f70b4 |
state=CONNECTING;
|
|
Packit |
8f70b4 |
timeout_timer.Reset();
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
case CONNECTING:
|
|
Packit |
8f70b4 |
fd=ssh->getfd();
|
|
Packit |
8f70b4 |
if(fd==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(ssh->error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(FATAL,ssh->error_text);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
TimeoutS(1);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
MakePtyBuffers();
|
|
Packit |
8f70b4 |
set_real_cwd("~");
|
|
Packit |
8f70b4 |
state=CONNECTING_1;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case CONNECTING_1:
|
|
Packit |
8f70b4 |
m|=HandleSSHMessage();
|
|
Packit |
8f70b4 |
if(state!=CONNECTING_1)
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
if(!received_greeting)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
charset=ResMgr::Query("fish:charset",hostname);
|
|
Packit |
8f70b4 |
if(charset && *charset)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
send_buf->SetTranslation(charset,false);
|
|
Packit |
8f70b4 |
recv_buf->SetTranslation(charset,true);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Send("#FISH\n"
|
|
Packit |
8f70b4 |
"TZ=GMT;export TZ;LC_ALL=C;export LC_ALL;"
|
|
Packit |
8f70b4 |
"exec 2>&1;echo;start_fish_server;"
|
|
Packit |
8f70b4 |
"echo '### 200'\n");
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_FISH);
|
|
Packit |
8f70b4 |
Send("#VER 0.0.2\n"
|
|
Packit |
8f70b4 |
"echo '### 000'\n");
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_VER);
|
|
Packit |
8f70b4 |
if(home_auto==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Send("#PWD\n"
|
|
Packit |
8f70b4 |
"pwd; echo '### 200'\n");
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_PWD);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
state=CONNECTED;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case CONNECTED:
|
|
Packit |
8f70b4 |
if(mode==CLOSED)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(home.path==0 && !RespQueueIsEmpty())
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
ExpandTildeInCWD();
|
|
Packit |
8f70b4 |
if(mode!=CHANGE_DIR && xstrcmp(cwd,real_cwd))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(xstrcmp(path_queue.LastString(),cwd))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Send("#CWD %s\n"
|
|
Packit |
8f70b4 |
"cd %s; echo '### 000'\n",cwd.path.get(),shell_encode(cwd).get());
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_CWD);
|
|
Packit |
8f70b4 |
PushDirectory(cwd);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!RespQueueIsEmpty())
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
SendMethod();
|
|
Packit |
8f70b4 |
if(mode==LONG_LIST || mode==LIST || mode==QUOTE_CMD)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
state=FILE_RECV;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
state=WAITING;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
case WAITING:
|
|
Packit |
8f70b4 |
if(RespQueueSize()==1 && mode==RETRIEVE)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
state=FILE_RECV;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(RespQueueSize()==1 && mode==STORE)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
state=FILE_SEND;
|
|
Packit |
8f70b4 |
real_pos=0;
|
|
Packit |
8f70b4 |
pos=0;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(RespQueueSize()==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
state=DONE;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case FILE_RECV:
|
|
Packit |
8f70b4 |
if(recv_buf->Size()>=rate_limit->BytesAllowedToGet())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
recv_buf->Suspend();
|
|
Packit |
8f70b4 |
Timeout(1000);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(recv_buf->Size()>=max_buf)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
recv_buf->Suspend();
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(recv_buf->IsSuspended())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
recv_buf->Resume();
|
|
Packit |
8f70b4 |
if(recv_buf->Size()>0 || (recv_buf->Size()==0 && recv_buf->Eof()))
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case FILE_SEND:
|
|
Packit |
8f70b4 |
case DONE:
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Fish::MoveConnectionHere(Fish *o)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
super::MoveConnectionHere(o);
|
|
Packit |
8f70b4 |
rate_limit=o->rate_limit.borrow();
|
|
Packit |
8f70b4 |
path_queue.MoveHere(o->path_queue);
|
|
Packit |
8f70b4 |
RespQueue.move_here(o->RespQueue);
|
|
Packit |
8f70b4 |
timeout_timer.Reset(o->timeout_timer);
|
|
Packit |
8f70b4 |
set_real_cwd(o->real_cwd);
|
|
Packit |
8f70b4 |
state=CONNECTED;
|
|
Packit |
8f70b4 |
o->Disconnect();
|
|
Packit |
8f70b4 |
if(!home)
|
|
Packit |
8f70b4 |
set_home(home_auto);
|
|
Packit |
8f70b4 |
ResumeInternal();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Fish::DisconnectLL()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
super::DisconnectLL();
|
|
Packit |
8f70b4 |
EmptyRespQueue();
|
|
Packit |
8f70b4 |
EmptyPathQueue();
|
|
Packit |
8f70b4 |
state=DISCONNECTED;
|
|
Packit |
8f70b4 |
if(mode==STORE)
|
|
Packit |
8f70b4 |
SetError(STORE_FAILED,0);
|
|
Packit |
8f70b4 |
home_auto.set(FindHomeAuto());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Fish::Init()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
state=DISCONNECTED;
|
|
Packit |
8f70b4 |
max_send=0;
|
|
Packit |
8f70b4 |
eof=false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Fish::Fish() : SSH_Access("FISH:")
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
Reconfig(0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Fish::~Fish()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Fish::Fish(const Fish *o) : super(o)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
Reconfig(0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Fish::Close()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
switch(state)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case(DISCONNECTED):
|
|
Packit |
8f70b4 |
case(CONNECTED):
|
|
Packit |
8f70b4 |
case(DONE):
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(WAITING):
|
|
Packit |
8f70b4 |
if(mode==STORE || mode==RETRIEVE)
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(FILE_SEND):
|
|
Packit |
8f70b4 |
if(!RespQueueIsEmpty())
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(FILE_RECV):
|
|
Packit |
8f70b4 |
case(CONNECTING):
|
|
Packit |
8f70b4 |
case(CONNECTING_1):
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
// if(!RespQueueIsEmpty())
|
|
Packit |
8f70b4 |
// Disconnect(); // play safe.
|
|
Packit |
8f70b4 |
CloseExpectQueue();
|
|
Packit |
8f70b4 |
state=(recv_buf?CONNECTED:DISCONNECTED);
|
|
Packit |
8f70b4 |
eof=false;
|
|
Packit |
8f70b4 |
encode_file=true;
|
|
Packit |
8f70b4 |
super::Close();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Fish::Send(const char *format,...)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
va_list va;
|
|
Packit |
8f70b4 |
va_start(va,format);
|
|
Packit |
8f70b4 |
xstring& str=xstring::vformat(format,va);
|
|
Packit |
8f70b4 |
va_end(va);
|
|
Packit |
8f70b4 |
LogSend(5,str);
|
|
Packit |
8f70b4 |
send_buf->Put(str);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Fish::SendArrayInfoRequests()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(int i=fileset_for_info->curr_index(); i<fileset_for_info->count(); i++)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FileInfo *fi=(*fileset_for_info)[i];
|
|
Packit |
8f70b4 |
if(fi->need)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *e=shell_encode(fi->name);
|
|
Packit |
8f70b4 |
Send("#INFO %s\n"
|
|
Packit |
8f70b4 |
"ls -lLd %s; echo '### 200'\n",fi->name.get(),e);
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_INFO);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Fish::SendMethod()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *e=file?alloca_strdup(shell_encode(file)):0;
|
|
Packit |
8f70b4 |
const char *e1=shell_encode(file1);
|
|
Packit |
8f70b4 |
switch((open_mode)mode)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case CHANGE_DIR:
|
|
Packit |
8f70b4 |
Send("#CWD %s\n"
|
|
Packit |
8f70b4 |
"cd %s; echo '### 000'\n",e,e);
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_CWD);
|
|
Packit |
8f70b4 |
PushDirectory(file);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case LONG_LIST:
|
|
Packit |
8f70b4 |
if(!encode_file)
|
|
Packit |
8f70b4 |
e=file;
|
|
Packit |
8f70b4 |
Send("#LIST %s\n"
|
|
Packit |
8f70b4 |
"ls -la %s; echo '### 200'\n",e,e);
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_DIR);
|
|
Packit |
8f70b4 |
real_pos=0;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case LIST:
|
|
Packit |
8f70b4 |
if(!encode_file)
|
|
Packit |
8f70b4 |
e=file;
|
|
Packit |
8f70b4 |
Send("#LIST %s\n"
|
|
Packit |
8f70b4 |
"ls -a %s; echo '### 200'\n",e,e);
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_DIR);
|
|
Packit |
8f70b4 |
real_pos=0;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case RETRIEVE:
|
|
Packit |
8f70b4 |
if(pos>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int bs=0x1000;
|
|
Packit |
8f70b4 |
real_pos=pos-pos%bs;
|
|
Packit |
8f70b4 |
// non-standard extension
|
|
Packit |
8f70b4 |
Send("#RETRP %lld %s\n"
|
|
Packit |
8f70b4 |
"ls -lLd %s; "
|
|
Packit |
8f70b4 |
"echo '### 100'; "
|
|
Packit |
8f70b4 |
"dd ibs=%d skip=%lld if=%s 2>/dev/null; "
|
|
Packit |
8f70b4 |
"echo '### 200'\n",
|
|
Packit |
8f70b4 |
(long long)real_pos,e,e,bs,(long long)real_pos/bs,e);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Send("#RETR %s\n"
|
|
Packit |
8f70b4 |
"ls -lLd %s; "
|
|
Packit |
8f70b4 |
"echo '### 100'; cat %s; echo '### 200'\n",e,e,e);
|
|
Packit |
8f70b4 |
real_pos=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_RETR_INFO);
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_RETR);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case STORE:
|
|
Packit |
8f70b4 |
if(entity_size<0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(NO_FILE,"Have to know file size before upload");
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(entity_size>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Send("#STOR %lld %s\n"
|
|
Packit |
8f70b4 |
"rest=%lld;file=%s;:>$file;echo '### 001';"
|
|
Packit |
8f70b4 |
"if echo 1|head -c 1 -q ->/dev/null 2>&1;then "
|
|
Packit |
8f70b4 |
"head -c $rest -q -|(cat>$file;cat>/dev/null);"
|
|
Packit |
8f70b4 |
"else while [ $rest -gt 0 ];do "
|
|
Packit |
8f70b4 |
"bs=4096;cnt=`expr $rest / $bs`;"
|
|
Packit |
8f70b4 |
"[ $cnt -eq 0 ] && { cnt=1;bs=$rest; }; "
|
|
Packit |
8f70b4 |
"n=`dd ibs=$bs count=$cnt 2>/dev/null|tee -a $file|wc -c`;"
|
|
Packit |
8f70b4 |
"[ \"$n\" -le 0 ] && exit;"
|
|
Packit |
8f70b4 |
"rest=`expr $rest - $n`; "
|
|
Packit |
8f70b4 |
"done;fi;echo '### 200'\n",
|
|
Packit |
8f70b4 |
(long long)entity_size,e,(long long)entity_size,e);
|
|
Packit |
8f70b4 |
#if 0
|
|
Packit |
8f70b4 |
// dd pays attension to read boundaries and reads wrong number
|
|
Packit |
8f70b4 |
// of bytes when ibs>1. Have to use the inefficient ibs=1.
|
|
Packit |
8f70b4 |
Send("#STOR %lld %s\n"
|
|
Packit |
8f70b4 |
">%s;echo '### 001';"
|
|
Packit |
8f70b4 |
"dd ibs=1 count=%lld 2>/dev/null"
|
|
Packit |
8f70b4 |
"|(cat>%s;cat>/dev/null);echo '### 200'\n",
|
|
Packit |
8f70b4 |
(long long)entity_size,e,
|
|
Packit |
8f70b4 |
e,
|
|
Packit |
8f70b4 |
(long long)entity_size,
|
|
Packit |
8f70b4 |
e);
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Send("#STOR %lld %s\n"
|
|
Packit |
8f70b4 |
">%s;echo '### 001';echo '### 200'\n",
|
|
Packit |
8f70b4 |
(long long)entity_size,e,e);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_STOR_PRELIMINARY);
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_STOR);
|
|
Packit |
8f70b4 |
real_pos=0;
|
|
Packit |
8f70b4 |
pos=0;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case ARRAY_INFO:
|
|
Packit |
8f70b4 |
SendArrayInfoRequests();
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case REMOVE:
|
|
Packit |
8f70b4 |
Send("#DELE %s\n"
|
|
Packit |
8f70b4 |
"rm -f %s; echo '### 000'\n",e,e);
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_DEFAULT);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case REMOVE_DIR:
|
|
Packit |
8f70b4 |
Send("#RMD %s\n"
|
|
Packit |
8f70b4 |
"rmdir %s; echo '### 000'\n",e,e);
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_DEFAULT);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case MAKE_DIR:
|
|
Packit |
8f70b4 |
Send("#MKD %s\n"
|
|
Packit |
8f70b4 |
"mkdir %s; echo '### 000'\n",e,e);
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_DEFAULT);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case RENAME:
|
|
Packit |
8f70b4 |
Send("#RENAME %s %s\n"
|
|
Packit |
8f70b4 |
"mv %s %s; echo '### 000'\n",e,e1,e,e1);
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_DEFAULT);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case CHANGE_MODE:
|
|
Packit |
8f70b4 |
Send("#CHMOD %04o %s\n"
|
|
Packit |
8f70b4 |
"chmod %04o %s; echo '### 000'\n",chmod_mode,e,chmod_mode,e);
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_DEFAULT);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case LINK:
|
|
Packit |
8f70b4 |
Send("#LINK %s %s\n"
|
|
Packit |
8f70b4 |
"ln %s %s; echo '### 000'\n",e,e1,e,e1);
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_DEFAULT);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case SYMLINK:
|
|
Packit |
8f70b4 |
Send("#SYMLINK %s %s\n"
|
|
Packit |
8f70b4 |
"ln -s %s %s; echo '### 000'\n",e,e1,e,e1);
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_DEFAULT);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case QUOTE_CMD:
|
|
Packit |
8f70b4 |
// non-standard extension
|
|
Packit |
8f70b4 |
Send("#EXEC %s\n"
|
|
Packit |
8f70b4 |
"%s; echo '### 200'\n",e,file.get());
|
|
Packit |
8f70b4 |
PushExpect(EXPECT_QUOTE);
|
|
Packit |
8f70b4 |
real_pos=0;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case MP_LIST:
|
|
Packit |
8f70b4 |
SetError(NOT_SUPP);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case CONNECT_VERIFY:
|
|
Packit |
8f70b4 |
case CLOSED:
|
|
Packit |
8f70b4 |
abort();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int Fish::ReplyLogPriority(int code)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(code==-1)
|
|
Packit |
8f70b4 |
return 3;
|
|
Packit |
8f70b4 |
return 4;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int Fish::HandleReplies()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
if(recv_buf==0)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(state==FILE_RECV) {
|
|
Packit |
8f70b4 |
const char *err=pty_recv_buf->Get();
|
|
Packit |
8f70b4 |
if(err && err[0]) {
|
|
Packit |
8f70b4 |
const char *eol=strchr(err,'\n');
|
|
Packit |
8f70b4 |
if(eol) {
|
|
Packit |
8f70b4 |
xstring &e=xstring::get_tmp(err,eol-err);
|
|
Packit |
8f70b4 |
LogError(0,"%s",e.get());
|
|
Packit |
8f70b4 |
SetError(NO_FILE,e);
|
|
Packit |
8f70b4 |
if(pty_recv_buf)
|
|
Packit |
8f70b4 |
pty_recv_buf->Skip(eol-err+1);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(pty_recv_buf->Eof()) {
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(entity_size!=NO_SIZE && real_pos
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(entity_size==NO_SIZE)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
recv_buf->Put(pty_recv_buf->Get(),pty_recv_buf->Size()); // join the messages.
|
|
Packit |
8f70b4 |
pty_recv_buf->Skip(pty_recv_buf->Size());
|
|
Packit |
8f70b4 |
if(recv_buf->Size()<5)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
hup:
|
|
Packit |
8f70b4 |
if(recv_buf->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(recv_buf->Eof())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
LogError(0,_("Peer closed connection"));
|
|
Packit |
8f70b4 |
// Solaris' shell exists when is given with wrong directory
|
|
Packit |
8f70b4 |
if(!RespQueueIsEmpty() && RespQueue[0]==EXPECT_CWD && message)
|
|
Packit |
8f70b4 |
SetError(NO_FILE,message);
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *b;
|
|
Packit |
8f70b4 |
int s;
|
|
Packit |
8f70b4 |
recv_buf->Get(&b,&s);
|
|
Packit |
8f70b4 |
const char *eol=(const char*)memchr(b,'\n',s);
|
|
Packit |
8f70b4 |
if(!eol)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(recv_buf->Eof() || recv_buf->Error())
|
|
Packit |
8f70b4 |
goto hup;
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
s=eol-b+1;
|
|
Packit |
8f70b4 |
line.nset(b,s-1);
|
|
Packit |
8f70b4 |
recv_buf->Skip(s);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int code=-1;
|
|
Packit |
8f70b4 |
if(s>7 && !memcmp(line,"### ",4)) {
|
|
Packit |
8f70b4 |
if(sscanf(line+4,"%3d",&code)!=1)
|
|
Packit |
8f70b4 |
code=-1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
LogRecv(ReplyLogPriority(code),line);
|
|
Packit |
8f70b4 |
if(code==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(message==0)
|
|
Packit |
8f70b4 |
message.set(line);
|
|
Packit |
8f70b4 |
else {
|
|
Packit |
8f70b4 |
message.append('\n');
|
|
Packit |
8f70b4 |
message.append(line);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(RespQueueIsEmpty())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
LogError(3,_("extra server response"));
|
|
Packit |
8f70b4 |
message.set(0);
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
expect_t e=RespQueue.next();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool keep_message=false;
|
|
Packit |
8f70b4 |
switch(e)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case EXPECT_FISH:
|
|
Packit |
8f70b4 |
case EXPECT_VER:
|
|
Packit |
8f70b4 |
/* nothing yet */
|
|
Packit |
8f70b4 |
break;;
|
|
Packit |
8f70b4 |
case EXPECT_PWD:
|
|
Packit |
8f70b4 |
if(!message)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
home_auto.set(message);
|
|
Packit |
8f70b4 |
LogNote(9,"home set to %s\n",home_auto.get());
|
|
Packit |
8f70b4 |
PropagateHomeAuto();
|
|
Packit |
8f70b4 |
if(!home)
|
|
Packit |
8f70b4 |
set_home(home_auto);
|
|
Packit |
8f70b4 |
cache->SetDirectory(this, home, true);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case EXPECT_CWD: {
|
|
Packit |
8f70b4 |
xstring p;
|
|
Packit |
8f70b4 |
PopDirectory(&p);
|
|
Packit |
8f70b4 |
if(message==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
set_real_cwd(p);
|
|
Packit |
8f70b4 |
if(mode==CHANGE_DIR && RespQueueIsEmpty())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
cwd.Set(p);
|
|
Packit |
8f70b4 |
eof=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
cache->SetDirectory(this,p,true);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
SetError(NO_FILE,message);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
case EXPECT_RETR_INFO:
|
|
Packit |
8f70b4 |
if(message && is_ascii_digit(message[0]) && !strchr(message,':'))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
long long size_ll;
|
|
Packit |
8f70b4 |
if(1==sscanf(message,"%lld",&size_ll))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
entity_size=size_ll;
|
|
Packit |
8f70b4 |
if(opt_size)
|
|
Packit |
8f70b4 |
*opt_size=entity_size;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(message && message[0]!='#')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FileInfo *fi=FileInfo::parse_ls_line(message,"GMT");
|
|
Packit |
8f70b4 |
if(!fi || !strncmp(message,"ls: ",4))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(NO_FILE,message);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(fi->defined&fi->SIZE)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
entity_size=fi->size;
|
|
Packit |
8f70b4 |
if(opt_size)
|
|
Packit |
8f70b4 |
*opt_size=entity_size;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(fi->defined&fi->DATE)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
entity_date=fi->date;
|
|
Packit |
8f70b4 |
if(opt_date)
|
|
Packit |
8f70b4 |
*opt_date=entity_date;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
state=FILE_RECV;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case EXPECT_INFO:
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Ref<FileInfo> new_info(FileInfo::parse_ls_line(message,"GMT"));
|
|
Packit |
8f70b4 |
FileInfo *fi=fileset_for_info->curr();
|
|
Packit |
8f70b4 |
while(!fi->need)
|
|
Packit |
8f70b4 |
fi=fileset_for_info->next();
|
|
Packit |
8f70b4 |
fi->Merge(*new_info);
|
|
Packit |
8f70b4 |
fi->need=0;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
case EXPECT_RETR:
|
|
Packit |
8f70b4 |
case EXPECT_DIR:
|
|
Packit |
8f70b4 |
case EXPECT_QUOTE:
|
|
Packit |
8f70b4 |
eof=true;
|
|
Packit |
8f70b4 |
state=DONE;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case EXPECT_DEFAULT:
|
|
Packit |
8f70b4 |
if(message)
|
|
Packit |
8f70b4 |
SetError(NO_FILE,message);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case EXPECT_STOR_PRELIMINARY:
|
|
Packit |
8f70b4 |
if(message)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
SetError(NO_FILE,message);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case EXPECT_STOR:
|
|
Packit |
8f70b4 |
if(message)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
SetError(NO_FILE,message);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case EXPECT_IGNORE:
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!keep_message)
|
|
Packit |
8f70b4 |
message.set(0);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void Fish::PushExpect(expect_t e)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
RespQueue.push(e);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void Fish::CloseExpectQueue()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int count=RespQueue.count();
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
switch(RespQueue[i])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case EXPECT_IGNORE:
|
|
Packit |
8f70b4 |
case EXPECT_FISH:
|
|
Packit |
8f70b4 |
case EXPECT_VER:
|
|
Packit |
8f70b4 |
case EXPECT_PWD:
|
|
Packit |
8f70b4 |
case EXPECT_CWD:
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case EXPECT_INFO:
|
|
Packit |
8f70b4 |
case EXPECT_DIR:
|
|
Packit |
8f70b4 |
case EXPECT_DEFAULT:
|
|
Packit |
8f70b4 |
RespQueue[i]=EXPECT_IGNORE;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case EXPECT_QUOTE:
|
|
Packit |
8f70b4 |
case EXPECT_RETR_INFO:
|
|
Packit |
8f70b4 |
case EXPECT_RETR:
|
|
Packit |
8f70b4 |
case EXPECT_STOR_PRELIMINARY:
|
|
Packit |
8f70b4 |
case EXPECT_STOR:
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *memstr(const char *mem,size_t len,const char *str)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
size_t str_len=strlen(str);
|
|
Packit |
8f70b4 |
while(len>=str_len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!memcmp(mem,str,str_len))
|
|
Packit |
8f70b4 |
return mem;
|
|
Packit |
8f70b4 |
mem++;
|
|
Packit |
8f70b4 |
len--;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int Fish::Read(Buffer *buf,int size)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(Error())
|
|
Packit |
8f70b4 |
return error_code;
|
|
Packit |
8f70b4 |
if(mode==CLOSED)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
if(state==DONE)
|
|
Packit |
8f70b4 |
return 0; // eof
|
|
Packit |
8f70b4 |
if(state==FILE_RECV && real_pos>=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *buf1;
|
|
Packit |
8f70b4 |
int size1;
|
|
Packit |
8f70b4 |
get_again:
|
|
Packit |
8f70b4 |
if(recv_buf->Size()==0 && recv_buf->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
recv_buf->Get(&buf1,&size1);
|
|
Packit |
8f70b4 |
if(buf1==0) // eof
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(size1==0)
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
if(entity_size!=NO_SIZE && real_pos
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(real_pos+size1>entity_size)
|
|
Packit |
8f70b4 |
size1=entity_size-real_pos;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *end=memstr(buf1,size1,"### ");
|
|
Packit |
8f70b4 |
if(end)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
size1=end-buf1;
|
|
Packit |
8f70b4 |
if(size1==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
state=WAITING;
|
|
Packit |
8f70b4 |
if(HandleReplies()==MOVED)
|
|
Packit |
8f70b4 |
current->Timeout(0);
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(int j=0; j<3; j++)
|
|
Packit |
8f70b4 |
if(size1>0 && buf1[size1-1]=='#')
|
|
Packit |
8f70b4 |
size1--;
|
|
Packit |
8f70b4 |
if(size1==0 && recv_buf->Eof())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int bytes_allowed=rate_limit->BytesAllowedToGet();
|
|
Packit |
8f70b4 |
if(size1>bytes_allowed)
|
|
Packit |
8f70b4 |
size1=bytes_allowed;
|
|
Packit |
8f70b4 |
if(size1==0)
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
if(norest_manual && real_pos==0 && pos>0)
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
if(real_pos
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
off_t to_skip=pos-real_pos;
|
|
Packit |
8f70b4 |
if(to_skip>size1)
|
|
Packit |
8f70b4 |
to_skip=size1;
|
|
Packit |
8f70b4 |
recv_buf->Skip(to_skip);
|
|
Packit |
8f70b4 |
real_pos+=to_skip;
|
|
Packit |
8f70b4 |
goto get_again;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(size>size1)
|
|
Packit |
8f70b4 |
size=size1;
|
|
Packit |
8f70b4 |
size=buf->MoveDataHere(recv_buf,size);
|
|
Packit |
8f70b4 |
if(size<=0)
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
pos+=size;
|
|
Packit |
8f70b4 |
real_pos+=size;
|
|
Packit |
8f70b4 |
rate_limit->BytesGot(size);
|
|
Packit |
8f70b4 |
TrySuccess();
|
|
Packit |
8f70b4 |
return size;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int Fish::Write(const void *buf,int size)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(mode!=STORE)
|
|
Packit |
8f70b4 |
return(0);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Resume();
|
|
Packit |
8f70b4 |
Do();
|
|
Packit |
8f70b4 |
if(Error())
|
|
Packit |
8f70b4 |
return(error_code);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(state!=FILE_SEND || rate_limit==0)
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int allowed=rate_limit->BytesAllowedToPut();
|
|
Packit |
8f70b4 |
if(allowed==0)
|
|
Packit |
8f70b4 |
return DO_AGAIN;
|
|
Packit |
8f70b4 |
if(size+send_buf->Size()>allowed)
|
|
Packit |
8f70b4 |
size=allowed-send_buf->Size();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(size+send_buf->Size()>0x4000)
|
|
Packit |
8f70b4 |
size=0x4000-send_buf->Size();
|
|
Packit |
8f70b4 |
if(pos+size>entity_size)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
size=entity_size-pos;
|
|
Packit |
8f70b4 |
// tried to write more than originally requested. Make it retry with Open:
|
|
Packit |
8f70b4 |
if(size==0)
|
|
Packit |
8f70b4 |
return STORE_FAILED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(size<=0)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
send_buf->Put((char*)buf,size);
|
|
Packit |
8f70b4 |
TrySuccess();
|
|
Packit |
8f70b4 |
rate_limit->BytesPut(size);
|
|
Packit |
8f70b4 |
pos+=size;
|
|
Packit |
8f70b4 |
real_pos+=size;
|
|
Packit |
8f70b4 |
return(size);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int Fish::Buffered()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(send_buf==0)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
return send_buf->Size();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int Fish::StoreStatus()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(Error())
|
|
Packit |
8f70b4 |
return error_code;
|
|
Packit |
8f70b4 |
if(state!=FILE_SEND)
|
|
Packit |
8f70b4 |
return IN_PROGRESS;
|
|
Packit |
8f70b4 |
if(real_pos!=entity_size)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Disconnect();
|
|
Packit |
8f70b4 |
return IN_PROGRESS;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(RespQueueSize()==0)
|
|
Packit |
8f70b4 |
return OK;
|
|
Packit |
8f70b4 |
return IN_PROGRESS;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int Fish::Done()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(mode==CLOSED)
|
|
Packit |
8f70b4 |
return OK;
|
|
Packit |
8f70b4 |
if(Error())
|
|
Packit |
8f70b4 |
return error_code;
|
|
Packit |
8f70b4 |
if(eof || state==DONE)
|
|
Packit |
8f70b4 |
return OK;
|
|
Packit |
8f70b4 |
if(mode==CONNECT_VERIFY)
|
|
Packit |
8f70b4 |
return OK;
|
|
Packit |
8f70b4 |
return IN_PROGRESS;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Fish::SuspendInternal()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
super::SuspendInternal();
|
|
Packit |
8f70b4 |
if(recv_buf)
|
|
Packit |
8f70b4 |
recv_buf->SuspendSlave();
|
|
Packit |
8f70b4 |
if(send_buf)
|
|
Packit |
8f70b4 |
send_buf->SuspendSlave();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void Fish::ResumeInternal()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(recv_buf)
|
|
Packit |
8f70b4 |
recv_buf->ResumeSlave();
|
|
Packit |
8f70b4 |
if(send_buf)
|
|
Packit |
8f70b4 |
send_buf->ResumeSlave();
|
|
Packit |
8f70b4 |
super::ResumeInternal();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *Fish::CurrentStatus()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
switch(state)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case DISCONNECTED:
|
|
Packit |
8f70b4 |
if(!ReconnectAllowed())
|
|
Packit |
8f70b4 |
return DelayingMessage();
|
|
Packit |
8f70b4 |
return _("Not connected");
|
|
Packit |
8f70b4 |
case CONNECTING:
|
|
Packit |
8f70b4 |
if(ssh && ssh->status)
|
|
Packit |
8f70b4 |
return ssh->status;
|
|
Packit |
8f70b4 |
case CONNECTING_1:
|
|
Packit |
8f70b4 |
return _("Connecting...");
|
|
Packit |
8f70b4 |
case CONNECTED:
|
|
Packit |
8f70b4 |
return _("Connected");
|
|
Packit |
8f70b4 |
case WAITING:
|
|
Packit |
8f70b4 |
return _("Waiting for response...");
|
|
Packit |
8f70b4 |
case FILE_RECV:
|
|
Packit |
8f70b4 |
return _("Receiving data");
|
|
Packit |
8f70b4 |
case FILE_SEND:
|
|
Packit |
8f70b4 |
return _("Sending data");
|
|
Packit |
8f70b4 |
case DONE:
|
|
Packit |
8f70b4 |
return _("Done");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool Fish::SameSiteAs(const FileAccess *fa) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!SameProtoAs(fa))
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
Fish *o=(Fish*)fa;
|
|
Packit |
8f70b4 |
return(!xstrcasecmp(hostname,o->hostname) && !xstrcmp(portname,o->portname)
|
|
Packit |
8f70b4 |
&& !xstrcmp(user,o->user) && !xstrcmp(pass,o->pass));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool Fish::SameLocationAs(const FileAccess *fa) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!SameSiteAs(fa))
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
Fish *o=(Fish*)fa;
|
|
Packit |
8f70b4 |
if(xstrcmp(cwd,o->cwd))
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Fish::Reconfig(const char *name)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
super::Reconfig(name);
|
|
Packit |
8f70b4 |
if(!xstrcmp(name,"fish:charset") && recv_buf && send_buf)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!IsSuspended())
|
|
Packit |
8f70b4 |
cache->TreeChanged(this,"/");
|
|
Packit |
8f70b4 |
const char *charset=ResMgr::Query("fish:charset",hostname);
|
|
Packit |
8f70b4 |
if(charset && *charset)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
send_buf->SetTranslation(charset,false);
|
|
Packit |
8f70b4 |
recv_buf->SetTranslation(charset,true);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
send_buf->SetTranslator(0);
|
|
Packit |
8f70b4 |
recv_buf->SetTranslator(0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Fish::ClassInit()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// register the class
|
|
Packit |
8f70b4 |
Register("fish",Fish::New);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileAccess *Fish::New() { return new Fish(); }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
DirList *Fish::MakeDirList(ArgV *args)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return new FishDirList(this,args);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#include "FileGlob.h"
|
|
Packit |
8f70b4 |
Glob *Fish::MakeGlob(const char *pattern)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return new GenericGlob(this,pattern);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ListInfo *Fish::MakeListInfo(const char *p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return new FishListInfo(this,p);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#undef super
|
|
Packit |
8f70b4 |
#define super DirList
|
|
Packit |
8f70b4 |
#include "ArgV.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int FishDirList::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(done)
|
|
Packit |
8f70b4 |
return STALL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(buf->Eof())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!ubuf)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *cache_buffer=0;
|
|
Packit |
8f70b4 |
int cache_buffer_size=0;
|
|
Packit |
8f70b4 |
int err;
|
|
Packit |
8f70b4 |
if(use_cache && FileAccess::cache->Find(session,pattern,FA::LONG_LIST,&err,
|
|
Packit |
8f70b4 |
&cache_buffer,&cache_buffer_size))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetErrorCached(cache_buffer);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ubuf=new IOBuffer(IOBuffer::GET);
|
|
Packit |
8f70b4 |
ubuf->Put(cache_buffer,cache_buffer_size);
|
|
Packit |
8f70b4 |
ubuf->PutEOF();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
session->Open(pattern,FA::LONG_LIST);
|
|
Packit |
8f70b4 |
session.Cast<Fish>()->DontEncodeFile();
|
|
Packit |
8f70b4 |
ubuf=new IOBufferFileAccess(session);
|
|
Packit |
8f70b4 |
if(FileAccess::cache->IsEnabled(session->GetHostName()))
|
|
Packit |
8f70b4 |
ubuf->Save(FileAccess::cache->SizeLimit());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *b;
|
|
Packit |
8f70b4 |
int len;
|
|
Packit |
8f70b4 |
ubuf->Get(&b,&len;;
|
|
Packit |
8f70b4 |
if(b==0) // eof
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
buf->PutEOF();
|
|
Packit |
8f70b4 |
FileAccess::cache->Add(session,pattern,FA::LONG_LIST,FA::OK,ubuf);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(len>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
buf->Put(b,len);
|
|
Packit |
8f70b4 |
ubuf->Skip(len);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(ubuf->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(ubuf->ErrorText());
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *FishDirList::Status()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(ubuf && !ubuf->Eof() && session->IsOpen())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return xstring::format(_("Getting file list (%lld) [%s]"),
|
|
Packit |
8f70b4 |
(long long)session->GetPos(),session->CurrentStatus());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FishDirList::SuspendInternal()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
super::SuspendInternal();
|
|
Packit |
8f70b4 |
if(ubuf)
|
|
Packit |
8f70b4 |
ubuf->SuspendSlave();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FishDirList::ResumeInternal()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(ubuf)
|
|
Packit |
8f70b4 |
ubuf->ResumeSlave();
|
|
Packit |
8f70b4 |
super::ResumeInternal();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static FileSet *ls_to_FileSet(const char *b,int len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FileSet *set=new FileSet;
|
|
Packit |
8f70b4 |
while(len>0) {
|
|
Packit |
8f70b4 |
// find one line
|
|
Packit |
8f70b4 |
const char *line=b;
|
|
Packit |
8f70b4 |
int ll=len;
|
|
Packit |
8f70b4 |
const char *eol=find_char(b,len,'\n');
|
|
Packit |
8f70b4 |
if(eol) {
|
|
Packit |
8f70b4 |
ll=eol-b;
|
|
Packit |
8f70b4 |
len-=ll+1;
|
|
Packit |
8f70b4 |
b+=ll+1;
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
len=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(ll && line[ll-1]=='\r')
|
|
Packit |
8f70b4 |
--ll;
|
|
Packit |
8f70b4 |
if(ll==0)
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileInfo *f=FileInfo::parse_ls_line(line,ll,"GMT");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!f)
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
set->Add(f);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return set;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileSet *Fish::ParseLongList(const char *b,int len,int *err) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(err)
|
|
Packit |
8f70b4 |
*err=0;
|
|
Packit |
8f70b4 |
return ls_to_FileSet(b,len);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// FishListInfo implementation
|
|
Packit |
8f70b4 |
FileSet *FishListInfo::Parse(const char *b,int len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return ls_to_FileSet(b,len);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "modconfig.h"
|
|
Packit |
8f70b4 |
#ifdef MODULE_PROTO_FISH
|
|
Packit |
8f70b4 |
void module_init()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Fish::ClassInit();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif
|