From 79f20f28c229fca01a802b61a7b391bbf585109e Mon Sep 17 00:00:00 2001 From: Michael Wetter Date: Mon, 23 May 2022 22:27:53 -0700 Subject: [PATCH] Issue3021 spawn - remove files extracted from FMU (#3033) * Adding deletion of files that are extracted from the FMU. Corrected bug as the function fmi2_import_terminate must only be called in event mode or continuous time mode --- .../libModelicaBuildingsEnergyPlus_9_6_0.so | 4 +- .../ModelicaBuildingsEnergyPlus_9_6_0.dll | 4 +- .../C-Sources/BuildingInstantiate.c | 11 -- .../EnergyPlus_9_6_0/C-Sources/SpawnFMU.c | 2 + .../C-Sources/SpawnObjectInstantiate.c | 4 + .../EnergyPlus_9_6_0/C-Sources/SpawnUtil.c | 180 +++++++++++++++++- .../EnergyPlus_9_6_0/C-Sources/SpawnUtil.h | 4 + 7 files changed, 193 insertions(+), 16 deletions(-) diff --git a/Buildings/Resources/Library/linux64/libModelicaBuildingsEnergyPlus_9_6_0.so b/Buildings/Resources/Library/linux64/libModelicaBuildingsEnergyPlus_9_6_0.so index dfb887c53ef..2233ca30355 100644 --- a/Buildings/Resources/Library/linux64/libModelicaBuildingsEnergyPlus_9_6_0.so +++ b/Buildings/Resources/Library/linux64/libModelicaBuildingsEnergyPlus_9_6_0.so @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3be265ba5bcbdfc3f14607bae6bbc52a37d672d18764b0702e52c6f09dc16507 -size 77104 +oid sha256:46aee6b4e492b401567ba0c367b978d88f939cd6a2c8f85617f58a31017d03c0 +size 81616 diff --git a/Buildings/Resources/Library/win64/ModelicaBuildingsEnergyPlus_9_6_0.dll b/Buildings/Resources/Library/win64/ModelicaBuildingsEnergyPlus_9_6_0.dll index d9ea1b595ce..30e13b0cbab 100644 --- a/Buildings/Resources/Library/win64/ModelicaBuildingsEnergyPlus_9_6_0.dll +++ b/Buildings/Resources/Library/win64/ModelicaBuildingsEnergyPlus_9_6_0.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fcf87307ddbd8ae60608521480e3cab01f2588c8693d99469bdd38bb7e3e8453 -size 144896 +oid sha256:4ba176cb0873f2c0ed5905ff68f2a76f0952e3880485bb0c4ae4405cc1fce9a3 +size 148480 diff --git a/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/BuildingInstantiate.c b/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/BuildingInstantiate.c index 6eb882b85dd..274f94f03b4 100644 --- a/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/BuildingInstantiate.c +++ b/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/BuildingInstantiate.c @@ -817,17 +817,6 @@ void setReusableFMU(FMUBuilding* bui){ } } - -int deleteFile(const char* fileName){ - /* Remove file if it exists */ - if (access(fileName, F_OK) == 0) { - /* FMU exists. Delete it. */ - return remove(fileName); - } - else - return 0; -} - void copyBinaryFile( const char* src, const char* des, diff --git a/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnFMU.c b/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnFMU.c index 209e3794e3f..4e37065cd48 100644 --- a/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnFMU.c +++ b/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnFMU.c @@ -308,6 +308,8 @@ void FMUBuildingFree(FMUBuilding* bui){ if (bui->context != NULL){ fmi_import_free_context(bui->context); } + /* Clean up files that were extracted from the FMU */ + delete_extracted_fmu_files(bui); if (bui->buildingsLibraryRoot != NULL) free(bui->buildingsLibraryRoot); diff --git a/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnObjectInstantiate.c b/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnObjectInstantiate.c index 8f3251754ca..9d0781e6ed9 100644 --- a/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnObjectInstantiate.c +++ b/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnObjectInstantiate.c @@ -36,6 +36,10 @@ void initialize_Spawn_EnergyPlus_9_6_0( Hence we cannot construct the FMU in the constructor because we don't know which is the last constructor to be called. */ + + /* Delete old files that were extracted from the FMU, if present */ + delete_extracted_fmu_files(bui); + loadFMU_setupExperiment_enterInitializationMode(bui, bui->time); } diff --git a/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnUtil.c b/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnUtil.c index 8eb573b23ce..12ef1e970ce 100644 --- a/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnUtil.c +++ b/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnUtil.c @@ -13,6 +13,13 @@ #include #include #include +#ifdef _WIN32 /* Win32 or Win64 */ +#include +#else +#include +#endif + + void mallocString(const size_t nChar, const char *error_message, char** str, void (*SpawnFormatError)(const char *string, ...)){ *str = malloc(nChar * sizeof(char)); @@ -709,13 +716,184 @@ void createDirectory(const char* dirName, void (*SpawnFormatError)(const char *s struct _stat64i32 st = {0}; if (_stat64i32(dirName, &st) == -1) { if ( _mkdir(dirName) == -1) + SpawnFormatError("Failed to create directory %s", dirName); + } #else struct stat st = {0}; if (stat(dirName, &st) == -1) { if ( mkdir(dirName, 0700) == -1) -#endif SpawnFormatError("Failed to create directory %s", dirName); } +#endif +} + +#ifndef _WIN32 /* Not Win32 or Win64 */ +int isDirectory(const char *path){ + struct stat statbuf; + if (stat(path, &statbuf) != 0) + return 0; + return S_ISDIR(statbuf.st_mode); +} + +int isRegularFile(const char *path) { + struct stat statbuf; + if (stat(path, &statbuf) != 0) + return 0; + return S_ISREG(statbuf.st_mode); +} +#endif + + +void remove_files_or_directory(FMUBuilding* bui, const char* directory, const char* wildCard, bool recursive){ +#ifdef _WIN32 /* Win32 or Win64 */ + WIN32_FIND_DATA fdFile; + HANDLE hFind = NULL; + size_t lenFilMas; + char* filMas; +#else + struct dirent **namelist; + int nFil; +#endif + + size_t lenFil; + char* filName; + + void (*SpawnFormatMessage)(const char *string, ...) = bui->SpawnFormatMessage; + void (*SpawnFormatError)(const char *string, ...) = bui->SpawnFormatError; + + if (bui->logLevel >= MEDIUM) + SpawnFormatMessage("%.3f %s: Entered remove_files_or_directory, directory = '%s', wildCard = '%s'.\n", + bui->time, bui->modelicaNameBuilding, directory, wildCard); + +#ifdef _WIN32 /* Win32 or Win64 */ + /* Specify file mask */ + lenFilMas = strlen(directory) + strlen(wildCard) + 2; + mallocString(lenFilMas, "Failed to allocate memory in remove_files_or_directory() for filMas.", + &filMas, SpawnFormatError); + memset(filMas, '\0', lenFilMas); + strcpy(filMas, directory); + strcat(filMas, "/"); + strcat(filMas, wildCard); + + if((hFind = FindFirstFile(filMas, &fdFile)) == INVALID_HANDLE_VALUE) + { + if (bui->logLevel >= MEDIUM) + SpawnFormatMessage("%.3f %s: Did not find old files when searching for '%s'.\n", bui->time, bui->modelicaNameBuilding, filMas); + free(filMas); + return; + } + do + { + //Find first file will always return "." + // and ".." as the first two directories. + if(strcmp(fdFile.cFileName, ".") != 0 + && strcmp(fdFile.cFileName, "..") != 0) + { + if(fdFile.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY){ + /* This is a directory. Call function recursively. */ + lenFil = lenFilMas + strlen("/") + strlen(fdFile.cFileName); + + mallocString(lenFil, "Failed to allocate memory in remove_files_or_directory() for filName.", + &filName, SpawnFormatError); + memset(filName, '\0', lenFil); + strcpy(filName, directory); + strcat(filName, "/"); + strcat(filName, fdFile.cFileName); + remove_files_or_directory(bui, filName, "*", recursive); + /* Now the directory is empty, delete it. */ + _rmdir(filName); + free(filName); + } + else{ + /* Delete the file */ + lenFil = lenFilMas + strlen("/") + strlen(fdFile.cFileName); + + mallocString(lenFil, "Failed to allocate memory in remove_files_or_directory() for filName.", + &filName, SpawnFormatError); + memset(filName, '\0', lenFil); + strcpy(filName, directory); + strcat(filName, "/"); + strcat(filName, fdFile.cFileName); + if (bui->logLevel >= MEDIUM) + SpawnFormatMessage("%.3f %s: Deleting file '%s'.\n", bui->time, bui->modelicaNameBuilding, filName); + deleteFile(filName); + free(filName); + } + } + } + while(FindNextFile(hFind, &fdFile)); /* Find the next file. */ + FindClose(hFind); /* Close the file handle */ + free(filMas); + +#else + /* Scan the directory for files */ + nFil = scandir(directory, &namelist, NULL, alphasort); + if (nFil == -1){ + /* scandir had an error, this may be if the directory does not exist. */ + if (bui->logLevel >= MEDIUM) + SpawnFormatMessage("%.3f %s: Did not find files in '%s'.\n", bui->time, bui->modelicaNameBuilding, directory); + return; + } + while (nFil--){ + if ( (strcmp(namelist[nFil]->d_name, "..") == 0) || + (strcmp(namelist[nFil]->d_name, ".") == 0) ) { + /* Skip for ".." and for "." */ + continue; + } + + lenFil = strlen(directory) + strlen("/") + strlen(namelist[nFil]->d_name) + 1; + mallocString(lenFil, "Failed to allocate memory in delete_extracted_fmu_files() for filName.", + &filName, SpawnFormatError); + + memset(filName, '\0', lenFil); + strcpy(filName, directory); + strcat(filName, "/"); + strcat(filName, namelist[nFil]->d_name); + + if (isDirectory(filName) && recursive && + ((strcmp(wildCard, namelist[nFil]->d_name) == 0) || (strcmp(wildCard, "*") == 0))){ + /* Have directory, and its name matches wildCard, or wildCard is equal to "*" */ + /* Call method recursively */ + remove_files_or_directory(bui, filName, "*", recursive); + /* Now the directory is empty. Delete it.*/ + rmdir(filName); + } + else if (isRegularFile(filName)){ + if ( (strcmp(wildCard, "*") == 0) || + (strcmp(wildCard, namelist[nFil]->d_name) == 0) ){ + if (bui->logLevel >= MEDIUM) + SpawnFormatMessage("%.3f %s: Deleting file '%s'.\n", bui->time, bui->modelicaNameBuilding, filName); + deleteFile(filName); + } + } + else{ + if (bui->logLevel >= MEDIUM) + SpawnFormatMessage("%.3f %s: Skipping removal of '%s', as it is does not match pattern.\n", + bui->time, bui->modelicaNameBuilding, filName); + } + free(filName); + free(namelist[nFil]); + } + free(namelist); +#endif +} + +void delete_extracted_fmu_files(FMUBuilding* bui){ + /* Delete old ep* libraries generated by previous simulation, if present. + */ + remove_files_or_directory(bui, bui->tmpDir, "binaries", true); + remove_files_or_directory(bui, bui->tmpDir, "resources", true); + remove_files_or_directory(bui, bui->tmpDir, "modelDescription.xml", false); +} + +int deleteFile(const char* fileName){ + /* Remove file if it exists */ + if (access(fileName, F_OK) == 0) { + /* File exists. Delete it. */ + return remove(fileName); + } + else + return 0; } diff --git a/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnUtil.h b/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnUtil.h index b6364f019de..e759c36d292 100644 --- a/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnUtil.h +++ b/Buildings/Resources/src/ThermalZones/EnergyPlus_9_6_0/C-Sources/SpawnUtil.h @@ -83,6 +83,10 @@ void getSimulationTemporaryDirectory( void createDirectory(const char* dirName, void (*SpawnFormatError)(const char *string, ...)); +int deleteFile(const char* fileName); + +void delete_extracted_fmu_files(FMUBuilding* bui); + void buildVariableNames( const char* firstPart, const char** secondParts,