Additional Obb functionality

* Rename all functions dealing with OBB files to mention Obb

* Add 'path' and 'list' functionality to OBB commands

* Store hashed filename in loop's lo_crypt_name and keep lo_file_name
  for the real source filename. That way we can recover it later with an
  ioctl call.

Change-Id: I29e468265988bfb931d981532d86d7be7b3adfc8
diff --git a/CommandListener.cpp b/CommandListener.cpp
index fead4f8..b0fc551 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -41,7 +41,7 @@
     registerCmd(new DumpCmd());
     registerCmd(new VolumeCmd());
     registerCmd(new AsecCmd());
-    registerCmd(new ImageCmd());
+    registerCmd(new ObbCmd());
     registerCmd(new ShareCmd());
     registerCmd(new StorageCmd());
     registerCmd(new XwarpCmd());
@@ -398,11 +398,11 @@
     return 0;
 }
 
-CommandListener::ImageCmd::ImageCmd() :
-                 VoldCommand("image") {
+CommandListener::ObbCmd::ObbCmd() :
+                 VoldCommand("obb") {
 }
 
-int CommandListener::ImageCmd::runCommand(SocketClient *cli,
+int CommandListener::ObbCmd::runCommand(SocketClient *cli,
                                                       int argc, char **argv) {
     if (argc < 2) {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
@@ -412,35 +412,51 @@
     VolumeManager *vm = VolumeManager::Instance();
     int rc = 0;
 
-    if (!strcmp(argv[1], "mount")) {
+    if (!strcmp(argv[1], "list")) {
+        dumpArgs(argc, argv, -1);
+
+        rc = vm->listMountedObbs(cli);
+    } else if (!strcmp(argv[1], "mount")) {
             dumpArgs(argc, argv, 3);
             if (argc != 5) {
                 cli->sendMsg(ResponseCode::CommandSyntaxError,
-                        "Usage: image mount <filename> <key> <ownerUid>", false);
+                        "Usage: obb mount <filename> <key> <ownerUid>", false);
                 return 0;
             }
-            rc = vm->mountImage(argv[2], argv[3], atoi(argv[4]));
+            rc = vm->mountObb(argv[2], argv[3], atoi(argv[4]));
     } else if (!strcmp(argv[1], "unmount")) {
         dumpArgs(argc, argv, -1);
         if (argc < 3) {
-            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: image unmount <container-id> [force]", false);
+            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb unmount <source file> [force]", false);
             return 0;
         }
         bool force = false;
         if (argc > 3 && !strcmp(argv[3], "force")) {
             force = true;
         }
-        rc = vm->unmountImage(argv[2], force);
+        rc = vm->unmountObb(argv[2], force);
+    } else if (!strcmp(argv[1], "path")) {
+        dumpArgs(argc, argv, -1);
+        if (argc != 3) {
+            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb path <source file>", false);
+            return 0;
+        }
+        char path[255];
+
+        if (!(rc = vm->getObbMountPath(argv[2], path, sizeof(path)))) {
+            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
+            return 0;
+        }
     } else {
         dumpArgs(argc, argv, -1);
-        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown image cmd", false);
+        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown obb cmd", false);
     }
 
     if (!rc) {
-        cli->sendMsg(ResponseCode::CommandOkay, "image operation succeeded", false);
+        cli->sendMsg(ResponseCode::CommandOkay, "obb operation succeeded", false);
     } else {
         rc = ResponseCode::convertFromErrno();
-        cli->sendMsg(rc, "image operation failed", true);
+        cli->sendMsg(rc, "obb operation failed", true);
     }
 
     return 0;
diff --git a/CommandListener.h b/CommandListener.h
index 23933bc..75c7e81 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -56,10 +56,10 @@
         int runCommand(SocketClient *c, int argc, char ** argv);
     };
 
-    class ImageCmd : public VoldCommand {
+    class ObbCmd : public VoldCommand {
     public:
-        ImageCmd();
-        virtual ~ImageCmd() {}
+        ObbCmd();
+        virtual ~ObbCmd() {}
         int runCommand(SocketClient *c, int argc, char ** argv);
     };
 
diff --git a/Loop.cpp b/Loop.cpp
index 374cac0..2209f1a 100644
--- a/Loop.cpp
+++ b/Loop.cpp
@@ -38,7 +38,7 @@
     char filename[256];
 
     for (i = 0; i < LOOP_MAX; i++) {
-        struct loop_info li;
+        struct loop_info64 li;
         int rc;
 
         sprintf(filename, "/dev/block/loop%d", i);
@@ -52,7 +52,7 @@
             return -1;
         }
 
-        rc = ioctl(fd, LOOP_GET_STATUS, &li);
+        rc = ioctl(fd, LOOP_GET_STATUS64, &li);
         close(fd);
         if (rc < 0 && errno == ENXIO) {
             continue;
@@ -64,9 +64,10 @@
             return -1;
         }
         char *tmp = NULL;
-        asprintf(&tmp, "%s %d %d:%d %lu %d:%d %d 0x%x {%s}", filename, li.lo_number,
+        asprintf(&tmp, "%s %d %lld:%lld %llu %lld:%lld %lld 0x%x {%s} {%s}", filename, li.lo_number,
                 MAJOR(li.lo_device), MINOR(li.lo_device), li.lo_inode, MAJOR(li.lo_rdevice),
-                        MINOR(li.lo_rdevice), li.lo_offset, li.lo_flags, li.lo_name);
+                        MINOR(li.lo_rdevice), li.lo_offset, li.lo_flags, li.lo_crypt_name,
+                        li.lo_file_name);
         c->sendMsg(0, tmp, false);
         free(tmp);
     }
@@ -81,7 +82,7 @@
     memset(buffer, 0, len);
 
     for (i = 0; i < LOOP_MAX; i++) {
-        struct loop_info li;
+        struct loop_info64 li;
         int rc;
 
         sprintf(filename, "/dev/block/loop%d", i);
@@ -95,7 +96,7 @@
             return -1;
         }
 
-        rc = ioctl(fd, LOOP_GET_STATUS, &li);
+        rc = ioctl(fd, LOOP_GET_STATUS64, &li);
         close(fd);
         if (rc < 0 && errno == ENXIO) {
             continue;
@@ -106,7 +107,7 @@
                  strerror(errno));
             return -1;
         }
-        if (!strncmp(li.lo_name, id, LO_NAME_SIZE)) {
+        if (!strncmp((const char*) li.lo_crypt_name, id, LO_NAME_SIZE)) {
             break;
         }
     }
@@ -148,7 +149,7 @@
             return -1;
         }
 
-        rc = ioctl(fd, LOOP_GET_STATUS, &li);
+        rc = ioctl(fd, LOOP_GET_STATUS64, &li);
         if (rc < 0 && errno == ENXIO)
             break;
 
@@ -184,12 +185,13 @@
         return -1;
     }
 
