From 720c6fe104963dba1956cc93ca864c84bacaf1dc Mon Sep 17 00:00:00 2001 From: falkTX Date: Sun, 12 Jul 2020 21:04:30 +0100 Subject: [PATCH] More work for LV2 state path, symlinks and move/copy when needed Signed-off-by: falkTX --- source/backend/plugin/CarlaPluginLV2.cpp | 159 ++++++++++++++++------- source/modules/water/files/File.cpp | 10 ++ source/modules/water/files/File.h | 8 ++ 3 files changed, 128 insertions(+), 49 deletions(-) diff --git a/source/backend/plugin/CarlaPluginLV2.cpp b/source/backend/plugin/CarlaPluginLV2.cpp index 52dee5edf..97e304278 100644 --- a/source/backend/plugin/CarlaPluginLV2.cpp +++ b/source/backend/plugin/CarlaPluginLV2.cpp @@ -196,6 +196,7 @@ enum CarlaLv2StateFeatures { kStateFeatureIdFreePath, kStateFeatureIdMakePath, kStateFeatureIdMapPath, + kStateFeatureIdWorker, kStateFeatureCountAll }; @@ -702,6 +703,14 @@ public: pData->active = false; } + if (fExt.state != nullptr) + { + const File tmpDir(handleStateMapToAbsolutePath(false, false, true, ".")); + + if (tmpDir.exists()) + tmpDir.deleteRecursively(); + } + if (fDescriptor != nullptr) { if (fDescriptor->cleanup != nullptr) @@ -1318,6 +1327,16 @@ public: if (fExt.state != nullptr && fExt.state->save != nullptr) { + const File tmpDir(handleStateMapToAbsolutePath(false, false, true, ".")); + + if (tmpDir.exists()) + { + const File stateDir(handleStateMapToAbsolutePath(true, false, false, ".")); + + if (stateDir.isNotNull()) + tmpDir.moveFileTo(stateDir); + } + fExt.state->save(fHandle, carla_lv2_state_store, this, LV2_STATE_IS_POD, fStateFeatures); if (fHandle2 != nullptr) @@ -4823,9 +4842,14 @@ public: void restoreLV2State() noexcept override { - if (fExt.state == nullptr) + if (fExt.state == nullptr || fExt.state->restore == nullptr) return; + const File tmpDir(handleStateMapToAbsolutePath(false, false, true, ".")); + + if (tmpDir.exists()) + tmpDir.deleteRecursively(); + LV2_State_Status status = LV2_STATE_ERR_UNKNOWN; { @@ -5232,67 +5256,97 @@ public: // ------------------------------------------------------------------- - char* handleStateMapToAbstractPath(const bool tmp, const char* const absolutePath) + char* handleStateMapToAbstractPath(const bool temporary, const char* const absolutePath) { // may already be an abstract path if (! File::isAbsolutePath(absolutePath)) return strdup(absolutePath); - File target; + File projectDir, targetDir; #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH if (const char* const projFolder = pData->engine->getCurrentProjectFolder()) - target = projFolder; + projectDir = projFolder; else #endif - target = File::getCurrentWorkingDirectory(); + projectDir = File::getCurrentWorkingDirectory(); + + + if (projectDir.isNull()) + return nullptr; water::String basedir(pData->engine->getName()); - if (tmp) + if (temporary) basedir += ".tmp"; - target = target.getChildFile(basedir) - .getChildFile(getName()); + targetDir = projectDir.getChildFile(basedir) + .getChildFile(getName()); + + if (! targetDir.exists()) + targetDir.createDirectory(); + + // we may be saving to non-tmp path, let's check + if (! temporary) + { + const File tmpDir = projectDir.getChildFile(basedir + ".tmp") + .getChildFile(getName()); + + if (File(absolutePath).getFullPathName().startsWith(tmpDir.getFullPathName())) + targetDir = tmpDir; + } + + carla_stdout("absolutePath is %s, targetDir is %s", absolutePath, targetDir.getFullPathName().toRawUTF8()); - return strdup(File(absolutePath).getRelativePathFrom(target).toRawUTF8()); + return strdup(File(absolutePath).getRelativePathFrom(targetDir).toRawUTF8()); } - char* handleStateMapToAbsolutePath(const bool createDir, const bool tmp, const char* const abstractPath) + File handleStateMapToAbsolutePath(const bool createDirIfNeeded, + const bool symlinkIfNeeded, + const bool temporary, + const char* const abstractPath) { - File target; + File targetDir, targetPath; - if (File::isAbsolutePath(abstractPath)) - { - target = abstractPath; - } - else - { #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH - if (const char* const projFolder = pData->engine->getCurrentProjectFolder()) - target = projFolder; - else + if (const char* const projFolder = pData->engine->getCurrentProjectFolder()) + targetDir = projFolder; + else #endif - target = File::getCurrentWorkingDirectory(); + targetDir = File::getCurrentWorkingDirectory(); - water::String basedir(pData->engine->getName()); + if (targetDir.isNull()) + return File(); - if (tmp) - basedir += ".tmp"; + water::String basedir(pData->engine->getName()); - target = target.getChildFile(basedir) - .getChildFile(getName()) - .getChildFile(abstractPath); - } + if (temporary) + basedir += ".tmp"; + + targetDir = targetDir.getChildFile(basedir) + .getChildFile(getName()); + + if (createDirIfNeeded && ! targetDir.exists()) + targetDir.createDirectory(); + + if (File::isAbsolutePath(abstractPath)) + { + File wabstractPath(abstractPath); + targetPath = targetDir.getChildFile(wabstractPath.getFileName()); - if (createDir) + if (symlinkIfNeeded) + wabstractPath.createSymbolicLink(targetPath, true); + } + else { - File dir(target.getParentDirectory()); - if (! dir.exists()) - dir.createDirectory(); + targetPath = targetDir.getChildFile(abstractPath); + targetDir = targetPath.getParentDirectory(); + + if (createDirIfNeeded && ! targetDir.exists()) + targetDir.createDirectory(); } - return strdup(target.getFullPathName().toRawUTF8()); + return targetPath; } LV2_State_Status handleStateStore(const uint32_t key, const void* const value, const size_t size, const uint32_t type, const uint32_t flags) @@ -6050,8 +6104,8 @@ public: LV2_State_Map_Path* const stateMapPathFt = new LV2_State_Map_Path; stateMapPathFt->handle = this; - stateMapPathFt->abstract_path = carla_lv2_state_map_abstract_path_tmp; - stateMapPathFt->absolute_path = carla_lv2_state_map_absolute_path_tmp; + stateMapPathFt->abstract_path = carla_lv2_state_map_to_abstract_path_tmp; + stateMapPathFt->absolute_path = carla_lv2_state_map_to_absolute_path_tmp; LV2_Programs_Host* const programsFt = new LV2_Programs_Host; programsFt->handle = this; @@ -6177,8 +6231,8 @@ public: LV2_State_Map_Path* const stateMapPathFt2 = new LV2_State_Map_Path; stateMapPathFt2->handle = this; - stateMapPathFt2->abstract_path = carla_lv2_state_map_abstract_path_real; - stateMapPathFt2->absolute_path = carla_lv2_state_map_absolute_path_real; + stateMapPathFt2->abstract_path = carla_lv2_state_map_to_abstract_path_real; + stateMapPathFt2->absolute_path = carla_lv2_state_map_to_absolute_path_real; for (uint32_t j=0; j < kStateFeatureCountAll; ++j) fStateFeatures[j] = new LV2_Feature; @@ -6192,6 +6246,9 @@ public: fStateFeatures[kStateFeatureIdMapPath]->URI = LV2_STATE__mapPath; fStateFeatures[kStateFeatureIdMapPath]->data = stateMapPathFt2; + fStateFeatures[kStateFeatureIdWorker]->URI = LV2_WORKER__schedule; + fStateFeatures[kStateFeatureIdWorker]->data = workerFt; + // --------------------------------------------------------------- // initialize plugin @@ -7023,7 +7080,8 @@ private: CARLA_SAFE_ASSERT_RETURN(path != nullptr && path[0] != '\0', nullptr); carla_stdout("carla_lv2_state_make_path_real(%p, \"%s\")", handle, path); - return ((CarlaPluginLV2*)handle)->handleStateMapToAbsolutePath(true, false, path); + const File file(((CarlaPluginLV2*)handle)->handleStateMapToAbsolutePath(true, false, false, path)); + return file.isNotNull() ? strdup(file.getFullPathName().toRawUTF8()) : nullptr; } static char* carla_lv2_state_make_path_tmp(LV2_State_Make_Path_Handle handle, const char* const path) @@ -7032,43 +7090,46 @@ private: CARLA_SAFE_ASSERT_RETURN(path != nullptr && path[0] != '\0', nullptr); carla_stdout("carla_lv2_state_make_path_tmp(%p, \"%s\")", handle, path); - return ((CarlaPluginLV2*)handle)->handleStateMapToAbsolutePath(true, true, path); + const File file(((CarlaPluginLV2*)handle)->handleStateMapToAbsolutePath(true, false, true, path)); + return file.isNotNull() ? strdup(file.getFullPathName().toRawUTF8()) : nullptr; } - static char* carla_lv2_state_map_abstract_path_real(LV2_State_Map_Path_Handle handle, const char* const absolute_path) + static char* carla_lv2_state_map_to_abstract_path_real(LV2_State_Map_Path_Handle handle, const char* const absolute_path) { CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr); CARLA_SAFE_ASSERT_RETURN(absolute_path != nullptr && absolute_path[0] != '\0', nullptr); - carla_stdout("carla_lv2_state_map_abstract_path_real(%p, \"%s\")", handle, absolute_path); + carla_stdout("carla_lv2_state_map_to_abstract_path_real(%p, \"%s\")", handle, absolute_path); return ((CarlaPluginLV2*)handle)->handleStateMapToAbstractPath(false, absolute_path); } - static char* carla_lv2_state_map_abstract_path_tmp(LV2_State_Map_Path_Handle handle, const char* const absolute_path) + static char* carla_lv2_state_map_to_abstract_path_tmp(LV2_State_Map_Path_Handle handle, const char* const absolute_path) { CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr); CARLA_SAFE_ASSERT_RETURN(absolute_path != nullptr && absolute_path[0] != '\0', nullptr); - carla_stdout("carla_lv2_state_map_abstract_path_tmp(%p, \"%s\")", handle, absolute_path); + carla_stdout("carla_lv2_state_map_to_abstract_path_tmp(%p, \"%s\")", handle, absolute_path); return ((CarlaPluginLV2*)handle)->handleStateMapToAbstractPath(true, absolute_path); } - static char* carla_lv2_state_map_absolute_path_real(LV2_State_Map_Path_Handle handle, const char* const abstract_path) + static char* carla_lv2_state_map_to_absolute_path_real(LV2_State_Map_Path_Handle handle, const char* const abstract_path) { CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr); CARLA_SAFE_ASSERT_RETURN(abstract_path != nullptr && abstract_path[0] != '\0', nullptr); - carla_stdout("carla_lv2_state_map_absolute_path_real(%p, \"%s\")", handle, abstract_path); + carla_stdout("carla_lv2_state_map_to_absolute_path_real(%p, \"%s\")", handle, abstract_path); - return ((CarlaPluginLV2*)handle)->handleStateMapToAbsolutePath(false, false, abstract_path); + const File file(((CarlaPluginLV2*)handle)->handleStateMapToAbsolutePath(true, true, false, abstract_path)); + return file.isNotNull() ? strdup(file.getFullPathName().toRawUTF8()) : nullptr; } - static char* carla_lv2_state_map_absolute_path_tmp(LV2_State_Map_Path_Handle handle, const char* const abstract_path) + static char* carla_lv2_state_map_to_absolute_path_tmp(LV2_State_Map_Path_Handle handle, const char* const abstract_path) { CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr); CARLA_SAFE_ASSERT_RETURN(abstract_path != nullptr && abstract_path[0] != '\0', nullptr); - carla_stdout("carla_lv2_state_map_absolute_path_tmp(%p, \"%s\")", handle, abstract_path); + carla_stdout("carla_lv2_state_map_to_absolute_path_tmp(%p, \"%s\")", handle, abstract_path); - return ((CarlaPluginLV2*)handle)->handleStateMapToAbsolutePath(false, true, abstract_path); + const File file(((CarlaPluginLV2*)handle)->handleStateMapToAbsolutePath(true, true, true, abstract_path)); + return file.isNotNull() ? strdup(file.getFullPathName().toRawUTF8()) : nullptr; } static LV2_State_Status carla_lv2_state_store(LV2_State_Handle handle, uint32_t key, const void* value, size_t size, uint32_t type, uint32_t flags) diff --git a/source/modules/water/files/File.cpp b/source/modules/water/files/File.cpp index 76f6b6b93..984477e48 100644 --- a/source/modules/water/files/File.cpp +++ b/source/modules/water/files/File.cpp @@ -99,6 +99,16 @@ File& File::operator= (File&& other) noexcept } #endif +bool File::isNull() const +{ + return fullPath.isEmpty(); +} + +bool File::isNotNull() const +{ + return fullPath.isNotEmpty(); +} + //============================================================================== static String removeEllipsis (const String& path) { diff --git a/source/modules/water/files/File.h b/source/modules/water/files/File.h index 5f3180375..1fa1a7c3e 100644 --- a/source/modules/water/files/File.h +++ b/source/modules/water/files/File.h @@ -118,6 +118,14 @@ public: */ bool isDirectory() const; + /** Checks whether the file is invalid (empty path). + */ + bool isNull() const; + + /** Checks whether the file is valid (non-empty path). + */ + bool isNotNull() const; + /** Returns the size of the file in bytes. @returns the number of bytes in the file, or 0 if it doesn't exist.