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 8a6ec904 Reduce dynamic memory allocation in
celix_utils_createDirectory.
8a6ec904 is described below
commit 8a6ec9041494383f034eea37c01ff59e37690986
Author: PengZheng <[email protected]>
AuthorDate: Wed Mar 29 22:20:44 2023 +0800
Reduce dynamic memory allocation in celix_utils_createDirectory.
---
.../celix_utils/src/celix_utils_ei.cc | 2 +
.../gtest/src/FileUtilsErrorInjectionTestSuite.cc | 15 ++++
libs/utils/src/celix_file_utils.c | 79 ++++++++++++++++------
3 files changed, 76 insertions(+), 20 deletions(-)
diff --git a/libs/error_injector/celix_utils/src/celix_utils_ei.cc
b/libs/error_injector/celix_utils/src/celix_utils_ei.cc
index 2db67233..24496158 100644
--- a/libs/error_injector/celix_utils/src/celix_utils_ei.cc
+++ b/libs/error_injector/celix_utils/src/celix_utils_ei.cc
@@ -26,7 +26,9 @@ extern "C" {
char* __real_celix_utils_strdup(const char *);
CELIX_EI_DEFINE(celix_utils_strdup, char*)
char* __wrap_celix_utils_strdup(const char* str) {
+ errno = ENOMEM;
CELIX_EI_IMPL(celix_utils_strdup);
+ errno = 0;
return __real_celix_utils_strdup(str);
}
diff --git a/libs/utils/gtest/src/FileUtilsErrorInjectionTestSuite.cc
b/libs/utils/gtest/src/FileUtilsErrorInjectionTestSuite.cc
index 6000c21e..c0b60a68 100644
--- a/libs/utils/gtest/src/FileUtilsErrorInjectionTestSuite.cc
+++ b/libs/utils/gtest/src/FileUtilsErrorInjectionTestSuite.cc
@@ -37,6 +37,7 @@ public:
celix_ei_expect_zip_fopen_index(nullptr, 0, nullptr);
celix_ei_expect_zip_fread(nullptr, 0, -1);
celix_ei_expect_celix_utils_writeOrCreateString(nullptr, 0, nullptr);
+ celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr);
celix_ei_expect_fopen(nullptr, 0, nullptr);
celix_ei_expect_fwrite(nullptr, 0, 0);
}
@@ -94,4 +95,18 @@ TEST_F(FileUtilsWithErrorInjectionTestSuite,
ExtractZipFileTest) {
status = celix_utils_extractZipFile(TEST_ZIP_LOCATION, extractLocation,
&error);
EXPECT_EQ(status, CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,ENOSPC));
EXPECT_NE(error, nullptr);
+}
+
+TEST_F(FileUtilsWithErrorInjectionTestSuite, CreateDirectory) {
+ const char* testDir = "celix_file_utils_test/directory";
+ celix_utils_deleteDirectory(testDir, nullptr);
+
+ //I can create a new directory.
+ const char* error = nullptr;
+ EXPECT_FALSE(celix_utils_directoryExists(testDir));
+ celix_ei_expect_celix_utils_strdup(CELIX_EI_UNKNOWN_CALLER, 0, nullptr);
+ auto status = celix_utils_createDirectory(testDir, true, &error);
+ EXPECT_EQ(status, CELIX_ENOMEM);
+ EXPECT_NE(error, nullptr);
+ EXPECT_FALSE(celix_utils_fileExists(testDir));
}
\ No newline at end of file
diff --git a/libs/utils/src/celix_file_utils.c
b/libs/utils/src/celix_file_utils.c
index 18203e54..97689995 100644
--- a/libs/utils/src/celix_file_utils.c
+++ b/libs/utils/src/celix_file_utils.c
@@ -48,8 +48,41 @@ bool celix_utils_directoryExists(const char* path) {
return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
}
+// https://gist.github.com/JonathonReinhart/8c0d90191c38af2dcadb102c4e202950
+/* Make a directory; already existing dir okay */
+static int maybe_mkdir(const char* path, mode_t mode)
+{
+ struct stat st;
+ errno = 0;
+
+ /* Try to make the directory */
+ if (mkdir(path, mode) == 0)
+ return 0;
+
+ /* If it fails for any reason but EEXIST, fail */
+ if (errno != EEXIST)
+ return -1;
+
+ /* Check if the existing path is a directory */
+ if (stat(path, &st) != 0)
+ return -1;
+
+ /* If not, fail with ENOTDIR */
+ if (!S_ISDIR(st.st_mode)) {
+ errno = ENOTDIR;
+ return -1;
+ }
+
+ errno = 0;
+ return 0;
+}
+
celix_status_t celix_utils_createDirectory(const char* path, bool
failIfPresent, const char** errorOut) {
const char *dummyErrorOut = NULL;
+ if (*path == '\0') {
+ //empty path, nothing to do
+ return CELIX_SUCCESS;
+ }
if (errorOut) {
//reset errorOut
*errorOut = NULL;
@@ -77,30 +110,36 @@ celix_status_t celix_utils_createDirectory(const char*
path, bool failIfPresent,
celix_status_t status = CELIX_SUCCESS;
- //loop over al finding of / and create intermediate dirs
- for (char* slashAt = strchr(path, '/'); slashAt != NULL; slashAt =
strchr(slashAt + 1, '/')) {
- // skip the first / of the absolute path
- if( slashAt == path) {
- continue;
- }
- char* subPath = strndup(path, slashAt - path);
- if (!celix_utils_directoryExists(subPath)) {
- int rc = mkdir(subPath, S_IRWXU);
- if (rc != 0) {
- status = CELIX_FILE_IO_EXCEPTION;
- *errorOut = strerror(errno);
+ char *_path = NULL;
+ char *p;
+ int result = -1;
+ errno = 0;
+ /* Copy string so it's mutable */
+ _path = celix_utils_strdup(path);
+ if (_path == NULL)
+ goto out;
+
+ /* Iterate the string */
+ for (p = _path + 1; *p; p++) {
+ if (*p == '/') {
+ /* Temporarily truncate */
+ *p = '\0';
+ if (maybe_mkdir(_path, S_IRWXU) != 0) {
+ goto out;
}
+ *p = '/';
}
- free(subPath);
}
+ if (maybe_mkdir(_path, S_IRWXU) != 0) {
+ goto out;
+ }
+ result = 0;
- //create last part of the dir (expect when path ends with / then this is
already done in the loop)
- if (status == CELIX_SUCCESS && strlen(path) >0 && path[strlen(path)-1] !=
'/') {
- int rc = mkdir(path, S_IRWXU);
- if (rc != 0) {
- status = CELIX_FILE_IO_EXCEPTION;
- *errorOut = strerror(errno);
- }
+out:
+ free(_path);
+ if (result != 0) {
+ status = CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,errno);
+ *errorOut = strerror(errno);
}
return status;
}