Add mkdirs() command.

Apps without sdcard_r or sdcard_rw need to have someone create
package-specific directories on their behalf.  If apps have trouble
creating on their own, they now delegate through system to have
vold create the paths.

Requires that the requested path is actually managed by vold.

Bug: 10577808
Change-Id: I6835fc8f52240f9de07f89742a426a153e3ca32a
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 5de920f..049d42c 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -202,6 +202,12 @@
                     (enabled ? "Share enabled" : "Share disabled"), false);
         }
         return 0;
+    } else if (!strcmp(argv[1], "mkdirs")) {
+        if (argc != 3) {
+            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mkdirs <path>", 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 <openssl/md5.h>
 
+#include <cutils/fs.h>
 #include <cutils/log.h>
 
 #include <sysutils/NetlinkEvent.h>
@@ -1577,6 +1578,26 @@
     }
 
     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 @@
     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();