|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8f70b4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8f70b4 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
8f70b4 |
* (at your option) any later version.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8f70b4 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8f70b4 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8f70b4 |
* GNU General Public License for more details.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8f70b4 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <config.h>
|
|
Packit |
8f70b4 |
#include <sys/types.h>
|
|
Packit |
8f70b4 |
#include <sys/stat.h>
|
|
Packit |
8f70b4 |
#include <stddef.h>
|
|
Packit |
8f70b4 |
#include <assert.h>
|
|
Packit |
8f70b4 |
#include <errno.h>
|
|
Packit |
8f70b4 |
#include <fcntl.h>
|
|
Packit |
8f70b4 |
#include "pgetJob.h"
|
|
Packit |
8f70b4 |
#include "url.h"
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "log.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ResType pget_vars[] = {
|
|
Packit |
8f70b4 |
{"pget:save-status", "10s", ResMgr::TimeIntervalValidate,ResMgr::NoClosure},
|
|
Packit |
8f70b4 |
{"pget:default-n", "5", ResMgr::UNumberValidate,ResMgr::NoClosure},
|
|
Packit |
8f70b4 |
{"pget:min-chunk-size", "1M", ResMgr::UNumberValidate,ResMgr::NoClosure},
|
|
Packit |
8f70b4 |
{0}
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
ResDecls pget_vars_register(pget_vars);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#undef MIN
|
|
Packit |
8f70b4 |
#define MIN(a,b) ((a)<(b)?(a):(b))
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define super CopyJob
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int pgetJob::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(Done())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(status_timer.Stopped())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SaveStatus();
|
|
Packit |
8f70b4 |
status_timer.Reset();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(c->Done())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(status_file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
remove(status_file);
|
|
Packit |
8f70b4 |
status_file.set(0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(no_parallel || max_chunks<2)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
c->Resume();
|
|
Packit |
8f70b4 |
return super::Do();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(chunks_done && chunks && c->GetPos()>=limit0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
c->SetRangeLimit(limit0); // make it stop.
|
|
Packit |
8f70b4 |
c->Resume();
|
|
Packit |
8f70b4 |
c->Do();
|
|
Packit |
8f70b4 |
free_chunks();
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(chunks==0 || c->GetPos()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
c->Resume();
|
|
Packit |
8f70b4 |
m|=super::Do();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(chunks.count()>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(chunks[0]->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Log::global->Format(0,"pget: chunk[%d] error: %s\n",0,chunks[0]->ErrorText());
|
|
Packit |
8f70b4 |
no_parallel=true;
|
|
Packit |
8f70b4 |
c->Resume();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(!chunks[0]->Done() && chunks[0]->GetBytesCount()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
c->Resume();
|
|
Packit |
8f70b4 |
if(chunks.count()==1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
free_chunks();
|
|
Packit |
8f70b4 |
no_parallel=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
limit0=chunks[0]->c->GetRangeLimit();
|
|
Packit |
8f70b4 |
chunks.remove(0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
c->Suspend();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(Done())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
off_t offset=c->GetPos();
|
|
Packit |
8f70b4 |
off_t size=c->GetSize();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(chunks==0 && !chunks_done)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(size==NO_SIZE_YET)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(size==NO_SIZE || (c->put && c->put->GetLocal()==0))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Log::global->Write(0,_("pget: falling back to plain get"));
|
|
Packit |
8f70b4 |
Log::global->Write(0," (");
|
|
Packit |
8f70b4 |
if(c->put && c->put->GetLocal()==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Log::global->Write(0,_("the target file is remote"));
|
|
Packit |
8f70b4 |
if(size==NO_SIZE)
|
|
Packit |
8f70b4 |
Log::global->Write(0,", ");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(size==NO_SIZE)
|
|
Packit |
8f70b4 |
Log::global->Write(0,_("the source file size is unknown"));
|
|
Packit |
8f70b4 |
Log::global->Write(0,")\n");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
no_parallel=true;
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// Make sure the destination file is open before starting chunks,
|
|
Packit |
8f70b4 |
// it disables temp-name creation in the chunk's Init.
|
|
Packit |
8f70b4 |
if(c->put->GetLocal()->getfd()==-1)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
c->put->NeedSeek(); // seek before writing
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(pget_cont)
|
|
Packit |
8f70b4 |
LoadStatus();
|
|
Packit |
8f70b4 |
else if(status_file)
|
|
Packit |
8f70b4 |
remove(status_file);
|
|
Packit |
8f70b4 |
if(!chunks)
|
|
Packit |
8f70b4 |
InitChunks(offset,size);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!chunks)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
no_parallel=true;
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!pget_cont)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
SaveStatus();
|
|
Packit |
8f70b4 |
status_timer.Reset();
|
|
Packit |
8f70b4 |
if(ResMgr::QueryBool("file:use-fallocate",0)) {
|
|
Packit |
8f70b4 |
// allocate space after creating *.lftp-pget-status file,
|
|
Packit |
8f70b4 |
// so that the incomplete status is more obvious.
|
|
Packit |
8f70b4 |
const Ref<FDStream>& local=c->put->GetLocal();
|
|
Packit |
8f70b4 |
if(lftp_fallocate(local->getfd(),size)==-1 && errno!=ENOSYS && errno!=EOPNOTSUPP) {
|
|
Packit |
8f70b4 |
eprintf(_("pget: warning: space allocation for %s (%lld bytes) failed: %s\n"),
|
|
Packit |
8f70b4 |
local->name.get(),(long long)size,strerror(errno));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* cycle through the chunks */
|
|
Packit |
8f70b4 |
chunks_done=true;
|
|
Packit |
8f70b4 |
total_xferred=MIN(offset,limit0);
|
|
Packit |
8f70b4 |
off_t got_already=c->GetSize()-limit0;
|
|
Packit |
8f70b4 |
total_xfer_rate=c->GetRate();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
off_t rem=limit0-c->GetPos();
|
|
Packit |
8f70b4 |
if(rem<=0)
|
|
Packit |
8f70b4 |
total_eta=0;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
total_eta=c->GetETA(rem);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(chunks[i]->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Log::global->Format(0,"pget: chunk[%d] error: %s\n",i,chunks[i]->ErrorText());
|
|
Packit |
8f70b4 |
no_parallel=true;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!chunks[i]->Done())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(chunks[i]->GetPos()>=chunks[i]->start)
|
|
Packit |
8f70b4 |
total_xferred+=MIN(chunks[i]->GetPos(),chunks[i]->limit)
|
|
Packit |
8f70b4 |
-chunks[i]->start;
|
|
Packit |
8f70b4 |
if(total_eta>=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
long eta=chunks[i]->GetETA();
|
|
Packit |
8f70b4 |
if(eta<0)
|
|
Packit |
8f70b4 |
total_eta=-1;
|
|
Packit |
8f70b4 |
else if(eta>total_eta)
|
|
Packit |
8f70b4 |
total_eta=eta; // total eta is the maximum.
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
total_xfer_rate+=chunks[i]->GetRate();
|
|
Packit |
8f70b4 |
chunks_done=false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else // done
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
total_xferred+=chunks[i]->limit-chunks[i]->start;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
got_already-=chunks[i]->limit-chunks[i]->start;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
total_xferred+=got_already;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(no_parallel)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
free_chunks();
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// xgettext:c-format
|
|
Packit |
8f70b4 |
static const char pget_status_format[]=N_("`%s', got %lld of %lld (%d%%) %s%s");
|
|
Packit |
8f70b4 |
#define PGET_STATUS _(pget_status_format),name, \
|
|
Packit |
8f70b4 |
(long long)total_xferred,(long long)size, \
|
|
Packit |
8f70b4 |
percent(total_xferred,size),Speedometer::GetStrS(total_xfer_rate), \
|
|
Packit |
8f70b4 |
c->GetETAStrSFromTime(total_eta)
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void pgetJob::ShowRunStatus(const SMTaskRef<StatusLine>& s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(Done() || no_parallel || max_chunks<2 || !chunks)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
super::ShowRunStatus(s);
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *name=SqueezeName(s->GetWidthDelayed()-58);
|
|
Packit |
8f70b4 |
off_t size=GetSize();
|
|
Packit |
8f70b4 |
StringSet status;
|
|
Packit |
8f70b4 |
status.AppendFormat(PGET_STATUS);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int w=s->GetWidthDelayed();
|
|
Packit |
8f70b4 |
char *bar=string_alloca(w--);
|
|
Packit |
8f70b4 |
memset(bar,'+',w);
|
|
Packit |
8f70b4 |
bar[w]=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int i;
|
|
Packit |
8f70b4 |
int p=c->GetPos()*w/size;
|
|
Packit |
8f70b4 |
for(i=start0*w/size; i
|
|
Packit |
8f70b4 |
bar[i]='o';
|
|
Packit |
8f70b4 |
p=limit0*w/size;
|
|
Packit |
8f70b4 |
for( ; i
|
|
Packit |
8f70b4 |
bar[i]='.';
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
for(int chunk=0; chunk
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
p=(chunks[chunk]->Done()?chunks[chunk]->limit:chunks[chunk]->GetPos())*w/size;
|
|
Packit |
8f70b4 |
for(i=chunks[chunk]->start*w/size; i
|
|
Packit |
8f70b4 |
bar[i]='o';
|
|
Packit |
8f70b4 |
p=chunks[chunk]->limit*w/size;
|
|
Packit |
8f70b4 |
for( ; i
|
|
Packit |
8f70b4 |
bar[i]='.';
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
status.Append(bar);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
s->Show(status);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// list subjobs (chunk xfers) only when verbose
|
|
Packit |
8f70b4 |
xstring& pgetJob::FormatJobs(xstring& s,int verbose,int indent)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
indent--;
|
|
Packit |
8f70b4 |
if(!chunks)
|
|
Packit |
8f70b4 |
return Job::FormatJobs(s,verbose,indent);
|
|
Packit |
8f70b4 |
if(verbose>1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(c->GetPos()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
s.appendf("%*s\\chunk %lld-%lld\n",indent,"",(long long)start0,(long long)limit0);
|
|
Packit |
8f70b4 |
c->SetRangeLimit(limit0); // to see right ETA.
|
|
Packit |
8f70b4 |
CopyJob::FormatStatus(s,verbose,"\t");
|
|
Packit |
8f70b4 |
c->SetRangeLimit(FILE_END);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
Job::FormatJobs(s,verbose,indent);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& pgetJob::FormatStatus(xstring& s,int verbose,const char *prefix)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(Done() || no_parallel || max_chunks<2 || !chunks)
|
|
Packit |
8f70b4 |
return super::FormatStatus(s,verbose,prefix);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
s.append(prefix);
|
|
Packit |
8f70b4 |
const char *name=GetDispName();
|
|
Packit |
8f70b4 |
off_t size=GetSize();
|
|
Packit |
8f70b4 |
s.appendf(PGET_STATUS);
|
|
Packit |
8f70b4 |
return s.append('\n');
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void pgetJob::free_chunks()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(chunks)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
chunks_bytes+=chunks[i]->GetBytesCount();
|
|
Packit |
8f70b4 |
chunks.unset();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pgetJob::pgetJob(FileCopy *c1,const char *n,int m)
|
|
Packit |
8f70b4 |
: CopyJob(c1,n,"pget")
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
chunks_bytes=0;
|
|
Packit |
8f70b4 |
start0=limit0=0;
|
|
Packit |
8f70b4 |
total_xferred=0;
|
|
Packit |
8f70b4 |
total_xfer_rate=0;
|
|
Packit |
8f70b4 |
no_parallel=false;
|
|
Packit |
8f70b4 |
chunks_done=false;
|
|
Packit |
8f70b4 |
pget_cont=c->SetContinue(false);
|
|
Packit |
8f70b4 |
max_chunks=m?m:ResMgr::Query("pget:default-n",0);
|
|
Packit |
8f70b4 |
total_eta=-1;
|
|
Packit |
8f70b4 |
status_timer.SetResource("pget:save-status",0);
|
|
Packit |
8f70b4 |
const Ref<FDStream>& local=c->put->GetLocal();
|
|
Packit |
8f70b4 |
if(local && local->full_name)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
status_file.vset(local->full_name.get(),".lftp-pget-status",NULL);
|
|
Packit |
8f70b4 |
if(pget_cont)
|
|
Packit |
8f70b4 |
LoadStatus0();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void pgetJob::PrepareToDie()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
free_chunks();
|
|
Packit |
8f70b4 |
super::PrepareToDie();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
pgetJob::~pgetJob()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pgetJob::ChunkXfer *pgetJob::NewChunk(const char *remote,off_t start,off_t limit)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const Ref<FDStream>& local=c->put->GetLocal();
|
|
Packit |
8f70b4 |
FileCopyPeerFDStream
|
|
Packit |
8f70b4 |
*dst_peer=new FileCopyPeerFDStream(local,FileCopyPeer::PUT);
|
|
Packit |
8f70b4 |
dst_peer->NeedSeek(); // seek before writing
|
|
Packit |
8f70b4 |
dst_peer->SetBase(0);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileCopy *c1=FileCopy::New(c->get->Clone(),dst_peer,false);
|
|
Packit |
8f70b4 |
c1->SetRange(start,limit);
|
|
Packit |
8f70b4 |
c1->SetSize(GetSize());
|
|
Packit |
8f70b4 |
c1->DontCopyDate();
|
|
Packit |
8f70b4 |
c1->DontVerify();
|
|
Packit |
8f70b4 |
c1->FailIfCannotSeek();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ChunkXfer *chunk=new ChunkXfer(c1,remote,start,limit);
|
|
Packit |
8f70b4 |
chunk->cmdline.setf("\\chunk %lld-%lld",(long long)start,(long long)(limit-1));
|
|
Packit |
8f70b4 |
return chunk;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pgetJob::ChunkXfer::ChunkXfer(FileCopy *c1,const char *name,
|
|
Packit |
8f70b4 |
off_t s,off_t lim)
|
|
Packit |
8f70b4 |
: CopyJob(c1,name,"pget-chunk")
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
start=s;
|
|
Packit |
8f70b4 |
limit=lim;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void pgetJob::SaveStatus()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!status_file)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FILE *f=fopen(status_file,"w");
|
|
Packit |
8f70b4 |
if(!f)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
off_t size=GetSize();
|
|
Packit |
8f70b4 |
fprintf(f,"size=%lld\n",(long long)size);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int i=0;
|
|
Packit |
8f70b4 |
fprintf(f,"%d.pos=%lld\n",i,(long long)GetPos());
|
|
Packit |
8f70b4 |
if(!chunks)
|
|
Packit |
8f70b4 |
goto out_close;
|
|
Packit |
8f70b4 |
fprintf(f,"%d.limit=%lld\n",i,(long long)limit0);
|
|
Packit |
8f70b4 |
for(int chunk=0; chunk
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(chunks[chunk]->Done())
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
i++;
|
|
Packit |
8f70b4 |
fprintf(f,"%d.pos=%lld\n",i,(long long)chunks[chunk]->GetPos());
|
|
Packit |
8f70b4 |
fprintf(f,"%d.limit=%lld\n",i,(long long)chunks[chunk]->limit);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
out_close:
|
|
Packit |
8f70b4 |
fclose(f);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void pgetJob::LoadStatus0()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!status_file)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FILE *f=fopen(status_file,"r");
|
|
Packit |
8f70b4 |
if(!f) {
|
|
Packit |
8f70b4 |
int saved_errno=errno;
|
|
Packit |
8f70b4 |
// Probably the file is already complete
|
|
Packit |
8f70b4 |
// or it was previously downloaded by plain get.
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(stat(c->put->GetLocal()->full_name,&st)==-1)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
Log::global->Format(0,"pget: %s: cannot open (%s), resuming at the file end\n",
|
|
Packit |
8f70b4 |
status_file.get(),strerror(saved_errno));
|
|
Packit |
8f70b4 |
c->SetRange(st.st_size,FILE_END);
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
long long size;
|
|
Packit |
8f70b4 |
if(fscanf(f,"size=%lld\n",&size)<1)
|
|
Packit |
8f70b4 |
goto out_close;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
long long pos;
|
|
Packit |
8f70b4 |
int j;
|
|
Packit |
8f70b4 |
if(fscanf(f,"%d.pos=%lld\n",&j,&pos)<2 || j!=0)
|
|
Packit |
8f70b4 |
goto out_close;
|
|
Packit |
8f70b4 |
Log::global->Format(10,"pget: got chunk[%d] pos=%lld\n",j,pos);
|
|
Packit |
8f70b4 |
c->SetRange(pos,FILE_END);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
out_close:
|
|
Packit |
8f70b4 |
fclose(f);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void pgetJob::LoadStatus()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!status_file)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FILE *f=fopen(status_file,"r");
|
|
Packit |
8f70b4 |
if(!f)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(fstat(fileno(f),&st)<0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
out_close:
|
|
Packit |
8f70b4 |
fclose(f);
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
long long size;
|
|
Packit |
8f70b4 |
if(fscanf(f,"size=%lld\n",&size)<1)
|
|
Packit |
8f70b4 |
goto out_close;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int i=0;
|
|
Packit |
8f70b4 |
int max_chunks=st.st_size/20; // highest estimate - min 20 bytes per chunk in status file.
|
|
Packit |
8f70b4 |
long long *pos=(long long *)alloca(2*max_chunks*sizeof(*pos));
|
|
Packit |
8f70b4 |
long long *limit=pos+max_chunks;
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int j;
|
|
Packit |
8f70b4 |
if(fscanf(f,"%d.pos=%lld\n",&j,pos+i)<2 || j!=i)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
if(fscanf(f,"%d.limit=%lld\n",&j,limit+i)<2 || j!=i)
|
|
Packit |
8f70b4 |
goto out_close;
|
|
Packit |
8f70b4 |
if(i>0 && pos[i]>=limit[i])
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
Log::global->Format(10,"pget: got chunk[%d] pos=%lld\n",j,pos[i]);
|
|
Packit |
8f70b4 |
Log::global->Format(10,"pget: got chunk[%d] limit=%lld\n",j,limit[i]);
|
|
Packit |
8f70b4 |
i++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(i<1)
|
|
Packit |
8f70b4 |
goto out_close;
|
|
Packit |
8f70b4 |
if(size<c->GetSize()) // file grew?
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(limit[i-1]==size)
|
|
Packit |
8f70b4 |
limit[i-1]=c->GetSize();
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
pos[i]=size;
|
|
Packit |
8f70b4 |
limit[i]=c->GetSize();
|
|
Packit |
8f70b4 |
i++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int num_of_chunks=i-1;
|
|
Packit |
8f70b4 |
start0=pos[0];
|
|
Packit |
8f70b4 |
limit0=limit[0];
|
|
Packit |
8f70b4 |
c->SetRange(pos[0],FILE_END);
|
|
Packit |
8f70b4 |
if(num_of_chunks<1)
|
|
Packit |
8f70b4 |
goto out_close;
|
|
Packit |
8f70b4 |
for(i=0; i
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ChunkXfer *c=NewChunk(GetName(),pos[i+1],limit[i+1]);
|
|
Packit |
8f70b4 |
c->SetParentFg(this,false);
|
|
Packit |
8f70b4 |
chunks.append(c);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
goto out_close;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void pgetJob::InitChunks(off_t offset,off_t size)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
/* initialize chunks */
|
|
Packit |
8f70b4 |
off_t chunk_size=(size-offset)/max_chunks;
|
|
Packit |
8f70b4 |
int min_chunk_size=ResMgr::Query("pget:min-chunk-size",0);
|
|
Packit |
8f70b4 |
if(chunk_size
|
|
Packit |
8f70b4 |
chunk_size=min_chunk_size;
|
|
Packit |
8f70b4 |
int num_of_chunks=(size-offset)/chunk_size-1;
|
|
Packit |
8f70b4 |
if(num_of_chunks<1)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
start0=0;
|
|
Packit |
8f70b4 |
limit0=size-chunk_size*num_of_chunks;
|
|
Packit |
8f70b4 |
off_t curr_offs=limit0;
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ChunkXfer *c=NewChunk(GetName(),curr_offs,curr_offs+chunk_size);
|
|
Packit |
8f70b4 |
c->SetParentFg(this,false);
|
|
Packit |
8f70b4 |
chunks.append(c);
|
|
Packit |
8f70b4 |
curr_offs+=chunk_size;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
assert(curr_offs==size);
|
|
Packit |
8f70b4 |
}
|