Add syncs when creating parent directories
vold creates some directories for storing encryption keys if they don't
already exist, potentially including parent directories:
/metadata/vold/metadata_encryption
/data/misc/vold/volume_keys/$volume_uuid
/data/misc_de/$user/vold/volume_keys/$volume_uuid
/data/misc_ce/$user/vold/volume_keys/$volume_uuid
Currently fs_mkdirs() is used for this. However, fs_mkdirs() doesn't
include the fsync()s of the parent directories that are needed to ensure
that the new directories are persisted to disk right away -- which is
important for encryption keys.
Add a utility function MkdirsSync() which does what is needed, and make
the appropriate places call it.
Test: Booted and checked log for "Created directory" message.
Also ran 'atest vold_tests' to run the new unit test.
Change-Id: Ie9917b616433080139b8db3fd6877203ee6faf77
diff --git a/Utils.cpp b/Utils.cpp
index c1fbf8f..cef0f39 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -1375,6 +1375,36 @@
return FsyncDirectory(android::base::Dirname(path));
}
+// Creates all parent directories of |path| that don't already exist. Assigns
+// the specified |mode| to any new directories, and also fsync()s their parent
+// directories so that the new directories get written to disk right away.
+bool MkdirsSync(const std::string& path, mode_t mode) {
+ if (path[0] != '/') {
+ LOG(ERROR) << "MkdirsSync() needs an absolute path, but got " << path;
+ return false;
+ }
+ std::vector<std::string> components = android::base::Split(android::base::Dirname(path), "/");
+
+ std::string current_dir = "/";
+ for (const std::string& component : components) {
+ if (component.empty()) continue;
+
+ std::string parent_dir = current_dir;
+ if (current_dir != "/") current_dir += "/";
+ current_dir += component;
+
+ if (!pathExists(current_dir)) {
+ if (mkdir(current_dir.c_str(), mode) != 0) {
+ PLOG(ERROR) << "Failed to create " << current_dir;
+ return false;
+ }
+ if (!FsyncDirectory(parent_dir)) return false;
+ LOG(DEBUG) << "Created directory " << current_dir;
+ }
+ }
+ return true;
+}
+
bool writeStringToFile(const std::string& payload, const std::string& filename) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(
open(filename.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0666)));