recovery: Update recovery from CM.

Change-Id: Ibda5ba8bbfc93ef6ff565128b63adc2991218a70
diff --git a/Android.mk b/Android.mk
index 0179dc0..3f9f1e8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -26,12 +26,12 @@
 
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 
-RECOVERY_VERSION := ClockworkMod Recovery v3.0.0.6
+RECOVERY_VERSION := ClockworkMod Recovery v3.0.2.4
 LOCAL_CFLAGS += -DRECOVERY_VERSION="$(RECOVERY_VERSION)"
 RECOVERY_API_VERSION := 2
 LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
 
-BOARD_RECOVERY_DEFINES := BOARD_HAS_NO_SELECT_BUTTON BOARD_HAS_SMALL_RECOVERY BOARD_LDPI_RECOVERY
+BOARD_RECOVERY_DEFINES := BOARD_HAS_NO_SELECT_BUTTON BOARD_HAS_SMALL_RECOVERY BOARD_LDPI_RECOVERY BOARD_UMS_LUNFILE
 
 $(foreach board_define,$(BOARD_RECOVERY_DEFINES), \
   $(if $($(board_define)), \
diff --git a/bootloader.c b/bootloader.c
index f3dc268..d455923 100644
--- a/bootloader.c
+++ b/bootloader.c
@@ -40,7 +40,6 @@
         LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
         return -1;
     }
-    LOGE("no misc partition\n");
     return -1;
 }
 
@@ -56,7 +55,6 @@
         LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
         return -1;
     }
-    LOGE("no misc partition\n");
     return -1;
 }
 
diff --git a/common.h b/common.h
index 5d24881..77cf143 100644
--- a/common.h
+++ b/common.h
@@ -113,6 +113,10 @@
                               // == "ext4" or "vfat" and mounting
                               // 'device' fails
     const char* fs_type2;
+
+    const char* fs_options;
+
+    const char* fs_options2;
 } Volume;
 
 #endif  // RECOVERY_COMMON_H
diff --git a/default_recovery_ui.c b/default_recovery_ui.c
index 9c192a2..6d61581 100644
--- a/default_recovery_ui.c
+++ b/default_recovery_ui.c
@@ -30,6 +30,7 @@
                        "backup and restore",
                        "mounts and storage",
                        "advanced",
+                       "power off",
                        NULL };
 
 int device_recovery_start() {
@@ -42,7 +43,8 @@
         return 1;
     // allow toggling of the display if the correct key is pressed, and the display toggle is allowed or the display is currently off
     if (ui_get_showing_back_button()) {
-        return get_allow_toggle_display() && (key_code == KEY_HOME || key_code == KEY_MENU || key_code == KEY_END);
+        return 0;
+        //return get_allow_toggle_display() && (key_code == KEY_HOME || key_code == KEY_MENU || key_code == KEY_END);
     }
     return get_allow_toggle_display() && (key_code == KEY_HOME || key_code == KEY_MENU || key_code == KEY_POWER || key_code == KEY_END);
 }
@@ -57,11 +59,13 @@
             case KEY_CAPSLOCK:
             case KEY_DOWN:
             case KEY_VOLUMEDOWN:
+            case KEY_MENU:
                 return HIGHLIGHT_DOWN;
 
             case KEY_LEFTSHIFT:
             case KEY_UP:
             case KEY_VOLUMEUP:
+            case KEY_HOME:
                 return HIGHLIGHT_UP;
 
             case KEY_POWER:
@@ -82,9 +86,14 @@
             
             case KEY_END:
             case KEY_BACKSPACE:
-            case KEY_BACK:
+            case KEY_SEARCH:
+                if (ui_get_showing_back_button()) {
+                    return SELECT_ITEM;
+                }
                 if (!get_allow_toggle_display())
                     return GO_BACK;
+            case KEY_BACK:
+                return GO_BACK;
         }
     }
 
diff --git a/edifyscripting.c b/edifyscripting.c
index 7d0d728..83f089f 100644
--- a/edifyscripting.c
+++ b/edifyscripting.c
@@ -134,6 +134,14 @@
         free(path);
         return StringValue(strdup(""));
     }
+    
+    if (strcmp(path, "/data") == 0 && has_datadata()) {
+        ui_print("Formatting /datadata...\n", path);
+        if (0 != format_volume("/datadata")) {
+            free(path);
+            return StringValue(strdup(""));
+        }
+    }
 
 done:
     return StringValue(strdup(path));
diff --git a/extendedcommands.c b/extendedcommands.c
index 1ce3bf1..717d8d2 100644
--- a/extendedcommands.c
+++ b/extendedcommands.c
@@ -340,12 +340,15 @@
         nandroid_restore(file, 1, 1, 1, 1, 1, 0);
 }
 
+#ifndef BOARD_UMS_LUNFILE
+#define BOARD_UMS_LUNFILE	"/sys/devices/platform/usb_mass_storage/lun0/file"
+#endif
+
 void show_mount_usb_storage_menu()
 {
     int fd;
     Volume *vol = volume_for_path("/sdcard");
-    if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
-                   O_WRONLY)) < 0) {
+    if ((fd = open(BOARD_UMS_LUNFILE, O_WRONLY)) < 0) {
         LOGE("Unable to open ums lunfile (%s)", strerror(errno));
         return -1;
     }
@@ -371,7 +374,7 @@
             break;
     }
 
-    if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
+    if ((fd = open(BOARD_UMS_LUNFILE, O_WRONLY)) < 0) {
         LOGE("Unable to open ums lunfile (%s)", strerror(errno));
         return -1;
     }
@@ -473,6 +476,17 @@
 //#define DEVICE_COUNT 4
 //#define MMC_COUNT 2
 
