/*************************************************************************
* UrBackup - Client/Server backup system
* Copyright (C) 2011-2015 Martin Raiber
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
**************************************************************************/
#include "restore_client.h"
#include "../../Interface/Thread.h"
#include "../../fileservplugin/IFileServ.h"
#include "../../Interface/File.h"
#include "../../Interface/Server.h"
#include "../server_settings.h"
#include "../ClientMain.h"
#include
#include "../../urbackupcommon/file_metadata.h"
#include "backups.h"
#include "../../urbackupcommon/filelist_utils.h"
#include "../../common/data.h"
#include "../database.h"
extern IFileServ* fileserv;
namespace
{
class MetadataCallback : public IFileServ::IMetadataCallback
{
public:
MetadataCallback(const std::wstring& basedir)
: basedir(basedir)
{
}
virtual IFile* getMetadata( const std::string& path, std::string& orig_path, int64& offset, int64& length )
{
if(path.empty()) return NULL;
std::wstring metadata_path = basedir;
std::vector path_segments;
TokenizeMail(path.substr(1), path_segments, "/");
bool isdir = path[0]=='d';
for(size_t i=1;iConvertToUnicode(path_segments[i]));
if(i==path_segments.size()-1 && isdir)
{
metadata_path+=os_file_sep() + metadata_dir_fn;
}
}
IFile* metadata_file = Server->openFile(os_file_prefix(metadata_path), MODE_READ);
if(metadata_file==NULL)
{
return metadata_file;
}
FileMetadata metadata;
if(!read_metadata(metadata_file, metadata))
{
delete metadata_file;
return NULL;
}
orig_path = metadata.orig_path;
offset = os_metadata_offset(metadata_file);
length = metadata_file->Size() - offset;
return metadata_file;
}
private:
std::wstring basedir;
};
class ClientDownloadThread : public IThread
{
public:
ClientDownloadThread(const std::wstring& clientname, int clientid, IFile* filelist_f, const std::wstring& foldername,
const std::wstring& hashfoldername, const std::wstring& filter,
bool token_authentication,
const std::vector &backup_tokens, const std::vector &tokens, bool skip_special_root,
const std::wstring& folder_log_name)
: clientname(clientname), clientid(clientid), filelist_f(filelist_f), foldername(foldername), hashfoldername(hashfoldername),
token_authentication(token_authentication), backup_tokens(backup_tokens),
tokens(tokens), skip_special_root(skip_special_root), folder_log_name(folder_log_name)
{
TokenizeMail(filter, filter_fns, L"/");
}
void operator()()
{
if(!createFilelist(foldername, hashfoldername, 0, skip_special_root))
{
return;
}
IDatabase* db = Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);
ServerBackupDao backup_dao(db);
std::string identity = ServerSettings::generateRandomAuthKey(25);
backup_dao.addRestore(clientid, folder_log_name, widen(identity));
int64 restore_id = db->getLastInsertID();
size_t status_id = ServerStatus::startProcess(clientname, sa_restore);
logid_t log_id = ServerLogger::getLogId(clientid);
fileserv->addIdentity(identity);
fileserv->shareDir(L"clientdl_filelist", filelist_f->getFilenameW(), identity);
ClientMain::addShareToCleanup(clientid, SShareCleanup("urbackup", identity, true, false));
delete filelist_f;
MetadataCallback* callback = new MetadataCallback(hashfoldername);
fileserv->shareDir(L"clientdl", foldername, identity);
ClientMain::addShareToCleanup(clientid, SShareCleanup("clientdl", identity, false, true));
fileserv->registerMetadataCallback(L"clientdl", identity, callback);
CWData data;
data.addBuffer("RESTORE", 7);
data.addString(identity);
data.addInt64(restore_id);
data.addUInt64(status_id);
data.addInt64(log_id.first);
std::string msg(data.getDataPtr(), data.getDataPtr()+data.getDataSize());
ServerStatus::sendToCommPipe(clientname, msg);
}
bool writeFile(const std::wstring& data)
{
std::string towrite = Server->ConvertToUTF8(data);
return filelist_f->Write(towrite)==towrite.size();
}
bool createFilelist(const std::wstring& foldername, const std::wstring& hashfoldername, size_t depth, bool skip_special)
{
bool has_error=false;
const std::vector files = getFiles(os_file_prefix(foldername), &has_error);
if(has_error)
return false;
bool ret=true;
for(size_t i=0;iConvertToUTF8(file.name);
if(!metadata.orig_path.empty() &&
(depth==0 || metadata.orig_path.find(fn_utf8)!=metadata.orig_path.size()-fn_utf8.size()))
{
extra="&orig_path="+base64_encode_dash(metadata.orig_path);
}
if(!metadata.shahash.empty())
{
extra+="&shahash="+base64_encode_dash(metadata.shahash);
}
writeFileItem(filelist_f, file, extra);
if(file.isdir)
{
ret = ret && createFilelist(filename, hashfoldername + os_file_sep() + escape_metadata_fn(file.name), depth+1, false);
SFile cf;
cf.name=L"..";
cf.isdir=true;
writeFileItem(filelist_f, cf);
}
}
return ret;
}
private:
std::wstring clientname;
int clientid;
IFile* filelist_f;
std::wstring foldername;
std::wstring hashfoldername;
std::vector filter_fns;
bool token_authentication;
std::vector backup_tokens;
std::vector tokens;
bool skip_special_root;
std::wstring folder_log_name;
};
}
bool create_clientdl_thread(const std::wstring& clientname, int clientid, const std::wstring& foldername, const std::wstring& hashfoldername,
const std::wstring& filter, bool token_authentication, const std::vector &backup_tokens, const std::vector &tokens, bool skip_hashes,
const std::wstring& folder_log_name)
{
IFile* filelist_f = Server->openTemporaryFile();
if(filelist_f==NULL)
{
return false;
}
Server->getThreadPool()->execute(new ClientDownloadThread(clientname, clientid, filelist_f, foldername, hashfoldername, filter, token_authentication, backup_tokens, tokens, skip_hashes, folder_log_name));
return true;
}