|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2012 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 |
|
|
Packit |
8f70b4 |
#include "FileCopyFtp.h"
|
|
Packit |
8f70b4 |
#include "log.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define super FileCopy
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#if !USE_SSL
|
|
Packit |
8f70b4 |
#define protect false
|
|
Packit |
8f70b4 |
#define passive_ssl_connect true
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define ftp_src get->GetSession().Cast<Ftp>()
|
|
Packit |
8f70b4 |
#define ftp_dst put->GetSession().Cast<Ftp>()
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyFtp::Close()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ftp_src->Close();
|
|
Packit |
8f70b4 |
ftp_dst->Close();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int FileCopyFtp::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int src_res,dst_res;
|
|
Packit |
8f70b4 |
int m=super::Do();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(disable_fxp || Error() || !put || !get)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(state==PUT_WAIT && put->GetSeekPos()!=FILE_END)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(get->GetSize()>=0 && put->GetSeekPos()>=get->GetSize())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(ftp_dst->IsClosed())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
put->OpenSession();
|
|
Packit |
8f70b4 |
ftp_dst->SetCopyMode(Ftp::COPY_DEST,!passive_source,protect,
|
|
Packit |
8f70b4 |
passive_source^passive_ssl_connect,dst_retries,dst_try_time);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(state!=DO_COPY || put->GetSeekPos()==FILE_END || get->Eof())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// FileCopy can suspend peers.
|
|
Packit |
8f70b4 |
get->Resume();
|
|
Packit |
8f70b4 |
put->Resume();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(ftp_src->IsClosed())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
get->OpenSession();
|
|
Packit |
8f70b4 |
ftp_src->SetCopyMode(Ftp::COPY_SOURCE,passive_source,protect,
|
|
Packit |
8f70b4 |
!(passive_source^passive_ssl_connect),src_retries,src_try_time);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(ftp_dst->IsClosed())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
put->OpenSession();
|
|
Packit |
8f70b4 |
ftp_dst->SetCopyMode(Ftp::COPY_DEST,!passive_source,protect,
|
|
Packit |
8f70b4 |
passive_source^passive_ssl_connect,dst_retries,dst_try_time);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// check for errors
|
|
Packit |
8f70b4 |
if(ftp_src->CopyFailed() || ftp_dst->CopyFailed())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(ftp_src->RestartFailed() || ftp_dst->RestartFailed())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
get->CannotSeek(put->GetSize());
|
|
Packit |
8f70b4 |
put->CannotSeek(put->GetSize());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(passive_source==orig_passive_source)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
passive_source=!passive_source;
|
|
Packit |
8f70b4 |
Log::global->Write(0,_("**** FXP: trying to reverse ftp:fxp-passive-source\n"));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#if USE_SSL
|
|
Packit |
8f70b4 |
else if(passive_ssl_connect==orig_passive_ssl_connect)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
passive_ssl_connect=!passive_ssl_connect;
|
|
Packit |
8f70b4 |
passive_source=orig_passive_source;
|
|
Packit |
8f70b4 |
Log::global->Write(0,_("**** FXP: trying to reverse ftp:fxp-passive-sscn\n"));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(protect
|
|
Packit |
8f70b4 |
&& !ResMgr::QueryBool("ftp:ssl-force",ftp_src->GetHostName())
|
|
Packit |
8f70b4 |
&& !ResMgr::QueryBool("ftp:ssl-force",ftp_dst->GetHostName()))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
passive_source=orig_passive_source;
|
|
Packit |
8f70b4 |
protect=false;
|
|
Packit |
8f70b4 |
Log::global->Write(0,_("**** FXP: trying to reverse ftp:ssl-protect-fxp\n"));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif // USE_SSL
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// both ways failed. Fall back to normal copying.
|
|
Packit |
8f70b4 |
Log::global->Write(0,_("**** FXP: giving up, reverting to plain copy\n"));
|
|
Packit |
8f70b4 |
Close();
|
|
Packit |
8f70b4 |
disable_fxp=true;
|
|
Packit |
8f70b4 |
get->SetFXP(false);
|
|
Packit |
8f70b4 |
put->SetFXP(false);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(ResMgr::QueryBool("ftp:fxp-force",ftp_src->GetHostName())
|
|
Packit |
8f70b4 |
|| ResMgr::QueryBool("ftp:fxp-force",ftp_dst->GetHostName()))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(_("ftp:fxp-force is set but FXP is not available"));
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
off_t pos=put->GetRealPos();
|
|
Packit |
8f70b4 |
if(!get->CanSeek(pos) || !put->CanSeek(pos))
|
|
Packit |
8f70b4 |
pos=0;
|
|
Packit |
8f70b4 |
get->Seek(pos);
|
|
Packit |
8f70b4 |
put->Seek(pos);
|
|
Packit |
8f70b4 |
RateReset();
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
RateReset();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
src_retries=ftp_src->GetRetries();
|
|
Packit |
8f70b4 |
dst_retries=ftp_dst->GetRetries();
|
|
Packit |
8f70b4 |
src_try_time=ftp_src->GetTryTime();
|
|
Packit |
8f70b4 |
dst_try_time=ftp_dst->GetTryTime();
|
|
Packit |
8f70b4 |
Close();
|
|
Packit |
8f70b4 |
if(put->CanSeek())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
put->Seek(FILE_END);
|
|
Packit |
8f70b4 |
get->Suspend();
|
|
Packit |
8f70b4 |
put->Resume();
|
|
Packit |
8f70b4 |
state=PUT_WAIT;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
put->Seek(0);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
src_res=ftp_src->Done();
|
|
Packit |
8f70b4 |
dst_res=ftp_dst->Done();
|
|
Packit |
8f70b4 |
if(src_res==FA::OK && dst_res==FA::OK)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Close();
|
|
Packit |
8f70b4 |
const long long size=GetSize();
|
|
Packit |
8f70b4 |
if(size>=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
get->SetPos(size);
|
|
Packit |
8f70b4 |
put->SetPos(size);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
get->PutEOF();
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(src_res!=FA::IN_PROGRESS && src_res!=FA::OK)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(ftp_src->StrError(src_res));
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(dst_res!=FA::IN_PROGRESS && dst_res!=FA::OK)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(ftp_dst->StrError(dst_res));
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// exchange copy address
|
|
Packit |
8f70b4 |
if(ftp_dst->SetCopyAddress(ftp_src) || ftp_src->SetCopyAddress(ftp_dst))
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!ftp_dst->CopyStoreAllowed()
|
|
Packit |
8f70b4 |
&& ftp_src->CopyIsReadyForStore() && ftp_dst->CopyIsReadyForStore())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ftp_dst->CopyAllowStore();
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
RateReset();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// check for timeout when one session is done, and the other is stuck
|
|
Packit |
8f70b4 |
if(dst_res==FA::OK && src_res==FA::IN_PROGRESS)
|
|
Packit |
8f70b4 |
ftp_src->CopyCheckTimeout(ftp_dst);
|
|
Packit |
8f70b4 |
if(src_res==FA::OK && dst_res==FA::IN_PROGRESS)
|
|
Packit |
8f70b4 |
ftp_dst->CopyCheckTimeout(ftp_src);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
off_t add=ftp_dst->GetPos()-put->GetRealPos();
|
|
Packit |
8f70b4 |
if(add>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
RateAdd(add);
|
|
Packit |
8f70b4 |
bytes_count+=add;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
off_t pos=ftp_dst->GetPos();
|
|
Packit |
8f70b4 |
get->SetPos(pos);
|
|
Packit |
8f70b4 |
put->SetPos(pos);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyFtp::Init()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
no_rest=false;
|
|
Packit |
8f70b4 |
orig_passive_source=passive_source=false;
|
|
Packit |
8f70b4 |
src_retries=dst_retries=0;
|
|
Packit |
8f70b4 |
src_try_time=dst_try_time=0;
|
|
Packit |
8f70b4 |
disable_fxp=false;
|
|
Packit |
8f70b4 |
#if USE_SSL
|
|
Packit |
8f70b4 |
protect=false;
|
|
Packit |
8f70b4 |
orig_passive_ssl_connect=passive_ssl_connect=true;
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// s,d must be FileCopyPeerFA, s->GetSession(),d->GetSession() must be Ftp.
|
|
Packit |
8f70b4 |
FileCopyFtp::FileCopyFtp(FileCopyPeer *s,FileCopyPeer *d,bool c,bool rp)
|
|
Packit |
8f70b4 |
: super(s,d,c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
passive_source=rp;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
get->SetFXP(true);
|
|
Packit |
8f70b4 |
put->SetFXP(true);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(ftp_src->IsPassive() && !ftp_dst->IsPassive())
|
|
Packit |
8f70b4 |
passive_source=true;
|
|
Packit |
8f70b4 |
else if(!ftp_src->IsPassive() && ftp_dst->IsPassive())
|
|
Packit |
8f70b4 |
passive_source=false;
|
|
Packit |
8f70b4 |
orig_passive_source=passive_source;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#if USE_SSL
|
|
Packit |
8f70b4 |
if(ResMgr::QueryBool("ftp:ssl-protect-fxp",ftp_src->GetHostName())
|
|
Packit |
8f70b4 |
|| ResMgr::QueryBool("ftp:ssl-protect-fxp",ftp_dst->GetHostName()))
|
|
Packit |
8f70b4 |
protect=true;
|
|
Packit |
8f70b4 |
passive_ssl_connect=ResMgr::QueryBool("ftp:fxp-passive-sscn",0);
|
|
Packit |
8f70b4 |
orig_passive_ssl_connect=passive_ssl_connect;
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileCopy *FileCopyFtp::New(FileCopyPeer *s,FileCopyPeer *d,bool c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const FileAccessRef& s_s=s->GetSession();
|
|
Packit |
8f70b4 |
const FileAccessRef& d_s=d->GetSession();
|
|
Packit |
8f70b4 |
if(!s_s || !d_s)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
if((strcmp(s_s->GetProto(),"ftp") && strcmp(s_s->GetProto(),"ftps"))
|
|
Packit |
8f70b4 |
|| (strcmp(d_s->GetProto(),"ftp") && strcmp(d_s->GetProto(),"ftps")))
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
if(!ResMgr::QueryBool("ftp:use-fxp",s_s->GetHostName())
|
|
Packit |
8f70b4 |
|| !ResMgr::QueryBool("ftp:use-fxp",d_s->GetHostName()))
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
return new FileCopyFtp(s,d,c,ResMgr::QueryBool("ftp:fxp-passive-source",0));
|
|
Packit |
8f70b4 |
}
|