urbackup_backend/urbackupclient/LocalFileBackup.cpp
2021-06-28 23:24:30 +02:00

277 lines
7.2 KiB
C++

/*************************************************************************
* UrBackup - Client/Server backup system
* Copyright (C) 2021 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 "LocalFileBackup.h"
#include "../urbackupcommon/filelist_utils.h"
#include "../common/data.h"
#include "client.h"
#include <assert.h>
LocalFileBackup::LocalFileBackup(bool incr, int64 local_process_id,
int64 server_log_id, int64 server_status_id, int64 backupid, std::string server_token,
std::string server_identity, int facet_id, size_t max_backups,
const std::string& dest_url, const std::string& dest_url_params,
const str_map& dest_secret_params)
: LocalBackup(true, incr, local_process_id, server_log_id,
server_status_id, backupid, std::move(server_token), std::move(server_identity),
facet_id, max_backups, dest_url, dest_url_params, dest_secret_params)
{
file_metadata_pipe.reset(IndexThread::getFileSrv()->getFileMetadataPipe());
}
_i64 LocalFileBackup::getIncrementalSize(IFile* f, const std::vector<size_t>& diffs, bool& backup_with_components, bool all)
{
f->Seek(0);
_i64 rsize = 0;
FileListParser list_parser;
SFile cf;
bool indirchange = false;
size_t read;
size_t line = 0;
char buffer[4096];
int indir_currdepth = 0;
int depth = 0;
int indir_curr_depth = 0;
int changelevel = 0;
backup_with_components = false;
if (all)
{
indirchange = true;
}
while ((read = f->Read(buffer, 4096)) > 0)
{
for (size_t i = 0; i < read; ++i)
{
bool b = list_parser.nextEntry(buffer[i], cf, nullptr);
if (b)
{
if (cf.isdir == true)
{
if (depth == 0
&& cf.name == "windows_components_config")
{
backup_with_components = true;
}
if (!indirchange && hasChange(line, diffs))
{
indirchange = true;
changelevel = depth;
indir_currdepth = 0;
}
else if (indirchange)
{
if (cf.name != "..")
++indir_currdepth;
else
--indir_currdepth;
}
if (cf.name == ".." && indir_currdepth > 0)
{
--indir_currdepth;
}
if (cf.name != "..")
{
++depth;
}
else
{
--depth;
if (indirchange && depth == changelevel)
{
if (!all)
{
indirchange = false;
}
}
}
}
else
{
if (indirchange || hasChange(line, diffs))
{
if (cf.size > 0)
{
rsize += cf.size;
}
}
}
++line;
}
}
if (read < 4096)
break;
}
return rsize;
}
bool LocalFileBackup::hasChange(size_t line, const std::vector<size_t>& diffs)
{
return std::binary_search(diffs.begin(), diffs.end(), line);
}
void LocalFileBackup::referenceShadowcopy(const std::string& name, const std::string& server_token, const std::string& clientsubname)
{
CWData data;
data.addChar(IndexThread::IndexThreadAction_ReferenceShadowcopy);
unsigned int curr_result_id = IndexThread::getResultId();
data.addUInt(curr_result_id);
data.addString(name);
data.addString(server_token);
data.addUChar(0);
data.addUChar(1);
data.addString(clientsubname);
IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize());
}
void LocalFileBackup::unreferenceShadowcopy(const std::string& name, const std::string& server_token, const std::string& clientsubname, int issues)
{
CWData data;
data.addChar(IndexThread::IndexThreadAction_ReleaseShadowcopy);
unsigned int curr_result_id = IndexThread::getResultId();
data.addUInt(curr_result_id);
data.addString(name);
data.addString(server_token);
data.addUChar(0);
data.addInt(-1);
data.addString(clientsubname);
data.addInt(issues);
IndexThread::getMsgPipe()->Write(data.getDataPtr(), data.getDataSize());
}
std::string LocalFileBackup::permissionsAllowAll()
{
CWData token_info;
//allow to all
token_info.addChar(0);
token_info.addVarInt(0);
return std::string(token_info.getDataPtr(), token_info.getDataSize());
}
namespace
{
const int64 win32_meta_magic = little_endian(0x320FAB3D119DCB4AULL);
const int64 unix_meta_magic = little_endian(0xFE4378A3467647F0ULL);
}
bool LocalFileBackup::backupMetadata(IFsFile* metadataf, const std::string& sourcepath, FileMetadata* metadata)
{
if (metadata != nullptr)
{
SFile file_meta = getFileMetadata(os_file_prefix(sourcepath));
if (file_meta.name.empty())
{
Server->Log("Error getting metadata (created and last modified time) of " + sourcepath, LL_ERROR);
return false;
}
metadata->accessed = file_meta.accessed;
metadata->created = file_meta.created;
metadata->last_modified = file_meta.last_modified;
int64 truncate_to_bytes;
if (!write_file_metadata(metadataf, nullptr, *metadata, true, truncate_to_bytes))
{
//Log
return false;
}
else if(truncate_to_bytes>=0)
{
if (!metadataf->Resize(truncate_to_bytes))
{
//Log
return false;
}
}
}
int64 osm_offset = os_metadata_offset(metadataf);
if (osm_offset == -1)
{
Server->Log("Error saving metadata. Metadata offset cannot be calculated at \"" + metadataf->getFilename() + "\"", LL_ERROR);
return false;
}
if (!metadataf->Seek(osm_offset))
{
Server->Log("Error saving metadata. Could not seek to end of file \"" + metadataf->getFilename() + "\"", LL_ERROR);
return false;
}
if (!writeOsMetadata(sourcepath, osm_offset, metadataf))
{
//Log
return false;
}
return true;
}
bool LocalFileBackup::writeOsMetadata(const std::string& sourcefn, int64 dest_start_offset, IFile* dest)
{
int64 win32_magic_and_size[2];
win32_magic_and_size[1] = win32_meta_magic;
win32_magic_and_size[0] = 0;
if (dest->Write(reinterpret_cast<char*>(win32_magic_and_size), sizeof(win32_magic_and_size)) != sizeof(win32_magic_and_size))
{
//Log
return false;
}
if (!file_metadata_pipe->openOsMetadataFile(sourcefn))
{
//Log
return false;
}
std::vector<char> buf(256 * 1024);
size_t read;
while (file_metadata_pipe->readCurrOsMetadata(buf.data(), buf.size(), read))
{
if (dest->Write(buf.data(), read) != read)
{
//Log
return false;
}
win32_magic_and_size[0] += read;
}
if (!dest->Seek(dest_start_offset))
{
//Log
return false;
}
if (dest->Write(reinterpret_cast<char*>(win32_magic_and_size), sizeof(win32_magic_and_size[0])) != sizeof(win32_magic_and_size[0]))
{
//Log
return false;
}
return true;
}