#include "FilesystemManager.h" #include "../btrfs/btrfsplugin/IBtrfsFactory.h" #include "DocanyMount.h" #include "../stringtools.h" #include "../fsimageplugin/IFSImageFactory.h" #include "../fsimageplugin/IVHDFile.h" #include "../clouddrive/IClouddriveFactory.h" #include "../common/miniz.h" extern IBtrfsFactory* btrfs_fak; extern IFSImageFactory* image_fak; extern IClouddriveFactory* clouddrive_fak; namespace { #include "cache_init_vhdx.h" std::string get_cache_init_vhdx() { size_t out_len; void* cdata = tinfl_decompress_mem_to_heap(btrfs2_vhdx_z, btrfs2_vhdx_z_len, &out_len, TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32); if (cdata == NULL) { return std::string(); } std::string ret(reinterpret_cast(cdata), reinterpret_cast(cdata) + out_len); mz_free(cdata); return ret; } bool copy_vhdx(const std::string& src_fn, const std::string& dst_fn, int64 dst_size) { std::unique_ptr src_vhdx(image_fak->createVHDFile(src_fn, true, 0, 2 * 1024 * 1024, false, IFSImageFactory::ImageFormat_VHDX)); if (!src_vhdx || !src_vhdx->isOpen()) return false; std::unique_ptr dst_vhdx(image_fak->createVHDFile(dst_fn + ".new", false, dst_size, 2 * 1024 * 1024, true, IFSImageFactory::ImageFormat_VHDX)); if (!dst_vhdx || !dst_vhdx->isOpen()) return false; std::vector buf(512 * 1024); unsigned int blocksize = src_vhdx->getBlocksize(); for (int64 pos = 0; pos < src_vhdx->Size();) { if (!src_vhdx->this_has_sector()) { pos += blocksize; src_vhdx->Seek(pos); dst_vhdx->Seek(pos); continue; } int64 spos = pos; while (pos < spos + blocksize) { size_t toread = (std::min)(static_cast((spos + blocksize) - pos), buf.size()); size_t read; if (!src_vhdx->Read(buf.data(), toread, read)) return false; if (!dst_vhdx->Write(buf.data(), static_cast<_u32>(read)) != read) return false; pos += read; } } src_vhdx.reset(); dst_vhdx.reset(); return os_rename_file(dst_fn + ".new", dst_fn); } } std::mutex FilesystemManager::mutex; std::map FilesystemManager::filesystems; bool FilesystemManager::openFilesystemImage(const std::string& url, const std::string& url_params, const str_map& secret_params) { std::lock_guard lock(mutex); if (filesystems.find(url) != filesystems.end()) return true; IFile* img; if (next(url, 0, "file://")) { std::string fpath = url.substr(7); std::string ext = findextension(fpath); if (ext == "img" || ext == "raw") { img = Server->openFile(fpath, MODE_RW); } else if (ext == "vhdx") { IVHDFile* vhdfile = image_fak->createVHDFile(fpath, false, 0, 2 * 1024 * 1024, false, IFSImageFactory::ImageFormat_VHDX); if (vhdfile == nullptr || !vhdfile->isOpen()) return false; img = vhdfile; } } else if (next(url, 0, "s3://")) { IClouddriveFactory::CloudSettings settings; settings.endpoint = IClouddriveFactory::CloudEndpoint::S3; std::string authorization = getbetween("s3://", "@", url); std::string server = getafter("@", url); if (server.empty()) { server = url.substr(5); } settings.s3_settings.access_key = getuntil(":", authorization); settings.s3_settings.secret_access_key = getafter(":", authorization); settings.s3_settings.endpoint = getuntil("/", server); settings.s3_settings.bucket_name = getafter("/", server); auto encryption_key_it = secret_params.find("encryption_key"); if (encryption_key_it != secret_params.end()) settings.encryption_key = encryption_key_it->second; if (settings.s3_settings.access_key.empty()) { auto access_key_it = secret_params.find("access_key"); if (access_key_it != secret_params.end()) settings.s3_settings.access_key = access_key_it->second; } if (settings.s3_settings.secret_access_key.empty()) { auto secret_access_key_it = secret_params.find("secret_access_key"); if (secret_access_key_it != secret_params.end()) settings.s3_settings.secret_access_key = secret_access_key_it->second; } std::string nurl = "s3://" + server; std::string cacheid = Server->GenerateHexMD5(nurl); std::string cache_img_path = "urbackup/" + cacheid + ".vhdx"; settings.s3_settings.cache_db_path = "urbackup/" + cacheid + ".db"; if (!FileExists(cache_img_path)) { if (!FileExists("urbackup/cache_init.vhdx")) { std::unique_ptr f(Server->openFile("urbackup/cache_init.vhdx.new", MODE_WRITE)); if (!f) return false; std::string data = get_cache_init_vhdx(); if (f->Write(data) != data.size()) return false; if (!f->Sync()) return false; f.reset(); if (!os_rename_file("urbackup/cache_init.vhdx.new", "urbackup/cache_init.vhdx")) return false; } if (!copy_vhdx("urbackup/cache_init.vhdx", cache_img_path, 1LL*1024*1024*1024)) { Server->Log("Could not copy urbackup/cache_init.vhdx to " + cache_img_path + ". " + os_last_error_str(), LL_ERROR); return false; } } IVHDFile* cachevhdx = image_fak->createVHDFile(cache_img_path, false, 0, 2 * 1024 * 1024, false, IFSImageFactory::ImageFormat_VHDX); if (cachevhdx == nullptr || !cachevhdx->isOpen()) { Server->Log("Could not open cache vhdx at " + cache_img_path, LL_ERROR); return false; } IBackupFileSystem* cachefs = btrfs_fak->openBtrfsImage(cachevhdx); if (cachefs == nullptr) { Server->Log("Could not open cache btrfs at " + cache_img_path, LL_ERROR); return false; } settings.size = 100LL * 1024 * 1024 * 1024 * 1024; //100TB img = clouddrive_fak->createCloudFile(cachefs, settings); } if (img == nullptr) return false; IBackupFileSystem* fs = btrfs_fak->openBtrfsImage(img); if (fs == nullptr) return false; filesystems[url] = fs; return true; } bool FilesystemManager::mountFileSystem(const std::string& url, const std::string& url_params, const str_map& secret_params, const std::string& mount_path) { if (!openFilesystemImage(url, url_params, secret_params)) return false; std::lock_guard lock(mutex); if (filesystems.find(url) == filesystems.end()) { return false; } IBackupFileSystem* fs = filesystems[url]; return dokany_mount(fs, mount_path); } IBackupFileSystem* FilesystemManager::getFileSystem(const std::string& path) { std::lock_guard lock(mutex); auto it = filesystems.find(path); if (it == filesystems.end()) return nullptr; return it->second; }