diff --git a/CommandListener.cpp b/CommandListener.cpp index 6bfb8da..0ac656b 100644 --- a/CommandListener.cpp +++ b/CommandListener.cpp @@ -200,6 +200,12 @@ int CommandListener::VolumeCmd::runCommand(SocketClient *cli, (enabled ? "Share enabled" : "Share disabled"), false); } return 0; + } else if (!strcmp(argv[1], "mkdirs")) { + if (argc != 3) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mkdirs ", false); + return 0; + } + rc = vm->mkdirs(argv[2]); } else { cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false); } diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 180387c..f606b5b 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -32,6 +32,7 @@ #include +#include #include #include @@ -1577,6 +1578,26 @@ int VolumeManager::cleanupAsec(Volume *v, bool force) { } return rc; - } +int VolumeManager::mkdirs(char* path) { + // Require that path lives under a volume we manage + const char* emulated_source = getenv("EMULATED_STORAGE_SOURCE"); + const char* root = NULL; + if (!strncmp(path, emulated_source, strlen(emulated_source))) { + root = emulated_source; + } else { + Volume* vol = getVolumeForFile(path); + if (vol) { + root = vol->getMountpoint(); + } + } + + if (!root) { + SLOGE("Failed to find volume for %s", path); + return -EINVAL; + } + + /* fs_mkdirs() does symlink checking and relative path enforcement */ + return fs_mkdirs(path, 0700); +} diff --git a/VolumeManager.h b/VolumeManager.h index be78516..9d69d6a 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -140,6 +140,15 @@ public: int getDirectVolumeList(struct volume_info *vol_list); int unmountAllAsecsInDir(const char *directory); + /* + * Ensure that all directories along given path exist, creating parent + * directories as needed. Validates that given path is absolute and that + * it contains no relative "." or ".." paths or symlinks. Last path segment + * is treated as filename and ignored, unless the path ends with "/". Also + * ensures that path belongs to a volume managed by vold. + */ + int mkdirs(char* path); + private: VolumeManager(); void readInitialState();