This is an automated email from the ASF dual-hosted git repository.

pengzheng pushed a commit to branch feature/522-support-uncompressed-bundle
in repository https://gitbox.apache.org/repos/asf/celix.git


The following commit(s) were added to 
refs/heads/feature/522-support-uncompressed-bundle by this push:
     new b0909e78 Remove dangling link to non-existing uncompressed bundle 
during bundle installation/updating.
b0909e78 is described below

commit b0909e78bb669692f724f5e2185b7ffddf38f4c6
Author: PengZheng <[email protected]>
AuthorDate: Tue Jun 27 20:21:10 2023 +0800

    Remove dangling link to non-existing uncompressed bundle during bundle 
installation/updating.
---
 libs/error_injector/stat/CMakeLists.txt            |  1 +
 libs/error_injector/stat/include/stat_ei.h         |  2 ++
 libs/error_injector/stat/src/stat_ei.cc            | 17 ++++++++---
 libs/error_injector/unistd/CMakeLists.txt          |  1 +
 libs/error_injector/unistd/include/unistd_ei.h     |  2 ++
 libs/error_injector/unistd/src/unistd_ei.cc        | 10 +++++++
 libs/framework/gtest/CMakeLists.txt                |  1 +
 .../BundleArchiveWithErrorInjectionTestSuite.cc    | 33 ++++++++++++++++++++++
 .../src/CelixBundleContextBundlesTestSuite.cc      | 31 +++++++++++++-------
 .../CelixFrameworkUtilsErrorInjectionTestSuite.cc  |  5 ++--
 .../gtest/src/CelixFrameworkUtilsTestSuite.cc      |  4 +--
 libs/framework/src/bundle_archive.c                | 27 ++++++++++++++----
 libs/framework/src/framework.c                     |  7 -----
 13 files changed, 111 insertions(+), 30 deletions(-)

diff --git a/libs/error_injector/stat/CMakeLists.txt 
b/libs/error_injector/stat/CMakeLists.txt
index 31ed0559..67e050f9 100644
--- a/libs/error_injector/stat/CMakeLists.txt
+++ b/libs/error_injector/stat/CMakeLists.txt
@@ -23,5 +23,6 @@ target_link_libraries(stat_ei PUBLIC Celix::error_injector)
 target_link_options(stat_ei INTERFACE
         LINKER:--wrap,mkdir
         LINKER:--wrap,stat
+        LINKER:--wrap,lstat
         )
 add_library(Celix::stat_ei ALIAS stat_ei)
diff --git a/libs/error_injector/stat/include/stat_ei.h 
b/libs/error_injector/stat/include/stat_ei.h
index 439a9bab..73089c34 100644
--- a/libs/error_injector/stat/include/stat_ei.h
+++ b/libs/error_injector/stat/include/stat_ei.h
@@ -31,6 +31,8 @@ CELIX_EI_DECLARE(mkdir, int);
 
 CELIX_EI_DECLARE(stat, int);
 
