diff --git a/init/util.cpp b/init/util.cpp index af6cf509b..20c1088ea 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -458,6 +458,24 @@ Result IsLegalPropertyValue(const std::string& name, const std::string& va return {}; } +// Remove unnecessary slashes so that any later checks (e.g., the check for +// whether the path is a top-level directory in /data) don't get confused. +std::string CleanDirPath(const std::string& path) { + std::string result; + result.reserve(path.length()); + // Collapse duplicate slashes, e.g. //data//foo// => /data/foo/ + for (char c : path) { + if (c != '/' || result.empty() || result.back() != '/') { + result += c; + } + } + // Remove trailing slash, e.g. /data/foo/ => /data/foo + if (result.length() > 1 && result.back() == '/') { + result.pop_back(); + } + return result; +} + static FscryptAction FscryptInferAction(const std::string& dir) { const std::string prefix = "/data/"; @@ -499,10 +517,11 @@ static FscryptAction FscryptInferAction(const std::string& dir) { } Result ParseMkdir(const std::vector& args) { + std::string path = CleanDirPath(args[1]); mode_t mode = 0755; Result uid = -1; Result gid = -1; - FscryptAction fscrypt_inferred_action = FscryptInferAction(args[1]); + FscryptAction fscrypt_inferred_action = FscryptInferAction(path); FscryptAction fscrypt_action = fscrypt_inferred_action; std::string ref_option = "ref"; bool set_option_encryption = false; @@ -569,14 +588,13 @@ Result ParseMkdir(const std::vector& args) { return Error() << "Key option set but encryption action is none"; } const std::string prefix = "/data/"; - if (StartsWith(args[1], prefix) && - args[1].find_first_of('/', prefix.size()) == std::string::npos) { + if (StartsWith(path, prefix) && path.find_first_of('/', prefix.size()) == std::string::npos) { if (!set_option_encryption) { - LOG(WARNING) << "Top-level directory needs encryption action, eg mkdir " << args[1] + LOG(WARNING) << "Top-level directory needs encryption action, eg mkdir " << path << " encryption=Require"; } if (fscrypt_action == FscryptAction::kNone) { - LOG(INFO) << "Not setting encryption policy on: " << args[1]; + LOG(INFO) << "Not setting encryption policy on: " << path; } } if (fscrypt_action != fscrypt_inferred_action) { @@ -585,7 +603,7 @@ Result ParseMkdir(const std::vector& args) { << static_cast(fscrypt_action); } - return MkdirOptions{args[1], mode, *uid, *gid, fscrypt_action, ref_option}; + return MkdirOptions{path, mode, *uid, *gid, fscrypt_action, ref_option}; } Result ParseMountAll(const std::vector& args) { diff --git a/init/util.h b/init/util.h index bf5367531..47d4ff518 100644 --- a/init/util.h +++ b/init/util.h @@ -69,6 +69,7 @@ bool is_android_dt_value_expected(const std::string& sub_path, const std::string bool IsLegalPropertyName(const std::string& name); Result IsLegalPropertyValue(const std::string& name, const std::string& value); +std::string CleanDirPath(const std::string& path); struct MkdirOptions { std::string target; diff --git a/init/util_test.cpp b/init/util_test.cpp index 565e7d4f0..e8144c307 100644 --- a/init/util_test.cpp +++ b/init/util_test.cpp @@ -170,5 +170,18 @@ TEST(util, mkdir_recursive_extra_slashes) { EXPECT_TRUE(is_dir(path1.c_str())); } +TEST(util, CleanDirPath) { + EXPECT_EQ("", CleanDirPath("")); + EXPECT_EQ("/", CleanDirPath("/")); + EXPECT_EQ("/", CleanDirPath("//")); + EXPECT_EQ("/foo", CleanDirPath("/foo")); + EXPECT_EQ("/foo", CleanDirPath("//foo")); + EXPECT_EQ("/foo", CleanDirPath("/foo/")); + EXPECT_EQ("/foo/bar", CleanDirPath("/foo/bar")); + EXPECT_EQ("/foo/bar", CleanDirPath("/foo/bar/")); + EXPECT_EQ("/foo/bar", CleanDirPath("/foo/bar////")); + EXPECT_EQ("/foo/bar", CleanDirPath("//foo//bar")); +} + } // namespace init } // namespace android