--- /dev/null
+/*
+ * 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 _ASEC_H
+#define _ASEC_H
+
+struct asec_superblock {
+#define ASEC_SB_MAGIC 0xc0def00d
+ unsigned int magic;
+
+#define ASEC_SB_VER 1
+ unsigned char ver;
+
+#define ASEC_SB_C_CIPHER_NONE 0
+#define ASEC_SB_C_CIPHER_TWOFISH 1
+#define ASEC_SB_C_CIPHER_AES 2
+ unsigned char c_cipher;
+
+#define ASEC_SB_C_CHAIN_NONE 0
+ unsigned char c_chain;
+
+#define ASEC_SB_C_OPTS_NONE 0
+ unsigned char c_opts;
+
+#define ASEC_SB_C_MODE_NONE 0
+ unsigned char c_mode;
+} __attribute__((packed));
+
+#endif
#include "Fat.h"
#include "Devmapper.h"
#include "Process.h"
+#include "Asec.h"
VolumeManager *VolumeManager::sInstance = NULL;
int VolumeManager::createAsec(const char *id, unsigned int numSectors,
const char *fstype, const char *key, int ownerUid) {
+ struct asec_superblock sb;
+ memset(&sb, 0, sizeof(sb));
+
+ sb.magic = ASEC_SB_MAGIC;
+ sb.ver = ASEC_SB_VER;
if (numSectors < ((1024*1024)/512)) {
LOGE("Invalid container size specified (%d sectors)", numSectors);
return -1;
}
- if (Loop::createImageFile(asecFileName, numSectors)) {
+ /*
+ * Add some headroom
+ */
+ unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
+ unsigned numImgSectors = numSectors + fatSize + 2;
+
+ if (numImgSectors % 63) {
+ numImgSectors += (63 - (numImgSectors % 63));
+ }
+
+ // Add +1 for our superblock which is at the end
+ if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
LOGE("ASEC image file creation failed (%s)", strerror(errno));
return -1;
}
bool cleanupDm = false;
if (strcmp(key, "none")) {
- if (Devmapper::create(id, loopDevice, key, numSectors, dmDevice,
+ // XXX: This is all we support for now
+ sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
+ if (Devmapper::create(id, loopDevice, key, numImgSectors, dmDevice,
sizeof(dmDevice))) {
LOGE("ASEC device mapping failed (%s)", strerror(errno));
Loop::destroyByDevice(loopDevice);
}
cleanupDm = true;
} else {
+ sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
strcpy(dmDevice, loopDevice);
}
+ /*
+ * Drop down the superblock at the end of the file
+ */
+
+ int sbfd = open(loopDevice, O_RDWR);
+ if (sbfd < 0) {
+ LOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
+ if (cleanupDm) {
+ Devmapper::destroy(id);
+ }
+ Loop::destroyByDevice(loopDevice);
+ unlink(asecFileName);
+ return -1;
+ }
+
+ if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
+ close(sbfd);
+ LOGE("Failed to lseek for superblock (%s)", strerror(errno));
+ if (cleanupDm) {
+ Devmapper::destroy(id);
+ }
+ Loop::destroyByDevice(loopDevice);
+ unlink(asecFileName);
+ return -1;
+ }
+
+ if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
+ close(sbfd);
+ LOGE("Failed to write superblock (%s)", strerror(errno));
+ if (cleanupDm) {
+ Devmapper::destroy(id);
+ }
+ Loop::destroyByDevice(loopDevice);
+ unlink(asecFileName);
+ return -1;
+ }
+ close(sbfd);
+
if (strcmp(fstype, "none")) {
if (strcmp(fstype, "fat")) {
LOGW("Unknown fstype '%s' specified for container", fstype);
}
- if (Fat::format(dmDevice)) {
+ if (Fat::format(dmDevice, numImgSectors)) {
LOGE("ASEC FAT format failed (%s)", strerror(errno));
if (cleanupDm) {
Devmapper::destroy(id);
char dmDevice[255];
bool cleanupDm = false;
- if (strcmp(key, "none")) {
- if (Devmapper::lookupActive(id, dmDevice, sizeof(dmDevice))) {
- unsigned int nr_sec = 0;
- int fd;
+ int fd;
+ unsigned int nr_sec = 0;
- if ((fd = open(loopDevice, O_RDWR)) < 0) {
- LOGE("Failed to open loopdevice (%s)", strerror(errno));
- Loop::destroyByDevice(loopDevice);
- return -1;
- }
+ if ((fd = open(loopDevice, O_RDWR)) < 0) {
+ LOGE("Failed to open loopdevice (%s)", strerror(errno));
+ Loop::destroyByDevice(loopDevice);
+ return -1;
+ }
- if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
- LOGE("Failed to get loop size (%s)", strerror(errno));
- Loop::destroyByDevice(loopDevice);
- close(fd);
- return -1;
- }
- close(fd);
+ if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
+ LOGE("Failed to get loop size (%s)", strerror(errno));
+ Loop::destroyByDevice(loopDevice);
+ close(fd);
+ return -1;
+ }
+
+ /*
+ * Validate superblock
+ */
+ struct asec_superblock sb;
+ memset(&sb, 0, sizeof(sb));
+ if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) {
+ LOGE("lseek failed (%s)", strerror(errno));
+ close(fd);
+ Loop::destroyByDevice(loopDevice);
+ return -1;
+ }
+ if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
+ LOGE("superblock read failed (%s)", strerror(errno));
+ close(fd);
+ Loop::destroyByDevice(loopDevice);
+ return -1;
+ }
+
+ close(fd);
+
+ LOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
+ if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
+ LOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
+ Loop::destroyByDevice(loopDevice);
+ errno = EMEDIUMTYPE;
+ return -1;
+ }
+ nr_sec--; // We don't want the devmapping to extend onto our superblock
+
+ if (strcmp(key, "none")) {
+ if (Devmapper::lookupActive(id, dmDevice, sizeof(dmDevice))) {
if (Devmapper::create(id, loopDevice, key, nr_sec,
dmDevice, sizeof(dmDevice))) {
LOGE("ASEC device mapping failed (%s)", strerror(errno));