-    struct loop_info li;
+    struct loop_info64 li;
 
     memset(&li, 0, sizeof(li));
-    strncpy(li.lo_name, id, LO_NAME_SIZE);
+    strncpy((char*) li.lo_crypt_name, id, LO_NAME_SIZE);
+    strncpy((char*) li.lo_file_name, loopFile, LO_NAME_SIZE);
 
-    if (ioctl(fd, LOOP_SET_STATUS, &li) < 0) {
+    if (ioctl(fd, LOOP_SET_STATUS64, &li) < 0) {
         SLOGE("Error setting loopback status (%s)", strerror(errno));
         close(file_fd);
         close(fd);
diff --git a/Volume.cpp b/Volume.cpp
index f43d375..f945b15 100644
--- a/Volume.cpp
+++ b/Volume.cpp
@@ -74,9 +74,9 @@
 const char *Volume::ASECDIR           = "/mnt/asec";
 
 /*
- * Path to where loop devices are mounted
+ * Path to where OBBs are mounted
  */
-const char *Volume::LOOPDIR           = "/mnt/loop";
+const char *Volume::LOOPDIR           = "/mnt/obb";
 
 static const char *stateToStr(int state) {
     if (state == Volume::State_Init)
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 2127eab..2cdac70 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -253,6 +253,24 @@
     return v->formatVol();
 }
 
+int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
+    char idHash[33];
+    if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
+        SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
+        return -1;
+    }
+
+    memset(mountPath, 0, mountPathLen);
+    snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
+
+    if (access(mountPath, F_OK)) {
+        errno = ENOENT;
+        return -1;
+    }
+
+    return 0;
+}
+
 int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
     char asecFileName[255];
     snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
