Multiple virtual clients per real client

This commit is contained in:
Martin 2015-12-09 22:53:57 +01:00
parent 6447563c2e
commit e90cb501ae
53 changed files with 2062 additions and 1664 deletions

3
.gitignore vendored
View File

@ -231,3 +231,6 @@ urbackup/server_ident_ecdsa409k1.priv
urbackup/server_ident_ecdsa409k1.pub
clientctl/Debug/*
urbackup/new_version_deb/*
urbackupserver/www/js/templates.js.new
urbackupserver/www/templates.js.new

View File

@ -48,6 +48,8 @@ AESGCMEncryption::AESGCMEncryption( const std::string& key, bool hash_password)
encryption.SetKeyWithIV(m_sbbKey.BytePtr(), m_sbbKey.size(),
m_IV.BytePtr(), m_IV.size());
m_orig_IV = m_IV;
iv_done=false;
assert(encryption.CanUseStructuredIVs());
@ -64,9 +66,9 @@ void AESGCMEncryption::put( const char *data, size_t data_size )
void AESGCMEncryption::flush()
{
encryption_filter.MessageEnd();
end_markers.push_back(encryption_filter.MaxRetrievable());
CryptoPP::IncrementCounterByOne(m_IV.BytePtr(), static_cast<unsigned int>(m_IV.size()));
encryption.Resynchronize(m_IV.BytePtr(), static_cast<int>(m_IV.size()));
end_markers.push_back(encryption_filter.MaxRetrievable());
overhead_size+=16; //tag size
}
@ -94,9 +96,9 @@ std::string AESGCMEncryption::get()
if(!iv_done)
{
memcpy(&ret[0], m_IV.BytePtr(), m_IV.size());
memcpy(&ret[0], m_orig_IV.BytePtr(), m_orig_IV.size());
iv_done=true;
overhead_size+=m_IV.size();
overhead_size+=m_orig_IV.size();
}
if(max_retrievable>0)

View File

@ -25,6 +25,7 @@ private:
bool iv_done;
CryptoPP::SecByteBlock m_sbbKey;
CryptoPP::SecByteBlock m_IV;
CryptoPP::SecByteBlock m_orig_IV;
CryptoPP::GCM<CryptoPP::AES >::Encryption encryption;
CryptoPP::AuthenticatedEncryptionFilter encryption_filter;

View File

@ -399,7 +399,7 @@ bool FileMetadataPipe::transmitCurrMetadata( char* buf, size_t buf_avail, size_t
_u32 data_size = little_endian(static_cast<_u32>(data.getDataSize()));
memcpy(metadata_buffer.data(), &data_size, sizeof(data_size));
memcpy(metadata_buffer.data()+sizeof(data_size), data.getDataPtr(), data.getDataSize());
metadata_buffer_size = data.getDataSize()+data_size;
metadata_buffer_size = data.getDataSize()+sizeof(data_size);
metadata_buffer_off=0;
return transmitCurrMetadata(buf, buf_avail, read_bytes);
}

View File

@ -21,6 +21,7 @@
#include "../Interface/Server.h"
#include "../stringtools.h"
#include "FileServ.h"
#include "CUDPThread.h"
int start_server_int(unsigned short tcpport, unsigned short udpport, const std::string &pSname, const bool *pDostop, bool use_fqdn);
@ -97,3 +98,8 @@ IFileServ* FileServFactory::createFileServNoBind(const std::wstring &name, bool
FileServ *fs=new FileServ(dostop, name, ILLEGAL_THREADPOOL_TICKET, use_fqdn_default);
return fs;
}
std::wstring FileServFactory::getDefaultServerName( bool use_fqdn )
{
return Server->ConvertToUnicode(getSystemServerName(use_fqdn));
}

View File

@ -13,6 +13,8 @@ public:
static IPermissionCallback* getPermissionCallback();
std::wstring getDefaultServerName(bool use_fqdn);
private:
static IPermissionCallback* permission_callback;
static bool backupground_backups_enabled;

View File

@ -16,6 +16,7 @@ public:
virtual IFileServ * createFileServNoBind(const std::wstring &name=L"", bool use_fqdn_default=false)=0;
virtual void destroyFileServ(IFileServ *filesrv)=0;
virtual void setPermissionCallback(IPermissionCallback* new_permission_callback)=0;
virtual std::wstring getDefaultServerName(bool use_fqdn)=0;
};
#endif //IFILESERVFACTORY_H

View File

@ -365,7 +365,7 @@ string ExtractFileName(string fulln, string separators)
bool separator = separators.find(fulln[i])!=string::npos;
if(separator)
{
if(i<(s32)fulln.length()-2)
if(i<(s32)fulln.length()-1)
break;
}
if(fulln[i]!=0 && !separator)
@ -386,7 +386,7 @@ wstring ExtractFileName(wstring fulln, wstring separators)
if( separator )
{
if(i<(s32)fulln.length()-2)
if(i<(s32)fulln.length()-1)
break;
}
if(fulln[i]!=0 && !separator)

View File

@ -1055,12 +1055,12 @@ namespace
}
bool ClientConnector::saveBackupDirs(str_map &args, bool server_default)
bool ClientConnector::saveBackupDirs(str_map &args, bool server_default, int group_offset)
{
IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_CLIENT);
db->BeginWriteTransaction();
db_results backupdirs=db->Prepare("SELECT name, path FROM backupdirs")->Read();
db->Prepare("DELETE FROM backupdirs WHERE symlinked=0")->Write();
db->Prepare("DELETE FROM backupdirs WHERE symlinked=0 AND tgroup BETWEEN "+nconvert(group_offset)+" AND "+nconvert(group_offset+c_group_max))->Write();
IQuery *q=db->Prepare("INSERT INTO backupdirs (name, path, server_default, optional, tgroup) VALUES (?, ? ,"+nconvert(server_default?1:0)+", ?, ?)");
/**
Use empty client settings
@ -1090,11 +1090,11 @@ bool ClientConnector::saveBackupDirs(str_map &args, bool server_default)
else
name=ExtractFileName(dir);
int group = c_group_default;
int group = group_offset + c_group_default;
str_map::iterator group_arg=args.find(L"dir_"+convert(i)+L"_group");
if(group_arg!=args.end() && !group_arg->second.empty())
group=watoi(group_arg->second);
group=group_offset + watoi(group_arg->second);
int flags = EBackupDirFlag_FollowSymlinks | EBackupDirFlag_SymlinksOptional; //default flags
size_t flags_off = name.find(L"/");
@ -1220,7 +1220,7 @@ bool ClientConnector::saveBackupDirs(str_map &args, bool server_default)
data.addChar(IndexThread::IndexThreadAction_RemoveWatchdir);
data.addVoidPtr(contractor);
data.addString(Server->ConvertToUTF8(backupdirs[i][L"path"]));
if(watoi(backupdirs[i][L"group"])==c_group_continuous)
if(watoi(backupdirs[i][L"group"])%c_group_size==c_group_continuous)
{
data.addString(Server->ConvertToUTF8(backupdirs[i][L"name"]));
}
@ -1348,9 +1348,23 @@ std::vector<std::wstring> getSettingsList(void);
void ClientConnector::updateSettings(const std::string &pData)
{
std::auto_ptr<ISettingsReader> curr_settings(Server->createFileSettingsReader("urbackup/data/settings.cfg"));
std::auto_ptr<ISettingsReader> new_settings(Server->createMemorySettingsReader(pData));
std::string settings_fn="urbackup/data/settings.cfg";
std::string settings_server_fn="urbackup/data/settings_"+server_token+".cfg";
std::string clientsubname;
std::string str_group_offset;
int group_offset=0;
if(new_settings->getValue("clientsubname", &clientsubname) && !clientsubname.empty()
&& new_settings->getValue("filebackup_group_offset", &str_group_offset))
{
settings_fn = "urbackup/data/settings_"+conv_filename(clientsubname)+".cfg";
settings_server_fn = "urbackup/data/settings_"+conv_filename(clientsubname) + "_"+server_token+".cfg";
group_offset = atoi(str_group_offset.c_str());
}
std::auto_ptr<ISettingsReader> curr_settings(Server->createFileSettingsReader(settings_fn));
std::vector<std::wstring> settings_names=getSettingsList();
settings_names.push_back(L"client_set_settings");
settings_names.push_back(L"client_set_settings_time");
@ -1455,7 +1469,8 @@ void ClientConnector::updateSettings(const std::string &pData)
}
IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_CLIENT);
IQuery *q=db->Prepare("SELECT id FROM backupdirs WHERE server_default=0", false);
IQuery *q=db->Prepare("SELECT id FROM backupdirs WHERE server_default=0 AND tgroup=?", false);
q->Bind(group_offset);
db_results res=q->Read();
db->destroyQuery(q);
if(res.empty())
@ -1474,15 +1489,20 @@ void ClientConnector::updateSettings(const std::string &pData)
std::wstring path=trim(def_dirs_toks[i]);
std::wstring name;
int group = c_group_default;
if(path.find(L"|")!=std::string::npos)
std::wstring first_path = path;
if(path.find(L"/")!=std::string::npos)
{
first_path = getuntil(L"/", path);
}
if(first_path.find(L"|")!=std::string::npos)
{
std::vector<std::wstring> toks;
Tokenize(default_dirs, toks, L"|");
Tokenize(first_path, toks, L"|");
name = toks[0];
path = toks[1];
if(toks.size()>2)
{
group = watoi(toks[2]);
group = (std::min)(c_group_max, (std::max)(0, watoi(toks[2])));
}
}
args[L"dir_"+convert(i)]=path;
@ -1492,18 +1512,18 @@ void ClientConnector::updateSettings(const std::string &pData)
args[L"dir_"+convert(i)+L"_group"]=convert(group);
}
saveBackupDirs(args, true);
saveBackupDirs(args, true, group_offset);
}
}
if(mod)
{
writestring(Server->ConvertToUTF8(new_settings_str), "urbackup/data/settings.cfg");
writestring(Server->ConvertToUTF8(new_settings_str), settings_fn);
InternetClient::updateSettings();
}
std::auto_ptr<ISettingsReader> curr_server_settings(Server->createFileSettingsReader("urbackup/data/settings_"+server_token+".cfg"));
std::auto_ptr<ISettingsReader> curr_server_settings(Server->createFileSettingsReader(settings_server_fn));
std::vector<std::wstring> global_settings = getGlobalizedSettingsList();
std::wstring new_token_settings=L"";
@ -1543,7 +1563,7 @@ void ClientConnector::updateSettings(const std::string &pData)
if(mod_server_settings)
{
writestring(Server->ConvertToUTF8(new_settings_str), "urbackup/data/settings_"+server_token+".cfg");
writestring(Server->ConvertToUTF8(new_settings_str), settings_server_fn);
}
}
@ -1560,7 +1580,14 @@ void ClientConnector::replaceSettings(const std::string &pData)
IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize());
}
ISettingsReader* old_settings=Server->createFileSettingsReader("urbackup/data/settings.cfg");
std::string settings_fn="urbackup/data/settings.cfg";
std::string clientsubname;
if(new_settings->getValue("clientsubname", &clientsubname) && !clientsubname.empty())
{
settings_fn = "urbackup/data/settings_"+conv_filename(clientsubname)+".cfg";
}
ISettingsReader* old_settings=Server->createFileSettingsReader(settings_fn);
std::vector<std::wstring> new_keys = new_settings->getKeys();
bool modified_settings=true;
@ -1618,7 +1645,7 @@ void ClientConnector::replaceSettings(const std::string &pData)
new_data+="client_set_settings=true\n";
new_data+="client_set_settings_time="+nconvert(Server->getTimeSeconds())+"\n";
writestring(new_data, "urbackup/data/settings.cfg");
writestring(new_data, settings_fn);
}
Server->destroy(new_settings);
@ -2442,11 +2469,16 @@ void ClientConnector::update_silent(void)
#endif
}
bool ClientConnector::calculateFilehashesOnClient(void)
bool ClientConnector::calculateFilehashesOnClient(const std::string& clientsubname)
{
if(internet_conn)
{
ISettingsReader *curr_settings=Server->createFileSettingsReader("urbackup/data/settings.cfg");
std::string settings_fn = "urbackup/data/settings.cfg";
if(!clientsubname.empty())
{
settings_fn = "urbackup/data/settings_"+clientsubname+".cfg";
}
ISettingsReader *curr_settings=Server->createFileSettingsReader(settings_fn);
std::string val;
if(curr_settings->getValue("internet_calculate_filehashes_on_client", &val)

View File

@ -133,7 +133,7 @@ public:
private:
bool checkPassword(const std::wstring &cmd, bool& change_pw);
bool saveBackupDirs(str_map &args, bool server_default=false);
bool saveBackupDirs(str_map &args, bool server_default=false, int group_offset=0);
void updateLastBackup(void);
std::string replaceChars(std::string in);
void updateSettings(const std::string &pData);
@ -155,7 +155,7 @@ private:
void tochannelSendStartbackup(RunningAction backup_type);
void ImageErr(const std::string &msg);
void update_silent(void);
bool calculateFilehashesOnClient(void);
bool calculateFilehashesOnClient(const std::string& clientsubname);
void sendStatus();
bool sendChannelPacket(const SChannel& channel, const std::string& msg);

View File

@ -211,6 +211,14 @@ void ClientConnector::CMD_START_INCR_FILEBACKUP(const std::string &cmd)
group = watoi(it_group->second);
}
std::string clientsubname;
str_map::iterator it_clientsubname = params.find(L"clientsubname");
if(it_clientsubname!=params.end())
{
clientsubname = conv_filename(Server->ConvertToUTF8(it_clientsubname->second));
}
unsigned int flags = 0;
if(params.find(L"with_scripts")!=params.end())
@ -238,7 +246,7 @@ void ClientConnector::CMD_START_INCR_FILEBACKUP(const std::string &cmd)
flags |= flag_end_to_end_verification;
}
if(calculateFilehashesOnClient())
if(calculateFilehashesOnClient(clientsubname))
{
flags |= flag_calc_checksums;
}
@ -248,11 +256,12 @@ void ClientConnector::CMD_START_INCR_FILEBACKUP(const std::string &cmd)
IScopedLock lock(backup_mutex);
CWData data;
data.addChar(0);
data.addChar(IndexThread::IndexThreadAction_StartIncrFileBackup);
data.addVoidPtr(mempipe);
data.addString(server_token);
data.addInt(group);
data.addInt(flags);
data.addString(clientsubname);
IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize());
mempipe_owner=false;
@ -308,6 +317,13 @@ void ClientConnector::CMD_START_FULL_FILEBACKUP(const std::string &cmd)
group = watoi(it_group->second);
}
std::string clientsubname;
str_map::iterator it_clientsubname = params.find(L"clientsubname");
if(it_clientsubname!=params.end())
{
clientsubname = conv_filename(Server->ConvertToUTF8(it_clientsubname->second));
}
int flags = 0;
if(params.find(L"with_scripts")!=params.end())
@ -335,7 +351,7 @@ void ClientConnector::CMD_START_FULL_FILEBACKUP(const std::string &cmd)
flags |= flag_end_to_end_verification;
}
if(calculateFilehashesOnClient())
if(calculateFilehashesOnClient(clientsubname))
{
flags |= flag_calc_checksums;
}
@ -345,11 +361,12 @@ void ClientConnector::CMD_START_FULL_FILEBACKUP(const std::string &cmd)
IScopedLock lock(backup_mutex);
CWData data;
data.addChar(1);
data.addChar(IndexThread::IndexThreadAction_StartFullFileBackup);
data.addVoidPtr(mempipe);
data.addString(server_token);
data.addInt(group);
data.addInt(flags);
data.addString(clientsubname);
IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize());
mempipe_owner=false;

View File

@ -119,7 +119,7 @@ void ImageThread::sendFullImageThread(void)
if(!image_inf->shadowdrive.empty())
{
fs.reset(image_fak->createFilesystem(Server->ConvertToUnicode(image_inf->shadowdrive), true,
IndexThread::backgroundBackupsEnabled(), true));
IndexThread::backgroundBackupsEnabled(std::string()), true));
shutdown_helper.reset(fs.get());
}
if(fs.get()==NULL)
@ -435,7 +435,7 @@ void ImageThread::sendIncrImageThread(void)
if(!image_inf->shadowdrive.empty())
{
fs.reset(image_fak->createFilesystem(Server->ConvertToUnicode(image_inf->shadowdrive), true,
IndexThread::backgroundBackupsEnabled(), true));
IndexThread::backgroundBackupsEnabled(std::string()), true));
shutdown_helper.reset(fs.get());
}
if(fs.get()==NULL)

View File

@ -254,7 +254,7 @@ void InternetClient::doUpdateSettings(void)
&& !settings->getValue("computername_def", &computername) )
|| computername.empty())
{
computername=Server->ConvertToUTF8(IndexThread::getFileSrv()->getServerName());
computername=Server->ConvertToUTF8(IndexThread::getFileSrv()->getServerName());
}
if(settings->getValue("internet_server", &server_name) || settings->getValue("internet_server_def", &server_name) )
{

View File

@ -73,8 +73,12 @@ bool ServerIdentityMgr::checkServerSessionIdentity(const std::string &pIdentity,
for(size_t i=0;i<session_identities.size();++i)
{
int64 time = online_session_identities[i];
if(time<0) time*=-1;
if(session_identities[i].ident==pIdentity
&& session_identities[i].endpoint==endpoint)
&& session_identities[i].endpoint==endpoint
&& Server->getTimeMS()-time<ident_online_timeout)
{
online_session_identities[i]=Server->getTimeMS();
return true;
@ -187,7 +191,7 @@ void ServerIdentityMgr::loadServerIdentities(void)
}
else
{
online_session_identities.push_back(0);
online_session_identities.push_back(-1*Server->getTimeMS());
}
}
}
@ -314,7 +318,7 @@ void ServerIdentityMgr::addSessionIdentity( const std::string &pIdentity, const
IScopedLock lock(mutex);
SSessionIdentity session_ident = { pIdentity, endpoint};
session_identities.push_back(session_ident);
online_session_identities.push_back(0);
online_session_identities.push_back(Server->getTimeMS());
filesrv->addIdentity("#I"+pIdentity+"#");
writeSessionIdentities();
}
@ -323,7 +327,7 @@ void ServerIdentityMgr::writeSessionIdentities()
{
IScopedLock lock(mutex);
const size_t max_session_identities=20;
const size_t max_session_identities=1000;
size_t start=0;
if(session_identities.size()>max_session_identities)
@ -331,12 +335,26 @@ void ServerIdentityMgr::writeSessionIdentities()
start=session_identities.size()-max_session_identities;
}
size_t written = 0;
std::string idents;
for(size_t i=start;i<session_identities.size();++i)
for(size_t i=session_identities.size(); i-- >0;)
{
if(!idents.empty()) idents+="\r\n";
idents+=session_identities[i].ident;
idents+="#endpoint="+session_identities[i].endpoint;
int64 time = online_session_identities[i];
if(time<0) time*=-1;
if(Server->getTimeMS()-time<ident_online_timeout)
{
if(!idents.empty()) idents+="\r\n";
idents+=session_identities[i].ident;
idents+="#endpoint="+session_identities[i].endpoint;
++written;
if(written>=max_session_identities)
{
break;
}
}
}
write_file_only_admin(idents, server_session_ident_file);
}

View File

@ -57,6 +57,8 @@ volatile bool IdleCheckerThread::pause=false;
volatile bool IndexThread::stop_index=false;
std::map<std::wstring, std::wstring> IndexThread::filesrv_share_dirs;
const char IndexThread::IndexThreadAction_StartFullFileBackup=0;
const char IndexThread::IndexThreadAction_StartIncrFileBackup=1;
const char IndexThread::IndexThreadAction_GetLog=9;
const char IndexThread::IndexThreadAction_PingShadowCopy=10;
const char IndexThread::IndexThreadAction_AddWatchdir = 5;
@ -361,7 +363,7 @@ void IndexThread::operator()(void)
#endif
#ifdef _WIN32
if(backgroundBackupsEnabled())
if(backgroundBackupsEnabled(std::string()))
{
#ifndef _DEBUG
#ifdef THREAD_MODE_BACKGROUND_BEGIN
@ -413,7 +415,7 @@ void IndexThread::operator()(void)
char action;
data.getChar(&action);
data.getVoidPtr((void**)&contractor);
if(action==0)
if(action==IndexThreadAction_StartFullFileBackup)
{
Server->Log("Removing VSS log data...", LL_DEBUG);
vsslog.clear();
@ -422,6 +424,7 @@ void IndexThread::operator()(void)
data.getInt(&index_group);
unsigned int flags;
data.getUInt(&flags);
data.getStr(&index_clientsubname);
setFlags(flags);
@ -498,7 +501,7 @@ void IndexThread::operator()(void)
contractor->Write("error - stop_index 1");
}
}
else if(action==1)
else if(action==IndexThreadAction_StartIncrFileBackup)
{
Server->Log("Removing VSS log data...", LL_DEBUG);
vsslog.clear();
@ -507,6 +510,7 @@ void IndexThread::operator()(void)
data.getInt(&index_group);
unsigned int flags;
data.getUInt(&flags);
data.getStr(&index_clientsubname);
setFlags(flags);
@ -1325,7 +1329,7 @@ bool IndexThread::readBackupScripts()
{
scripts.clear();
if(!with_scripts)
if(!with_scripts || index_group!=c_group_default)
{
return false;
}
@ -2569,7 +2573,13 @@ void IndexThread::readPatterns(bool &pattern_changed, bool update_saved_patterns
include_pattern_key=L"continuous_include_files";
}
ISettingsReader *curr_settings=Server->createFileSettingsReader("urbackup/data/settings.cfg");
std::string settings_fn = "urbackup/data/settings.cfg";
if(!index_clientsubname.empty())
{
settings_fn = "urbackup/data/settings_"+index_clientsubname+".cfg";
}
ISettingsReader *curr_settings=Server->createFileSettingsReader(settings_fn);
exlude_dirs.clear();
if(curr_settings!=NULL)
{
@ -2862,6 +2872,10 @@ void IndexThread::start_filesrv(void)
curr_udpport=0;
}
IFileServFactory* filesrv_fak = (IFileServFactory*)Server->getPlugin(Server->getThreadID(), filesrv_pluginid);
filesrv=filesrv_fak->createFileServ(curr_tcpport, curr_udpport, name, use_fqdn,
backgroundBackupsEnabled(std::string()));
filesrv->shareDir(L"urbackup", Server->getServerWorkingDir()+L"/urbackup/data", std::string());
ServerIdentityMgr::setFileServ(filesrv);
@ -3415,9 +3429,16 @@ std::string IndexThread::escapeListName( const std::string& listname )
return ret;
}
bool IndexThread::backgroundBackupsEnabled()
bool IndexThread::backgroundBackupsEnabled(const std::string& clientsubname)
{
std::auto_ptr<ISettingsReader> curr_settings(Server->createFileSettingsReader("urbackup/data/settings.cfg"));
std::string settings_fn = "urbackup/data/settings.cfg";
if(!clientsubname.empty())
{
settings_fn = "urbackup/data/settings_"+conv_filename(clientsubname)+".cfg";
}
std::auto_ptr<ISettingsReader> curr_settings(Server->createFileSettingsReader(settings_fn));
if(curr_settings.get()!=NULL)
{
std::string background_backups;

View File

@ -39,6 +39,8 @@
const int c_group_default = 0;
const int c_group_continuous = 1;
const int c_group_max = 99;
const int c_group_size = 100;
const unsigned int flag_end_to_end_verification = 2;
const unsigned int flag_with_scripts = 4;
@ -142,6 +144,8 @@ class ClientDAO;
class IndexThread : public IThread
{
public:
static const char IndexThreadAction_StartFullFileBackup;
static const char IndexThreadAction_StartIncrFileBackup;
static const char IndexThreadAction_GetLog;
static const char IndexThreadAction_PingShadowCopy;
static const char IndexThreadAction_AddWatchdir;
@ -168,7 +172,7 @@ public:
static void doStop(void);
static bool backgroundBackupsEnabled();
static bool backgroundBackupsEnabled(const std::string& clientsubname);
static std::vector<std::wstring> parseExcludePatterns(const std::wstring& val);
static std::vector<std::wstring> parseIncludePatterns(const std::wstring& val, std::vector<int>& include_depth,
@ -322,6 +326,7 @@ private:
int index_group;
int index_flags;
std::string index_clientsubname;
SCDirs* index_scd;

View File

@ -477,10 +477,10 @@ std::string get_file_tokens( const std::wstring& fn, ClientDAO* dao, TokenCache&
std::map<std::vector<char>, Token>::iterator token_it =
token_cache.get()->tokens.find(sid);
assert(token_it->second.id!=0);
if(token_it!=token_cache.get()->tokens.end())
{
assert(token_it->second.id!=0);
if(allow)
{
token_info.addChar(ID_GRANT_ACCESS);

View File

@ -102,7 +102,7 @@ size_t InternetServicePipe2::Read( char *buffer, size_t bsize, int timeoutms/*=-
return 0;
}
}
while(timeoutms>0 && Server->getTimeMS()-starttime<timeoutms);
while(timeoutms==-1 || (timeoutms>0 && Server->getTimeMS()-starttime<timeoutms));
return 0;
}

View File

@ -607,27 +607,32 @@ bool FileClient::Reconnect(void)
{
transferred_bytes+=tcpsock->getTransferedBytes();
real_transferred_bytes+=tcpsock->getRealTransferredBytes();
IScopedLock lock(mutex);
Server->destroy(tcpsock);
tcpsock=NULL;
}
connect_starttime=Server->getTimeMS();
while(Server->getTimeMS()-connect_starttime<reconnection_timeout)
{
IPipe* new_tcpsock;
if(reconnection_callback==NULL)
{
tcpsock=Server->ConnectStream(inet_ntoa(server_addr.sin_addr), TCP_PORT, 10000);
new_tcpsock=Server->ConnectStream(inet_ntoa(server_addr.sin_addr), TCP_PORT, 10000);
}
else
{
tcpsock=reconnection_callback->new_fileclient_connection();
new_tcpsock=reconnection_callback->new_fileclient_connection();
}
if(tcpsock!=NULL)
if(new_tcpsock!=NULL)
{
for(size_t i=0;i<throttlers.size();++i)
{
tcpsock->addThrottler(throttlers[i]);
new_tcpsock->addThrottler(throttlers[i]);
}
Server->Log("Reconnected successfully,", LL_DEBUG);
IScopedLock lock(mutex);
tcpsock = new_tcpsock;
socket_open=true;
return true;
}
@ -1491,6 +1496,10 @@ _i64 FileClient::getRealTransferredBytes()
void FileClient::Shutdown()
{
tcpsock->shutdown();
IScopedLock lock(mutex);
if(tcpsock!=NULL)
{
tcpsock->shutdown();
}
}

View File

@ -79,7 +79,7 @@ std::vector<SFile> getFiles(const std::wstring &path, bool *has_error)
}
std::wstring errmsg;
int err = os_last_error(errmsg);
Server->Log(L"Cannot open \""+path+L"\": "+errmsg+L" ("+convert(err)+L")", LL_ERROR);
Log(L"Cannot open \""+path+L"\": "+errmsg+L" ("+convert(err)+L")", LL_ERROR);
return tmp;
}
@ -156,9 +156,9 @@ std::vector<SFile> getFiles(const std::wstring &path, bool *has_error)
}
else
{
std::wstring errmsg;
std::wstring errmsg;
int err = os_last_error(errmsg);
Server->Log("Cannot stat \""+upath+dirp->d_name+"\": "+Server->ConvertToUTF8(errmsg)+" ("+nconvert(err)+")", LL_ERROR);
Log("Cannot stat \""+upath+dirp->d_name+"\": "+ConvertToUTF8(errmsg)+" ("+nconvert(err)+")", LL_ERROR);
if(has_error!=NULL)
{
*has_error=true;
@ -181,7 +181,7 @@ std::vector<SFile> getFiles(const std::wstring &path, bool *has_error)
{
std::wstring errmsg;
int err = os_last_error(errmsg);
Server->Log(L"Error listing files in directory \""+path+L"\": "+errmsg+L" ("+convert(err)+L")", LL_ERROR);
Log(L"Error listing files in directory \""+path+L"\": "+errmsg+L" ("+convert(err)+L")", LL_ERROR);
if(has_error!=NULL)
*has_error=true;
}
@ -696,7 +696,7 @@ int64 os_last_error(std::wstring& message)
char* str = strerror(err);
if(str!=NULL)
{
message = Server->ConvertToUnicode(str);
message = ConvertToUnicode(str);
}
return err;
}

View File

@ -41,6 +41,7 @@ std::vector<std::wstring> getSettingsList(void)
ret.push_back(L"exclude_files");
ret.push_back(L"include_files");
ret.push_back(L"computername");
ret.push_back(L"virtual_clients");
ret.push_back(L"default_dirs");
ret.push_back(L"allow_config_paths");
ret.push_back(L"allow_starting_full_file_backups");

View File

@ -30,8 +30,8 @@
extern IUrlFactory *url_fak;
Backup::Backup(ClientMain* client_main, int clientid, std::wstring clientname, LogAction log_action, bool is_file_backup, bool is_incremental)
: client_main(client_main), clientid(clientid), clientname(clientname), log_action(log_action),
Backup::Backup(ClientMain* client_main, int clientid, std::wstring clientname, std::wstring clientsubname, LogAction log_action, bool is_file_backup, bool is_incremental)
: client_main(client_main), clientid(clientid), clientname(clientname), clientsubname(clientsubname), log_action(log_action),
is_file_backup(is_file_backup), r_incremental(is_incremental), r_resumed(false), backup_result(false),
log_backup(true), has_early_error(false), should_backoff(true), db(NULL), status_id(0)
{

View File

@ -34,7 +34,7 @@ enum LogAction
class Backup : public IThread
{
public:
Backup(ClientMain* client_main, int clientid, std::wstring clientname, LogAction log_action, bool is_file_backup, bool is_incremental);
Backup(ClientMain* client_main, int clientid, std::wstring clientname, std::wstring clientsubname, LogAction log_action, bool is_file_backup, bool is_incremental);
virtual ~Backup() {}
virtual void operator()();
@ -70,6 +70,7 @@ protected:
ClientMain* client_main;
int clientid;
std::wstring clientname;
std::wstring clientsubname;
LogAction log_action;
IDatabase* db;

View File

@ -96,16 +96,18 @@ int ClientMain::restore_client_id = -1;
ClientMain::ClientMain(IPipe *pPipe, sockaddr_in pAddr, const std::wstring &pName,
bool internet_connection, bool use_snapshots, bool use_reflink)
const std::wstring& pSubName, const std::wstring& pMainName, int filebackup_group_offset, bool internet_connection, bool use_snapshots, bool use_reflink)
: internet_connection(internet_connection), server_settings(NULL), client_throttler(NULL),
use_snapshots(use_snapshots), use_reflink(use_reflink),
backup_dao(NULL), client_updated_time(0), continuous_backup(NULL)
backup_dao(NULL), client_updated_time(0), continuous_backup(NULL),
clientsubname(pSubName), filebackup_group_offset(filebackup_group_offset)
{
q_update_lastseen=NULL;
pipe=pPipe;
clientaddr=pAddr;
clientaddr_mutex=Server->createMutex();
clientname=pName;
clientmainname=pMainName;
clientid=0;
do_full_backup_now=false;
@ -321,6 +323,10 @@ void ClientMain::operator ()(void)
delete this;
return;
}
else if(!clientsubname.empty())
{
backup_dao->setVirtualMainClient(clientmainname, clientid);
}
logid = ServerLogger::getLogId(clientid);
@ -341,10 +347,11 @@ void ClientMain::operator ()(void)
return;
}
if(server_settings->getSettings()->computername.empty())
if(server_settings->getSettings()->computername.empty() || !clientsubname.empty())
{
server_settings->getSettings()->computername=clientname;
}
if(server_settings->getImageFileFormat()==image_file_format_cowraw)
{
curr_image_version = curr_image_version & c_image_cowraw_bit;
@ -420,6 +427,11 @@ void ClientMain::operator ()(void)
sendSettings();
}
if(!server_settings->getSettings()->virtual_clients.empty())
{
BackupServer::setVirtualClients(clientname, server_settings->getSettings()->virtual_clients);
}
ServerLogger::Log(logid, "Sending backup incr intervall...", LL_DEBUG);
sendClientBackupIncrIntervall();
@ -464,6 +476,20 @@ void ClientMain::operator ()(void)
ServerLogger::Log(logid, "Getting client settings failed -2", LL_ERROR);
received_client_settings=false;
}
if(server_settings->getImageFileFormat()==image_file_format_cowraw)
{
curr_image_version = curr_image_version & c_image_cowraw_bit;
}
else
{
curr_image_version = curr_image_version & ~c_image_cowraw_bit;
}
if(!server_settings->getSettings()->virtual_clients.empty())
{
BackupServer::setVirtualClients(clientname, server_settings->getSettings()->virtual_clients);
}
}
if(settings_updated && (received_client_settings || settings_dont_exist) )
@ -512,10 +538,10 @@ void ClientMain::operator ()(void)
&& (!isRunningFileBackup(c_group_default) || do_full_backup_now) )
{
SRunningBackup backup;
backup.backup = new FullFileBackup(this, clientid, clientname,
do_full_backup_now?LogAction_AlwaysLog:LogAction_LogIfNotDisabled, c_group_default, use_tmpfiles,
backup.backup = new FullFileBackup(this, clientid, clientname, clientsubname,
do_full_backup_now?LogAction_AlwaysLog:LogAction_LogIfNotDisabled, filebackup_group_offset + c_group_default, use_tmpfiles,
tmpfile_path, use_reflink, use_snapshots);
backup.group=c_group_default;
backup.group=filebackup_group_offset + c_group_default;
backup_queue.push_back(backup);
@ -528,10 +554,10 @@ void ClientMain::operator ()(void)
&& (!isRunningFileBackup(c_group_default) || do_incr_backup_now) )
{
SRunningBackup backup;
backup.backup = new IncrFileBackup(this, clientid, clientname,
do_full_backup_now?LogAction_AlwaysLog:LogAction_LogIfNotDisabled, c_group_default, use_tmpfiles,
backup.backup = new IncrFileBackup(this, clientid, clientname, clientsubname,
do_full_backup_now?LogAction_AlwaysLog:LogAction_LogIfNotDisabled, filebackup_group_offset + c_group_default, use_tmpfiles,
tmpfile_path, use_reflink, use_snapshots);
backup.group=c_group_default;
backup.group=filebackup_group_offset + c_group_default;
backup_queue.push_back(backup);
@ -550,7 +576,7 @@ void ClientMain::operator ()(void)
if( (isUpdateFullImage(letter) && !isRunningImageBackup(letter)) || do_full_image_now )
{
SRunningBackup backup;
backup.backup = new ImageBackup(this, clientid, clientname, do_full_image_now?LogAction_AlwaysLog:LogAction_LogIfNotDisabled,
backup.backup = new ImageBackup(this, clientid, clientname, clientsubname, do_full_image_now?LogAction_AlwaysLog:LogAction_LogIfNotDisabled,
false, letter);
backup.letter=letter;
@ -572,7 +598,7 @@ void ClientMain::operator ()(void)
if( (isUpdateIncrImage(letter) && !isRunningImageBackup(letter)) || do_incr_image_now )
{
SRunningBackup backup;
backup.backup = new ImageBackup(this, clientid, clientname, do_full_image_now?LogAction_AlwaysLog:LogAction_LogIfNotDisabled,
backup.backup = new ImageBackup(this, clientid, clientname, clientsubname, do_full_image_now?LogAction_AlwaysLog:LogAction_LogIfNotDisabled,
true, letter);
backup.letter=letter;
@ -587,7 +613,7 @@ void ClientMain::operator ()(void)
cdp_needs_sync=false;
SRunningBackup backup;
backup.backup = new ContinuousBackup(this, clientid, clientname,
backup.backup = new ContinuousBackup(this, clientid, clientname, clientsubname,
LogAction_LogIfNotDisabled, c_group_default, use_tmpfiles,
tmpfile_path, use_reflink, use_snapshots);
backup.group=c_group_continuous;
@ -603,6 +629,8 @@ void ClientMain::operator ()(void)
{
if(Server->getThreadPool()->waitFor(backup_queue[i].ticket, 0))
{
ServerStatus::subRunningJob(clientmainname);
if(!backup_queue[i].backup->getResult() &&
backup_queue[i].backup->shouldBackoff())
{
@ -650,11 +678,7 @@ void ClientMain::operator ()(void)
size_t running_jobs=0;
for(size_t i=0;i<backup_queue.size();++i)
{
if(backup_queue[i].ticket!=ILLEGAL_THREADPOOL_TICKET)
{
++running_jobs;
}
else
if(backup_queue[i].ticket==ILLEGAL_THREADPOOL_TICKET)
{
can_start=true;
}
@ -662,16 +686,23 @@ void ClientMain::operator ()(void)
if(can_start)
{
while(running_jobs<server_settings->getSettings()->max_running_jobs_per_client)
while(ServerStatus::numRunningJobs(clientmainname)<server_settings->getSettings()->max_running_jobs_per_client)
{
bool started_job=false;
for(size_t i=0;i<backup_queue.size();++i)
{
if(backup_queue[i].ticket==ILLEGAL_THREADPOOL_TICKET)
{
backup_queue[i].ticket=Server->getThreadPool()->execute(backup_queue[i].backup);
++running_jobs;
started_job=true;
ServerStatus::addRunningJob(clientmainname);
if(ServerStatus::numRunningJobs(clientmainname)<=server_settings->getSettings()->max_running_jobs_per_client)
{
backup_queue[i].ticket=Server->getThreadPool()->execute(backup_queue[i].backup);
started_job=true;
}
else
{
ServerStatus::subRunningJob(clientmainname);
}
break;
}
}
@ -756,6 +787,7 @@ void ClientMain::operator ()(void)
if(backup_queue[i].ticket!=ILLEGAL_THREADPOOL_TICKET)
{
Server->getThreadPool()->waitFor(backup_queue[i].ticket);
ServerStatus::subRunningJob(clientmainname);
}
delete backup_queue[i].backup;
@ -1239,6 +1271,12 @@ void ClientMain::sendSettings(void)
{
std::string s_settings;
if(!clientsubname.empty())
{
s_settings+="clientsubname="+Server->ConvertToUTF8(clientsubname)+"\n";
s_settings+="filebackup_group_offset="+nconvert(filebackup_group_offset)+"\n";
}
std::vector<std::wstring> settings_names=getSettingsList();
std::vector<std::wstring> global_settings_names=getGlobalizedSettingsList();
std::vector<std::wstring> local_settings_names=getLocalizedSettingsList();
@ -1263,10 +1301,10 @@ void ClientMain::sendSettings(void)
ServerBackupDao::CondString origSettingsData = backup_dao->getOrigClientSettings(clientid);
ISettingsReader* origSettings = NULL;
std::auto_ptr<ISettingsReader> origSettings;
if(origSettingsData.exists)
{
origSettings = Server->createMemorySettingsReader(Server->ConvertToUTF8(origSettingsData.value));
origSettings.reset(Server->createMemorySettingsReader(Server->ConvertToUTF8(origSettingsData.value)));
}
for(size_t i=0;i<settings_names.size();++i)
@ -1289,7 +1327,7 @@ void ClientMain::sendSettings(void)
{
s_settings+=Server->ConvertToUTF8(key)+"="+Server->ConvertToUTF8(value)+"\n";
}
else if(origSettings!=NULL)
else if(origSettings.get()!=NULL)
{
std::wstring orig_v;
if( (origSettings->getValue(key, &orig_v) ||
@ -1313,7 +1351,6 @@ void ClientMain::sendSettings(void)
}
}
}
delete origSettings;
escapeClientMessage(s_settings);
if(sendClientMessage("SETTINGS "+s_settings, "OK", L"Sending settings to client failed", 10000))
{
@ -1339,7 +1376,15 @@ bool ClientMain::getClientSettings(bool& doesnt_exist)
ServerLogger::Log(logid, "Error creating temporary file in BackupServerGet::getClientSettings", LL_ERROR);
return false;
}
rc=fc.GetFile("urbackup/settings.cfg", tmp, true, false);
std::string settings_fn = "urbackup/settings.cfg";
if(!clientsubname.empty())
{
settings_fn = "urbackup/settings_"+Server->ConvertToUTF8(clientsubname)+".cfg";
}
rc=fc.GetFile(settings_fn, tmp, true, false);
if(rc!=ERR_SUCCESS)
{
ServerLogger::Log(logid, L"Error getting Client settings of "+clientname+L". Errorcode: "+widen(fc.getErrorString(rc))+L" ("+convert(rc)+L")", LL_ERROR);
@ -1437,15 +1482,6 @@ bool ClientMain::getClientSettings(bool& doesnt_exist)
if(mod)
{
server_settings->update(true);
if(server_settings->getImageFileFormat()==image_file_format_cowraw)
{
curr_image_version = curr_image_version & c_image_cowraw_bit;
}
else
{
curr_image_version = curr_image_version & ~c_image_cowraw_bit;
}
}
return true;
@ -1780,15 +1816,21 @@ IPipeThrottler *ClientMain::getThrottler(size_t speed_bps)
IPipe *ClientMain::getClientCommandConnection(int timeoutms, std::string* clientaddr)
{
std::string curr_clientname = Server->ConvertToUTF8(clientname);
if(!clientsubname.empty())
{
curr_clientname = Server->ConvertToUTF8(clientmainname);
}
if(clientaddr!=NULL)
{
unsigned int ip = ServerStatus::getStatus(clientname).ip_addr;
unsigned int ip = ServerStatus::getStatus(Server->ConvertToUnicode(curr_clientname)).ip_addr;
unsigned char *ips=reinterpret_cast<unsigned char*>(&ip);
*clientaddr=nconvert(ips[0])+"."+nconvert(ips[1])+"."+nconvert(ips[2])+"."+nconvert(ips[3]);
}
if(internet_connection)
{
IPipe *ret=InternetServiceConnector::getConnection(Server->ConvertToUTF8(clientname), SERVICE_COMMANDS, timeoutms);
IPipe *ret=InternetServiceConnector::getConnection(curr_clientname, SERVICE_COMMANDS, timeoutms);
if(server_settings!=NULL && ret!=NULL)
{
int internet_speed=server_settings->getInternetSpeed();
@ -1826,10 +1868,16 @@ IPipe *ClientMain::getClientCommandConnection(int timeoutms, std::string* client
_u32 ClientMain::getClientFilesrvConnection(FileClient *fc, ServerSettings* server_settings, int timeoutms)
{
std::string curr_clientname = Server->ConvertToUTF8(clientname);
if(!clientsubname.empty())
{
curr_clientname = Server->ConvertToUTF8(clientmainname);
}
fc->setProgressLogCallback(this);
if(internet_connection)
{
IPipe *cp=InternetServiceConnector::getConnection(Server->ConvertToUTF8(clientname), SERVICE_FILESRV, timeoutms);
IPipe *cp=InternetServiceConnector::getConnection(curr_clientname, SERVICE_FILESRV, timeoutms);
_u32 ret=fc->Connect(cp);
@ -1876,10 +1924,16 @@ _u32 ClientMain::getClientFilesrvConnection(FileClient *fc, ServerSettings* serv
bool ClientMain::getClientChunkedFilesrvConnection(std::auto_ptr<FileClientChunked>& fc_chunked, ServerSettings* server_settings, int timeoutms)
{
std::string curr_clientname = Server->ConvertToUTF8(clientname);
if(!clientsubname.empty())
{
curr_clientname = Server->ConvertToUTF8(clientmainname);
}
std::string identity = session_identity.empty()?server_identity:session_identity;
if(internet_connection)
{
IPipe *cp=InternetServiceConnector::getConnection(Server->ConvertToUTF8(clientname), SERVICE_FILESRV, timeoutms);
IPipe *cp=InternetServiceConnector::getConnection(curr_clientname, SERVICE_FILESRV, timeoutms);
if(cp!=NULL)
{
fc_chunked.reset(new FileClientChunked(cp, false, &tcpstack, this, use_tmpfiles?NULL:this, identity, NULL));
@ -1986,10 +2040,16 @@ void ClientMain::destroyTemporaryFile(IFile *tmp)
IPipe * ClientMain::new_fileclient_connection(void)
{
std::string curr_clientname = Server->ConvertToUTF8(clientname);
if(!clientsubname.empty())
{
curr_clientname = Server->ConvertToUTF8(clientmainname);
}
IPipe *rp=NULL;
if(internet_connection)
{
rp=InternetServiceConnector::getConnection(Server->ConvertToUTF8(clientname), SERVICE_FILESRV, c_filesrv_connect_timeout);
rp=InternetServiceConnector::getConnection(curr_clientname, SERVICE_FILESRV, c_filesrv_connect_timeout);
}
else
{

View File

@ -31,9 +31,10 @@ class BackupServerContinuous;
class ContinuousBackup;
class Backup;
const int c_group_all = -1;
const int c_group_default = 0;
const int c_group_continuous = 1;
const int c_group_max = 99;
const int c_group_size = 100;
struct SProtocolVersions
{
@ -94,7 +95,7 @@ class ClientMain : public IThread, public FileClientChunked::ReconnectionCallbac
{
friend class ServerHashExisting;
public:
ClientMain(IPipe *pPipe, sockaddr_in pAddr, const std::wstring &pName, bool internet_connection, bool use_snapshots, bool use_reflink);
ClientMain(IPipe *pPipe, sockaddr_in pAddr, const std::wstring &pName, const std::wstring& pSubName, const std::wstring& pMainName, int filebackup_group_offset, bool internet_connection, bool use_snapshots, bool use_reflink);
~ClientMain(void);
void operator()(void);
@ -218,6 +219,9 @@ private:
sockaddr_in clientaddr;
IMutex *clientaddr_mutex;
std::wstring clientname;
std::wstring clientsubname;
std::wstring clientmainname;
int filebackup_group_offset;
std::wstring tmpfile_path;
static size_t tmpfile_num;

View File

@ -21,9 +21,9 @@
#include "server_continuous.h"
#include "IncrFileBackup.h"
ContinuousBackup::ContinuousBackup( ClientMain* client_main, int clientid, std::wstring clientname, LogAction log_action,
ContinuousBackup::ContinuousBackup( ClientMain* client_main, int clientid, std::wstring clientname, std::wstring clientsubname, LogAction log_action,
int group, bool use_tmpfiles, std::wstring tmpfile_path, bool use_reflink, bool use_snapshots )
: FileBackup(client_main, clientid, clientname, log_action, true, group, use_tmpfiles, tmpfile_path, use_reflink, use_snapshots)
: FileBackup(client_main, clientid, clientname, clientsubname, log_action, true, group, use_tmpfiles, tmpfile_path, use_reflink, use_snapshots)
{
cdp_path=true;
}
@ -59,7 +59,7 @@ bool ContinuousBackup::doFileBackup()
client_main->setContinuousBackup(continuous_update);
}
IncrFileBackup incr_backup(client_main, clientid, clientname, LogAction_NoLogging, group, use_tmpfiles, tmpfile_path, use_reflink, use_snapshots);
IncrFileBackup incr_backup(client_main, clientid, clientname, clientsubname, LogAction_NoLogging, group, use_tmpfiles, tmpfile_path, use_reflink, use_snapshots);
incr_backup();
if(incr_backup.getResult())

View File

@ -7,7 +7,7 @@ class BackupServerContinuous;
class ContinuousBackup : public FileBackup
{
public:
ContinuousBackup(ClientMain* client_main, int clientid, std::wstring clientname, LogAction log_action,
ContinuousBackup(ClientMain* client_main, int clientid, std::wstring clientname, std::wstring clientsubname, LogAction log_action,
int group, bool use_tmpfiles, std::wstring tmpfile_path, bool use_reflink, bool use_snapshots);
~ContinuousBackup();

View File

@ -45,8 +45,8 @@ const unsigned int full_backup_construct_timeout=4*60*60*1000;
extern std::string server_identity;
extern std::string server_token;
FileBackup::FileBackup( ClientMain* client_main, int clientid, std::wstring clientname, LogAction log_action, bool is_incremental, int group, bool use_tmpfiles, std::wstring tmpfile_path, bool use_reflink, bool use_snapshots)
: Backup(client_main, clientid, clientname, log_action, true, is_incremental), group(group), use_tmpfiles(use_tmpfiles), tmpfile_path(tmpfile_path), use_reflink(use_reflink), use_snapshots(use_snapshots),
FileBackup::FileBackup( ClientMain* client_main, int clientid, std::wstring clientname, std::wstring clientsubname, LogAction log_action, bool is_incremental, int group, bool use_tmpfiles, std::wstring tmpfile_path, bool use_reflink, bool use_snapshots)
: Backup(client_main, clientid, clientname, clientsubname, log_action, true, is_incremental), group(group), use_tmpfiles(use_tmpfiles), tmpfile_path(tmpfile_path), use_reflink(use_reflink), use_snapshots(use_snapshots),
disk_error(false), with_hashes(false),
backupid(-1), hashpipe(NULL), hashpipe_prepare(NULL), bsh(NULL), bsh_prepare(NULL),
bsh_ticket(ILLEGAL_THREADPOOL_TICKET), bsh_prepare_ticket(ILLEGAL_THREADPOOL_TICKET), pingthread(NULL),
@ -92,7 +92,8 @@ bool FileBackup::getResult()
return backup_result;
}
bool FileBackup::request_filelist_construct(bool full, bool resume, int group, bool with_token, bool& no_backup_dirs, bool& connect_fail)
bool FileBackup::request_filelist_construct(bool full, bool resume, int group,
bool with_token, bool& no_backup_dirs, bool& connect_fail, const std::wstring& clientsubname)
{
if(server_settings->getSettings()->end_to_end_file_backup_verification)
{
@ -144,6 +145,10 @@ bool FileBackup::request_filelist_construct(bool full, bool resume, int group, b
if(client_main->getProtocolVersions().file_protocol_version_v2>=1)
{
start_backup_cmd+=" group="+nconvert(group);
if(!clientsubname.empty())
{
start_backup_cmd+="&clientsubname="+EscapeParamString(Server->ConvertToUTF8(clientsubname));
}
}
if(resume && client_main->getProtocolVersions().file_protocol_version_v2>=1)
@ -177,7 +182,7 @@ bool FileBackup::request_filelist_construct(bool full, bool resume, int group, b
{
Server->destroy(cc);
ServerLogger::Log(logid, clientname+L": Trying old filelist request", LL_WARNING);
return request_filelist_construct(full, resume, group, false, no_backup_dirs, connect_fail);
return request_filelist_construct(full, resume, group, false, no_backup_dirs, connect_fail, clientsubname);
}
else
{

View File

@ -46,7 +46,7 @@ struct SContinuousSequence
class FileBackup : public Backup
{
public:
FileBackup(ClientMain* client_main, int clientid, std::wstring clientname, LogAction log_action, bool is_incremental, int group, bool use_tmpfiles, std::wstring tmpfile_path, bool use_reflink, bool use_snapshots);
FileBackup(ClientMain* client_main, int clientid, std::wstring clientname, std::wstring subclientname, LogAction log_action, bool is_incremental, int group, bool use_tmpfiles, std::wstring tmpfile_path, bool use_reflink, bool use_snapshots);
~FileBackup();
bool getResult();
@ -71,7 +71,8 @@ protected:
virtual bool doFileBackup() = 0;
ServerBackupDao::SDuration interpolateDurations(const std::vector<ServerBackupDao::SDuration>& durations);
bool request_filelist_construct(bool full, bool resume, int group, bool with_token, bool& no_backup_dirs, bool& connect_fail);
bool request_filelist_construct(bool full, bool resume, int group,
bool with_token, bool& no_backup_dirs, bool& connect_fail, const std::wstring& clientsubname);
void logVssLogdata(int64 vss_duration_s);
bool getTokenFile(FileClient &fc, bool hashed_transfer );
std::string clientlistName( int group, bool new_list=false );

View File

@ -396,7 +396,7 @@ bool FileMetadataDownloadThread::applyWindowsMetadata( IFile* metadata_f, IFile*
if(cont==0)
{
return true;
break;
}
WIN32_STREAM_ID_INT stream_id;

View File

@ -34,8 +34,8 @@ extern std::string server_identity;
extern std::string server_token;
FullFileBackup::FullFileBackup( ClientMain* client_main, int clientid, std::wstring clientname, LogAction log_action, int group, bool use_tmpfiles, std::wstring tmpfile_path, bool use_reflink, bool use_snapshots )
: FileBackup(client_main, clientid, clientname, log_action, false, group, use_tmpfiles, tmpfile_path, use_reflink, use_snapshots)
FullFileBackup::FullFileBackup( ClientMain* client_main, int clientid, std::wstring clientname, std::wstring clientsubname, LogAction log_action, int group, bool use_tmpfiles, std::wstring tmpfile_path, bool use_reflink, bool use_snapshots )
: FileBackup(client_main, clientid, clientname, clientsubname, log_action, false, group, use_tmpfiles, tmpfile_path, use_reflink, use_snapshots)
{
}
@ -69,7 +69,7 @@ bool FullFileBackup::doFileBackup()
bool no_backup_dirs=false;
bool connect_fail=false;
bool b=request_filelist_construct(true, false, group, true, no_backup_dirs, connect_fail);
bool b=request_filelist_construct(true, false, group, true, no_backup_dirs, connect_fail, clientsubname);
if(!b)
{
has_early_error=true;

View File

@ -5,7 +5,7 @@
class FullFileBackup : public FileBackup
{
public:
FullFileBackup(ClientMain* client_main, int clientid, std::wstring clientname, LogAction log_action, int group, bool use_tmpfiles, std::wstring tmpfile_path, bool use_reflink, bool use_snapshots);
FullFileBackup(ClientMain* client_main, int clientid, std::wstring clientname, std::wstring clientsubname, LogAction log_action, int group, bool use_tmpfiles, std::wstring tmpfile_path, bool use_reflink, bool use_snapshots);
protected:
virtual bool doFileBackup();

View File

@ -99,8 +99,8 @@ namespace
}
}
ImageBackup::ImageBackup(ClientMain* client_main, int clientid, std::wstring clientname, LogAction log_action, bool incremental, std::string letter)
: Backup(client_main, clientid, clientname, log_action, false, incremental), pingthread_ticket(ILLEGAL_THREADPOOL_TICKET), letter(letter), synthetic_full(false)
ImageBackup::ImageBackup(ClientMain* client_main, int clientid, std::wstring clientname, std::wstring clientsubname, LogAction log_action, bool incremental, std::string letter)
: Backup(client_main, clientid, clientname, clientsubname, log_action, false, incremental), pingthread_ticket(ILLEGAL_THREADPOOL_TICKET), letter(letter), synthetic_full(false)
{
}
@ -157,7 +157,7 @@ bool ImageBackup::doBackup()
{
ServerLogger::Log(logid, "Backing up SYSVOL...", LL_DEBUG);
client_main->stopBackupRunning(false);
ImageBackup sysvol_backup(client_main, clientid, clientname, LogAction_NoLogging, false, "SYSVOL");
ImageBackup sysvol_backup(client_main, clientid, clientname, clientsubname, LogAction_NoLogging, false, "SYSVOL");
sysvol_backup();
if(sysvol_backup.getResult())
@ -173,7 +173,7 @@ bool ImageBackup::doBackup()
{
ServerLogger::Log(logid, "Backing up EFI System Partition...", LL_DEBUG);
client_main->stopBackupRunning(false);
ImageBackup esp_backup(client_main, clientid, clientname, LogAction_NoLogging, false, "ESP");
ImageBackup esp_backup(client_main, clientid, clientname, clientsubname, LogAction_NoLogging, false, "ESP");
esp_backup();
if(esp_backup.getResult())

View File

@ -11,7 +11,7 @@ class ServerPingThread;
class ImageBackup : public Backup
{
public:
ImageBackup(ClientMain* client_main, int clientid, std::wstring clientname, LogAction log_action, bool incremental, std::string letter);
ImageBackup(ClientMain* client_main, int clientid, std::wstring clientname, std::wstring clientsubname, LogAction log_action, bool incremental, std::string letter);
int getBackupId()
{

View File

@ -40,9 +40,9 @@ extern std::string server_token;
const int64 c_readd_size_limit=100*1024;
IncrFileBackup::IncrFileBackup( ClientMain* client_main, int clientid, std::wstring clientname, LogAction log_action,
IncrFileBackup::IncrFileBackup( ClientMain* client_main, int clientid, std::wstring clientname, std::wstring clientsubname, LogAction log_action,
int group, bool use_tmpfiles, std::wstring tmpfile_path, bool use_reflink, bool use_snapshots )
: FileBackup(client_main, clientid, clientname, log_action, true, group, use_tmpfiles, tmpfile_path, use_reflink, use_snapshots),
: FileBackup(client_main, clientid, clientname, clientsubname, log_action, true, group, use_tmpfiles, tmpfile_path, use_reflink, use_snapshots),
intra_file_diffs(intra_file_diffs), hash_existing_mutex(NULL)
{
@ -106,7 +106,7 @@ bool IncrFileBackup::doFileBackup()
bool no_backup_dirs=false;
bool connect_fail = false;
bool b=request_filelist_construct(resumed_full, resumed_backup, group, true, no_backup_dirs, connect_fail);
bool b=request_filelist_construct(resumed_full, resumed_backup, group, true, no_backup_dirs, connect_fail, clientsubname);
if(!b)
{
has_early_error=true;
@ -1433,7 +1433,7 @@ bool IncrFileBackup::doFullBackup()
ServerStatus::stopProcess(clientname, status_id);
FullFileBackup full_backup(client_main, clientid, clientname, LogAction_NoLogging, group, use_tmpfiles, tmpfile_path, use_reflink, use_snapshots);
FullFileBackup full_backup(client_main, clientid, clientname, clientsubname, LogAction_NoLogging, group, use_tmpfiles, tmpfile_path, use_reflink, use_snapshots);
full_backup();
disk_error = full_backup.hasDiskError();

View File

@ -8,7 +8,7 @@ class FileMetadata;
class IncrFileBackup : public FileBackup
{
public:
IncrFileBackup(ClientMain* client_main, int clientid, std::wstring clientname, LogAction log_action,
IncrFileBackup(ClientMain* client_main, int clientid, std::wstring clientname, std::wstring clientsubname, LogAction log_action,
int group, bool use_tmpfiles, std::wstring tmpfile_path, bool use_reflink, bool use_snapshots);
void addExistingHash(const std::wstring& fullpath, const std::wstring& hashpath, const std::string& shahash, int64 filesize, int64 rsize);

File diff suppressed because it is too large Load Diff

View File

@ -153,6 +153,7 @@ public:
void addToOldBackupfolders(const std::wstring& backupfolder);
std::vector<std::wstring> getOldBackupfolders(void);
std::vector<std::wstring> getDeletePendingClientNames(void);
CondString getVirtualMainClientname(int clientid);
bool createTemporaryLastFilesTable(void);
void dropTemporaryLastFilesTable(void);
bool createTemporaryLastFilesTableIndex(void);
@ -225,6 +226,7 @@ public:
CondString getRestoreIdentity(int64 restore_id, int clientid);
void setRestoreDone(int success, int64 restore_id);
SFileBackupInfo getFileBackupInfo(int backupid);
void setVirtualMainClient(const std::wstring& virtualmain, int64 clientid);
//@-SQLGenFunctionsEnd
int64 addFileEntryExternal(int backupid, const std::wstring& fullpath, const std::wstring& hashpath, const std::string& shahash, int64 filesize, int64 rsize, int clientid, int incremental, int64 next_entry, int64 prev_entry, int pointed_to);
@ -252,6 +254,7 @@ private:
IQuery* q_addToOldBackupfolders;
IQuery* q_getOldBackupfolders;
IQuery* q_getDeletePendingClientNames;
IQuery* q_getVirtualMainClientname;
IQuery* q_createTemporaryLastFilesTable;
IQuery* q_dropTemporaryLastFilesTable;
IQuery* q_createTemporaryLastFilesTableIndex;
@ -324,6 +327,7 @@ private:
IQuery* q_getRestoreIdentity;
IQuery* q_setRestoreDone;
IQuery* q_getFileBackupInfo;
IQuery* q_setVirtualMainClient;
//@-SQLGenVariablesEnd
IDatabase *db;

View File

@ -1398,6 +1398,17 @@ bool upgrade40_41()
return b;
}
bool upgrade41_42()
{
IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);
bool b = true;
b &= db->Write("ALTER TABLE clients ADD virtualmain TEXT");
return b;
}
void upgrade(void)
{
@ -1420,7 +1431,7 @@ void upgrade(void)
int ver=watoi(res_v[0][L"tvalue"]);
int old_v;
int max_v=41;
int max_v=42;
{
IScopedLock lock(startup_status.mutex);
startup_status.target_db_version=max_v;
@ -1637,6 +1648,12 @@ void upgrade(void)
has_error=true;
}
++ver;
case 41:
if(!upgrade41_42())
{
has_error=true;
}
++ver;
default:
break;
}

View File

@ -15,9 +15,6 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
#ifndef CLIENT_ONLY
#include "server.h"
#include "../Interface/Server.h"
#include "../Interface/Database.h"
@ -46,6 +43,8 @@ bool BackupServer::filesystem_transactions_enabled = false;
volatile bool BackupServer::update_delete_pending_clients=true;
IMutex* BackupServer::force_offline_mutex=NULL;
std::vector<std::wstring> BackupServer::force_offline_clients;
std::map<std::wstring, std::vector<std::wstring> > BackupServer::virtual_clients;
IMutex* BackupServer::virtual_clients_mutex=NULL;
BackupServer::BackupServer(IPipe *pExitpipe)
@ -54,6 +53,7 @@ BackupServer::BackupServer(IPipe *pExitpipe)
throttle_mutex=Server->createMutex();
exitpipe=pExitpipe;
force_offline_mutex=Server->createMutex();
virtual_clients_mutex=Server->createMutex();
if(Server->getServerParameter("internet_only_mode")=="true")
internet_only_mode=true;
@ -65,6 +65,7 @@ BackupServer::~BackupServer()
{
Server->destroy(throttle_mutex);
Server->destroy(force_offline_mutex);
Server->destroy(virtual_clients_mutex);
}
void BackupServer::operator()(void)
@ -218,59 +219,116 @@ void BackupServer::findClients(FileClient &fc)
}
}
namespace
{
struct SClientInfo
{
explicit SClientInfo(std::wstring name)
: name(name), internetclient(false), delete_pending(false),
filebackup_group_offset(0)
{
}
SClientInfo() :
internetclient(false), delete_pending(false),
filebackup_group_offset(0)
{
}
bool operator==(const SClientInfo& other) const
{
return name==other.name;
}
std::wstring name;
std::wstring subname;
std::wstring mainname;
sockaddr_in addr;
std::string endpoint_name;
bool internetclient;
bool delete_pending;
int filebackup_group_offset;
};
}
void BackupServer::startClients(FileClient &fc)
{
std::vector<std::wstring> names;
std::vector<sockaddr_in> servers;
std::vector<std::string> endpoint_names;
std::vector<SClientInfo> client_info;
if(!internet_only_mode)
{
names=fc.getServerNames();
servers=fc.getServers();
std::vector<std::wstring> names=fc.getServerNames();
std::vector<sockaddr_in> servers=fc.getServers();
client_info.resize(servers.size());
for(size_t i=0;i<names.size();++i)
{
client_info[i].name = names[i];
client_info[i].addr = servers[i];
}
}
endpoint_names.resize(servers.size());
maybeUpdateExistingClientsLower();
for(size_t i=0;i<names.size();++i)
{
names[i]=Server->ConvertToUnicode(conv_filename(Server->ConvertToUTF8(names[i])));
fixClientnameCase(names[i]);
}
std::vector<bool> inetclient;
inetclient.resize(names.size());
std::fill(inetclient.begin(), inetclient.end(), false);
std::vector<std::pair<std::string, std::string> > anames=InternetServiceConnector::getOnlineClients();
for(size_t i=0;i<anames.size();++i)
{
std::wstring new_name=Server->ConvertToUnicode(conv_filename(anames[i].first));
bool skip=false;
for(size_t j=0;j<names.size();++j)
std::wstring new_name = Server->ConvertToUnicode(anames[i].first);
if(std::find(client_info.begin(), client_info.end(), SClientInfo(new_name))!=client_info.end())
{
if( new_name==names[j] )
{
skip=true;
break;
}
}
if(skip)
continue;
}
fixClientnameCase(new_name);
names.push_back(new_name);
inetclient.push_back(true);
sockaddr_in n;
memset(&n, 0, sizeof(sockaddr_in));
servers.push_back(n);
endpoint_names.push_back(anames[i].second);
SClientInfo new_client;
new_client.name = new_name;
memset(&(new_client.addr), 0, sizeof(sockaddr_in));
new_client.endpoint_name = anames[i].second;
new_client.internetclient = true;
client_info.push_back(new_client);
}
for(size_t i=0;i<client_info.size();++i)
{
client_info[i].name=Server->ConvertToUnicode(conv_filename(Server->ConvertToUTF8(client_info[i].name)));
fixClientnameCase(client_info[i].name);
client_info[i].mainname=client_info[i].name;
}
{
IScopedLock lock(virtual_clients_mutex);
for(size_t i=0,size=client_info.size();i<size;++i)
{
std::map<std::wstring, std::vector<std::wstring> >::iterator it=virtual_clients.find(client_info[i].name);
if(it!=virtual_clients.end())
{
for(size_t j=0;j<it->second.size();++j)
{
std::wstring new_name = client_info[i].name+L"["+it->second[j]+L"]";
new_name = Server->ConvertToUnicode(conv_filename(Server->ConvertToUTF8(new_name)));
fixClientnameCase(new_name);
SClientInfo new_client = client_info[i];
new_client.name = new_name;
new_client.mainname = client_info[i].name;
new_client.subname = it->second[j];
new_client.filebackup_group_offset = static_cast<int>((j+1)*c_group_size);
client_info.push_back(new_client);
}
}
}
}
std::vector<bool> delete_pending_curr;
delete_pending_curr.resize(names.size());
maybeUpdateDeletePendingClients();
std::vector<std::wstring> local_force_offline_clients;
@ -279,20 +337,23 @@ void BackupServer::startClients(FileClient &fc)
local_force_offline_clients = force_offline_clients;
}
for(size_t i=0;i<names.size();++i)
for(size_t i=0;i<client_info.size();++i)
{
delete_pending_curr[i]=isDeletePendingClient(names[i]);
delete_pending_curr[i] = delete_pending_curr[i] ||
std::find(local_force_offline_clients.begin(), local_force_offline_clients.end(), names[i]) != local_force_offline_clients.end();
SClientInfo& curr_info = client_info[i];
curr_info.delete_pending=isDeletePendingClient(curr_info.name);
curr_info.delete_pending = curr_info.delete_pending ||
std::find(local_force_offline_clients.begin(), local_force_offline_clients.end(), curr_info.name) != local_force_offline_clients.end();
if(delete_pending_curr[i])
if(curr_info.delete_pending)
{
continue;
}
std::map<std::wstring, SClient>::iterator it=clients.find(names[i]);
std::map<std::wstring, SClient>::iterator it=clients.find(curr_info.name);
if( it==clients.end() )
{
Server->Log(L"New Backupclient: "+names[i]);
ServerStatus::setOnline(names[i], true);
Server->Log(L"New Backupclient: "+curr_info.name);
ServerStatus::setOnline(curr_info.name, true);
IPipe *np=Server->createMemoryPipe();
update_existing_client_names=true;
@ -302,44 +363,46 @@ void BackupServer::startClients(FileClient &fc)
if(snapshots_enabled)
use_reflink=true;
#endif
ClientMain *client=new ClientMain(np, servers[i], names[i], inetclient[i], snapshots_enabled, use_reflink);
ClientMain *client=new ClientMain(np, curr_info.addr, curr_info.name, curr_info.subname, curr_info.mainname,
curr_info.filebackup_group_offset, curr_info.internetclient, snapshots_enabled, use_reflink);
Server->getThreadPool()->execute(client);
SClient c;
c.pipe=np;
c.offlinecount=0;
c.addr=servers[i];
c.internet_connection=inetclient[i];
c.addr=curr_info.addr;
c.internet_connection=curr_info.internetclient;
if(c.internet_connection)
{
ServerStatus::setIP(names[i], inet_addr(endpoint_names[i].c_str()));
ServerStatus::setIP(curr_info.name, inet_addr(curr_info.endpoint_name.c_str()));
}
else
{
ServerStatus::setIP(names[i], c.addr.sin_addr.s_addr);
ServerStatus::setIP(curr_info.name, c.addr.sin_addr.s_addr);
}
clients.insert(std::pair<std::wstring, SClient>(names[i], c) );
clients.insert(std::pair<std::wstring, SClient>(curr_info.name, c) );
}
else if(it->second.offlinecount<max_offline)
{
bool found_lan=false;
if(inetclient[i]==false && it->second.internet_connection==true)
if(!curr_info.internetclient && it->second.internet_connection)
{
found_lan=true;
}
if(it->second.addr.sin_addr.s_addr==servers[i].sin_addr.s_addr && !found_lan)
if(it->second.addr.sin_addr.s_addr==curr_info.addr.sin_addr.s_addr && !found_lan)
{
it->second.offlinecount=0;
}
else
{
bool none_fits=true;
for(size_t j=0;j<names.size();++j)
for(size_t j=0;j<client_info.size();++j)
{
if(i!=j && names[j]==names[i] && it->second.addr.sin_addr.s_addr==servers[j].sin_addr.s_addr)
if(i!=j && client_info[j].name==curr_info.name
&& it->second.addr.sin_addr.s_addr==client_info[j].addr.sin_addr.s_addr)
{
none_fits=false;
break;
@ -347,28 +410,23 @@ void BackupServer::startClients(FileClient &fc)
}
if(none_fits || found_lan)
{
it->second.addr=servers[i];
it->second.internet_connection=inetclient[i];
it->second.addr=curr_info.addr;
it->second.internet_connection=curr_info.internetclient;
std::string msg;
msg.resize(7+sizeof(sockaddr_in)+1);
msg[0]='a'; msg[1]='d'; msg[2]='d'; msg[3]='r'; msg[4]='e'; msg[5]='s'; msg[6]='s';
memcpy(&msg[7], &it->second.addr, sizeof(sockaddr_in));
msg[7+sizeof(sockaddr_in)]=(inetclient[i]==true?1:0);
msg[7+sizeof(sockaddr_in)]=(curr_info.internetclient?1:0);
it->second.pipe->Write(msg);
char *ip=(char*)&it->second.addr.sin_addr.s_addr;
Server->Log("New client address: "+nconvert((unsigned char)ip[0])+"."+nconvert((unsigned char)ip[1])+"."+nconvert((unsigned char)ip[2])+"."+nconvert((unsigned char)ip[3]), LL_INFO);
ServerStatus::setIP(names[i], it->second.addr.sin_addr.s_addr);
ServerStatus::setIP(curr_info.name, it->second.addr.sin_addr.s_addr);
it->second.offlinecount=0;
}
/*else if(found_lan)
{
force_offline_clients.push_back(names[i]);
it->second.offlinecount=max_offline;
}*/
}
}
}
@ -383,12 +441,12 @@ void BackupServer::startClients(FileClient &fc)
for(std::map<std::wstring, SClient>::iterator it=clients.begin();it!=clients.end();++it)
{
bool found=false;
for(size_t i=0;i<names.size();++i)
for(size_t i=0;i<client_info.size();++i)
{
if(delete_pending_curr[i])
if(client_info[i].delete_pending)
continue;
if( it->first==names[i] )
if( it->first==client_info[i].name )
{
found=true;
break;
@ -420,6 +478,16 @@ void BackupServer::startClients(FileClient &fc)
ServerStatus::removeStatus(it->first);
Server->destroy(it->second.pipe);
{
IScopedLock lock(virtual_clients_mutex);
std::map<std::wstring, std::vector<std::wstring> >::iterator virt_it=virtual_clients.find(it->first);
if(virt_it!=virtual_clients.end())
{
virtual_clients.erase(virt_it);
}
}
IScopedLock lock(force_offline_mutex);
std::vector<std::wstring>::iterator off_iter = std::find(force_offline_clients.begin(),
force_offline_clients.end(),
@ -718,5 +786,13 @@ void BackupServer::fixClientnameCase( std::wstring& clientname )
}
}
}
#endif //CLIENT_ONLY
void BackupServer::setVirtualClients( const std::wstring& clientname, const std::wstring& new_virtual_clients )
{
std::vector<std::wstring> toks;
TokenizeMail(new_virtual_clients, toks, L"|");
IScopedLock lock(virtual_clients_mutex);
virtual_clients[clientname] = toks;
}

View File

@ -42,6 +42,8 @@ public:
static void forceOfflineClient(const std::wstring& clientname);
static void setVirtualClients(const std::wstring& clientname, const std::wstring& virtual_clients);
private:
void findClients(FileClient &fc);
void startClients(FileClient &fc);
@ -77,6 +79,9 @@ private:
static IMutex* force_offline_mutex;
static std::vector<std::wstring> force_offline_clients;
static IMutex* virtual_clients_mutex;
static std::map<std::wstring, std::vector<std::wstring> > virtual_clients;
};
#endif //URB_SERVER_H

