ueventd: convert mkdir_recursive() to std::string
Bug: 36250207
Test: Boot bullhead
Test: Boot sailfish, observe no boot time regression
Test: init unit tests
Change-Id: I5a2ac369d846e044230b709fd07eb21ad12d47bb
diff --git a/init/Android.mk b/init/Android.mk
index dbbf40a..7e9b613 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -148,8 +148,9 @@
util_test.cpp \
LOCAL_SHARED_LIBRARIES += \
- libcutils \
libbase \
+ libcutils \
+ libselinux \
LOCAL_STATIC_LIBRARIES := libinit
LOCAL_SANITIZE := integer
diff --git a/init/util.cpp b/init/util.cpp
index bbc59cb..32ae93d 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -194,37 +194,18 @@
return success;
}
-int mkdir_recursive(const char *pathname, mode_t mode)
-{
- char buf[128];
- const char *slash;
- const char *p = pathname;
- int width;
- int ret;
- struct stat info;
-
- while ((slash = strchr(p, '/')) != NULL) {
- width = slash - pathname;
- p = slash + 1;
- if (width < 0)
- break;
- if (width == 0)
- continue;
- if ((unsigned int)width > sizeof(buf) - 1) {
- LOG(ERROR) << "path too long for mkdir_recursive";
- return -1;
- }
- memcpy(buf, pathname, width);
- buf[width] = 0;
- if (stat(buf, &info) != 0) {
- ret = make_dir(buf, mode);
- if (ret && errno != EEXIST)
- return ret;
+int mkdir_recursive(const std::string& path, mode_t mode) {
+ std::string::size_type slash = 0;
+ while ((slash = path.find('/', slash + 1)) != std::string::npos) {
+ auto directory = path.substr(0, slash);
+ struct stat info;
+ if (stat(directory.c_str(), &info) != 0) {
+ auto ret = make_dir(directory.c_str(), mode);
+ if (ret && errno != EEXIST) return ret;
}
}
- ret = make_dir(pathname, mode);
- if (ret && errno != EEXIST)
- return ret;
+ auto ret = make_dir(path.c_str(), mode);
+ if (ret && errno != EEXIST) return ret;
return 0;
}
diff --git a/init/util.h b/init/util.h
index 38a7bdb..0bb9cdf 100644
--- a/init/util.h
+++ b/init/util.h
@@ -60,7 +60,7 @@
unsigned int decode_uid(const char *s);
-int mkdir_recursive(const char *pathname, mode_t mode);
+int mkdir_recursive(const std::string& pathname, mode_t mode);
int wait_for_file(const char *filename, std::chrono::nanoseconds timeout);
void import_kernel_cmdline(bool in_qemu,
const std::function<void(const std::string&, const std::string&, bool)>&);
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 0c0350a..b8b409a 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -120,3 +120,39 @@
EXPECT_EQ(UINT_MAX, decode_uid("toot"));
EXPECT_EQ(123U, decode_uid("123"));
}
+
+TEST(util, is_dir) {
+ TemporaryDir test_dir;
+ EXPECT_TRUE(is_dir(test_dir.path));
+ TemporaryFile tf;
+ EXPECT_FALSE(is_dir(tf.path));
+}
+
+// sehandle is needed for make_dir()
+// TODO: Remove once sehandle is encapsulated
+#include <selinux/label.h>
+selabel_handle* sehandle;
+
+TEST(util, mkdir_recursive) {
+ TemporaryDir test_dir;
+ std::string path = android::base::StringPrintf("%s/three/directories/deep", test_dir.path);
+ EXPECT_EQ(0, mkdir_recursive(path, 0755));
+ std::string path1 = android::base::StringPrintf("%s/three", test_dir.path);
+ EXPECT_TRUE(is_dir(path1.c_str()));
+ std::string path2 = android::base::StringPrintf("%s/three/directories", test_dir.path);
+ EXPECT_TRUE(is_dir(path1.c_str()));
+ std::string path3 = android::base::StringPrintf("%s/three/directories/deep", test_dir.path);
+ EXPECT_TRUE(is_dir(path1.c_str()));
+}
+
+TEST(util, mkdir_recursive_extra_slashes) {
+ TemporaryDir test_dir;
+ std::string path = android::base::StringPrintf("%s/three////directories/deep//", test_dir.path);
+ EXPECT_EQ(0, mkdir_recursive(path, 0755));
+ std::string path1 = android::base::StringPrintf("%s/three", test_dir.path);
+ EXPECT_TRUE(is_dir(path1.c_str()));
+ std::string path2 = android::base::StringPrintf("%s/three/directories", test_dir.path);
+ EXPECT_TRUE(is_dir(path1.c_str()));
+ std::string path3 = android::base::StringPrintf("%s/three/directories/deep", test_dir.path);
+ EXPECT_TRUE(is_dir(path1.c_str()));
+}