+CELIX_EI_DECLARE(lstat, int);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libs/error_injector/stat/src/stat_ei.cc 
b/libs/error_injector/stat/src/stat_ei.cc
index 7edf5744..1a095d62 100644
--- a/libs/error_injector/stat/src/stat_ei.cc
+++ b/libs/error_injector/stat/src/stat_ei.cc
@@ -22,9 +22,9 @@
 
 extern "C" {
 
-int __real_mkdir (const char *__path, __mode_t __mode);
+int __real_mkdir(const char *__path, __mode_t __mode);
 CELIX_EI_DEFINE(mkdir, int)
-int __wrap_mkdir (const char *__path, __mode_t __mode) {
+int __wrap_mkdir(const char *__path, __mode_t __mode) {
     errno = EACCES;
     CELIX_EI_IMPL(mkdir);
     errno = 0;
@@ -32,12 +32,21 @@ int __wrap_mkdir (const char *__path, __mode_t __mode) {
 }
 
 
-int __real_stat (const char *__restrict __file, struct stat *__restrict __buf);
+int __real_stat(const char *__restrict __file, struct stat *__restrict __buf);
 CELIX_EI_DEFINE(stat, int)
-int __wrap_stat (const char *__restrict __file, struct stat *__restrict __buf) 
{
+int __wrap_stat(const char *__restrict __file, struct stat *__restrict __buf) {
     errno = EOVERFLOW;
     CELIX_EI_IMPL(stat);
     errno = 0;
     return __real_stat(__file, __buf);
 }
+
+int __real_lstat(const char *__restrict __file, struct stat *__restrict __buf);
+CELIX_EI_DEFINE(lstat, int)
+int __wrap_lstat(const char *__restrict __file, struct stat *__restrict __buf) 
{
+    errno = EACCES;
+    CELIX_EI_IMPL(lstat);
+    errno = 0;
+    return __real_lstat(__file, __buf);
+}
 }
\ No newline at end of file
diff --git a/libs/error_injector/unistd/CMakeLists.txt 
b/libs/error_injector/unistd/CMakeLists.txt
index 1835afcf..328fc427 100644
--- a/libs/error_injector/unistd/CMakeLists.txt
+++ b/libs/error_injector/unistd/CMakeLists.txt
@@ -23,5 +23,6 @@ target_link_libraries(unistd_ei PUBLIC Celix::error_injector)
 target_link_options(unistd_ei INTERFACE
         LINKER:--wrap,getcwd
         LINKER:--wrap,symlink
+        LINKER:--wrap,unlink
         )
 add_library(Celix::unistd_ei ALIAS unistd_ei)
diff --git a/libs/error_injector/unistd/include/unistd_ei.h 
b/libs/error_injector/unistd/include/unistd_ei.h
index 8ded930c..dde5dccc 100644
--- a/libs/error_injector/unistd/include/unistd_ei.h
+++ b/libs/error_injector/unistd/include/unistd_ei.h
@@ -31,6 +31,8 @@ CELIX_EI_DECLARE(getcwd, char*);
 
 CELIX_EI_DECLARE(symlink, int);
 
+CELIX_EI_DECLARE(unlink, int);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libs/error_injector/unistd/src/unistd_ei.cc 
b/libs/error_injector/unistd/src/unistd_ei.cc
index 22673e99..5f01ddc7 100644
--- a/libs/error_injector/unistd/src/unistd_ei.cc
+++ b/libs/error_injector/unistd/src/unistd_ei.cc
@@ -39,4 +39,14 @@ int __wrap_symlink(const char *target, const char *linkpath) 
{
     errno = 0;
     return __real_symlink(target, linkpath);
 }
+
+int __real_unlink(const char *pathname);
+CELIX_EI_DEFINE(unlink, int)
+int __wrap_unlink(const char *pathname) {
+    errno = EACCES;
+    CELIX_EI_IMPL(unlink);
+    errno = 0;
+    return __real_unlink(pathname);
 }
+
+}
\ No newline at end of file
diff --git a/libs/framework/gtest/CMakeLists.txt 
b/libs/framework/gtest/CMakeLists.txt
index 05491882..2d57dc7b 100644
--- a/libs/framework/gtest/CMakeLists.txt
+++ b/libs/framework/gtest/CMakeLists.txt
@@ -147,6 +147,7 @@ if (LINKER_WRAP_SUPPORTED)
             Celix::hash_map_ei
             Celix::properties_ei
             Celix::stdlib_ei
+            Celix::stat_ei
             GTest::gtest GTest::gtest_main
     )
 
diff --git 
a/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc 
b/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc
index 4861ea44..9525c3b1 100644
--- a/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc
+++ b/libs/framework/gtest/src/BundleArchiveWithErrorInjectionTestSuite.cc
@@ -19,6 +19,7 @@
 
 #include <gtest/gtest.h>
 
+#include <thread>
 #include <unistd.h>
 
 #include "celix_constants.h"
@@ -36,6 +37,8 @@
 #include "framework_private.h"
 #include "malloc_ei.h"
 #include "manifest.h"
+#include "stat_ei.h"
+#include "unistd_ei.h"
 
 class BundleArchiveWithErrorInjectionTestSuite : public ::testing::Test {
   public:
@@ -62,6 +65,8 @@ class BundleArchiveWithErrorInjectionTestSuite : public 
::testing::Test {
         celix_ei_expect_celix_utils_deleteDirectory(nullptr, 0, CELIX_SUCCESS);
         celix_ei_expect_celix_utils_writeOrCreateString(nullptr, 0, nullptr);
         celix_ei_expect_celix_utils_extractZipData(nullptr, 0, CELIX_SUCCESS);
+        celix_ei_expect_lstat(nullptr, 0, 0);
+        celix_ei_expect_unlink(nullptr, 0, 0);
     }
 
     void installBundleAndExpectFailure() {
@@ -192,6 +197,34 @@ TEST_F(CelixBundleArchiveErrorInjectionTestSuite, 
ArchiveCreateErrorTest) {
     EXPECT_FALSE(celix_utils_directoryExists(TEST_ARCHIVE_ROOT));
     teardownErrorInjectors();
 
+    celix_ei_expect_lstat((void*) celix_bundleArchive_create, 2, -1);
+    EXPECT_EQ(CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,EACCES),
+              celix_bundleArchive_create(&fw, TEST_ARCHIVE_ROOT, 1, 
SIMPLE_TEST_BUNDLE1_LOCATION, &archive));
+    EXPECT_EQ(nullptr, archive);
+    EXPECT_FALSE(celix_utils_directoryExists(TEST_ARCHIVE_ROOT));
+    teardownErrorInjectors();
+
+    const char* testExtractDir = "extractBundleTestDir";
+    EXPECT_EQ(CELIX_SUCCESS, 
celix_utils_extractZipFile(SIMPLE_TEST_BUNDLE1_LOCATION, testExtractDir, 
nullptr));
+    EXPECT_EQ(CELIX_SUCCESS,
+              celix_bundleArchive_create(&fw, TEST_ARCHIVE_ROOT, 2, 
testExtractDir, &archive));
+    bundleArchive_destroy(archive);
+    archive = nullptr;
+    std::this_thread::sleep_for(std::chrono::milliseconds(10));
+    celix_utils_touch(SIMPLE_TEST_BUNDLE1_LOCATION);
+    celix_ei_expect_unlink((void*)celix_bundleArchive_create, 2, -1);
+    EXPECT_EQ(CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,EACCES),
+              celix_bundleArchive_create(&fw, TEST_ARCHIVE_ROOT, 2, 
SIMPLE_TEST_BUNDLE1_LOCATION, &archive));
+    EXPECT_EQ(nullptr, archive);
+    celix_utils_deleteDirectory(testExtractDir, nullptr);
+    teardownErrorInjectors();
+
+    EXPECT_EQ(CELIX_SUCCESS,
+              celix_bundleArchive_create(&fw, TEST_ARCHIVE_ROOT, 1, 
SIMPLE_TEST_BUNDLE1_LOCATION, &archive));
+    bundleArchive_destroy(archive);
+    archive = nullptr;
+    std::this_thread::sleep_for(std::chrono::milliseconds(10));
+    celix_utils_touch(SIMPLE_TEST_BUNDLE1_LOCATION);
     
celix_ei_expect_celix_utils_deleteDirectory((void*)celix_bundleArchive_create, 
2, CELIX_FILE_IO_EXCEPTION);
     EXPECT_EQ(CELIX_FILE_IO_EXCEPTION,
               celix_bundleArchive_create(&fw, TEST_ARCHIVE_ROOT, 1, 
SIMPLE_TEST_BUNDLE1_LOCATION, &archive));
diff --git a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc 
b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
index 37cf9b2a..e68e08d4 100644
--- a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
+++ b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc
@@ -307,20 +307,31 @@ TEST_F(CelixBundleContextBundlesTestSuite, 
UpdateBundlesTest) {
     ASSERT_FALSE(celix_bundleContext_updateBundle(ctx, bndId1, TEST_BND2_LOC));
     ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId1));
 
-    // remove it from cache before updating
-    ASSERT_EQ(bndId2, celix_bundleContext_installBundle(ctx, TEST_BND2_LOC, 
false));
-    ASSERT_TRUE(celix_bundleContext_uninstallBundle(ctx, bndId2));
-    auto sn1 = celix_bundleContext_getBundleSymbolicName(ctx, bndId1);
-    ASSERT_TRUE(celix_bundleContext_updateBundle(ctx, bndId1, TEST_BND2_LOC));
-    auto sn2 = celix_bundleContext_getBundleSymbolicName(ctx, bndId1);
-    ASSERT_STRNE(sn1, sn2);
-    free(sn2);
-    free(sn1);
-
     ASSERT_TRUE(celix_bundleContext_unloadBundle(ctx, bndId1));
     ASSERT_FALSE(celix_bundleContext_updateBundle(ctx, bndId1, NULL));
 }
 
