vold2: Initial support for Android Secure External Caches
Signed-off-by: San Mehat <san@google.com>
diff --git a/Android.mk b/Android.mk
index b9e63c7..9802c9e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -22,7 +22,8 @@
logwrapper.c \
ProcessKiller.c \
geom_mbr_enc.c \
- Fat.cpp
+ Fat.cpp \
+ Loop.cpp
LOCAL_MODULE:= vold
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 702ae32..db6899d 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -16,8 +16,10 @@
#include <stdlib.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <dirent.h>
#include <errno.h>
#define LOG_TAG "CommandListener"
@@ -39,6 +41,12 @@
registerCmd(new ShareAvailableCmd());
registerCmd(new SimulateCmd());
registerCmd(new FormatCmd());
+ registerCmd(new CreateAsecCmd());
+ registerCmd(new FinalizeAsecCmd());
+ registerCmd(new DestroyAsecCmd());
+ registerCmd(new MountAsecCmd());
+ registerCmd(new ListAsecCmd());
+ registerCmd(new AsecPathCmd());
}
CommandListener::ListVolumesCmd::ListVolumesCmd() :
@@ -160,3 +168,142 @@
return 0;
}
+
+CommandListener::CreateAsecCmd::CreateAsecCmd() :
+ VoldCommand("create_asec") {
+}
+
+int CommandListener::CreateAsecCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ if (argc != 6) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: create_asec <namespace-id> <size_mb> <fstype> <key> <ownerUid>",
+ false);
+ return 0;
+ }
+
+ if (VolumeManager::Instance()->createAsec(argv[1], atoi(argv[2]),
+ argv[3], argv[4],
+ atoi(argv[5]))) {
+ cli->sendMsg(ResponseCode::OperationFailed, "Cache creation failed", true);
+ } else {
+ cli->sendMsg(ResponseCode::CommandOkay, "Cache created", false);
+ }
+
+ return 0;
+}
+
+CommandListener::FinalizeAsecCmd::FinalizeAsecCmd() :
+ VoldCommand("finalize_asec") {
+}
+
+int CommandListener::FinalizeAsecCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ if (argc != 2) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: finalize_asec <namespace-id>", false);
+ return 0;
+ }
+
+ if (VolumeManager::Instance()->finalizeAsec(argv[1])) {
+ cli->sendMsg(ResponseCode::OperationFailed, "Cache finalize failed", true);
+ } else {
+ cli->sendMsg(ResponseCode::CommandOkay, "Cache finalized", false);
+ }
+ return 0;
+}
+
+CommandListener::DestroyAsecCmd::DestroyAsecCmd() :
+ VoldCommand("destroy_asec") {
+}
+
+int CommandListener::DestroyAsecCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ if (argc != 2) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: destroy_asec <namespace-id>", false);
+ return 0;
+ }
+
+ if (VolumeManager::Instance()->destroyAsec(argv[1])) {
+ cli->sendMsg(ResponseCode::OperationFailed, "Destroy failed", true);
+ } else {
+ cli->sendMsg(ResponseCode::CommandOkay, "Cache Destroyed", false);
+ }
+ return 0;
+}
+
+CommandListener::MountAsecCmd::MountAsecCmd() :
+ VoldCommand("mount_asec") {
+}
+
+int CommandListener::MountAsecCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ if (argc != 4) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: mount_asec <namespace-id> <key> <ownerUid>", false);
+ return 0;
+ }
+
+ if (VolumeManager::Instance()->mountAsec(argv[1], argv[2], atoi(argv[3]))) {
+ cli->sendMsg(ResponseCode::OperationFailed, "Mount failed", true);
+ } else {
+ cli->sendMsg(ResponseCode::CommandOkay, "Mount succeeded", false);
+ }
+ return 0;
+}
+
+CommandListener::ListAsecCmd::ListAsecCmd() :
+ VoldCommand("list_asec") {
+
+}
+
+int CommandListener::ListAsecCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ DIR *d = opendir("/sdcard/android_secure");
+
+ if (!d) {
+ cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
+ return 0;
+ }
+
+ struct dirent *dent;
+ while ((dent = readdir(d))) {
+ if (dent->d_name[0] == '.')
+ continue;
+ if (!strcmp(&dent->d_name[strlen(dent->d_name)-5], ".asec")) {
+ char id[255];
+ memset(id, 0, sizeof(id));
+ strncpy(id, dent->d_name, strlen(dent->d_name) -5);
+ cli->sendMsg(ResponseCode::AsecListResult, id, false);
+ }
+ }
+ closedir(d);
+ cli->sendMsg(ResponseCode::CommandOkay, "ASEC listing complete", false);
+
+ return 0;
+}
+
+CommandListener::AsecPathCmd::AsecPathCmd() :
+ VoldCommand("asec_path") {
+}
+
+int CommandListener::AsecPathCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ if (argc != 2) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: asec_path <namespace-id>", false);
+ return 0;
+ }
+
+ char mountPath[255];
+
+ if (VolumeManager::Instance()->getAsecMountPath(argv[1], mountPath,
+ sizeof(mountPath))) {
+ cli->sendMsg(ResponseCode::OperationFailed, "Failed to get mount path", true);
+ } else {
+ cli->sendMsg(ResponseCode::AsecPathResult, mountPath, false);
+ }
+
+ return 0;
+}
diff --git a/CommandListener.h b/CommandListener.h
index 5acec5b..cc078da 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -83,6 +83,49 @@
int runCommand(SocketClient *c, int argc, char ** argv);
};
+ class CreateAsecCmd : public VoldCommand {
+ public:
+ CreateAsecCmd();
+ virtual ~CreateAsecCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class FinalizeAsecCmd : public VoldCommand {
+ public:
+ FinalizeAsecCmd();
+ virtual ~FinalizeAsecCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class DestroyAsecCmd : public VoldCommand {
+ public:
+ DestroyAsecCmd();
+ virtual ~DestroyAsecCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class MountAsecCmd : public VoldCommand {
+ public:
+ MountAsecCmd();
+ virtual ~MountAsecCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class ListAsecCmd : public VoldCommand {
+ public:
+ ListAsecCmd();
+ virtual ~ListAsecCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class AsecPathCmd : public VoldCommand {
+ public:
+ AsecPathCmd();
+ virtual ~AsecPathCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+
};
#endif
diff --git a/Fat.cpp b/Fat.cpp
index ec1ead5..6537a68 100644
--- a/Fat.cpp
+++ b/Fat.cpp
@@ -92,12 +92,15 @@
return 0;
}
-int Fat::doMount(const char *fsPath, const char *mountPoint) {
+int Fat::doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount) {
int rc;
unsigned long flags;
flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_DIRSYNC;
+ flags |= (ro ? MS_RDONLY : 0);
+ flags |= (remount ? MS_REMOUNT : 0);
+
/*
* Note: This is a temporary hack. If the sampling profiler is enabled,
* we make the SD card world-writable so any process can write snapshots.
@@ -168,7 +171,9 @@
int rc;
args[0] = MKDOSFS_PATH;
args[1] = "-F";
- if ((nr_sec * 512) <= ((unsigned int) (1024*1024*1024) * 2))
+ if ((nr_sec * 512) <= ((unsigned int) (1024*1024) * 32))
+ args[2] = "12";
+ else if ((nr_sec * 512) <= ((unsigned int) (1024*1024*1024) * 2))
args[2] = "16";
else
args[2] = "32";
diff --git a/Fat.h b/Fat.h
index 174f008..e5d76e3 100644
--- a/Fat.h
+++ b/Fat.h
@@ -22,7 +22,8 @@
class Fat {
public:
static int check(const char *fsPath);
- static int doMount(const char *fsPath, const char *mountPoint);
+ static int doMount(const char *fsPath, const char *mountPoint, bool ro,
+ bool remount);
static int format(const char *fsPath);
};
diff --git a/Loop.cpp b/Loop.cpp
new file mode 100644
index 0000000..064e553
--- /dev/null
+++ b/Loop.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#define LOG_TAG "Vold"
+
+#include <cutils/log.h>
+
+#include "Loop.h"
+
+int Loop::lookupActive(const char *loopFile, char *buffer, size_t len) {
+ int i;
+ int fd;
+ char filename[256];
+
+ memset(buffer, 0, len);
+
+ for (i = 0; i < LOOP_MAX; i++) {
+ struct loop_info li;
+ int rc;
+
+ sprintf(filename, "/dev/block/loop%d", i);
+
+ if ((fd = open(filename, O_RDWR)) < 0) {
+ LOGE("Unable to open %s (%s)", filename, strerror(errno));
+ return -1;
+ }
+
+ rc = ioctl(fd, LOOP_GET_STATUS, &li);
+ close(fd);
+ if (rc < 0 && errno == ENXIO) {
+ continue;
+ break;
+ }
+
+ if (rc < 0) {
+ LOGE("Unable to get loop status for %s (%s)", filename,
+ strerror(errno));
+ return -1;
+ }
+ if (!strncmp(li.lo_name, loopFile, LO_NAME_SIZE)) {
+ break;
+ }
+ }
+
+ if (i == LOOP_MAX) {
+ errno = ENOENT;
+ return -1;
+ }
+ strncpy(buffer, filename, len -1);
+ return 0;
+}
+
+int Loop::getNextAvailable(char *buffer, size_t len) {
+ int i;
+ int fd;
+ char filename[256];
+
+ memset(buffer, 0, len);
+
+ for (i = 0; i < LOOP_MAX; i++) {
+ struct loop_info li;
+ int rc;
+
+ sprintf(filename, "/dev/block/loop%d", i);
+
+ if ((fd = open(filename, O_RDWR)) < 0) {
+ LOGE("Unable to open %s (%s)", filename, strerror(errno));
+ return -1;
+ }
+
+ rc = ioctl(fd, LOOP_GET_STATUS, &li);
+ close(fd);
+ if (rc < 0 && errno == ENXIO)
+ break;
+
+ if (rc < 0) {
+ LOGE("Unable to get loop status for %s (%s)", filename,
+ strerror(errno));
+ return -1;
+ }
+ }
+
+ if (i == LOOP_MAX) {
+ LOGE("Exhausted all loop devices");
+ errno = ENOSPC;
+ return -1;
+ }
+ strncpy(buffer, filename, len -1);
+ return 0;
+}
+
+int Loop::create(const char *loopDevice, const char *loopFile) {
+ int fd;
+ int file_fd;
+
+ LOGD("Creating loop for file '%s' into loop device '%s'", loopFile,
+ loopDevice);
+ if ((fd = open(loopDevice, O_RDWR)) < 0) {
+ LOGE("Unable to open loop device %s (%s)", loopDevice,
+ strerror(errno));
+ return -1;
+ }
+
+ if ((file_fd = open(loopFile, O_RDWR)) < 0) {
+ LOGE("Unable to open %s (%s)", loopFile, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ if (ioctl(fd, LOOP_SET_FD, file_fd) < 0) {
+ LOGE("Error setting up loopback interface (%s)", strerror(errno));
+ close(file_fd);
+ close(fd);
+ return -1;
+ }
+
+ struct loop_info li;
+
+ memset(&li, 0, sizeof(li));
+ strncpy(li.lo_name, loopFile, LO_NAME_SIZE);
+
+ if (ioctl(fd, LOOP_SET_STATUS, &li) < 0) {
+ LOGE("Error setting loopback status (%s)", strerror(errno));
+ close(file_fd);
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ close(file_fd);
+
+ return 0;
+}
+
+int Loop::destroyByDevice(const char *loopDevice) {
+ int device_fd;
+
+ device_fd = open(loopDevice, O_RDONLY);
+ if (device_fd < 0) {
+ LOGE("Failed to open loop (%d)", errno);
+ return -1;
+ }
+
+ if (ioctl(device_fd, LOOP_CLR_FD, 0) < 0) {
+ LOGE("Failed to destroy loop (%d)", errno);
+ close(device_fd);
+ return -1;
+ }
+
+ close(device_fd);
+ return 0;
+}
+
+int Loop::destroyByFile(const char *loopFile) {
+ errno = ENOSYS;
+ return -1;
+}
+
+int Loop::createImageFile(const char *file, size_t sizeMb) {
+ int fd;
+
+ LOGD("Creating ASEC image file %s (%d mb)", file, sizeMb);
+
+ if ((fd = creat(file, 0600)) < 0) {
+ LOGE("Error creating imagefile (%s)", strerror(errno));
+ return -1;
+ }
+
+ if (ftruncate(fd, (sizeMb * (1024 * 1024))) < 0) {
+ LOGE("Error truncating imagefile (%s)", strerror(errno));
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return 0;
+}
diff --git a/Loop.h b/Loop.h
new file mode 100644
index 0000000..540db8b
--- /dev/null
+++ b/Loop.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LOOP_H
+#define _LOOP_H
+
+#include <unistd.h>
+#include <linux/loop.h>
+
+class Loop {
+public:
+ static const int LOOP_MAX = 8;
+public:
+ static int getNextAvailable(char *buffer, size_t len);
+ static int lookupActive(const char *loopFile, char *buffer, size_t len);
+
+ static int create(const char *loopDevice, const char *loopFile);
+ static int destroyByDevice(const char *loopDevice);
+ static int destroyByFile(const char *loopFile);
+ static int createImageFile(const char *file, size_t sizeMb);
+};
+
+#endif
diff --git a/ResponseCode.h b/ResponseCode.h
index 4f7237c..bb27787 100644
--- a/ResponseCode.h
+++ b/ResponseCode.h
@@ -21,13 +21,15 @@
public:
// 100 series - Requestion action was initiated; expect another reply
// before proceeding with a new command.
- static const int ActionInitiated = 100;
+ static const int ActionInitiated = 100;
static const int VolumeListResult = 110;
+ static const int AsecListResult = 111;
// 200 series - Requested action has been successfully completed
- static const int CommandOkay = 200;
+ static const int CommandOkay = 200;
static const int ShareAvailabilityResult = 210;
+ static const int AsecPathResult = 211;
// 400 series - The command was accepted but the requested action
// did not take place.
diff --git a/Volume.cpp b/Volume.cpp
index d234c6f..787d4cd 100644
--- a/Volume.cpp
+++ b/Volume.cpp
@@ -268,7 +268,7 @@
LOGI("%s checks out - attempting to mount\n", devicePath);
errno = 0;
- if (!(rc = Fat::doMount(devicePath, getMountpoint()))) {
+ if (!(rc = Fat::doMount(devicePath, getMountpoint(), false, false))) {
LOGI("%s sucessfully mounted for volume %s\n", devicePath,
getLabel());
setState(Volume::State_Mounted);
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;
+}
+
diff --git a/VolumeManager.h b/VolumeManager.h
index f686a50..a0b63ac 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -55,6 +55,12 @@
int shareAvailable(const char *method, bool *avail);
int simulate(const char *cmd, const char *arg);
int formatVolume(const char *label);
+ int createAsec(const char *id, int sizeMb, const char *fstype,
+ const char *key, int ownerUid);
+ int finalizeAsec(const char *id);
+ int destroyAsec(const char *id);
+ int mountAsec(const char *id, const char *key, int ownerUid);
+ int getAsecMountPath(const char *id, char *buffer, int maxlen);
// XXX: This should be moved private once switch uevents are working
void notifyUmsConnected(bool connected);
@@ -67,5 +73,6 @@
private:
VolumeManager();
Volume *lookupVolume(const char *label);
+ bool isMountpointMounted(const char *mp);
};
#endif