vold2: Initial support for Android Secure External Caches

Signed-off-by: San Mehat <san@google.com>
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 462029c..f4b62c4 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -19,6 +19,10 @@
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+
 #include <linux/kdev_t.h>
 
 #define LOG_TAG "Vold"
@@ -30,6 +34,8 @@
 #include "VolumeManager.h"
 #include "DirectVolume.h"
 #include "ResponseCode.h"
+#include "Loop.h"
+#include "Fat.h"
 
 VolumeManager *VolumeManager::sInstance = NULL;
 
@@ -149,6 +155,191 @@
     return v->formatVol();
 }
 
+int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
+    char mountPoint[255];
+
+    snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
+
+    if (!isMountpointMounted(mountPoint)) {
+        errno = ENOENT;
+        return -1;
+    } 
+    snprintf(buffer, maxlen, "/asec/%s", id);
+    return 0;
+}
+
+int VolumeManager::createAsec(const char *id, int sizeMb,
+                              const char *fstype, const char *key, int ownerUid) {
+
+    mkdir("/sdcard/android_secure", 0777);
+
+    if (lookupVolume(id)) {
+        LOGE("ASEC volume '%s' currently exists", id);
+        errno = EADDRINUSE;
+        return -1;
+    }
+
+    char asecFileName[255];
+    snprintf(asecFileName, sizeof(asecFileName),
+             "/sdcard/android_secure/%s.asec", id);
+
+    if (!access(asecFileName, F_OK)) {
+        LOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
+             asecFileName, strerror(errno));
+        errno = EADDRINUSE;
+        return -1;
+    }
+
+    if (Loop::createImageFile(asecFileName, sizeMb)) {
+        LOGE("ASEC image file creation failed (%s)", strerror(errno));
+        return -1;
+    }
+
+    char loopDevice[255];
+    if (Loop::getNextAvailable(loopDevice, sizeof(loopDevice))) {
+        unlink(asecFileName);
+        return -1;
+    }
+
+    if (Loop::create(loopDevice, asecFileName)) {
+        LOGE("ASEC loop device creation failed (%s)", strerror(errno));
+        unlink(asecFileName);
+        return -1;
+    }
+
+    /* XXX: Start devmapper */
+
+    if (Fat::format(loopDevice)) {
+        LOGE("ASEC FAT format failed (%s)", strerror(errno));
+        Loop::destroyByDevice(loopDevice);
+        unlink(asecFileName);
+        return -1;
+    }
+
+    char mountPoint[255];
+
+    snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
+    if (mkdir(mountPoint, 0777)) {
+        LOGE("Mountpoint creation failed (%s)", strerror(errno));
+        Loop::destroyByDevice(loopDevice);
+        unlink(asecFileName);
+        return -1;
+    }
+
+    if (Fat::doMount(loopDevice, mountPoint, false, false)) {
+        LOGE("ASEC FAT mount failed (%s)", strerror(errno));
+        Loop::destroyByDevice(loopDevice);
+        unlink(asecFileName);
+        return -1;
+    }
+    
+    return 0;
+}
+
+int VolumeManager::finalizeAsec(const char *id) {
+    char asecFileName[255];
+    char loopDevice[255];
+    char mountPoint[255];
+
+    snprintf(asecFileName, sizeof(asecFileName),
+             "/sdcard/android_secure/%s.asec", id);
+
+    if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
+        LOGE("Unable to finalize %s (%s)", id, strerror(errno));
+        return -1;
+    }
+
+    snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
+    if (Fat::doMount(loopDevice, mountPoint, true, true)) {
+        LOGE("ASEC finalize mount failed (%s)", strerror(errno));
+        return -1;
+    }
+
+    LOGD("ASEC %s finalized", id);
+    return 0;
+}
+
+int VolumeManager::destroyAsec(const char *id) {
+    char asecFileName[255];
+    char mountPoint[255];
+
+    snprintf(asecFileName, sizeof(asecFileName),
+             "/sdcard/android_secure/%s.asec", id);
+    snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
+
+    if (isMountpointMounted(mountPoint)) {
+        int i, rc;
+        for (i = 0; i < 10; i++) {
+            rc = umount(mountPoint);
+            if (!rc) {
+                break;
+            }
+            if (rc && (errno == EINVAL || errno == ENOENT)) {
+                rc = 0;
+                break;
+            }
+            LOGW("ASEC %s unmount attempt %d failed (%s)",
+                  id, i +1, strerror(errno));
+            usleep(1000 * 250);
+        }
+        if (rc) {
+            LOGE("Failed to unmount ASEC %s for destroy", id);
+            return -1;
+        }
+    }
+
+    char loopDevice[255];
+    if (!Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
+        Loop::destroyByDevice(loopDevice);
+    }
+
+    unlink(asecFileName);
+
+    LOGD("ASEC %s destroyed", id);
+    return 0;
+}
+
+int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
+    char asecFileName[255];
+    char mountPoint[255];
+
+    snprintf(asecFileName, sizeof(asecFileName),
+             "/sdcard/android_secure/%s.asec", id);
+    snprintf(mountPoint, sizeof(mountPoint), "/asec/%s", id);
+
+    if (isMountpointMounted(mountPoint)) {
+        LOGE("ASEC %s already mounted", id);
+        errno = EBUSY;
+        return -1;
+    }
+
+    char loopDevice[255];
+    if (Loop::lookupActive(asecFileName, loopDevice, sizeof(loopDevice))) {
+        if (Loop::getNextAvailable(loopDevice, sizeof(loopDevice))) {
+            LOGE("Unable to find loop device for ASEC mount");
+            return -1;
+        }
+
+        if (Loop::create(loopDevice, asecFileName)) {
+            LOGE("ASEC loop device creation failed (%s)", strerror(errno));
+            return -1;
+        }
+    }
+
+    if (mkdir(mountPoint, 0777)) {
+        LOGE("Mountpoint creation failed (%s)", strerror(errno));
+        return -1;
+    }
+
+    if (Fat::doMount(loopDevice, mountPoint, true, false)) {
+        LOGE("ASEC mount failed (%s)", strerror(errno));
+        return -1;
+    }
+
+    LOGD("ASEC %s mounted", id);
+    return 0;
+}
+
 int VolumeManager::mountVolume(const char *label) {
     Volume *v = lookupVolume(label);
 
@@ -334,3 +525,31 @@
     }
     return NULL;
 }
+
+bool VolumeManager::isMountpointMounted(const char *mp)
+{
+    char device[256];
+    char mount_path[256];
+    char rest[256];
+    FILE *fp;
+    char line[1024];
+
+    if (!(fp = fopen("/proc/mounts", "r"))) {
+        LOGE("Error opening /proc/mounts (%s)", strerror(errno));
+        return false;
+    }
+
+    while(fgets(line, sizeof(line), fp)) {
+        line[strlen(line)-1] = '\0';
+        sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
+        if (!strcmp(mount_path, mp)) {
+            fclose(fp);
+            return true;
+        }
+
+    }
+
+    fclose(fp);
+    return false;
+}
+