|
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 |
#include <config.h>
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <sys/types.h>
|
|
Packit |
8f70b4 |
#include <sys/stat.h>
|
|
Packit |
8f70b4 |
#include <errno.h>
|
|
Packit |
8f70b4 |
#include <fcntl.h>
|
|
Packit |
8f70b4 |
#include <unistd.h>
|
|
Packit |
8f70b4 |
#include <assert.h>
|
|
Packit |
8f70b4 |
#include <mbswidth.h>
|
|
Packit |
8f70b4 |
#include "MirrorJob.h"
|
|
Packit |
8f70b4 |
#include "CmdExec.h"
|
|
Packit |
8f70b4 |
#include "rmJob.h"
|
|
Packit |
8f70b4 |
#include "mvJob.h"
|
|
Packit |
8f70b4 |
#include "ChmodJob.h"
|
|
Packit |
8f70b4 |
#include "mkdirJob.h"
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "plural.h"
|
|
Packit |
8f70b4 |
#include "FindJob.h"
|
|
Packit |
8f70b4 |
#include "url.h"
|
|
Packit |
8f70b4 |
#include "CopyJob.h"
|
|
Packit |
8f70b4 |
#include "pgetJob.h"
|
|
Packit |
8f70b4 |
#include "log.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define set_state(s) do { state=(s); \
|
|
Packit |
8f70b4 |
Log::global->Format(11,"mirror(%p) enters state %s\n", this, #s); } while(0)
|
|
Packit |
8f70b4 |
#define waiting_num waiting.count()
|
|
Packit |
8f70b4 |
#define transfer_count root_mirror->root_transfer_count
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& MirrorJob::FormatStatus(xstring& s,int v,const char *tab)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(Done())
|
|
Packit |
8f70b4 |
goto final;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
switch(state)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case(INITIAL_STATE):
|
|
Packit |
8f70b4 |
case(FINISHING):
|
|
Packit |
8f70b4 |
case(DONE):
|
|
Packit |
8f70b4 |
case(WAITING_FOR_TRANSFER):
|
|
Packit |
8f70b4 |
case(TARGET_REMOVE_OLD):
|
|
Packit |
8f70b4 |
case(TARGET_REMOVE_OLD_FIRST):
|
|
Packit |
8f70b4 |
case(TARGET_CHMOD):
|
|
Packit |
8f70b4 |
case(TARGET_MKDIR):
|
|
Packit |
8f70b4 |
case(SOURCE_REMOVING_SAME):
|
|
Packit |
8f70b4 |
case(LAST_EXEC):
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case(MAKE_TARGET_DIR):
|
|
Packit |
8f70b4 |
s.appendf("\tmkdir `%s' [%s]\n",target_dir.get(),target_session->CurrentStatus());
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case(CHANGING_DIR_SOURCE):
|
|
Packit |
8f70b4 |
case(CHANGING_DIR_TARGET):
|
|
Packit |
8f70b4 |
if(target_session->IsOpen())
|
|
Packit |
8f70b4 |
s.appendf("\tcd `%s' [%s]\n",target_dir.get(),target_session->CurrentStatus());
|
|
Packit |
8f70b4 |
if(source_session->IsOpen())
|
|
Packit |
8f70b4 |
s.appendf("\tcd `%s' [%s]\n",source_dir.get(),source_session->CurrentStatus());
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case(GETTING_LIST_INFO):
|
|
Packit |
8f70b4 |
if(target_list_info)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(target_relative_dir)
|
|
Packit |
8f70b4 |
s.appendf("\t%s: %s\n",target_relative_dir.get(),target_list_info->Status());
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
s.appendf("\t%s\n",target_list_info->Status());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(source_list_info)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(source_relative_dir)
|
|
Packit |
8f70b4 |
s.appendf("\t%s: %s\n",source_relative_dir.get(),source_list_info->Status());
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
s.appendf("\t%s\n",source_list_info->Status());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
final:
|
|
Packit |
8f70b4 |
if(stats.dirs>0)
|
|
Packit |
8f70b4 |
s.appendf(plural("%sTotal: %d director$y|ies$, %d file$|s$, %d symlink$|s$\n",
|
|
Packit |
8f70b4 |
stats.dirs,stats.tot_files,stats.tot_symlinks),
|
|
Packit |
8f70b4 |
tab,stats.dirs,stats.tot_files,stats.tot_symlinks);
|
|
Packit |
8f70b4 |
if(stats.new_files || stats.new_symlinks)
|
|
Packit |
8f70b4 |
s.appendf(plural("%sNew: %d file$|s$, %d symlink$|s$\n",
|
|
Packit |
8f70b4 |
stats.new_files,stats.new_symlinks),
|
|
Packit |
8f70b4 |
tab,stats.new_files,stats.new_symlinks);
|
|
Packit |
8f70b4 |
if(stats.mod_files || stats.mod_symlinks)
|
|
Packit |
8f70b4 |
s.appendf(plural("%sModified: %d file$|s$, %d symlink$|s$\n",
|
|
Packit |
8f70b4 |
stats.mod_files,stats.mod_symlinks),
|
|
Packit |
8f70b4 |
tab,stats.mod_files,stats.mod_symlinks);
|
|
Packit |
8f70b4 |
if(stats.bytes)
|
|
Packit |
8f70b4 |
s.appendf("%s%s\n",tab,CopyJob::FormatBytesTimeRate(stats.bytes,transfer_time_elapsed));
|
|
Packit |
8f70b4 |
if(stats.del_dirs || stats.del_files || stats.del_symlinks)
|
|
Packit |
8f70b4 |
s.appendf(plural(FlagSet(DELETE) ?
|
|
Packit |
8f70b4 |
"%sRemoved: %d director$y|ies$, %d file$|s$, %d symlink$|s$\n"
|
|
Packit |
8f70b4 |
:"%sTo be removed: %d director$y|ies$, %d file$|s$, %d symlink$|s$\n",
|
|
Packit |
8f70b4 |
stats.del_dirs,stats.del_files,stats.del_symlinks),
|
|
Packit |
8f70b4 |
tab,stats.del_dirs,stats.del_files,stats.del_symlinks);
|
|
Packit |
8f70b4 |
if(stats.error_count)
|
|
Packit |
8f70b4 |
s.appendf(plural("%s%d error$|s$ detected\n",stats.error_count),
|
|
Packit |
8f70b4 |
tab,stats.error_count);
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void MirrorJob::ShowRunStatus(const SMTaskRef<StatusLine>& s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int w=s->GetWidthDelayed();
|
|
Packit |
8f70b4 |
switch(state)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case(INITIAL_STATE):
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// these have a sub-job
|
|
Packit |
8f70b4 |
case(WAITING_FOR_TRANSFER):
|
|
Packit |
8f70b4 |
case(TARGET_REMOVE_OLD):
|
|
Packit |
8f70b4 |
case(TARGET_REMOVE_OLD_FIRST):
|
|
Packit |
8f70b4 |
case(TARGET_CHMOD):
|
|
Packit |
8f70b4 |
case(TARGET_MKDIR):
|
|
Packit |
8f70b4 |
case(SOURCE_REMOVING_SAME):
|
|
Packit |
8f70b4 |
case(FINISHING):
|
|
Packit |
8f70b4 |
case(DONE):
|
|
Packit |
8f70b4 |
case(LAST_EXEC):
|
|
Packit |
8f70b4 |
Job::ShowRunStatus(s);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case(MAKE_TARGET_DIR):
|
|
Packit |
8f70b4 |
s->Show("mkdir `%s' [%s]",target_dir.get(),target_session->CurrentStatus());
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case(CHANGING_DIR_SOURCE):
|
|
Packit |
8f70b4 |
case(CHANGING_DIR_TARGET):
|
|
Packit |
8f70b4 |
if(target_session->IsOpen() && (!source_session->IsOpen() || now%4>=2))
|
|
Packit |
8f70b4 |
s->Show("cd `%s' [%s]",target_dir.get(),target_session->CurrentStatus());
|
|
Packit |
8f70b4 |
else if(source_session->IsOpen())
|
|
Packit |
8f70b4 |
s->Show("cd `%s' [%s]",source_dir.get(),source_session->CurrentStatus());
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case(GETTING_LIST_INFO):
|
|
Packit |
8f70b4 |
if(target_list_info && (!source_list_info || now%4>=2))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *status=target_list_info->Status();
|
|
Packit |
8f70b4 |
int status_w=mbswidth(status, 0);
|
|
Packit |
8f70b4 |
int dw=w-status_w;
|
|
Packit |
8f70b4 |
if(dw<20)
|
|
Packit |
8f70b4 |
dw=20;
|
|
Packit |
8f70b4 |
if(target_relative_dir)
|
|
Packit |
8f70b4 |
s->Show("%s: %s",squeeze_file_name(target_relative_dir,dw),status);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
s->Show("%s",status);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(source_list_info)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *status=source_list_info->Status();
|
|
Packit |
8f70b4 |
int status_w=mbswidth(status, 0);
|
|
Packit |
8f70b4 |
int dw=w-status_w;
|
|
Packit |
8f70b4 |
if(dw<20)
|
|
Packit |
8f70b4 |
dw=20;
|
|
Packit |
8f70b4 |
if(source_relative_dir)
|
|
Packit |
8f70b4 |
s->Show("%s: %s",squeeze_file_name(source_relative_dir,dw),status);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
s->Show("%s",status);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& MirrorJob::FormatShortStatus(xstring& s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(bytes_to_transfer>0 && (!parent_mirror || parent_mirror->bytes_to_transfer!=bytes_to_transfer)) {
|
|
Packit |
8f70b4 |
long long curr_bytes_transferred=GetBytesCount();
|
|
Packit |
8f70b4 |
if(parent_mirror)
|
|
Packit |
8f70b4 |
curr_bytes_transferred+=bytes_transferred;
|
|
Packit |
8f70b4 |
s.appendf("%s/%s (%d%%)",
|
|
Packit |
8f70b4 |
xhuman(curr_bytes_transferred),xhuman(bytes_to_transfer),
|
|
Packit |
8f70b4 |
percent(curr_bytes_transferred,bytes_to_transfer));
|
|
Packit |
8f70b4 |
double rate=GetTransferRate();
|
|
Packit |
8f70b4 |
if(rate>=1)
|
|
Packit |
8f70b4 |
s.append(' ').append(Speedometer::GetStrProper(rate));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return s;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void MirrorJob::TransferStarted(CopyJob *cp)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(transfer_count==0)
|
|
Packit |
8f70b4 |
root_mirror->transfer_start_ts=now;
|
|
Packit |
8f70b4 |
JobStarted(cp);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void MirrorJob::JobStarted(Job *j)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
AddWaiting(j);
|
|
Packit |
8f70b4 |
transfer_count++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void MirrorJob::TransferFinished(Job *j)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
long long bytes_count=j->GetBytesCount();
|
|
Packit |
8f70b4 |
AddBytesTransferred(bytes_count);
|
|
Packit |
8f70b4 |
stats.bytes+=bytes_count;
|
|
Packit |
8f70b4 |
stats.time +=j->GetTimeSpent();
|
|
Packit |
8f70b4 |
if(j->ExitCode()==0 && verbose_report>=2) {
|
|
Packit |
8f70b4 |
xstring finished;
|
|
Packit |
8f70b4 |
const xstring& cmd=j->GetCmdLine();
|
|
Packit |
8f70b4 |
if(cmd[0]=='\\')
|
|
Packit |
8f70b4 |
finished.append(cmd+1,cmd.length()-1);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
finished.append(cmd);
|
|
Packit |
8f70b4 |
const xstring& rate=Speedometer::GetStrProper(j->GetTransferRate());
|
|
Packit |
8f70b4 |
if(rate.length()>0)
|
|
Packit |
8f70b4 |
finished.append(" (").append(rate).append(')');
|
|
Packit |
8f70b4 |
if(!(FlagSet(SCAN_ALL_FIRST) && finished.begins_with("mirror")))
|
|
Packit |
8f70b4 |
Report(_("Finished %s"),finished.get());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
JobFinished(j);
|
|
Packit |
8f70b4 |
if(transfer_count==0)
|
|
Packit |
8f70b4 |
root_mirror->transfer_time_elapsed += now-root_mirror->transfer_start_ts;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void MirrorJob::JobFinished(Job *j)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(j->ExitCode()!=0)
|
|
Packit |
8f70b4 |
stats.error_count++;
|
|
Packit |
8f70b4 |
RemoveWaiting(j);
|
|
Packit |
8f70b4 |
Delete(j);
|
|
Packit |
8f70b4 |
assert(transfer_count>0);
|
|
Packit |
8f70b4 |
transfer_count--;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
off_t MirrorJob::GetBytesCount()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
long long bytes_count=Job::GetBytesCount();
|
|
Packit |
8f70b4 |
if(!parent_mirror) {
|
|
Packit |
8f70b4 |
// bytes_transferred is cumulative over the mirror tree,
|
|
Packit |
8f70b4 |
// add it on the top only
|
|
Packit |
8f70b4 |
bytes_count+=bytes_transferred;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return bytes_count;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
double MirrorJob::GetTimeSpent()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
double t=transfer_time_elapsed;
|
|
Packit |
8f70b4 |
if(transfer_count>0)
|
|
Packit |
8f70b4 |
t+=now-root_mirror->transfer_start_ts;
|
|
Packit |
8f70b4 |
return t;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void MirrorJob::HandleFile(FileInfo *file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int res;
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// TODO: get rid of local hacks.
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *dst_name=file->name;
|
|
Packit |
8f70b4 |
if(FlagSet(TARGET_FLAT))
|
|
Packit |
8f70b4 |
dst_name=basename_ptr(dst_name);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// dir_name returns pointer to static data - need to dup it.
|
|
Packit |
8f70b4 |
const char *source_name=dir_file(source_dir,file->name);
|
|
Packit |
8f70b4 |
source_name=alloca_strdup(source_name);
|
|
Packit |
8f70b4 |
const char *target_name=dir_file(target_dir,dst_name);
|
|
Packit |
8f70b4 |
target_name=alloca_strdup(target_name);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *source_name_rel=dir_file(source_relative_dir,file->name);
|
|
Packit |
8f70b4 |
source_name_rel=alloca_strdup(source_name_rel);
|
|
Packit |
8f70b4 |
const char *target_name_rel=dir_file(target_relative_dir,dst_name);
|
|
Packit |
8f70b4 |
target_name_rel=alloca_strdup(target_name_rel);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileInfo::type filetype=FileInfo::NORMAL;
|
|
Packit |
8f70b4 |
if(file->Has(file->TYPE))
|
|
Packit |
8f70b4 |
filetype=file->filetype;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FileInfo *target=target_set->FindByName(file->name);
|
|
Packit |
8f70b4 |
if(target && target->Has(target->TYPE))
|
|
Packit |
8f70b4 |
filetype=target->filetype;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
switch(filetype)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case(FileInfo::NORMAL):
|
|
Packit |
8f70b4 |
case(FileInfo::REDIRECT):
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
bool remove_target=false;
|
|
Packit |
8f70b4 |
bool cont_this=false;
|
|
Packit |
8f70b4 |
bool use_pget=(pget_n>1) && target_is_local;
|
|
Packit |
8f70b4 |
if(file->Has(file->SIZE) && file->size
|
|
Packit |
8f70b4 |
use_pget=false;
|
|
Packit |
8f70b4 |
if(target_is_local)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(lstat(target_name,&st)!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// few safety checks.
|
|
Packit |
8f70b4 |
FileInfo *old=new_files_set->FindByName(file->name);
|
|
Packit |
8f70b4 |
if(old)
|
|
Packit |
8f70b4 |
goto skip; // file has appeared after mirror start
|
|
Packit |
8f70b4 |
old=old_files_set->FindByName(file->name);
|
|
Packit |
8f70b4 |
if(old && ((old->Has(old->SIZE) && old->size!=st.st_size)
|
|
Packit |
8f70b4 |
||(old->Has(old->DATE) && old->date!=st.st_mtime)))
|
|
Packit |
8f70b4 |
goto skip; // the file has changed after mirror start
|
|
Packit |
8f70b4 |
if(!script_only && access(target_name,W_OK)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// try to enable write access.
|
|
Packit |
8f70b4 |
chmod(target_name,st.st_mode|0200);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileInfo *old=target_set->FindByName(FileCopy::TempFileName(file->name));
|
|
Packit |
8f70b4 |
if(old)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(FlagSet(CONTINUE)
|
|
Packit |
8f70b4 |
&& old->Has(file->TYPE) && old->filetype==old->NORMAL
|
|
Packit |
8f70b4 |
&& (FlagSet(IGNORE_TIME) ||
|
|
Packit |
8f70b4 |
(file->Has(file->DATE) && old->Has(old->DATE)
|
|
Packit |
8f70b4 |
&& file->date + file->date.ts_prec < old->date - old->date.ts_prec))
|
|
Packit |
8f70b4 |
&& file->Has(file->SIZE) && old->Has(old->SIZE)
|
|
Packit |
8f70b4 |
&& file->size >= old->size)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
cont_this=true;
|
|
Packit |
8f70b4 |
stats.mod_files++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(!to_rm_mismatched->FindByName(file->name))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!FlagSet(OVERWRITE)) {
|
|
Packit |
8f70b4 |
remove_target=true;
|
|
Packit |
8f70b4 |
Report(_("Removing old file `%s'"),target_name_rel);
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
Report(_("Overwriting old file `%s'"),target_name_rel);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
stats.mod_files++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
stats.new_files++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(FlagSet(ONLY_EXISTING))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Report(_("Skipping file `%s' (only-existing)"),source_name_rel);
|
|
Packit |
8f70b4 |
goto skip;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
stats.new_files++;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Report(_("Transferring file `%s'"),source_name_rel);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(script)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV args(use_pget?"pget":"get");
|
|
Packit |
8f70b4 |
if(use_pget)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
args.Append("-n");
|
|
Packit |
8f70b4 |
args.Append(pget_n);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(cont_this)
|
|
Packit |
8f70b4 |
args.Append("-c");
|
|
Packit |
8f70b4 |
if(remove_target)
|
|
Packit |
8f70b4 |
args.Append("-e");
|
|
Packit |
8f70b4 |
if(FlagSet(ASCII))
|
|
Packit |
8f70b4 |
args.Append("-a");
|
|
Packit |
8f70b4 |
if(remove_source_files)
|
|
Packit |
8f70b4 |
args.Append("-E");
|
|
Packit |
8f70b4 |
args.Append("-O");
|
|
Packit |
8f70b4 |
args.Append(target_is_local?target_dir.get()
|
|
Packit |
8f70b4 |
:target_session->GetConnectURL().get());
|
|
Packit |
8f70b4 |
args.Append(source_session->GetFileURL(file->name));
|
|
Packit |
8f70b4 |
xstring_ca cmd(args.CombineQuoted());
|
|
Packit |
8f70b4 |
fprintf(script,"%s\n",cmd.get());
|
|
Packit |
8f70b4 |
if(script_only)
|
|
Packit |
8f70b4 |
goto skip;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileCopyPeer *src_peer=0;
|
|
Packit |
8f70b4 |
if(source_is_local)
|
|
Packit |
8f70b4 |
src_peer=new FileCopyPeerFDStream(new FileStream(source_name,O_RDONLY),FileCopyPeer::GET);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
src_peer=new FileCopyPeerFA(source_session->Clone(),file->name,FA::RETRIEVE);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileCopyPeer *dst_peer=0;
|
|
Packit |
8f70b4 |
if(target_is_local)
|
|
Packit |
8f70b4 |
dst_peer=new FileCopyPeerFDStream(new FileStream(target_name,O_WRONLY|O_CREAT|(cont_this?0:O_TRUNC)),FileCopyPeer::PUT);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
dst_peer=new FileCopyPeerFA(target_session->Clone(),dst_name,FA::STORE);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileCopy *c=FileCopy::New(src_peer,dst_peer,cont_this);
|
|
Packit |
8f70b4 |
if(remove_source_files)
|
|
Packit |
8f70b4 |
c->RemoveSourceLater();
|
|
Packit |
8f70b4 |
if(remove_target)
|
|
Packit |
8f70b4 |
c->RemoveTargetFirst();
|
|
Packit |
8f70b4 |
if(FlagSet(ASCII))
|
|
Packit |
8f70b4 |
c->Ascii();
|
|
Packit |
8f70b4 |
CopyJob *cp=(use_pget ? new pgetJob(c,file->name,pget_n) : new CopyJob(c,file->name,"mirror"));
|
|
Packit |
8f70b4 |
if(file->Has(file->DATE))
|
|
Packit |
8f70b4 |
cp->SetDate(file->date);
|
|
Packit |
8f70b4 |
if(file->Has(file->SIZE) && !FlagSet(IGNORE_SIZE))
|
|
Packit |
8f70b4 |
cp->SetSize(file->size);
|
|
Packit |
8f70b4 |
TransferStarted(cp);
|
|
Packit |
8f70b4 |
cp->cmdline.vset("\\transfer `",source_name_rel,"'",NULL);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
set_state(WAITING_FOR_TRANSFER);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
case(FileInfo::DIRECTORY):
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(recursion_mode==RECURSION_NEVER || FlagSet(NO_RECURSION))
|
|
Packit |
8f70b4 |
goto skip;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool create_target_subdir=true;
|
|
Packit |
8f70b4 |
const FileInfo *old=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(FlagSet(TARGET_FLAT)) {
|
|
Packit |
8f70b4 |
create_target_subdir=false;
|
|
Packit |
8f70b4 |
target_name=target_dir;
|
|
Packit |
8f70b4 |
goto do_submirror;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(target_set)
|
|
Packit |
8f70b4 |
old=target_set->FindByName(file->name);
|
|
Packit |
8f70b4 |
if(!old)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(FlagSet(ONLY_EXISTING))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Report(_("Skipping directory `%s' (only-existing)"),target_name_rel);
|
|
Packit |
8f70b4 |
goto skip;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(old->TypeIs(old->DIRECTORY))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
create_target_subdir=false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(target_is_local && !script_only)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if((FlagSet(RETR_SYMLINKS)?stat:lstat)(target_name,&st)!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(S_ISDIR(st.st_mode))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// try to enable write access
|
|
Packit |
8f70b4 |
// only if not enabled as chmod can clear sgid flags on directories
|
|
Packit |
8f70b4 |
if(st.st_mode!=(st.st_mode|0700))
|
|
Packit |
8f70b4 |
chmod(target_name,st.st_mode|0700);
|
|
Packit |
8f70b4 |
create_target_subdir=false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Report(_("Removing old local file `%s'"),target_name_rel);
|
|
Packit |
8f70b4 |
if(remove(target_name)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
eprintf("mirror: remove(%s): %s\n",target_name,strerror(errno));
|
|
Packit |
8f70b4 |
goto skip;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
create_target_subdir=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
do_submirror:
|
|
Packit |
8f70b4 |
// launch sub-mirror
|
|
Packit |
8f70b4 |
MirrorJob *mj=new MirrorJob(this,
|
|
Packit |
8f70b4 |
source_session->Clone(),target_session->Clone(),
|
|
Packit |
8f70b4 |
source_name,target_name);
|
|
Packit |
8f70b4 |
AddWaiting(mj);
|
|
Packit |
8f70b4 |
mj->cmdline.vset("\\mirror `",source_name_rel,"'",NULL);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
mj->source_relative_dir.set(source_name_rel);
|
|
Packit |
8f70b4 |
mj->target_relative_dir.set(target_name_rel);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
mj->create_target_dir=create_target_subdir;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(verbose_report>=3) {
|
|
Packit |
8f70b4 |
if(FlagSet(SCAN_ALL_FIRST))
|
|
Packit |
8f70b4 |
Report(_("Scanning directory `%s'"),mj->target_relative_dir.get());
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
Report(_("Mirroring directory `%s'"),mj->target_relative_dir.get());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
case(FileInfo::SYMLINK):
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(FlagSet(NO_SYMLINKS))
|
|
Packit |
8f70b4 |
goto skip;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!file->symlink)
|
|
Packit |
8f70b4 |
goto skip;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!target_is_local)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(script)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV args("ln");
|
|
Packit |
8f70b4 |
args.Append("-s");
|
|
Packit |
8f70b4 |
args.Append(file->symlink);
|
|
Packit |
8f70b4 |
args.Append(target_name);
|
|
Packit |
8f70b4 |
xstring_ca cmd(args.CombineQuoted());
|
|
Packit |
8f70b4 |
fprintf(script,"%s\n",cmd.get());
|
|
Packit |
8f70b4 |
if(script_only)
|
|
Packit |
8f70b4 |
goto skip;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool remove_target=false;
|
|
Packit |
8f70b4 |
FileInfo *old=target_set->FindByName(file->name);
|
|
Packit |
8f70b4 |
if(old && !to_rm_mismatched->FindByName(file->name))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Report(_("Removing old file `%s'"),target_name_rel);
|
|
Packit |
8f70b4 |
remove_target=true;
|
|
Packit |
8f70b4 |
stats.mod_symlinks++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
stats.new_symlinks++;
|
|
Packit |
8f70b4 |
Report(_("Making symbolic link `%s' to `%s'"),target_name_rel,file->symlink.get());
|
|
Packit |
8f70b4 |
mvJob *j=new mvJob(target_session->Clone(),file->symlink,target_name,FA::SYMLINK);
|
|
Packit |
8f70b4 |
if(remove_target)
|
|
Packit |
8f70b4 |
j->RemoveTargetFirst();
|
|
Packit |
8f70b4 |
JobStarted(j);
|
|
Packit |
8f70b4 |
RemoveSourceLater(file);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(script)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV args("shell");
|
|
Packit |
8f70b4 |
args.Append("ln");
|
|
Packit |
8f70b4 |
args.Append("-sf");
|
|
Packit |
8f70b4 |
args.Append(shell_encode(file->symlink));
|
|
Packit |
8f70b4 |
args.Append(shell_encode(target_name));
|
|
Packit |
8f70b4 |
xstring_ca cmd(args.CombineQuoted());
|
|
Packit |
8f70b4 |
fprintf(script,"%s\n",cmd.get());
|
|
Packit |
8f70b4 |
if(script_only)
|
|
Packit |
8f70b4 |
goto skip;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(lstat(target_name,&st)!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Report(_("Removing old local file `%s'"),target_name_rel);
|
|
Packit |
8f70b4 |
stats.mod_symlinks++;
|
|
Packit |
8f70b4 |
if(remove(target_name)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
eprintf("mirror: remove(%s): %s\n",target_name,strerror(errno));
|
|
Packit |
8f70b4 |
goto skip;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(FlagSet(ONLY_EXISTING))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Report(_("Skipping symlink `%s' (only-existing)"),target_name_rel);
|
|
Packit |
8f70b4 |
goto skip;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
stats.new_symlinks++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
Report(_("Making symbolic link `%s' to `%s'"),target_name_rel,file->symlink.get());
|
|
Packit |
8f70b4 |
res=symlink(file->symlink,target_name);
|
|
Packit |
8f70b4 |
if(res==-1)
|
|
Packit |
8f70b4 |
eprintf("mirror: symlink(%s): %s\n",target_name,strerror(errno));
|
|
Packit |
8f70b4 |
RemoveSourceLater(file);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
case FileInfo::UNKNOWN:
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
skip:
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void MirrorJob::InitSets()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(FlagSet(TARGET_FLAT) && !parent_mirror && target_set)
|
|
Packit |
8f70b4 |
source_set->Sort(FileSet::BYNAME_FLAT);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
source_set->Count(NULL,&stats.tot_files,&stats.tot_symlinks,&stats.tot_files);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
to_rm=new FileSet(target_set);
|
|
Packit |
8f70b4 |
to_rm->SubtractAny(source_set);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(FlagSet(DELETE_EXCLUDED) && target_set_excluded)
|
|
Packit |
8f70b4 |
to_rm->Merge(target_set_excluded);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
to_transfer=new FileSet(source_set);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!FlagSet(TRANSFER_ALL)) {
|
|
Packit |
8f70b4 |
same=new FileSet(source_set);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int ignore=0;
|
|
Packit |
8f70b4 |
if(FlagSet(ONLY_NEWER))
|
|
Packit |
8f70b4 |
ignore|=FileInfo::IGNORE_SIZE_IF_OLDER|FileInfo::IGNORE_DATE_IF_OLDER;
|
|
Packit |
8f70b4 |
if(!FlagSet(UPLOAD_OLDER) && strcmp(target_session->GetProto(),"file"))
|
|
Packit |
8f70b4 |
ignore|=FileInfo::IGNORE_DATE_IF_OLDER;
|
|
Packit |
8f70b4 |
if(FlagSet(IGNORE_TIME))
|
|
Packit |
8f70b4 |
ignore|=FileInfo::DATE;
|
|
Packit |
8f70b4 |
if(FlagSet(IGNORE_SIZE))
|
|
Packit |
8f70b4 |
ignore|=FileInfo::SIZE;
|
|
Packit |
8f70b4 |
to_transfer->SubtractSame(target_set,ignore);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
same->SubtractAny(to_transfer);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(newer_than!=NO_DATE)
|
|
Packit |
8f70b4 |
to_transfer->SubtractNotNewerThan(newer_than);
|
|
Packit |
8f70b4 |
if(older_than!=NO_DATE)
|
|
Packit |
8f70b4 |
to_transfer->SubtractNotOlderThan(older_than);
|
|
Packit |
8f70b4 |
if(size_range)
|
|
Packit |
8f70b4 |
to_transfer->SubtractSizeOutside(size_range);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(FlagSet(SCAN_ALL_FIRST)) {
|
|
Packit |
8f70b4 |
to_mkdir=new FileSet(to_transfer);
|
|
Packit |
8f70b4 |
to_mkdir->SubtractNotDirs();
|
|
Packit |
8f70b4 |
to_mkdir->SubtractAny(target_set);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
switch(recursion_mode) {
|
|
Packit |
8f70b4 |
case RECURSION_NEVER:
|
|
Packit |
8f70b4 |
to_transfer->SubtractDirs();
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case RECURSION_MISSING:
|
|
Packit |
8f70b4 |
to_transfer->SubtractDirs(target_set);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case RECURSION_NEWER:
|
|
Packit |
8f70b4 |
to_transfer->SubtractNotOlderDirs(target_set);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case RECURSION_ALWAYS:
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(skip_noaccess)
|
|
Packit |
8f70b4 |
to_transfer->ExcludeUnaccessible(source_session->GetUser());
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
new_files_set=new FileSet(to_transfer);
|
|
Packit |
8f70b4 |
new_files_set->SubtractAny(target_set);
|
|
Packit |
8f70b4 |
old_files_set=new FileSet(target_set);
|
|
Packit |
8f70b4 |
old_files_set->SubtractNotIn(to_transfer);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
to_rm_mismatched=new FileSet(old_files_set);
|
|
Packit |
8f70b4 |
to_rm_mismatched->SubtractSameType(to_transfer);
|
|
Packit |
8f70b4 |
to_rm_mismatched->SubtractNotDirs();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!FlagSet(DELETE))
|
|
Packit |
8f70b4 |
to_transfer->SubtractAny(to_rm_mismatched);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(FlagSet(TARGET_FLAT) && !parent_mirror && target_set) {
|
|
Packit |
8f70b4 |
source_set->Unsort();
|
|
Packit |
8f70b4 |
to_transfer->UnsortFlat();
|
|
Packit |
8f70b4 |
to_transfer->SubtractDirs();
|
|
Packit |
8f70b4 |
same->UnsortFlat();
|
|
Packit |
8f70b4 |
to_mkdir->Empty();
|
|
Packit |
8f70b4 |
new_files_set->UnsortFlat();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *sort_by=ResMgr::Query("mirror:sort-by",0);
|
|
Packit |
8f70b4 |
bool desc=strstr(sort_by,"-desc");
|
|
Packit |
8f70b4 |
if(!strncmp(sort_by,"name",4))
|
|
Packit |
8f70b4 |
to_transfer->SortByPatternList(ResMgr::Query("mirror:order",0));
|
|
Packit |
8f70b4 |
else if(!strncmp(sort_by,"date",4))
|
|
Packit |
8f70b4 |
to_transfer->Sort(FileSet::BYDATE);
|
|
Packit |
8f70b4 |
else if(!strncmp(sort_by,"size",4))
|
|
Packit |
8f70b4 |
to_transfer->Sort(FileSet::BYSIZE,false,true);
|
|
Packit |
8f70b4 |
if(desc)
|
|
Packit |
8f70b4 |
to_transfer->ReverseSort();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int dir_count=0;
|
|
Packit |
8f70b4 |
if(to_mkdir) {
|
|
Packit |
8f70b4 |
to_mkdir->Count(&dir_count,NULL,NULL,NULL);
|
|
Packit |
8f70b4 |
only_dirs = (dir_count==to_mkdir->count());
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
to_transfer->Count(&dir_count,NULL,NULL,NULL);
|
|
Packit |
8f70b4 |
only_dirs = (dir_count==to_transfer->count());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* root_transfer_count of child mirrors contains the value to add or
|
|
Packit |
8f70b4 |
subtract from transfer_count when doing "cd", "mkdir", "ls" on the source
|
|
Packit |
8f70b4 |
or target directories. This would prevent other mirrors (siblings, etc)
|
|
Packit |
8f70b4 |
from starting more jobs.
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
root_transfer_count is initialized once in ctor, so that change of
|
|
Packit |
8f70b4 |
mirror:parallel-directories setting won't disbalance the count.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
void MirrorJob::MirrorStarted()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!parent_mirror)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
transfer_count+=root_transfer_count;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void MirrorJob::MirrorFinished()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!parent_mirror)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
assert(transfer_count>=root_transfer_count);
|
|
Packit |
8f70b4 |
transfer_count-=root_transfer_count;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void MirrorJob::HandleChdir(FileAccessRef& session, int &redirections)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!session->IsOpen())
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
int res=session->Done();
|
|
Packit |
8f70b4 |
if(res<0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(res==FA::FILE_MOVED)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// cd to another url.
|
|
Packit |
8f70b4 |
const char *loc_c=session->GetNewLocation();
|
|
Packit |
8f70b4 |
int max_redirections=ResMgr::Query("xfer:max-redirections",0);
|
|
Packit |
8f70b4 |
if(loc_c && max_redirections>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(++redirections>max_redirections)
|
|
Packit |
8f70b4 |
goto cd_err_normal;
|
|
Packit |
8f70b4 |
eprintf(_("%s: received redirection to `%s'\n"),"mirror",loc_c);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char *loc=alloca_strdup(loc_c);
|
|
Packit |
8f70b4 |
ParsedURL u(loc,true);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool is_file=(last_char(loc)!='/');
|
|
Packit |
8f70b4 |
if(!u.proto)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FileAccess::Path new_cwd(session->GetNewCwd());
|
|
Packit |
8f70b4 |
new_cwd.Change(0,is_file,loc);
|
|
Packit |
8f70b4 |
session->PathVerify(new_cwd);
|
|
Packit |
8f70b4 |
session->Roll();
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
session->Close(); // loc_c is no longer valid.
|
|
Packit |
8f70b4 |
session=FA::New(&u);
|
|
Packit |
8f70b4 |
FileAccess::Path new_cwd(u.path,is_file,url::path_ptr(loc));
|
|
Packit |
8f70b4 |
session->PathVerify(new_cwd);
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
cd_err_normal:
|
|
Packit |
8f70b4 |
if(session==target_session && (script_only || FlagSet(SCAN_ALL_FIRST)))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char *dir=alloca_strdup(session->GetFile());
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
session->Chdir(dir,false);
|
|
Packit |
8f70b4 |
no_target_dir=true;
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(session==source_session && create_target_dir
|
|
Packit |
8f70b4 |
&& !FlagSet(NO_EMPTY_DIRS) && !skip_noaccess && parent_mirror)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// create target dir even if failed to cd to source dir.
|
|
Packit |
8f70b4 |
if(script)
|
|
Packit |
8f70b4 |
fprintf(script,"mkdir %s\n",target_session->GetFileURL(target_dir).get());
|
|
Packit |
8f70b4 |
if(!script_only)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV *a=new ArgV("mkdir");
|
|
Packit |
8f70b4 |
a->Append(target_dir);
|
|
Packit |
8f70b4 |
mkdirJob *mkj=new mkdirJob(target_session->Clone(),a);
|
|
Packit |
8f70b4 |
a->CombineTo(mkj->cmdline);
|
|
Packit |
8f70b4 |
JobStarted(mkj);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
remove_this_source_dir=false;
|
|
Packit |
8f70b4 |
eprintf("mirror: %s\n",session->StrError(res));
|
|
Packit |
8f70b4 |
stats.error_count++;
|
|
Packit |
8f70b4 |
MirrorFinished();
|
|
Packit |
8f70b4 |
set_state(FINISHING);
|
|
Packit |
8f70b4 |
source_session->Close();
|
|
Packit |
8f70b4 |
target_session->Close();
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(res==FA::OK)
|
|
Packit |
8f70b4 |
session->Close();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void MirrorJob::HandleListInfoCreation(const FileAccessRef& session,SMTaskRef<ListInfo>& list_info,const char *relative_dir)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(state!=GETTING_LIST_INFO)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(session==target_session && no_target_dir)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
target_set=new FileSet();
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
list_info=session->MakeListInfo();
|
|
Packit |
8f70b4 |
if(list_info==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
eprintf(_("mirror: protocol `%s' is not suitable for mirror\n"),
|
|
Packit |
8f70b4 |
session->GetProto());
|
|
Packit |
8f70b4 |
MirrorFinished();
|
|
Packit |
8f70b4 |
set_state(FINISHING);
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
list_info->UseCache(use_cache);
|
|
Packit |
8f70b4 |
int need=FileInfo::ALL_INFO;
|
|
Packit |
8f70b4 |
if(FlagSet(IGNORE_TIME))
|
|
Packit |
8f70b4 |
need&=~FileInfo::DATE;
|
|
Packit |
8f70b4 |
if(FlagSet(IGNORE_SIZE))
|
|
Packit |
8f70b4 |
need&=~FileInfo::SIZE;
|
|
Packit |
8f70b4 |
list_info->Need(need);
|
|
Packit |
8f70b4 |
if(FlagSet(RETR_SYMLINKS))
|
|
Packit |
8f70b4 |
list_info->FollowSymlinks();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
list_info->SetExclude(relative_dir,top_exclude?top_exclude:exclude);
|
|
Packit |
8f70b4 |
list_info->Roll();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void MirrorJob::HandleListInfo(SMTaskRef<ListInfo>& list_info, Ref<FileSet>& set, Ref<FileSet> *fsx)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!list_info)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
if(!list_info->Done())
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
if(list_info->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
eprintf("mirror: %s\n",list_info->ErrorText());
|
|
Packit |
8f70b4 |
stats.error_count++;
|
|
Packit |
8f70b4 |
MirrorFinished();
|
|
Packit |
8f70b4 |
set_state(FINISHING);
|
|
Packit |
8f70b4 |
source_list_info=0;
|
|
Packit |
8f70b4 |
target_list_info=0;
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
set=list_info->GetResult();
|
|
Packit |
8f70b4 |
if(fsx)
|
|
Packit |
8f70b4 |
*fsx=list_info->GetExcluded();
|
|
Packit |
8f70b4 |
list_info=0;
|
|
Packit |
8f70b4 |
set->ExcludeDots(); // don't need .. and .
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int MirrorJob::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int res;
|
|
Packit |
8f70b4 |
int m=STALL;
|
|
Packit |
8f70b4 |
FileInfo *file;
|
|
Packit |
8f70b4 |
Job *j;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
switch(state)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case(INITIAL_STATE):
|
|
Packit |
8f70b4 |
remove_this_source_dir=(remove_source_dirs && source_dir.last_char()!='/');
|
|
Packit |
8f70b4 |
if(!strcmp(target_dir,".") || !strcmp(target_dir,"..") || (FlagSet(SCAN_ALL_FIRST) && parent_mirror))
|
|
Packit |
8f70b4 |
create_target_dir=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
source_session->Chdir(source_dir);
|
|
Packit |
8f70b4 |
source_redirections=0;
|
|
Packit |
8f70b4 |
source_session->Roll();
|
|
Packit |
8f70b4 |
set_state(CHANGING_DIR_SOURCE);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
/*fallthrough*/
|
|
Packit |
8f70b4 |
case(CHANGING_DIR_SOURCE):
|
|
Packit |
8f70b4 |
HandleChdir(source_session,source_redirections);
|
|
Packit |
8f70b4 |
if(state!=CHANGING_DIR_SOURCE)
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
if(source_session->IsOpen())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
source_dir.set(source_session->GetCwd().GetDirectory());
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pre_MAKE_TARGET_DIR:
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!create_target_dir)
|
|
Packit |
8f70b4 |
goto pre_CHANGING_DIR_TARGET;
|
|
Packit |
8f70b4 |
if(target_is_local)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if((FlagSet(RETR_SYMLINKS)?stat:lstat)(target_dir,&st)!=-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(S_ISDIR(st.st_mode))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// try to enable write access
|
|
Packit |
8f70b4 |
// only if not enabled as chmod can clear sgid flags on directories
|
|
Packit |
8f70b4 |
if(!script_only && (st.st_mode!=(st.st_mode|0700)))
|
|
Packit |
8f70b4 |
chmod(target_dir,st.st_mode|0700);
|
|
Packit |
8f70b4 |
create_target_dir=false;
|
|
Packit |
8f70b4 |
goto pre_CHANGING_DIR_TARGET;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Report(_("Removing old local file `%s'"),target_dir.get());
|
|
Packit |
8f70b4 |
if(script)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV args("rm");
|
|
Packit |
8f70b4 |
args.Append(target_session->GetFileURL(target_dir));
|
|
Packit |
8f70b4 |
xstring_ca cmd(args.CombineQuoted());
|
|
Packit |
8f70b4 |
fprintf(script,"%s\n",cmd.get());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!script_only)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(remove(target_dir)==-1)
|
|
Packit |
8f70b4 |
eprintf("mirror: remove(%s): %s\n",target_dir.get(),strerror(errno));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(FlagSet(DEPTH_FIRST))
|
|
Packit |
8f70b4 |
goto pre_GETTING_LIST_INFO;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(target_relative_dir)
|
|
Packit |
8f70b4 |
Report(_("Making directory `%s'"),target_relative_dir.get());
|
|
Packit |
8f70b4 |
bool mkdir_p=(parent_mirror==0 || parent_mirror->create_target_dir);
|
|
Packit |
8f70b4 |
if(script)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV args("mkdir");
|
|
Packit |
8f70b4 |
if(mkdir_p)
|
|
Packit |
8f70b4 |
args.Append("-p");
|
|
Packit |
8f70b4 |
args.Append(target_session->GetFileURL(target_dir));
|
|
Packit |
8f70b4 |
xstring_ca cmd(args.CombineQuoted());
|
|
Packit |
8f70b4 |
fprintf(script,"%s\n",cmd.get());
|
|
Packit |
8f70b4 |
if(script_only)
|
|
Packit |
8f70b4 |
goto pre_CHANGING_DIR_TARGET;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
target_session->Mkdir(target_dir,mkdir_p);
|
|
Packit |
8f70b4 |
set_state(MAKE_TARGET_DIR);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
/*fallthrough*/
|
|
Packit |
8f70b4 |
case(MAKE_TARGET_DIR):
|
|
Packit |
8f70b4 |
res=target_session->Done();
|
|
Packit |
8f70b4 |
if(res==FA::IN_PROGRESS)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
target_session->Close();
|
|
Packit |
8f70b4 |
create_target_dir=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pre_CHANGING_DIR_TARGET:
|
|
Packit |
8f70b4 |
target_session->Chdir(target_dir);
|
|
Packit |
8f70b4 |
target_redirections=0;
|
|
Packit |
8f70b4 |
target_session->Roll();
|
|
Packit |
8f70b4 |
set_state(CHANGING_DIR_TARGET);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
/*fallthrough*/
|
|
Packit |
8f70b4 |
case(CHANGING_DIR_TARGET):
|
|
Packit |
8f70b4 |
HandleChdir(target_session,target_redirections);
|
|
Packit |
8f70b4 |
if(state!=CHANGING_DIR_TARGET)
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
if(target_session->IsOpen())
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
create_target_dir=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
target_dir.set(target_session->GetCwd().GetDirectory());
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pre_GETTING_LIST_INFO:
|
|
Packit |
8f70b4 |
set_state(GETTING_LIST_INFO);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
if(!source_set)
|
|
Packit |
8f70b4 |
HandleListInfoCreation(source_session,source_list_info,source_relative_dir);
|
|
Packit |
8f70b4 |
if(!target_set && !create_target_dir
|
|
Packit |
8f70b4 |
&& (!FlagSet(DEPTH_FIRST) || FlagSet(ONLY_EXISTING))
|
|
Packit |
8f70b4 |
&& !(FlagSet(TARGET_FLAT) && parent_mirror))
|
|
Packit |
8f70b4 |
HandleListInfoCreation(target_session,target_list_info,target_relative_dir);
|
|
Packit |
8f70b4 |
if(state!=GETTING_LIST_INFO)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
source_list_info=0;
|
|
Packit |
8f70b4 |
target_list_info=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return m; // give time to other tasks
|
|
Packit |
8f70b4 |
case(GETTING_LIST_INFO):
|
|
Packit |
8f70b4 |
HandleListInfo(source_list_info,source_set);
|
|
Packit |
8f70b4 |
HandleListInfo(target_list_info,target_set,&target_set_excluded);
|
|
Packit |
8f70b4 |
if(state!=GETTING_LIST_INFO)
|
|
Packit |
8f70b4 |
return MOVED;
|
|
Packit |
8f70b4 |
if(source_list_info || target_list_info)
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
MirrorFinished(); // leave room for transfers.
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(FlagSet(DEPTH_FIRST) && source_set && !target_set)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// transfer directories first
|
|
Packit |
8f70b4 |
InitSets();
|
|
Packit |
8f70b4 |
to_transfer->Unsort();
|
|
Packit |
8f70b4 |
to_transfer->SubtractNotDirs();
|
|
Packit |
8f70b4 |
goto pre_WAITING_FOR_TRANSFER;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// now we have both target and source file sets.
|
|
Packit |
8f70b4 |
if(parent_mirror)
|
|
Packit |
8f70b4 |
stats.dirs++;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(FlagSet(SCAN_ALL_FIRST) && parent_mirror)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
source_set->PrependPath(source_relative_dir);
|
|
Packit |
8f70b4 |
if(root_mirror->source_set_recursive)
|
|
Packit |
8f70b4 |
root_mirror->source_set_recursive->Merge(source_set);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
root_mirror->source_set_recursive=source_set.borrow();
|
|
Packit |
8f70b4 |
if(target_set) {
|
|
Packit |
8f70b4 |
target_set->PrependPath(target_relative_dir);
|
|
Packit |
8f70b4 |
if(root_mirror->target_set_recursive)
|
|
Packit |
8f70b4 |
root_mirror->target_set_recursive->Merge(target_set);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
root_mirror->target_set_recursive=target_set.borrow();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(target_set_excluded) {
|
|
Packit |
8f70b4 |
target_set_excluded->PrependPath(target_relative_dir);
|
|
Packit |
8f70b4 |
if(root_mirror->target_set_excluded)
|
|
Packit |
8f70b4 |
root_mirror->target_set_excluded->Merge(target_set_excluded);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
root_mirror->target_set_excluded=target_set_excluded.borrow();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
root_mirror->stats.dirs++;
|
|
Packit |
8f70b4 |
transfer_count++; // parent mirror will decrement it.
|
|
Packit |
8f70b4 |
goto pre_DONE;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(source_set_recursive) {
|
|
Packit |
8f70b4 |
source_set->Merge(source_set_recursive);
|
|
Packit |
8f70b4 |
source_set_recursive=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(target_set_recursive) {
|
|
Packit |
8f70b4 |
target_set->Merge(target_set_recursive);
|
|
Packit |
8f70b4 |
target_set_recursive=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
InitSets();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
to_transfer->CountBytes(&bytes_to_transfer);
|
|
Packit |
8f70b4 |
if(parent_mirror)
|
|
Packit |
8f70b4 |
parent_mirror->AddBytesToTransfer(bytes_to_transfer);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
to_rm->Count(&stats.del_dirs,&stats.del_files,&stats.del_symlinks,&stats.del_files);
|
|
Packit |
8f70b4 |
to_rm->rewind();
|
|
Packit |
8f70b4 |
to_rm_mismatched->Count(&stats.del_dirs,&stats.del_files,&stats.del_symlinks,&stats.del_files);
|
|
Packit |
8f70b4 |
to_rm_mismatched->rewind();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
target_set->Merge(target_set_excluded);
|
|
Packit |
8f70b4 |
target_set_excluded=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
set_state(TARGET_REMOVE_OLD_FIRST);
|
|
Packit |
8f70b4 |
goto TARGET_REMOVE_OLD_FIRST_label;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pre_TARGET_MKDIR:
|
|
Packit |
8f70b4 |
if(!to_mkdir)
|
|
Packit |
8f70b4 |
goto pre_WAITING_FOR_TRANSFER;
|
|
Packit |
8f70b4 |
to_mkdir->rewind();
|
|
Packit |
8f70b4 |
set_state(TARGET_MKDIR);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
/*fallthrough*/
|
|
Packit |
8f70b4 |
case(TARGET_MKDIR):
|
|
Packit |
8f70b4 |
while((j=FindDoneAwaitedJob())!=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
JobFinished(j);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(max_error_count>0 && stats.error_count>=max_error_count)
|
|
Packit |
8f70b4 |
goto pre_FINISHING;
|
|
Packit |
8f70b4 |
while(transfer_count
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
file=to_mkdir->curr();
|
|
Packit |
8f70b4 |
if(!file)
|
|
Packit |
8f70b4 |
goto pre_WAITING_FOR_TRANSFER;
|
|
Packit |
8f70b4 |
to_mkdir->next();
|
|
Packit |
8f70b4 |
if(!file->TypeIs(file->DIRECTORY))
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
if(script)
|
|
Packit |
8f70b4 |
fprintf(script,"mkdir %s\n",target_session->GetFileURL(file->name).get());
|
|
Packit |
8f70b4 |
if(!script_only)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV *a=new ArgV("mkdir");
|
|
Packit |
8f70b4 |
a->Append(file->name);
|
|
Packit |
8f70b4 |
mkdirJob *mkj=new mkdirJob(target_session->Clone(),a);
|
|
Packit |
8f70b4 |
a->CombineTo(mkj->cmdline);
|
|
Packit |
8f70b4 |
JobStarted(mkj);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pre_WAITING_FOR_TRANSFER:
|
|
Packit |
8f70b4 |
to_transfer->rewind();
|
|
Packit |
8f70b4 |
set_state(WAITING_FOR_TRANSFER);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
/*fallthrough*/
|
|
Packit |
8f70b4 |
case(WAITING_FOR_TRANSFER):
|
|
Packit |
8f70b4 |
while((j=FindDoneAwaitedJob())!=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
TransferFinished(j);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(max_error_count>0 && stats.error_count>=max_error_count)
|
|
Packit |
8f70b4 |
goto pre_FINISHING;
|
|
Packit |
8f70b4 |
while(transfer_count
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
file=to_transfer->curr();
|
|
Packit |
8f70b4 |
if(!file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// go to the next step only when all transfers have finished
|
|
Packit |
8f70b4 |
if(waiting_num>0)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
if(FlagSet(DEPTH_FIRST))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// we have been in the depth, don't go there again
|
|
Packit |
8f70b4 |
SetFlags(DEPTH_FIRST,false);
|
|
Packit |
8f70b4 |
SetFlags(NO_RECURSION,true);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// if we have not created any subdirs and there are only subdirs,
|
|
Packit |
8f70b4 |
// then the directory would be empty - skip it.
|
|
Packit |
8f70b4 |
if(FlagSet(NO_EMPTY_DIRS) && stats.dirs==0 && only_dirs)
|
|
Packit |
8f70b4 |
goto pre_FINISHING_FIX_LOCAL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
MirrorStarted();
|
|
Packit |
8f70b4 |
goto pre_MAKE_TARGET_DIR;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
goto pre_TARGET_REMOVE_OLD;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
HandleFile(file);
|
|
Packit |
8f70b4 |
to_transfer->next();
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pre_TARGET_REMOVE_OLD:
|
|
Packit |
8f70b4 |
if(FlagSet(REMOVE_FIRST))
|
|
Packit |
8f70b4 |
goto pre_TARGET_CHMOD;
|
|
Packit |
8f70b4 |
set_state(TARGET_REMOVE_OLD);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
/*fallthrough*/
|
|
Packit |
8f70b4 |
case(TARGET_REMOVE_OLD):
|
|
Packit |
8f70b4 |
case(TARGET_REMOVE_OLD_FIRST):
|
|
Packit |
8f70b4 |
TARGET_REMOVE_OLD_FIRST_label:
|
|
Packit |
8f70b4 |
while((j=FindDoneAwaitedJob())!=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
JobFinished(j);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(max_error_count>0 && stats.error_count>=max_error_count)
|
|
Packit |
8f70b4 |
goto pre_FINISHING;
|
|
Packit |
8f70b4 |
while(transfer_count
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
file=0;
|
|
Packit |
8f70b4 |
if(!file && state==TARGET_REMOVE_OLD_FIRST)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
file=to_rm_mismatched->curr();
|
|
Packit |
8f70b4 |
to_rm_mismatched->next();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!file && (state==TARGET_REMOVE_OLD || FlagSet(REMOVE_FIRST)))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
file=to_rm->curr();
|
|
Packit |
8f70b4 |
to_rm->next();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(waiting_num>0)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
if(state==TARGET_REMOVE_OLD)
|
|
Packit |
8f70b4 |
goto pre_TARGET_CHMOD;
|
|
Packit |
8f70b4 |
goto pre_TARGET_MKDIR;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!FlagSet(DELETE))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(FlagSet(REPORT_NOT_DELETED))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *target_name_rel=dir_file(target_relative_dir,file->name);
|
|
Packit |
8f70b4 |
if(file->TypeIs(file->DIRECTORY))
|
|
Packit |
8f70b4 |
Report(_("Old directory `%s' is not removed"),target_name_rel);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
Report(_("Old file `%s' is not removed"),target_name_rel);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool use_rmdir = (file->TypeIs(file->DIRECTORY)
|
|
Packit |
8f70b4 |
&& recursion_mode==RECURSION_NEVER);
|
|
Packit |
8f70b4 |
if(script)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV args(use_rmdir?"rmdir":"rm");
|
|
Packit |
8f70b4 |
if(file->TypeIs(file->DIRECTORY) && !use_rmdir)
|
|
Packit |
8f70b4 |
args.Append("-r");
|
|
Packit |
8f70b4 |
args.Append(target_session->GetFileURL(file->name));
|
|
Packit |
8f70b4 |
xstring_ca cmd(args.CombineQuoted());
|
|
Packit |
8f70b4 |
fprintf(script,"%s\n",cmd.get());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!script_only)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV *args=new ArgV(use_rmdir?"rmdir":"rm");
|
|
Packit |
8f70b4 |
args->Append(dir_file(".",file->name));
|
|
Packit |
8f70b4 |
args->seek(1);
|
|
Packit |
8f70b4 |
rmJob *j=new rmJob(target_session->Clone(),args);
|
|
Packit |
8f70b4 |
args->CombineTo(j->cmdline);
|
|
Packit |
8f70b4 |
JobStarted(j);
|
|
Packit |
8f70b4 |
if(file->TypeIs(file->DIRECTORY))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(recursion_mode==RECURSION_NEVER)
|
|
Packit |
8f70b4 |
j->Rmdir();
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
j->Recurse();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *target_name_rel=dir_file(target_relative_dir,file->name);
|
|
Packit |
8f70b4 |
if(file->TypeIs(file->DIRECTORY))
|
|
Packit |
8f70b4 |
Report(_("Removing old directory `%s'"),target_name_rel);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
Report(_("Removing old file `%s'"),target_name_rel);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pre_TARGET_CHMOD:
|
|
Packit |
8f70b4 |
if(FlagSet(NO_PERMS))
|
|
Packit |
8f70b4 |
goto pre_FINISHING_FIX_LOCAL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
to_transfer->rewind();
|
|
Packit |
8f70b4 |
if(FlagSet(TARGET_FLAT))
|
|
Packit |
8f70b4 |
to_transfer->Sort(FileSet::BYNAME_FLAT);
|
|
Packit |
8f70b4 |
set_state(TARGET_CHMOD);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
/*fallthrough*/
|
|
Packit |
8f70b4 |
case(TARGET_CHMOD):
|
|
Packit |
8f70b4 |
while((j=FindDoneAwaitedJob())!=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
JobFinished(j);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(max_error_count>0 && stats.error_count>=max_error_count)
|
|
Packit |
8f70b4 |
goto pre_FINISHING;
|
|
Packit |
8f70b4 |
while(transfer_count
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
file=to_transfer->curr();
|
|
Packit |
8f70b4 |
if(!file)
|
|
Packit |
8f70b4 |
goto pre_FINISHING_FIX_LOCAL;
|
|
Packit |
8f70b4 |
to_transfer->next();
|
|
Packit |
8f70b4 |
if(file->TypeIs(file->SYMLINK))
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
if(!file->Has(file->MODE))
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
mode_t mode_mask=get_mode_mask();
|
|
Packit |
8f70b4 |
mode_t def_mode=(file->TypeIs(file->DIRECTORY)?0775:0664)&~mode_mask;
|
|
Packit |
8f70b4 |
if(target_is_local && file->mode==def_mode)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(!target_is_local || lstat(dir_file(target_dir,file->name),&st)==-1)
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
if((st.st_mode&07777)==(file->mode&~mode_mask))
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
FileInfo *target=target_set->FindByName(file->name);
|
|
Packit |
8f70b4 |
if(target && target->filetype==file->DIRECTORY && file->filetype==file->DIRECTORY
|
|
Packit |
8f70b4 |
&& target->mode==(file->mode&~mode_mask) && (target->mode&0200))
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
if(script)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV args("chmod");
|
|
Packit |
8f70b4 |
args.Append(xstring::format("%03lo",(unsigned long)(file->mode&~mode_mask)));
|
|
Packit |
8f70b4 |
args.Append(target_session->GetFileURL(file->name));
|
|
Packit |
8f70b4 |
xstring_ca cmd(args.CombineQuoted());
|
|
Packit |
8f70b4 |
fprintf(script,"%s\n",cmd.get());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!script_only)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV *a=new ArgV("chmod");
|
|
Packit |
8f70b4 |
a->Append(dir_file(".",file->name));
|
|
Packit |
8f70b4 |
a->seek(1);
|
|
Packit |
8f70b4 |
ChmodJob *cj=new ChmodJob(target_session->Clone(),
|
|
Packit |
8f70b4 |
file->mode&~mode_mask,a);
|
|
Packit |
8f70b4 |
a->CombineTo(cj->cmdline);
|
|
Packit |
8f70b4 |
if(!verbose_report)
|
|
Packit |
8f70b4 |
cj->BeQuiet(); // chmod is not supported on all servers; be quiet.
|
|
Packit |
8f70b4 |
JobStarted(cj);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pre_FINISHING_FIX_LOCAL:
|
|
Packit |
8f70b4 |
if(target_is_local && !script_only) // FIXME
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const bool flat=FlagSet(TARGET_FLAT);
|
|
Packit |
8f70b4 |
to_transfer->Sort(FileSet::BYNAME_FLAT);
|
|
Packit |
8f70b4 |
to_transfer->LocalUtime(target_dir,/*only_dirs=*/true,flat);
|
|
Packit |
8f70b4 |
if(FlagSet(ALLOW_CHOWN))
|
|
Packit |
8f70b4 |
to_transfer->LocalChown(target_dir,flat);
|
|
Packit |
8f70b4 |
if(!FlagSet(NO_PERMS) && same)
|
|
Packit |
8f70b4 |
same->LocalChmod(target_dir,get_mode_mask(),flat);
|
|
Packit |
8f70b4 |
if(FlagSet(ALLOW_CHOWN) && same)
|
|
Packit |
8f70b4 |
same->LocalChown(target_dir,flat);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(remove_source_files && (same || to_rm_src))
|
|
Packit |
8f70b4 |
goto pre_SOURCE_REMOVING_SAME;
|
|
Packit |
8f70b4 |
pre_FINISHING:
|
|
Packit |
8f70b4 |
set_state(FINISHING);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
/*fallthrough*/
|
|
Packit |
8f70b4 |
case(FINISHING):
|
|
Packit |
8f70b4 |
while((j=FindDoneAwaitedJob())!=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
JobFinished(j);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(waiting_num>0)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// all jobs finished.
|
|
Packit |
8f70b4 |
if(remove_this_source_dir) {
|
|
Packit |
8f70b4 |
// remove source directory once.
|
|
Packit |
8f70b4 |
remove_this_source_dir=false;
|
|
Packit |
8f70b4 |
if(script)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV args("rmdir");
|
|
Packit |
8f70b4 |
args.Append(source_session->GetFileURL(source_dir));
|
|
Packit |
8f70b4 |
xstring_ca cmd(args.CombineQuoted());
|
|
Packit |
8f70b4 |
fprintf(script,"%s\n",cmd.get());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!script_only)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV *args=new ArgV("rmdir");
|
|
Packit |
8f70b4 |
args->Append(source_dir);
|
|
Packit |
8f70b4 |
args->seek(1);
|
|
Packit |
8f70b4 |
rmJob *j=new rmJob(source_session->Clone(),args);
|
|
Packit |
8f70b4 |
args->CombineTo(j->cmdline);
|
|
Packit |
8f70b4 |
j->Rmdir();
|
|
Packit |
8f70b4 |
JobStarted(j);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(source_relative_dir)
|
|
Packit |
8f70b4 |
Report(_("Removing source directory `%s'"),source_relative_dir.get());
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// all jobs finished and src dir removed, if needed.
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
transfer_count++; // parent mirror will decrement it.
|
|
Packit |
8f70b4 |
if(parent_mirror)
|
|
Packit |
8f70b4 |
parent_mirror->stats.Add(stats);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(stats.HaveSomethingDone(flags) && on_change)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
CmdExec *exec=new CmdExec(source_session->Clone(),0);
|
|
Packit |
8f70b4 |
AddWaiting(exec);
|
|
Packit |
8f70b4 |
exec->FeedCmd(on_change);
|
|
Packit |
8f70b4 |
exec->FeedCmd("\n");
|
|
Packit |
8f70b4 |
set_state(LAST_EXEC);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
goto pre_DONE;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pre_SOURCE_REMOVING_SAME:
|
|
Packit |
8f70b4 |
if(!same)
|
|
Packit |
8f70b4 |
same=to_rm_src.borrow();
|
|
Packit |
8f70b4 |
else if(to_rm_src)
|
|
Packit |
8f70b4 |
same->Merge(to_rm_src);
|
|
Packit |
8f70b4 |
same->rewind();
|
|
Packit |
8f70b4 |
set_state(SOURCE_REMOVING_SAME);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
/*fallthrough*/
|
|
Packit |
8f70b4 |
case(SOURCE_REMOVING_SAME):
|
|
Packit |
8f70b4 |
while((j=FindDoneAwaitedJob())!=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
JobFinished(j);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(max_error_count>0 && stats.error_count>=max_error_count)
|
|
Packit |
8f70b4 |
goto pre_FINISHING;
|
|
Packit |
8f70b4 |
while(transfer_count
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
file=same->curr();
|
|
Packit |
8f70b4 |
same->next();
|
|
Packit |
8f70b4 |
if(!file)
|
|
Packit |
8f70b4 |
goto pre_FINISHING;
|
|
Packit |
8f70b4 |
if(file->TypeIs(file->DIRECTORY))
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
if(script)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV args("rm");
|
|
Packit |
8f70b4 |
args.Append(source_session->GetFileURL(file->name));
|
|
Packit |
8f70b4 |
xstring_ca cmd(args.CombineQuoted());
|
|
Packit |
8f70b4 |
fprintf(script,"%s\n",cmd.get());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!script_only)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ArgV *args=new ArgV("rm");
|
|
Packit |
8f70b4 |
args->Append(dir_file(".",file->name));
|
|
Packit |
8f70b4 |
args->seek(1);
|
|
Packit |
8f70b4 |
rmJob *j=new rmJob(source_session->Clone(),args);
|
|
Packit |
8f70b4 |
args->CombineTo(j->cmdline);
|
|
Packit |
8f70b4 |
JobStarted(j);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *source_name_rel=dir_file(source_relative_dir,file->name);
|
|
Packit |
8f70b4 |
Report(_("Removing source file `%s'"),source_name_rel);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
case(LAST_EXEC):
|
|
Packit |
8f70b4 |
while((j=FindDoneAwaitedJob())!=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
RemoveWaiting(j);
|
|
Packit |
8f70b4 |
Delete(j);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(waiting_num>0)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
pre_DONE:
|
|
Packit |
8f70b4 |
set_state(DONE);
|
|
Packit |
8f70b4 |
m=MOVED;
|
|
Packit |
8f70b4 |
bytes_transferred=0;
|
|
Packit |
8f70b4 |
if(!parent_mirror && FlagSet(LOOP) && stats.HaveSomethingDone(flags) && !stats.error_count)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
PrintStatus(0,"");
|
|
Packit |
8f70b4 |
printf(_("Retrying mirror...\n"));
|
|
Packit |
8f70b4 |
stats.Reset();
|
|
Packit |
8f70b4 |
source_set=0;
|
|
Packit |
8f70b4 |
target_set=0;
|
|
Packit |
8f70b4 |
goto pre_GETTING_LIST_INFO;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
/*fallthrough*/
|
|
Packit |
8f70b4 |
case(DONE):
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
// give direct parent priority over grand-parents.
|
|
Packit |
8f70b4 |
if(transfer_count
|
|
Packit |
8f70b4 |
m|=parent_mirror->Roll();
|
|
Packit |
8f70b4 |
return m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
MirrorJob::MirrorJob(MirrorJob *parent,
|
|
Packit |
8f70b4 |
FileAccess *source,FileAccess *target,
|
|
Packit |
8f70b4 |
const char *new_source_dir,const char *new_target_dir)
|
|
Packit |
8f70b4 |
:
|
|
Packit |
8f70b4 |
bytes_transferred(0), bytes_to_transfer(0),
|
|
Packit |
8f70b4 |
source_dir(new_source_dir), target_dir(new_target_dir),
|
|
Packit |
8f70b4 |
transfer_time_elapsed(0), root_transfer_count(0),
|
|
Packit |
8f70b4 |
verbose_report(0),
|
|
Packit |
8f70b4 |
parent_mirror(parent), root_mirror(parent?parent->root_mirror:this)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
source_session=source;
|
|
Packit |
8f70b4 |
target_session=target;
|
|
Packit |
8f70b4 |
// TODO: get rid of this.
|
|
Packit |
8f70b4 |
source_is_local=!strcmp(source_session->GetProto(),"file");
|
|
Packit |
8f70b4 |
target_is_local=!strcmp(target_session->GetProto(),"file");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
create_target_dir=true;
|
|
Packit |
8f70b4 |
no_target_dir=false;
|
|
Packit |
8f70b4 |
remove_this_source_dir=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
flags=0;
|
|
Packit |
8f70b4 |
recursion_mode=RECURSION_ALWAYS;
|
|
Packit |
8f70b4 |
max_error_count=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
exclude=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
set_state(INITIAL_STATE);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
newer_than=NO_DATE;
|
|
Packit |
8f70b4 |
older_than=NO_DATE;
|
|
Packit |
8f70b4 |
size_range=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
script=0;
|
|
Packit |
8f70b4 |
script_only=false;
|
|
Packit |
8f70b4 |
script_needs_closing=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
use_cache=false;
|
|
Packit |
8f70b4 |
remove_source_files=false;
|
|
Packit |
8f70b4 |
remove_source_dirs=false;
|
|
Packit |
8f70b4 |
skip_noaccess=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
parallel=1;
|
|
Packit |
8f70b4 |
pget_n=1;
|
|
Packit |
8f70b4 |
pget_minchunk=0x10000;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
source_redirections=0;
|
|
Packit |
8f70b4 |
target_redirections=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(parent_mirror)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
bool parallel_dirs=ResMgr::QueryBool("mirror:parallel-directories",0);
|
|
Packit |
8f70b4 |
// If parallel_dirs is true, allow parent mirror to continue
|
|
Packit |
8f70b4 |
// processing other directories, otherwise block it until we
|
|
Packit |
8f70b4 |
// get file sets and start transfers.
|
|
Packit |
8f70b4 |
// See also comment at MirrorJob::MirrorStarted().
|
|
Packit |
8f70b4 |
root_transfer_count=parallel_dirs?1:1024;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// inherit flags and other things
|
|
Packit |
8f70b4 |
SetFlags(parent->flags,1);
|
|
Packit |
8f70b4 |
UseCache(parent->use_cache);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
SetExclude(parent->exclude);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
verbose_report=parent->verbose_report;
|
|
Packit |
8f70b4 |
newer_than=parent->newer_than;
|
|
Packit |
8f70b4 |
older_than=parent->older_than;
|
|
Packit |
8f70b4 |
size_range=parent->size_range;
|
|
Packit |
8f70b4 |
parallel=parent->parallel;
|
|
Packit |
8f70b4 |
pget_n=parent->pget_n;
|
|
Packit |
8f70b4 |
pget_minchunk=parent->pget_minchunk;
|
|
Packit |
8f70b4 |
remove_source_files=parent->remove_source_files;
|
|
Packit |
8f70b4 |
remove_source_dirs=parent->remove_source_dirs;
|
|
Packit |
8f70b4 |
skip_noaccess=parent->skip_noaccess;
|
|
Packit |
8f70b4 |
no_target_dir=parent->no_target_dir;
|
|
Packit |
8f70b4 |
recursion_mode=parent->recursion_mode;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
script=parent->script;
|
|
Packit |
8f70b4 |
script_needs_closing=false;
|
|
Packit |
8f70b4 |
script_name.set(parent->script_name);
|
|
Packit |
8f70b4 |
script_only=parent->script_only;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
max_error_count=parent->max_error_count;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
MirrorStarted();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
MirrorJob::~MirrorJob()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(script && script_needs_closing)
|
|
Packit |
8f70b4 |
fclose(script);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void MirrorJob::va_Report(const char *fmt,va_list v)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(parent_mirror)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
parent_mirror->va_Report(fmt,v);
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(verbose_report)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
pid_t p=tcgetpgrp(fileno(stdout));
|
|
Packit |
8f70b4 |
if(p>0 && p!=getpgrp())
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
vfprintf(stdout,fmt,v);
|
|
Packit |
8f70b4 |
printf("\n");
|
|
Packit |
8f70b4 |
fflush(stdout);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void MirrorJob::Report(const char *fmt,...)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
va_list v;
|
|
Packit |
8f70b4 |
va_start(v,fmt);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
va_Report(fmt,v);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
va_end(v);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
extern "C" {
|
|
Packit |
8f70b4 |
#include "parse-datetime.h"
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void MirrorJob::SetNewerThan(const char *f)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct timespec ts;
|
|
Packit |
8f70b4 |
if(parse_datetime(&ts,f,0))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
newer_than=ts.tv_sec;
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(stat(f,&st)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
perror(f);
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
newer_than=st.st_mtime;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void MirrorJob::SetOlderThan(const char *f)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct timespec ts;
|
|
Packit |
8f70b4 |
if(parse_datetime(&ts,f,0))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
older_than=ts.tv_sec;
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(stat(f,&st)==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
perror(f);
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
older_than=st.st_mtime;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
mode_t MirrorJob::get_mode_mask()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
mode_t mode_mask=0;
|
|
Packit |
8f70b4 |
if(!FlagSet(ALLOW_SUID))
|
|
Packit |
8f70b4 |
mode_mask|=S_ISUID|S_ISGID;
|
|
Packit |
8f70b4 |
if(!FlagSet(NO_UMASK))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(target_is_local)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
mode_t u=umask(022); // get+set
|
|
Packit |
8f70b4 |
umask(u); // retore
|
|
Packit |
8f70b4 |
mode_mask|=u;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
mode_mask|=022; // sane default.
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return mode_mask;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void MirrorJob::Fg()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Job::Fg();
|
|
Packit |
8f70b4 |
source_session->SetPriority(1);
|
|
Packit |
8f70b4 |
target_session->SetPriority(1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void MirrorJob::Bg()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
source_session->SetPriority(0);
|
|
Packit |
8f70b4 |
target_session->SetPriority(0);
|
|
Packit |
8f70b4 |
Job::Bg();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
MirrorJob::Statistics::Statistics()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Reset();
|
|
Packit |
8f70b4 |
error_count=0;
|
|
Packit |
8f70b4 |
bytes=0;
|
|
Packit |
8f70b4 |
time=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void MirrorJob::Statistics::Reset()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
tot_files=new_files=mod_files=del_files=
|
|
Packit |
8f70b4 |
tot_symlinks=new_symlinks=mod_symlinks=del_symlinks=
|
|
Packit |
8f70b4 |
dirs=del_dirs=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void MirrorJob::Statistics::Add(const Statistics &s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
tot_files +=s.tot_files;
|
|
Packit |
8f70b4 |
new_files +=s.new_files;
|
|
Packit |
8f70b4 |
mod_files +=s.mod_files;
|
|
Packit |
8f70b4 |
del_files +=s.del_files;
|
|
Packit |
8f70b4 |
tot_symlinks+=s.tot_symlinks;
|
|
Packit |
8f70b4 |
new_symlinks+=s.new_symlinks;
|
|
Packit |
8f70b4 |
mod_symlinks+=s.mod_symlinks;
|
|
Packit |
8f70b4 |
del_symlinks+=s.del_symlinks;
|
|
Packit |
8f70b4 |
dirs +=s.dirs;
|
|
Packit |
8f70b4 |
del_dirs +=s.del_dirs;
|
|
Packit |
8f70b4 |
error_count +=s.error_count;
|
|
Packit |
8f70b4 |
bytes +=s.bytes;
|
|
Packit |
8f70b4 |
time +=s.time;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool MirrorJob::Statistics::HaveSomethingDone(unsigned flags)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
bool del=(flags&MirrorJob::DELETE);
|
|
Packit |
8f70b4 |
return new_files|mod_files|(del_files*del)|new_symlinks|mod_symlinks|(del_symlinks*del)|(del_dirs*del);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *MirrorJob::SetScriptFile(const char *n)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
script_name.set(n);
|
|
Packit |
8f70b4 |
if(strcmp(n,"-"))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
script=fopen(n,"w");
|
|
Packit |
8f70b4 |
if(!script)
|
|
Packit |
8f70b4 |
return xstring::format("%s: %s",n,strerror(errno));
|
|
Packit |
8f70b4 |
setvbuf(script,NULL,_IOLBF,0);
|
|
Packit |
8f70b4 |
script_needs_closing=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
script=stdout;
|
|
Packit |
8f70b4 |
script_needs_closing=false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void MirrorJob::SetOnChange(const char *oc)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
on_change.set(oc);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *MirrorJob::AddPattern(Ref<PatternSet>& exclude,char opt,const char *optarg)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
PatternSet::Type type=
|
|
Packit |
8f70b4 |
(opt=='x'||opt=='X'||opt=='\0'?PatternSet::EXCLUDE:PatternSet::INCLUDE);
|
|
Packit |
8f70b4 |
PatternSet::Pattern *pattern=0;
|
|
Packit |
8f70b4 |
if(opt=='x' || opt=='i')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Ref<PatternSet::Regex> rx(new PatternSet::Regex(optarg));
|
|
Packit |
8f70b4 |
if(rx->Error())
|
|
Packit |
8f70b4 |
return xstring::get_tmp(rx->ErrorText());
|
|
Packit |
8f70b4 |
pattern=rx.borrow();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(opt=='X' || opt=='I')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
pattern=new PatternSet::Glob(optarg);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!exclude)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *default_exclude=ResMgr::Query("mirror:exclude-regex",0);
|
|
Packit |
8f70b4 |
const char *default_include=ResMgr::Query("mirror:include-regex",0);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// don't create default pattern set if not needed
|
|
Packit |
8f70b4 |
if(!pattern && !(default_exclude && *default_exclude))
|
|
Packit |
8f70b4 |
return NULL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
exclude=new PatternSet;
|
|
Packit |
8f70b4 |
/* Make default_exclude the first pattern so that it can be
|
|
Packit |
8f70b4 |
* overridden by --include later, and do that only when first
|
|
Packit |
8f70b4 |
* explicit pattern is for exclusion - otherwise all files are
|
|
Packit |
8f70b4 |
* excluded by default and no default exclusion is needed. */
|
|
Packit |
8f70b4 |
if(type==PatternSet::EXCLUDE && default_exclude && *default_exclude)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
exclude->Add(type,new PatternSet::Regex(default_exclude));
|
|
Packit |
8f70b4 |
if(default_include && *default_include)
|
|
Packit |
8f70b4 |
exclude->Add(PatternSet::INCLUDE,new PatternSet::Regex(default_include));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(pattern)
|
|
Packit |
8f70b4 |
exclude->Add(type,pattern);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return NULL; // no error
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *MirrorJob::AddPatternsFrom(Ref<PatternSet>& exclude,char opt,const char *file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
FILE *f=fopen(file,"r");
|
|
Packit |
8f70b4 |
if(!f)
|
|
Packit |
8f70b4 |
return xstring::format("%s: %s",file,strerror(errno));
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring line;
|
|
Packit |
8f70b4 |
const char *err=0;
|
|
Packit |
8f70b4 |
int c;
|
|
Packit |
8f70b4 |
while(!feof(f)) {
|
|
Packit |
8f70b4 |
line.truncate();
|
|
Packit |
8f70b4 |
while((c=getc(f))!=EOF && c!='\n')
|
|
Packit |
8f70b4 |
line.append(c);
|
|
Packit |
8f70b4 |
if(line.length()>0) {
|
|
Packit |
8f70b4 |
err=AddPattern(exclude,opt,line);
|
|
Packit |
8f70b4 |
if(err)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
fclose(f);
|
|
Packit |
8f70b4 |
return err;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *MirrorJob::SetRecursionMode(const char *m)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct { const char name[8]; recursion_mode_t mode; } map[]={
|
|
Packit |
8f70b4 |
{"always", RECURSION_ALWAYS},
|
|
Packit |
8f70b4 |
{"never", RECURSION_NEVER},
|
|
Packit |
8f70b4 |
{"missing",RECURSION_MISSING},
|
|
Packit |
8f70b4 |
{"newer", RECURSION_NEWER},
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
unsigned i;
|
|
Packit |
8f70b4 |
for(i=0; i
|
|
Packit |
8f70b4 |
if(!strcasecmp(m,map[i].name)) {
|
|
Packit |
8f70b4 |
recursion_mode=map[i].mode;
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring list(map[0].name);
|
|
Packit |
8f70b4 |
for(i=1; i
|
|
Packit |
8f70b4 |
list.append(", ").append(map[i].name);
|
|
Packit |
8f70b4 |
return xstring::format(_("%s must be one of: %s"),"--recursion",list.get());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
CMD(mirror)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#define args (parent->args)
|
|
Packit |
8f70b4 |
#define eprintf parent->eprintf
|
|
Packit |
8f70b4 |
enum {
|
|
Packit |
8f70b4 |
OPT_ALLOW_CHOWN,
|
|
Packit |
8f70b4 |
OPT_DELETE_FIRST,
|
|
Packit |
8f70b4 |
OPT_IGNORE_SIZE,
|
|
Packit |
8f70b4 |
OPT_IGNORE_TIME,
|
|
Packit |
8f70b4 |
OPT_LOOP,
|
|
Packit |
8f70b4 |
OPT_MAX_ERRORS,
|
|
Packit |
8f70b4 |
OPT_NO_DEREFERENCE,
|
|
Packit |
8f70b4 |
OPT_NO_SYMLINKS,
|
|
Packit |
8f70b4 |
OPT_NO_UMASK,
|
|
Packit |
8f70b4 |
OPT_OLDER_THAN,
|
|
Packit |
8f70b4 |
OPT_ONLY_MISSING,
|
|
Packit |
8f70b4 |
OPT_ONLY_EXISTING,
|
|
Packit |
8f70b4 |
OPT_PERMS,
|
|
Packit |
8f70b4 |
OPT_REMOVE_SOURCE_FILES,
|
|
Packit |
8f70b4 |
OPT_REMOVE_SOURCE_DIRS,
|
|
Packit |
8f70b4 |
OPT_SCRIPT,
|
|
Packit |
8f70b4 |
OPT_SCRIPT_ONLY,
|
|
Packit |
8f70b4 |
OPT_SIZE_RANGE,
|
|
Packit |
8f70b4 |
OPT_USE_CACHE,
|
|
Packit |
8f70b4 |
OPT_USE_PGET_N,
|
|
Packit |
8f70b4 |
OPT_SKIP_NOACCESS,
|
|
Packit |
8f70b4 |
OPT_ON_CHANGE,
|
|
Packit |
8f70b4 |
OPT_NO_EMPTY_DIRS,
|
|
Packit |
8f70b4 |
OPT_DEPTH_FIRST,
|
|
Packit |
8f70b4 |
OPT_ASCII,
|
|
Packit |
8f70b4 |
OPT_SCAN_ALL_FIRST,
|
|
Packit |
8f70b4 |
OPT_OVERWRITE,
|
|
Packit |
8f70b4 |
OPT_NO_OVERWRITE,
|
|
Packit |
8f70b4 |
OPT_RECURSION,
|
|
Packit |
8f70b4 |
OPT_UPLOAD_OLDER,
|
|
Packit |
8f70b4 |
OPT_TRANSFER_ALL,
|
|
Packit |
8f70b4 |
OPT_TARGET_FLAT,
|
|
Packit |
8f70b4 |
OPT_DELETE_EXCLUDED,
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
static const struct option mirror_opts[]=
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
{"delete",no_argument,0,'e'},
|
|
Packit |
8f70b4 |
{"allow-suid",no_argument,0,'s'},
|
|
Packit |
8f70b4 |
{"allow-chown",no_argument,0,OPT_ALLOW_CHOWN},
|
|
Packit |
8f70b4 |
{"include",required_argument,0,'i'},
|
|
Packit |
8f70b4 |
{"exclude",required_argument,0,'x'},
|
|
Packit |
8f70b4 |
{"include-glob",required_argument,0,'I'},
|
|
Packit |
8f70b4 |
{"exclude-glob",required_argument,0,'X'},
|
|
Packit |
8f70b4 |
{"include-rx-from",required_argument,0,'i'+'f'},
|
|
Packit |
8f70b4 |
{"exclude-rx-from",required_argument,0,'x'+'f'},
|
|
Packit |
8f70b4 |
{"include-glob-from",required_argument,0,'I'+'f'},
|
|
Packit |
8f70b4 |
{"exclude-glob-from",required_argument,0,'X'+'f'},
|
|
Packit |
8f70b4 |
{"only-newer",no_argument,0,'n'},
|
|
Packit |
8f70b4 |
{"no-recursion",no_argument,0,'r'},
|
|
Packit |
8f70b4 |
{"no-perms",no_argument,0,'p'},
|
|
Packit |
8f70b4 |
{"perms",no_argument,0,OPT_PERMS},
|
|
Packit |
8f70b4 |
{"no-umask",no_argument,0,OPT_NO_UMASK},
|
|
Packit |
8f70b4 |
{"continue",no_argument,0,'c'},
|
|
Packit |
8f70b4 |
{"reverse",no_argument,0,'R'},
|
|
Packit |
8f70b4 |
{"verbose",optional_argument,0,'v'},
|
|
Packit |
8f70b4 |
{"newer-than",required_argument,0,'N'},
|
|
Packit |
8f70b4 |
{"file",required_argument,0,'f'},
|
|
Packit |
8f70b4 |
{"directory",required_argument,0,'F'},
|
|
Packit |
8f70b4 |
{"older-than",required_argument,0,OPT_OLDER_THAN},
|
|
Packit |
8f70b4 |
{"size-range",required_argument,0,OPT_SIZE_RANGE},
|
|
Packit |
8f70b4 |
{"dereference",no_argument,0,'L'},
|
|
Packit |
8f70b4 |
{"no-dereference",no_argument,0,OPT_NO_DEREFERENCE},
|
|
Packit |
8f70b4 |
{"use-cache",no_argument,0,OPT_USE_CACHE},
|
|
Packit |
8f70b4 |
{"Remove-source-files",no_argument,0,OPT_REMOVE_SOURCE_FILES},
|
|
Packit |
8f70b4 |
{"Remove-source-dirs",no_argument,0,OPT_REMOVE_SOURCE_DIRS},
|
|
Packit |
8f70b4 |
{"Move",no_argument,0,OPT_REMOVE_SOURCE_DIRS},
|
|
Packit |
8f70b4 |
{"parallel",optional_argument,0,'P'},
|
|
Packit |
8f70b4 |
{"ignore-time",no_argument,0,OPT_IGNORE_TIME},
|
|
Packit |
8f70b4 |
{"ignore-size",no_argument,0,OPT_IGNORE_SIZE},
|
|
Packit |
8f70b4 |
{"only-missing",no_argument,0,OPT_ONLY_MISSING},
|
|
Packit |
8f70b4 |
{"only-existing",no_argument,0,OPT_ONLY_EXISTING},
|
|
Packit |
8f70b4 |
{"log",required_argument,0,OPT_SCRIPT},
|
|
Packit |
8f70b4 |
{"script", required_argument,0,OPT_SCRIPT_ONLY},
|
|
Packit |
8f70b4 |
{"just-print",optional_argument,0,OPT_SCRIPT_ONLY},
|
|
Packit |
8f70b4 |
{"dry-run", optional_argument,0,OPT_SCRIPT_ONLY},
|
|
Packit |
8f70b4 |
{"delete-first",no_argument,0,OPT_DELETE_FIRST},
|
|
Packit |
8f70b4 |
{"use-pget-n",optional_argument,0,OPT_USE_PGET_N},
|
|
Packit |
8f70b4 |
{"no-symlinks",no_argument,0,OPT_NO_SYMLINKS},
|
|
Packit |
8f70b4 |
{"loop",no_argument,0,OPT_LOOP},
|
|
Packit |
8f70b4 |
{"max-errors",required_argument,0,OPT_MAX_ERRORS},
|
|
Packit |
8f70b4 |
{"skip-noaccess",no_argument,0,OPT_SKIP_NOACCESS},
|
|
Packit |
8f70b4 |
{"on-change",required_argument,0,OPT_ON_CHANGE},
|
|
Packit |
8f70b4 |
{"no-empty-dirs",no_argument,0,OPT_NO_EMPTY_DIRS},
|
|
Packit |
8f70b4 |
{"depth-first",no_argument,0,OPT_DEPTH_FIRST},
|
|
Packit |
8f70b4 |
{"ascii",no_argument,0,OPT_ASCII},
|
|
Packit |
8f70b4 |
{"target-directory",required_argument,0,'O'},
|
|
Packit |
8f70b4 |
{"destination-directory",required_argument,0,'O'},
|
|
Packit |
8f70b4 |
{"scan-all-first",no_argument,0,OPT_SCAN_ALL_FIRST},
|
|
Packit |
8f70b4 |
{"overwrite",no_argument,0,OPT_OVERWRITE},
|
|
Packit |
8f70b4 |
{"no-overwrite",no_argument,0,OPT_NO_OVERWRITE},
|
|
Packit |
8f70b4 |
{"recursion",required_argument,0,OPT_RECURSION},
|
|
Packit |
8f70b4 |
{"upload-older",no_argument,0,OPT_UPLOAD_OLDER},
|
|
Packit |
8f70b4 |
{"transfer-all",no_argument,0,OPT_TRANSFER_ALL},
|
|
Packit |
8f70b4 |
{"flat",no_argument,0,OPT_TARGET_FLAT},
|
|
Packit |
8f70b4 |
{"delete-excluded",no_argument,0,OPT_DELETE_EXCLUDED},
|
|
Packit |
8f70b4 |
{0}
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int opt;
|
|
Packit |
8f70b4 |
unsigned flags=0;
|
|
Packit |
8f70b4 |
int max_error_count=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool use_cache=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FileAccessRef source_session;
|
|
Packit |
8f70b4 |
FileAccessRef target_session;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int verbose=0;
|
|
Packit |
8f70b4 |
const char *newer_than=0;
|
|
Packit |
8f70b4 |
const char *older_than=0;
|
|
Packit |
8f70b4 |
Ref<Range> size_range;
|
|
Packit |
8f70b4 |
bool remove_source_files=false;
|
|
Packit |
8f70b4 |
bool remove_source_dirs=false;
|
|
Packit |
8f70b4 |
bool skip_noaccess=ResMgr::QueryBool("mirror:skip-noaccess",0);
|
|
Packit |
8f70b4 |
int parallel=-1;
|
|
Packit |
8f70b4 |
int use_pget=-1;
|
|
Packit |
8f70b4 |
bool reverse=false;
|
|
Packit |
8f70b4 |
bool script_only=false;
|
|
Packit |
8f70b4 |
bool no_empty_dirs=ResMgr::QueryBool("mirror:no-empty-dirs",0);
|
|
Packit |
8f70b4 |
const char *script_file=0;
|
|
Packit |
8f70b4 |
const char *on_change=0;
|
|
Packit |
8f70b4 |
const char *recursion_mode=0;
|
|
Packit |
8f70b4 |
bool single_file=false;
|
|
Packit |
8f70b4 |
bool single_dir=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Ref<PatternSet> exclude;
|
|
Packit |
8f70b4 |
Ref<PatternSet> top_exclude;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!ResMgr::QueryBool("mirror:set-permissions",0))
|
|
Packit |
8f70b4 |
flags|=MirrorJob::NO_PERMS;
|
|
Packit |
8f70b4 |
if(ResMgr::QueryBool("mirror:dereference",0))
|
|
Packit |
8f70b4 |
flags|=MirrorJob::RETR_SYMLINKS;
|
|
Packit |
8f70b4 |
if(ResMgr::QueryBool("mirror:overwrite",0))
|
|
Packit |
8f70b4 |
flags|=MirrorJob::OVERWRITE;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *source_dir=NULL;
|
|
Packit |
8f70b4 |
const char *target_dir=NULL;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
args->rewind();
|
|
Packit |
8f70b4 |
while((opt=args->getopt_long("esi:x:I:X:nrpcRvN:LP:af:F:O:",mirror_opts,0))!=EOF)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
switch(opt)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case('e'):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::DELETE;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('s'):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::ALLOW_SUID;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_ALLOW_CHOWN):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::ALLOW_CHOWN;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('a'):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::ALLOW_SUID|MirrorJob::ALLOW_CHOWN|MirrorJob::NO_UMASK;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('r'):
|
|
Packit |
8f70b4 |
recursion_mode="never";
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('n'):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::ONLY_NEWER;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('p'):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::NO_PERMS;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_PERMS):
|
|
Packit |
8f70b4 |
flags&=~MirrorJob::NO_PERMS;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('c'):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::CONTINUE;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('x'):
|
|
Packit |
8f70b4 |
case('i'):
|
|
Packit |
8f70b4 |
case('X'):
|
|
Packit |
8f70b4 |
case('I'):
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *err=MirrorJob::AddPattern(exclude,opt,optarg);
|
|
Packit |
8f70b4 |
if(err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
eprintf("%s: %s\n",args->a0(),err);
|
|
Packit |
8f70b4 |
goto no_job;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
case('x'+'f'):
|
|
Packit |
8f70b4 |
case('i'+'f'):
|
|
Packit |
8f70b4 |
case('X'+'f'):
|
|
Packit |
8f70b4 |
case('I'+'f'):
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *err=MirrorJob::AddPatternsFrom(exclude,opt-'f',optarg);
|
|
Packit |
8f70b4 |
if(err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
eprintf("%s: %s\n",args->a0(),err);
|
|
Packit |
8f70b4 |
goto no_job;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
case('R'):
|
|
Packit |
8f70b4 |
reverse=true;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('L'):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::RETR_SYMLINKS;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_NO_DEREFERENCE):
|
|
Packit |
8f70b4 |
flags&=~MirrorJob::RETR_SYMLINKS;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('v'):
|
|
Packit |
8f70b4 |
if(optarg)
|
|
Packit |
8f70b4 |
verbose=atoi(optarg);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
verbose++;
|
|
Packit |
8f70b4 |
if(verbose>1)
|
|
Packit |
8f70b4 |
flags|=MirrorJob::REPORT_NOT_DELETED;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('N'):
|
|
Packit |
8f70b4 |
newer_than=optarg;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('f'): // mirror for a single file (or glob pattern).
|
|
Packit |
8f70b4 |
single_file=true;
|
|
Packit |
8f70b4 |
/*fallthrough*/
|
|
Packit |
8f70b4 |
case('F'): // mirror for a single directory (or glob pattern).
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xstring pattern(basename_ptr(optarg));
|
|
Packit |
8f70b4 |
if(opt=='F') {
|
|
Packit |
8f70b4 |
single_dir=true;
|
|
Packit |
8f70b4 |
if(pattern.last_char()!='/')
|
|
Packit |
8f70b4 |
pattern.append('/');
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!top_exclude)
|
|
Packit |
8f70b4 |
top_exclude=new PatternSet();
|
|
Packit |
8f70b4 |
top_exclude->Add(PatternSet::INCLUDE,new PatternSet::Glob(pattern));
|
|
Packit |
8f70b4 |
const char *dir=dirname(optarg);
|
|
Packit |
8f70b4 |
if(source_dir && strcmp(source_dir,dir)) {
|
|
Packit |
8f70b4 |
eprintf(_("%s: multiple --file or --directory options must have the same base directory\n"),args->a0());
|
|
Packit |
8f70b4 |
goto no_job;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!source_dir)
|
|
Packit |
8f70b4 |
source_dir=alloca_strdup(dir); // save the temp string
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
case('O'):
|
|
Packit |
8f70b4 |
target_dir=optarg;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_OLDER_THAN):
|
|
Packit |
8f70b4 |
older_than=optarg;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_SIZE_RANGE):
|
|
Packit |
8f70b4 |
size_range=new Range(optarg);
|
|
Packit |
8f70b4 |
if(size_range->Error())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
eprintf("%s: --size-range \"%s\": %s\n",
|
|
Packit |
8f70b4 |
args->a0(),optarg,size_range->ErrorText());
|
|
Packit |
8f70b4 |
goto no_job;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_NO_UMASK):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::NO_UMASK;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_USE_CACHE):
|
|
Packit |
8f70b4 |
use_cache=true;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_REMOVE_SOURCE_FILES):
|
|
Packit |
8f70b4 |
remove_source_files=true;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_REMOVE_SOURCE_DIRS):
|
|
Packit |
8f70b4 |
remove_source_dirs=true;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_IGNORE_TIME):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::IGNORE_TIME;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_IGNORE_SIZE):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::IGNORE_SIZE;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_ONLY_MISSING):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::IGNORE_TIME|MirrorJob::IGNORE_SIZE;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('P'):
|
|
Packit |
8f70b4 |
if(optarg)
|
|
Packit |
8f70b4 |
parallel=atoi(optarg);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
parallel=3;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_USE_PGET_N):
|
|
Packit |
8f70b4 |
if(optarg)
|
|
Packit |
8f70b4 |
use_pget=atoi(optarg);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
use_pget=3;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_SCRIPT_ONLY):
|
|
Packit |
8f70b4 |
script_only=true;
|
|
Packit |
8f70b4 |
case(OPT_SCRIPT):
|
|
Packit |
8f70b4 |
script_file=optarg;
|
|
Packit |
8f70b4 |
if(script_file==0)
|
|
Packit |
8f70b4 |
script_file="-";
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_DELETE_FIRST):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::REMOVE_FIRST|MirrorJob::DELETE;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_NO_SYMLINKS):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::NO_SYMLINKS;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_LOOP):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::LOOP;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_MAX_ERRORS):
|
|
Packit |
8f70b4 |
max_error_count=atoi(optarg);
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_SKIP_NOACCESS):
|
|
Packit |
8f70b4 |
skip_noaccess=true;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_ON_CHANGE):
|
|
Packit |
8f70b4 |
on_change=optarg;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_ONLY_EXISTING):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::ONLY_EXISTING;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_NO_EMPTY_DIRS):
|
|
Packit |
8f70b4 |
no_empty_dirs=true;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_DEPTH_FIRST):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::DEPTH_FIRST;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_SCAN_ALL_FIRST):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::SCAN_ALL_FIRST|MirrorJob::DEPTH_FIRST;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_ASCII):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::ASCII|MirrorJob::IGNORE_SIZE;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_OVERWRITE):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::OVERWRITE;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_NO_OVERWRITE):
|
|
Packit |
8f70b4 |
flags&=~MirrorJob::OVERWRITE;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_RECURSION):
|
|
Packit |
8f70b4 |
recursion_mode=optarg;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_UPLOAD_OLDER):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::UPLOAD_OLDER;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_TRANSFER_ALL):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::TRANSFER_ALL;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_TARGET_FLAT):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::TARGET_FLAT|MirrorJob::SCAN_ALL_FIRST|MirrorJob::DEPTH_FIRST;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case(OPT_DELETE_EXCLUDED):
|
|
Packit |
8f70b4 |
flags|=MirrorJob::DELETE_EXCLUDED;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case('?'):
|
|
Packit |
8f70b4 |
eprintf(_("Try `help %s' for more information.\n"),args->a0());
|
|
Packit |
8f70b4 |
no_job:
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(exclude && xstrcasecmp(recursion_mode,"never"))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
/* Users usually don't want to exclude all directories when recursing */
|
|
Packit |
8f70b4 |
if(exclude->GetFirstType()==PatternSet::INCLUDE)
|
|
Packit |
8f70b4 |
exclude->AddFirst(PatternSet::INCLUDE,new PatternSet::Regex("/$"));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* add default exclusion if no explicit patterns were specified */
|
|
Packit |
8f70b4 |
if(!exclude)
|
|
Packit |
8f70b4 |
MirrorJob::AddPattern(exclude,'\0',0);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
args->back();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *arg=args->getnext();
|
|
Packit |
8f70b4 |
if(arg)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(source_dir)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
eprintf(_("%s: ambiguous source directory (`%s' or `%s'?)\n"),args->a0(),
|
|
Packit |
8f70b4 |
source_dir,arg);
|
|
Packit |
8f70b4 |
goto no_job;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
source_dir=arg;
|
|
Packit |
8f70b4 |
ParsedURL source_url(source_dir);
|
|
Packit |
8f70b4 |
if(source_url.proto && source_url.path)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
source_session=FileAccess::New(&source_url);
|
|
Packit |
8f70b4 |
if(!source_session)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
eprintf("%s: %s%s\n",args->a0(),source_url.proto.get(),
|
|
Packit |
8f70b4 |
_(" - not supported protocol"));
|
|
Packit |
8f70b4 |
goto no_job;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
source_dir=alloca_strdup(source_url.path);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
arg=args->getnext();
|
|
Packit |
8f70b4 |
if(arg)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(target_dir)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
eprintf(_("%s: ambiguous target directory (`%s' or `%s'?)\n"),args->a0(),
|
|
Packit |
8f70b4 |
target_dir,arg);
|
|
Packit |
8f70b4 |
goto no_job;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
target_dir=arg;
|
|
Packit |
8f70b4 |
ParsedURL target_url(target_dir);
|
|
Packit |
8f70b4 |
if(target_url.proto && target_url.path)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
target_session=FileAccess::New(&target_url);
|
|
Packit |
8f70b4 |
if(!target_session)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
eprintf("%s: %s%s\n",args->a0(),target_url.proto.get(),
|
|
Packit |
8f70b4 |
_(" - not supported protocol"));
|
|
Packit |
8f70b4 |
goto no_job;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
target_dir=alloca_strdup(target_url.path);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(last_char(arg)=='/' && basename_ptr(arg)[0]!='/' && last_char(source_dir)!='/')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// user wants source dir name appended.
|
|
Packit |
8f70b4 |
const char *base=basename_ptr(source_dir);
|
|
Packit |
8f70b4 |
if(base[0]!='/' && strcmp(base,basename_ptr(arg))) {
|
|
Packit |
8f70b4 |
target_dir=xstring::cat(target_dir,base,NULL);
|
|
Packit |
8f70b4 |
target_dir=alloca_strdup(target_dir); // save the buffer
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
target_dir=basename_ptr(source_dir);
|
|
Packit |
8f70b4 |
if(target_dir[0]=='/')
|
|
Packit |
8f70b4 |
target_dir=".";
|
|
Packit |
8f70b4 |
else if(target_dir[0]=='~') {
|
|
Packit |
8f70b4 |
target_dir=dir_file(".",target_dir);
|
|
Packit |
8f70b4 |
target_dir=alloca_strdup(target_dir); // save the buffer
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!source_dir) {
|
|
Packit |
8f70b4 |
if(ResMgr::QueryBool("mirror:require-source",0)) {
|
|
Packit |
8f70b4 |
eprintf(_("%s: source directory is required (mirror:require-source is set)\n"),args->a0());
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
source_dir=".";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!target_dir)
|
|
Packit |
8f70b4 |
target_dir=".";
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!reverse)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!source_session)
|
|
Packit |
8f70b4 |
source_session=parent->session->Clone();
|
|
Packit |
8f70b4 |
if(!target_session)
|
|
Packit |
8f70b4 |
target_session=FileAccess::New("file");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else //reverse
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!source_session)
|
|
Packit |
8f70b4 |
source_session=FileAccess::New("file");
|
|
Packit |
8f70b4 |
if(!target_session)
|
|
Packit |
8f70b4 |
target_session=parent->session->Clone();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(no_empty_dirs)
|
|
Packit |
8f70b4 |
flags|=MirrorJob::NO_EMPTY_DIRS|MirrorJob::DEPTH_FIRST;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(recursion_mode && strcasecmp(recursion_mode,"always")
|
|
Packit |
8f70b4 |
&& (flags&MirrorJob::DEPTH_FIRST)) {
|
|
Packit |
8f70b4 |
eprintf("%s: --recursion-mode=%s conflicts with other specified options\n",
|
|
Packit |
8f70b4 |
args->a0(),recursion_mode);
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(parallel<0) {
|
|
Packit |
8f70b4 |
int parallel1=ResMgr::Query("mirror:parallel-transfer-count",source_session->GetHostName());
|
|
Packit |
8f70b4 |
int parallel2=ResMgr::Query("mirror:parallel-transfer-count",target_session->GetHostName());
|
|
Packit |
8f70b4 |
if(parallel1>0)
|
|
Packit |
8f70b4 |
parallel=parallel1;
|
|
Packit |
8f70b4 |
if(parallel2>0 && (parallel<0 || parallel>parallel2))
|
|
Packit |
8f70b4 |
parallel=parallel2;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(use_pget<0) {
|
|
Packit |
8f70b4 |
int use_pget1=ResMgr::Query("mirror:use-pget-n",source_session->GetHostName());
|
|
Packit |
8f70b4 |
int use_pget2=ResMgr::Query("mirror:use-pget-n",target_session->GetHostName());
|
|
Packit |
8f70b4 |
if(use_pget1>0)
|
|
Packit |
8f70b4 |
use_pget=use_pget1;
|
|
Packit |
8f70b4 |
if(use_pget2>0 && (use_pget<0 || use_pget>use_pget2))
|
|
Packit |
8f70b4 |
use_pget=use_pget2;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
JobRef<MirrorJob> j(new MirrorJob(0,source_session.borrow(),target_session.borrow(),source_dir,target_dir));
|
|
Packit |
8f70b4 |
j->SetFlags(flags,1);
|
|
Packit |
8f70b4 |
j->SetVerbose(verbose);
|
|
Packit |
8f70b4 |
j->SetExclude(exclude.borrow());
|
|
Packit |
8f70b4 |
j->SetTopExclude(top_exclude.borrow());
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(newer_than)
|
|
Packit |
8f70b4 |
j->SetNewerThan(newer_than);
|
|
Packit |
8f70b4 |
if(older_than)
|
|
Packit |
8f70b4 |
j->SetOlderThan(older_than);
|
|
Packit |
8f70b4 |
if(size_range)
|
|
Packit |
8f70b4 |
j->SetSizeRange(size_range.borrow());
|
|
Packit |
8f70b4 |
j->UseCache(use_cache);
|
|
Packit |
8f70b4 |
if(remove_source_files)
|
|
Packit |
8f70b4 |
j->RemoveSourceFiles();
|
|
Packit |
8f70b4 |
if(remove_source_dirs)
|
|
Packit |
8f70b4 |
j->RemoveSourceDirs();
|
|
Packit |
8f70b4 |
if(skip_noaccess)
|
|
Packit |
8f70b4 |
j->SkipNoAccess();
|
|
Packit |
8f70b4 |
if(parallel<0)
|
|
Packit |
8f70b4 |
parallel=0;
|
|
Packit |
8f70b4 |
if(parallel>64)
|
|
Packit |
8f70b4 |
parallel=64; // a (in)sane limit.
|
|
Packit |
8f70b4 |
if(parallel)
|
|
Packit |
8f70b4 |
j->SetParallel(parallel);
|
|
Packit |
8f70b4 |
if(use_pget>1 && !(flags&MirrorJob::ASCII))
|
|
Packit |
8f70b4 |
j->SetPGet(use_pget);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!recursion_mode && single_file && !single_dir)
|
|
Packit |
8f70b4 |
recursion_mode="never";
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(recursion_mode) {
|
|
Packit |
8f70b4 |
const char *err=j->SetRecursionMode(recursion_mode);
|
|
Packit |
8f70b4 |
if(err) {
|
|
Packit |
8f70b4 |
eprintf("%s: %s\n",args->a0(),err);
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(script_file)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *err=j->SetScriptFile(script_file);
|
|
Packit |
8f70b4 |
if(err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
eprintf("%s: %s\n",args->a0(),err);
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(script_only)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
j->ScriptOnly();
|
|
Packit |
8f70b4 |
if(!script_file)
|
|
Packit |
8f70b4 |
j->SetScriptFile("-");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
j->SetMaxErrorCount(max_error_count);
|
|
Packit |
8f70b4 |
if(on_change)
|
|
Packit |
8f70b4 |
j->SetOnChange(on_change);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return j.borrow();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#undef args
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "modconfig.h"
|
|
Packit |
8f70b4 |
#ifndef MODULE_CMD_MIRROR
|
|
Packit |
8f70b4 |
# define module_init cmd_mirror_module_init
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
CDECL void module_init()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
CmdExec::RegisterCommand("mirror",cmd_mirror,0,
|
|
Packit |
8f70b4 |
N_("\n"
|
|
Packit |
8f70b4 |
"Mirror specified remote directory to local directory\n"
|
|
Packit |
8f70b4 |
"\n"
|
|
Packit |
8f70b4 |
" -R, --reverse reverse mirror (put files)\n"
|
|
Packit |
8f70b4 |
"Lots of other options are documented in the man page lftp(1).\n"
|
|
Packit |
8f70b4 |
"\n"
|
|
Packit |
8f70b4 |
"When using -R, the first directory is local and the second is remote.\n"
|
|
Packit |
8f70b4 |
"If the second directory is omitted, basename of the first directory is used.\n"
|
|
Packit |
8f70b4 |
"If both directories are omitted, current local and remote directories are used.\n"
|
|
Packit |
8f70b4 |
"\n"
|
|
Packit |
8f70b4 |
"See the man page lftp(1) for a complete documentation.\n"
|
|
Packit |
8f70b4 |
)
|
|
Packit |
8f70b4 |
);
|
|
Packit |
8f70b4 |
}
|