// // Created by kikab on 04.06.2018. // #include #include #include "DatSubsystems/DatBackupManager.h" #include "EasyLogging++/easylogging++.h" namespace LOTRO_DAT { DatBackupManager::DatBackupManager(DatFile *datFilePtr) {} /*! * \author Gi1dor * \date 11.07.2018 * Проверка доступности и корректности бэкапа dat файла * \param[in] backup_datname путь к файлу бэкапа * \returns true - если файл доступен для чтения его структура корректна. Иначе false */ bool DatBackupManager::CheckIfBackupAvailable(const std::string &backup_datname) { DatFile file; return file.Initialise(backup_datname, 0).result == SUCCESS && file.Initialized(); } /*! * \author Gi1dor * \date 11.07.2018 * Создание резервной копии инициализированного Dat файла. * * \param[in] backup_datname путь к файлу создаваемого бэкапа */ DatOperationResult<> DatBackupManager::CreateBackup(const std::string &backup_datname) { FILE* file = fopen(backup_datname.c_str(), "w+b"); if (!file) return DatOperationResult<>(ERROR, "CREATEBACKUP: cannot open file " + backup_datname); auto operation = CopyDatFile(*dat, file); fclose(file); if (operation.result != SUCCESS) return DatOperationResult<>(ERROR, "CREATEBACKUP: Error in copy dat file"); return DatOperationResult<>(SUCCESS); } /*! * \author Gi1dor * \date 11.07.2018 * Восстановление dat файла из резервной копии. Если восстановление не удалось, DatFile будет деинициализирован. * \param[in] backup_datname путь к файлу резервной копии */ DatOperationResult<> DatBackupManager::RestoreFromBackup(const std::string &backup_datname) { if (!CheckIfBackupAvailable(backup_datname)) return DatOperationResult<>(ERROR, "RESTOREFROMBACKUP: incorrect backup file " + backup_datname); DatFile backup_file; backup_file.Initialise(backup_datname, 0); std::string dat_filename = dat->GetIO().GetFilename().value; dat->Deinitialize(); FILE* file = fopen(backup_datname.c_str(), "w+b"); if (!file) return DatOperationResult<>(ERROR, "RESTOREFROMBACKUP: cannot open file " + backup_datname); auto operation = CopyDatFile(backup_file, file); fclose(file); if (operation.result == ERROR) return DatOperationResult<>(ERROR, "RESTOREFROMBACKUP: error in copy dat file"); dat->Initialise(dat_filename, dat->GetDatID()); return DatOperationResult<>(SUCCESS); } /*! * \author Gi1dor * \date 11.07.2018 * Удаление резервной копии. * \param[in] backup_datname путь к файлу резервной копии */ DatOperationResult<> DatBackupManager::RemoveBackup(const std::string &backup_datname) { if (remove(backup_datname.c_str()) != 0) LOG(INFO) << "Removed backup file " << backup_datname; return DatOperationResult<>(SUCCESS); } /*! * \author Gi1dor * \date 11.07.2018 * Копирует содержимое dat файла в файл target * \param[in] source dat файл для копирования. Должен быть проинициализирован * \param[in] target файл для записи. Должен быть открыт на запись. * \warning Файл target после выполнения функции НЕ будет закрыт. Требуется закрыть командой fclose; */ DatOperationResult<> DatBackupManager::CopyDatFile(DatFile &source, FILE *target) { long long parts_count = source.GetIO().file_size / COPY_BLOCK_SIZE + (source.GetIO().file_size % COPY_BLOCK_SIZE != 0); long long newfile_size = 0; long long elapsed_size = source.GetIO().file_size - newfile_size; BinaryData data(COPY_BLOCK_SIZE); for (unsigned i = 0; i < parts_count; i++) { auto operation = source.GetIO().ReadData(data, std::min((long long)(COPY_BLOCK_SIZE), elapsed_size), newfile_size); if (operation.result == ERROR) return DatOperationResult<>(ERROR, "Copy failed. Read data error"); fwrite(data.data(), data.size(), 1, target); newfile_size += std::min((long long)(COPY_BLOCK_SIZE), elapsed_size); elapsed_size -= std::min((long long)(COPY_BLOCK_SIZE), elapsed_size); } return DatOperationResult<>(SUCCESS); } }