+typedef struct {
+    char mount[255];
+    char unmount[255];
+    Volume* v;
+} MountMenuEntry;
+
+typedef struct {
+    char txt[255];
+    Volume* v;
+} FormatMenuEntry;
+
 void show_partition_menu()
 {
     static char* headers[] = {  "Mounts and Storage Menu",
@@ -480,87 +494,118 @@
                                 NULL
     };
 
+    static MountMenuEntry* mount_menue = NULL;
+    static FormatMenuEntry* format_menue = NULL;
+
     typedef char* string;
-    string mounts[][3] = {
-        { "mount /system", "unmount /system", "/system" },
-        { "mount /data", "unmount /data", "/data" },
-        { "mount /cache", "unmount /cache", "/cache" },
-        { "mount /sdcard", "unmount /sdcard", "/sdcard" },
-#ifdef BOARD_HAS_SDCARD_INTERNAL
-        { "mount /emmc", "unmount /emmc", "/emmc" },
-#endif
-        { "mount /sd-ext", "unmount /sd-ext", "/sd-ext" }
-    };
 
-    string devices[][2] = {
-        { "format boot", "/boot" },
-        { "format system", "/system" },
-        { "format data", "/data" },
-        { "format cache", "/cache" },
-        { "format sdcard", "/sdcard" },
-        { "format sd-ext", "/sd-ext" },
-#ifdef BOARD_HAS_SDCARD_INTERNAL
-        { "format internal sdcard", "/emmc" }
-#endif
-    };
+    int i, mountable_volumes, formatable_volumes;
+    int num_volumes;
+    Volume* device_volumes;
 
-    const int MOUNTABLE_COUNT = sizeof(mounts) / sizeof(string) / 3;
-    const int DEVICE_COUNT = sizeof(devices) / sizeof(string) / 2;
+    num_volumes = get_num_volumes();
+    device_volumes = get_device_volumes();
+
+    string options[255];
+
+    if(!device_volumes)
+		return;
+
+		mountable_volumes = 0;
+		formatable_volumes = 0;
+
+		mount_menue = malloc(num_volumes * sizeof(MountMenuEntry));
+		format_menue = malloc(num_volumes * sizeof(FormatMenuEntry));
+
+		for (i = 0; i < num_volumes; ++i) {
+			Volume* v = &device_volumes[i];
+			if(strcmp("ramdisk", v->fs_type) != 0 && strcmp("mtd", v->fs_type) != 0 && strcmp("emmc", v->fs_type) != 0 && strcmp("bml", v->fs_type) != 0)
+			{
+				sprintf(&mount_menue[mountable_volumes].mount, "mount %s", v->mount_point);
+				sprintf(&mount_menue[mountable_volumes].unmount, "unmount %s", v->mount_point);
+				mount_menue[mountable_volumes].v = &device_volumes[i];
+				++mountable_volumes;
+				sprintf(&format_menue[formatable_volumes].txt, "format %s", v->mount_point);
+				format_menue[formatable_volumes].v = &device_volumes[i];
+				++formatable_volumes;
+		    }
+		    else if (strcmp("ramdisk", v->fs_type) != 0 && strcmp("misc", v->mount_point) != 0 && strcmp("mtd", v->fs_type) == 0)
+		    {
+				sprintf(&format_menue[formatable_volumes].txt, "format %s", v->mount_point);
+				format_menue[formatable_volumes].v = &device_volumes[i];
+				++formatable_volumes;
+			}
+		}
+
 
     static char* confirm_format  = "Confirm format?";
     static char* confirm = "Yes - Format";
 
     for (;;)
     {
-        int ismounted[MOUNTABLE_COUNT];
-        int i;
-        static string options[MOUNTABLE_COUNT + DEVICE_COUNT + 1 + 1]; // mountables, format mtds, format mmcs, usb storage, null
-        for (i = 0; i < MOUNTABLE_COUNT; i++)
-        {
-            ismounted[i] = is_path_mounted(mounts[i][2]);
-            options[i] = ismounted[i] ? mounts[i][1] : mounts[i][0];
-        }
 
-        for (i = 0; i < DEVICE_COUNT; i++)
-        {
-            options[MOUNTABLE_COUNT + i] = devices[i][0];
-        }
+		for (i = 0; i < mountable_volumes; i++)
+		{
+			MountMenuEntry* e = &mount_menue[i];
+			Volume* v = e->v;
+			if(is_path_mounted(v->mount_point))
+				options[i] = e->unmount;
+			else
+				options[i] = e->mount;
+		}
 
-        options[MOUNTABLE_COUNT + DEVICE_COUNT] = "mount USB storage";
-        options[MOUNTABLE_COUNT + DEVICE_COUNT + 1] = NULL;
+		for (i = 0; i < formatable_volumes; i++)
+		{
+			FormatMenuEntry* e = &format_menue[i];
 
-        int chosen_item = get_menu_selection(headers, options, 0, 0);
+			options[mountable_volumes+i] = e->txt;
+		}
+
+        options[mountable_volumes+formatable_volumes] = "mount USB storage";
+        options[mountable_volumes+formatable_volumes + 1] = NULL;
+
+        int chosen_item = get_menu_selection(headers, &options, 0, 0);
         if (chosen_item == GO_BACK)
             break;
-        if (chosen_item == MOUNTABLE_COUNT + DEVICE_COUNT)
+        if (chosen_item == (mountable_volumes+formatable_volumes))
         {
             show_mount_usb_storage_menu();
         }
-        else if (chosen_item < MOUNTABLE_COUNT)
+        else if (chosen_item < mountable_volumes)
         {
-            if (ismounted[chosen_item])
+			MountMenuEntry* e = &mount_menue[chosen_item];
+            Volume* v = e->v;
+
+            if (is_path_mounted(v->mount_point))
             {
-                if (0 != ensure_path_unmounted(mounts[chosen_item][2]))
-                    ui_print("Error unmounting %s!\n", mounts[chosen_item][2]);
+                if (0 != ensure_path_unmounted(v->mount_point))
+                    ui_print("Error unmounting %s!\n", v->mount_point);
             }
             else
             {
-                if (0 != ensure_path_mounted(mounts[chosen_item][2]))
-                    ui_print("Error mounting %s!\n", mounts[chosen_item][2]);
+                if (0 != ensure_path_mounted(v->mount_point))
+                    ui_print("Error mounting %s!\n",  v->mount_point);
             }
         }
-        else if (chosen_item < MOUNTABLE_COUNT + DEVICE_COUNT)
+        else if (chosen_item < (mountable_volumes + formatable_volumes))
         {
-            chosen_item = chosen_item - MOUNTABLE_COUNT;
+            chosen_item = chosen_item - mountable_volumes;
+            FormatMenuEntry* e = &format_menue[chosen_item];
+            Volume* v = e->v;
+
             if (!confirm_selection(confirm_format, confirm))
                 continue;
-            ui_print("Formatting %s...\n", devices[chosen_item][1]);
-            if (0 != format_volume(devices[chosen_item][1]))
-                ui_print("Error formatting %s!\n", devices[chosen_item][1]);
+            ui_print("Formatting %s...\n", v->mount_point);
+            if (0 != format_volume(v->mount_point))
+                ui_print("Error formatting %s!\n", v->mount_point);
             else
                 ui_print("Done.\n");
         }
     }
+
+    free(mount_menue);
+    free(format_menue);
+
 }
 
 #define EXTENDEDCOMMAND_SCRIPT "/cache/recovery/extendedcommand"