+TEST_F(CelixBundleContextBundlesTestSuite, 
UpdateCorruptUncompressedBundlesTest) {
+    const char* testExtractDir1 = "extractBundleTestDir1";
+    const char* testExtractDir2 = "extractBundleTestDir2";
+    celix_utils_deleteDirectory(testExtractDir1, nullptr);
+    EXPECT_EQ(CELIX_SUCCESS, celix_utils_extractZipFile(TEST_BND1_LOC, 
testExtractDir1, nullptr));
+    long bndId1 = celix_bundleContext_installBundle(ctx, testExtractDir1, 
true);
+    ASSERT_TRUE(bndId1 >= 0L);
+    ASSERT_TRUE(celix_bundleContext_isBundleInstalled(ctx, bndId1));
+    ASSERT_TRUE(celix_bundleContext_isBundleActive(ctx, bndId1));
+
+    // make the symbolic link in cache dangling
+    celix_utils_deleteDirectory(testExtractDir1, nullptr);
+
+    std::this_thread::sleep_for(std::chrono::milliseconds{10});
+    EXPECT_EQ(CELIX_SUCCESS, celix_utils_extractZipFile(TEST_BND2_LOC, 
testExtractDir2, nullptr));
+    ASSERT_TRUE(celix_bundleContext_updateBundle(ctx, bndId1, 
testExtractDir2));
+
+    celix_utils_deleteDirectory(testExtractDir1, nullptr);
+    celix_utils_deleteDirectory(testExtractDir2, nullptr);
+}
+
 TEST_F(CelixBundleContextBundlesTestSuite, StartBundleWithException) {
     long bndId = celix_bundleContext_installBundle(ctx, 
TEST_BND_WITH_EXCEPTION_LOC, true);
     ASSERT_TRUE(bndId > 0); //bundle is installed, but not started
diff --git 
a/libs/framework/gtest/src/CelixFrameworkUtilsErrorInjectionTestSuite.cc 
b/libs/framework/gtest/src/CelixFrameworkUtilsErrorInjectionTestSuite.cc
index 58ab0901..cee8be4b 100644
--- a/libs/framework/gtest/src/CelixFrameworkUtilsErrorInjectionTestSuite.cc
+++ b/libs/framework/gtest/src/CelixFrameworkUtilsErrorInjectionTestSuite.cc
@@ -21,6 +21,7 @@
 
 #include <dirent.h>
 #include <time.h>
+#include <unistd.h>
 
 #include "celix/FrameworkFactory.h"
 #include "celix/FrameworkUtils.h"
@@ -95,7 +96,7 @@ TEST_F(CelixFrameworkUtilsErrorInjectionTestSuite, 
ExtractUncompressedBundleTest
     const char* testExtractDir = "extractBundleTestDir";
     const char* testLinkDir = "linkBundleTestDir";
     celix_utils_deleteDirectory(testExtractDir, nullptr);
-    celix_utils_deleteDirectory(testLinkDir, nullptr);
+    unlink(testLinkDir);
     EXPECT_EQ(CELIX_SUCCESS, 
celix_utils_extractZipFile(SIMPLE_TEST_BUNDLE1_LOCATION, testExtractDir, 
nullptr));
 
     // failed to get realpath of bundle
@@ -109,7 +110,7 @@ TEST_F(CelixFrameworkUtilsErrorInjectionTestSuite, 
ExtractUncompressedBundleTest
     EXPECT_EQ(status, CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,EIO));
 
     celix_utils_deleteDirectory(testExtractDir, nullptr);
-    celix_utils_deleteDirectory(testLinkDir, nullptr);
+    unlink(testLinkDir);
 }
 
 TEST_F(CelixFrameworkUtilsErrorInjectionTestSuite, CheckBundleAge) {
diff --git a/libs/framework/gtest/src/CelixFrameworkUtilsTestSuite.cc 
b/libs/framework/gtest/src/CelixFrameworkUtilsTestSuite.cc
index 667ff309..2dbecd80 100644
--- a/libs/framework/gtest/src/CelixFrameworkUtilsTestSuite.cc
+++ b/libs/framework/gtest/src/CelixFrameworkUtilsTestSuite.cc
@@ -121,7 +121,7 @@ TEST_F(CelixFrameworkUtilsTestSuite, 
ExtractUncompressedBundleTest) {
     const char* testExtractDir = "extractBundleTestDir";
     const char* testLinkDir = "linkBundleTestDir";
     celix_utils_deleteDirectory(testExtractDir, nullptr);
-    celix_utils_deleteDirectory(testLinkDir, nullptr);
+    unlink(testLinkDir);
     EXPECT_EQ(CELIX_SUCCESS, 
celix_utils_extractZipFile(SIMPLE_TEST_BUNDLE1_LOCATION, testExtractDir, 
nullptr));
 
     //valid bundle path -> install a symbolic link
@@ -135,7 +135,7 @@ TEST_F(CelixFrameworkUtilsTestSuite, 
ExtractUncompressedBundleTest) {
     EXPECT_EQ(0, memcmp(&st2, &st3, sizeof(struct stat)));
 
     celix_utils_deleteDirectory(testExtractDir, nullptr);
-    celix_utils_deleteDirectory(testLinkDir, nullptr);
+    unlink(testLinkDir);
 }
 
 TEST_F(CelixFrameworkUtilsTestSuite, ExtractEmbeddedBundleTest) {
diff --git a/libs/framework/src/bundle_archive.c 
b/libs/framework/src/bundle_archive.c
index 9bb0b0fd..bd151729 100644
--- a/libs/framework/src/bundle_archive.c
+++ b/libs/framework/src/bundle_archive.c
@@ -125,13 +125,30 @@ celix_bundleArchive_extractBundle(bundle_archive_t* 
archive, const char* bundleU
      * If dlopen/dlsym is used with newer files, but with the same inode 
already used in dlopen/dlsym this leads to
      * segfaults.
      */
-    const char* error;
-    status = celix_utils_deleteDirectory(archive->resourceCacheRoot, &error);
-    if (status != CELIX_SUCCESS) {
-        fw_logCode(archive->fw->logger, CELIX_LOG_LEVEL_ERROR, status, "Failed 
to remove existing bundle archive revision directory '%s': %s", 
archive->resourceCacheRoot, error);
+    const char* error = NULL;
+    struct stat st;
+    status = lstat(archive->resourceCacheRoot, &st);
+    if(status == -1 && errno != ENOENT) {
+        status = CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,errno);
+        fw_logCode(archive->fw->logger, CELIX_LOG_LEVEL_ERROR, status, "Failed 
to stat bundle archive directory '%s'", archive->resourceCacheRoot);
         return status;
     }
-
+    if (status == 0) {
+        // celix_utils_deleteDirectory does not work for dangling symlinks, so 
handle this case separately
+        if (S_ISLNK(st.st_mode)) {
+            status = unlink(archive->resourceCacheRoot);
+            if (status == -1) {
+                status = CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,errno);
+                error = "Failed to remove existing bundle symlink";
+            }
+        } else {
+            status = celix_utils_deleteDirectory(archive->resourceCacheRoot, 
&error);
+        }
+        if (status != CELIX_SUCCESS) {
+            fw_logCode(archive->fw->logger, CELIX_LOG_LEVEL_ERROR, status, 
"Failed to remove existing bundle archive revision directory '%s': %s", 
archive->resourceCacheRoot, error);
+            return status;
+        }
+    }
     status = celix_framework_utils_extractBundle(archive->fw, bundleUrl, 
archive->resourceCacheRoot);
     if (status != CELIX_SUCCESS) {
         fw_log(archive->fw->logger, CELIX_LOG_LEVEL_ERROR, "Failed to 
initialize archive. Failed to extract bundle zip to revision directory.");
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index d86a7e93..57f3f41f 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -2308,7 +2308,6 @@ celix_status_t 
celix_framework_updateBundleEntry(celix_framework_t* framework,
     celix_status_t status = CELIX_SUCCESS;
     long bundleId = bndEntry->bndId;
     const char* errMsg;
-    char *bndRoot = NULL;
     fw_log(framework->logger, CELIX_LOG_LEVEL_DEBUG, "Updating bundle %s", 
celix_bundle_getSymbolicName(bndEntry->bnd));
     celix_bundle_state_e bndState = celix_bundle_getState(bndEntry->bnd);
     char *location = celix_bundle_getLocation(bndEntry->bnd);
@@ -2326,7 +2325,6 @@ celix_status_t 
celix_framework_updateBundleEntry(celix_framework_t* framework,
                 status = CELIX_ILLEGAL_STATE;
                 break;
             }
-            bndRoot = celix_bundle_getEntry(bndEntry->bnd, NULL);
         }
         status = celix_framework_uninstallBundleEntryImpl(framework, bndEntry, 
false);
         if (status != CELIX_SUCCESS) {
@@ -2335,10 +2333,6 @@ celix_status_t 
celix_framework_updateBundleEntry(celix_framework_t* framework,
             break;
         }
         // bndEntry is now invalid
-        if (bndRoot) {
-            // the bundle is updated with a new location, so the old bundle 
root can be removed
-            celix_utils_deleteDirectory(bndRoot, NULL);
-        }
         status = celix_framework_installBundleInternalImpl(framework, 
updatedBundleUrl, &bundleId);
         if (status != CELIX_SUCCESS) {
             errMsg = "reinstall failure";
@@ -2361,7 +2355,6 @@ celix_status_t 
celix_framework_updateBundleEntry(celix_framework_t* framework,
         }
     } while(0);
     framework_logIfError(framework->logger, status, errMsg, "Could not update 
bundle from %s", updatedBundleUrl);
-    free(bndRoot);
     free(location);
     return status;
 }

Reply via email to