View File

@ -395,6 +395,8 @@ void ServerSettings::readSettingsClient(void)
std::wstring swtmp=settings_client->getValue(L"computername", L"");
if(!swtmp.empty())
settings->computername=swtmp;
if(settings_client->getValue(L"virtual_clients", &swtmp))
settings->virtual_clients=swtmp;
if(settings_client->getValue(L"exclude_files", &swtmp))
settings->exclude_files=swtmp;
if(settings_client->getValue(L"include_files", &swtmp))

View File

@ -51,6 +51,7 @@ struct SSettings
std::string backup_window_incr_image;
std::string backup_window_full_image;
std::wstring computername;
std::wstring virtual_clients;
std::wstring exclude_files;
std::wstring include_files;
std::wstring default_dirs;

View File

@ -358,6 +358,27 @@ void ServerStatus::setClientId( const std::wstring &clientname, int clientid)
SStatus *s=&status[clientname];
s->clientid = clientid;
}
void ServerStatus::addRunningJob( const std::wstring &clientname )
{
IScopedLock lock(mutex);
SStatus *s=&status[clientname];
s->running_jobs+=1;
}
void ServerStatus::subRunningJob( const std::wstring &clientname )
{
IScopedLock lock(mutex);
SStatus *s=&status[clientname];
s->running_jobs-=1;
}
int ServerStatus::numRunningJobs( const std::wstring &clientname )
{
IScopedLock lock(mutex);
SStatus *s=&status[clientname];
return s->running_jobs;
}
ACTION_IMPL(server_status)
{

View File

@ -62,7 +62,7 @@ struct SProcess
struct SStatus
{
SStatus(void){ online=false; has_status=false;r_online=false; clientid=0;
comm_pipe=NULL; status_error=se_none; ; }
comm_pipe=NULL; status_error=se_none; running_jobs=0; }
std::wstring client;
int clientid;
@ -75,6 +75,7 @@ struct SStatus
std::string client_version_string;
std::string os_version_string;
std::vector<SProcess> processes;
int running_jobs;
};
class ServerStatus
@ -131,6 +132,12 @@ public:
static void setProcessPcDone(const std::wstring &clientname, size_t id,
int pcdone);
static void addRunningJob(const std::wstring &clientname);
static void subRunningJob(const std::wstring &clientname);
static int numRunningJobs(const std::wstring &clientname);
static SProcess getProcess(const std::wstring &clientname, size_t id);
private:

View File

@ -111,6 +111,7 @@ JSON::Object getJSONClientSettings(ServerSettings &settings)
SET_SETTING(backup_window_incr_image);
SET_SETTING(backup_window_full_image);
SET_SETTING(computername);
SET_SETTING(virtual_clients);
SET_SETTING(exclude_files);
SET_SETTING(include_files);
SET_SETTING(default_dirs);
@ -772,6 +773,7 @@ ACTION_IMPL(settings)
s=getClientSettings(db, t_clientid);
obj.set("overwrite", s.overwrite);
obj.set("clientid", t_clientid);
obj.set("main_client", backupdao.getVirtualMainClientname(t_clientid).value.empty());
ret.set("cowraw_available", BackupServer::isSnapshotsEnabled());
ret.set("settings", obj);

View File

@ -222,7 +222,8 @@ ACTION_IMPL(status)
{
for(size_t i=0;i<remove_client.size();++i)
{
IQuery *q=db->Prepare("UPDATE clients SET delete_pending=1 WHERE id=?");
IQuery *q=db->Prepare("UPDATE clients SET delete_pending=1 WHERE id=? OR virtualmain = (SELECT name FROM clients WHERE id=?)");
q->Bind(remove_client[i]);
q->Bind(remove_client[i]);
q->Write();
q->Reset();

File diff suppressed because one or more lines are too long

View File

@ -1809,6 +1809,8 @@ function show_settings2(data)
data.settings.global_settings_start="";
data.settings.global_settings_end="";
data.settings.main_client = true;
data.settings.client_plural="s";
data.settings.ONLY_WIN32_BEGIN=unescapeHTML(data.settings.ONLY_WIN32_BEGIN);
@ -2191,6 +2193,7 @@ g.settings_list=[
"internet_mode_enabled",
"silent_update",
"client_quota",
"virtual_clients",
"end_to_end_file_backup_verification",
"local_full_file_transfer_mode",
"internet_full_file_transfer_mode",

View File

@ -565,7 +565,7 @@ function validate_text_int(a)
{
for(var i=0;i<a.length;++i)
{
if(!isInt(I(a[i]).value))
if(I(a[i]) && !isInt(I(a[i]).value))
{
if(trans("validate_err_notint_"+a[i]))
{

File diff suppressed because one or more lines are too long

View File

@ -162,6 +162,7 @@
</div>
</div>
{?main_client}
<div class="tab-pane" id="permissions">
<div class="panel panel-default">
<div class="panel-body">
@ -224,11 +225,13 @@
</div>
</div>
</div>
{/main_client}
<div class="tab-pane" id="client">
<div class="panel panel-default">
<div class="panel-body">
<form class="form-horizontal" role="form">
{?main_client}
<div class="form-group">
<label class="col-sm-4 control-label" for="startup_backup_delay">{tDelay after system startup}:</label>
<div class="col-sm-6">
@ -238,6 +241,7 @@
</div>
</div>
</div>
{/main_client}
<div class="form-group">
<label class="col-sm-4 control-label">{tBackup window}</label>
<div class="col-sm-6">
@ -283,14 +287,16 @@
</div>
</div>
</div>
{?main_client}
{no_compname_start|s}
<div class="form-group">
<label class="col-sm-4 control-label" for="computername">{tComputer name}</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="computername" value="{computername|s}"/>
<input type="text" class="form-control" id="computername" value="{computername}"/>
</div>
</div>
{no_compname_end|s}
{/main_client}
<div class="form-group">
<label class="col-sm-4 control-label" for="local_speed">{tMax backup speed for local network}:</label>
<div class="col-sm-6">
@ -300,18 +306,30 @@
</div>
</div>
</div>
{?main_client}
<div class="form-group">
<label class="col-sm-4 control-label" for="silent_update">{tPerform autoupdates silently}:</label>
<div class="col-sm-6">
<label><input type="checkbox" id="silent_update" {silent_update}/></label>
</div>
</div>
{/main_client}
<div class="form-group">
<label class="col-sm-4 control-label" for="client_quota">{tSoft client quota}:</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="client_quota" value="{client_quota}"/>
</div>
</div>
{?main_client}
{no_compname_start|s}
<div class="form-group">
<label class="col-sm-4 control-label" for="virtual_clients">{tVirtual sub client names}</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="virtual_clients" value="{virtual_clients}"/>
</div>
</div>
{no_compname_end|s}
{/main_client}
</form>
</div>
</div>
@ -399,6 +417,7 @@
</div>
</div>
{global_settings_end_inet|s}
{?main_client}
{no_compname_start_inet|s}
<div class="form-group">
<label class="col-sm-4 control-label" for="internet_mode_enabled">{tEnable internet mode}:</label>
@ -413,6 +432,7 @@
</div>
</div>
{no_compname_end_inet|s}
{/main_client}
<div class="form-group">
<label class="col-sm-4 control-label" for="internet_image_backups">{tDo image backups over internet}:</label>
<div class="col-sm-6">
@ -445,6 +465,7 @@
</div>
</div>
{global_settings_end_inet|s}
{?main_client}
<div class="form-group">
<label class="col-sm-4 control-label" for="internet_encrypt">{tEncrypted transfer}:</label>
<div class="col-sm-6">
@ -457,18 +478,21 @@
<label><input type="checkbox" id="internet_compress" value="false" {internet_compress}/></label>
</div>
</div>
{/main_client}
<div class="form-group">
<label class="col-sm-4 control-label" for="internet_calculate_filehashes_on_client">{tCalculate file-hashes on the client}:</label>
<div class="col-sm-6">
<label><input type="checkbox" id="internet_calculate_filehashes_on_client" value="false" {internet_calculate_filehashes_on_client}/></label>
</div>
</div>
{?main_client}
<div class="form-group">
<label class="col-sm-4 control-label" for="internet_connect_always">{tConnect to Internet backup server if connected to local backup server}:</label>
<div class="col-sm-6">
<label><input type="checkbox" id="internet_connect_always" value="false" {internet_connect_always}/></label>
</div>
</div>
{/main_client}
</form>
</div>
</div>
@ -582,10 +606,6 @@
<div class="col-sm-6">
<label><input type="checkbox" id="end_to_end_file_backup_verification" value="false" {end_to_end_file_backup_verification}/></label>
</div>
<tr>
<td>{tFollow symbolic links on Linux}:</td>
<td><input type="checkbox" id="follow_symlinks" value="true" {follow_symlinks}/></td>
</tr>
</div>
<div class="form-group">
<label class="col-sm-4 control-label" for="verify_using_client_hashes">{tVerify file backups using client side hashes}:</label>

View File

@ -11,7 +11,9 @@
<ul class="nav nav-pills" id="settings_tabber" data-tabs="tabs">
<li class="active"><a href="#file_backups" data-toggle="tab">{tFile Backups}</a></li>
<li><a href="#image_backups" data-toggle="tab">{tImage Backups}</a></li>
{?main_client}
<li><a href="#permissions" data-toggle="tab">{tPermissions}</a></li>
{/main_client}
<li><a href="#client" data-toggle="tab">{tClient}</a></li>
<li><a href="#archive" data-toggle="tab">{tArchive}</a></li>
{internet_settings_start|s}