mirror of
https://github.com/uroni/urbackup_backend.git
synced 2025-10-26 11:36:50 +00:00
357 lines
7.6 KiB
C++
357 lines
7.6 KiB
C++
#include <string>
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include "../stringtools.h"
|
|
#include "../urbackupcommon/os_functions.h"
|
|
#include <stdlib.h>
|
|
#ifndef _WIN32
|
|
#include <unistd.h>
|
|
#include <stdarg.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <pwd.h>
|
|
extern char **environ;
|
|
#endif
|
|
|
|
#define DEF_Server
|
|
#include "../Server.h"
|
|
|
|
|
|
const std::string btrfs_cmd="/sbin/btrfs";
|
|
|
|
CServer *Server;
|
|
|
|
#ifdef _WIN32
|
|
#include <Windows.h>
|
|
|
|
bool CopyFolder(std::wstring src, std::wstring dst)
|
|
{
|
|
if(!os_create_dir(dst))
|
|
return false;
|
|
|
|
std::vector<SFile> curr_files=getFiles(src);
|
|
for(size_t i=0;i<curr_files.size();++i)
|
|
{
|
|
if(curr_files[i].isdir)
|
|
{
|
|
bool b=CopyFolder(src+os_file_sep()+curr_files[i].name, dst+os_file_sep()+curr_files[i].name);
|
|
if(!b)
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if(!os_create_hardlink(dst+os_file_sep()+curr_files[i].name, src+os_file_sep()+curr_files[i].name, false, NULL) )
|
|
{
|
|
BOOL b=CopyFileW( (src+os_file_sep()+curr_files[i].name).c_str(), (dst+os_file_sep()+curr_files[i].name).c_str(), FALSE);
|
|
if(!b)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
|
|
std::string getBackupfolderPath(void)
|
|
{
|
|
std::string fn;
|
|
#ifdef _WIN32
|
|
fn=trim(getFile("backupfolder"));
|
|
#else
|
|
fn=trim(getFile("/etc/urbackup/backupfolder"));
|
|
#endif
|
|
if(fn.find("\n")!=std::string::npos)
|
|
fn=getuntil("\n", fn);
|
|
if(fn.find("\r")!=std::string::npos)
|
|
fn=getuntil("\r", fn);
|
|
|
|
return fn;
|
|
}
|
|
|
|
std::string handleFilename(std::string fn)
|
|
{
|
|
fn=conv_filename(fn);
|
|
if(fn=="..")
|
|
{
|
|
return "";
|
|
}
|
|
return fn;
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
int exec_wait(const std::string& path, ...)
|
|
{
|
|
va_list vl;
|
|
va_start(vl, path);
|
|
|
|
std::vector<char*> args;
|
|
args.push_back(const_cast<char*>(path.c_str()));
|
|
|
|
while(true)
|
|
{
|
|
const char* p = va_arg(vl, const char*);
|
|
if(p==NULL) break;
|
|
args.push_back(const_cast<char*>(p));
|
|
}
|
|
va_end(vl);
|
|
|
|
args.push_back(NULL);
|
|
|
|
pid_t child_pid = fork();
|
|
|
|
if(child_pid==0)
|
|
{
|
|
environ = new char*[1];
|
|
*environ=NULL;
|
|
int rc = execvp(path.c_str(), args.data());
|
|
exit(rc);
|
|
}
|
|
else
|
|
{
|
|
int status;
|
|
waitpid(child_pid, &status, 0);
|
|
if(WIFEXITED(status))
|
|
{
|
|
return WEXITSTATUS(status);
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool chown_dir(const std::string& dir)
|
|
{
|
|
passwd* user_info = getpwnam("urbackup");
|
|
if(user_info)
|
|
{
|
|
int rc = chown(dir.c_str(), user_info->pw_uid, user_info->pw_gid);
|
|
return rc!=-1;
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
|
|
bool create_subvolume(std::string subvolume_folder)
|
|
{
|
|
#ifdef _WIN32
|
|
return os_create_dir(subvolume_folder);
|
|
#else
|
|
int rc=exec_wait(btrfs_cmd, "subvolume", "create", subvolume_folder.c_str(), NULL);
|
|
chown_dir(subvolume_folder);
|
|
return rc==0;
|
|
#endif
|
|
}
|
|
|
|
bool create_snapshot(std::string snapshot_src, std::string snapshot_dst)
|
|
{
|
|
#ifdef _WIN32
|
|
return CopyFolder(widen(snapshot_src), widen(snapshot_dst));
|
|
#else
|
|
int rc=exec_wait(btrfs_cmd, "subvolume", "snapshot", snapshot_src.c_str(), snapshot_dst.c_str(), NULL);
|
|
chown_dir(snapshot_dst);
|
|
return rc==0;
|
|
#endif
|
|
}
|
|
|
|
bool remove_subvolume(std::string subvolume_folder)
|
|
{
|
|
#ifdef _WIN32
|
|
return os_remove_nonempty_dir(widen(subvolume_folder));
|
|
#else
|
|
int rc=exec_wait(btrfs_cmd, "subvolume", "delete", subvolume_folder.c_str(), NULL);
|
|
return rc==0;
|
|
#endif
|
|
}
|
|
|
|
bool is_subvolume(std::string subvolume_folder)
|
|
{
|
|
#ifdef _WIN32
|
|
return true;
|
|
#else
|
|
int rc=exec_wait(btrfs_cmd, "subvolume", "list", subvolume_folder.c_str(), NULL);
|
|
return rc==0;
|
|
#endif
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
if(argc<2)
|
|
{
|
|
std::cout << "Not enough parameters" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
std::string cmd=argv[1];
|
|
|
|
std::string backupfolder=getBackupfolderPath();
|
|
|
|
if(backupfolder.empty())
|
|
{
|
|
std::cout << "Backupfolder not set" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
if(seteuid(0)!=0)
|
|
{
|
|
std::cout << "Cannot become root user" << std::endl;
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
if(cmd=="create")
|
|
{
|
|
if(argc<4)
|
|
{
|
|
std::cout << "Not enough parameters for create" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
std::string clientname=handleFilename(argv[2]);
|
|
std::string name=handleFilename(argv[3]);
|
|
|
|
std::string subvolume_folder=backupfolder+os_file_sep()+clientname+os_file_sep()+name;
|
|
|
|
return create_subvolume(subvolume_folder)?0:1;
|
|
}
|
|
else if(cmd=="snapshot")
|
|
{
|
|
if(argc<5)
|
|
{
|
|
std::cout << "Not enough parameters for snapshot" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
std::string clientname=handleFilename(argv[2]);
|
|
std::string src_name=handleFilename(argv[3]);
|
|
std::string dst_name=handleFilename(argv[4]);
|
|
|
|
std::string subvolume_src_folder=backupfolder+os_file_sep()+clientname+os_file_sep()+src_name;
|
|
std::string subvolume_dst_folder=backupfolder+os_file_sep()+clientname+os_file_sep()+dst_name;
|
|
|
|
return create_snapshot(subvolume_src_folder, subvolume_dst_folder)?0:1;
|
|
}
|
|
else if(cmd=="remove")
|
|
{
|
|
if(argc<4)
|
|
{
|
|
std::cout << "Not enough parameters for remove" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
std::string clientname=handleFilename(argv[2]);
|
|
std::string name=handleFilename(argv[3]);
|
|
|
|
std::string subvolume_folder=backupfolder+os_file_sep()+clientname+os_file_sep()+name;
|
|
|
|
return remove_subvolume(subvolume_folder)?0:1;
|
|
}
|
|
else if(cmd=="test")
|
|
{
|
|
std::string clientdir=backupfolder+os_file_sep()+"testA54hj5luZtlorr494";
|
|
|
|
bool create_dir_rc=os_create_dir(clientdir);
|
|
if(!create_dir_rc)
|
|
{
|
|
remove_subvolume(clientdir+os_file_sep()+"A");
|
|
remove_subvolume(clientdir+os_file_sep()+"B");
|
|
os_remove_dir(clientdir);
|
|
}
|
|
create_dir_rc = create_dir_rc || os_create_dir(clientdir);
|
|
if(create_dir_rc)
|
|
{
|
|
if(!create_subvolume(clientdir+os_file_sep()+"A") )
|
|
{
|
|
std::cout << "TEST FAILED: Creating test subvolume failed" << std::endl;
|
|
os_remove_dir(clientdir);
|
|
return 1;
|
|
}
|
|
|
|
bool suc=true;
|
|
|
|
if(!create_snapshot(clientdir+os_file_sep()+"A", clientdir+os_file_sep()+"B") )
|
|
{
|
|
std::cout << "TEST FAILED: Creating test snapshot failed" << std::endl;
|
|
suc=false;
|
|
}
|
|
|
|
if(suc)
|
|
{
|
|
writestring("test", clientdir+os_file_sep()+"A"+os_file_sep()+"test");
|
|
|
|
if(!os_create_hardlink(clientdir+os_file_sep()+"B"+os_file_sep()+"test", clientdir+os_file_sep()+"A"+os_file_sep()+"test", true, NULL))
|
|
{
|
|
std::cout << "TEST FAILED: Creating cross sub-volume reflink failed. Need Linux kernel >= 3.6." << std::endl;
|
|
suc=false;
|
|
}
|
|
else
|
|
{
|
|
if(getFile(clientdir+os_file_sep()+"B"+os_file_sep()+"test")!="test")
|
|
{
|
|
std::cout << "TEST FAILED: Cannot read reflinked file" << std::endl;
|
|
suc=false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!remove_subvolume(clientdir+os_file_sep()+"A") )
|
|
{
|
|
std::cout << "TEST FAILED: Removing subvolume A failed" << std::endl;
|
|
suc=false;
|
|
}
|
|
|
|
if(!remove_subvolume(clientdir+os_file_sep()+"B") )
|
|
{
|
|
std::cout << "TEST FAILED: Removing subvolume B failed" << std::endl;
|
|
suc=false;
|
|
}
|
|
|
|
if(!os_remove_dir(clientdir))
|
|
{
|
|
std::cout << "TEST FAILED: Removing test clientdir failed" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
if(!suc)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::cout << "TEST FAILED: Creating test clientdir \"" << clientdir << "\" failed" << std::endl;
|
|
return 1;
|
|
}
|
|
std::cout << "TEST OK" << std::endl;
|
|
return 0;
|
|
}
|
|
else if(cmd=="issubvolume")
|
|
{
|
|
if(argc<4)
|
|
{
|
|
std::cout << "Not enough parameters for issubvolume" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
std::string clientname=handleFilename(argv[2]);
|
|
std::string name=handleFilename(argv[3]);
|
|
|
|
std::string subvolume_folder=backupfolder+os_file_sep()+clientname+os_file_sep()+name;
|
|
|
|
return is_subvolume(subvolume_folder)?0:1;
|
|
}
|
|
else
|
|
{
|
|
std::cout << "Command not found" << std::endl;
|
|
return 1;
|
|
}
|
|
}
|
|
|