Преглед на файлове

Completed BackupManager module. Needs testing and adding to patcher example

Ivan Arkhipov преди 5 години
родител
ревизия
fb9d956188
променени са 5 файла, в които са добавени 138 реда и са изтрити 26 реда
  1. 3 2
      include/DatFile.h
  2. 15 5
      include/DatSubsystems/DatBackupManager.h
  3. 9 3
      src/DatFile.cpp
  4. 110 15
      src/DatSubsystems/DatBackupManager.cpp
  5. 1 1
      src/Examples/patcher_example.cpp

+ 3 - 2
include/DatFile.h

@@ -48,11 +48,12 @@ namespace LOTRO_DAT {
         DatFile(DatFile &&other) = default;
         DatFile &operator=(const DatFile &other) = delete;
         DatFile &operator=(DatFile &&other) = default;
+        ~DatFile();
 
         DatLocaleManager &getLocaleManager();
         DatExporter &getExporter();
         DatPatcher &getPatcher();
-//        DatBackupManager &getBackupManager();
+        DatBackupManager &getBackupManager();
         DatIO &getIO();
         DatFileSystem &getFileSystem();
 
@@ -67,7 +68,7 @@ namespace LOTRO_DAT {
         std::unique_ptr<DatLocaleManager> localeManager_;
         std::unique_ptr<DatPatcher> patcher_;
         std::unique_ptr<DatExporter> exporter_;
-//        std::unique_ptr<DatBackupManager> backupManager_;
+        std::unique_ptr<DatBackupManager> backupManager_;
         bool initialized_;
         long long dat_id_;
     };

+ 15 - 5
include/DatSubsystems/DatBackupManager.h

@@ -12,6 +12,16 @@ extern "C++" {
 namespace LOTRO_DAT {
     class DatFile;
 
+    /*!
+     * \brief Модуль резервного копирования файлов
+     * \author Gi1dor
+     * \date 30.06.2018
+     *
+     * Класс для осуществления резервного копирования без деинициализации модулей и потери данных dat файла.
+     *
+     * \warning Объекты этого класса не должны создаваться отдельно! Созданием и управлением ими занимается класс DatFile
+     */
+
     class DatBackupManager {
     public:
         DatBackupManager() = delete;
@@ -24,9 +34,7 @@ namespace LOTRO_DAT {
 
         explicit DatBackupManager(DatFile *datFilePtr);
 
-        void Init();
-
-        bool CheckIfBackupExists(const std::string &backup_datname);
+        bool CheckIfBackupAvailable(const std::string &backup_datname);
 
         DatOperationResult<> CreateBackup(const std::string &backup_datname);
 
@@ -34,11 +42,13 @@ namespace LOTRO_DAT {
 
         DatOperationResult<> RemoveBackup(const std::string &backup_datname);
 
-        void DeInit();
-
     private:
+
+        DatOperationResult<> CopyDatFile(DatFile &source, FILE* target);
+
         DatFile *dat;
 
+        const unsigned COPY_BLOCK_SIZE = 16 * 1024 * 1024; // 16 megabytes
     };
 }
 };

+ 9 - 3
src/DatFile.cpp

@@ -56,6 +56,12 @@ namespace LOTRO_DAT {
 //        backupManager_ = std::make_unique<DatBackupManager>(this);
     }
 
+
+    DatFile::~DatFile() {
+        if (Initialized())
+            Deinitialize();
+    }
+
     LOTRO_DAT::DatLocaleManager &DatFile::getLocaleManager() {
         return *localeManager_;
     }
@@ -68,9 +74,9 @@ namespace LOTRO_DAT {
         return *patcher_;
     }
 
-//    DatBackupManager &DatFile::getBackupManager() {
-//        return *backupManager_;
-//    }
+    DatBackupManager &DatFile::getBackupManager() {
+        return *backupManager_;
+    }
 
     DatIO &DatFile::getIO() {
         return *io_;

+ 110 - 15
src/DatSubsystems/DatBackupManager.cpp

@@ -2,29 +2,124 @@
 // Created by kikab on 04.06.2018.
 //
 
+#include <DatFile.h>
+#include <DatSubsystems/DatBackupManager.h>
+
 #include "DatSubsystems/DatBackupManager.h"
 #include "EasyLogging++/easylogging++.h"
 
-LOTRO_DAT::DatBackupManager::DatBackupManager(LOTRO_DAT::DatFile *datFilePtr) {
+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->dat_id_);
+        return DatOperationResult<>(SUCCESS);
+    }
+
 
-}
+    /*!
+     * \author Gi1dor
+     * \date 11.07.2018
+     * Удаление резервной копии.
+     * \param[in] backup_datname путь к файлу резервной копии
+     */
 
-void LOTRO_DAT::DatBackupManager::Init() {
+    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;
+     */
 
-bool LOTRO_DAT::DatBackupManager::CheckIfBackupExists(const std::string &backup_datname) {
-    return false;
-}
+    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;
 
-LOTRO_DAT::DatOperationResult<> LOTRO_DAT::DatBackupManager::CreateBackup(const std::string &backup_datname) {
-}
+        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);
 
-LOTRO_DAT::DatOperationResult<> LOTRO_DAT::DatBackupManager::RestoreFromBackup(const std::string &backup_datname) {
-}
+            newfile_size += std::min((long long)(COPY_BLOCK_SIZE), elapsed_size);
+            elapsed_size -= std::min((long long)(COPY_BLOCK_SIZE), elapsed_size);
+        }
 
-LOTRO_DAT::DatOperationResult<> LOTRO_DAT::DatBackupManager::RemoveBackup(const std::string &backup_datname) {
-}
+        return DatOperationResult<>(SUCCESS);
+    }
 
-void LOTRO_DAT::DatBackupManager::DeInit() {
-}
+}

+ 1 - 1
src/Examples/patcher_example.cpp

@@ -181,7 +181,7 @@ int main() {
 //        }
 //
 //        if (cmd == 10) {
-//            std::cout << "Backup file " << (file.CheckIfBackupExists("clie_local_En.backup") ? "exists!" : "doesn't exist.") << std::endl;
+//            std::cout << "Backup file " << (file.CheckIfBackupAvailable("clie_local_En.backup") ? "exists!" : "doesn't exist.") << std::endl;
 //        }
     }
     //system("pause");