From 9728fa5f89b18b761a355a141a8e6bc4a8106bdb Mon Sep 17 00:00:00 2001 From: Martin Date: Sun, 10 May 2020 13:02:01 +0200 Subject: [PATCH] Remove Windows registry hive files from CBT --- urbackupclient/client.cpp | 118 ++++++++++++++++++++++++++++++++++- urbackupclient/client.h | 6 ++ urbackupclient/clientdao.cpp | 2 +- 3 files changed, 124 insertions(+), 2 deletions(-) diff --git a/urbackupclient/client.cpp b/urbackupclient/client.cpp index b99db79f..3988e9e1 100644 --- a/urbackupclient/client.cpp +++ b/urbackupclient/client.cpp @@ -6178,6 +6178,55 @@ bool IndexThread::normalizeVolume(std::string & volume) } bool IndexThread::finishCbt(std::string volume, int shadow_id, std::string snap_volume, bool for_image_backup) +inline int64 roundDown(int64 numToRound, int64 multiple) +{ + return ((numToRound / multiple) * multiple); +} + +bool IndexThread::addFileToCbt(const std::string& fpath, const DWORD& blocksize, const PURBCT_BITMAP_DATA& bitmap_data) +{ + std::auto_ptr hive_file(Server->openFile(fpath, MODE_READ)); + + if (hive_file.get() != nullptr) + { + bool ret = true; + bool more_exts = true; + int64 offset = 0; + while (more_exts) + { + std::vector exts = hive_file->getFileExtents(offset, blocksize, more_exts); + for (size_t j = 0; j < exts.size(); ++j) + { + for (int64 k = roundDown(exts[j].volume_offset, URBT_BLOCKSIZE); + k < exts[j].volume_offset + exts[j].size; k += URBT_BLOCKSIZE) + { + int64 block = k / URBT_BLOCKSIZE; + int64 bitmap_byte_wmagic = block / 8; + int64 real_block_size = bitmap_data->SectorSize - URBT_MAGIC_SIZE; + int64 bitmap_byte = (bitmap_byte_wmagic / real_block_size) + * bitmap_data->SectorSize + URBT_MAGIC_SIZE + bitmap_byte_wmagic % real_block_size; + unsigned int bitmap_bit = block % 8; + + if (bitmap_byte >= bitmap_data->BitmapSize) + { + VSSLog("Registry hive extent outside of cbt data", LL_WARNING); + ret = false; + } + else + { + bitmap_data->Bitmap[bitmap_byte] |= (1 << bitmap_bit); + } + } + } + } + return ret; + } + else + { + return false; + } +} + { #ifdef _WIN32 ScopedUnlockCbtMutex unlock_cbt_mutex; @@ -6269,7 +6318,18 @@ bool IndexThread::finishCbt(std::string volume, int shadow_id, std::string snap_ { BytesPerSector = alignmentDescr.BytesPerPhysicalSector; } - + + DWORD sectors_per_cluster; + DWORD bytes_per_sector; + DWORD NumberOfFreeClusters; + DWORD TotalNumberOfClusters; + b = GetDiskFreeSpaceW((Server->ConvertToWchar(volume) + L"\\").c_str(), §ors_per_cluster, &bytes_per_sector, &NumberOfFreeClusters, &TotalNumberOfClusters); + if (!b) + { + VSSLog("Error in GetDiskFreeSpaceW. "+os_last_error_str(), LL_ERROR); + return false; + } + DWORD blocksize = bytes_per_sector * sectors_per_cluster; ULONGLONG bitmapBlocks = lengthInfo.Length.QuadPart / URBT_BLOCKSIZE + (lengthInfo.Length.QuadPart%URBT_BLOCKSIZE == 0 ? 0 : 1); @@ -6501,6 +6561,62 @@ bool IndexThread::finishCbt(std::string volume, int shadow_id, std::string snap_ } } + if (!snap_volume.empty()) + { + HKEY profile_list; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, + Server->ConvertToWchar("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList").c_str(), + 0, KEY_READ, &profile_list) == ERROR_SUCCESS) + { + wchar_t buf[300]; + + for (DWORD i = 0; RegEnumKeyW(profile_list, i, buf, sizeof(buf) == ERROR_SUCCESS); ++i) + { + DWORD rsize = sizeof(buf) * sizeof(wchar_t); + if (RegGetValueW(profile_list, std::wstring(buf).c_str(), L"ProfileImagePath", + RRF_RT_REG_SZ, NULL, buf, &rsize) == ERROR_SUCCESS) + { + std::string profile_path = Server->ConvertFromWchar(buf); + + if (next(profile_path, 0, volume)) + { + profile_path.erase(0, volume.size()); + + addFileToCbt(snap_volume + profile_path + "\\NTUSER.DAT", blocksize, bitmap_data); + for (size_t n = 1; n < 100; ++n) + { + if (!addFileToCbt(snap_volume + profile_path + "\\ntuser.dat.LOG"+convert(n), blocksize, bitmap_data)) + break; + } + } + } + } + + RegCloseKey(profile_list); + } + + if (strlower(volume) == "c:") + { + char* locations[] = { "\\Windows\\System32\\config\\SYSTEM", + "\\Windows\\System32\\config\\SOFTWARE", + "\\Windows\\System32\\config\\SECURITY", + "\\Windows\\System32\\config\\SAM", + "\\Windows\\System32\\config\\DEFAULT" }; + + for (size_t i = 0; i < sizeof(locations) / sizeof(locations[0]); ++i) + { + std::string loc = locations[i]; + + addFileToCbt(snap_volume + loc, blocksize, bitmap_data); + for (size_t n = 1; n < 100; ++n) + { + if (!addFileToCbt(snap_volume + loc +"LOG" + convert(n), blocksize, bitmap_data)) + break; + } + } + } + } + if (for_image_backup) { if (!saveMergeBitmap("urbackup\\hdat_file_" + conv_filename(strlower(volume)) + ".cbt", bitmap_data)) diff --git a/urbackupclient/client.h b/urbackupclient/client.h index a829bf63..4756b393 100644 --- a/urbackupclient/client.h +++ b/urbackupclient/client.h @@ -310,6 +310,11 @@ struct SQueueRef } }; +#ifdef _WIN32 +struct _URBCT_BITMAP_DATA; +typedef struct _URBCT_BITMAP_DATA* PURBCT_BITMAP_DATA; +#endif + class IndexThread : public IThread, public IFileServ::IReadErrorCallback, public IDeregisterFileSrvScriptFn { public: @@ -461,6 +466,7 @@ private: void removeUnconfirmedVssDirs(); std::string expandPath(BSTR pathStr); void removeBackupcomReferences(IVssBackupComponents *backupcom); + bool addFileToCbt(const std::string& fpath, const DWORD& blocksize, const PURBCT_BITMAP_DATA& bitmap_data); #else bool start_shadowcopy_lin( SCDirs * dir, std::string &wpath, bool for_imagebackup, bool * &onlyref, bool* not_configured); std::string get_snapshot_script_location(const std::string& name); diff --git a/urbackupclient/clientdao.cpp b/urbackupclient/clientdao.cpp index 807013ed..603e8c15 100644 --- a/urbackupclient/clientdao.cpp +++ b/urbackupclient/clientdao.cpp @@ -40,7 +40,7 @@ void ClientDAO::prepareQueries() { q_get_files=db->Prepare("SELECT data, num, generation FROM files WHERE name=? AND tgroup=?", false); q_add_files=db->Prepare("INSERT OR REPLACE INTO files (name, tgroup, num, data) VALUES (?,?,?,?)", false); - q_get_dirs=db->Prepare("SELECT name, path, id, optional, tgroup, symlinked, server_default, reset_keep FROM backupdirs", false); + q_get_dirs=db->Prepare("SELECT name, path, id, optional, tgroup, symlinked, server_default, reset_keep FROM backupdirs ORDER BY id ASC", false); q_remove_all=db->Prepare("DELETE FROM files", false); q_get_changed_dirs=db->Prepare("SELECT id, name FROM mdirs WHERE name GLOB ? UNION SELECT id, name FROM mdirs_backup WHERE name GLOB ?", false); q_modify_files=db->Prepare("UPDATE files SET data=?, num=?, generation=? WHERE name=? AND tgroup=? AND generation=?", false);