diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp index 919b65bc3..13c4abf98 100644 --- a/libcutils/fs_config.cpp +++ b/libcutils/fs_config.cpp @@ -266,14 +266,27 @@ static bool is_partition(const char* path, size_t len) { return false; } +static inline bool prefix_cmp(bool partial, const char* prefix, size_t len, const char* path, + size_t plen) { + return ((partial && plen >= len) || (plen == len)) && !strncmp(prefix, path, len); +} + // alias prefixes of "/" to "system//" or // "system//" to "/" -static bool prefix_cmp(const char* prefix, const char* path, size_t len) { - if (!strncmp(prefix, path, len)) return true; +static bool fs_config_cmp(bool partial, const char* prefix, size_t len, const char* path, + size_t plen) { + // If name ends in * then allow partial matches. + if (!partial && prefix[len - 1] == '*') { + len--; + partial = true; + } + + if (prefix_cmp(partial, prefix, len, path, plen)) return true; static const char system[] = "system/"; if (!strncmp(path, system, strlen(system))) { path += strlen(system); + plen -= strlen(system); } else if (len <= strlen(system)) { return false; } else if (strncmp(prefix, system, strlen(system))) { @@ -282,25 +295,11 @@ static bool prefix_cmp(const char* prefix, const char* path, size_t len) { prefix += strlen(system); len -= strlen(system); } - return is_partition(prefix, len) && !strncmp(prefix, path, len); -} - -static bool fs_config_cmp(bool dir, const char* prefix, size_t len, const char* path, size_t plen) { - if (dir) { - if (plen < len) { - return false; - } - } else { - // If name ends in * then allow partial matches. - if (prefix[len - 1] == '*') { - return prefix_cmp(prefix, path, len - 1); - } - if (plen != len) { - return false; - } - } - return prefix_cmp(prefix, path, len); + return is_partition(prefix, len) && prefix_cmp(partial, prefix, len, path, plen); } +#ifndef __ANDROID_VNDK__ +auto __for_testing_only__fs_config_cmp = fs_config_cmp; +#endif void fs_config(const char* path, int dir, const char* target_out_path, unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) { diff --git a/libcutils/tests/fs_config.cpp b/libcutils/tests/fs_config.cpp index a62cd51a2..391adb64b 100644 --- a/libcutils/tests/fs_config.cpp +++ b/libcutils/tests/fs_config.cpp @@ -29,12 +29,39 @@ extern const fs_path_config* __for_testing_only__android_dirs; extern const fs_path_config* __for_testing_only__android_files; +extern bool (*__for_testing_only__fs_config_cmp)(bool, const char*, size_t, const char*, size_t); // Maximum entries in system/core/libcutils/fs_config.cpp:android_* before we // hit a nullptr termination, before we declare the list is just too big or // could be missing the nullptr. static constexpr size_t max_idx = 4096; +static const struct fs_config_cmp_test { + bool dir; + const char* prefix; + const char* path; + bool match; +} fs_config_cmp_tests[] = { + // clang-format off + { true, "system/lib", "system/lib/hw", true }, + { true, "vendor/lib", "system/vendor/lib/hw", true }, + { true, "system/vendor/lib", "vendor/lib/hw", true }, + { true, "system/vendor/lib", "system/vendor/lib/hw", true }, + { false, "vendor/bin/wifi", "system/vendor/bin/w", false }, + { false, "vendor/bin/wifi", "system/vendor/bin/wifi", true }, + { false, "vendor/bin/wifi", "system/vendor/bin/wifi2", false }, + { false, "system/vendor/bin/wifi", "system/vendor/bin/wifi", true, }, + { false, "odm/bin/wifi", "system/odm/bin/wifi", true }, + { false, "oem/bin/wifi", "system/oem/bin/wifi", true }, + { false, "data/bin/wifi", "system/data/bin/wifi", false }, + { false, "system/bin/*", "system/bin/wifi", true }, + { false, "vendor/bin/*", "system/vendor/bin/wifi", true }, + { false, "system/bin/*", "system/bin", false }, + { false, "system/vendor/bin/*", "vendor/bin/wifi", true }, + { false, NULL, NULL, false }, + // clang-format on +}; + static bool check_unique(std::vector& paths, const std::string& config_name, const std::string& prefix) { bool retval = false; @@ -106,6 +133,22 @@ static bool check_unique(const fs_path_config* paths, const char* type_name, return check_unique(paths_tmp, config, prefix) || retval; } +static bool check_fs_config_cmp(const fs_config_cmp_test* tests) { + bool match, retval = false; + for (size_t idx = 0; tests[idx].prefix; ++idx) { + match = __for_testing_only__fs_config_cmp(tests[idx].dir, tests[idx].prefix, + strlen(tests[idx].prefix), tests[idx].path, + strlen(tests[idx].path)); + if (match != tests[idx].match) { + GTEST_LOG_(ERROR) << tests[idx].path << (match ? " matched " : " didn't match ") + << tests[idx].prefix; + retval = true; + break; + } + } + return retval; +} + #define endof(pointer, field) (offsetof(typeof(*(pointer)), field) + sizeof((pointer)->field)) static bool check_unique(const std::string& config, const std::string& prefix) { @@ -199,3 +242,7 @@ TEST(fs_config, odm_dirs_alias) { TEST(fs_config, odm_files_alias) { check_two(__for_testing_only__android_files, "files", "odm/"); } + +TEST(fs_config, system_alias) { + EXPECT_FALSE(check_fs_config_cmp(fs_config_cmp_tests)); +}