auto import from //depot/cupcake/@135843
diff --git a/vold/blkdev.c b/vold/blkdev.c
new file mode 100644
index 0000000..533bc35
--- /dev/null
+++ b/vold/blkdev.c
@@ -0,0 +1,319 @@
+
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <linux/fs.h>
+#include <linux/msdos_fs.h>
+
+#include "vold.h"
+#include "blkdev.h"
+#include "diskmbr.h"
+
+#define DEBUG_BLKDEV 0
+
+static blkdev_list_t *list_root = NULL;
+
+static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major,
+ int minor, char *type, struct media *media);
+
+static int fat_valid_media(unsigned char media)
+{
+ return 0xf8 <= media || media == 0xf0;
+}
+
+char *blkdev_get_devpath(blkdev_t *blk)
+{
+ char *dp = malloc(256);
+ sprintf(dp, "%s/vold/%d:%d", DEVPATH, blk->major, blk->minor);
+ return dp;
+}
+
+int blkdev_refresh(blkdev_t *blk)
+{
+ int fd = 0;
+ char *devpath = NULL;
+ unsigned char *block = NULL;
+ int i, rc;
+
+ if (!(block = malloc(512)))
+ goto out;
+
+ /*
+ * Get the device size
+ */
+ devpath = blkdev_get_devpath(blk);
+
+ if ((fd = open(devpath, O_RDONLY)) < 0) {
+ LOGE("Unable to open device '%s' (%s)", devpath, strerror(errno));
+ return -errno;
+ }
+
+ if (ioctl(fd, BLKGETSIZE, &blk->nr_sec)) {
+ LOGE("Unable to get device size (%m)");
+ return -errno;
+ }
+ close(fd);
+ free(devpath);
+
+ /*
+ * Open the disk partition table
+ */
+ devpath = blkdev_get_devpath(blk->disk);
+ if ((fd = open(devpath, O_RDONLY)) < 0) {
+ LOGE("Unable to open device '%s' (%s)", devpath,
+ strerror(errno));
+ free(devpath);
+ return -errno;
+ }
+
+ free(devpath);
+
+ if ((rc = read(fd, block, 512)) != 512) {
+ LOGE("Unable to read device partition table (%d, %s)",
+ rc, strerror(errno));
+ goto out;
+ }
+
+ /*
+ * If we're a disk, then process the partition table. Otherwise we're
+ * a partition so get the partition type
+ */
+
+ if (blk->type == blkdev_disk) {
+ blk->nr_parts = 0;
+
+ if ((block[0x1fe] != 0x55) || (block[0x1ff] != 0xAA)) {
+ LOG_VOL("Disk %d:%d does not contain a partition table",
+ blk->major, blk->minor);
+ goto out;
+ }
+
+ for (i = 0; i < 4; i++) {
+ struct dos_partition part;
+
+ dos_partition_dec(block + DOSPARTOFF + i * sizeof(struct dos_partition), &part);
+ if (part.dp_flag != 0 && part.dp_flag != 0x80) {
+ struct fat_boot_sector *fb = (struct fat_boot_sector *) &block[0];
+
+ if (!i && fb->reserved && fb->fats && fat_valid_media(fb->media)) {
+ LOG_VOL("Detected FAT filesystem in partition table");
+ break;
+ } else {
+ LOG_VOL("Partition table looks corrupt");
+ break;
+ }
+ }
+ if (part.dp_size != 0 && part.dp_typ != 0)
+ blk->nr_parts++;
+ }
+ } else if (blk->type == blkdev_partition) {
+ struct dos_partition part;
+ int part_no = blk->minor -1;
+
+ dos_partition_dec(block + DOSPARTOFF + part_no * sizeof(struct dos_partition), &part);
+ blk->part_type = part.dp_typ;
+ }
+
+ out:
+
+ if (block)
+ free(block);
+
+ char tmp[255];
+ char tmp2[32];
+ sprintf(tmp, "%s (blkdev %d:%d), %u secs (%u MB)",
+ (blk->type == blkdev_disk ? "Disk" : "Partition"),
+ blk->major, blk->minor,
+ blk->nr_sec,
+ (uint32_t) (((uint64_t) blk->nr_sec * 512) / 1024) / 1024);
+
+ if (blk->type == blkdev_disk)
+ sprintf(tmp2, " %d partitions", blk->nr_parts);
+ else
+ sprintf(tmp2, " type 0x%x", blk->part_type);
+
+ strcat(tmp, tmp2);
+ LOG_VOL(tmp);
+
+ close(fd);
+
+ return 0;
+}
+
+blkdev_t *blkdev_create(blkdev_t *disk, char *devpath, int major, int minor, struct media *media, char *type)
+{
+ return _blkdev_create(disk, devpath, major, minor, type, media);
+}
+
+static blkdev_t *_blkdev_create(blkdev_t *disk, char *devpath, int major,
+ int minor, char *type, struct media *media)
+{
+ blkdev_t *new;
+ struct blkdev_list *list_entry;
+
+ if (disk && disk->type != blkdev_disk) {
+ LOGE("Non disk parent specified for blkdev!");
+ return NULL;
+ }
+
+ if (!(new = malloc(sizeof(blkdev_t))))
+ return NULL;
+
+ memset(new, 0, sizeof(blkdev_t));
+
+ if (!(list_entry = malloc(sizeof(struct blkdev_list)))) {
+ free (new);
+ return NULL;
+ }
+ list_entry->dev = new;
+ list_entry->next = NULL;
+
+ if (!list_root)
+ list_root = list_entry;
+ else {
+ struct blkdev_list *list_scan = list_root;
+ while (list_scan->next)
+ list_scan = list_scan->next;
+ list_scan->next = list_entry;
+ }
+
+ if (devpath)
+ new->devpath = strdup(devpath);
+ new->major = major;
+ new->minor = minor;
+ new->media = media;
+ new->nr_sec = 0xffffffff;
+
+ if (disk)
+ new->disk = disk;
+ else
+ new->disk = new; // Note the self disk pointer
+
+ /* Create device nodes */
+ char nodepath[255];
+ mode_t mode = 0666 | S_IFBLK;
+ dev_t dev = (major << 8) | minor;
+
+ sprintf(nodepath, "%s/vold/%d:%d", DEVPATH, major, minor);
+ if (mknod(nodepath, mode, dev) < 0) {
+ LOGE("Error making device nodes for '%s' (%s)",
+ nodepath, strerror(errno));
+ }
+
+ if (!strcmp(type, "disk"))
+ new->type = blkdev_disk;
+ else if (!strcmp(type, "partition"))
+ new->type = blkdev_partition;
+ else {
+ LOGE("Unknown block device type '%s'", type);
+ new->type = blkdev_unknown;
+ }
+
+ return new;
+}
+
+void blkdev_destroy(blkdev_t *blkdev)
+{
+ struct blkdev_list *list_next;
+
+ if (list_root->dev == blkdev) {
+ list_next = list_root->next;
+ free (list_root);
+ list_root = list_next;
+ } else {
+ struct blkdev_list *list_scan = list_root;
+ while (list_scan->next->dev != blkdev)
+ list_scan = list_scan -> next;
+ list_next = list_scan->next->next;
+ free(list_scan->next);
+ list_scan->next = list_next;
+ }
+
+ if (blkdev->devpath)
+ free(blkdev->devpath);
+
+ char nodepath[255];
+ sprintf(nodepath, "%s/vold/%d:%d", DEVPATH, blkdev->major, blkdev->minor);
+ unlink(nodepath);
+
+ free(blkdev);
+}
+
+blkdev_t *blkdev_lookup_by_path(char *devpath)
+{
+ struct blkdev_list *list_scan = list_root;
+
+ while (list_scan) {
+ if (!strcmp(list_scan->dev->devpath, devpath))
+ return list_scan->dev;
+ list_scan = list_scan->next;
+ }
+ return NULL;
+}
+
+blkdev_t *blkdev_lookup_by_devno(int maj, int min)
+{
+ struct blkdev_list *list_scan = list_root;
+
+ while (list_scan) {
+ if ((list_scan->dev->major == maj) &&
+ (list_scan->dev->minor == min))
+ return list_scan->dev;
+ list_scan = list_scan->next;
+ }
+ return NULL;
+}
+
+/*
+ * Given a disk device, return the number of partitions which
+ * have yet to be processed.
+ */
+int blkdev_get_num_pending_partitions(blkdev_t *blk)
+{
+ struct blkdev_list *list_scan = list_root;
+ int num = blk->nr_parts;
+
+ if (blk->type != blkdev_disk)
+ return -EINVAL;
+
+ while (list_scan) {
+ if (list_scan->dev->type != blkdev_partition)
+ goto next;
+
+ if (list_scan->dev->major != blk->major)
+ goto next;
+
+ if (list_scan->dev->nr_sec != 0xffffffff &&
+ list_scan->dev->devpath) {
+ num--;
+ }
+ next:
+ list_scan = list_scan->next;
+ }
+ return num;
+}
+