This is an automated email from the ASF dual-hosted git repository.
pengzheng pushed a commit to branch feature/refactor_bundle_cache
in repository https://gitbox.apache.org/repos/asf/celix.git
The following commit(s) were added to refs/heads/feature/refactor_bundle_cache
by this push:
new 0d3e3d71 Optimize celix_utils_deleteDirectory to eliminate `stat`
calls and test it thoroughly.
0d3e3d71 is described below
commit 0d3e3d71f2c3d9576368ffea4da4db2d20e1aa59
Author: Pepijn Noltes <[email protected]>
AuthorDate: Fri Mar 31 13:08:50 2023 +0200
Optimize celix_utils_deleteDirectory to eliminate `stat` calls and test it
thoroughly.
---
libs/error_injector/CMakeLists.txt | 1 +
libs/error_injector/{stdio => fts}/CMakeLists.txt | 16 +++---
.../include/stdio_ei.h => fts/include/fts_ei.h} | 12 ++---
.../{stdio/src/stdio_ei.cc => fts/src/fts_ei.cc} | 29 ++++++-----
libs/error_injector/stdio/CMakeLists.txt | 1 +
libs/error_injector/stdio/include/stdio_ei.h | 2 +
libs/error_injector/stdio/src/stdio_ei.cc | 10 ++++
libs/utils/gtest/CMakeLists.txt | 2 +-
.../gtest/src/FileUtilsErrorInjectionTestSuite.cc | 58 +++++++++++++++++++++-
libs/utils/gtest/src/FileUtilsTestSuite.cc | 33 ++++++++++++
libs/utils/src/celix_file_utils.c | 55 ++++++++++----------
11 files changed, 162 insertions(+), 57 deletions(-)
diff --git a/libs/error_injector/CMakeLists.txt
b/libs/error_injector/CMakeLists.txt
index 193873cb..1d95086c 100644
--- a/libs/error_injector/CMakeLists.txt
+++ b/libs/error_injector/CMakeLists.txt
@@ -33,6 +33,7 @@ add_subdirectory(celix_threads)
add_subdirectory(eventfd)
add_subdirectory(celix_bundle_ctx)
add_subdirectory(stat)
+add_subdirectory(fts)
celix_subproject(ERROR_INJECTOR_MDNSRESPONDER "Option to enable building the
mdnsresponder error injector" OFF)
if (ERROR_INJECTOR_MDNSRESPONDER)
diff --git a/libs/error_injector/stdio/CMakeLists.txt
b/libs/error_injector/fts/CMakeLists.txt
similarity index 68%
copy from libs/error_injector/stdio/CMakeLists.txt
copy to libs/error_injector/fts/CMakeLists.txt
index 44882882..b94e0f36 100644
--- a/libs/error_injector/stdio/CMakeLists.txt
+++ b/libs/error_injector/fts/CMakeLists.txt
@@ -15,13 +15,13 @@
# specific language governing permissions and limitations
# under the License.
-add_library(stdio_ei STATIC src/stdio_ei.cc)
+add_library(fts_ei STATIC src/fts_ei.cc)
-target_include_directories(stdio_ei PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
-target_link_libraries(stdio_ei PUBLIC Celix::error_injector)
-# It plays nicely with address sanitizer this way.
-target_link_options(stdio_ei INTERFACE
- LINKER:--wrap,fopen
- LINKER:--wrap,fwrite
+target_include_directories(fts_ei PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
+target_link_libraries(fts_ei PUBLIC Celix::error_injector)
+
+target_link_options(fts_ei INTERFACE
+ LINKER:--wrap,fts_open
+ LINKER:--wrap,fts_read
)
-add_library(Celix::stdio_ei ALIAS stdio_ei)
+add_library(Celix::fts_ei ALIAS fts_ei)
diff --git a/libs/error_injector/stdio/include/stdio_ei.h
b/libs/error_injector/fts/include/fts_ei.h
similarity index 84%
copy from libs/error_injector/stdio/include/stdio_ei.h
copy to libs/error_injector/fts/include/fts_ei.h
index f528e40d..5bb7862d 100644
--- a/libs/error_injector/stdio/include/stdio_ei.h
+++ b/libs/error_injector/fts/include/fts_ei.h
@@ -17,20 +17,20 @@
under the License.
*/
-#ifndef CELIX_STDIO_EI_H
-#define CELIX_STDIO_EI_H
+#ifndef CELIX_FTS_EI_H
+#define CELIX_FTS_EI_H
#ifdef __cplusplus
extern "C" {
#endif
#include "celix_error_injector.h"
-#include <stdio.h>
+#include <fts.h>
-CELIX_EI_DECLARE(fopen, FILE *);
+CELIX_EI_DECLARE(fts_open, FTS*);
-CELIX_EI_DECLARE(fwrite, size_t);
+CELIX_EI_DECLARE(fts_read, FTSENT*);
#ifdef __cplusplus
}
#endif
-#endif //CELIX_STDIO_EI_H
+#endif //CELIX_FTS_EI_H
diff --git a/libs/error_injector/stdio/src/stdio_ei.cc
b/libs/error_injector/fts/src/fts_ei.cc
similarity index 58%
copy from libs/error_injector/stdio/src/stdio_ei.cc
copy to libs/error_injector/fts/src/fts_ei.cc
index 8165c5fd..9d86fc2c 100644
--- a/libs/error_injector/stdio/src/stdio_ei.cc
+++ b/libs/error_injector/fts/src/fts_ei.cc
@@ -17,26 +17,29 @@
under the License.
*/
+#include "fts_ei.h"
#include <errno.h>
-#include "stdio_ei.h"
extern "C" {
-FILE *__real_fopen (const char *__filename, const char *__modes);
-CELIX_EI_DEFINE(fopen, FILE *)
-FILE *__wrap_fopen (const char *__filename, const char *__modes) {
- errno = EMFILE;
- CELIX_EI_IMPL(fopen);
+
+
+FTS *__real_fts_open (char * const *, int, int (*)(const FTSENT **, const
FTSENT **));
+CELIX_EI_DEFINE(fts_open, FTS*)
+FTS *__wrap_fts_open (char * const *path_argv, int options, int
(*compar)(const FTSENT **, const FTSENT **)) {
+ errno = ENOMEM;
+ CELIX_EI_IMPL(fts_open);
errno = 0;
- return __real_fopen(__filename, __modes);
+ return __real_fts_open(path_argv, options, compar);
}
-size_t __real_fwrite (const void *__restrict __ptr, size_t __size, size_t __n,
FILE *__restrict __s);
-CELIX_EI_DEFINE(fwrite, size_t)
-size_t __wrap_fwrite (const void *__restrict __ptr, size_t __size, size_t __n,
FILE *__restrict __s) {
- errno = ENOSPC;
- CELIX_EI_IMPL(fwrite);
+FTSENT *__real_fts_read (FTS *);
+CELIX_EI_DEFINE(fts_read, FTSENT*)
+FTSENT *__wrap_fts_read (FTS *ftsp) {
+ errno = ENOMEM;
+ CELIX_EI_IMPL(fts_read);
errno = 0;
- return __real_fwrite(__ptr, __size, __n, __s);
+ return __real_fts_read(ftsp);
}
+
}
\ No newline at end of file
diff --git a/libs/error_injector/stdio/CMakeLists.txt
b/libs/error_injector/stdio/CMakeLists.txt
index 44882882..cfae3d68 100644
--- a/libs/error_injector/stdio/CMakeLists.txt
+++ b/libs/error_injector/stdio/CMakeLists.txt
@@ -23,5 +23,6 @@ target_link_libraries(stdio_ei PUBLIC Celix::error_injector)
target_link_options(stdio_ei INTERFACE
LINKER:--wrap,fopen
LINKER:--wrap,fwrite
+ LINKER:--wrap,remove
)
add_library(Celix::stdio_ei ALIAS stdio_ei)
diff --git a/libs/error_injector/stdio/include/stdio_ei.h
b/libs/error_injector/stdio/include/stdio_ei.h
index f528e40d..15c2e0ee 100644
--- a/libs/error_injector/stdio/include/stdio_ei.h
+++ b/libs/error_injector/stdio/include/stdio_ei.h
@@ -30,6 +30,8 @@ CELIX_EI_DECLARE(fopen, FILE *);
CELIX_EI_DECLARE(fwrite, size_t);
+CELIX_EI_DECLARE(remove, int);
+
#ifdef __cplusplus
}
#endif
diff --git a/libs/error_injector/stdio/src/stdio_ei.cc
b/libs/error_injector/stdio/src/stdio_ei.cc
index 8165c5fd..e621b249 100644
--- a/libs/error_injector/stdio/src/stdio_ei.cc
+++ b/libs/error_injector/stdio/src/stdio_ei.cc
@@ -39,4 +39,14 @@ size_t __wrap_fwrite (const void *__restrict __ptr, size_t
__size, size_t __n, F
errno = 0;
return __real_fwrite(__ptr, __size, __n, __s);
}
+
+
+int __real_remove (const char *__filename);
+CELIX_EI_DEFINE(remove, int)
+int __wrap_remove (const char *__filename) {
+ errno = EACCES;
+ CELIX_EI_IMPL(remove);
+ errno = 0;
+ return __real_remove(__filename);
+}
}
\ No newline at end of file
diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt
index 2527d6a0..27482733 100644
--- a/libs/utils/gtest/CMakeLists.txt
+++ b/libs/utils/gtest/CMakeLists.txt
@@ -80,7 +80,7 @@ if (LINKER_WRAP_SUPPORTED)
add_executable(test_utils_with_ei
src/FileUtilsErrorInjectionTestSuite.cc
)
- target_link_libraries(test_utils_with_ei PRIVATE Celix::zip_ei
Celix::stdio_ei Celix::stat_ei Celix::utils_obj Celix::utils_ei GTest::gtest
GTest::gtest_main)
+ target_link_libraries(test_utils_with_ei PRIVATE Celix::zip_ei
Celix::stdio_ei Celix::stat_ei Celix::fts_ei Celix::utils_obj Celix::utils_ei
GTest::gtest GTest::gtest_main)
target_include_directories(test_utils_with_ei PRIVATE ../src) #for
version_private (needs refactoring of test)
celix_deprecated_utils_headers(test_utils_with_ei)
add_dependencies(test_utils_with_ei test_utils_resources)
diff --git a/libs/utils/gtest/src/FileUtilsErrorInjectionTestSuite.cc
b/libs/utils/gtest/src/FileUtilsErrorInjectionTestSuite.cc
index 139b95a6..544f371b 100644
--- a/libs/utils/gtest/src/FileUtilsErrorInjectionTestSuite.cc
+++ b/libs/utils/gtest/src/FileUtilsErrorInjectionTestSuite.cc
@@ -20,6 +20,7 @@
#include <fstream>
#include <gtest/gtest.h>
#include <stdlib.h>
+#include <string.h>
#include <string>
#include <thread>
#include <unistd.h>
@@ -28,6 +29,7 @@
#include "celix_file_utils.h"
#include "celix_properties.h"
#include "celix_utils_ei.h"
+#include "fts_ei.h"
#include "stat_ei.h"
#include "stdio_ei.h"
#include "zip_ei.h"
@@ -42,8 +44,11 @@ public:
celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr);
celix_ei_expect_fopen(nullptr, 0, nullptr);
celix_ei_expect_fwrite(nullptr, 0, 0);
+ celix_ei_expect_remove(nullptr, 0, 0);
celix_ei_expect_mkdir(nullptr, 0, 0);
celix_ei_expect_stat(nullptr, 0, 0);
+ celix_ei_expect_fts_open(nullptr, 0, nullptr);
+ celix_ei_expect_fts_read(nullptr, 0, nullptr);
}
};
@@ -147,4 +152,55 @@ TEST_F(FileUtilsWithErrorInjectionTestSuite,
CreateDirectory) {
status = celix_utils_createDirectory(testDir.c_str(), true, &error);
EXPECT_EQ(status, CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,EOVERFLOW));
EXPECT_NE(error, nullptr);
-}
\ No newline at end of file
+ celix_utils_deleteDirectory(root.c_str(), nullptr);
+}
+
+TEST_F(FileUtilsWithErrorInjectionTestSuite, DeleteDirectory) {
+ const std::string root = "celix_file_utils_test";
+ const std::string testDir = root + "/directory";
+
+ auto status = celix_utils_createDirectory(root.c_str(), false, nullptr);
+ EXPECT_EQ(status, CELIX_SUCCESS);
+ celix_ei_expect_fts_open(CELIX_EI_UNKNOWN_CALLER, 0, nullptr);
+ celix_ei_expect_fts_read(nullptr, 0, nullptr);
+ const char* error = nullptr;
+ status = celix_utils_deleteDirectory(root.c_str(), &error);
+ EXPECT_EQ(status, CELIX_ENOMEM);
+ EXPECT_NE(error, nullptr);
+ EXPECT_TRUE(celix_utils_directoryExists(root.c_str()));
+
+ status = celix_utils_createDirectory(testDir.c_str(), false, nullptr);
+ EXPECT_EQ(status, CELIX_SUCCESS);
+ celix_ei_expect_fts_open(nullptr, 0, nullptr);
+ // fts_open followed by fts_close without calling fts_read will cause
memory leak reported by ASAN
+ celix_ei_expect_fts_read(CELIX_EI_UNKNOWN_CALLER, 0, nullptr, 2);
+ status = celix_utils_deleteDirectory(root.c_str(), &error);
+ EXPECT_EQ(status, CELIX_ENOMEM);
+ EXPECT_NE(error, nullptr);
+ EXPECT_TRUE(celix_utils_directoryExists(root.c_str()));
+
+ status = celix_utils_createDirectory(testDir.c_str(), false, nullptr);
+ EXPECT_EQ(status, CELIX_SUCCESS);
+ FTSENT ent;
+ memset(&ent, 0, sizeof(ent));
+ ent.fts_info = FTS_DNR;
+ ent.fts_errno = EACCES;
+ celix_ei_expect_fts_open(nullptr, 0, nullptr);
+ // fts_open followed by fts_close without calling fts_read will cause
memory leak reported by ASAN
+ celix_ei_expect_fts_read(CELIX_EI_UNKNOWN_CALLER, 0, &ent, 2);
+ status = celix_utils_deleteDirectory(root.c_str(), &error);
+ EXPECT_EQ(status, CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,EACCES));
+ EXPECT_NE(error, nullptr);
+ EXPECT_TRUE(celix_utils_directoryExists(root.c_str()));
+
+ status = celix_utils_createDirectory(testDir.c_str(), false, nullptr);
+ EXPECT_EQ(status, CELIX_SUCCESS);
+ celix_ei_expect_remove(CELIX_EI_UNKNOWN_CALLER, 0, -1);
+ status = celix_utils_deleteDirectory(root.c_str(), &error);
+ EXPECT_EQ(status, CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,EACCES));
+ EXPECT_NE(error, nullptr);
+ EXPECT_TRUE(celix_utils_directoryExists(root.c_str()));
+
+ status = celix_utils_deleteDirectory(root.c_str(), &error);
+ EXPECT_EQ(status, CELIX_SUCCESS);
+}
diff --git a/libs/utils/gtest/src/FileUtilsTestSuite.cc
b/libs/utils/gtest/src/FileUtilsTestSuite.cc
index 79bc80ea..0b4755a9 100644
--- a/libs/utils/gtest/src/FileUtilsTestSuite.cc
+++ b/libs/utils/gtest/src/FileUtilsTestSuite.cc
@@ -17,6 +17,7 @@
* under the License.
*/
+#include <fstream>
#include <gtest/gtest.h>
#include <stdlib.h>
#include <string>
@@ -132,6 +133,38 @@ TEST_F(FileUtilsTestSuite, CreateAndDeleteDirectory) {
EXPECT_EQ(status, CELIX_SUCCESS);
}
+TEST_F(FileUtilsTestSuite, DeleteFileAsDirectory) {
+ const std::string root = "celix_file_utils_test";
+ celix_utils_deleteDirectory(root.c_str(), nullptr);
+ const char* error = nullptr;
+ celix_utils_createDirectory(root.c_str(), true, nullptr);
+ const std::string filename = root + "/file";
+ std::fstream file(filename, std::ios::out);
+ file.close();
+ auto status = celix_utils_deleteDirectory(filename.c_str(), &error);
+ EXPECT_EQ(status, CELIX_FILE_IO_EXCEPTION);
+ EXPECT_NE(error, nullptr);
+ EXPECT_TRUE(celix_utils_fileExists(filename.c_str()));
+ celix_utils_deleteDirectory(root.c_str(), nullptr);
+}
+
+TEST_F(FileUtilsTestSuite, DeleteSymbolicLinkToDirectory) {
+ const std::string root = "celix_file_utils_test";
+ const std::string testDir = root + "/directory";
+ const std::string symLink = root + "/link";
+ celix_utils_deleteDirectory(root.c_str(), nullptr);
+ const char* error = nullptr;
+ celix_utils_createDirectory(testDir.c_str(), true, nullptr);
+ auto status = symlink("./directory", symLink.c_str()); // link ->
./directory
+ EXPECT_EQ(status, 0);
+ status = celix_utils_deleteDirectory(symLink.c_str(), &error);
+ EXPECT_EQ(status, CELIX_SUCCESS);
+ EXPECT_EQ(error, nullptr);
+ EXPECT_FALSE(celix_utils_fileExists(symLink.c_str()));
+ EXPECT_TRUE(celix_utils_directoryExists(testDir.c_str()));
+ celix_utils_deleteDirectory(root.c_str(), nullptr);
+}
+
TEST_F(FileUtilsTestSuite, ExtractZipFileTest) {
std::cout << "Using test zip location " << TEST_ZIP_LOCATION << std::endl;
const char* extractLocation = "extract_location";
diff --git a/libs/utils/src/celix_file_utils.c
b/libs/utils/src/celix_file_utils.c
index 66abddd4..dcfd6b70 100644
--- a/libs/utils/src/celix_file_utils.c
+++ b/libs/utils/src/celix_file_utils.c
@@ -172,37 +172,36 @@ celix_status_t celix_utils_deleteDirectory(const char*
path, const char** errorO
//file exist and is directory
celix_status_t status = CELIX_SUCCESS;
char *paths[] = { (char*)path, NULL };
- FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_XDEV | FTS_NOCHDIR, NULL);
+ FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_XDEV | FTS_NOCHDIR |
FTS_NOSTAT, NULL);
if (fts == NULL) {
- status = CELIX_FILE_IO_EXCEPTION;
- *errorOut = strerror(errno);
- } else {
- FTSENT *ent;
- while ((ent = fts_read(fts)) != NULL) {
- switch (ent->fts_info) {
- case FTS_DP:
- case FTS_F:
- case FTS_SL:
- case FTS_SLNONE:
- if (remove(ent->fts_accpath) != 0) {
- status = CELIX_FILE_IO_EXCEPTION;
- *errorOut = strerror(errno);
- }
- break;
- case FTS_DNR:
- case FTS_ERR:
- case FTS_NS:
- status = CELIX_FILE_IO_EXCEPTION;
- *errorOut = strerror(ent->fts_errno);
- break;
- default:
- break;
- }
- if (status != CELIX_SUCCESS) {
+ goto out;
+ }
+ FTSENT *ent = NULL;
+ while ((ent = fts_read(fts)) != NULL) {
+ switch (ent->fts_info) {
+ case FTS_DP:
+ case FTS_NSOK:
+ case FTS_SL:
+ case FTS_SLNONE:
+ if (remove(ent->fts_accpath) != 0) {
+ goto out;
+ }
+ break;
+ case FTS_DNR:
+ case FTS_ERR:
+ errno = ent->fts_errno;
+ goto out;
+ default:
break;
- }
}
- fts_close(fts);
+ }
+out:
+ if (errno != 0) {
+ status = CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,errno);
+ *errorOut = strerror(errno);
+ }
+ if (fts != NULL) {
+ fts_close(fts); // it may change errno
}
return status;
}