diff --git a/CHANGELOG.md b/CHANGELOG.md index d37fee16..bed6a274 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -176,7 +176,8 @@ The git repositories are hosted at the following sites: ### Fixed -* Prevent deletion of backup files during restore process. (#1249) +* Fixed Device Management-Backup and Restore-B functionality to keep + configuration files during the restore operation. (#1250) * Fixed Device Management-Backup and Restore-B Backup_Failure_Timeout to count down and abort at BACKUP_FAILURE or RESTORE_FAILURE states, successful STARTBACKUP to end in PERFORMING_A_BACKUP state, diff --git a/src/bacnet/basic/object/device.c b/src/bacnet/basic/object/device.c index 989e60a3..12727315 100644 --- a/src/bacnet/basic/object/device.c +++ b/src/bacnet/basic/object/device.c @@ -2463,6 +2463,32 @@ uint32_t Device_Configuration_File(unsigned index) return instance; } +/** + * @brief Determine if the given file instance number is one of the configured + * configuration file object instances. + * @param instance [in] The object instance number to check + * @return True if the given instance is one of the configured configuration + * file object instances, else False. + */ +bool Device_Is_Configuration_File(uint32_t instance) +{ + bool status = false; + +#if BACNET_BACKUP_FILE_COUNT + unsigned i; + for (i = 0; i < BACNET_BACKUP_FILE_COUNT; i++) { + if (Configuration_Files[i] == instance) { + status = true; + break; + } + } +#else + (void)instance; +#endif + + return status; +} + /** * @brief Encode a BACnetARRAY property element * @param object_instance [in] BACnet network port object instance number @@ -3755,8 +3781,9 @@ bool Device_Delete_Object(BACNET_DELETE_OBJECT_DATA *data) } /** - * @brief Loops through all the objects and deletes them, + * @brief Loops through all the children objects and deletes them, * if DeleteObject service is supported by the object type. + * Skips the Device object itself and any configuration files. */ void Device_Delete_Objects(void) { @@ -3766,6 +3793,10 @@ void Device_Delete_Objects(void) pObject = Object_Table; while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { + if (pObject->Object_Type == OBJECT_DEVICE) { + pObject++; + continue; + } count = 0; if (pObject->Object_Count) { count = pObject->Object_Count(); @@ -3775,6 +3806,12 @@ void Device_Delete_Objects(void) if ((pObject->Object_Delete) && (pObject->Object_Index_To_Instance)) { instance = pObject->Object_Index_To_Instance(count); + /* keep Backup-Restore Configuration files */ + if (pObject->Object_Type == OBJECT_FILE) { + if (Device_Is_Configuration_File(instance)) { + continue; + } + } pObject->Object_Delete(instance); } } @@ -3852,20 +3889,12 @@ void Device_End_Restore(void) #if defined BACNET_BACKUP_RESTORE BACNET_DATE_TIME bdateTime = { 0 }; BACNET_CREATE_OBJECT_DATA create_data = { 0 }; - struct object_functions *device_functions = NULL; - delete_object_function file_function = NULL; uint8_t apdu[MAX_APDU] = { 0 }; int32_t apdu_len = 0, offset = 0, file_size = 0; int decoded_len = 0; datetime_local(&bdateTime.date, &bdateTime.time, NULL, NULL); bacapp_timestamp_datetime_set(&Last_Restore_Time, &bdateTime); - /* avoid deleting our backup file - don't delete files */ - device_functions = Device_Object_Functions_Find(OBJECT_FILE); - if (device_functions) { - file_function = device_functions->Object_Delete; - device_functions->Object_Delete = NULL; - } /* delete all existing objects before restore */ Device_Delete_Objects(); /* create objects from the backup file */ @@ -3900,10 +3929,6 @@ void Device_End_Restore(void) if (Backup_State != BACKUP_STATE_RESTORE_FAILURE) { Backup_State = BACKUP_STATE_IDLE; } - if (device_functions) { - /* restore the delete-object for file objects */ - device_functions->Object_Delete = file_function; - } #endif } diff --git a/src/bacnet/basic/object/device.h b/src/bacnet/basic/object/device.h index 3be24571..09a7dcfd 100644 --- a/src/bacnet/basic/object/device.h +++ b/src/bacnet/basic/object/device.h @@ -246,6 +246,9 @@ BACNET_STACK_EXPORT bool Device_Configuration_File_Set(unsigned index, uint32_t instance); BACNET_STACK_EXPORT uint32_t Device_Configuration_File(unsigned index); +BACNET_STACK_EXPORT +bool Device_Is_Configuration_File(uint32_t instance); + BACNET_STACK_EXPORT uint16_t Device_Backup_Failure_Timeout(void); BACNET_STACK_EXPORT diff --git a/src/bacnet/basic/server/bacnet_device.c b/src/bacnet/basic/server/bacnet_device.c index c58491cf..dab84b42 100644 --- a/src/bacnet/basic/server/bacnet_device.c +++ b/src/bacnet/basic/server/bacnet_device.c @@ -2321,6 +2321,32 @@ uint32_t Device_Configuration_File(unsigned index) return instance; } +/** + * @brief Determine if the given file instance number is one of the configured + * configuration file object instances. + * @param instance [in] The object instance number to check + * @return True if the given instance is one of the configured configuration + * file object instances, else False. + */ +bool Device_Is_Configuration_File(uint32_t instance) +{ + bool status = false; + +#if BACNET_BACKUP_FILE_COUNT + unsigned i; + for (i = 0; i < BACNET_BACKUP_FILE_COUNT; i++) { + if (Configuration_Files[i] == instance) { + status = true; + break; + } + } +#else + (void)instance; +#endif + + return status; +} + /** * @brief Encode a BACnetARRAY property element * @param object_instance [in] BACnet network port object instance number @@ -3617,8 +3643,9 @@ bool Device_Delete_Object(BACNET_DELETE_OBJECT_DATA *data) } /** - * @brief Loops through all the objects and deletes them, + * @brief Loops through all the children objects and deletes them, * if DeleteObject service is supported by the object type. + * Skips the Device object itself and any configuration files. */ void Device_Delete_Objects(void) { @@ -3628,6 +3655,10 @@ void Device_Delete_Objects(void) pObject = Object_Table; while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { + if (pObject->Object_Type == OBJECT_DEVICE) { + pObject++; + continue; + } count = 0; if (pObject->Object_Count) { count = pObject->Object_Count(); @@ -3637,6 +3668,12 @@ void Device_Delete_Objects(void) if ((pObject->Object_Delete) && (pObject->Object_Index_To_Instance)) { instance = pObject->Object_Index_To_Instance(count); + /* keep Backup-Restore Configuration files */ + if (pObject->Object_Type == OBJECT_FILE) { + if (Device_Is_Configuration_File(instance)) { + continue; + } + } pObject->Object_Delete(instance); } } @@ -3714,20 +3751,12 @@ void Device_End_Restore(void) #if defined BACNET_BACKUP_RESTORE BACNET_DATE_TIME bdateTime = { 0 }; BACNET_CREATE_OBJECT_DATA create_data = { 0 }; - struct object_functions *device_functions = NULL; - delete_object_function file_function = NULL; uint8_t apdu[MAX_APDU] = { 0 }; int32_t apdu_len = 0, offset = 0, file_size = 0; int decoded_len = 0; datetime_local(&bdateTime.date, &bdateTime.time, NULL, NULL); bacapp_timestamp_datetime_set(&Last_Restore_Time, &bdateTime); - /* avoid deleting our backup file - don't delete files */ - device_functions = Device_Object_Functions_Find(OBJECT_FILE); - if (device_functions) { - file_function = device_functions->Object_Delete; - device_functions->Object_Delete = NULL; - } /* delete all existing objects before restore */ Device_Delete_Objects(); /* create objects from the backup file */ @@ -3762,10 +3791,6 @@ void Device_End_Restore(void) if (Backup_State != BACKUP_STATE_RESTORE_FAILURE) { Backup_State = BACKUP_STATE_IDLE; } - if (device_functions) { - /* restore the delete-object for file objects */ - device_functions->Object_Delete = file_function; - } #endif }