|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2017 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 |
/* FileCopyPeer behaviour:
|
|
Packit |
8f70b4 |
1) when suspended, does nothing
|
|
Packit |
8f70b4 |
2) tries to read some data at seek_pos, sets pos to position of Get (get).
|
|
Packit |
8f70b4 |
2.5) tries to position to seek_pos and gets ready to write (put).
|
|
Packit |
8f70b4 |
3) if it cannot seek to seek_pos, changes pos to what it can seek.
|
|
Packit |
8f70b4 |
4) if it knows that it cannot seek to pos>0, CanSeek()==false
|
|
Packit |
8f70b4 |
5) if it knows that it cannot seek to pos==0, CanSeek0()==false
|
|
Packit |
8f70b4 |
6) it tries to get date/size if told to. (get)
|
|
Packit |
8f70b4 |
7) it sets date on the file if eof is reached and date is known (put).
|
|
Packit |
8f70b4 |
8) if put needs size/date before it writes data, NeedSizeDateBeforehand()==true.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <config.h>
|
|
Packit |
8f70b4 |
#include <assert.h>
|
|
Packit |
8f70b4 |
#include <unistd.h>
|
|
Packit |
8f70b4 |
#include <errno.h>
|
|
Packit |
8f70b4 |
#include <sys/types.h>
|
|
Packit |
8f70b4 |
#include <sys/stat.h>
|
|
Packit |
8f70b4 |
#include <fcntl.h>
|
|
Packit |
8f70b4 |
#include <math.h>
|
|
Packit |
8f70b4 |
#include <stddef.h>
|
|
Packit |
8f70b4 |
#include "FileCopy.h"
|
|
Packit |
8f70b4 |
#include "url.h"
|
|
Packit |
8f70b4 |
#include "log.h"
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "LsCache.h"
|
|
Packit |
8f70b4 |
#include "plural.h"
|
|
Packit |
8f70b4 |
#include "ArgV.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define skip_threshold 0x1000
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ResDecl rate_period ("xfer:rate-period","15", ResMgr::UNumberValidate,ResMgr::NoClosure);
|
|
Packit |
8f70b4 |
ResDecl eta_period ("xfer:eta-period", "120",ResMgr::UNumberValidate,ResMgr::NoClosure);
|
|
Packit |
8f70b4 |
ResDecl max_redir ("xfer:max-redirections", "5",ResMgr::UNumberValidate,ResMgr::NoClosure);
|
|
Packit |
8f70b4 |
ResDecl buffer_size ("xfer:buffer-size","0x10000",ResMgr::UNumberValidate,ResMgr::NoClosure);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// It's bad when lftp receives data in small chunks, try to accumulate
|
|
Packit |
8f70b4 |
// data in a kernel buffer using a delay and slurp it at once:
|
|
Packit |
8f70b4 |
enum {
|
|
Packit |
8f70b4 |
// Delays in microseconds
|
|
Packit |
8f70b4 |
MAX_DELAY=30000,
|
|
Packit |
8f70b4 |
DELAY_STEP=30,
|
|
Packit |
8f70b4 |
// This size is related to socket buffer size.
|
|
Packit |
8f70b4 |
// When it is too large, tcp slowdown happens.
|
|
Packit |
8f70b4 |
// SSL has packet size 0x4000, so we have to use a lower threshold.
|
|
Packit |
8f70b4 |
MAX_READ_TO_DELAY=0x3F00,
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// FileCopy
|
|
Packit |
8f70b4 |
#define super SMTask
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define set_state(s) do { state=(s); \
|
|
Packit |
8f70b4 |
Log::global->Format(11,"FileCopy(%p) enters state %s\n", this, #s); } while(0)
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int FileCopy::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
const char *b;
|
|
Packit |
8f70b4 |
int s;
|
|
Packit |
8f70b4 |
int rate_add;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(Error() || Done())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
switch(state)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
pre_INITIAL:
|
|
Packit |
8f70b4 |
set_state(INITIAL);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
case(INITIAL):
|
|
Packit |
8f70b4 |
if(remove_target_first && !put->FileRemoved())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
remove_target_first=false;
|
|
Packit |
8f70b4 |
if(cont && put->CanSeek())
|
|
Packit |
8f70b4 |
put->WantSize();
|
|
Packit |
8f70b4 |
if(put->NeedSizeDateBeforehand() || (cont && put->CanSeek() && put->GetSize()==NO_SIZE_YET))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(get->GetSize()==NO_SIZE_YET || get->GetDate()==NO_DATE_YET)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
put->Suspend();
|
|
Packit |
8f70b4 |
get->DontStartTransferYet();
|
|
Packit |
8f70b4 |
get->Resume();
|
|
Packit |
8f70b4 |
get->WantSize();
|
|
Packit |
8f70b4 |
if(put->NeedDate())
|
|
Packit |
8f70b4 |
get->WantDate();
|
|
Packit |
8f70b4 |
goto pre_GET_INFO_WAIT;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(get->GetSize()==NO_SIZE_YET)
|
|
Packit |
8f70b4 |
get->WantSize();
|
|
Packit |
8f70b4 |
if(get->GetSize()!=NO_SIZE && get->GetSize()!=NO_SIZE_YET)
|
|
Packit |
8f70b4 |
put->SetEntitySize(get->GetSize());
|
|
Packit |
8f70b4 |
if(get->GetDate()!=NO_DATE && get->GetDate()!=NO_DATE_YET)
|
|
Packit |
8f70b4 |
put->SetDate(get->GetDate());
|
|
Packit |
8f70b4 |
else if(get->GetDate()==NO_DATE_YET)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(put->NeedDate())
|
|
Packit |
8f70b4 |
get->WantDate();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(cont && put->CanSeek())
|
|
Packit |
8f70b4 |
put->Seek(FILE_END);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(put->range_start>0 && put->CanSeek())
|
|
Packit |
8f70b4 |
put->Seek(put->range_start);
|
|
Packit |
8f70b4 |
if(get->range_start>0 && get->CanSeek())
|
|
Packit |
8f70b4 |
get->Seek(get->range_start);
|
|
Packit |
8f70b4 |
goto pre_DO_COPY;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
get->Suspend();
|
|
Packit |
8f70b4 |
put->Resume();
|
|
Packit |
8f70b4 |
set_state(PUT_WAIT);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
/* fallthrough */
|
|
Packit |
8f70b4 |
case(PUT_WAIT):
|
|
Packit |
8f70b4 |
if(put->Error())
|
|
Packit |
8f70b4 |
goto put_error;
|
|
Packit |
8f70b4 |
if(put->GetSeekPos()!=FILE_END && get->GetSize()>=0
|
|
Packit |
8f70b4 |
&& put->GetSeekPos()>=get->GetSize())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
debug((9,_("copy: destination file is already complete\n")));
|
|
Packit |
8f70b4 |
if(get->GetDate()!=NO_DATE)
|
|
Packit |
8f70b4 |
goto pre_CONFIRM_WAIT; // have to set the date.
|
|
Packit |
8f70b4 |
goto pre_GET_DONE_WAIT;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!put->IOReady())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
/* now we know if put's seek failed. Seek get accordingly. */
|
|
Packit |
8f70b4 |
if(get->CanSeek())
|
|
Packit |
8f70b4 |
get->Seek(put->GetRealPos());
|
|
Packit |
8f70b4 |
pre_DO_COPY:
|
|
Packit |
8f70b4 |
get->Resume();
|
|
Packit |
8f70b4 |
get->StartTransfer();
|
|
Packit |
8f70b4 |
RateReset();
|
|
Packit |
8f70b4 |
set_state(DO_COPY);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
/* fallthrough */
|
|
Packit |
8f70b4 |
case(DO_COPY): {
|
|
Packit |
8f70b4 |
if(put->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
put_error:
|
|
Packit |
8f70b4 |
SetError(put->ErrorText());
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(get->Error() && get->Size()==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
put->DontVerify();
|
|
Packit |
8f70b4 |
if(put->GetPos()>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
put->PutEOF();
|
|
Packit |
8f70b4 |
put->Roll();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
get_error:
|
|
Packit |
8f70b4 |
SetError(get->ErrorText());
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(put->Broken())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
get->Suspend();
|
|
Packit |
8f70b4 |
if(!put->Done())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
debug((9,_("copy: put is broken\n")));
|
|
Packit |
8f70b4 |
if(fail_if_broken)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(strerror(EPIPE));
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
goto pre_GET_DONE_WAIT;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
put->Resume();
|
|
Packit |
8f70b4 |
if(put->GetSeekPos()==FILE_END) // put position is not known yet.
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
get->Suspend();
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
get->Resume();
|
|
Packit |
8f70b4 |
if(fail_if_cannot_seek && (get->GetRealPos()<get->range_start
|
|
Packit |
8f70b4 |
|| put->GetRealPos()<put->range_start
|
|
Packit |
8f70b4 |
|| get->GetRealPos()!=put->GetRealPos()))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(_("seek failed"));
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(high_watermark_timeout.Stopped())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(_("no progress timeout"));
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(get->GetSize()>0 && get->GetRealPos()>get->GetSize())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
get->SetSize(NO_SIZE_YET);
|
|
Packit |
8f70b4 |
get->SetDate(NO_DATE_YET);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
long lbsize=0;
|
|
Packit |
8f70b4 |
if(line_buffer)
|
|
Packit |
8f70b4 |
lbsize=line_buffer->Size();
|
|
Packit |
8f70b4 |
/* check if positions are correct */
|
|
Packit |
8f70b4 |
off_t get_pos=get->GetRealPos()-get->range_start;
|
|
Packit |
8f70b4 |
off_t put_pos=put->GetRealPos()-put->range_start;
|
|
Packit |
8f70b4 |
if(get_pos-lbsize!=put_pos)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(line_buffer)
|
|
Packit |
8f70b4 |
line_buffer->Empty();
|
|
Packit |
8f70b4 |
if(get_pos==put_pos)
|
|
Packit |
8f70b4 |
{ // rare case.
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(put_pos
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!get->CanSeek(put->GetRealPos()))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// we lose... How about a large buffer?
|
|
Packit |
8f70b4 |
SetError(_("cannot seek on data source"));
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
debug((9,_("copy: put rolled back to %lld, seeking get accordingly\n"),
|
|
Packit |
8f70b4 |
(long long)put->GetRealPos()));
|
|
Packit |
8f70b4 |
debug((10,"copy: get position was %lld\n",
|
|
Packit |
8f70b4 |
(long long)get->GetRealPos()));
|
|
Packit |
8f70b4 |
get->Seek(put->GetRealPos());
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else // put_pos > get_pos
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
off_t size=get->GetSize();
|
|
Packit |
8f70b4 |
if(size>=0 && put->GetRealPos()>=size)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// simulate eof, as we have already have the whole file.
|
|
Packit |
8f70b4 |
debug((9,_("copy: all data received, but get rolled back\n")));
|
|
Packit |
8f70b4 |
goto eof;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
off_t skip=put->GetRealPos()-get->GetRealPos();
|
|
Packit |
8f70b4 |
if(!put->CanSeek(get->GetRealPos()) || skip
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// we have to skip some data
|
|
Packit |
8f70b4 |
get->Get(&b,&s);
|
|
Packit |
8f70b4 |
if(skip>s)
|
|
Packit |
8f70b4 |
skip=s;
|
|
Packit |
8f70b4 |
if(skip==0)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
get->Skip(skip);
|
|
Packit |
8f70b4 |
bytes_count+=skip;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
debug((9,_("copy: get rolled back to %lld, seeking put accordingly\n"),
|
|
Packit |
8f70b4 |
(long long)get->GetRealPos()));
|
|
Packit |
8f70b4 |
put->Seek(get->GetRealPos());
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(put->IsFull())
|
|
Packit |
8f70b4 |
get->Suspend(); // stall the get.
|
|
Packit |
8f70b4 |
get->Get(&b,&s);
|
|
Packit |
8f70b4 |
if(b==0) // eof
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
debug((10,"copy: get hit eof\n"));
|
|
Packit |
8f70b4 |
goto eof;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
rate_add=put_buf;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(s==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
put_buf=put->Buffered();
|
|
Packit |
8f70b4 |
rate_add-=put_buf;
|
|
Packit |
8f70b4 |
RateAdd(rate_add);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(put->Size()==0)
|
|
Packit |
8f70b4 |
put->Suspend();
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(get->range_limit!=FILE_END && get->range_limit<get->GetRealPos()+s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
s=get->range_limit-get->GetRealPos();
|
|
Packit |
8f70b4 |
if(s<0)
|
|
Packit |
8f70b4 |
s=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(line_buffer)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *lb;
|
|
Packit |
8f70b4 |
int ls;
|
|
Packit |
8f70b4 |
if(line_buffer->Size()>line_buffer_max)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
line_buffer->Get(&lb,&ls);
|
|
Packit |
8f70b4 |
put->Put(lb,ls);
|
|
Packit |
8f70b4 |
line_buffer->Skip(ls);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
line_buffer->Put(b,s);
|
|
Packit |
8f70b4 |
get->Skip(s);
|
|
Packit |
8f70b4 |
bytes_count+=s;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// now find eol in line_buffer.
|
|
Packit |
8f70b4 |
line_buffer->Get(&lb,&ls);
|
|
Packit |
8f70b4 |
const char *eol=0;
|
|
Packit |
8f70b4 |
if(get->Eof() || get->Error())
|
|
Packit |
8f70b4 |
eol=lb+ls-1;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
eol=memrchr(lb,'\n',ls);
|
|
Packit |
8f70b4 |
if(eol)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
put->Put(lb,eol-lb+1);
|
|
Packit |
8f70b4 |
line_buffer->Skip(eol-lb+1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
put->Put(b,s);
|
|
Packit |
8f70b4 |
get->Skip(s);
|
|
Packit |
8f70b4 |
bytes_count+=s;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
put_buf=put->Buffered();
|
|
Packit |
8f70b4 |
rate_add-=put_buf-s;
|
|
Packit |
8f70b4 |
RateAdd(rate_add);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(high_watermark
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
high_watermark=put_pos+s;
|
|
Packit |
8f70b4 |
high_watermark_timeout.Reset();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(get->range_limit!=FILE_END && get->range_limit<=get->GetRealPos())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
debug((10,"copy: get reached range limit\n"));
|
|
Packit |
8f70b4 |
goto eof;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
eof:
|
|
Packit |
8f70b4 |
if(line_buffer)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
line_buffer->Get(&b,&s);
|
|
Packit |
8f70b4 |
put->Put(b,s);
|
|
Packit |
8f70b4 |
line_buffer->Skip(s);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!CheckFileSizeAtEOF())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(_("file size decreased during transfer"));
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
pre_CONFIRM_WAIT:
|
|
Packit |
8f70b4 |
put->SetSuggestedFileName(get->GetSuggestedFileName());
|
|
Packit |
8f70b4 |
put->SetDate(get->GetDate());
|
|
Packit |
8f70b4 |
if(get->GetSize()!=NO_SIZE && get->GetSize()!=NO_SIZE_YET)
|
|
Packit |
8f70b4 |
put->SetEntitySize(get->GetSize());
|
|
Packit |
8f70b4 |
put->PutEOF();
|
|
Packit |
8f70b4 |
get->Suspend();
|
|
Packit |
8f70b4 |
put->Resume();
|
|
Packit |
8f70b4 |
put_eof_pos=put->GetRealPos();
|
|
Packit |
8f70b4 |
debug((10,"copy: waiting for put confirmation\n"));
|
|
Packit |
8f70b4 |
set_state(CONFIRM_WAIT);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
case(CONFIRM_WAIT):
|
|
Packit |
8f70b4 |
if(put->Error())
|
|
Packit |
8f70b4 |
goto put_error;
|
|
Packit |
8f70b4 |
/* check if put position is correct */
|
|
Packit |
8f70b4 |
if(put_eof_pos!=put->GetRealPos() || put->GetSeekPos()==FILE_END)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
set_state(DO_COPY);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
rate_add=put_buf;
|
|
Packit |
8f70b4 |
put_buf=put->Buffered();
|
|
Packit |
8f70b4 |
rate_add-=put_buf;
|
|
Packit |
8f70b4 |
RateAdd(rate_add);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!put->Done())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
debug((10,"copy: put confirmed store\n"));
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pre_GET_DONE_WAIT:
|
|
Packit |
8f70b4 |
get->Empty();
|
|
Packit |
8f70b4 |
get->PutEOF();
|
|
Packit |
8f70b4 |
get->Resume();
|
|
Packit |
8f70b4 |
set_state(GET_DONE_WAIT);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
end_time=now;
|
|
Packit |
8f70b4 |
put->Suspend();
|
|
Packit |
8f70b4 |
/* fallthrough */
|
|
Packit |
8f70b4 |
case(GET_DONE_WAIT):
|
|
Packit |
8f70b4 |
if(get->Error())
|
|
Packit |
8f70b4 |
goto get_error;
|
|
Packit |
8f70b4 |
if(remove_source_later)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
get->RemoveFile();
|
|
Packit |
8f70b4 |
remove_source_later=false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!get->Done())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
debug((10,"copy: get is finished - all done\n"));
|
|
Packit |
8f70b4 |
set_state(ALL_DONE);
|
|
Packit |
8f70b4 |
get->Suspend();
|
|
Packit |
8f70b4 |
LogTransfer();
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pre_GET_INFO_WAIT:
|
|
Packit |
8f70b4 |
set_state(GET_INFO_WAIT);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
case(GET_INFO_WAIT):
|
|
Packit |
8f70b4 |
if(get->Error())
|
|
Packit |
8f70b4 |
goto get_error;
|
|
Packit |
8f70b4 |
if(get->GetSize()==NO_SIZE_YET || get->GetDate()==NO_DATE_YET)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
goto pre_INITIAL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case(ALL_DONE):
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileCopy::FileCopy(FileCopyPeer *s,FileCopyPeer *d,bool c)
|
|
Packit |
8f70b4 |
: get(s), put(d), cont(c),
|
|
Packit |
8f70b4 |
rate("xfer:rate-period"),
|
|
Packit |
8f70b4 |
rate_for_eta("xfer:eta-period"),
|
|
Packit |
8f70b4 |
high_watermark_timeout("xfer:timeout",0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
set_state(INITIAL);
|
|
Packit |
8f70b4 |
int max_buf=buffer_size.Query(0);
|
|
Packit |
8f70b4 |
if(max_buf<1)
|
|
Packit |
8f70b4 |
max_buf=1;
|
|
Packit |
8f70b4 |
s->SetMaxBuffered(max_buf);
|
|
Packit |
8f70b4 |
d->SetMaxBuffered(max_buf);
|
|
Packit |
8f70b4 |
put_buf=0;
|
|
Packit |
8f70b4 |
put_eof_pos=0;
|
|
Packit |
8f70b4 |
high_watermark=0;
|
|
Packit |
8f70b4 |
bytes_count=0;
|
|
Packit |
8f70b4 |
fail_if_cannot_seek=false;
|
|
Packit |
8f70b4 |
fail_if_broken=true;
|
|
Packit |
8f70b4 |
remove_source_later=false;
|
|
Packit |
8f70b4 |
remove_target_first=false;
|
|
Packit |
8f70b4 |
line_buffer_max=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileCopy::~FileCopy()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileCopy *FileCopy::New(FileCopyPeer *s,FileCopyPeer *d,bool c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FileCopy *res=0;
|
|
Packit |
8f70b4 |
if(fxp_create)
|
|
Packit |
8f70b4 |
res=fxp_create(s,d,c);
|
|
Packit |
8f70b4 |
if(res)
|
|
Packit |
8f70b4 |
return res;
|
|
Packit |
8f70b4 |
return new FileCopy(s,d,c);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileCopy::SuspendInternal()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
super::SuspendInternal();
|
|
Packit |
8f70b4 |
if(get) get->SuspendSlave();
|
|
Packit |
8f70b4 |
if(put) put->SuspendSlave();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileCopy::ResumeInternal()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(get) get->ResumeSlave();
|
|
Packit |
8f70b4 |
if(put) put->ResumeSlave();
|
|
Packit |
8f70b4 |
super::ResumeInternal();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileCopy::Fg()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(get) get->Fg();
|
|
Packit |
8f70b4 |
if(put) put->Fg();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileCopy::Bg()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(get) get->Bg();
|
|
Packit |
8f70b4 |
if(put) put->Bg();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopy::SetError(const char *str)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
error_text.set(str);
|
|
Packit |
8f70b4 |
get=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopy::LineBuffered(int s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!line_buffer)
|
|
Packit |
8f70b4 |
line_buffer=new Buffer();
|
|
Packit |
8f70b4 |
line_buffer_max=s;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
off_t FileCopy::GetPos() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(put) {
|
|
Packit |
8f70b4 |
off_t pos = put->GetRealPos() - put->Buffered();
|
|
Packit |
8f70b4 |
// sometimes Buffered overestimates the amount of buffered data
|
|
Packit |
8f70b4 |
if(pos<0)
|
|
Packit |
8f70b4 |
pos=0;
|
|
Packit |
8f70b4 |
return pos;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(get)
|
|
Packit |
8f70b4 |
return get->GetRealPos();
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
off_t FileCopy::GetSize() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(get)
|
|
Packit |
8f70b4 |
return get->GetSize();
|
|
Packit |
8f70b4 |
return NO_SIZE;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int FileCopy::GetPercentDone() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!get || !put)
|
|
Packit |
8f70b4 |
return 100;
|
|
Packit |
8f70b4 |
off_t size=get->GetSize();
|
|
Packit |
8f70b4 |
if(size==NO_SIZE || size==NO_SIZE_YET)
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
if(size==0)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
off_t ppos=put->GetRealPos() - put->Buffered() - put->range_start;
|
|
Packit |
8f70b4 |
if(ppos<0)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
off_t psize=size-put->range_start;
|
|
Packit |
8f70b4 |
if(put->range_limit!=FILE_END)
|
|
Packit |
8f70b4 |
psize=put->range_limit-put->range_start;
|
|
Packit |
8f70b4 |
if(psize<0)
|
|
Packit |
8f70b4 |
return 100;
|
|
Packit |
8f70b4 |
if(ppos>psize)
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
return percent(ppos,psize);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *FileCopy::GetPercentDoneStr() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int pct=GetPercentDone();
|
|
Packit |
8f70b4 |
if(pct==-1)
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
static char buf[8];
|
|
Packit |
8f70b4 |
snprintf(buf,8,"(%d%%) ",pct);
|
|
Packit |
8f70b4 |
return buf;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileCopy::RateAdd(int a)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
rate.Add(a);
|
|
Packit |
8f70b4 |
rate_for_eta.Add(a);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileCopy::RateReset()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
start_time=now;
|
|
Packit |
8f70b4 |
rate.Reset();
|
|
Packit |
8f70b4 |
rate_for_eta.Reset();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
float FileCopy::GetRate()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!rate.Valid() || !put)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
return rate.Get();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *FileCopy::GetRateStr()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!rate.Valid() || !put)
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
return rate.GetStrS();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
off_t FileCopy::GetBytesRemaining()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!get)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
if(get->range_limit==FILE_END)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
off_t size=get->GetSize();
|
|
Packit |
8f70b4 |
if(size<=0 || size<get->GetRealPos() || !rate_for_eta.Valid())
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
return(size-GetPos());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return get->range_limit-GetPos();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *FileCopy::GetETAStr()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
off_t b=GetBytesRemaining();
|
|
Packit |
8f70b4 |
if(b<0 || !put)
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
return rate_for_eta.GetETAStrSFromSize(b);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
long FileCopy::GetETA(off_t b)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(b<0 || !rate_for_eta.Valid())
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
return (long)(double(b) / rate_for_eta.Get() + 0.5);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *FileCopy::GetStatus()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static xstring buf;
|
|
Packit |
8f70b4 |
const char *get_st=get?get->GetStatus():0;
|
|
Packit |
8f70b4 |
const char *put_st=put?put->GetStatus():0;
|
|
Packit |
8f70b4 |
if(get_st && get_st[0] && put_st && put_st[0])
|
|
Packit |
8f70b4 |
buf.vset("[",get_st,"->",put_st,"]",NULL);
|
|
Packit |
8f70b4 |
else if(get_st && get_st[0])
|
|
Packit |
8f70b4 |
buf.vset("[",get_st,"]",NULL);
|
|
Packit |
8f70b4 |
else if(put_st && put_st[0])
|
|
Packit |
8f70b4 |
buf.vset("[",put_st,"]",NULL);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
return buf;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
double FileCopy::GetTimeSpent()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(end_time
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
return TimeDiff(end_time,start_time);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FgData *FileCopy::GetFgData(bool fg)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// NOTE: only one of get/put can have FgData in this implementation.
|
|
Packit |
8f70b4 |
FgData *f=0;
|
|
Packit |
8f70b4 |
if(get) f=get->GetFgData(fg);
|
|
Packit |
8f70b4 |
if(f) return f;
|
|
Packit |
8f70b4 |
if(put) f=put->GetFgData(fg);
|
|
Packit |
8f70b4 |
return f;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pid_t FileCopy::GetProcGroup()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
pid_t p=0;
|
|
Packit |
8f70b4 |
if(get) p=get->GetProcGroup();
|
|
Packit |
8f70b4 |
if(p) return p;
|
|
Packit |
8f70b4 |
if(put) p=put->GetProcGroup();
|
|
Packit |
8f70b4 |
return p;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopy::Kill(int sig)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(get) get->Kill(sig);
|
|
Packit |
8f70b4 |
if(put) put->Kill(sig);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Ref<Log> FileCopy::transfer_log;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopy::LogTransfer()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *log_ctx="xfer";
|
|
Packit |
8f70b4 |
if(!ResMgr::QueryBool("log:enabled",log_ctx))
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
const char *src=get->GetURL();
|
|
Packit |
8f70b4 |
if(!src)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
src=alloca_strdup(src);
|
|
Packit |
8f70b4 |
const char *dst=put->GetURL();
|
|
Packit |
8f70b4 |
if(!dst)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
dst=alloca_strdup(dst);
|
|
Packit |
8f70b4 |
if(!transfer_log)
|
|
Packit |
8f70b4 |
transfer_log=new Log(log_ctx);
|
|
Packit |
8f70b4 |
long long range_limit=GetRangeLimit();
|
|
Packit |
8f70b4 |
if(range_limit==FILE_END)
|
|
Packit |
8f70b4 |
range_limit=get->GetPos();
|
|
Packit |
8f70b4 |
transfer_log->Format(0,"%s -> %s %lld-%lld %s\n",
|
|
Packit |
8f70b4 |
url::remove_password(src),url::remove_password(dst),
|
|
Packit |
8f70b4 |
(long long)GetRangeStart(),range_limit,
|
|
Packit |
8f70b4 |
Speedometer::GetStrProper(GetBytesCount()/GetTimeSpent()).get());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopy::SetRange(off_t s,off_t lim)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
get->SetRange(s,lim);
|
|
Packit |
8f70b4 |
put->SetRange(s,lim);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool FileCopy::CheckFileSizeAtEOF() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
long long range_limit=GetRangeLimit();
|
|
Packit |
8f70b4 |
if(range_limit==FILE_END)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const long long size=GetSize();
|
|
Packit |
8f70b4 |
if(size==NO_SIZE || size==NO_SIZE_YET)
|
|
Packit |
8f70b4 |
return true; // nothing to compare with.
|
|
Packit |
8f70b4 |
range_limit=size;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const long long get_pos=get->GetRealPos();
|
|
Packit |
8f70b4 |
const long long put_pos=put->GetRealPos();
|
|
Packit |
8f70b4 |
const long long pos=(get_pos>put_pos ? get_pos : put_pos);
|
|
Packit |
8f70b4 |
if(pos<=0 || pos>=range_limit)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
debug((0,"expected pos=%lld, actual pos=%lld\n",range_limit,pos));
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// FileCopyPeer implementation
|
|
Packit |
8f70b4 |
#undef super
|
|
Packit |
8f70b4 |
#define super Buffer
|
|
Packit |
8f70b4 |
off_t FileCopyPeer::GetSize()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(size>=0 && pos>size)
|
|
Packit |
8f70b4 |
WantSize();
|
|
Packit |
8f70b4 |
return size;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileCopyPeer::SetSize(off_t s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
size=s;
|
|
Packit |
8f70b4 |
if(seek_pos==FILE_END)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(size!=NO_SIZE && size!=NO_SIZE_YET)
|
|
Packit |
8f70b4 |
seek_pos=size;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
seek_pos=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileCopyPeer::SetDate(time_t d,int p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
date.set(d,p);
|
|
Packit |
8f70b4 |
if(d==NO_DATE || d==NO_DATE_YET)
|
|
Packit |
8f70b4 |
date_set=true;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
date_set=false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyPeer::SetRange(const off_t s,const off_t lim)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
range_start=s;
|
|
Packit |
8f70b4 |
range_limit=lim;
|
|
Packit |
8f70b4 |
if(mode==PUT || range_start>GetPos()+0x4000)
|
|
Packit |
8f70b4 |
Seek(range_start);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool FileCopyPeer::Done()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(Error())
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
if(eof && Size()==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(removing)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(mode==PUT)
|
|
Packit |
8f70b4 |
return done;
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(broken)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyPeer::Seek(off_t offs)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
seek_pos=offs;
|
|
Packit |
8f70b4 |
if(mode==PUT)
|
|
Packit |
8f70b4 |
pos-=Size();
|
|
Packit |
8f70b4 |
Empty();
|
|
Packit |
8f70b4 |
eof=false;
|
|
Packit |
8f70b4 |
broken=false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *FileCopy::TempFileName(const char *file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!ResMgr::QueryBool("xfer:use-temp-file",0))
|
|
Packit |
8f70b4 |
return file;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring &temp=xstring::get_tmp(ResMgr::Query("xfer:temp-file-name",0));
|
|
Packit |
8f70b4 |
if(temp.length()==0 || temp.eq("*"))
|
|
Packit |
8f70b4 |
return file;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *name=basename_ptr(file);
|
|
Packit |
8f70b4 |
int subst_pos=temp.instr('*');
|
|
Packit |
8f70b4 |
if(subst_pos>=0)
|
|
Packit |
8f70b4 |
temp.set_substr(subst_pos,1,name);
|
|
Packit |
8f70b4 |
else {
|
|
Packit |
8f70b4 |
if(temp.last_char()=='.')
|
|
Packit |
8f70b4 |
temp.append(name);
|
|
Packit |
8f70b4 |
else if(temp[0]=='.')
|
|
Packit |
8f70b4 |
temp.set_substr(0,0,name);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
temp.append('.').append(name);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return dir_file(dirname(file),temp);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *FileCopyPeer::UseTempFile(const char *file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *temp=FileCopy::TempFileName(file);
|
|
Packit |
8f70b4 |
if(temp==file)
|
|
Packit |
8f70b4 |
return file;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
auto_rename=true;
|
|
Packit |
8f70b4 |
temp_file=true;
|
|
Packit |
8f70b4 |
SetSuggestedFileName(basename_ptr(file));
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return temp;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileCopyPeer::FileCopyPeer(dir_t m) : IOBuffer(m)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
want_size=false;
|
|
Packit |
8f70b4 |
want_date=false;
|
|
Packit |
8f70b4 |
start_transfer=true;
|
|
Packit |
8f70b4 |
size=NO_SIZE_YET;
|
|
Packit |
8f70b4 |
date=NO_DATE_YET;
|
|
Packit |
8f70b4 |
e_size=NO_SIZE;
|
|
Packit |
8f70b4 |
seek_pos=0;
|
|
Packit |
8f70b4 |
can_seek=false;
|
|
Packit |
8f70b4 |
can_seek0=false;
|
|
Packit |
8f70b4 |
date_set=false;
|
|
Packit |
8f70b4 |
do_set_date=true;
|
|
Packit |
8f70b4 |
do_verify=true;
|
|
Packit |
8f70b4 |
ascii=false;
|
|
Packit |
8f70b4 |
range_start=0;
|
|
Packit |
8f70b4 |
range_limit=FILE_END;
|
|
Packit |
8f70b4 |
removing=false;
|
|
Packit |
8f70b4 |
file_removed=false;
|
|
Packit |
8f70b4 |
temp_file=false;
|
|
Packit |
8f70b4 |
do_mkdir=false;
|
|
Packit |
8f70b4 |
use_cache=true;
|
|
Packit |
8f70b4 |
write_allowed=true;
|
|
Packit |
8f70b4 |
done=false;
|
|
Packit |
8f70b4 |
auto_rename=false;
|
|
Packit |
8f70b4 |
Suspend(); // don't do anything too early
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// FileCopyPeerFA implementation
|
|
Packit |
8f70b4 |
#undef super
|
|
Packit |
8f70b4 |
#define super FileCopyPeer
|
|
Packit |
8f70b4 |
int FileCopyPeerFA::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
int res;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(session->OpenMode()==FA::MAKE_DIR)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// doing mkdir
|
|
Packit |
8f70b4 |
int res=session->Done();
|
|
Packit |
8f70b4 |
if(res==FA::IN_PROGRESS)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(res<0)
|
|
Packit |
8f70b4 |
debug((3,"mkdir failed: %s\n",session->StrError(res)));
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(session->OpenMode()==FA::RENAME)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int res=session->Done();
|
|
Packit |
8f70b4 |
if(res==FA::IN_PROGRESS)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(res<0) {
|
|
Packit |
8f70b4 |
if(temp_file)
|
|
Packit |
8f70b4 |
SetError(session->StrError(res));
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
debug((3,"rename failed: %s\n",session->StrError(res)));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(do_mkdir) {
|
|
Packit |
8f70b4 |
// do mkdir just once
|
|
Packit |
8f70b4 |
do_mkdir=false;
|
|
Packit |
8f70b4 |
assert(!session->IsOpen());
|
|
Packit |
8f70b4 |
const xstring& dir=dirname(file);
|
|
Packit |
8f70b4 |
if(dir.length()>0 && dir.ne("/") && dir.ne(".") && dir.ne("..")) {
|
|
Packit |
8f70b4 |
// FIXME: .././.. should be also excluded
|
|
Packit |
8f70b4 |
session->Mkdir(dirname(file),true);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(removing)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
res=session->Done();
|
|
Packit |
8f70b4 |
if(res<=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
removing=false;
|
|
Packit |
8f70b4 |
file_removed=true;
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
Suspend();
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(Done() || Error())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(verify)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(verify->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(verify->ErrorText());
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(verify->Done())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(suggested_filename && auto_rename)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *new_name=dir_file(dirname(file),suggested_filename);
|
|
Packit |
8f70b4 |
bool clobber=temp_file;
|
|
Packit |
8f70b4 |
session->Rename(file,new_name,clobber);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// if we need some info and cannot start the transfer (yet),
|
|
Packit |
8f70b4 |
// then use ARRAY_INFO to fetch the file information.
|
|
Packit |
8f70b4 |
if(((want_size && size==NO_SIZE_YET) || (want_date && date==NO_DATE_YET))
|
|
Packit |
8f70b4 |
&& (mode==PUT || !start_transfer) && session->IsClosed())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FileInfo *fi=new FileInfo(file);
|
|
Packit |
8f70b4 |
if(want_size)
|
|
Packit |
8f70b4 |
fi->Need(fi->SIZE);
|
|
Packit |
8f70b4 |
if(want_date)
|
|
Packit |
8f70b4 |
fi->Need(fi->DATE);
|
|
Packit |
8f70b4 |
info.Empty();
|
|
Packit |
8f70b4 |
info.Add(fi);
|
|
Packit |
8f70b4 |
session->GetInfoArray(&info;;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(session->OpenMode()==FA::ARRAY_INFO)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
res=session->Done();
|
|
Packit |
8f70b4 |
if(res==FA::IN_PROGRESS)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(res<0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
SetSize(NO_SIZE);
|
|
Packit |
8f70b4 |
SetDate(NO_DATE);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileInfo *fi=info[0];
|
|
Packit |
8f70b4 |
if(want_size)
|
|
Packit |
8f70b4 |
SetSize(fi->size);
|
|
Packit |
8f70b4 |
if(want_date)
|
|
Packit |
8f70b4 |
SetDate(fi->date);
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
switch(mode)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case PUT:
|
|
Packit |
8f70b4 |
if(fxp)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(eof)
|
|
Packit |
8f70b4 |
goto fxp_eof;
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
res=Put_LL(buffer+buffer_ptr,Size());
|
|
Packit |
8f70b4 |
if(res>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
buffer_ptr+=res;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(res<0)
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
if(Size()==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(eof)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(date!=NO_DATE && date!=NO_DATE_YET)
|
|
Packit |
8f70b4 |
session->SetDate(date);
|
|
Packit |
8f70b4 |
if(e_size!=NO_SIZE && e_size!=NO_SIZE_YET)
|
|
Packit |
8f70b4 |
session->SetSize(e_size);
|
|
Packit |
8f70b4 |
res=session->StoreStatus();
|
|
Packit |
8f70b4 |
if(res==FA::OK)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
fxp_eof:
|
|
Packit |
8f70b4 |
// FIXME: set date for real.
|
|
Packit |
8f70b4 |
date_set=true;
|
|
Packit |
8f70b4 |
if(!verify && do_verify)
|
|
Packit |
8f70b4 |
verify=new FileVerificator(session,file);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(res==FA::IN_PROGRESS)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(res==FA::DO_AGAIN)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(res==FA::STORE_FAILED)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
upload_state.Save(session);
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
if(can_seek && seek_pos>0)
|
|
Packit |
8f70b4 |
Seek(FILE_END);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
Seek(0);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
SetError(session->StrError(res));
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case GET:
|
|
Packit |
8f70b4 |
if(eof)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(fxp)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
res=TuneGetSize(Get_LL(get_size));
|
|
Packit |
8f70b4 |
if(res>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
EmbraceNewData(res);
|
|
Packit |
8f70b4 |
SaveMaxCheck(0);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(res<0)
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
if(eof)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool FileCopyPeerFA::IOReady()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(seek_pos==0)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
if(seek_pos==FILE_END && size==NO_SIZE_YET)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
return session->IOReady();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyPeerFA::SuspendInternal()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(fxp && mode==PUT)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
if(session->IsOpen())
|
|
Packit |
8f70b4 |
session->SuspendSlave();
|
|
Packit |
8f70b4 |
super::SuspendInternal();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileCopyPeerFA::ResumeInternal()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
super::ResumeInternal();
|
|
Packit |
8f70b4 |
session->ResumeSlave();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *FileCopyPeerFA::GetStatus()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(verify)
|
|
Packit |
8f70b4 |
return verify->Status();
|
|
Packit |
8f70b4 |
if(!session->IsOpen())
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
return session->CurrentStatus();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyPeerFA::Seek(off_t new_pos)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(pos==new_pos)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
super::Seek(new_pos);
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
if(seek_pos==FILE_END)
|
|
Packit |
8f70b4 |
WantSize();
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
pos=new_pos;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyPeerFA::OpenSession()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
current->Timeout(0); // mark it MOVED.
|
|
Packit |
8f70b4 |
if(mode==GET)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(size!=NO_SIZE && size!=NO_SIZE_YET && !ascii
|
|
Packit |
8f70b4 |
&& (seek_pos>size || (seek_pos==size && size>0)))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
past_eof:
|
|
Packit |
8f70b4 |
debug((10,"copy src: seek past eof (seek_pos=%lld, size=%lld)\n",
|
|
Packit |
8f70b4 |
(long long)seek_pos,(long long)size));
|
|
Packit |
8f70b4 |
pos=seek_pos;
|
|
Packit |
8f70b4 |
eof=true;
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *b;
|
|
Packit |
8f70b4 |
int s;
|
|
Packit |
8f70b4 |
int err;
|
|
Packit |
8f70b4 |
if(use_cache && FileAccess::cache->Find(session,file,FAmode,&err,&b,&s))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(b);
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
size=s;
|
|
Packit |
8f70b4 |
if(seek_pos>=s)
|
|
Packit |
8f70b4 |
goto past_eof;
|
|
Packit |
8f70b4 |
b+=seek_pos;
|
|
Packit |
8f70b4 |
s-=seek_pos;
|
|
Packit |
8f70b4 |
Save(0);
|
|
Packit |
8f70b4 |
Put(b,s);
|
|
Packit |
8f70b4 |
pos=seek_pos;
|
|
Packit |
8f70b4 |
eof=true;
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else // mode==PUT
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(e_size>=0 && size>=0 && seek_pos>=e_size)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
debug((10,"copy dst: seek past eof (seek_pos=%lld, size=%lld)\n",
|
|
Packit |
8f70b4 |
(long long)seek_pos,(long long)e_size));
|
|
Packit |
8f70b4 |
eof=true;
|
|
Packit |
8f70b4 |
if(date==NO_DATE || date==NO_DATE_YET)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
session->Open(file,FAmode,seek_pos);
|
|
Packit |
8f70b4 |
session->SetFileURL(orig_url);
|
|
Packit |
8f70b4 |
session->SetLimit(range_limit);
|
|
Packit |
8f70b4 |
if(mode==PUT) {
|
|
Packit |
8f70b4 |
upload_state.Restore(session);
|
|
Packit |
8f70b4 |
if(e_size!=NO_SIZE && e_size!=NO_SIZE_YET)
|
|
Packit |
8f70b4 |
session->SetSize(e_size);
|
|
Packit |
8f70b4 |
if(date!=NO_DATE && date!=NO_DATE_YET)
|
|
Packit |
8f70b4 |
session->SetDate(date);
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
if(size!=NO_SIZE && size!=NO_SIZE_YET)
|
|
Packit |
8f70b4 |
session->SetSize(size);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
session->RereadManual();
|
|
Packit |
8f70b4 |
if(ascii)
|
|
Packit |
8f70b4 |
session->AsciiTransfer();
|
|
Packit |
8f70b4 |
if(want_size && size==NO_SIZE_YET)
|
|
Packit |
8f70b4 |
session->WantSize(&size);
|
|
Packit |
8f70b4 |
if(want_date && (date==NO_DATE_YET || date.ts_prec>0))
|
|
Packit |
8f70b4 |
session->WantDate(&date);
|
|
Packit |
8f70b4 |
if(mode==GET)
|
|
Packit |
8f70b4 |
SaveRollback(seek_pos);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
pos=seek_pos+Size();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyPeerFA::WantSize()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(!strcmp(session->GetProto(),"file")
|
|
Packit |
8f70b4 |
&& stat(dir_file(session->GetCwd(),file),&st)!=-1)
|
|
Packit |
8f70b4 |
SetSize(S_ISREG(st.st_mode)?st.st_size:NO_SIZE);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
super::WantSize();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyPeerFA::RemoveFile()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
session->Open(file,FA::REMOVE);
|
|
Packit |
8f70b4 |
removing=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int FileCopyPeerFA::Get_LL(int len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(get_delay>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!get_ll_timer.Stopped())
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
session->ResumeSlave();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int res=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(session->IsClosed())
|
|
Packit |
8f70b4 |
OpenSession();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(eof) // OpenSession can set eof=true.
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
off_t io_at=pos;
|
|
Packit |
8f70b4 |
if(GetRealPos()!=io_at) // GetRealPos can alter pos.
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
res=session->Read(this,len);
|
|
Packit |
8f70b4 |
if(res<0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(res==FA::DO_AGAIN)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
if(res==FA::FILE_MOVED)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// handle redirection.
|
|
Packit |
8f70b4 |
assert(!fxp);
|
|
Packit |
8f70b4 |
const char *loc_c=session->GetNewLocation();
|
|
Packit |
8f70b4 |
int max_redirections=max_redir.Query(0);
|
|
Packit |
8f70b4 |
if(loc_c && loc_c[0] && max_redirections>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Log::global->Format(3,_("copy: received redirection to `%s'\n"),loc_c);
|
|
Packit |
8f70b4 |
if(++redirections>max_redirections)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(_("Too many redirections"));
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(FAmode==FA::QUOTE_CMD)
|
|
Packit |
8f70b4 |
FAmode=FA::RETRIEVE;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring loc(loc_c);
|
|
Packit |
8f70b4 |
session->Close(); // loc_c is no longer valid.
|
|
Packit |
8f70b4 |
loc_c=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ParsedURL u(loc,true);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(u.proto)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
my_session=FileAccess::New(&u);
|
|
Packit |
8f70b4 |
session=my_session;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
file.set(u.path?u.path.get():"");
|
|
Packit |
8f70b4 |
orig_url.set(loc);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else // !proto
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(orig_url)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int p_ind=url::path_index(orig_url);
|
|
Packit |
8f70b4 |
const char *s=strrchr(orig_url,'/');
|
|
Packit |
8f70b4 |
int s_ind=s?s-orig_url:-1;
|
|
Packit |
8f70b4 |
if(p_ind==-1 || s_ind==-1 || s_ind
|
|
Packit |
8f70b4 |
s_ind=p_ind=strlen(orig_url);
|
|
Packit |
8f70b4 |
if(loc[0]=='/')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
orig_url.truncate(p_ind);
|
|
Packit |
8f70b4 |
orig_url.append(loc);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
orig_url.truncate(s_ind);
|
|
Packit |
8f70b4 |
orig_url.append('/');
|
|
Packit |
8f70b4 |
orig_url.append(loc);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
loc.url_decode();
|
|
Packit |
8f70b4 |
const char *slash=strrchr(file,'/');
|
|
Packit |
8f70b4 |
if(loc[0]!='/' && slash)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
file.truncate(slash-file);
|
|
Packit |
8f70b4 |
file.set(dir_file(file,loc));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
file.set(loc);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(want_size || size!=NO_SIZE)
|
|
Packit |
8f70b4 |
WantSize();
|
|
Packit |
8f70b4 |
if(want_date || date!=NO_DATE)
|
|
Packit |
8f70b4 |
WantDate();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
upload_state.Clear();
|
|
Packit |
8f70b4 |
current->Timeout(0); // retry with new location.
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
SetError(session->StrError(res));
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(res==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
debug((10,"copy-peer: EOF on %s\n",session->GetFileURL(session->GetFile()).get()));
|
|
Packit |
8f70b4 |
eof=true;
|
|
Packit |
8f70b4 |
FileAccess::cache->Add(session,file,FAmode,FA::OK,this);
|
|
Packit |
8f70b4 |
SetSuggestedFileName(session->GetSuggestedFileName());
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(res<=MAX_READ_TO_DELAY)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(get_delay<=MAX_DELAY-DELAY_STEP)
|
|
Packit |
8f70b4 |
get_delay+=DELAY_STEP;
|
|
Packit |
8f70b4 |
get_ll_timer.SetMicroSeconds(get_delay);
|
|
Packit |
8f70b4 |
session->SuspendSlave();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(res>MAX_READ_TO_DELAY && get_delay>=DELAY_STEP)
|
|
Packit |
8f70b4 |
get_delay-=DELAY_STEP;
|
|
Packit |
8f70b4 |
return res;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int FileCopyPeerFA::Put_LL(const char *buf,int len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(do_mkdir)
|
|
Packit |
8f70b4 |
return 0; // can't write yet
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(session->IsClosed())
|
|
Packit |
8f70b4 |
OpenSession();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
off_t io_at=pos; // GetRealPos can alter pos, save it.
|
|
Packit |
8f70b4 |
if(GetRealPos()!=io_at)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(len==0 && eof)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int res=session->Write(buf,len);
|
|
Packit |
8f70b4 |
if(res<0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(res==FA::DO_AGAIN)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
if(res==FA::STORE_FAILED)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
upload_state.Save(session);
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
if(can_seek && seek_pos>0)
|
|
Packit |
8f70b4 |
Seek(FILE_END);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
Seek(0);
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
SetError(session->StrError(res));
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
seek_pos+=res; // mainly to indicate that there was some output.
|
|
Packit |
8f70b4 |
return res;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int FileCopyPeerFA::PutEOF_LL()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(mode==GET && session)
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
off_t FileCopyPeerFA::GetRealPos()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(session->OpenMode()!=FAmode || fxp)
|
|
Packit |
8f70b4 |
return pos;
|
|
Packit |
8f70b4 |
if(mode==PUT)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(pos-Size()!=session->GetPos())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Empty();
|
|
Packit |
8f70b4 |
can_seek=false;
|
|
Packit |
8f70b4 |
pos=session->GetPos();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(eof)
|
|
Packit |
8f70b4 |
return pos;
|
|
Packit |
8f70b4 |
if(session->GetRealPos()==0 && session->GetPos()>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
can_seek=false;
|
|
Packit |
8f70b4 |
session->SeekReal();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(pos+Size()!=session->GetPos())
|
|
Packit |
8f70b4 |
SaveRollback(session->GetPos());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return pos;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyPeerFA::Init()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
get_delay=0;
|
|
Packit |
8f70b4 |
fxp=false;
|
|
Packit |
8f70b4 |
redirections=0;
|
|
Packit |
8f70b4 |
can_seek=true;
|
|
Packit |
8f70b4 |
can_seek0=true;
|
|
Packit |
8f70b4 |
if(FAmode==FA::LIST || FAmode==FA::LONG_LIST)
|
|
Packit |
8f70b4 |
Save(FileAccess::cache->SizeLimit());
|
|
Packit |
8f70b4 |
if(mode==PUT)
|
|
Packit |
8f70b4 |
file.set(UseTempFile(file));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileCopyPeerFA::FileCopyPeerFA(FileAccess *s,const char *f,int m)
|
|
Packit |
8f70b4 |
: FileCopyPeer(m==FA::STORE ? PUT : GET), file(f),
|
|
Packit |
8f70b4 |
my_session(s), session(my_session), FAmode(m)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileCopyPeerFA::FileCopyPeerFA(const FileAccessRef& s,const char *f,int m)
|
|
Packit |
8f70b4 |
: FileCopyPeer(m==FA::STORE ? PUT : GET), file(f),
|
|
Packit |
8f70b4 |
session(s), FAmode(m)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileCopyPeerFA::FileCopyPeerFA(const ParsedURL *u,int m)
|
|
Packit |
8f70b4 |
: FileCopyPeer(m==FA::STORE ? PUT : GET), file(u->path), orig_url(u->orig_url),
|
|
Packit |
8f70b4 |
my_session(FileAccess::New(u)), session(my_session), FAmode(m)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
if(!file)
|
|
Packit |
8f70b4 |
SetError(_("file name missed in URL"));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyPeerFA::PrepareToDie()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(session)
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileCopyPeerFA::~FileCopyPeerFA() {}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileCopyPeerFA *FileCopyPeerFA::New(FileAccess *s,const char *url,int m)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ParsedURL u(url,true);
|
|
Packit |
8f70b4 |
if(u.proto)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SessionPool::Reuse(s);
|
|
Packit |
8f70b4 |
return new FileCopyPeerFA(&u,m);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return new FileCopyPeerFA(s,url,m);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileCopyPeerFA *FileCopyPeerFA::New(const FileAccessRef& s,const char *url,int m)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ParsedURL u(url,true);
|
|
Packit |
8f70b4 |
if(u.proto)
|
|
Packit |
8f70b4 |
return new FileCopyPeerFA(&u,m);
|
|
Packit |
8f70b4 |
return new FileCopyPeerFA(s,url,m);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileCopyPeer *FileCopyPeerFA::Clone()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FileCopyPeerFA *c=new FileCopyPeerFA(session->Clone(),file,FAmode);
|
|
Packit |
8f70b4 |
c->orig_url.set(orig_url);
|
|
Packit |
8f70b4 |
return c;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// FileCopyPeerFDStream
|
|
Packit |
8f70b4 |
#undef super
|
|
Packit |
8f70b4 |
#define super FileCopyPeer
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileCopyPeerFDStream::FileCopyPeerFDStream(FDStream *o,dir_t m)
|
|
Packit |
8f70b4 |
: FileCopyPeer(m), my_stream(o?o:new FDStream(1,"<stdout>")), stream(my_stream), close_when_done(o!=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileCopyPeerFDStream::FileCopyPeerFDStream(const Ref<FDStream>& o,dir_t m)
|
|
Packit |
8f70b4 |
: FileCopyPeer(m), stream(o), close_when_done(false)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyPeerFDStream::Init()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
seek_base=0;
|
|
Packit |
8f70b4 |
create_fg_data=true;
|
|
Packit |
8f70b4 |
need_seek=false;
|
|
Packit |
8f70b4 |
can_seek = can_seek0 = stream->can_seek();
|
|
Packit |
8f70b4 |
if(can_seek && stream->fd!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
seek_base=lseek(stream->fd,0,SEEK_CUR);
|
|
Packit |
8f70b4 |
if(seek_base==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
can_seek=false;
|
|
Packit |
8f70b4 |
can_seek0=false;
|
|
Packit |
8f70b4 |
seek_base=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(stream->usesfd(1))
|
|
Packit |
8f70b4 |
write_allowed=false;
|
|
Packit |
8f70b4 |
if(mode==PUT)
|
|
Packit |
8f70b4 |
put_ll_timer=new Timer(0,200);
|
|
Packit |
8f70b4 |
if(mode==PUT && stream->fd==-1 && stream->can_setmtime())
|
|
Packit |
8f70b4 |
stream->full_name.set(UseTempFile(stream->full_name));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyPeerFDStream::Seek_LL()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int fd=stream->fd;
|
|
Packit |
8f70b4 |
assert(fd!=-1);
|
|
Packit |
8f70b4 |
if(CanSeek(seek_pos))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(seek_pos==FILE_END)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
seek_pos=lseek(fd,0,SEEK_END);
|
|
Packit |
8f70b4 |
if(seek_pos==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
can_seek=false;
|
|
Packit |
8f70b4 |
can_seek0=false;
|
|
Packit |
8f70b4 |
seek_pos=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetSize(seek_pos);
|
|
Packit |
8f70b4 |
if(seek_pos>seek_base)
|
|
Packit |
8f70b4 |
seek_pos-=seek_base;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
seek_pos=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
pos=seek_pos;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(lseek(fd,seek_pos+seek_base,SEEK_SET)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
can_seek=false;
|
|
Packit |
8f70b4 |
can_seek0=false;
|
|
Packit |
8f70b4 |
seek_pos=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
pos=seek_pos;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(mode==PUT)
|
|
Packit |
8f70b4 |
pos+=Size();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
seek_pos=pos;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int FileCopyPeerFDStream::getfd()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!stream)
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
if(stream->fd!=-1)
|
|
Packit |
8f70b4 |
return stream->fd;
|
|
Packit |
8f70b4 |
int fd=stream->getfd();
|
|
Packit |
8f70b4 |
if(fd==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(stream->error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(stream->error_text);
|
|
Packit |
8f70b4 |
current->Timeout(0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
current->TimeoutS(1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
stream->clear_status();
|
|
Packit |
8f70b4 |
pos=0;
|
|
Packit |
8f70b4 |
if(mode==PUT)
|
|
Packit |
8f70b4 |
pos+=Size();
|
|
Packit |
8f70b4 |
Seek_LL();
|
|
Packit |
8f70b4 |
return fd;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int FileCopyPeerFDStream::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
if(Done() || Error())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(do_mkdir) {
|
|
Packit |
8f70b4 |
do_mkdir=false;
|
|
Packit |
8f70b4 |
create_directories(dirname(stream->full_name).get_non_const());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(verify)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(verify->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(verify->ErrorText());
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(verify->Done())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(suggested_filename && stream && stream->full_name && auto_rename)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *new_name=dir_file(dirname(stream->full_name),suggested_filename);
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(temp_file || (lstat(new_name,&st)==-1 && errno==ENOENT) || ResMgr::QueryBool("xfer:clobber",0)) {
|
|
Packit |
8f70b4 |
debug((5,"copy: renaming `%s' to `%s'\n",stream->full_name.get(),suggested_filename.get()));
|
|
Packit |
8f70b4 |
int res=rename(stream->full_name,new_name);
|
|
Packit |
8f70b4 |
if(res==-1 && errno==EIO) {
|
|
Packit |
8f70b4 |
// FUSE with HadoopFS workaround
|
|
Packit |
8f70b4 |
unlink(new_name);
|
|
Packit |
8f70b4 |
res=rename(stream->full_name,new_name);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(res==-1) {
|
|
Packit |
8f70b4 |
const char *err=xstring::format("rename(%s, %s): %s\n",stream->full_name.get(),new_name,strerror(errno));
|
|
Packit |
8f70b4 |
if(temp_file)
|
|
Packit |
8f70b4 |
SetError(err);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
debug((3,"%s\n",err));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool check_min_size=true;
|
|
Packit |
8f70b4 |
#ifndef NATIVE_CRLF
|
|
Packit |
8f70b4 |
if(ascii)
|
|
Packit |
8f70b4 |
check_min_size=false;
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
int res;
|
|
Packit |
8f70b4 |
switch(mode)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case PUT:
|
|
Packit |
8f70b4 |
if(Size()==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(eof)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// make sure the stream is open - it may create an empty file.
|
|
Packit |
8f70b4 |
if(stream && !stream->is_closed() && getfd()==-1)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(!date_set && date!=NO_DATE && do_set_date)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(date==NO_DATE_YET)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
stream->setmtime(date);
|
|
Packit |
8f70b4 |
date_set=true;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(stream && close_when_done && !stream->Done())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(!verify && do_verify)
|
|
Packit |
8f70b4 |
verify=new FileVerificator(stream);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(seek_pos==0)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!write_allowed)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(getfd()==-1)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(check_min_size && !eof && Size()
|
|
Packit |
8f70b4 |
&& put_ll_timer && !put_ll_timer->Stopped())
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
res=Put_LL(buffer+buffer_ptr,Size());
|
|
Packit |
8f70b4 |
if(res>0)
|
|
Packit |
8f70b4 |
buffer_ptr+=res;
|
|
Packit |
8f70b4 |
if(res!=0)
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case GET:
|
|
Packit |
8f70b4 |
if(eof)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
res=TuneGetSize(Get_LL(get_size));
|
|
Packit |
8f70b4 |
if(res>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
EmbraceNewData(res);
|
|
Packit |
8f70b4 |
SaveMaxCheck(0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(res!=0 || eof)
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool FileCopyPeerFDStream::IOReady()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return seek_pos==pos || stream->fd!=-1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyPeerFDStream::Seek(off_t new_pos)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(pos==new_pos)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
#ifndef NATIVE_CRLF
|
|
Packit |
8f70b4 |
if(ascii && new_pos!=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// it is possible to read file to determine right position,
|
|
Packit |
8f70b4 |
// but it is costly.
|
|
Packit |
8f70b4 |
can_seek=false;
|
|
Packit |
8f70b4 |
// can_seek0 is still true.
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
super::Seek(new_pos);
|
|
Packit |
8f70b4 |
int fd=stream->fd;
|
|
Packit |
8f70b4 |
if(fd==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(seek_pos!=FILE_END)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
pos=seek_pos;
|
|
Packit |
8f70b4 |
if(mode==PUT)
|
|
Packit |
8f70b4 |
pos+=Size();
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
off_t s=stream->get_size();
|
|
Packit |
8f70b4 |
if(s!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetSize(s);
|
|
Packit |
8f70b4 |
pos=seek_pos+((mode==PUT)?Size():0);
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// ok, have to try getfd.
|
|
Packit |
8f70b4 |
fd=getfd();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(fd==-1)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
Seek_LL();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int FileCopyPeerFDStream::Get_LL(int len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int res=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int fd=getfd();
|
|
Packit |
8f70b4 |
if(fd==-1)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if((want_date && date==NO_DATE_YET)
|
|
Packit |
8f70b4 |
|| (want_size && size==NO_SIZE_YET))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(fstat(fd,&st)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetDate(NO_DATE);
|
|
Packit |
8f70b4 |
SetSize(NO_SIZE);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetDate(st.st_mtime);
|
|
Packit |
8f70b4 |
SetSize(S_ISREG(st.st_mode)?st.st_size:NO_SIZE);
|
|
Packit |
8f70b4 |
#ifndef NATIVE_CRLF
|
|
Packit |
8f70b4 |
if(ascii)
|
|
Packit |
8f70b4 |
SetSize(NO_SIZE);
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(need_seek) // this does not combine with ascii.
|
|
Packit |
8f70b4 |
lseek(fd,seek_base+pos,SEEK_SET);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char *p=GetSpace(ascii?len*2:len);
|
|
Packit |
8f70b4 |
res=read(fd,p,len);
|
|
Packit |
8f70b4 |
if(res==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(E_RETRY(errno))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Block(fd,POLLIN);
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(stream->NonFatalError(errno))
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
stream->MakeErrorText();
|
|
Packit |
8f70b4 |
SetError(stream->error_text);
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
stream->clear_status();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifndef NATIVE_CRLF
|
|
Packit |
8f70b4 |
if(ascii)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(int i=res; i>0; i--)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(*p=='\n')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
memmove(p+1,p,i);
|
|
Packit |
8f70b4 |
*p++='\r';
|
|
Packit |
8f70b4 |
res++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
p++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(res==0) {
|
|
Packit |
8f70b4 |
debug((10,"copy-peer: EOF on FD %d\n",fd));
|
|
Packit |
8f70b4 |
eof=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return res;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int FileCopyPeerFDStream::Put_LL(const char *buf,int len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(len==0)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int fd=getfd();
|
|
Packit |
8f70b4 |
if(fd==-1)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int skip_cr=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifndef NATIVE_CRLF
|
|
Packit |
8f70b4 |
if(ascii)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// find where line ends.
|
|
Packit |
8f70b4 |
const char *cr=buf;
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
cr=(const char *)memchr(cr,'\r',len-(cr-buf));
|
|
Packit |
8f70b4 |
if(!cr)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
if(cr-buf
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
skip_cr=1;
|
|
Packit |
8f70b4 |
len=cr-buf;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(cr-buf==len-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(eof)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
len--;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
cr++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif // NATIVE_CRLF
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(len==0)
|
|
Packit |
8f70b4 |
return skip_cr;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(need_seek) // this does not combine with ascii.
|
|
Packit |
8f70b4 |
lseek(fd,seek_base+pos-Size(),SEEK_SET);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int res=write(fd,buf,len);
|
|
Packit |
8f70b4 |
if(res<0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(E_RETRY(errno))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Block(fd,POLLOUT);
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(errno==EPIPE)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
broken=true;
|
|
Packit |
8f70b4 |
buffer.truncate(buffer_ptr);
|
|
Packit |
8f70b4 |
eof=true;
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(stream->NonFatalError(errno))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// in case of full disk, check file correctness.
|
|
Packit |
8f70b4 |
if(errno==ENOSPC && can_seek)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(fstat(fd,&st)!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(st.st_size
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// workaround solaris nfs bug. It can lose data if disk is full.
|
|
Packit |
8f70b4 |
if(buffer_ptr>=seek_base+pos-Size()-buffer_ptr-st.st_size)
|
|
Packit |
8f70b4 |
UnSkip(seek_base+pos-Size()-st.st_size);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Empty();
|
|
Packit |
8f70b4 |
pos=st.st_size;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
stream->MakeErrorText();
|
|
Packit |
8f70b4 |
SetError(stream->error_text);
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
stream->clear_status();
|
|
Packit |
8f70b4 |
if(res==len && skip_cr)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
res+=skip_cr;
|
|
Packit |
8f70b4 |
// performance gets worse because of writing a single char,
|
|
Packit |
8f70b4 |
// but leaving uncomplete line on screen allows mixing it with debug text.
|
|
Packit |
8f70b4 |
if(write(fd,"\n",1)==1)
|
|
Packit |
8f70b4 |
res+=1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(put_ll_timer)
|
|
Packit |
8f70b4 |
put_ll_timer->Reset();
|
|
Packit |
8f70b4 |
return res;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FgData *FileCopyPeerFDStream::GetFgData(bool fg)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!my_stream || !create_fg_data)
|
|
Packit |
8f70b4 |
return 0; // if we don't own the stream, don't create FgData.
|
|
Packit |
8f70b4 |
if(stream->GetProcGroup())
|
|
Packit |
8f70b4 |
return new FgData(stream->GetProcGroup(),fg);
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyPeerFDStream::WantSize()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
int res=-1;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(stream->fd!=-1)
|
|
Packit |
8f70b4 |
res=fstat(stream->fd,&st);
|
|
Packit |
8f70b4 |
else if(stream->full_name)
|
|
Packit |
8f70b4 |
res=stat(stream->full_name,&st);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(res!=-1)
|
|
Packit |
8f70b4 |
SetSize(S_ISREG(st.st_mode)?st.st_size:NO_SIZE);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
super::WantSize();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void FileCopyPeerFDStream::RemoveFile()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
stream->remove();
|
|
Packit |
8f70b4 |
removing=false; // it is instant.
|
|
Packit |
8f70b4 |
file_removed=true;
|
|
Packit |
8f70b4 |
Suspend();
|
|
Packit |
8f70b4 |
current->Timeout(0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *FileCopyPeerFDStream::GetStatus()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(verify)
|
|
Packit |
8f70b4 |
return verify->Status();
|
|
Packit |
8f70b4 |
return stream->status;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileCopyPeerFDStream::Kill(int sig)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
stream->Kill(sig);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileCopyPeerFDStream *FileCopyPeerFDStream::NewPut(const char *file,bool cont)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int flags=O_WRONLY|O_CREAT;
|
|
Packit |
8f70b4 |
if(!cont) {
|
|
Packit |
8f70b4 |
flags|=O_TRUNC;
|
|
Packit |
8f70b4 |
if(!ResMgr::QueryBool("xfer:clobber",0))
|
|
Packit |
8f70b4 |
flags|=O_EXCL;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return new FileCopyPeerFDStream(new FileStream(file,flags),
|
|
Packit |
8f70b4 |
FileCopyPeer::PUT);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileCopyPeerFDStream *FileCopyPeerFDStream::NewGet(const char *file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return new FileCopyPeerFDStream(new FileStream(file,O_RDONLY),
|
|
Packit |
8f70b4 |
FileCopyPeer::GET);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileCopyPeer *FileCopyPeerFDStream::Clone()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
NeedSeek();
|
|
Packit |
8f70b4 |
FileCopyPeerFDStream *peer=new FileCopyPeerFDStream(stream,mode);
|
|
Packit |
8f70b4 |
peer->NeedSeek();
|
|
Packit |
8f70b4 |
peer->SetBase(0);
|
|
Packit |
8f70b4 |
return peer;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// FileCopyPeerDirList
|
|
Packit |
8f70b4 |
FileCopyPeerDirList::FileCopyPeerDirList(FA *s,ArgV *v)
|
|
Packit |
8f70b4 |
: FileCopyPeer(GET), session(s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
dl=session->MakeDirList(v);
|
|
Packit |
8f70b4 |
if(dl==0)
|
|
Packit |
8f70b4 |
eof=true;
|
|
Packit |
8f70b4 |
can_seek=false;
|
|
Packit |
8f70b4 |
can_seek0=false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int FileCopyPeerDirList::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(Done())
|
|
Packit |
8f70b4 |
return STALL;
|
|
Packit |
8f70b4 |
if(dl->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SetError(dl->ErrorText());
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *b;
|
|
Packit |
8f70b4 |
int s;
|
|
Packit |
8f70b4 |
dl->Get(&b,&s);
|
|
Packit |
8f70b4 |
if(b==0) // eof
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
eof=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(s==0)
|
|
Packit |
8f70b4 |
return STALL;
|
|
Packit |
8f70b4 |
memcpy(GetSpace(s),b,s);
|
|
Packit |
8f70b4 |
SpaceAdd(s);
|
|
Packit |
8f70b4 |
dl->Skip(s);
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// FileCopyPeerMemory
|
|
Packit |
8f70b4 |
int FileCopyPeerMemory::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
if(mode==PUT) {
|
|
Packit |
8f70b4 |
max_buf=max_size+1;
|
|
Packit |
8f70b4 |
if(Size()>max_size) {
|
|
Packit |
8f70b4 |
SetError("buffer limit exceeded");
|
|
Packit |
8f70b4 |
broken=true;
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// FileVerificator
|
|
Packit |
8f70b4 |
void FileVerificator::Init0()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
done=false;
|
|
Packit |
8f70b4 |
if(!ResMgr::QueryBool("xfer:verify",0)
|
|
Packit |
8f70b4 |
|| ResMgr::Query("xfer:verify-command",0).is_empty())
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void FileVerificator::InitVerify(const char *f)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(done)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
ArgV *args=new ArgV(ResMgr::Query("xfer:verify-command",0));
|
|
Packit |
8f70b4 |
args->Append(f);
|
|
Packit |
8f70b4 |
Log::global->Format(9,"running %s %s\n",args->a0(),f);
|
|
Packit |
8f70b4 |
verify_process=new InputFilter(args);
|
|
Packit |
8f70b4 |
verify_process->StderrToStdout();
|
|
Packit |
8f70b4 |
verify_buffer=new IOBufferFDStream(verify_process.Cast<FDStream>(),IOBuffer::GET);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileVerificator::FileVerificator(const char *f)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init0();
|
|
Packit |
8f70b4 |
InitVerify(f);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileVerificator::FileVerificator(const FDStream *stream)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init0();
|
|
Packit |
8f70b4 |
if(done)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
const char *f=stream->full_name;
|
|
Packit |
8f70b4 |
if(!f)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *cwd=stream->GetCwd();
|
|
Packit |
8f70b4 |
int cwd_len=xstrlen(cwd);
|
|
Packit |
8f70b4 |
if(cwd && cwd_len>0 && !strncmp(f,cwd,cwd_len))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
f+=cwd_len;
|
|
Packit |
8f70b4 |
while(*f=='/')
|
|
Packit |
8f70b4 |
f++;
|
|
Packit |
8f70b4 |
if(*f==0)
|
|
Packit |
8f70b4 |
f=".";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
InitVerify(f);
|
|
Packit |
8f70b4 |
if(verify_process)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
verify_process->SetProcGroup(stream->GetProcGroup());
|
|
Packit |
8f70b4 |
verify_process->SetCwd(cwd);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileVerificator::FileVerificator(const FileAccess *session,const char *f)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Init0();
|
|
Packit |
8f70b4 |
if(done)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
if(strcmp(session->GetProto(),"file"))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
InitVerify(f);
|
|
Packit |
8f70b4 |
verify_process->SetCwd(session->GetCwd());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileVerificator::~FileVerificator() {}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int FileVerificator::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
if(done)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
verify_process->Kill(SIGCONT);
|
|
Packit |
8f70b4 |
if(!verify_buffer->Eof())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
if(verify_process->GetProcState()!=ProcWait::TERMINATED)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
done=true;
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
if(verify_process->GetProcExitCode()!=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
error_text.set(verify_buffer->Get());
|
|
Packit |
8f70b4 |
error_text.rtrim('\n');
|
|
Packit |
8f70b4 |
if(error_text.length()==0)
|
|
Packit |
8f70b4 |
error_text.set(_("Verify command failed without a message"));
|
|
Packit |
8f70b4 |
const char *nl=strrchr(error_text,'\n');
|
|
Packit |
8f70b4 |
if(nl)
|
|
Packit |
8f70b4 |
error_text.set(nl+1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// special pointer to creator of ftp/ftp copier. It is init'ed in Ftp class.
|
|
Packit |
8f70b4 |
FileCopy *(*FileCopy::fxp_create)(FileCopyPeer *src,FileCopyPeer *dst,bool cont);
|