vold2: Initial support for Android Secure External Caches
Signed-off-by: San Mehat <san@google.com>
This commit is contained in:
parent
7b8f2db4b0
commit
a19b250bd2
11 changed files with 663 additions and 7 deletions
|
@ -22,7 +22,8 @@ LOCAL_SRC_FILES:= \
|
|||
logwrapper.c \
|
||||
ProcessKiller.c \
|
||||
geom_mbr_enc.c \
|
||||
Fat.cpp
|
||||
Fat.cpp \
|
||||
Loop.cpp
|
||||
|
||||
LOCAL_MODULE:= vold
|
||||
|
||||
|
|
|
@ -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 @@ CommandListener::CommandListener() :
|
|||
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 @@ int CommandListener::FormatCmd::runCommand(SocketClient *cli,
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -83,6 +83,49 @@ private:
|
|||
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
|
||||
|
|
9
Fat.cpp
9
Fat.cpp
|
@ -92,12 +92,15 @@ int Fat::check(const char *fsPath) {
|
|||
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 Fat::format(const char *fsPath) {
|
|||
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";
|
||||
|
|
3
Fat.h
3
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);
|
||||
};
|
||||
|
||||
|
|
195
Loop.cpp
Normal file
195
Loop.cpp
Normal file
|
@ -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;
|
||||
}
|
36
Loop.h
Normal file
36
Loop.h
Normal file
|
@ -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
|
|
@ -21,13 +21,15 @@ class ResponseCode {
|
|||
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.
|
||||
|
|
|
@ -268,7 +268,7 @@ int Volume::mountVol() {
|
|||
|
||||
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);
|
||||
|
|
|
@ -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 @@ int VolumeManager::formatVolume(const char *label) {
|
|||
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 @@ Volume *VolumeManager::lookupVolume(const char *label) {
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,12 @@ public:
|
|||
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 @@ public:
|
|||
private:
|
||||
VolumeManager();
|
||||
Volume *lookupVolume(const char *label);
|
||||
bool isMountpointMounted(const char *mp);
|
||||
};
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue