mirror of
https://github.com/uroni/urbackup_backend.git
synced 2025-10-26 11:36:50 +00:00
282 lines
5.4 KiB
C++
282 lines
5.4 KiB
C++
#include "partclone.h"
|
|
#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
|
|
#include "../common/miniz.h"
|
|
#include <stdio.h>
|
|
#include "../urbackupcommon/os_functions.h"
|
|
#include "../stringtools.h"
|
|
|
|
#ifndef _WIN32
|
|
#define _popen popen
|
|
#define _pclose pclose
|
|
#endif
|
|
|
|
#if defined(__ANDROID__)
|
|
#include <unistd.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <sys/un.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#define fsblkcnt64_t fsblkcnt_t
|
|
#include "../urbackupcommon/android_popen.h"
|
|
#endif
|
|
|
|
Partclone::Partclone(const std::string& pDev, IFSImageFactory::EReadaheadMode read_ahead, bool background_priority, IFsNextBlockCallback* next_block_callback)
|
|
: Filesystem(pDev, read_ahead, next_block_callback), bitmap(nullptr)
|
|
{
|
|
init();
|
|
initReadahead(read_ahead, background_priority);
|
|
}
|
|
|
|
Partclone::Partclone(IFile* pDev, IFSImageFactory::EReadaheadMode read_ahead, bool background_priority, IFsNextBlockCallback* next_block_callback)
|
|
:Filesystem(pDev, next_block_callback), bitmap(nullptr)
|
|
{
|
|
init();
|
|
initReadahead(read_ahead, background_priority);
|
|
}
|
|
|
|
Partclone::~Partclone()
|
|
{
|
|
delete[] bitmap;
|
|
}
|
|
|
|
void Partclone::logFileChanges(std::string volpath, int64 min_size, char* fc_bitmap)
|
|
{
|
|
}
|
|
|
|
int64 Partclone::getBlocksize(void)
|
|
{
|
|
return block_size;
|
|
}
|
|
|
|
int64 Partclone::getSize(void)
|
|
{
|
|
return total_size;
|
|
}
|
|
|
|
const unsigned char* Partclone::getBitmap(void)
|
|
{
|
|
return bitmap;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
#define HEADER_ENDIAN_MAGIC 0xC0DE
|
|
|
|
#pragma pack(push)
|
|
#pragma pack(1)
|
|
struct partclone_header
|
|
{
|
|
char magic[16];
|
|
char partclone_version[14];
|
|
char image_version[4];
|
|
unsigned short endianess;
|
|
char fs[16];
|
|
uint64 device_size;
|
|
uint64 total_blocks;
|
|
uint64 used_blocks;
|
|
uint64 used_bitmap;
|
|
unsigned int block_size;
|
|
unsigned int feature_size;
|
|
unsigned short f_image_version;
|
|
unsigned short cpu_bits;
|
|
unsigned short checksum_mode;
|
|
unsigned short checksum_size;
|
|
unsigned int blocks_per_checksum;
|
|
unsigned char reseed_checksum;
|
|
unsigned char bitmap_mode;
|
|
unsigned int crc;
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
bool read_in(FILE* in, char* buf, size_t buf_size)
|
|
{
|
|
do
|
|
{
|
|
size_t nread = fread(buf, 1, buf_size, in);
|
|
if (nread == 0
|
|
&& (feof(in)
|
|
|| ferror(in)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
buf += nread;
|
|
buf_size -= nread;
|
|
} while (buf_size > 0);
|
|
|
|
return true;
|
|
}
|
|
|
|
class AutoClose
|
|
{
|
|
FILE* in;
|
|
public:
|
|
AutoClose(FILE* in)
|
|
: in(in)
|
|
{}
|
|
|
|
~AutoClose() {
|
|
_pclose(in);
|
|
}
|
|
};
|
|
|
|
#ifdef __ANDROID__
|
|
class AutoCloseAnd
|
|
{
|
|
POFILE* in;
|
|
public:
|
|
AutoCloseAnd(POFILE* in)
|
|
: in(in)
|
|
{}
|
|
|
|
~AutoCloseAnd() {
|
|
and_pclose(in);
|
|
}
|
|
};
|
|
#endif
|
|
}
|
|
|
|
void Partclone::init()
|
|
{
|
|
if (has_error)
|
|
return;
|
|
|
|
std::string cmd = "blkid -o export \""+dev->getFilename()+"\"";
|
|
std::string blkid_out;
|
|
if(os_popen(cmd, blkid_out)!=0)
|
|
{
|
|
has_error = true;
|
|
return;
|
|
}
|
|
|
|
fstype = strlower(trim(getbetween("TYPE=", "\n", blkid_out)));
|
|
|
|
Server->Log("Detected fs type "+fstype);
|
|
|
|
if(fstype!="ext2" && fstype!="ext3"
|
|
&& fstype!="ext4" && fstype!="xfs")
|
|
{
|
|
Server->Log("Fs type not supported");
|
|
has_error = true;
|
|
return;
|
|
}
|
|
|
|
cmd = "partclone."+fstype+" -o - -c -s \"" + dev->getFilename() + "\"";
|
|
FILE* in = nullptr;
|
|
#ifdef __ANDROID__
|
|
POFILE* pin = NULL;
|
|
#endif
|
|
|
|
#ifdef __ANDROID__
|
|
pin = and_popen(cmd.c_str(), "r");
|
|
if (pin != NULL) in = pin->fp;
|
|
#elif __linux__
|
|
in = _popen(cmd.c_str(), "re");
|
|
if (!in) in = _popen(cmd.c_str(), "r");
|
|
#else
|
|
in = _popen(cmd.c_str(), "r");
|
|
#endif
|
|
|
|
if (in == nullptr)
|
|
{
|
|
has_error = true;
|
|
return;
|
|
}
|
|
|
|
#ifdef __ANDROID__
|
|
AutoCloseAnd close_in(pin);
|
|
#else
|
|
AutoClose close_in(in);
|
|
#endif
|
|
|
|
partclone_header header;
|
|
if (!read_in(in, reinterpret_cast<char*>(&header), sizeof(header)))
|
|
{
|
|
has_error = true;
|
|
return;
|
|
}
|
|
|
|
unsigned int curr_crc = mz_crc32(0, reinterpret_cast<unsigned char*>(&header), sizeof(header) - sizeof(unsigned int));
|
|
curr_crc = ~curr_crc;
|
|
|
|
if (curr_crc != header.crc)
|
|
{
|
|
has_error = true;
|
|
return;
|
|
}
|
|
|
|
header.magic[15] = 0;
|
|
|
|
if (std::string(header.magic) != "partclone-image")
|
|
{
|
|
has_error = true;
|
|
return;
|
|
}
|
|
|
|
std::string image_version(header.image_version, 4);
|
|
if (watoi(image_version) != 2)
|
|
{
|
|
has_error = true;
|
|
return;
|
|
}
|
|
|
|
if (header.endianess != HEADER_ENDIAN_MAGIC)
|
|
{
|
|
has_error = true;
|
|
return;
|
|
}
|
|
|
|
if (header.bitmap_mode != 1)
|
|
{
|
|
has_error = true;
|
|
return;
|
|
}
|
|
|
|
size_t bitmap_bytes = (header.total_blocks + 7) / 8;
|
|
|
|
bitmap = new unsigned char[bitmap_bytes];
|
|
|
|
if (!read_in(in, reinterpret_cast<char*>(bitmap), bitmap_bytes))
|
|
{
|
|
has_error = true;
|
|
return;
|
|
}
|
|
|
|
unsigned int bitmap_crc;
|
|
if (!read_in(in, reinterpret_cast<char*>(&bitmap_crc), sizeof(bitmap_crc)))
|
|
{
|
|
has_error=true;
|
|
return;
|
|
}
|
|
|
|
curr_crc = mz_crc32(mz_crc32(0, nullptr, 0), bitmap, bitmap_bytes);
|
|
curr_crc = ~curr_crc;
|
|
|
|
if (curr_crc != bitmap_crc)
|
|
{
|
|
has_error = true;
|
|
return;
|
|
}
|
|
|
|
block_size = header.block_size;
|
|
total_size = header.device_size;
|
|
|
|
unsigned int* bitmap_test = reinterpret_cast<unsigned int*>(bitmap);
|
|
const unsigned int bits_per = sizeof(unsigned int) * 8;
|
|
|
|
for (unsigned int nr = 0; nr < total_size/ block_size; ++nr)
|
|
{
|
|
unsigned int offset = nr / bits_per;
|
|
unsigned int bit = nr & (bits_per - 1);
|
|
bool has_bit = (bitmap_test[offset] >> bit) & 1;
|
|
|
|
assert(hasBlock(nr) == has_bit);
|
|
}
|
|
}
|
|
|
|
std::string Partclone::getType()
|
|
{
|
|
return fstype;
|
|
}
|