@@ -974,7 +1019,8 @@
 
     fprintf(file, "%s ", device);
     fprintf(file, "%s ", path);
-    fprintf(file, "%s rw\n", vol->fs_type2 != NULL ? "auto" : vol->fs_type);
+    // special case rfs cause auto will mount it as vfat on samsung.
+    fprintf(file, "%s rw\n", vol->fs_type2 != NULL && strcmp(vol->fs_type, "rfs") != 0 ? "auto" : vol->fs_type);
 }
 
 void create_fstab()
@@ -1026,6 +1072,9 @@
 void process_volumes() {
     create_fstab();
     
+    return;
+
+    // dead code.
     if (device_flash_type() != BML)
         return;
 
@@ -1127,4 +1176,4 @@
     
     if (strstr(file_data, "androidboot.mode=offmode_charging") != NULL)
         reboot(RB_POWER_OFF);
- }
\ No newline at end of file
+ }
diff --git a/flashutils/flashutils.c b/flashutils/flashutils.c
index b71d4fa..0b1467e 100644
--- a/flashutils/flashutils.c
+++ b/flashutils/flashutils.c
@@ -69,9 +69,21 @@
     return (pid == -1 ? -1 : pstat);
 }
 
-int restore_raw_partition(const char *partition, const char *filename)
+static int detect_partition(const char *partition)
 {
     int type = device_flash_type();
+    if (strstr(partition, "/dev/block/mtd") != NULL)
+        type = MTD;
+    else if (strstr(partition, "/dev/block/mmc") != NULL)
+        type = MMC;
+    else if (strstr(partition, "/dev/block/bml") != NULL)
+        type = BML;
+        
+    return type;
+}
+int restore_raw_partition(const char *partition, const char *filename)
+{
+    int type = detect_partition(partition);
     switch (type) {
         case MTD:
             return cmd_mtd_restore_raw_partition(partition, filename);
@@ -86,7 +98,7 @@
 
 int backup_raw_partition(const char *partition, const char *filename)
 {
-    int type = device_flash_type();
+    int type = detect_partition(partition);
     switch (type) {
         case MTD:
             return cmd_mtd_backup_raw_partition(partition, filename);
@@ -101,7 +113,7 @@
 
 int erase_raw_partition(const char *partition)
 {
-    int type = device_flash_type();
+    int type = detect_partition(partition);
     switch (type) {
         case MTD:
             return cmd_mtd_erase_raw_partition(partition);
@@ -116,7 +128,7 @@
 
 int erase_partition(const char *partition, const char *filesystem)
 {
-    int type = device_flash_type();
+    int type = detect_partition(partition);
     switch (type) {
         case MTD:
             return cmd_mtd_erase_partition(partition, filesystem);
@@ -131,7 +143,7 @@
 
 int mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only)
 {
-    int type = device_flash_type();
+    int type = detect_partition(partition);
     switch (type) {
         case MTD:
             return cmd_mtd_mount_partition(partition, mount_point, filesystem, read_only);
diff --git a/mmcutils/Android.mk b/mmcutils/Android.mk
index f1fe294..0046dc9 100644
--- a/mmcutils/Android.mk
+++ b/mmcutils/Android.mk
@@ -4,6 +4,10 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
+ifeq ($(BOARD_HAS_LARGE_FILESYSTEM),true)
+LOCAL_CFLAGS += -DBOARD_HAS_LARGE_FILESYSTEM
+endif
+
 LOCAL_SRC_FILES := \
 	mmcutils.c
 
diff --git a/mmcutils/mmcutils.c b/mmcutils/mmcutils.c
index e0efe55..76b8ff8 100644
--- a/mmcutils/mmcutils.c
+++ b/mmcutils/mmcutils.c
@@ -340,13 +340,18 @@
 
 int
 format_ext3_device (const char *device) {
-    // Run mke2fs
+#ifdef BOARD_HAS_LARGE_FILESYSTEM
+    char *const mke2fs[] = {MKE2FS_BIN, "-j", "-q", device, NULL};
+    char *const tune2fs[] = {TUNE2FS_BIN, "-C", "1", device, NULL};
+#else
     char *const mke2fs[] = {MKE2FS_BIN, "-j", device, NULL};
+    char *const tune2fs[] = {TUNE2FS_BIN, "-j", "-C", "1", device, NULL};
+#endif
+    // Run mke2fs
     if(run_exec_process(mke2fs))
         return -1;
 
     // Run tune2fs
-    char *const tune2fs[] = {TUNE2FS_BIN, "-j", "-C", "1", device, NULL};
     if(run_exec_process(tune2fs))
         return -1;
 
@@ -464,9 +469,8 @@
 }
 
 
-// TODO: refactor this to not be a giant copy paste mess
 int
-mmc_raw_dump (const MmcPartition *partition, char *out_file) {
+mmc_raw_dump_internal (const char* in_file, const char *out_file) {
     int ch;
     FILE *in;
     FILE *out;
@@ -475,7 +479,6 @@
     unsigned sz = 0;
     unsigned i;
     int ret = -1;
-    char *in_file = partition->device_index;
 
     in  = fopen ( in_file,  "r" );
     if (in == NULL)
@@ -516,6 +519,12 @@
 
 }
 
+// TODO: refactor this to not be a giant copy paste mess
+int
+mmc_raw_dump (const MmcPartition *partition, char *out_file) {
+    return mmc_raw_dump_internal(partition->device_index, out_file);
+}
+
 
 int
 mmc_raw_read (const MmcPartition *partition, char *data, int data_size) {
@@ -575,33 +584,36 @@
 
 int cmd_mmc_restore_raw_partition(const char *partition, const char *filename)
 {
-    mmc_scan_partitions();
-    const MmcPartition *p;
-    p = mmc_find_partition_by_name(partition);
-    if (p == NULL)
-        return -1;
-    return mmc_raw_copy(p, filename);
+    if (partition[0] != '/') {
+        mmc_scan_partitions();
+        const MmcPartition *p;
+        p = mmc_find_partition_by_name(partition);
+        if (p == NULL)
+            return -1;
+        return mmc_raw_copy(p, filename);
+    }
+    else {
+        return mmc_raw_dump_internal(filename, partition);
+    }
 }
 
 int cmd_mmc_backup_raw_partition(const char *partition, const char *filename)
 {
-    mmc_scan_partitions();
-    const MmcPartition *p;
-    p = mmc_find_partition_by_name(partition);
-    if (p == NULL)
-        return -1;
-    return mmc_raw_dump(p, filename);
+    if (partition[0] != '/') {
+        mmc_scan_partitions();
+        const MmcPartition *p;
+        p = mmc_find_partition_by_name(partition);
+        if (p == NULL)
+            return -1;
+        return mmc_raw_dump(p, filename);
+    }
+    else {
+        return mmc_raw_dump_internal(partition, filename);
+    }
 }
 
 int cmd_mmc_erase_raw_partition(const char *partition)
 {
-    mmc_scan_partitions();
-    const MmcPartition *p;
-    p = mmc_find_partition_by_name(partition);
-    if (p == NULL)
-        return -1;
-
-    // TODO: implement raw wipe
     return 0;
 }
 
diff --git a/nandroid.c b/nandroid.c
index 45417fb..933faa3 100644
--- a/nandroid.c
+++ b/nandroid.c
@@ -110,6 +110,7 @@
     char tmp[PATH_MAX];
     int ret;
     if (strcmp(vol->fs_type, "mtd") == 0 ||
+            strcmp(vol->fs_type, "bml") == 0 ||
             strcmp(vol->fs_type, "emmc") == 0) {
         const char* name = basename(root);
         sprintf(tmp, "%s/%s.img", backup_path, name);
@@ -153,14 +154,15 @@
     if (0 != (ret = nandroid_backup_partition(backup_path, "/recovery")))
         return ret;
 
-    if (0 == (ret = get_partition_device("wimax", tmp)))
+    Volume *vol = volume_for_path("/wimax");
+    if (vol != NULL && 0 == stat(vol->device, &s))
     {
         char serialno[PROPERTY_VALUE_MAX];
         ui_print("Backing up WiMAX...\n");
         serialno[0] = 0;
         property_get("ro.serialno", serialno, "");
         sprintf(tmp, "%s/wimax.%s.img", backup_path, serialno);
-        ret = backup_raw_partition("wimax", tmp);
+        ret = backup_raw_partition(vol->device, tmp);
         if (0 != ret)
             return print_and_error("Error while dumping WiMAX image!\n");
     }
@@ -176,8 +178,7 @@
             return ret;
     }
 
-    struct stat st;
-    if (0 != stat("/sdcard/.android_secure", &st))
+    if (0 != stat("/sdcard/.android_secure", &s))
     {
         ui_print("No /sdcard/.android_secure found. Skipping backup of applications on external storage.\n");
     }
@@ -190,8 +191,8 @@
     if (0 != (ret = nandroid_backup_partition_extended(backup_path, "/cache", 0)))
         return ret;
 
-    Volume *vol = volume_for_path("/sd-ext");
-    if (vol == NULL || 0 != stat(vol->device, &st))
+    vol = volume_for_path("/sd-ext");
+    if (vol == NULL || 0 != stat(vol->device, &s))
     {
         ui_print("No sd-ext found. Skipping backup of sd-ext.\n");
     }
@@ -282,6 +283,7 @@
     // see if we need a raw restore (mtd)
     char tmp[PATH_MAX];
     if (strcmp(vol->fs_type, "mtd") == 0 ||
+            strcmp(vol->fs_type, "bml") == 0 ||
             strcmp(vol->fs_type, "emmc") == 0) {
         int ret;
         const char* name = basename(root);
@@ -322,7 +324,9 @@
     if (restore_boot && NULL != volume_for_path("/boot") && 0 != (ret = nandroid_restore_partition(backup_path, "/boot")))
         return ret;
     
-    if (restore_wimax && 0 == (ret = get_partition_device("wimax", tmp)))
+    struct stat s;
+    Volume *vol = volume_for_path("/wimax");
+    if (restore_wimax && vol != NULL && 0 == stat(vol->device, &s))
     {
         char serialno[PROPERTY_VALUE_MAX];
         
@@ -344,7 +348,7 @@
             if (0 != (ret = format_volume("/wimax")))
                 return print_and_error("Error while formatting wimax!\n");
             ui_print("Restoring WiMAX image...\n");
-            if (0 != (ret = restore_raw_partition("wimax", tmp)))
+            if (0 != (ret = restore_raw_partition(vol->device, tmp)))
                 return ret;
         }
     }
diff --git a/recovery.c b/recovery.c
index bb4c1be..963c724 100644
--- a/recovery.c
+++ b/recovery.c
@@ -61,6 +61,7 @@
 static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
 static const char *SDCARD_ROOT = "/sdcard";
 static int allow_display_toggle = 1;
+static int poweroff = 0;
 static const char *SDCARD_PACKAGE_FILE = "/sdcard/update.zip";
 static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
 static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
@@ -707,6 +708,7 @@
 
         switch (chosen_item) {
             case ITEM_REBOOT:
+                poweroff=0;
                 return;
 
             case ITEM_WIPE_DATA:
@@ -751,6 +753,9 @@
             case ITEM_ADVANCED:
                 show_advanced_menu();
                 break;
+            case ITEM_POWEROFF:
+                poweroff=1;
+                return;
         }
     }
 }
@@ -782,6 +787,9 @@
             return nandroid_main(argc, argv);
         if (strstr(argv[0], "reboot"))
             return reboot_main(argc, argv);
+        if (strstr(argv[0], "poweroff")){
+            return reboot_main(argc, argv);
+        }
         if (strstr(argv[0], "setprop"))
             return setprop_main(argc, argv);
 		return busybox_driver(argc, argv);
@@ -939,9 +947,12 @@
 
     // Otherwise, get ready to boot the main system...
     finish_recovery(send_intent);
-    ui_print("Rebooting...\n");
+    if(!poweroff)
+        ui_print("Rebooting...\n");
+    else
+        ui_print("Shutting down...\n");
     sync();
-    reboot(RB_AUTOBOOT);
+    reboot((!poweroff) ? RB_AUTOBOOT : RB_POWER_OFF);
     return EXIT_SUCCESS;
 }
 
diff --git a/recovery_ui.h b/recovery_ui.h
index f34365f..50af45b 100644
--- a/recovery_ui.h
+++ b/recovery_ui.h
@@ -74,6 +74,7 @@
 #define ITEM_NANDROID        5
 #define ITEM_PARTITION       6
 #define ITEM_ADVANCED        7
+#define ITEM_POWEROFF        8          
 
 // Header text to display above the main menu.
 extern char* MENU_HEADERS[];
diff --git a/roots.c b/roots.c
index 4ef5c37..a3c4677 100644
--- a/roots.c
+++ b/roots.c
@@ -28,8 +28,30 @@
 #include "common.h"
 #include "make_ext4fs.h"
 
-static int num_volumes = 0;
-static Volume* device_volumes = NULL;
+int num_volumes;
+Volume* device_volumes;
+
+int get_num_volumes() {
+    return num_volumes;
+}
+
+Volume* get_device_volumes() {
+    return device_volumes;
+}
+
+static int is_null(const char* sz) {
+    if (sz == NULL)
+        return 1;
+    if (strcmp("NULL", sz) == 0)
+        return 1;
+    return 0;
+}
+
+static char* dupe_string(const char* sz) {
+    if (is_null(sz))
+        return NULL;
+    return strdup(sz);
+}
 
 void load_volume_table() {
     int alloc = 2;
@@ -40,6 +62,8 @@
     device_volumes[0].fs_type = "ramdisk";
     device_volumes[0].device = NULL;
     device_volumes[0].device2 = NULL;
+    device_volumes[0].fs_options = NULL;
+    device_volumes[0].fs_options2 = NULL;
     num_volumes = 1;
 
     FILE* fstab = fopen("/etc/recovery.fstab", "r");
@@ -63,6 +87,8 @@
         // mounting the first one fails.
         char* device2 = strtok(NULL, " \t\n");
         char* fs_type2 = strtok(NULL, " \t\n");
+        char* fs_options = strtok(NULL, " \t\n");
+        char* fs_options2 = strtok(NULL, " \t\n");
 
         if (mount_point && fs_type && device) {
             while (num_volumes >= alloc) {
@@ -70,11 +96,20 @@
                 device_volumes = realloc(device_volumes, alloc*sizeof(Volume));
             }
             device_volumes[num_volumes].mount_point = strdup(mount_point);
-            device_volumes[num_volumes].fs_type = fs_type2 != NULL ? strdup(fs_type2) : strdup(fs_type);
+            device_volumes[num_volumes].fs_type = !is_null(fs_type2) ? strdup(fs_type2) : strdup(fs_type);
             device_volumes[num_volumes].device = strdup(device);
             device_volumes[num_volumes].device2 =
-                (device2 != NULL && strcmp(device2, "NULL") != 0) ? strdup(device2) : NULL;
-            device_volumes[num_volumes].fs_type2 = fs_type2 != NULL ? strdup(fs_type) : NULL;
+                !is_null(device2) ? strdup(device2) : NULL;
+            device_volumes[num_volumes].fs_type2 = !is_null(fs_type2) ? strdup(fs_type) : NULL;
+
+            if (!is_null(fs_type2)) {
+                device_volumes[num_volumes].fs_options2 = dupe_string(fs_options);
+                device_volumes[num_volumes].fs_options = dupe_string(fs_options2);
+            }
+            else {
+                device_volumes[num_volumes].fs_options2 = NULL;
+                device_volumes[num_volumes].fs_options = dupe_string(fs_options);
+            }
             ++num_volumes;
         } else {
             LOGE("skipping malformed recovery.fstab line: %s\n", original);
@@ -107,11 +142,20 @@
     return NULL;
 }
 
-int try_mount(const char* device, const char* mount_point, const char* fs_type) {
+int try_mount(const char* device, const char* mount_point, const char* fs_type, const char* fs_options) {
     if (device == NULL || mount_point == NULL || fs_type == NULL)
         return -1;
-    int ret = mount(device, mount_point, fs_type,
+    int ret = 0;
+    if (fs_options == NULL) {
+        ret = mount(device, mount_point, fs_type,
                        MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
+    }
+    else {
+        char mount_cmd[PATH_MAX];
+        sprintf(mount_cmd, "mount -t %s -o%s %s %s", fs_type, fs_options, device, mount_point);
+        LOGE("%s\n", mount_cmd);
+        ret = __system(mount_cmd);
+    }
     if (ret == 0)
         return 0;
     LOGW("failed to mount %s (%s)\n", device, strerror(errno));
@@ -158,15 +202,15 @@
         return mtd_mount_partition(partition, v->mount_point, v->fs_type, 0);
     } else if (strcmp(v->fs_type, "ext4") == 0 ||
                strcmp(v->fs_type, "ext3") == 0 ||
+               strcmp(v->fs_type, "rfs") == 0 ||
                strcmp(v->fs_type, "vfat") == 0) {
-        // try fs type 2 first
-        if ((result = try_mount(v->device, v->mount_point, v->fs_type)) == 0)
+        if ((result = try_mount(v->device, v->mount_point, v->fs_type, v->fs_options)) == 0)
             return 0;
-        if ((result = try_mount(v->device2, v->mount_point, v->fs_type)) == 0)
+        if ((result = try_mount(v->device2, v->mount_point, v->fs_type, v->fs_options)) == 0)
             return 0;
-        if ((result = try_mount(v->device, v->mount_point, v->fs_type2)) == 0)
+        if ((result = try_mount(v->device, v->mount_point, v->fs_type2, v->fs_options2)) == 0)
             return 0;
-        if ((result = try_mount(v->device2, v->mount_point, v->fs_type2)) == 0)
+        if ((result = try_mount(v->device2, v->mount_point, v->fs_type2, v->fs_options2)) == 0)
             return 0;
         return result;
     } else {
diff --git a/roots.h b/roots.h
index cf59bfd..7132fed 100644
--- a/roots.h
+++ b/roots.h
@@ -38,4 +38,8 @@
 // it is mounted.
 int format_volume(const char* volume);
 
+int get_num_volumes();
+
+Volume* get_device_volumes();
+
 #endif  // RECOVERY_ROOTS_H_
diff --git a/utilities/Android.mk b/utilities/Android.mk
index f6b6e64..251c9e6 100644
--- a/utilities/Android.mk
+++ b/utilities/Android.mk
@@ -42,4 +42,14 @@
 LOCAL_SRC_FILES := $(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
 
+ifeq ($BOARD_HAS_LARGE_FILESYSTEM,true)
+include $(CLEAR_VARS)
+LOCAL_MODULE := mke2fs
+LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+endif
+
 endif
diff --git a/utilities/mke2fs b/utilities/mke2fs
new file mode 100644
index 0000000..6e415b8
--- /dev/null
+++ b/utilities/mke2fs
Binary files differ