@@ -523,7 +541,7 @@
     return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
 }
 
-int VolumeManager::unmountImage(const char *fileName, bool force) {
+int VolumeManager::unmountObb(const char *fileName, bool force) {
     char mountPoint[255];
 
     char idHash[33];
@@ -782,23 +800,9 @@
 /**
  * Mounts an image file <code>img</code>.
  */
-int VolumeManager::mountImage(const char *img, const char *key, int ownerUid) {
+int VolumeManager::mountObb(const char *img, const char *key, int ownerUid) {
     char mountPoint[255];
 
-#if 0
-    struct stat imgStat;
-    if (stat(img, &imgStat) != 0) {
-        SLOGE("Could not stat '%s': %s", img, strerror(errno));
-        return -1;
-    }
-
-    if (imgStat.st_uid != ownerUid) {
-        SLOGW("Image UID does not match requestor UID (%d != %d)",
-                imgStat.st_uid, ownerUid);
-        return -1;
-    }
-#endif
-
     char idHash[33];
     if (!asecHash(img, idHash, sizeof(idHash))) {
         SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
@@ -908,6 +912,51 @@
     return v->mountVol();
 }
 
+int VolumeManager::listMountedObbs(SocketClient* cli) {
+    char device[256];
+    char mount_path[256];
+    char rest[256];
+    FILE *fp;
+    char line[1024];
+
+    if (!(fp = fopen("/proc/mounts", "r"))) {
+        SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
+        return -1;
+    }
+
+    // Create a string to compare against that has a trailing slash
+    int loopDirLen = sizeof(Volume::LOOPDIR);
+    char loopDir[loopDirLen + 2];
+    strcpy(loopDir, Volume::LOOPDIR);
+    loopDir[loopDirLen++] = '/';
+    loopDir[loopDirLen] = '\0';
+
+    while(fgets(line, sizeof(line), fp)) {
+        line[strlen(line)-1] = '\0';
+
+        /*
+         * Should look like:
+         * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
+         */
+        sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
+
+        if (!strncmp(mount_path, loopDir, loopDirLen)) {
+            int fd = open(device, O_RDONLY);
+            if (fd >= 0) {
+                struct loop_info64 li;
+                if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
+                    cli->sendMsg(ResponseCode::AsecListResult,
+                            (const char*) li.lo_file_name, false);
+                }
+                close(fd);
+            }
+        }
+    }
+
+    fclose(fp);
+    return 0;
+}
+
 int VolumeManager::shareAvailable(const char *method, bool *avail) {
 
     if (strcmp(method, "ums")) {
diff --git a/VolumeManager.h b/VolumeManager.h
index 31870e5..0619c73 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -75,8 +75,10 @@
     int getAsecMountPath(const char *id, char *buffer, int maxlen);
 
     /* Loopback images */
-    int mountImage(const char *fileName, const char *key, int ownerUid);
-    int unmountImage(const char *fileName, bool force);
+    int listMountedObbs(SocketClient* cli);
+    int mountObb(const char *fileName, const char *key, int ownerUid);
+    int unmountObb(const char *fileName, bool force);
+    int getObbMountPath(const char *id, char *buffer, int maxlen);
 
     /* Shared between ASEC and Loopback images */
     int unmountLoopImage(const char *containerId, const char *loopId,