/************************************************************************* * UrBackup - Client/Server backup system * Copyright (C) 2011 Martin Raiber * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . **************************************************************************/ #include "ClientService.h" #include "client.h" #include "../Interface/Server.h" #include "../Interface/Database.h" #include "../Interface/Query.h" #include "../Interface/SettingsReader.h" #include "../Interface/File.h" #include "../Interface/ThreadPool.h" #include "../stringtools.h" #include "escape.h" #include "database.h" #include "fileclient/data.h" #include "../fsimageplugin/IFSImageFactory.h" #include "../fsimageplugin/IFilesystem.h" #include "../cryptoplugin/ICryptoFactory.h" #include "sha2/sha2.h" #include "ClientSend.h" #include "ServerIdentityMgr.h" #include "settings.h" #include #include #ifndef _WIN32 #define _atoi64 atoll #endif extern IFSImageFactory *image_fak; extern ICryptoFactory *crypto_fak; extern unsigned char *zero_hash; ICustomClient* ClientService::createClient() { return new ClientConnector(); } void ClientService::destroyClient( ICustomClient * pClient) { delete ((ClientConnector*)pClient); } int ClientConnector::backup_running=0; volatile bool ClientConnector::backup_done=false; IMutex *ClientConnector::backup_mutex=NULL; unsigned int ClientConnector::incr_update_intervall=0; unsigned int ClientConnector::last_pingtime=0; IPipe *ClientConnector::channel_pipe=NULL; unsigned int ClientConnector::last_channel_ping=0; int ClientConnector::pcdone=0; int ClientConnector::pcdone2=0; std::vector ClientConnector::channel_pipes; std::vector ClientConnector::channel_exit; std::vector ClientConnector::channel_ping; IMutex *ClientConnector::progress_mutex=NULL; volatile bool ClientConnector::img_download_running=false; void ClientConnector::init_mutex(void) { if(backup_mutex==NULL) { backup_mutex=Server->createMutex(); progress_mutex=Server->createMutex(); } } bool ClientConnector::wantReceive(void) { return want_receive; } void ClientConnector::Init(THREAD_ID pTID, IPipe *pPipe) { tid=pTID; pipe=pPipe; state=0; thread_action=0; mempipe=Server->createMemoryPipe(); lasttime=Server->getTimeMS(); do_quit=false; is_channel=false; lcmd="none"; want_receive=true; } ClientConnector::~ClientConnector(void) { mempipe->Write("exit"); } bool ClientConnector::Run(void) { if(do_quit) { if(is_channel) { IScopedLock lock(backup_mutex); if(channel_pipe==pipe) { channel_pipe=NULL; } for(size_t i=0;iwait(10); do_quit=true; return true; } return false; } switch(state) { case 0: if(Server->getTimeMS()-lasttime>10000) { Server->Log("Client timeout in ClientConnector::Run lcmd="+lcmd, LL_DEBUG); if(waitForThread()) { do_quit=true; return true; } return false; } return true; case 1: { std::string msg; mempipe->Read(&msg, 0); if(msg=="exit") { mempipe->Write(msg); if(waitForThread()) { do_quit=true; return true; } return false; } else if(msg=="done") { tcpstack.Send(pipe, "DONE"); lasttime=Server->getTimeMS(); state=0; } else if(!msg.empty()) { tcpstack.Send(pipe, msg); lasttime=Server->getTimeMS(); state=0; } }break; case 2: { std::string msg; mempipe->Read(&msg, 0); if(msg=="exit") { mempipe->Write(msg); if(waitForThread()) { do_quit=true; return true; } return false; } else if(msg.find("done")==0) { tcpstack.Send(pipe, "DONE"); lasttime=Server->getTimeMS(); state=0; } else if(msg.find("failed")==0) { tcpstack.Send(pipe, "FAILED"); lasttime=Server->getTimeMS(); state=0; } }break; case 3: //Channel { IScopedLock lock(backup_mutex); if(Server->getTimeMS()-lasttime>180000) { Server->Log("Client timeout in ClientConnector::Run - Channel", LL_DEBUG); { if(channel_pipe==pipe) channel_pipe=NULL; for(size_t i=0;iLog("Channel got replaced.", LL_DEBUG); if(waitForThread()) { do_quit=true; return true; } return false; }*/ for(size_t i=0;igetTimeMS()-last_channel_ping>60000) { channel_ping.push_back(pipe); tcpstack.Send(pipe, "PING"); last_channel_ping=Server->getTimeMS(); for(size_t i=0;igetThreadPool()->isRunning(thread_ticket)==false ) { return false; } }break; case 6: case 7: { if(Server->getTimeMS()-lasttime>10000) { Server->Log("Client timeout in ClientConnector::Run-update(state6|7)", LL_DEBUG); if(waitForThread()) { do_quit=true; return true; } return false; } if(state==7) { if(hashdataok) { hashdatafile->Seek(0); writeUpdateFile(hashdatafile, "version_new.txt"); writeUpdateFile(hashdatafile, "UrBackupUpdate.sig"); writeUpdateFile(hashdatafile, "UrBackupUpdate_untested.exe"); if(crypto_fak!=NULL) { IFile *updatefile=Server->openFile("UrBackupUpdate_untested.exe"); if(updatefile!=NULL) { if(checkHash(getSha512Hash(updatefile))) { Server->destroy(updatefile); if(crypto_fak->verifyFile("urbackup_dsa.pub", "UrBackupUpdate_untested.exe", "UrBackupUpdate.sig")) { Server->deleteFile("version.txt"); Server->deleteFile("UrBackupUpdate.exe"); moveFile(L"UrBackupUpdate_untested.exe", L"UrBackupUpdate.exe"); moveFile(L"version_new.txt", L"version.txt"); tcpstack.Send(pipe, "ok"); } else { Server->Log("Verifying update file failed. Signature did not match", LL_ERROR); tcpstack.Send(pipe, "verify_sig_err"); } } else { Server->destroy(updatefile); Server->Log("Verifing update file failed. Update was installed previously", LL_ERROR); tcpstack.Send(pipe, "verify_sig_already_used_err"); } } } else { Server->Log("Verifing update file failed. Cryptomodule not present", LL_ERROR); tcpstack.Send(pipe, "verify_cryptmodule_err"); } } else { do_quit=true; } } return true; }break; case 8: // wait for contractors { for(size_t i=0;iRead(&resp, 0); if(!resp.empty()) { contractors[i]->Write("exit"); contractors.erase(contractors.begin()+i); break; } } if(contractors.empty()) { return false; } }break; } return true; } std::string ClientConnector::getSha512Hash(IFile *fn) { sha512_ctx ctx; char buf[4096]; _u32 r; sha512_init(&ctx); while((r=fn->Read(buf, 4096))!=0) { sha512_update(&ctx, (unsigned char*)buf, r); } unsigned char digest[64]; sha512_final(&ctx,digest); return bytesToHex(digest, 64); } bool ClientConnector::checkHash(std::string shah) { std::string prev_h=getFile("updates_h.dat"); int lc=linecount(prev_h); for(int i=0;iRead((char*)&size, sizeof(unsigned int))!=sizeof(unsigned int)) return false; IFile *out=Server->openFile(outfn, MODE_WRITE); size_t read=0; char buf[4096]; while(true) { size_t tr=(std::min)((size_t)4096, size-read); if(tr==0) break; if(datafile->Read(buf, (_u32)tr)!=tr) { Server->destroy(out); return false; } if(out->Write(buf, (_u32)tr)!=tr) { Server->destroy(out); return false; } read+=tr; } Server->destroy(out); return true; } void ClientConnector::ReceivePackets(void) { if(state==8) { return; } IMutex *l_mutex=NULL; if(is_channel) { l_mutex=backup_mutex; } IScopedLock g_lock(l_mutex); std::string cmd; size_t rc=pipe->Read(&cmd, is_channel?0:-1); if(rc==0 ) { Server->Log("rc=0 hasError="+nconvert(pipe->hasError())+" state="+nconvert(state), LL_DEBUG); if(is_channel && pipe->hasError()) { do_quit=true; } else if(!is_channel) { do_quit=true; } else { lasttime=Server->getTimeMS(); } return; } lcmd=cmd; if(state==5 || state==6) { lasttime=Server->getTimeMS(); if(hashdatafile->Write(cmd)!=cmd.size()) { Server->Log("Error writing to hashdata temporary file", LL_ERROR); do_quit=true; return; } if(hashdataleft>=cmd.size()) { hashdataleft-=(_u32)cmd.size(); Server->Log("Hashdataleft: "+nconvert(hashdataleft), LL_DEBUG); } else { Server->Log("Too much hashdata - error", LL_ERROR); } if(hashdataleft==0) { hashdataok=true; if(state==5) state=4; else if(state==6) state=7; return; } } tcpstack.AddData((char*)cmd.c_str(), cmd.size()); size_t packetsize; char *ccstr; while( (ccstr=tcpstack.getPacket(&packetsize))!=NULL) { cmd.resize(packetsize); if(packetsize>0) { memcpy(&cmd[0], ccstr, packetsize); } delete [] ccstr; Server->Log("ClientService cmd: "+cmd, LL_DEBUG); bool pw_ok=false; std::string identity; bool ident_ok=false; str_map params; size_t hashpos; if(cmd.size()>3 && cmd[0]=='#' && cmd[1]=='I' ) { identity=getbetween("#I", "#", cmd); cmd.erase(0, identity.size()+3); } else if((hashpos=cmd.find("#"))!=std::string::npos) { ParseParamStr(getafter("#", cmd), ¶ms); cmd.erase(hashpos, cmd.size()-hashpos); if(!checkPassword(params[L"pw"])) { Server->Log("Password wrong!", LL_ERROR); break; } else { pw_ok=true; } } if(!identity.empty() && ServerIdentityMgr::checkServerIdentity(identity)==true) { ident_ok=true; } if(cmd=="ADD IDENTITY") { if(identity.empty()) { tcpstack.Send(pipe, "Identity empty"); } else { if(Server->getServerParameter("restore_mode")=="true" && !ident_ok ) { ServerIdentityMgr::addServerIdentity(identity); tcpstack.Send(pipe, "OK"); } else if( ident_ok ) { tcpstack.Send(pipe, "OK"); } else { if( ServerIdentityMgr::numServerIdentities()==0 ) { ServerIdentityMgr::addServerIdentity(identity); tcpstack.Send(pipe, "OK"); } else { tcpstack.Send(pipe, "failed"); } } } } else if(cmd=="START BACKUP" && ident_ok==true) { state=1; const size_t bsize=sizeof(char)+sizeof(IPipe*); char buffer[bsize]; buffer[0]=0; memcpy(&buffer[1], &mempipe, sizeof(IPipe*)); IndexThread::getMsgPipe()->Write(buffer, bsize); lasttime=Server->getTimeMS(); IScopedLock lock(backup_mutex); backup_running=1; last_pingtime=0; pcdone=0; } else if(cmd=="START FULL BACKUP" && ident_ok==true) { state=1; const size_t bsize=sizeof(char)+sizeof(IPipe*); char buffer[bsize]; buffer[0]=1; memcpy(&buffer[1], &mempipe, sizeof(IPipe*)); IndexThread::getMsgPipe()->Write(buffer, bsize); lasttime=Server->getTimeMS(); IScopedLock lock(backup_mutex); backup_running=2; last_pingtime=0; pcdone=0; } else if(cmd.find("START SC \"")!=std::string::npos && ident_ok==true) { if(cmd[cmd.size()-1]=='"') { state=2; std::string dir=cmd.substr(10, cmd.size()-11); CWData data; data.addChar(2); data.addVoidPtr(mempipe); data.addString(dir); IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize()); lasttime=Server->getTimeMS(); } else { Server->Log("Invalid command", LL_ERROR); } } else if(cmd.find("STOP SC \"")!=std::string::npos && ident_ok==true) { if(cmd[cmd.size()-1]=='"') { state=2; std::string dir=cmd.substr(9, cmd.size()-10); CWData data; data.addChar(3); data.addVoidPtr(mempipe); data.addString(dir); IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize()); lasttime=Server->getTimeMS(); } else { Server->Log("Invalid command", LL_ERROR); } } else if(cmd.find("INCRINTERVALL \"")!=std::string::npos && ident_ok==true) { if(cmd[cmd.size()-1]=='"') { std::string intervall=cmd.substr(15, cmd.size()-16); incr_update_intervall=atoi(intervall.c_str()); tcpstack.Send(pipe, "OK"); lasttime=Server->getTimeMS(); } else { Server->Log("Invalid command", LL_ERROR); } } else if(cmd.find("GET BACKUP DIRS")==0 && pw_ok==true) { getBackupDirs(); lasttime=Server->getTimeMS(); } else if(cmd.find("SAVE BACKUP DIRS")==0 && pw_ok==true) { if(saveBackupDirs(params)) { tcpstack.Send(pipe, "OK"); } lasttime=Server->getTimeMS(); } else if(cmd.find("GET INCRINTERVALL")==0 && pw_ok==true) { if(incr_update_intervall==0 ) { tcpstack.Send(pipe, nconvert(0)); } else { tcpstack.Send(pipe, nconvert(incr_update_intervall+10*60) ); } lasttime=Server->getTimeMS(); } else if(cmd=="DID BACKUP" && ident_ok==true) { updateLastBackup(); tcpstack.Send(pipe, "OK"); IScopedLock lock(backup_mutex); if(backup_running==1 || backup_running==2) { backup_running=0; backup_done=true; } lasttime=Server->getTimeMS(); } else if(cmd.find("STATUS")==0 && pw_ok==true) { getBackupStatus(); lasttime=Server->getTimeMS(); } else if(cmd.find("SETTINGS ")==0 && ident_ok==true) { std::string s_settings=cmd.substr(9); unescapeMessage(s_settings); updateSettings( s_settings ); tcpstack.Send(pipe, "OK"); lasttime=Server->getTimeMS(); } else if(cmd.find("PING RUNNING")==0 && ident_ok==true) { last_pingtime=Server->getTimeMS(); tcpstack.Send(pipe, "OK"); lasttime=Server->getTimeMS(); IScopedLock lock(backup_mutex); pcdone=atoi(getbetween("-","-", cmd).c_str()); } else if(cmd=="CHANNEL" && ident_ok==true) { if(!img_download_running) { g_lock.relock(backup_mutex); channel_pipe=pipe; channel_pipes.push_back(pipe); is_channel=true; state=3; last_channel_ping=Server->getTimeMS(); lasttime=Server->getTimeMS(); Server->Log("New channel: Number of Channels: "+nconvert((int)channel_pipes.size()), LL_DEBUG); } } else if(cmd=="PONG" && is_channel==true ) { lasttime=Server->getTimeMS(); } else if(cmd=="PING" && is_channel==true ) { lasttime=Server->getTimeMS(); if(tcpstack.Send(pipe, "PONG")==0) { do_quit=true; } } else if(cmd.find("START BACKUP INCR")==0 && pw_ok==true ) { IScopedLock lock(backup_mutex); lasttime=Server->getTimeMS(); if(backup_running!=0) tcpstack.Send(pipe, "RUNNING"); else { bool ok=false; if(channel_pipe!=NULL) { _u32 rc=(_u32)tcpstack.Send(channel_pipe, "START BACKUP INCR"); if(rc!=0) ok=true; } if(!ok) { tcpstack.Send(pipe, "FAILED"); } else { tcpstack.Send(pipe, "OK"); } } } else if(cmd.find("START BACKUP FULL")==0 && pw_ok==true ) { IScopedLock lock(backup_mutex); lasttime=Server->getTimeMS(); if(backup_running!=0) tcpstack.Send(pipe, "RUNNING"); else { bool ok=false; if(channel_pipe!=NULL) { _u32 rc=(_u32)tcpstack.Send(channel_pipe, "START BACKUP FULL"); if(rc!=0) ok=true; } if(!ok) { tcpstack.Send(pipe, "FAILED"); } else { tcpstack.Send(pipe, "OK"); } } } else if(cmd.find("START IMAGE FULL")==0 && pw_ok==true ) { IScopedLock lock(backup_mutex); lasttime=Server->getTimeMS(); if(backup_running!=0) tcpstack.Send(pipe, "RUNNING"); else { bool ok=false; if(channel_pipe!=NULL) { _u32 rc=(_u32)tcpstack.Send(channel_pipe, "START IMAGE FULL"); if(rc!=0) ok=true; } if(!ok) { tcpstack.Send(pipe, "FAILED"); } else { tcpstack.Send(pipe, "OK"); } } } else if(cmd.find("START IMAGE INCR")==0 && pw_ok==true ) { IScopedLock lock(backup_mutex); lasttime=Server->getTimeMS(); if(backup_running!=0) tcpstack.Send(pipe, "RUNNING"); else { bool ok=false; if(channel_pipe!=NULL) { _u32 rc=(_u32)tcpstack.Send(channel_pipe, "START IMAGE INCR"); if(rc!=0) ok=true; } if(!ok) { tcpstack.Send(pipe, "FAILED"); } else { tcpstack.Send(pipe, "OK"); } } } else if(cmd.find("UPDATE SETTINGS ")==0 && pw_ok==true ) { std::string s_settings=cmd.substr(16); lasttime=Server->getTimeMS(); unescapeMessage(s_settings); replaceSettings( s_settings ); IScopedLock lock(backup_mutex); bool ok=false; if(channel_pipe!=NULL) { _u32 rc=(_u32)tcpstack.Send(channel_pipe, "UPDATE SETTINGS"); if(rc!=0) ok=true; } if(!ok) { tcpstack.Send(pipe, "FAILED"); } else { tcpstack.Send(pipe, "OK"); } } else if(cmd.find("2LOGDATA ")==0 && ident_ok==true) { std::string ldata=cmd.substr(9); size_t cpos=ldata.find(" "); std::string created=getuntil(" ", ldata); lasttime=Server->getTimeMS(); saveLogdata(created, getafter(" ",ldata)); tcpstack.Send(pipe, "OK"); } else if(cmd.find("PAUSE ")==0 && pw_ok==true) { lasttime=Server->getTimeMS(); std::string b=cmd.substr(6); bool ok=false; if(b=="true") { ok=true; IdleCheckerThread::setPause(true); IndexThread::getFileSrv()->setPause(true); } else if(b=="false") { ok=true; IdleCheckerThread::setPause(false); IndexThread::getFileSrv()->setPause(false); } if(ok) tcpstack.Send(pipe, "OK"); else tcpstack.Send(pipe, "FAILED"); } else if(cmd.find("GET LOGPOINTS")==0 && pw_ok==true) { lasttime=Server->getTimeMS(); tcpstack.Send(pipe, getLogpoints() ); } else if(cmd.find("GET LOGDATA")==0 && pw_ok==true ) { lasttime=Server->getTimeMS(); int logid=watoi(params[L"logid"]); int loglevel=watoi(params[L"loglevel"]); std::string ret; getLogLevel(logid, loglevel, ret); tcpstack.Send(pipe, ret); } else if(cmd.find("FULL IMAGE ")==0) { if(ident_ok==true) { lasttime=Server->getTimeMS(); std::string s_params=cmd.substr(11); str_map params; ParseParamStr(s_params, ¶ms); image_letter=Server->ConvertToUTF8(params[L"letter"]); shadowdrive=Server->ConvertToUTF8(params[L"shadowdrive"]); if(params.find(L"start")!=params.end()) { startpos=(uint64)_atoi64(Server->ConvertToUTF8(params[L"start"]).c_str()); } else { startpos=0; } if(params.find(L"shadowid")!=params.end()) { shadow_id=watoi(params[L"shadowid"]); } else { shadow_id=-1; } if(startpos==0) { CWData data; data.addChar(2); data.addVoidPtr(mempipe); data.addString(image_letter); data.addUChar(0); IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize()); } else if(shadow_id!=-1) { shadowdrive.clear(); CWData data; data.addChar(4); data.addVoidPtr(mempipe); data.addInt(shadow_id); IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize()); } lasttime=Server->getTimeMS(); sendFullImage(); } else { ImageErr("Ident reset (1)"); } } else if(cmd.find("INCR IMAGE ")==0 && ident_ok==true) { if(ident_ok==true) { lasttime=Server->getTimeMS(); std::string s_params=cmd.substr(11); str_map params; ParseParamStr(s_params, ¶ms); str_map::iterator f_hashsize=params.find(L"hashsize"); if(f_hashsize!=params.end()) { hashdataok=false; hashdataleft=watoi(f_hashsize->second); image_letter=Server->ConvertToUTF8(params[L"letter"]); shadowdrive=Server->ConvertToUTF8(params[L"shadowdrive"]); if(params.find(L"start")!=params.end()) { startpos=(uint64)_atoi64(Server->ConvertToUTF8(params[L"start"]).c_str()); } else { startpos=0; } if(params.find(L"shadowid")!=params.end()) { shadow_id=watoi(params[L"shadowid"]); } else { shadow_id=-1; } if(startpos==0) { CWData data; data.addChar(2); data.addVoidPtr(mempipe); data.addString(image_letter); data.addUChar(0); IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize()); } else if(shadow_id!=-1) { shadowdrive.clear(); CWData data; data.addChar(4); data.addVoidPtr(mempipe); data.addInt(shadow_id); IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize()); } hashdatafile=Server->openTemporaryFile(); if(tcpstack.getBuffersize()>0) { if(hashdatafile->Write(tcpstack.getBuffer(), (_u32)tcpstack.getBuffersize())!=tcpstack.getBuffersize()) { Server->Log("Error writing to hashdata temporary file -1", LL_ERROR); do_quit=true; return; } if(hashdataleft>=tcpstack.getBuffersize()) { hashdataleft-=(_u32)tcpstack.getBuffersize(); //Server->Log("Hashdataleft: "+nconvert(hashdataleft), LL_DEBUG); } else { Server->Log("Too much hashdata - error -1", LL_ERROR); } if(hashdataleft==0) { hashdataok=true; state=4; return; } } lasttime=Server->getTimeMS(); sendIncrImage(); } else { ImageErr("Ident reset (2)"); } } } else if( cmd.find("MBR ")==0 && ident_ok==true ) { lasttime=Server->getTimeMS(); std::string s_params=cmd.substr(4); str_map params; ParseParamStr(s_params, ¶ms); std::wstring dl=params[L"driveletter"]; bool b=false; if(!dl.empty()) { b=sendMBR(dl); } if(!b) { CWData r;r.addChar(0); tcpstack.Send(pipe, r); } } else if( cmd.find("GET BACKUPCLIENTS")==0 && pw_ok==true ) { lasttime=Server->getTimeMS(); IScopedLock lock(backup_mutex); waitForPings(&lock); if(channel_pipes.size()==0) { tcpstack.Send(pipe, "0"); } else { std::string clients; for(size_t i=0;igetTimeMS(); IScopedLock lock(backup_mutex); waitForPings(&lock); if(channel_pipes.size()==0) { tcpstack.Send(pipe, "0"); } else { std::string imgs; for(size_t i=0;igetTimeMS(); Server->Log("Downloading image...", LL_DEBUG); IScopedLock lock(backup_mutex); waitForPings(&lock); Server->Log("In mutex...",LL_DEBUG); img_download_running=true; downloadImage(params); img_download_running=false; Server->Log("Donwload done -2", LL_DEBUG); do_quit=true; } else if( cmd.find("GET DOWNLOADPROGRESS")==0 && pw_ok==true) { Server->Log("Sending progress...", LL_DEBUG); lasttime=Server->getTimeMS(); if(img_download_running==false) { pipe->Write("100"); do_quit=true; } else { while(img_download_running) { { int progress=0; { IScopedLock lock(progress_mutex); progress=pcdone; } if(!pipe->Write(nconvert(progress)+"\n", 10000)) { break; } } { Server->wait(1000); } } do_quit=true; } } else if( cmd.find("VERSION ")==0 && ident_ok==true ) { int n_version=atoi(cmd.substr(8).c_str()); std::string version_1=getFile("version.txt"); std::string version_2=getFile("curr_version.txt"); if(version_1.empty() ) version_1="0"; if(version_2.empty() ) version_2="0"; if( atoi(version_1.c_str())openTemporaryFile(); hashdataleft=atoi(cmd.substr(13).c_str()); hashdataok=false; state=6; if(tcpstack.getBuffersize()>0) { if(hashdatafile->Write(tcpstack.getBuffer(), (_u32)tcpstack.getBuffersize())!=tcpstack.getBuffersize()) { Server->Log("Error writing to hashdata temporary file -1update", LL_ERROR); do_quit=true; return; } if(hashdataleft>=tcpstack.getBuffersize()) { hashdataleft-=(_u32)tcpstack.getBuffersize(); //Server->Log("Hashdataleft: "+nconvert(hashdataleft), LL_DEBUG); } else { Server->Log("Too much hashdata - error -1update", LL_ERROR); } if(hashdataleft==0) { hashdataok=true; state=6; return; } } return; } } } bool ClientConnector::checkPassword(const std::wstring &pw) { static std::string stored_pw=getFile("pw.txt"); return stored_pw==Server->ConvertToUTF8(pw); } void ClientConnector::getBackupDirs(void) { IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_CLIENT); IQuery *q=db->Prepare("SELECT id,path FROM backupdirs"); db_results res=q->Read(); std::string msg; for(size_t i=0;iConvertToUTF8(res[i][L"id"])+"\n"; msg+=Server->ConvertToUTF8(res[i][L"path"]); if(i+1destroyAllQueries(); } bool ClientConnector::saveBackupDirs(str_map &args) { IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_CLIENT); db->BeginTransaction(); db_results backupdirs=db->Prepare("SELECT name, path FROM backupdirs")->Read(); db->Prepare("DELETE FROM backupdirs")->Write(); IQuery *q=db->Prepare("INSERT INTO backupdirs (name, path) VALUES (?, ?)"); IQuery *q2=db->Prepare("SELECT id FROM backupdirs WHERE name=?"); std::wstring dir; size_t i=0; std::vector new_watchdirs; do { dir=args[L"dir_"+convert(i)]; if(!dir.empty()) { std::string name=replaceChars( ExtractFileName(wnarrow(dir) ) ); if(name=="urbackup") name="urbackup_1"; if(dir[dir.size()-1]=='\\' || dir[dir.size()-1]=='/' ) dir.erase(dir.size()-1,1); q2->Bind(name); if(q2->Read().empty()==false) { for(int k=0;k<100;++k) { q2->Reset(); q2->Bind(name+"_"+nconvert(k)); if(q2->Read().empty()==true) { name+="_"+nconvert(k); break; } } } q2->Reset(); bool found=false; for(size_t i=0;iBind(name); q->Bind(dir); q->Write(); q->Reset(); } ++i; } while(!dir.empty()); db->EndTransaction(); for(size_t i=0;icreateMemoryPipe(); CWData data; data.addChar(5); data.addVoidPtr(contractor); data.addString(Server->ConvertToUTF8(new_watchdirs[i])); IndexThread::stopIndex(); IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize()); contractors.push_back(contractor); state=8; want_receive=false; } for(size_t i=0;icreateMemoryPipe(); CWData data; data.addChar(6); data.addVoidPtr(contractor); data.addString(Server->ConvertToUTF8(backupdirs[i][L"path"])); IndexThread::stopIndex(); IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize()); contractors.push_back(contractor); state=8; want_receive=false; } } db->destroyAllQueries(); return true; } std::string ClientConnector::replaceChars(std::string in) { char legalchars[] = {'_', '-'}; for(size_t i=0;igetDatabase(Server->getThreadID(), URBACKUPDB_CLIENT); IQuery *q=db->Prepare("UPDATE status SET last_backup=CURRENT_TIMESTAMP WHERE id=1"); IQuery *q2=db->Prepare("SELECT last_backup FROM status WHERE id=1"); if(q!=NULL && q2!=NULL) { if(q2->Read().size()>0) { q->Write(); } else { q=db->Prepare("INSERT INTO status (last_backup, id) VALUES (CURRENT_TIMESTAMP, 1)"); if(q!=NULL) q->Write(); } } db->destroyAllQueries(); } const unsigned int x_pingtimeout=180000; void ClientConnector::getBackupStatus(void) { IScopedLock lock(backup_mutex); IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_CLIENT); IQuery *q=db->Prepare("SELECT strftime('"+time_format_str+"',last_backup, 'localtime') AS last_backup FROM status"); if(q==NULL) return; db_results res=q->Read(); std::string ret; if(res.size()>0) { ret+=Server->ConvertToUTF8(res[0][L"last_backup"]); } if(backup_running==0) { if(backup_done) ret+="#DONE"; else ret+="#NOA"; backup_done=false; } else if(backup_running==1) { if(last_pingtime!=0 && Server->getTimeMS()-last_pingtime>x_pingtimeout ) ret+="#NOA"; else ret+="#INCR"; } else if(backup_running==2) { if(last_pingtime!=0 && Server->getTimeMS()-last_pingtime>x_pingtimeout ) ret+="#NOA"; else ret+="#FULL"; } else if(backup_running==3) { if(last_pingtime!=0 && Server->getTimeMS()-last_pingtime>x_pingtimeout ) ret+="#NOA"; else ret+="#FULLI"; } else if(backup_running==4) { if(last_pingtime!=0 && Server->getTimeMS()-last_pingtime>x_pingtimeout ) ret+="#NOA"; else ret+="#INCRI"; } if(backup_running!=4) ret+="#"+nconvert(pcdone); else ret+="#"+nconvert(pcdone2); if(IdleCheckerThread::getPause()) { ret+="#P"; } else { ret+="#NP"; } tcpstack.Send(pipe, ret); db->destroyAllQueries(); } std::vector getSettingsList(void); void ClientConnector::updateSettings(const std::string &pData) { ISettingsReader *curr_settings=Server->createFileSettingsReader("urbackup/data/settings.cfg"); ISettingsReader *new_settings=Server->createMemorySettingsReader(pData); std::vector settings_names=getSettingsList(); std::wstring toadd=L"\n"; bool mod=false; for(size_t i=0;igetValue(key, &v) ) { std::wstring nv; if(new_settings->getValue(key, &nv) ) { toadd+=key+L"="+nv+L"\n"; mod=true; } } } Server->destroy(curr_settings); Server->destroy(new_settings); if(mod) { IFile *sf=Server->openFile("urbackup/data/settings.cfg", MODE_RW ); if(sf==NULL) { sf=Server->openFile("urbackup/data/settings.cfg", MODE_WRITE); if(sf==NULL) { Server->Log("Error opening settings file!", LL_ERROR); return; } } sf->Seek(sf->Size()); sf->Write(Server->ConvertToUTF8(toadd)); Server->destroy(sf); } } void ClientConnector::replaceSettings(const std::string &pData) { IFile *sf=Server->openFile("urbackup/data/settings.cfg", MODE_WRITE); if(sf==NULL) { Server->Log("Error opening settings file!", LL_ERROR); return; } sf->Write(pData); Server->destroy(sf); } void ClientConnector::saveLogdata(const std::string &created, const std::string &pData) { IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_CLIENT); IQuery *q_p=db->Prepare("INSERT INTO logs (ttime) VALUES (datetime(?, 'unixepoch'))"); q_p->Bind(created); q_p->Write(); _i64 logid=db->getLastInsertID(); while(!db->Write("BEGIN IMMEDIATE;")) Server->wait(500); IQuery *q=db->Prepare("INSERT INTO logdata (logid, loglevel, message, idx, ltime) VALUES (?, ?, ?, ?, datetime(?, 'unixepoch'))"); std::vector lines; TokenizeMail(pData, lines, "\n"); for(size_t i=0,lc=lines.size();iConvertToUnicode(u_msg); q->Bind(logid); q->Bind(loglevel); q->Bind(msg); q->Bind(i); q->Bind(ltime); q->Write(); q->Reset(); } db->EndTransaction(); db->destroyAllQueries(); } std::string ClientConnector::getLogpoints(void) { IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_CLIENT); IQuery *q=db->Prepare("SELECT id, strftime('"+time_format_str+"',ttime, 'localtime') AS ltime FROM logs ORDER BY ttime DESC LIMIT 100"); db_results res=q->Read(); std::string ret; for(size_t i=0;iConvertToUTF8(res[i][L"id"])+"-"; ret+=Server->ConvertToUTF8(res[i][L"ltime"])+"\n"; } db->destroyAllQueries(); return ret; } void ClientConnector::getLogLevel(int logid, int loglevel, std::string &data) { IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_CLIENT); IQuery *q=db->Prepare("SELECT loglevel, message FROM logdata WHERE logid=? AND loglevel>=? ORDER BY idx ASC"); q->Bind(logid); q->Bind(loglevel); db_results res=q->Read(); for(size_t i=0;iConvertToUTF8(res[i][L"loglevel"])+"-"; data+=Server->ConvertToUTF8(res[i][L"message"])+"\n"; } db->destroyAllQueries(); } bool ClientConnector::sendFullImage(void) { thread_action=1; thread_ticket=Server->getThreadPool()->execute(this); state=4; IScopedLock lock(backup_mutex); backup_running=3; pcdone=0; return true; } bool ClientConnector::sendIncrImage(void) { thread_action=2; thread_ticket=Server->getThreadPool()->execute(this); state=5; IScopedLock lock(backup_mutex); backup_running=4; pcdone=0; pcdone2=0; return true; } void ClientConnector::operator ()(void) { #ifdef _WIN32 #ifdef THREAD_MODE_BACKGROUND_BEGIN SetThreadPriority( GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN); #endif #endif if(thread_action==1) { sendFullImageThread(); } else if(thread_action==2) { int timeouts=1800; while(hashdataok==false) { Server->wait(1000); --timeouts; if(timeouts<=0 || do_quit==true ) { break; } } if(timeouts>0 || do_quit==true ) { sendIncrImageThread(); } } { IScopedLock lock(backup_mutex); if(backup_running==3 || backup_running==4) { backup_running=0; } } #ifdef _WIN32 #ifdef THREAD_MODE_BACKGROUND_END SetThreadPriority( GetCurrentThread(), THREAD_MODE_BACKGROUND_END); #endif #endif } bool ClientConnector::waitForThread(void) { if(thread_action!=0 && Server->getThreadPool()->isRunning(thread_ticket ) ) return true; else return false; } void ClientConnector::ImageErr(const std::string &msg) { /*Server->Log(msg, LL_ERROR); unsigned int bs=0xFFFFFFFF; char *buffer=new char[sizeof(unsigned int)+msg.size()]; memcpy(buffer, &bs, sizeof(unsigned int) ); memcpy(&buffer[sizeof(unsigned int)], msg.c_str(), msg.size()); pipe->Write(buffer, sizeof(unsigned int)+msg.size()); delete [] buffer;*/ Server->Log(msg, LL_ERROR); #ifdef _WIN32 uint64 bs=0xFFFFFFFFFFFFFFFF; #else uint64 bs=0xFFFFFFFFFFFFFFFFLLU; #endif char *buffer=new char[sizeof(uint64)+msg.size()]; memcpy(buffer, &bs, sizeof(uint64) ); memcpy(&buffer[sizeof(uint64)], msg.c_str(), msg.size()); pipe->Write(buffer, sizeof(uint64)+msg.size()); delete [] buffer; } void ClientConnector::ImageErrRunning(const std::string &msg) { Server->Log(msg, LL_ERROR); int64 bs=-124; char *buffer=new char[sizeof(int64)+msg.size()]; memcpy(buffer, &bs, sizeof(int64) ); memcpy(&buffer[sizeof(int64)], msg.c_str(), msg.size()); pipe->Write(buffer, sizeof(int64)+msg.size()); delete [] buffer; } void ClientConnector::sendFullImageThread(void) { bool has_error=true; int save_id=-1; bool run=true; while(run) { if(shadowdrive.empty()) { std::string msg; mempipe->Read(&msg); if(msg.find("done")==0) { shadowdrive=getafter("-", msg); save_id=atoi(getuntil("-", shadowdrive).c_str()); shadowdrive=getafter("-", shadowdrive); if(shadowdrive.size()>0 && shadowdrive[shadowdrive.size()-1]=='\\') shadowdrive.erase(shadowdrive.begin()+shadowdrive.size()-1); if(shadowdrive.empty()) { ImageErr("Creating Shadow drive failed. Stopping. -2"); run=false; } } else { ImageErr("Creating Shadow drive failed. Stopping."); run=false; } mempipe->Write("exit"); mempipe=Server->createMemoryPipe(); } else { IFilesystem *fs=image_fak->createFilesystem(Server->ConvertToUnicode(shadowdrive)); if(fs==NULL) { ImageErr("Opening Shadow drive filesystem failed. Stopping."); run=false; break; } unsigned int blocksize=(unsigned int)fs->getBlocksize(); int64 drivesize=fs->getSize(); int64 blockcnt=fs->calculateUsedSpace()/blocksize; if(startpos==0) { char *buffer=new char[sizeof(unsigned int)+sizeof(int64)*2+1+sizeof(unsigned int)+shadowdrive.size()+sizeof(int)]; char *cptr=buffer; memcpy(cptr, &blocksize, sizeof(unsigned int)); cptr+=sizeof(unsigned int); memcpy(cptr, &drivesize, sizeof(int64) ); cptr+=sizeof(int64); memcpy(cptr, &blockcnt, sizeof(int64) ); cptr+=sizeof(int64); #ifndef VSS_XP //persistence #ifndef VSS_S03 *cptr=1; #else *cptr=0; #endif #else *cptr=0; #endif ++cptr; unsigned int shadowdrive_size=(unsigned int)shadowdrive.size(); memcpy(cptr, &shadowdrive_size, sizeof(unsigned int)); cptr+=sizeof(unsigned int); memcpy(cptr, &shadowdrive[0], shadowdrive.size()); cptr+=shadowdrive.size(); memcpy(cptr, &save_id, sizeof(int)); cptr+=sizeof(int); bool b=pipe->Write(buffer, sizeof(unsigned int)+sizeof(int64)*2+1+sizeof(unsigned int)+shadowdrive.size()+sizeof(int) ); if(!b) { Server->Log("Pipe broken -1", LL_ERROR); run=false; break; } } ClientSend *cs=new ClientSend(pipe, blocksize+sizeof(int64), 2000); THREADPOOL_TICKET send_ticket=Server->getThreadPool()->execute(cs); unsigned int needed_bufs=64; std::vector bufs; for(int64 i=startpos,blocks=drivesize/blocksize;i n_bufs=cs->getBuffers(needed_bufs); bufs.insert(bufs.end(), n_bufs.begin(), n_bufs.end() ); needed_bufs=0; unsigned int n=(unsigned int)(std::min)(blocks-i, (int64)64); std::vector secs=fs->readBlocks(i, n, bufs, sizeof(int64)); needed_bufs+=(_u32)secs.size(); for(size_t j=0;jsendBuffer(bufs[j], sizeof(int64)+blocksize); } if(!secs.empty()) bufs.erase(bufs.begin(), bufs.begin()+secs.size() ); if(cs->hasError() ) { Server->Log("Pipe broken -2", LL_ERROR); run=false; break; } if(IdleCheckerThread::getPause()) { Server->wait(5000); } } for(size_t i=0;ifreeBuffer(bufs[i]); } cs->doExit(); std::vector wf; wf.push_back(send_ticket); Server->getThreadPool()->waitFor(wf); delete cs; if(!run)break; char lastbuffer[sizeof(int64)]; int64 lastn=-123; memcpy(lastbuffer,&lastn, sizeof(int64)); bool b=pipe->Write(lastbuffer, sizeof(int64)); if(!b) { Server->Log("Pipe broken -3", LL_ERROR); run=false; break; } has_error=false; run=false; } } Server->Log("Sending full image done", LL_INFO); #ifdef VSS_XP //persistence has_error=false; #endif #ifdef VSS_S03 has_error=false; #endif if(!has_error) { removeShadowCopyThread(); std::string msg; mempipe->Read(&msg); if(msg.find("done")!=0) { Server->Log("Removing shadow copy failed in image streaming: "+msg, LL_ERROR); } mempipe->Write("exit"); mempipe=Server->createMemoryPipe(); } do_quit=true; } const unsigned int c_vhdblocksize=(1024*1024/4); const unsigned int c_hashsize=32; void ClientConnector::sendIncrImageThread(void) { char *blockbuf=NULL; char *blockdatabuf=NULL; bool has_error=true; int save_id=-1; int update_cnt=0; bool run=true; while(run) { if(shadowdrive.empty()) { std::string msg; mempipe->Read(&msg); if(msg.find("done")==0) { shadowdrive=getafter("-", msg); save_id=atoi(getuntil("-", shadowdrive).c_str()); shadowdrive=getafter("-", shadowdrive); if(shadowdrive.size()>0 && shadowdrive[shadowdrive.size()-1]=='\\') shadowdrive.erase(shadowdrive.begin()+shadowdrive.size()-1); if(shadowdrive.empty()) { ImageErr("Creating Shadow drive failed. Stopping. -2"); run=false; } } else { ImageErr("Creating Shadow drive failed. Stopping."); run=false; } mempipe->Write("exit"); mempipe=Server->createMemoryPipe(); } else { IFilesystem *fs=image_fak->createFilesystem(Server->ConvertToUnicode(shadowdrive)); if(fs==NULL) { ImageErr("Opening Shadow drive filesystem failed. Stopping."); run=false; break; } sha256_ctx shactx; unsigned int vhdblocks; unsigned int blocksize=(unsigned int)fs->getBlocksize(); int64 drivesize=fs->getSize(); int64 blockcnt=fs->calculateUsedSpace()/blocksize; vhdblocks=c_vhdblocksize/blocksize; int64 currvhdblock=0; int64 numblocks=drivesize/blocksize; if(startpos==0) { char *buffer=new char[sizeof(unsigned int)+sizeof(int64)*2+1+sizeof(unsigned int)+shadowdrive.size()+sizeof(int)]; char *cptr=buffer; memcpy(cptr, &blocksize, sizeof(unsigned int)); cptr+=sizeof(unsigned int); memcpy(cptr, &drivesize, sizeof(int64) ); cptr+=sizeof(int64); memcpy(cptr, &blockcnt, sizeof(int64) ); cptr+=sizeof(int64); #ifndef VSS_XP //persistence #ifndef VSS_S03 *cptr=1; #else *cptr=0; #endif #else *cptr=0; #endif ++cptr; unsigned int shadowdrive_size=(unsigned int)shadowdrive.size(); memcpy(cptr, &shadowdrive_size, sizeof(unsigned int)); cptr+=sizeof(unsigned int); memcpy(cptr, &shadowdrive[0], shadowdrive.size()); cptr+=shadowdrive.size(); memcpy(cptr, &save_id, sizeof(int)); cptr+=sizeof(int); bool b=pipe->Write(buffer, sizeof(unsigned int)+sizeof(int64)*2+1+sizeof(unsigned int)+shadowdrive.size()+sizeof(int) ); if(!b) { Server->Log("Pipe broken -1", LL_ERROR); run=false; break; } } blockbuf=new char[vhdblocks*blocksize]; ClientSend *cs=new ClientSend(pipe, blocksize+sizeof(int64), 2000); THREADPOOL_TICKET send_ticket=Server->getThreadPool()->execute(cs); for(int64 i=startpos,blocks=drivesize/blocksize;i10) { IScopedLock lock(backup_mutex); pcdone2=(int)(((float)i/(float)blocks)*100.f+0.5f); update_cnt=0; } currvhdblock=i/vhdblocks; bool has_data=false; for(int64 j=i;jreadBlock(j, NULL) ) { has_data=true; break; } } if(has_data) { sha256_init(&shactx); for(int64 j=i;jreadBlock(j, dpos) ) { if(IdleCheckerThread::getPause()) { Server->wait(5000); } sha256_update(&shactx, (unsigned char*)dpos, blocksize); } else { memset(dpos, 0, blocksize); sha256_update(&shactx, (unsigned char*)dpos, blocksize); } } unsigned char digest[c_hashsize]; sha256_final(&shactx, digest); if(hashdatafile->Size()>=(currvhdblock+1)*c_hashsize) { hashdatafile->Seek(currvhdblock*c_hashsize); char hashdata_buf[c_hashsize]; if( hashdatafile->Read(hashdata_buf, c_hashsize)!=c_hashsize ) { Server->Log("Reading hashdata failed!", LL_ERROR); } if(memcmp(hashdata_buf, digest, c_hashsize)!=0) { for(int64 j=i;jgetBuffer(); memcpy(&cb[sizeof(int64)], blockbuf+(j-i)*blocksize, blocksize); memcpy(cb, &j, sizeof(int64) ); cs->sendBuffer(cb, sizeof(int64)+blocksize); if(cs->hasError()) { Server->Log("Pipe broken -2", LL_ERROR); run=false; break; } } } else { Server->Log("Block didn't change: "+nconvert(i), LL_DEBUG); int64 bs=-125; char* buffer=cs->getBuffer(); memcpy(buffer, &bs, sizeof(int64) ); cs->sendBuffer(buffer, sizeof(int64)); } } else { ImageErrRunning("Hashdata from server too small"); run=false; break; } if(!run)break; } } cs->doExit(); std::vector wf; wf.push_back(send_ticket); Server->getThreadPool()->waitFor(wf); delete cs; if(!run)break; char lastbuffer[sizeof(int64)]; int64 lastn=-123; memcpy(lastbuffer,&lastn, sizeof(int64)); bool b=pipe->Write(lastbuffer, sizeof(int64)); if(!b) { Server->Log("Pipe broken -3", LL_ERROR); run=false; break; } has_error=false; run=false; } } delete [] blockbuf; Server->destroy(hashdatafile); Server->Log("Sending image done", LL_INFO); #ifdef VSS_XP //persistence has_error=false; #endif #ifdef VSS_S03 has_error=false; #endif if(!has_error) { removeShadowCopyThread(); std::string msg; mempipe->Read(&msg); if(msg.find("done")!=0) { Server->Log("Removing shadow copy failed in image streaming: "+msg, LL_ERROR); } mempipe->Write("exit"); mempipe=Server->createMemoryPipe(); } do_quit=true; } void ClientConnector::removeShadowCopyThread(void) { CWData data; data.addChar(3); data.addVoidPtr(mempipe); data.addString(image_letter); IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize()); } bool ClientConnector::sendMBR(const std::wstring &dl) { #ifdef _WIN32 HANDLE hVolume=CreateFileW((L"\\\\.\\"+dl+L":").c_str(), GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hVolume==INVALID_HANDLE_VALUE) { Server->Log(L"CreateFile of volume '"+dl+L"' failed. - sendMBR", LL_ERROR); return false; } STORAGE_DEVICE_NUMBER dev_num; DWORD ret_bytes; BOOL b=DeviceIoControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &dev_num, sizeof(STORAGE_DEVICE_NUMBER), &ret_bytes, NULL); CloseHandle(hVolume); if(b==0) { Server->Log(L"DeviceIoControl IOCTL_STORAGE_GET_DEVICE_NUMBER failed. Volume: '"+dl+L"'", LL_ERROR); return false; } wchar_t voln[MAX_PATH+1]; DWORD voln_size=MAX_PATH+1; DWORD voln_sern; wchar_t fsn[MAX_PATH+1]; DWORD fsn_size=MAX_PATH+1; b=GetVolumeInformationW((dl+L":\\").c_str(), voln, voln_size, &voln_sern, NULL, NULL, fsn, fsn_size); if(b==0) { Server->Log(L"GetVolumeInformationW failed. Volume: '"+dl+L"'", LL_ERROR); return false; } CWData mbr; mbr.addChar(1); mbr.addChar(0); mbr.addInt(dev_num.DeviceNumber); mbr.addInt(dev_num.PartitionNumber); mbr.addString(nconvert((_i64)voln_sern)); mbr.addString(Server->ConvertToUTF8((std::wstring)voln)); mbr.addString(Server->ConvertToUTF8((std::wstring)fsn)); IFile *dev=Server->openFile(L"\\\\.\\PhysicalDrive"+convert((int)dev_num.DeviceNumber), MODE_READ); if(dev==NULL) { Server->Log(L"Error opening Device "+convert((int)dev_num.DeviceNumber), LL_ERROR); return false; } std::string mbr_bytes=dev->Read(512); mbr.addString(mbr_bytes); tcpstack.Send(pipe, mbr); return true; #endif //WIN_32 } const unsigned int receive_timeouttime=60000; std::string ClientConnector::receivePacket(IPipe *p) { unsigned int starttime=Server->getTimeMS(); while(Server->getTimeMS()-starttime<=receive_timeouttime) { std::string ret; size_t rc=p->Read(&ret, 10000); if(rc==0) { return ""; } tcpstack.AddData((char*)ret.c_str(), ret.size()); size_t packetsize; char *pck=tcpstack.getPacket(&packetsize); if(pck!=NULL && packetsize>0) { ret.resize(packetsize); memcpy(&ret[0], pck, packetsize); delete [] pck; return ret; } } return ""; } void ClientConnector::removeChannelpipe(IPipe *cp) { channel_exit.push_back(cp); } void ClientConnector::downloadImage(str_map params) { _i64 imgsize=-1; if(channel_pipes.size()==0) { pipe->Write((char*)&imgsize, sizeof(_i64), (int)receive_timeouttime); Server->Log("No channel found!", LL_DEBUG); return; } int l_pcdone=0; { IScopedLock lock(progress_mutex); pcdone=0; } for(size_t i=0;iLog("Downloading from channel "+nconvert((int)i), LL_DEBUG); _i64 imgsize=-1; c->Read((char*)&imgsize, sizeof(_i64), 60000); Server->Log("Imagesize "+nconvert(imgsize), LL_DEBUG); if(imgsize==-1) { Server->Log("Error reading size", LL_ERROR); continue; } if(!pipe->Write((char*)&imgsize, sizeof(_i64), (int)receive_timeouttime)) { Server->Log("Could not write to pipe! downloadImage-1", LL_ERROR); return; } char buf[4096]; _i64 read=0; if(params[L"mbr"]==L"true") { Server->Log("Downloading MBR...", LL_DEBUG); while(readRead(buf, 4096, 60000); if(c_read==0) { Server->Log("Read Timeout", LL_ERROR); removeChannelpipe(c); return; } if(!pipe->Write(buf, (_u32)c_read, (int)receive_timeouttime*5)) { Server->Log("Could not write to pipe! downloadImage-5", LL_ERROR); removeChannelpipe(c); return; } read+=c_read; } Server->Log("Downloading MBR done"); return; } unsigned int blockleft=0; unsigned int off=0; _i64 pos=0; while(posRead(&buf[off], 4096-off, 180000); if( r==0 ) { Server->Log("Read Timeout -2", LL_ERROR); removeChannelpipe(c); return; } if(!pipe->Write(&buf[off], r, (int)receive_timeouttime*5)) { Server->Log("Could not write to pipe! downloadImage-3 size "+nconvert(r)+" off "+nconvert(off), LL_ERROR); removeChannelpipe(c); return; } if(r!=0) r+=off; off=0; while(true) { if( blockleft==0 ) { if(r-off>=sizeof(_i64) ) { blockleft=4096; _i64 s; memcpy((char*)&s, &buf[off], sizeof(_i64) ); if(s>imgsize) { Server->Log("invalid seek value: "+nconvert(s), LL_ERROR); } off+=sizeof(_i64); pos=s; } else if(r-off>0) { char buf2[4096]; memcpy(buf2, &buf[off], r-off); memcpy(buf, buf2, r-off); off=(_u32)r-off; break; } else { off=0; break; } } else { unsigned int available=(std::min)((unsigned int)r-off, blockleft); read+=available; blockleft-=available; off+=available; if(off>=r) { off=0; break; } } } int t_pcdone=(int)(((float)pos/(float)imgsize)*100.f+0.5f); if(t_pcdone!=l_pcdone) { l_pcdone=t_pcdone; IScopedLock lock(progress_mutex); pcdone=l_pcdone; } lasttime=Server->getTimeMS(); } Server->Log("Downloading image done", LL_DEBUG); return; } imgsize=-1; pipe->Write((char*)&imgsize, sizeof(_i64), (int)receive_timeouttime); } void ClientConnector::waitForPings(IScopedLock *lock) { Server->Log("Waiting for pings...", LL_DEBUG); while(!channel_ping.empty()) { lock->relock(NULL); Server->wait(1000); lock->relock(backup_mutex); } Server->Log("done. (Waiting for pings)", LL_DEBUG); }