Adopted Storage support

 -Detects, decrypts, and mounts an adopted SD card if a
  secondary block device is defined (usually mmcblk1)
 -Handles unified storage
 -Displays the adopted storage in MTP along with internal
 -Factory Reset - wiped just like a data media device, we
  retain the keys folder and the storage.xml during a
  factory reset
 -Backup / Restore
 -Disable mass storage when adopted storage is present
 -Read storage nickname from storage.xml and apply it to
  display names in the GUI
 -Read storage.xml and determine what storage location is in
  use for /sdcard and remap accordingly

libgpt_twrp is source code mostly kanged from an efimanager
project. It is GPL v2 or higher, so we will opt for GPL v3.

Change-Id: Ieda0030bec5155ba8d2b9167dc0016cebbf39d55
diff --git a/crypto/lollipop/cryptfs.c b/crypto/lollipop/cryptfs.c
index 1e65a22..fa440ed 100644
--- a/crypto/lollipop/cryptfs.c
+++ b/crypto/lollipop/cryptfs.c
@@ -1060,6 +1060,7 @@
     if (! ioctl(fd, DM_TABLE_LOAD, io)) {
       break;
     }
+    printf("%i\n", errno);
     usleep(500000);
   }
 
@@ -1145,7 +1146,7 @@
 
   ioctl_init(io, DM_CRYPT_BUF_SIZE, name, 0);
   if (ioctl(fd, DM_DEV_CREATE, io)) {
-    printf("Cannot create dm-crypt device\n");
+    printf("Cannot create dm-crypt device %i\n", errno);
     goto errout;
   }
 
@@ -2017,3 +2018,45 @@
 
     return crypt_ftr.crypt_type;
 }
+
+/*
+ * Called by vold when it's asked to mount an encrypted external
+ * storage volume. The incoming partition has no crypto header/footer,
+ * as any metadata is been stored in a separate, small partition.
+ *
+ * out_crypto_blkdev must be MAXPATHLEN.
+ */
+int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev,
+        const unsigned char* key, int keysize, char* out_crypto_blkdev) {
+    int fd = open(real_blkdev, O_RDONLY|O_CLOEXEC);
+    if (fd == -1) {
+        printf("Failed to open %s: %s", real_blkdev, strerror(errno));
+        return -1;
+    }
+
+    unsigned long nr_sec = 0;
+    nr_sec = get_blkdev_size(fd);
+    close(fd);
+
+    if (nr_sec == 0) {
+        printf("Failed to get size of %s: %s", real_blkdev, strerror(errno));
+        return -1;
+    }
+
+    struct crypt_mnt_ftr ext_crypt_ftr;
+    memset(&ext_crypt_ftr, 0, sizeof(ext_crypt_ftr));
+    ext_crypt_ftr.fs_size = nr_sec;
+    ext_crypt_ftr.keysize = keysize;
+    strcpy((char*) ext_crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256");
+
+    return create_crypto_blk_dev(&ext_crypt_ftr, key, real_blkdev,
+            out_crypto_blkdev, label);
+}
+
+/*
+ * Called by vold when it's asked to unmount an encrypted external
+ * storage volume.
+ */
+int cryptfs_revert_ext_volume(const char* label) {
+    return delete_crypto_blk_dev((char*) label);
+}