tar nandroid and /data/media support.
Change-Id: I9405e701887fc83c422c63c1dbf5ff087fff880d
diff --git a/nandroid.c b/nandroid.c
index 54d90b0..8cee3be 100644
--- a/nandroid.c
+++ b/nandroid.c
@@ -37,10 +37,11 @@
#include "extendedcommands.h"
#include "nandroid.h"
+#include "mounts.h"
+
#include "flashutils/flashutils.h"
#include <libgen.h>
-
void nandroid_generate_timestamp_path(const char* backup_path)
{
time_t t = time(NULL);
@@ -57,25 +58,31 @@
}
}
-int print_and_error(const char* message) {
+static int print_and_error(const char* message) {
ui_print("%s", message);
return 1;
}
-int yaffs_files_total = 0;
-int yaffs_files_count = 0;
-void yaffs_callback(const char* filename)
+static int yaffs_files_total = 0;
+static int yaffs_files_count = 0;
+static void yaffs_callback(const char* filename)
{
- char* justfile = basename(filename);
- if (strlen(justfile) < 30)
- ui_print("%s", justfile);
+ if (filename == NULL)
+ return;
+ const char* justfile = basename(filename);
+ char tmp[PATH_MAX];
+ strcpy(tmp, justfile);
+ if (tmp[strlen(tmp) - 1] == '\n')
+ tmp[strlen(tmp) - 1] = NULL;
+ if (strlen(tmp) < 30)
+ ui_print("%s", tmp);
yaffs_files_count++;
if (yaffs_files_total != 0)
ui_set_progress((float)yaffs_files_count / (float)yaffs_files_total);
ui_reset_text_col();
}
-void compute_directory_stats(const char* directory)
+static void compute_directory_stats(const char* directory)
{
char tmp[PATH_MAX];
sprintf(tmp, "find %s | wc -l > /tmp/dircount", directory);
@@ -90,12 +97,62 @@
ui_show_progress(1, 0);
}
+typedef void (*file_event_callback)(const char* filename);
+typedef int (*nandroid_backup_handler)(const char* backup_path, const char* backup_file_image, const file_event_callback callback);
+
+static int mkyaffs2image_wrapper(const char* backup_path, const char* backup_file_image, const file_event_callback callback) {
+ return mkyaffs2image(backup_path, backup_file_image, 0, callback);
+}
+
+static int tar_compress_wrapper(const char* backup_path, const char* backup_file_image, const file_event_callback callback) {
+ char tmp[PATH_MAX];
+ if (strcmp(backup_path, "/data") == 0 && volume_for_path("/sdcard") == NULL)
+ sprintf(tmp, "cd $(dirname %s) ; tar cvf %s --exclude 'media' $(basename %s) ; exit $?", backup_path, backup_file_image, backup_path);
+ else
+ sprintf(tmp, "cd $(dirname %s) ; tar cvf %s $(basename %s) ; exit $?", backup_path, backup_file_image, backup_path);
+
+ FILE *fp = __popen(tmp, "r");
+ if (fp == NULL) {
+ ui_print("Unable to execute tar.\n");
+ return -1;
+ }
+
+ while (fgets(tmp, PATH_MAX, fp) != NULL) {
+ tmp[PATH_MAX - 1] = NULL;
+ if (NULL != callback)
+ yaffs_callback(tmp);
+ }
+
+ return __pclose(fp);
+}
+
+static nandroid_backup_handler get_backup_handler(const char *backup_path) {
+ Volume *v = volume_for_path(backup_path);
+ if (v == NULL) {
+ ui_print("Unable to find volume.\n");
+ return NULL;
+ }
+ scan_mounted_volumes();
+ MountedVolume *mv = find_mounted_volume_by_mount_point(v->mount_point);
+ if (mv == NULL) {
+ ui_print("Unable to find mounted volume: %s\n", v->mount_point);
+ return NULL;
+ }
+
+ if (strcmp("yaffs2", mv->filesystem) == 0) {
+ return mkyaffs2image_wrapper;
+ }
+
+ return tar_compress_wrapper;
+}
+
+
int nandroid_backup_partition_extended(const char* backup_path, const char* mount_point, int umount_when_finished) {
int ret = 0;
char* name = basename(mount_point);
struct stat file_info;
- mkyaffs2image_callback callback = NULL;
+ file_event_callback callback = NULL;
if (0 != stat("/sdcard/clockworkmod/.hidenandroidprogress", &file_info)) {
callback = yaffs_callback;
}
@@ -108,12 +165,17 @@
compute_directory_stats(mount_point);
char tmp[PATH_MAX];
sprintf(tmp, "%s/%s.img", backup_path, name);
- ret = mkyaffs2image(mount_point, tmp, 0, callback);
+ nandroid_backup_handler backup_handler = get_backup_handler(mount_point);
+ if (backup_handler == NULL) {
+ ui_print("Error finding an appropriate backup handler.\n");
+ return -2;
+ }
+ ret = backup_handler(mount_point, tmp, callback);
if (umount_when_finished) {
ensure_path_unmounted(mount_point);
}
if (0 != ret) {
- ui_print("Error while making a yaffs2 image of %s!\n", mount_point);
+ ui_print("Error while making a backup image of %s!\n", mount_point);
return ret;
}
return 0;
@@ -245,6 +307,51 @@
__system(tmp);
}
+typedef int (*nandroid_restore_handler)(const char* backup_file_image, const char* backup_path, file_event_callback callback);
+
+static int unyaffs_wrapper(const char* backup_file_image, const char* backup_path, file_event_callback callback) {
+ return unyaffs(backup_file_image, backup_path, callback);
+}
+
+static int tar_extract_wrapper(const char* backup_file_image, const char* backup_path, file_event_callback callback) {
+ char tmp[PATH_MAX];
+ sprintf(tmp, "cd $(dirname %s) ; tar xvf %s ; exit $?", backup_path, backup_file_image);
+
+ char path[PATH_MAX];
+ FILE *fp = __popen(tmp, "r");
+ if (fp == NULL) {
+ ui_print("Unable to execute tar.\n");
+ return -1;
+ }
+
+ while (fgets(path, PATH_MAX, fp) != NULL) {
+ if (NULL != callback)
+ callback(path);
+ }
+
+ return __pclose(fp);
+}
+
+static nandroid_restore_handler get_restore_handler(const char *backup_path) {
+ Volume *v = volume_for_path(backup_path);
+ if (v == NULL) {
+ ui_print("Unable to find volume.\n");
+ return NULL;
+ }
+ scan_mounted_volumes();
+ MountedVolume *mv = find_mounted_volume_by_mount_point(v->mount_point);
+ if (mv == NULL) {
+ ui_print("Unable to find mounted volume: %s\n", v->mount_point);
+ return NULL;
+ }
+
+ if (strcmp("yaffs2", mv->filesystem) == 0) {
+ return unyaffs_wrapper;
+ }
+
+ return tar_extract_wrapper;
+}
+
int nandroid_restore_partition_extended(const char* backup_path, const char* mount_point, int umount_when_finished) {
int ret = 0;
char* name = basename(mount_point);
@@ -259,7 +366,7 @@
ensure_directory(mount_point);
- unyaffs_callback callback = NULL;
+ file_event_callback callback = NULL;
if (0 != stat("/sdcard/clockworkmod/.hidenandroidprogress", &file_info)) {
callback = yaffs_callback;
}
@@ -281,7 +388,12 @@
return ret;
}
- if (0 != (ret = unyaffs(tmp, mount_point, callback))) {
+ nandroid_restore_handler restore_handler = get_restore_handler(mount_point);
+ if (restore_handler == NULL) {
+ ui_print("Error finding an appropriate restore handler.\n");
+ return -2;
+ }
+ if (0 != (ret = restore_handler(tmp, mount_point, callback))) {
ui_print("Error while restoring %s!\n", mount_point);
return ret;
}