#include "skiphash_copy.h" #include #include "../../urbackupcommon/chunk_hasher.h" #include "../../stringtools.h" #include "../../urbackupcommon/os_functions.h" #include bool skiphash_copy(const std::string& src_path, const std::string& dst_path, const std::string& hashinput_path) { std::unique_ptr src(Server->openFile(os_file_prefix(src_path), MODE_READ_SEQUENTIAL)); if(!src.get()) { Server->Log("Could not open source file for reading at \"" + src_path+"\"", LL_ERROR); return false; } std::unique_ptr hashoutput(Server->openFile(os_file_prefix(dst_path+".hash"), MODE_WRITE)); if(!hashoutput.get()) { Server->Log("Could not open hash output for writing at \""+dst_path+".hash\"", LL_ERROR); return false; } bool dst_exists = Server->fileExists(dst_path); std::unique_ptr dst(Server->openFile(os_file_prefix(dst_path), MODE_RW)); if(!dst.get()) { dst.reset(Server->openFile(os_file_prefix(dst_path), MODE_WRITE)); } if(!dst.get()) { Server->Log("Could not open output file for writing at \""+dst_path+"\"", LL_ERROR); return false; } std::unique_ptr hashinput; if(!hashinput_path.empty()) { hashinput.reset(Server->openFile(os_file_prefix(hashinput_path), MODE_READ_DEVICE)); if(!hashinput.get()) { Server->Log("Could not open hash input file at \""+hashinput_path+"\"", LL_ERROR); return false; } } if(!dst_exists || !hashinput.get()) { Server->Log("Destination file does not exist or there is no hash input. Performing full copy (with hash output)...", LL_INFO); bool ret = build_chunk_hashs(src.get(), hashoutput.get(), NULL, dst.get(), false, NULL, NULL, true); if (!ret) { Server->Log("Copying failed.", LL_ERROR); } if (ret && dst->Size() != src->Size()) { ret = dst->Resize(src->Size()); if (!ret) { Server->Log("Could not resize destionation file to size " + convert(src->Size()) + ". " + os_last_error_str(), LL_ERROR); } } return ret; } else { int64 inplace_written = 0; bool ret = build_chunk_hashs(src.get(), hashoutput.get(), NULL, dst.get(), true, &inplace_written, hashinput.get(), true); float skipped_pc=0; if(src->Size()>0) { if (inplace_written == 0) { skipped_pc = 100.f; } else { skipped_pc = 100.f - (100.f*src->Size()) / inplace_written; } } if (!ret) { Server->Log("Copying failed.", LL_ERROR); } if (ret && dst->Size()!=src->Size()) { ret = dst->Resize(src->Size()); if (!ret) { Server->Log("Could not resize destionation file to size " + convert(src->Size()) + ". " + os_last_error_str(), LL_ERROR); } } Server->Log("Wrote "+PrettyPrintBytes(inplace_written) +". Skipped "+PrettyPrintBytes((std::max)(0LL, src->Size()-inplace_written))+" ("+ convert(static_cast(skipped_pc+0.5f))+"%)", LL_INFO); return ret; } } int skiphash_copy_file() { std::string src = Server->getServerParameter("src"); std::string dst = Server->getServerParameter("dst"); std::string hashsrc = Server->getServerParameter("hashsrc"); return skiphash_copy((src), (dst), (hashsrc)) ? 0 : 1; }