mirror of
https://github.com/uroni/urbackup_backend.git
synced 2025-10-26 11:36:50 +00:00
730 lines
23 KiB
C++
730 lines
23 KiB
C++
/*************************************************************************
|
||
* UrBackup - Client/Server backup system
|
||
* Copyright (C) 2011-2016 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 <http://www.gnu.org/licenses/>.
|
||
**************************************************************************/
|
||
|
||
#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 <algorithm>
|
||
#include "../urbackupcommon/file_metadata.h"
|
||
#include "serverinterface/backups.h"
|
||
#include "../urbackupcommon/filelist_utils.h"
|
||
#include "../common/data.h"
|
||
#include "database.h"
|
||
#include "dao/ServerBackupDao.h"
|
||
#include "dao/ServerCleanupDao.h"
|
||
#include "server.h"
|
||
|
||
extern IFileServ* fileserv;
|
||
|
||
|
||
namespace
|
||
{
|
||
const int64 win32_meta_magic = little_endian(0x320FAB3D119DCB4AULL);
|
||
const int64 unix_meta_magic = little_endian(0xFE4378A3467647F0ULL);
|
||
|
||
const _u32 ID_METADATA_V1_WIN = 1<<0 | 1<<3;
|
||
const _u32 ID_METADATA_V1_UNIX = 1<<2 | 1<<3;
|
||
|
||
std::string reconstructOrigPath(const std::string& metadata_fn, bool isdir)
|
||
{
|
||
std::string cp;
|
||
if (isdir)
|
||
{
|
||
cp = ExtractFilePath(metadata_fn, os_file_sep());
|
||
}
|
||
else
|
||
{
|
||
cp = metadata_fn;
|
||
}
|
||
|
||
std::string orig_path_add = ExtractFileName(cp, os_file_sep());
|
||
FileMetadata parent_metadata;
|
||
while (!(cp = ExtractFilePath(cp, os_file_sep())).empty()
|
||
&& read_metadata(cp + os_file_sep() + metadata_dir_fn, parent_metadata))
|
||
{
|
||
if (!parent_metadata.orig_path.empty())
|
||
{
|
||
break;
|
||
}
|
||
|
||
orig_path_add = ExtractFileName(cp, os_file_sep()) + os_file_sep() + orig_path_add;
|
||
}
|
||
|
||
return parent_metadata.orig_path + os_file_sep() + orig_path_add;
|
||
}
|
||
|
||
class MetadataCallback : public IFileServ::IMetadataCallback
|
||
{
|
||
public:
|
||
MetadataCallback(const std::string& basedir, const std::vector < std::pair<std::string, std::string> >& map_paths)
|
||
: basedir(basedir), map_paths(map_paths)
|
||
{
|
||
|
||
}
|
||
|
||
virtual IFile* getMetadata( const std::string& path, std::string* orig_path, int64* offset,
|
||
int64* length, _u32* version, bool get_hashdata)
|
||
{
|
||
if(path.empty()) return NULL;
|
||
|
||
std::string metadata_path = basedir;
|
||
|
||
std::vector<std::string> path_segments;
|
||
Tokenize(path.substr(1), path_segments, "/");
|
||
|
||
bool isdir = path[0]=='d';
|
||
|
||
for(size_t i=1;i<path_segments.size();++i)
|
||
{
|
||
if(path_segments[i]=="." || path_segments[i]=="..")
|
||
{
|
||
continue;
|
||
}
|
||
|
||
metadata_path+=os_file_sep() + escape_metadata_fn((path_segments[i]));
|
||
|
||
if(i==path_segments.size()-1 && isdir)
|
||
{
|
||
metadata_path+=os_file_sep() + metadata_dir_fn;
|
||
}
|
||
}
|
||
|
||
std::auto_ptr<IFile> metadata_file(Server->openFile(os_file_prefix(metadata_path), MODE_READ));
|
||
|
||
if(metadata_file.get()==NULL)
|
||
{
|
||
Server->Log("Cannot open metadata file \"" + metadata_path + "\". " + os_last_error_str(), LL_ERROR);
|
||
return NULL;
|
||
}
|
||
|
||
if (orig_path != NULL)
|
||
{
|
||
FileMetadata metadata;
|
||
|
||
if (!read_metadata(metadata_file.get(), metadata))
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
*orig_path = metadata.orig_path;
|
||
|
||
if (orig_path->empty())
|
||
{
|
||
*orig_path = reconstructOrigPath(metadata_path, isdir);
|
||
}
|
||
|
||
for (size_t j = 0; j < map_paths.size(); ++j)
|
||
{
|
||
if (next(*orig_path, 0, map_paths[j].first))
|
||
{
|
||
orig_path->replace(orig_path->begin(), orig_path->begin() + map_paths[j].first.size(), map_paths[j].second);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
if (!get_hashdata)
|
||
{
|
||
int64 m_offset = os_metadata_offset(metadata_file.get());
|
||
|
||
if (offset != NULL) *offset = m_offset;
|
||
|
||
int64 m_length = metadata_file->Size() - m_offset;
|
||
|
||
if (length != NULL) *length = m_length;
|
||
|
||
int64 metadata_magic_and_size[2];
|
||
|
||
if (!metadata_file->Seek(m_offset))
|
||
{
|
||
Server->Log("Cannot seek to " + convert(m_offset) + " in metadata file " + metadata_file->getFilename() + ". " + os_last_error_str(), LL_ERROR);
|
||
return NULL;
|
||
}
|
||
|
||
if (metadata_file->Read(reinterpret_cast<char*>(&metadata_magic_and_size), sizeof(metadata_magic_and_size)) != sizeof(metadata_magic_and_size))
|
||
{
|
||
Server->Log("Cannot read from metadata file " + metadata_file->getFilename() + ". " + os_last_error_str(), LL_ERROR);
|
||
return NULL;
|
||
}
|
||
|
||
if (version != NULL)
|
||
{
|
||
if (metadata_magic_and_size[1] == win32_meta_magic)
|
||
{
|
||
*version = ID_METADATA_V1_WIN;
|
||
}
|
||
else if (metadata_magic_and_size[1] == unix_meta_magic)
|
||
{
|
||
*version = ID_METADATA_V1_UNIX;
|
||
}
|
||
else
|
||
{
|
||
*version = 0;
|
||
}
|
||
}
|
||
|
||
if (!metadata_file->Seek(m_offset))
|
||
{
|
||
Server->Log("Cannot seek to " + convert(m_offset) + " in metadata file " + metadata_file->getFilename() + ". " + os_last_error_str(), LL_ERROR);
|
||
return NULL;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
int64 m_length = get_hashdata_size(metadata_file.get());
|
||
|
||
if (m_length <= sizeof(int64) )
|
||
{
|
||
Server->Log("Length too small ("+convert(m_length)+") in metadata file " + metadata_file->getFilename() + ". " + os_last_error_str(), LL_ERROR);
|
||
return NULL;
|
||
}
|
||
|
||
if (offset != NULL) *offset = sizeof(int64);
|
||
|
||
if (length != NULL) *length = m_length - sizeof(int64);
|
||
}
|
||
|
||
return metadata_file.release();
|
||
}
|
||
|
||
private:
|
||
std::string basedir;
|
||
std::vector < std::pair<std::string, std::string> > map_paths;
|
||
};
|
||
|
||
class ClientDownloadThread : public IThread
|
||
{
|
||
private:
|
||
struct SRestoreFolder
|
||
{
|
||
std::string foldername;
|
||
std::string hashfoldername;
|
||
std::string share_path;
|
||
std::vector<std::string> filter_fns;
|
||
};
|
||
|
||
public:
|
||
ClientDownloadThread(const std::string& curr_clientname, int curr_clientid, int restore_clientid, IFile* filelist_f, const std::string& foldername,
|
||
const std::string& hashfoldername, const std::string& filter, bool skip_special_root,
|
||
const std::string& folder_log_name, int64 restore_id, size_t status_id, logid_t log_id, const std::string& restore_token, const std::string& identity,
|
||
const std::vector<std::pair<std::string, std::string> >& map_paths,
|
||
bool clean_other, bool ignore_other_fs, const std::string& share_path,
|
||
bool follow_symlinks, int64 restore_flags, const std::vector<std::string>& tokens, backupaccess::STokens access_tokens)
|
||
: curr_clientname(curr_clientname), curr_clientid(curr_clientid), restore_clientid(restore_clientid),
|
||
filelist_f(filelist_f),
|
||
skip_special_root(skip_special_root),
|
||
restore_token(restore_token), identity(identity), restore_id(restore_id), status_id(status_id), log_id(log_id),
|
||
single_file(false), map_paths(map_paths), clean_other(clean_other), ignore_other_fs(ignore_other_fs),
|
||
curr_restore_folder_idx(0), follow_symlinks(follow_symlinks), restore_flags(restore_flags),
|
||
tokens(tokens), access_tokens(access_tokens)
|
||
{
|
||
SRestoreFolder restore_folder;
|
||
restore_folder.foldername = foldername;
|
||
restore_folder.hashfoldername = hashfoldername;
|
||
restore_folder.share_path = share_path;
|
||
|
||
Tokenize(filter, restore_folder.filter_fns, "/");
|
||
|
||
if (restore_folder.filter_fns.size() == 1)
|
||
{
|
||
single_file = true;
|
||
}
|
||
|
||
if (!restore_folder.share_path.empty()
|
||
&& restore_folder.share_path[restore_folder.share_path.size() - 1] == '/')
|
||
{
|
||
restore_folder.share_path.erase(restore_folder.share_path.size() - 1, 1);
|
||
}
|
||
|
||
restore_folders.push_back(restore_folder);
|
||
}
|
||
|
||
void operator()()
|
||
{
|
||
IDatabase* db = Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);
|
||
ServerBackupDao backup_dao(db);
|
||
|
||
for (; curr_restore_folder_idx < restore_folders.size(); ++curr_restore_folder_idx)
|
||
{
|
||
SRestoreFolder& restore_folder = restore_folders[curr_restore_folder_idx];
|
||
|
||
filter_fns = restore_folder.filter_fns;
|
||
|
||
if (!createFilelist(restore_folder.foldername, restore_folder.hashfoldername,
|
||
restore_folder.share_path, 0,
|
||
curr_restore_folder_idx==0 ? skip_special_root : false) )
|
||
{
|
||
ServerStatus::stopProcess(curr_clientname, status_id);
|
||
|
||
int errors = 0;
|
||
int warnings = 0;
|
||
int infos = 0;
|
||
std::string logdata = ServerLogger::getLogdata(log_id, errors, warnings, infos);
|
||
|
||
backup_dao.saveBackupLog(restore_clientid, errors, warnings, infos, 0,
|
||
0, 0, 1);
|
||
|
||
backup_dao.saveBackupLogData(db->getLastInsertID(), logdata);
|
||
|
||
backup_dao.setRestoreDone(0, restore_id);
|
||
|
||
return;
|
||
}
|
||
}
|
||
|
||
fileserv->addIdentity(identity);
|
||
fileserv->shareDir("clientdl_filelist", filelist_f->getFilename(), identity, false);
|
||
ClientMain::addShareToCleanup(curr_clientid, SShareCleanup("clientdl_filelist", identity, true, false));
|
||
|
||
delete filelist_f;
|
||
|
||
for (size_t i = 0; i < restore_folders.size(); ++i)
|
||
{
|
||
SRestoreFolder& restore_folder = restore_folders[i];
|
||
|
||
MetadataCallback* callback = new MetadataCallback(restore_folder.hashfoldername, map_paths);
|
||
fileserv->shareDir("clientdl"+convert(i), restore_folder.foldername, identity, false);
|
||
ClientMain::addShareToCleanup(curr_clientid, SShareCleanup("clientdl" + convert(i), identity, false, true));
|
||
fileserv->registerMetadataCallback("clientdl" + convert(i), identity, callback);
|
||
}
|
||
|
||
fileserv->shareDir("urbackup", "/tmp/mkmergsdfklrzrehmklregmfdkgfdgwretkl<6B>df", identity, false);
|
||
ClientMain::addShareToCleanup(curr_clientid, SShareCleanup("urbackup", identity, false, false));
|
||
|
||
|
||
CWData data;
|
||
data.addBuffer("RESTORE", 7);
|
||
data.addString(identity);
|
||
data.addInt64(restore_id);
|
||
data.addUInt64(status_id);
|
||
data.addInt64(log_id.first);
|
||
data.addString(restore_token);
|
||
data.addChar(single_file ? 1 : 0);
|
||
data.addChar(clean_other ? 1 : 0);
|
||
data.addChar(ignore_other_fs ? 1 : 0);
|
||
data.addInt64(restore_flags);
|
||
|
||
std::string msg(data.getDataPtr(), data.getDataPtr()+data.getDataSize());
|
||
ServerStatus::sendToCommPipe(curr_clientname, msg);
|
||
}
|
||
|
||
bool writeFile(const std::string& data)
|
||
{
|
||
std::string towrite = (data);
|
||
return filelist_f->Write(towrite)==towrite.size();
|
||
}
|
||
|
||
|
||
bool createFilelist(std::string foldername, std::string hashfoldername, std::string curr_share_path,
|
||
size_t depth, bool skip_special)
|
||
{
|
||
bool has_error=false;
|
||
const std::vector<SFile> files = getFiles(os_file_prefix(foldername), &has_error);
|
||
|
||
if(has_error)
|
||
{
|
||
ServerLogger::Log(log_id, "Cannot read files from folder "+foldername+". Cannot start restore.", LL_ERROR);
|
||
return false;
|
||
}
|
||
|
||
bool ret=true;
|
||
|
||
for(size_t i=0;i<files.size();++i)
|
||
{
|
||
SFile file=files[i];
|
||
|
||
if(depth==0 && (!filter_fns.empty() && std::find(filter_fns.begin(), filter_fns.end(), file.name)==filter_fns.end()) )
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if(skip_special
|
||
&& (file.name==".hashes" || file.name=="user_views") )
|
||
{
|
||
continue;
|
||
}
|
||
|
||
std::string metadataname = hashfoldername + os_file_sep() + escape_metadata_fn(file.name);
|
||
std::string filename = foldername + os_file_sep() + file.name;
|
||
|
||
if (file.issym)
|
||
{
|
||
std::string pool_path;
|
||
if (os_get_symlink_target(filename, pool_path))
|
||
{
|
||
std::string directory_pool = ExtractFileName(ExtractFilePath(ExtractFilePath(pool_path, os_file_sep()), os_file_sep()), os_file_sep());
|
||
|
||
if (directory_pool != ".directory_pool")
|
||
{
|
||
followSymlink(pool_path, filename, metadataname, file.isdir);
|
||
file.size = 0;
|
||
}
|
||
else
|
||
{
|
||
file.issym = false;
|
||
file.isdir = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
std::string metadatasource;
|
||
bool recurse_dir = false;
|
||
if(file.isdir && !file.issym
|
||
&& os_directory_exists(os_file_prefix(metadataname)) )
|
||
{
|
||
metadatasource = metadataname + os_file_sep()+metadata_dir_fn;
|
||
single_file = false;
|
||
recurse_dir = true;
|
||
}
|
||
else
|
||
{
|
||
metadatasource = metadataname;
|
||
}
|
||
|
||
bool has_metadata = false;
|
||
|
||
FileMetadata metadata;
|
||
if(!read_metadata(metadatasource, metadata))
|
||
{
|
||
ServerLogger::Log(log_id, "Cannot read file metadata of file "+filename+" from "+ metadatasource +". Cannot start restore.", LL_ERROR);
|
||
return false;
|
||
}
|
||
|
||
std::string extra;
|
||
|
||
if (depth == 0
|
||
&& metadata.orig_path.empty())
|
||
{
|
||
metadata.orig_path = reconstructOrigPath(metadatasource, file.isdir);
|
||
}
|
||
|
||
if(!metadata.orig_path.empty() &&
|
||
(depth==0 || metadata.orig_path.rfind(file.name)!=metadata.orig_path.size()-file.name.size()))
|
||
{
|
||
std::string alt_orig_path = metadata.orig_path;
|
||
for (size_t j = 0; j < map_paths.size(); ++j)
|
||
{
|
||
if (next(metadata.orig_path, 0, map_paths[j].first))
|
||
{
|
||
metadata.orig_path.replace(metadata.orig_path.begin(), metadata.orig_path.begin()+map_paths[j].first.size(), map_paths[j].second);
|
||
break;
|
||
}
|
||
}
|
||
|
||
extra="&orig_path="+EscapeParamString(metadata.orig_path);
|
||
|
||
if (metadata.orig_path != alt_orig_path)
|
||
{
|
||
extra+="&alt_orig_path="+EscapeParamString(alt_orig_path);
|
||
}
|
||
}
|
||
|
||
if (depth == 0)
|
||
{
|
||
extra += "&share_path=" + EscapeParamString(curr_share_path.empty() ? file.name : (curr_share_path + "/" + file.name));
|
||
extra += "&server_path=clientdl" + convert(curr_restore_folder_idx);
|
||
}
|
||
|
||
if(!metadata.shahash.empty())
|
||
{
|
||
if (BackupServer::useTreeHashing())
|
||
{
|
||
extra += "&thash=" + base64_encode_dash(metadata.shahash);
|
||
}
|
||
else
|
||
{
|
||
extra += "&shahash=" + base64_encode_dash(metadata.shahash);
|
||
}
|
||
}
|
||
|
||
if(depth==0 &&
|
||
( !filter_fns.empty() || skip_special ) )
|
||
{
|
||
extra+="&single_item=1";
|
||
}
|
||
|
||
if (!tokens.empty())
|
||
{
|
||
if (!backupaccess::checkFileToken(access_tokens.tokens, tokens, metadata))
|
||
{
|
||
extra += "&skip=1";
|
||
recurse_dir = false;
|
||
}
|
||
}
|
||
|
||
if (depth == 0)
|
||
{
|
||
std::string tids;
|
||
for (size_t j = 0; j < access_tokens.tokens.size(); ++j)
|
||
{
|
||
if (access_tokens.tokens[j].token.empty())
|
||
continue;
|
||
|
||
for (size_t k = 0; k < tokens.size(); ++k)
|
||
{
|
||
if (access_tokens.tokens[j].token == tokens[k])
|
||
{
|
||
if (!tids.empty()) tids += ",";
|
||
tids += convert(access_tokens.tokens[j].id);
|
||
}
|
||
}
|
||
}
|
||
extra += "&tids=" + tids;
|
||
}
|
||
|
||
writeFileItem(filelist_f, file, extra);
|
||
|
||
if(file.isdir)
|
||
{
|
||
if (recurse_dir)
|
||
{
|
||
ret = ret && createFilelist(filename, metadataname, curr_share_path + "/" + file.name, depth + 1, false);
|
||
}
|
||
|
||
SFile cf;
|
||
cf.name="..";
|
||
cf.isdir=true;
|
||
writeFileItem(filelist_f, cf);
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
void followSymlink(const std::string& symlink_target,
|
||
std::string file_path,
|
||
std::string hash_file_path,
|
||
bool& is_dir)
|
||
{
|
||
std::vector<std::string> symlink_path_toks;
|
||
Tokenize(symlink_target, symlink_path_toks, os_file_sep());
|
||
|
||
SRestoreFolder restore_folder;
|
||
restore_folder.foldername = file_path;
|
||
restore_folder.hashfoldername = hash_file_path;
|
||
|
||
size_t sym_off = 0;
|
||
restore_folder.foldername = ExtractFilePath(restore_folder.foldername, os_file_sep());
|
||
restore_folder.hashfoldername = ExtractFilePath(restore_folder.hashfoldername, os_file_sep());
|
||
for (sym_off = 0; sym_off< symlink_path_toks.size()
|
||
&& symlink_path_toks[sym_off] == ".."; ++sym_off)
|
||
{
|
||
restore_folder.foldername = ExtractFilePath(restore_folder.foldername, os_file_sep());
|
||
restore_folder.hashfoldername = ExtractFilePath(restore_folder.hashfoldername, os_file_sep());
|
||
}
|
||
|
||
for (; sym_off < symlink_path_toks.size(); ++sym_off)
|
||
{
|
||
restore_folder.foldername += os_file_sep() + symlink_path_toks[sym_off];
|
||
restore_folder.hashfoldername += os_file_sep() + symlink_path_toks[sym_off];
|
||
if (!restore_folder.share_path.empty())
|
||
{
|
||
restore_folder.share_path += "/";
|
||
}
|
||
restore_folder.share_path += symlink_path_toks[sym_off];
|
||
}
|
||
|
||
is_dir = (os_get_file_type(restore_folder.foldername) & EFileType_Directory) > 0;
|
||
|
||
if (!follow_symlinks)
|
||
{
|
||
return;
|
||
}
|
||
|
||
for (size_t i = 0; i < restore_folders.size(); ++i)
|
||
{
|
||
if (next(restore_folder.foldername, 0, restore_folders[i].foldername) )
|
||
{
|
||
if (restore_folders[i].filter_fns.empty())
|
||
{
|
||
//Is already being restored
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
for (size_t j = 0; j < restore_folders[i].filter_fns.size(); ++j)
|
||
{
|
||
if (next(restore_folder.foldername, 0, restore_folders[i].foldername + os_file_sep()+ restore_folders[i].filter_fns[j]))
|
||
{
|
||
//Is already being restored
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (is_dir)
|
||
{
|
||
for (size_t i = curr_restore_folder_idx + 1; i < restore_folders.size();)
|
||
{
|
||
if (next(restore_folders[i].foldername, 0, restore_folder.foldername))
|
||
{
|
||
//Will be restored by new restore folder
|
||
restore_folders.erase(restore_folders.begin() + i);
|
||
}
|
||
else
|
||
{
|
||
++i;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!is_dir)
|
||
{
|
||
std::string fn = ExtractFileName(restore_folder.foldername, os_file_sep());
|
||
restore_folder.foldername = ExtractFilePath(restore_folder.foldername, os_file_sep());
|
||
restore_folder.hashfoldername = ExtractFilePath(restore_folder.hashfoldername, os_file_sep());
|
||
restore_folder.share_path = ExtractFilePath(restore_folder.share_path, "/");
|
||
restore_folder.filter_fns.push_back(fn);
|
||
}
|
||
|
||
restore_folders.push_back(restore_folder);
|
||
}
|
||
|
||
private:
|
||
std::string curr_clientname;
|
||
int curr_clientid;
|
||
int restore_clientid;
|
||
IFile* filelist_f;
|
||
std::vector<std::string> filter_fns;
|
||
bool skip_special_root;
|
||
int64 restore_id;
|
||
size_t status_id;
|
||
logid_t log_id;
|
||
std::string restore_token;
|
||
std::string identity;
|
||
bool single_file;
|
||
std::vector < std::pair<std::string, std::string> > map_paths;
|
||
bool clean_other;
|
||
bool ignore_other_fs;
|
||
std::vector<SRestoreFolder> restore_folders;
|
||
size_t curr_restore_folder_idx;
|
||
bool follow_symlinks;
|
||
int64 restore_flags;
|
||
std::vector<std::string> tokens;
|
||
backupaccess::STokens access_tokens;
|
||
};
|
||
}
|
||
|
||
bool create_clientdl_thread(const std::string& curr_clientname, int curr_clientid, int restore_clientid, std::string foldername, std::string hashfoldername,
|
||
const std::string& filter, bool skip_hashes,
|
||
const std::string& folder_log_name, int64& restore_id, size_t& status_id, logid_t& log_id, const std::string& restore_token,
|
||
const std::vector<std::pair<std::string, std::string> >& map_paths, bool clean_other, bool ignore_other_fs, const std::string& share_path,
|
||
bool follow_symlinks, int64 restore_flags, THREADPOOL_TICKET& ticket, const std::vector<std::string>& tokens, const backupaccess::STokens& access_tokens)
|
||
{
|
||
IFile* filelist_f = Server->openTemporaryFile();
|
||
|
||
if(filelist_f==NULL)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if(!foldername.empty() && foldername[foldername.size()-1]==os_file_sep()[0])
|
||
{
|
||
foldername = foldername.substr(0, foldername.size()-1);
|
||
}
|
||
|
||
if(!hashfoldername.empty() && hashfoldername[hashfoldername.size()-1]==os_file_sep()[0])
|
||
{
|
||
hashfoldername = hashfoldername.substr(0, hashfoldername.size()-1);
|
||
}
|
||
|
||
IDatabase* db = Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);
|
||
ServerBackupDao backup_dao(db);
|
||
|
||
std::string full_log_name;
|
||
if (filter.find("/") != std::string::npos)
|
||
{
|
||
full_log_name = folder_log_name + "[" + filter + "]";
|
||
}
|
||
else
|
||
{
|
||
full_log_name = folder_log_name + filter;
|
||
}
|
||
|
||
|
||
std::string identity = ServerSettings::generateRandomAuthKey(25);
|
||
|
||
backup_dao.addRestore(restore_clientid, full_log_name, identity, 0, std::string());
|
||
restore_id = db->getLastInsertID();
|
||
|
||
status_id = ServerStatus::startProcess(curr_clientname, sa_restore_file, full_log_name, log_id, false);
|
||
|
||
log_id = ServerLogger::getLogId(restore_clientid);
|
||
|
||
ticket = Server->getThreadPool()->execute(new ClientDownloadThread(curr_clientname, curr_clientid, restore_clientid,
|
||
filelist_f, foldername, hashfoldername, filter, skip_hashes, folder_log_name, restore_id,
|
||
status_id, log_id, restore_token, identity, map_paths, clean_other, ignore_other_fs, share_path, follow_symlinks,
|
||
restore_flags, tokens, access_tokens), "frestore preparation");
|
||
|
||
return true;
|
||
}
|
||
|
||
bool create_clientdl_thread( int backupid, const std::string& curr_clientname, int curr_clientid,
|
||
int64& restore_id, size_t& status_id, logid_t& log_id, const std::string& restore_token,
|
||
const std::vector<std::pair<std::string, std::string> >& map_paths,
|
||
bool clean_other, bool ignore_other_fs, bool follow_symlinks, int64 restore_flags,
|
||
const std::vector<std::string>& tokens)
|
||
{
|
||
IDatabase* db = Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER);
|
||
ServerBackupDao backup_dao(db);
|
||
ServerCleanupDao cleanup_dao(db);
|
||
|
||
ServerBackupDao::SFileBackupInfo file_backup_info = backup_dao.getFileBackupInfo(backupid);
|
||
|
||
if(!file_backup_info.exists)
|
||
{
|
||
Server->Log("Could not get file backup info for backupid "+convert(backupid));
|
||
return false;
|
||
}
|
||
|
||
ServerCleanupDao::CondString client_name = cleanup_dao.getClientName(file_backup_info.clientid);
|
||
|
||
if(!client_name.exists)
|
||
{
|
||
Server->Log("Could not get client name for clientid "+convert(file_backup_info.clientid));
|
||
return false;
|
||
}
|
||
|
||
ServerBackupDao::CondString backupfolder = backup_dao.getSetting(0, "backupfolder");
|
||
|
||
if(!backupfolder.exists)
|
||
{
|
||
Server->Log("Could not get backup storage folder");
|
||
return false;
|
||
}
|
||
|
||
backupaccess::STokens access_tokens = backupaccess::readTokens(backupfolder.value, client_name.value, file_backup_info.path);
|
||
|
||
std::string curr_path=backupfolder.value+os_file_sep()+client_name.value+os_file_sep()+file_backup_info.path;
|
||
std::string curr_metadata_path=backupfolder.value+os_file_sep()+client_name.value+os_file_sep()+file_backup_info.path+os_file_sep()+".hashes";
|
||
std::string share_path = greplace(os_file_sep(), "/", file_backup_info.path);
|
||
THREADPOOL_TICKET ticket;
|
||
|
||
return create_clientdl_thread(curr_clientname, curr_clientid, file_backup_info.clientid, curr_path, curr_metadata_path, std::string(),
|
||
true, "", restore_id, status_id, log_id, restore_token, map_paths, clean_other, ignore_other_fs, share_path, follow_symlinks, restore_flags,
|
||
ticket, tokens, access_tokens);
|
||
}
|
||
|