From 1b7a31bd65d4e6bf5e337d6280e3d5319d460bef Mon Sep 17 00:00:00 2001 From: Ethan Yonker Date: Thu, 3 Jul 2014 15:09:22 -0500 Subject: Track backup and restore progress Track backup and restore progress based on the sizes of the files as they are being added to the tar backup file. Update the progress bar based on the sizes of the files. Change-Id: Idf649efa1db3e91830b4b2add86203a3f30042ff --- Android.mk | 3 +- gui/devices/1024x600/res/ui.xml | 18 +++ gui/devices/1024x768/res/ui.xml | 18 +++ gui/devices/1080x1920/res/ui.xml | 18 +++ gui/devices/1200x1920/res/ui.xml | 18 +++ gui/devices/1280x800/res/ui.xml | 18 +++ gui/devices/1600x2560/res/ui.xml | 22 ++- gui/devices/1920x1200/res/ui.xml | 18 +++ gui/devices/2560x1600/res/ui.xml | 18 +++ gui/devices/320x480/res/ui.xml | 18 +++ gui/devices/480x800/res/ui.xml | 18 +++ gui/devices/480x854/res/ui.xml | 18 +++ gui/devices/540x960/res/ui.xml | 18 +++ gui/devices/720x1280/res/ui.xml | 18 +++ gui/devices/800x1280/res/ui.xml | 18 +++ gui/devices/800x480/res/ui.xml | 18 +++ infomanager.cpp | 206 +++++++++++++++++++++++++ infomanager.hpp | 58 +++++++ libtar/extract.c | 11 +- libtar/libtar.h | 6 +- libtar/wrapper.c | 8 +- partition.cpp | 104 ++++++++++--- partitionmanager.cpp | 35 +++-- partitions.hpp | 17 ++- twrp-functions.cpp | 24 +++ twrp-functions.hpp | 1 + twrpTar.cpp | 315 ++++++++++++++++++++++++++++++++++++--- twrpTar.hpp | 10 +- twrpTarMain/twrpTarMain.cpp | 5 +- 29 files changed, 1005 insertions(+), 72 deletions(-) create mode 100644 infomanager.cpp create mode 100644 infomanager.hpp diff --git a/Android.mk b/Android.mk index 1b4cb0751..c864ff0f7 100644 --- a/Android.mk +++ b/Android.mk @@ -24,7 +24,8 @@ LOCAL_SRC_FILES := \ twrpTar.cpp \ twrpDU.cpp \ twrpDigest.cpp \ - find_file.cpp + find_file.cpp \ + infomanager.cpp LOCAL_SRC_FILES += \ data.cpp \ diff --git a/gui/devices/1024x600/res/ui.xml b/gui/devices/1024x600/res/ui.xml index d54771941..4795ce0ed 100755 --- a/gui/devices/1024x600/res/ui.xml +++ b/gui/devices/1024x600/res/ui.xml @@ -2304,6 +2304,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2679,6 +2691,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + diff --git a/gui/devices/1024x768/res/ui.xml b/gui/devices/1024x768/res/ui.xml index f404b466d..d041c50e0 100644 --- a/gui/devices/1024x768/res/ui.xml +++ b/gui/devices/1024x768/res/ui.xml @@ -2304,6 +2304,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2679,6 +2691,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + diff --git a/gui/devices/1080x1920/res/ui.xml b/gui/devices/1080x1920/res/ui.xml index 28130b7db..f95ae090f 100644 --- a/gui/devices/1080x1920/res/ui.xml +++ b/gui/devices/1080x1920/res/ui.xml @@ -2056,6 +2056,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2429,6 +2441,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + diff --git a/gui/devices/1200x1920/res/ui.xml b/gui/devices/1200x1920/res/ui.xml index d19813947..0630e10e1 100644 --- a/gui/devices/1200x1920/res/ui.xml +++ b/gui/devices/1200x1920/res/ui.xml @@ -2059,6 +2059,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2432,6 +2444,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + diff --git a/gui/devices/1280x800/res/ui.xml b/gui/devices/1280x800/res/ui.xml index 21fc3b7a8..fdd205941 100644 --- a/gui/devices/1280x800/res/ui.xml +++ b/gui/devices/1280x800/res/ui.xml @@ -2304,6 +2304,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2679,6 +2691,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + diff --git a/gui/devices/1600x2560/res/ui.xml b/gui/devices/1600x2560/res/ui.xml index b6ca28c7e..95ef1d1bf 100644 --- a/gui/devices/1600x2560/res/ui.xml +++ b/gui/devices/1600x2560/res/ui.xml @@ -2061,6 +2061,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2434,6 +2446,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + @@ -3902,7 +3920,7 @@ filemanageracction - + @@ -3918,7 +3936,7 @@ main - + diff --git a/gui/devices/1920x1200/res/ui.xml b/gui/devices/1920x1200/res/ui.xml index 5ee5b4646..2622a8878 100644 --- a/gui/devices/1920x1200/res/ui.xml +++ b/gui/devices/1920x1200/res/ui.xml @@ -2304,6 +2304,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2679,6 +2691,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + diff --git a/gui/devices/2560x1600/res/ui.xml b/gui/devices/2560x1600/res/ui.xml index 25b86194f..06880b22e 100644 --- a/gui/devices/2560x1600/res/ui.xml +++ b/gui/devices/2560x1600/res/ui.xml @@ -2304,6 +2304,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2679,6 +2691,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + diff --git a/gui/devices/320x480/res/ui.xml b/gui/devices/320x480/res/ui.xml index 369b9941e..fff85334e 100644 --- a/gui/devices/320x480/res/ui.xml +++ b/gui/devices/320x480/res/ui.xml @@ -2043,6 +2043,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2416,6 +2428,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + diff --git a/gui/devices/480x800/res/ui.xml b/gui/devices/480x800/res/ui.xml index 72b44e51f..6baa70293 100644 --- a/gui/devices/480x800/res/ui.xml +++ b/gui/devices/480x800/res/ui.xml @@ -2043,6 +2043,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2416,6 +2428,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + diff --git a/gui/devices/480x854/res/ui.xml b/gui/devices/480x854/res/ui.xml index 5026f4016..4f5a7c98a 100644 --- a/gui/devices/480x854/res/ui.xml +++ b/gui/devices/480x854/res/ui.xml @@ -2042,6 +2042,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2415,6 +2427,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + diff --git a/gui/devices/540x960/res/ui.xml b/gui/devices/540x960/res/ui.xml index bd39a18f2..11c9490a4 100644 --- a/gui/devices/540x960/res/ui.xml +++ b/gui/devices/540x960/res/ui.xml @@ -2043,6 +2043,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2416,6 +2428,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + diff --git a/gui/devices/720x1280/res/ui.xml b/gui/devices/720x1280/res/ui.xml index c9e68629a..157548564 100644 --- a/gui/devices/720x1280/res/ui.xml +++ b/gui/devices/720x1280/res/ui.xml @@ -2056,6 +2056,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2429,6 +2441,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + diff --git a/gui/devices/800x1280/res/ui.xml b/gui/devices/800x1280/res/ui.xml index b4cbb508e..abd62de8e 100755 --- a/gui/devices/800x1280/res/ui.xml +++ b/gui/devices/800x1280/res/ui.xml @@ -2044,6 +2044,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2417,6 +2429,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + diff --git a/gui/devices/800x480/res/ui.xml b/gui/devices/800x480/res/ui.xml index 272bf6491..6a2c08fa9 100755 --- a/gui/devices/800x480/res/ui.xml +++ b/gui/devices/800x480/res/ui.xml @@ -2312,6 +2312,18 @@ %tw_operation% %tw_partition% + + + + %tw_file_progress% + + + + + + %tw_size_progress% + + @@ -2687,6 +2699,12 @@ %tw_operation% %tw_partition% + + + + %tw_size_progress% + + diff --git a/infomanager.cpp b/infomanager.cpp new file mode 100644 index 000000000..080fe1d28 --- /dev/null +++ b/infomanager.cpp @@ -0,0 +1,206 @@ +/* + Copyright 2012 bigbiff/Dees_Troy TeamWin + This file is part of TWRP/TeamWin Recovery Project. + + TWRP is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TWRP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TWRP. If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "infomanager.hpp" +#include "twcommon.h" +#include "partitions.hpp" + +using namespace std; + +InfoManager::InfoManager(const string filename) { + File = filename; +} + +InfoManager::~InfoManager(void) { + mValues.clear(); +} + +int InfoManager::LoadValues(void) { + string str; + + // Read in the file, if possible + FILE* in = fopen(File.c_str(), "rb"); + if (!in) { + LOGINFO("InfoManager file '%s' not found.\n", File.c_str()); + return -1; + } else { + LOGINFO("InfoManager loading from '%s'.\n", File.c_str()); + } + + while (!feof(in)) { + string Name; + string Value; + unsigned short length; + char array[512]; + + if (fread(&length, 1, sizeof(unsigned short), in) != sizeof(unsigned short)) goto error; + if (length >= 512) goto error; + if (fread(array, 1, length, in) != length) goto error; + Name = array; + + if (fread(&length, 1, sizeof(unsigned short), in) != sizeof(unsigned short)) goto error; + if (length >= 512) goto error; + if (fread(array, 1, length, in) != length) goto error; + Value = array; + + map::iterator pos; + + pos = mValues.find(Name); + if (pos != mValues.end()) { + pos->second = Value; + } else { + mValues.insert(make_pair(Name, Value)); + } + } +error: + fclose(in); + return 0; +} + +int InfoManager::SaveValues(void) { + if (File.empty()) + return -1; + + PartitionManager.Mount_By_Path(File, true); +LOGINFO("InfoManager saving '%s'\n", File.c_str()); + FILE* out = fopen(File.c_str(), "wb"); + if (!out) + return -1; + + map::iterator iter; + for (iter = mValues.begin(); iter != mValues.end(); ++iter) { + unsigned short length = (unsigned short) iter->first.length() + 1; + fwrite(&length, 1, sizeof(unsigned short), out); + fwrite(iter->first.c_str(), 1, length, out); + length = (unsigned short) iter->second.length() + 1; + fwrite(&length, 1, sizeof(unsigned short), out); + fwrite(iter->second.c_str(), 1, length, out); + } + fclose(out); + return 0; +} + +int InfoManager::GetValue(const string varName, string& value) { + string localStr = varName; + + map::iterator pos; + pos = mValues.find(localStr); + if (pos == mValues.end()) + return -1; + + value = pos->second; + return 0; +} + +int InfoManager::GetValue(const string varName, int& value) { + string data; + + if (GetValue(varName,data) != 0) + return -1; + + value = atoi(data.c_str()); + return 0; +} + +int InfoManager::GetValue(const string varName, float& value) { + string data; + + if (GetValue(varName,data) != 0) + return -1; + + value = atof(data.c_str()); + return 0; +} + +unsigned long long InfoManager::GetValue(const string varName, unsigned long long& value) { + string data; + + if (GetValue(varName,data) != 0) + return -1; + + value = strtoull(data.c_str(), NULL, 10); + return 0; +} + +// This function will return an empty string if the value doesn't exist +string InfoManager::GetStrValue(const string varName) { + string retVal; + + GetValue(varName, retVal); + return retVal; +} + +// This function will return 0 if the value doesn't exist +int InfoManager::GetIntValue(const string varName) { + string retVal; + GetValue(varName, retVal); + return atoi(retVal.c_str()); +} + +int InfoManager::SetValue(const string varName, string value) { + // Don't allow empty values or numerical starting values + if (varName.empty() || (varName[0] >= '0' && varName[0] <= '9')) + return -1; + + map::iterator pos; + pos = mValues.find(varName); + if (pos == mValues.end()) + mValues.insert(make_pair(varName, value)); + else + pos->second = value; + + return 0; +} + +int InfoManager::SetValue(const string varName, int value) { + ostringstream valStr; + valStr << value; + return SetValue(varName, valStr.str()); +} + +int InfoManager::SetValue(const string varName, float value) { + ostringstream valStr; + valStr << value; + return SetValue(varName, valStr.str()); +} + +int InfoManager::SetValue(const string varName, unsigned long long value) { + ostringstream valStr; + valStr << value; + return SetValue(varName, valStr.str()); +} diff --git a/infomanager.hpp b/infomanager.hpp new file mode 100644 index 000000000..de8aef423 --- /dev/null +++ b/infomanager.hpp @@ -0,0 +1,58 @@ +/* + Copyright 2012 bigbiff/Dees_Troy TeamWin + This file is part of TWRP/TeamWin Recovery Project. + + TWRP is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TWRP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TWRP. If not, see . +*/ + +#ifndef _INFOMANAGER_HPP_HEADER +#define _INFOMANAGER_HPP_HEADER + +#include +#include +#include + +using namespace std; + +class InfoManager +{ +public: + InfoManager(const string filename); + virtual ~InfoManager(); + int LoadValues(); + int SaveValues(); + + // Core get routines + int GetValue(const string varName, string& value); + int GetValue(const string varName, int& value); + int GetValue(const string varName, float& value); + unsigned long long GetValue(const string varName, unsigned long long& value); + + string GetStrValue(const string varName); + int GetIntValue(const string varName); + + // Core set routines + int SetValue(const string varName, string value); + int SetValue(const string varName, int value); + int SetValue(const string varName, float value); + int SetValue(const string varName, unsigned long long value); + +private: + string File; + map mValues; + +}; + +#endif // _DATAMANAGER_HPP_HEADER + diff --git a/libtar/extract.c b/libtar/extract.c index 4526c98ee..e605aca43 100644 --- a/libtar/extract.c +++ b/libtar/extract.c @@ -94,7 +94,7 @@ tar_set_file_perms(TAR *t, char *realname) /* switchboard */ int -tar_extract_file(TAR *t, char *realname, char *prefix) +tar_extract_file(TAR *t, char *realname, char *prefix, const int *progress_fd) { int i; char *lnp; @@ -141,7 +141,7 @@ tar_extract_file(TAR *t, char *realname, char *prefix) } else /* if (TH_ISREG(t)) */ { printf("reg\n"); - i = tar_extract_regfile(t, realname); + i = tar_extract_regfile(t, realname, progress_fd); } if (i != 0) { @@ -189,7 +189,7 @@ tar_extract_file(TAR *t, char *realname, char *prefix) /* extract regular file */ int -tar_extract_regfile(TAR *t, char *realname) +tar_extract_regfile(TAR *t, char *realname, const int *progress_fd) { //mode_t mode; size_t size; @@ -285,6 +285,11 @@ tar_extract_regfile(TAR *t, char *realname) printf("### done extracting %s\n", filename); #endif + if (*progress_fd != 0) { + unsigned long long file_size = (unsigned long long)(size); + write(*progress_fd, &file_size, sizeof(file_size)); + } + return 0; } diff --git a/libtar/libtar.h b/libtar/libtar.h index 91523d043..e3154ae90 100644 --- a/libtar/libtar.h +++ b/libtar/libtar.h @@ -226,7 +226,7 @@ void th_finish(TAR *t); /***** extract.c ***********************************************************/ /* sequentially extract next file from t */ -int tar_extract_file(TAR *t, char *realname, char *prefix); +int tar_extract_file(TAR *t, char *realname, char *prefix, const int *progress_fd); /* extract different file types */ int tar_extract_dir(TAR *t, char *realname); @@ -237,7 +237,7 @@ int tar_extract_blockdev(TAR *t, char *realname); int tar_extract_fifo(TAR *t, char *realname); /* for regfiles, we need to extract the content blocks as well */ -int tar_extract_regfile(TAR *t, char *realname); +int tar_extract_regfile(TAR *t, char *realname, const int *progress_fd); int tar_skip_regfile(TAR *t); @@ -294,7 +294,7 @@ void int_to_oct_nonull(int num, char *oct, size_t octlen); /* extract groups of files */ int tar_extract_glob(TAR *t, char *globname, char *prefix); -int tar_extract_all(TAR *t, char *prefix); +int tar_extract_all(TAR *t, char *prefix, const int *progress_fd); /* add a whole tree of files */ int tar_append_tree(TAR *t, char *realdir, char *savedir, char *exclude); diff --git a/libtar/wrapper.c b/libtar/wrapper.c index 708c845b9..82f045f7d 100644 --- a/libtar/wrapper.c +++ b/libtar/wrapper.c @@ -27,7 +27,7 @@ tar_extract_glob(TAR *t, char *globname, char *prefix) { char *filename; char buf[MAXPATHLEN]; - int i; + int i, fd = 0; while ((i = th_read(t)) == 0) { @@ -44,7 +44,7 @@ tar_extract_glob(TAR *t, char *globname, char *prefix) snprintf(buf, sizeof(buf), "%s/%s", prefix, filename); else strlcpy(buf, filename, sizeof(buf)); - if (tar_extract_file(t, filename, prefix) != 0) + if (tar_extract_file(t, filename, prefix, &fd) != 0) return -1; } @@ -53,7 +53,7 @@ tar_extract_glob(TAR *t, char *globname, char *prefix) int -tar_extract_all(TAR *t, char *prefix) +tar_extract_all(TAR *t, char *prefix, const int *progress_fd) { char *filename; char buf[MAXPATHLEN]; @@ -80,7 +80,7 @@ tar_extract_all(TAR *t, char *prefix) "\"%s\")\n", buf); #endif printf("item name: '%s'\n", filename); - if (tar_extract_file(t, buf, prefix) != 0) + if (tar_extract_file(t, buf, prefix, progress_fd) != 0) return -1; } return (i == 1 ? 0 : -1); diff --git a/partition.cpp b/partition.cpp index 37654311b..1a62bbae8 100644 --- a/partition.cpp +++ b/partition.cpp @@ -41,6 +41,7 @@ #include "twrpTar.hpp" #include "twrpDU.hpp" #include "fixPermissions.hpp" +#include "infomanager.hpp" extern "C" { #include "mtdutils/mtdutils.h" #include "mtdutils/mounts.h" @@ -1284,9 +1285,9 @@ bool TWPartition::Repair() { return false; } -bool TWPartition::Backup(string backup_folder) { +bool TWPartition::Backup(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size) { if (Backup_Method == FILES) - return Backup_Tar(backup_folder); + return Backup_Tar(backup_folder, overall_size, other_backups_size); else if (Backup_Method == DD) return Backup_DD(backup_folder); else if (Backup_Method == FLASH_UTILS) @@ -1343,13 +1344,32 @@ bool TWPartition::Check_MD5(string restore_folder) { return false; } -bool TWPartition::Restore(string restore_folder) { - size_t first_period, second_period; +bool TWPartition::Restore(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size) { string Restore_File_System; TWFunc::GUI_Operation_Text(TW_RESTORE_TEXT, Display_Name, "Restoring"); LOGINFO("Restore filename is: %s\n", Backup_FileName.c_str()); + Restore_File_System = Get_Restore_File_System(restore_folder); + + if (Is_File_System(Restore_File_System)) + return Restore_Tar(restore_folder, Restore_File_System, total_restore_size, already_restored_size); + else if (Is_Image(Restore_File_System)) { + *already_restored_size += TWFunc::Get_File_Size(Backup_Name); + if (Restore_File_System == "emmc") + return Restore_DD(restore_folder, total_restore_size, already_restored_size); + else if (Restore_File_System == "mtd" || Restore_File_System == "bml") + return Restore_Flash_Image(restore_folder, total_restore_size, already_restored_size); + } + + LOGERR("Unknown restore method for '%s'\n", Mount_Point.c_str()); + return false; +} + +string TWPartition::Get_Restore_File_System(string restore_folder) { + size_t first_period, second_period; + string Restore_File_System; + // Parse backup filename to extract the file system before wiping first_period = Backup_FileName.find("."); if (first_period == string::npos) { @@ -1364,18 +1384,7 @@ bool TWPartition::Restore(string restore_folder) { } Restore_File_System.resize(second_period); LOGINFO("Restore file system is: '%s'.\n", Restore_File_System.c_str()); - - if (Is_File_System(Restore_File_System)) - return Restore_Tar(restore_folder, Restore_File_System); - else if (Is_Image(Restore_File_System)) { - if (Restore_File_System == "emmc") - return Restore_DD(restore_folder); - else if (Restore_File_System == "mtd" || Restore_File_System == "bml") - return Restore_Flash_Image(restore_folder); - } - - LOGERR("Unknown restore method for '%s'\n", Mount_Point.c_str()); - return false; + return Restore_File_System; } string TWPartition::Backup_Method_By_Name() { @@ -1709,7 +1718,7 @@ bool TWPartition::Wipe_Data_Without_Wiping_Media() { #endif // ifdef TW_OEM_BUILD } -bool TWPartition::Backup_Tar(string backup_folder) { +bool TWPartition::Backup_Tar(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size) { char back_name[255], split_index[5]; string Full_FileName, Split_FileName, Tar_Args, Command; int use_compression, use_encryption = 0, index, backup_count; @@ -1749,7 +1758,9 @@ bool TWPartition::Backup_Tar(string backup_folder) { tar.setdir(Backup_Path); tar.setfn(Full_FileName); tar.setsize(Backup_Size); - if (tar.createTarFork() != 0) + tar.partition_name = Backup_Name; + tar.backup_folder = backup_folder; + if (tar.createTarFork(overall_size, other_backups_size) != 0) return false; return true; } @@ -1804,7 +1815,40 @@ bool TWPartition::Backup_Dump_Image(string backup_folder) { return true; } -bool TWPartition::Restore_Tar(string restore_folder, string Restore_File_System) { +unsigned long long TWPartition::Get_Restore_Size(string restore_folder) { + InfoManager restore_info(restore_folder + "/" + Backup_Name + ".info"); + if (restore_info.LoadValues() == 0) { + if (restore_info.GetValue("backup_size", Restore_Size) == 0) { + LOGINFO("Read info file, restore size is %llu\n", Restore_Size); + return Restore_Size; + } + } + string Full_FileName, Restore_File_System = Get_Restore_File_System(restore_folder); + + Full_FileName = restore_folder + "/" + Backup_FileName; + + if (Is_Image(Restore_File_System)) { + Restore_Size = TWFunc::Get_File_Size(Full_FileName); + return Restore_Size; + } + + twrpTar tar; + tar.setdir(Backup_Path); + tar.setfn(Full_FileName); + tar.backup_name = Backup_Name; +#ifndef TW_EXCLUDE_ENCRYPTED_BACKUPS + string Password; + DataManager::GetValue("tw_restore_password", Password); + if (!Password.empty()) + tar.setpassword(Password); +#endif + tar.partition_name = Backup_Name; + tar.backup_folder = restore_folder; + Restore_Size = tar.get_size(); + return Restore_Size; +} + +bool TWPartition::Restore_Tar(string restore_folder, string Restore_File_System, const unsigned long long *total_restore_size, unsigned long long *already_restored_size) { string Full_FileName, Command; int index = 0; char split_index[5]; @@ -1842,7 +1886,7 @@ bool TWPartition::Restore_Tar(string restore_folder, string Restore_File_System) if (!Password.empty()) tar.setpassword(Password); #endif - if (tar.extractTarFork() != 0) + if (tar.extractTarFork(total_restore_size, already_restored_size) != 0) ret = false; else ret = true; @@ -1868,8 +1912,10 @@ bool TWPartition::Restore_Tar(string restore_folder, string Restore_File_System) return ret; } -bool TWPartition::Restore_DD(string restore_folder) { +bool TWPartition::Restore_DD(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size) { string Full_FileName, Command; + double display_percent, progress_percent; + char size_progress[1024]; TWFunc::GUI_Operation_Text(TW_RESTORE_TEXT, Display_Name, "Restoring"); Full_FileName = restore_folder + "/" + Backup_FileName; @@ -1890,11 +1936,19 @@ bool TWPartition::Restore_DD(string restore_folder) { Command = "dd bs=4096 if='" + Full_FileName + "' of=" + Actual_Block_Device; LOGINFO("Restore command: '%s'\n", Command.c_str()); TWFunc::Exec_Cmd(Command); + display_percent = (double)(Restore_Size + *already_restored_size) / (double)(*total_restore_size) * 100; + sprintf(size_progress, "%lluMB of %lluMB, %i%%", (Restore_Size + *already_restored_size) / 1048576, *total_restore_size / 1048576, (int)(display_percent)); + DataManager::SetValue("tw_size_progress", size_progress); + progress_percent = (display_percent / 100); + DataManager::SetProgress((float)(progress_percent)); + *already_restored_size += Restore_Size; return true; } -bool TWPartition::Restore_Flash_Image(string restore_folder) { +bool TWPartition::Restore_Flash_Image(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size) { string Full_FileName, Command; + double display_percent, progress_percent; + char size_progress[1024]; gui_print("Restoring %s...\n", Display_Name.c_str()); Full_FileName = restore_folder + "/" + Backup_FileName; @@ -1905,6 +1959,12 @@ bool TWPartition::Restore_Flash_Image(string restore_folder) { Command = "flash_image " + MTD_Name + " '" + Full_FileName + "'"; LOGINFO("Restore command: '%s'\n", Command.c_str()); TWFunc::Exec_Cmd(Command); + display_percent = (double)(Restore_Size + *already_restored_size) / (double)(*total_restore_size) * 100; + sprintf(size_progress, "%lluMB of %lluMB, %i%%", (Restore_Size + *already_restored_size) / 1048576, *total_restore_size / 1048576, (int)(display_percent)); + DataManager::SetValue("tw_size_progress", size_progress); + progress_percent = (display_percent / 100); + DataManager::SetProgress((float)(progress_percent)); + *already_restored_size += Restore_Size; return true; } diff --git a/partitionmanager.cpp b/partitionmanager.cpp index df623fa83..de727f4a2 100644 --- a/partitionmanager.cpp +++ b/partitionmanager.cpp @@ -599,6 +599,7 @@ bool TWPartitionManager::Backup_Partition(TWPartition* Part, string Backup_Folde unsigned long total_time, remain_time, section_time; int use_compression, backup_time; float pos; + unsigned long long total_size, current_size; if (Part == NULL) return true; @@ -615,7 +616,10 @@ bool TWPartitionManager::Backup_Partition(TWPartition* Part, string Backup_Folde total_time = (*img_bytes / (unsigned long)img_bps) + (*file_bytes / (unsigned long)file_bps); remain_time = (*img_bytes_remaining / (unsigned long)img_bps) + (*file_bytes_remaining / (unsigned long)file_bps); - pos = (total_time - remain_time) / (float) total_time; + //pos = (total_time - remain_time) / (float) total_time; + total_size = *file_bytes + *img_bytes; + current_size = *file_bytes + *img_bytes - *file_bytes_remaining - *img_bytes_remaining; + pos = ((float)(current_size) / (float)(total_size)); DataManager::SetProgress(pos); LOGINFO("Estimated total time: %lu\nEstimated remaining time: %lu\n", total_time, remain_time); @@ -628,17 +632,20 @@ bool TWPartitionManager::Backup_Partition(TWPartition* Part, string Backup_Folde // Set the position pos = section_time / (float) total_time; - DataManager::ShowProgress(pos, section_time); + //DataManager::ShowProgress(pos, section_time); time(&start); - if (Part->Backup(Backup_Folder)) { + if (Part->Backup(Backup_Folder, &total_size, ¤t_size)) { + current_size += Part->Backup_Size; + pos = (float)((float)(current_size) / (float)(total_size)); + DataManager::SetProgress(pos); if (Part->Has_SubPartition) { std::vector::iterator subpart; for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) { if ((*subpart)->Can_Be_Backed_Up && (*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point) { - if (!(*subpart)->Backup(Backup_Folder)) + if (!(*subpart)->Backup(Backup_Folder, &total_size, ¤t_size)) return false; sync(); sync(); @@ -649,6 +656,9 @@ bool TWPartitionManager::Backup_Partition(TWPartition* Part, string Backup_Folde } else { *img_bytes_remaining -= (*subpart)->Backup_Size; } + current_size += Part->Backup_Size; + pos = (float)(current_size / total_size); + DataManager::SetProgress(pos); } } } @@ -833,18 +843,18 @@ int TWPartitionManager::Run_Backup(void) { return true; } -bool TWPartitionManager::Restore_Partition(TWPartition* Part, string Restore_Name, int partition_count) { +bool TWPartitionManager::Restore_Partition(TWPartition* Part, string Restore_Name, int partition_count, const unsigned long long *total_restore_size, unsigned long long *already_restored_size) { time_t Start, Stop; time(&Start); - DataManager::ShowProgress(1.0 / (float)partition_count, 150); - if (!Part->Restore(Restore_Name)) + //DataManager::ShowProgress(1.0 / (float)partition_count, 150); + if (!Part->Restore(Restore_Name, total_restore_size, already_restored_size)) return false; if (Part->Has_SubPartition) { std::vector::iterator subpart; for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) { if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point) { - if (!(*subpart)->Restore(Restore_Name)) + if (!(*subpart)->Restore(Restore_Name, total_restore_size, already_restored_size)) return false; } } @@ -861,6 +871,7 @@ int TWPartitionManager::Run_Restore(string Restore_Name) { time(&rStart); string Restore_List, restore_path; size_t start_pos = 0, end_pos; + unsigned long long total_restore_size = 0, already_restored_size = 0; gui_print("\n[RESTORE STARTED]\n\n"); gui_print("Restore folder: '%s'\n", Restore_Name.c_str()); @@ -876,6 +887,7 @@ int TWPartitionManager::Run_Restore(string Restore_Name) { } else { gui_print("Skipping MD5 check based on user setting.\n"); } + gui_print("Calculating restore details...\n"); DataManager::GetValue("tw_restore_selected", Restore_List); if (!Restore_List.empty()) { end_pos = Restore_List.find(";", start_pos); @@ -886,6 +898,7 @@ int TWPartitionManager::Run_Restore(string Restore_Name) { partition_count++; if (check_md5 > 0 && !restore_part->Check_MD5(Restore_Name)) return false; + total_restore_size += restore_part->Get_Restore_Size(Restore_Name); if (restore_part->Has_SubPartition) { std::vector::iterator subpart; @@ -893,6 +906,7 @@ int TWPartitionManager::Run_Restore(string Restore_Name) { if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == restore_part->Mount_Point) { if (check_md5 > 0 && !(*subpart)->Check_MD5(Restore_Name)) return false; + total_restore_size += (*subpart)->Get_Restore_Size(Restore_Name); } } } @@ -910,7 +924,9 @@ int TWPartitionManager::Run_Restore(string Restore_Name) { } gui_print("Restoring %i partitions...\n", partition_count); + gui_print("Total restore size is %lluMB\n", total_restore_size / 1048576); DataManager::SetProgress(0.0); + start_pos = 0; if (!Restore_List.empty()) { end_pos = Restore_List.find(";", start_pos); @@ -919,7 +935,7 @@ int TWPartitionManager::Run_Restore(string Restore_Name) { restore_part = Find_Partition_By_Path(restore_path); if (restore_part != NULL) { partition_count++; - if (!Restore_Partition(restore_part, Restore_Name, partition_count)) + if (!Restore_Partition(restore_part, Restore_Name, partition_count, &total_restore_size, &already_restored_size)) return false; } else { LOGERR("Unable to locate '%s' partition for restoring.\n", restore_path.c_str()); @@ -933,6 +949,7 @@ int TWPartitionManager::Run_Restore(string Restore_Name) { UnMount_Main_Partitions(); time(&rStop); gui_print_color("highlight", "[RESTORE COMPLETED IN %d SECONDS]\n\n",(int)difftime(rStop,rStart)); + DataManager::SetValue("tw_file_progress", ""); return true; } diff --git a/partitions.hpp b/partitions.hpp index 73ff1fbc5..0d74315b4 100644 --- a/partitions.hpp +++ b/partitions.hpp @@ -57,9 +57,10 @@ public: bool Wipe_AndSec(); // Wipes android secure bool Can_Repair(); // Checks to see if we have everything needed to be able to repair the current file system bool Repair(); // Repairs the current file system - bool Backup(string backup_folder); // Backs up the partition to the folder specified + bool Backup(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size); // Backs up the partition to the folder specified bool Check_MD5(string restore_folder); // Checks MD5 of a backup - bool Restore(string restore_folder); // Restores the partition using the backup folder provided + bool Restore(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size); // Restores the partition using the backup folder provided + unsigned long long Get_Restore_Size(string restore_folder); // Returns the overall restore size of the backup string Backup_Method_By_Name(); // Returns a string of the backup method for human readable output bool Decrypt(string Password); // Decrypts the partition, return 0 for failure and -1 for success bool Wipe_Encryption(); // Ignores wipe commands for /data/media devices and formats the original block device @@ -94,12 +95,13 @@ private: bool Wipe_RMRF(); // Uses rm -rf to wipe bool Wipe_F2FS(); // Uses mkfs.f2fs to wipe bool Wipe_Data_Without_Wiping_Media(); // Uses rm -rf to wipe but does not wipe /data/media - bool Backup_Tar(string backup_folder); // Backs up using tar for file systems + bool Backup_Tar(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size); // Backs up using tar for file systems bool Backup_DD(string backup_folder); // Backs up using dd for emmc memory types bool Backup_Dump_Image(string backup_folder); // Backs up using dump_image for MTD memory types - bool Restore_Tar(string restore_folder, string Restore_File_System); // Restore using tar for file systems - bool Restore_DD(string restore_folder); // Restore using dd for emmc memory types - bool Restore_Flash_Image(string restore_folder); // Restore using flash_image for MTD memory types + string Get_Restore_File_System(string restore_folder); // Returns the file system that was in place at the time of the backup + bool Restore_Tar(string restore_folder, string Restore_File_System, const unsigned long long *total_restore_size, unsigned long long *already_restored_size); // Restore using tar for file systems + bool Restore_DD(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size); // Restore using dd for emmc memory types + bool Restore_Flash_Image(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size); // Restore using flash_image for MTD memory types bool Get_Size_Via_statfs(bool Display_Error); // Get Partition size, used, and free space using statfs bool Get_Size_Via_df(bool Display_Error); // Get Partition size, used, and free space using df command bool Make_Dir(string Path, bool Display_Error); // Creates a directory if it doesn't already exist @@ -131,6 +133,7 @@ private: unsigned long long Used; // Overall used space unsigned long long Free; // Overall free space unsigned long long Backup_Size; // Backup size -- may be different than used space especially when /data/media is present + unsigned long long Restore_Size; // Restore size of the current restore operation bool Can_Be_Encrypted; // This partition might be encrypted, affects error handling, can only be true if crypto support is compiled in bool Is_Encrypted; // This partition is thought to be encrypted -- it wouldn't mount for some reason, only avialble with crypto support bool Is_Decrypted; // This partition has successfully been decrypted @@ -227,7 +230,7 @@ private: void Setup_Android_Secure_Location(TWPartition* Part); // Sets up .android_secure if needed bool Make_MD5(bool generate_md5, string Backup_Folder, string Backup_Filename); // Generates an MD5 after a backup is made bool Backup_Partition(TWPartition* Part, string Backup_Folder, bool generate_md5, unsigned long long* img_bytes_remaining, unsigned long long* file_bytes_remaining, unsigned long *img_time, unsigned long *file_time, unsigned long long *img_bytes, unsigned long long *file_bytes); - bool Restore_Partition(TWPartition* Part, string Restore_Name, int partition_count); + bool Restore_Partition(TWPartition* Part, string Restore_Name, int partition_count, const unsigned long long *total_restore_size, unsigned long long *already_restored_size); void Output_Partition(TWPartition* Part); TWPartition* Find_Next_Storage(string Path, string Exclude); int Open_Lun_File(string Partition_Path, string Lun_File); diff --git a/twrp-functions.cpp b/twrp-functions.cpp index 2128c9635..db98a363a 100644 --- a/twrp-functions.cpp +++ b/twrp-functions.cpp @@ -299,6 +299,30 @@ std::string TWFunc::Remove_Trailing_Slashes(const std::string& path, bool leaveL return res; } +vector TWFunc::split_string(const string &in, char del, bool skip_empty) { + vector res; + + if (in.empty() || del == '\0') + return res; + + string field; + istringstream f(in); + if (del == '\n') { + while(getline(f, field)) { + if (field.empty() && skip_empty) + continue; + res.push_back(field); + } + } else { + while(getline(f, field, del)) { + if (field.empty() && skip_empty) + continue; + res.push_back(field); + } + } + return res; +} + #ifndef BUILD_TWRPTAR_MAIN // Returns "/path" from a full /path/to/file.name diff --git a/twrp-functions.hpp b/twrp-functions.hpp index ff1176389..284a29783 100644 --- a/twrp-functions.hpp +++ b/twrp-functions.hpp @@ -50,6 +50,7 @@ public: static int Try_Decrypting_File(string fn, string password); // -1 for some error, 0 for failed to decrypt, 1 for decrypted, 3 for decrypted and found gzip format static unsigned long Get_File_Size(string Path); // Returns the size of a file static std::string Remove_Trailing_Slashes(const std::string& path, bool leaveLast = false); // Normalizes the path, e.g /data//media/ -> /data/media + static vector split_string(const string &in, char del, bool skip_empty); #ifndef BUILD_TWRPTAR_MAIN static void install_htc_dumlock(void); // Installs HTC Dumlock diff --git a/twrpTar.cpp b/twrpTar.cpp index 7f00da5c7..28ac91ac1 100644 --- a/twrpTar.cpp +++ b/twrpTar.cpp @@ -40,6 +40,10 @@ extern "C" { #include "twcommon.h" #include "variables.h" #include "twrp-functions.hpp" +#ifndef BUILD_TWRPTAR_MAIN +#include "data.hpp" +#include "infomanager.hpp" +#endif //ndef BUILD_TWRPTAR_MAIN using namespace std; @@ -75,20 +79,35 @@ void twrpTar::setpassword(string pass) { password = pass; } -int twrpTar::createTarFork() { +int twrpTar::createTarFork(const unsigned long long *overall_size, const unsigned long long *other_backups_size) { int status = 0; pid_t pid, rc_pid; + int progress_pipe[2], ret; + + file_count = 0; + + if (pipe(progress_pipe) < 0) { + LOGERR("Error creating progress tracking pipe\n"); + return -1; + } if ((pid = fork()) == -1) { LOGINFO("create tar failed to fork.\n"); + close(progress_pipe[0]); + close(progress_pipe[1]); return -1; } if (pid == 0) { // Child process + + // Child closes input side of progress pipe + close(progress_pipe[0]); + progress_pipe_fd = progress_pipe[1]; + if (use_encryption || userdata_encryption) { LOGINFO("Using encryption\n"); DIR* d; struct dirent* de; - unsigned long long regular_size = 0, encrypt_size = 0, target_size = 0, core_count = 1; + unsigned long long regular_size = 0, encrypt_size = 0, target_size = 0, core_count = 1, total_size; unsigned enc_thread_id = 1, regular_thread_id = 0, i, start_thread_id = 1; int item_len, ret, thread_error = 0; std::vector RegularList; @@ -110,6 +129,7 @@ int twrpTar::createTarFork() { d = opendir(tardir.c_str()); if (d == NULL) { LOGERR("error opening '%s'\n", tardir.c_str()); + close(progress_pipe[1]); _exit(-1); } // Figure out the size of all data to be encrypted and create a list of unencrypted files @@ -121,11 +141,15 @@ int twrpTar::createTarFork() { if (de->d_type == DT_DIR) { item_len = strlen(de->d_name); if (userdata_encryption && ((item_len >= 3 && strncmp(de->d_name, "app", 3) == 0) || (item_len >= 6 && strncmp(de->d_name, "dalvik", 6) == 0))) { - if (Generate_TarList(FileName, &RegularList, &target_size, ®ular_thread_id) < 0) { + ret = Generate_TarList(FileName, &RegularList, &target_size, ®ular_thread_id); + if (ret < 0) { LOGERR("Error in Generate_TarList with regular list!\n"); closedir(d); + close(progress_pipe_fd); + close(progress_pipe[1]); _exit(-1); } + file_count = (unsigned long long)(ret); regular_size += du.Get_Folder_Size(FileName); } else { encrypt_size += du.Get_Folder_Size(FileName); @@ -152,6 +176,7 @@ int twrpTar::createTarFork() { d = opendir(tardir.c_str()); if (d == NULL) { LOGERR("error opening '%s'\n", tardir.c_str()); + close(progress_pipe[1]); _exit(-1); } // Divide up the encrypted file list for threading @@ -166,11 +191,14 @@ int twrpTar::createTarFork() { // Do nothing, we added these to RegularList earlier } else { FileName = tardir + "/" + de->d_name; - if (Generate_TarList(FileName, &EncryptList, &target_size, &enc_thread_id) < 0) { + ret = Generate_TarList(FileName, &EncryptList, &target_size, &enc_thread_id); + if (ret < 0) { LOGERR("Error in Generate_TarList with encrypted list!\n"); closedir(d); + close(progress_pipe[1]); _exit(-1); } + file_count += (unsigned long long)(ret); } } else if (de->d_type == DT_REG || de->d_type == DT_LNK) { stat(FileName.c_str(), &st); @@ -179,17 +207,26 @@ int twrpTar::createTarFork() { TarItem.fn = FileName; TarItem.thread_id = enc_thread_id; EncryptList.push_back(TarItem); + file_count++; } } closedir(d); if (enc_thread_id != core_count) { LOGERR("Error dividing up threads for encryption, %i threads for %i cores!\n", enc_thread_id, core_count); - if (enc_thread_id > core_count) + if (enc_thread_id > core_count) { + close(progress_pipe[1]); _exit(-1); - else + } else { LOGERR("Continuining anyway."); + } } + // Send file count to parent + write(progress_pipe_fd, &file_count, sizeof(file_count)); + // Send backup size to parent + total_size = regular_size + encrypt_size; + write(progress_pipe_fd, &total_size, sizeof(total_size)); + if (userdata_encryption) { // Create a backup of unencrypted data reg.setfn(tarfn); @@ -198,23 +235,28 @@ int twrpTar::createTarFork() { reg.use_encryption = 0; reg.use_compression = use_compression; reg.split_archives = 1; + reg.progress_pipe_fd = progress_pipe_fd; LOGINFO("Creating unencrypted backup...\n"); if (createList((void*)®) != 0) { LOGERR("Error creating unencrypted backup.\n"); + close(progress_pipe[1]); _exit(-1); } } if (pthread_attr_init(&tattr)) { LOGERR("Unable to pthread_attr_init\n"); + close(progress_pipe[1]); _exit(-1); } if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) { LOGERR("Error setting pthread_attr_setdetachstate\n"); + close(progress_pipe[1]); _exit(-1); } if (pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM)) { LOGERR("Error setting pthread_attr_setscope\n"); + close(progress_pipe[1]); _exit(-1); } /*if (pthread_attr_setstacksize(&tattr, 524288)) { @@ -232,12 +274,14 @@ int twrpTar::createTarFork() { enc[i].setpassword(password); enc[i].use_compression = use_compression; enc[i].split_archives = 1; + enc[i].progress_pipe_fd = progress_pipe_fd; LOGINFO("Start encryption thread %i\n", i); ret = pthread_create(&enc_thread[i], &tattr, createList, (void*)&enc[i]); if (ret) { - LOGINFO("Unable to create %i thread for encryption! %i\nContinuing in same thread (backup will be slower).", i, ret); + LOGINFO("Unable to create %i thread for encryption! %i\nContinuing in same thread (backup will be slower).\n", i, ret); if (createList((void*)&enc[i]) != 0) { LOGERR("Error creating encrypted backup %i.\n", i); + close(progress_pipe[1]); _exit(-1); } else { enc[i].thread_id = i + 1; @@ -252,6 +296,7 @@ int twrpTar::createTarFork() { if (enc[i].thread_id == i) { if (pthread_join(enc_thread[i], &thread_return)) { LOGERR("Error joining thread %i\n", i); + close(progress_pipe[1]); _exit(-1); } else { LOGINFO("Joined thread %i.\n", i); @@ -259,6 +304,7 @@ int twrpTar::createTarFork() { if (ret != 0) { thread_error = 1; LOGERR("Thread %i returned an error %i.\n", i, ret); + close(progress_pipe[1]); _exit(-1); } } @@ -268,21 +314,28 @@ int twrpTar::createTarFork() { } if (thread_error) { LOGERR("Error returned by one or more threads.\n"); + close(progress_pipe[1]); _exit(-1); } LOGINFO("Finished encrypted backup.\n"); + close(progress_pipe[1]); _exit(0); } else { + // Not encrypted std::vector FileList; unsigned thread_id = 0; unsigned long long target_size = 0; twrpTar reg; + int ret; // Generate list of files to back up - if (Generate_TarList(tardir, &FileList, &target_size, &thread_id) < 0) { + ret = Generate_TarList(tardir, &FileList, &target_size, &thread_id); + if (ret < 0) { LOGERR("Error in Generate_TarList!\n"); + close(progress_pipe[1]); _exit(-1); } + file_count = (unsigned long long)(ret); // Create a backup reg.setfn(tarfn); reg.ItemList = &FileList; @@ -290,6 +343,7 @@ int twrpTar::createTarFork() { reg.use_encryption = 0; reg.use_compression = use_compression; reg.setsize(Total_Backup_Size); + reg.progress_pipe_fd = progress_pipe_fd; if (Total_Backup_Size > MAX_ARCHIVE_SIZE) { gui_print("Breaking backup file into multiple archives...\n"); reg.split_archives = 1; @@ -297,28 +351,96 @@ int twrpTar::createTarFork() { reg.split_archives = 0; } LOGINFO("Creating backup...\n"); + write(progress_pipe_fd, &file_count, sizeof(file_count)); + write(progress_pipe_fd, &Total_Backup_Size, sizeof(Total_Backup_Size)); if (createList((void*)®) != 0) { LOGERR("Error creating backup.\n"); + close(progress_pipe[1]); _exit(-1); } + close(progress_pipe[1]); _exit(0); } } else { + // Parent side + unsigned long long fs, size_backup, files_backup, total_backup_size; + int first_data = 0; + double display_percent, progress_percent; + char file_progress[1024]; + char size_progress[1024]; + files_backup = 0; + size_backup = 0; + + // Parent closes output side + close(progress_pipe[1]); + + // Read progress data from children + while (read(progress_pipe[0], &fs, sizeof(fs)) > 0) { + if (first_data == 0) { + // First incoming data is the file count + file_count = fs; + if (file_count == 0) file_count = 1; // prevent division by 0 below + first_data = 1; + } else if (first_data == 1) { + // Second incoming data is total size + total_backup_size = fs; + first_data = 2; + } else { + files_backup++; + size_backup += fs; + display_percent = (double)(files_backup) / (double)(file_count) * 100; + sprintf(file_progress, "%llu of %llu files, %i%%", files_backup, file_count, (int)(display_percent)); +#ifndef BUILD_TWRPTAR_MAIN + DataManager::SetValue("tw_file_progress", file_progress); + display_percent = (double)(size_backup + *other_backups_size) / (double)(*overall_size) * 100; + sprintf(size_progress, "%lluMB of %lluMB, %i%%", (size_backup + *other_backups_size) / 1048576, *overall_size / 1048576, (int)(display_percent)); + DataManager::SetValue("tw_size_progress", size_progress); + progress_percent = (display_percent / 100); + DataManager::SetProgress((float)(progress_percent)); +#endif //ndef BUILD_TWRPTAR_MAIN + } + } + close(progress_pipe[0]); +#ifndef BUILD_TWRPTAR_MAIN + DataManager::SetValue("tw_file_progress", ""); + DataManager::SetValue("tw_size_progress", ""); + + InfoManager backup_info(backup_folder + partition_name + ".info"); + backup_info.SetValue("backup_size", size_backup); + if (use_compression && use_encryption) + backup_info.SetValue("backup_type", 3); + else if (use_encryption) + backup_info.SetValue("backup_type", 2); + else if (use_compression) + backup_info.SetValue("backup_type", 1); + else + backup_info.SetValue("backup_type", 0); + backup_info.SetValue("file_count", files_backup); + backup_info.SaveValues(); +#endif //ndef BUILD_TWRPTAR_MAIN if (TWFunc::Wait_For_Child(pid, &status, "createTarFork()") != 0) return -1; } return 0; } -int twrpTar::extractTarFork() { +int twrpTar::extractTarFork(const unsigned long long *overall_size, unsigned long long *other_backups_size) { int status = 0; pid_t pid, rc_pid; + int progress_pipe[2], ret; + + if (pipe(progress_pipe) < 0) { + LOGERR("Error creating progress tracking pipe\n"); + return -1; + } pid = fork(); if (pid >= 0) // fork was successful { if (pid == 0) // child process { + close(progress_pipe[0]); + progress_pipe_fd = progress_pipe[1]; if (TWFunc::Path_Exists(tarfn)) { LOGINFO("Single archive\n"); if (extract() != 0) @@ -340,14 +462,17 @@ int twrpTar::extractTarFork() { tarfn += "000"; if (!TWFunc::Path_Exists(tarfn)) { LOGERR("Unable to locate '%s' or '%s'\n", basefn.c_str(), tarfn.c_str()); + close(progress_pipe_fd); _exit(-1); } if (TWFunc::Get_File_Type(tarfn) != 2) { LOGINFO("First tar file '%s' not encrypted\n", tarfn.c_str()); tars[0].basefn = basefn; tars[0].thread_id = 0; + tars[0].progress_pipe_fd = progress_pipe_fd; if (extractMulti((void*)&tars[0]) != 0) { LOGERR("Error extracting split archive.\n"); + close(progress_pipe_fd); _exit(-1); } } else { @@ -356,18 +481,22 @@ int twrpTar::extractTarFork() { // Start threading encrypted restores if (pthread_attr_init(&tattr)) { LOGERR("Unable to pthread_attr_init\n"); + close(progress_pipe_fd); _exit(-1); } if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) { LOGERR("Error setting pthread_attr_setdetachstate\n"); + close(progress_pipe_fd); _exit(-1); } if (pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM)) { LOGERR("Error setting pthread_attr_setscope\n"); + close(progress_pipe_fd); _exit(-1); } /*if (pthread_attr_setstacksize(&tattr, 524288)) { LOGERR("Error setting pthread_attr_setstacksize\n"); + close(progress_pipe_fd); _exit(-1); }*/ for (i = start_thread_id; i < 9; i++) { @@ -377,12 +506,14 @@ int twrpTar::extractTarFork() { tars[i].basefn = basefn; tars[i].setpassword(password); tars[i].thread_id = i; + tars[i].progress_pipe_fd = progress_pipe_fd; LOGINFO("Creating extract thread ID %i\n", i); ret = pthread_create(&tar_thread[i], &tattr, extractMulti, (void*)&tars[i]); if (ret) { - LOGINFO("Unable to create %i thread for extraction! %i\nContinuing in same thread (restore will be slower).", i, ret); + LOGINFO("Unable to create %i thread for extraction! %i\nContinuing in same thread (restore will be slower).\n", i, ret); if (extractMulti((void*)&tars[i]) != 0) { LOGERR("Error extracting backup in thread %i.\n", i); + close(progress_pipe_fd); _exit(-1); } else { tars[i].thread_id = i + 1; @@ -397,6 +528,7 @@ int twrpTar::extractTarFork() { if (tars[i].thread_id == i) { if (pthread_join(tar_thread[i], &thread_return)) { LOGERR("Error joining thread %i\n", i); + close(progress_pipe_fd); _exit(-1); } else { LOGINFO("Joined thread %i.\n", i); @@ -404,6 +536,7 @@ int twrpTar::extractTarFork() { if (ret != 0) { thread_error = 1; LOGERR("Thread %i returned an error %i.\n", i, ret); + close(progress_pipe_fd); _exit(-1); } } @@ -413,20 +546,49 @@ int twrpTar::extractTarFork() { } if (thread_error) { LOGERR("Error returned by one or more threads.\n"); + close(progress_pipe_fd); _exit(-1); } - LOGINFO("Finished encrypted backup.\n"); + LOGINFO("Finished encrypted restore.\n"); + close(progress_pipe_fd); _exit(0); } } else // parent process { + unsigned long long fs, size_backup; + double display_percent, progress_percent; + char size_progress[1024]; + size_backup = 0; + + // Parent closes output side + close(progress_pipe[1]); + + // Read progress data from children + while (read(progress_pipe[0], &fs, sizeof(fs)) > 0) { + size_backup += fs; + display_percent = (double)(size_backup + *other_backups_size) / (double)(*overall_size) * 100; + sprintf(size_progress, "%lluMB of %lluMB, %i%%", (size_backup + *other_backups_size) / 1048576, *overall_size / 1048576, (int)(display_percent)); + progress_percent = (display_percent / 100); +#ifndef BUILD_TWRPTAR_MAIN + DataManager::SetValue("tw_size_progress", size_progress); + DataManager::SetProgress((float)(progress_percent)); +#endif //ndef BUILD_TWRPTAR_MAIN + } + close(progress_pipe[0]); +#ifndef BUILD_TWRPTAR_MAIN + DataManager::SetValue("tw_file_progress", ""); +#endif //ndef BUILD_TWRPTAR_MAIN + *other_backups_size += size_backup; + if (TWFunc::Wait_For_Child(pid, &status, "extractTarFork()") != 0) return -1; } } else // fork has failed { + close(progress_pipe[0]); + close(progress_pipe[1]); LOGINFO("extract tar failed to fork.\n"); return -1; } @@ -440,6 +602,8 @@ int twrpTar::Generate_TarList(string Path, std::vector *TarList, string FileName; struct TarListStruct TarItem; string::size_type i; + int ret, file_count; + file_count = 0; d = opendir(Path.c_str()); if (d == NULL) { @@ -456,13 +620,17 @@ int twrpTar::Generate_TarList(string Path, std::vector *TarList, TarItem.thread_id = *thread_id; if (de->d_type == DT_DIR) { TarList->push_back(TarItem); - if (Generate_TarList(FileName, TarList, Target_Size, thread_id) < 0) + ret = Generate_TarList(FileName, TarList, Target_Size, thread_id); + if (ret < 0) return -1; + file_count += ret; } else if (de->d_type == DT_REG || de->d_type == DT_LNK) { stat(FileName.c_str(), &st); TarList->push_back(TarItem); - if (de->d_type == DT_REG) + if (de->d_type == DT_REG) { + file_count++; Archive_Current_Size += st.st_size; + } if (Archive_Current_Size != 0 && *Target_Size != 0 && Archive_Current_Size > *Target_Size) { *thread_id = *thread_id + 1; Archive_Current_Size = 0; @@ -470,14 +638,14 @@ int twrpTar::Generate_TarList(string Path, std::vector *TarList, } } closedir(d); - return 0; + return file_count; } int twrpTar::extractTar() { char* charRootDir = (char*) tardir.c_str(); if (openTar() == -1) return -1; - if (tar_extract_all(t, charRootDir) != 0) { + if (tar_extract_all(t, charRootDir, &progress_pipe_fd) != 0) { LOGERR("Unable to extract tar archive '%s'\n", tarfn.c_str()); return -1; } @@ -525,6 +693,7 @@ int twrpTar::tarList(std::vector *TarList, unsigned thread_id) { string temp; char actual_filename[PATH_MAX]; char *ptr; + unsigned long long fs; if (split_archives) { basefn = tarfn; @@ -547,7 +716,8 @@ int twrpTar::tarList(std::vector *TarList, unsigned thread_id) { strcpy(buf, TarList->at(i).fn.c_str()); lstat(buf, &st); if (S_ISREG(st.st_mode)) { // item is a regular file - if (split_archives && Archive_Current_Size + (unsigned long long)(st.st_size) > MAX_ARCHIVE_SIZE) { + fs = (unsigned long long)(st.st_size); + if (split_archives && Archive_Current_Size + fs > MAX_ARCHIVE_SIZE) { if (closeTar() != 0) { LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id); return -3; @@ -566,7 +736,8 @@ int twrpTar::tarList(std::vector *TarList, unsigned thread_id) { } Archive_Current_Size = 0; } - Archive_Current_Size += (unsigned long long)(st.st_size); + Archive_Current_Size += fs; + write(progress_pipe_fd, &fs, sizeof(fs)); } LOGINFO("addFile '%s' including root: %i\n", buf, include_root_dir); if (addFile(buf, include_root_dir) != 0) { @@ -1106,6 +1277,116 @@ int twrpTar::entryExists(string entry) { return ret; } +unsigned long long twrpTar::get_size() { + if (TWFunc::Path_Exists(tarfn)) { + LOGINFO("Single archive\n"); + int type = 0; + return uncompressedSize(tarfn, &type); + } else { + LOGINFO("Multiple archives\n"); + string temp; + char actual_filename[255]; + int archive_count = 0, i, type = 0, temp_type = 0; + unsigned long long total_restore_size = 0; + + basefn = tarfn; + temp = basefn + "%i%02i"; + tarfn += "000"; + thread_id = 0; + sprintf(actual_filename, temp.c_str(), thread_id, archive_count); + if (!TWFunc::Path_Exists(actual_filename)) { + LOGERR("Unable to locate '%s' or '%s'\n", basefn.c_str(), tarfn.c_str()); + return 0; + } + for (i = 0; i < 9; i++) { + archive_count = 0; + sprintf(actual_filename, temp.c_str(), i, archive_count); + while (TWFunc::Path_Exists(actual_filename)) { + total_restore_size += uncompressedSize(actual_filename, &temp_type); + if (temp_type > type) + type = temp_type; + archive_count++; + if (archive_count > 99) + break; + sprintf(actual_filename, temp.c_str(), i, archive_count); + } + } +#ifndef BUILD_TWRPTAR_MAIN + InfoManager backup_info(backup_folder + "/" + partition_name + ".info"); + backup_info.SetValue("backup_size", total_restore_size); + backup_info.SetValue("backup_type", type); + backup_info.SaveValues(); +#endif //ndef BUILD_TWRPTAR_MAIN + return total_restore_size; + } + return 0; +} + +unsigned long long twrpTar::uncompressedSize(string filename, int *archive_type) { + int type = 0; + unsigned long long total_size = 0; + string Tar, Command, result; + vector split; + + Tar = TWFunc::Get_Filename(filename); + type = TWFunc::Get_File_Type(filename); + if (type == 0) { + total_size = TWFunc::Get_File_Size(filename); + *archive_type = 0; + } else if (type == 1) { + // Compressed + Command = "pigz -l '" + filename + "'"; + /* if we set Command = "pigz -l " + tarfn + " | sed '1d' | cut -f5 -d' '"; + we get the uncompressed size at once. */ + TWFunc::Exec_Cmd(Command, result); + if (!result.empty()) { + /* Expected output: + compressed original reduced name + 95855838 179403776 -1.3% data.yaffs2.win + ^ + split[5] + */ + split = TWFunc::split_string(result, ' ', true); + if (split.size() > 4) + total_size = atoi(split[5].c_str()); + } + *archive_type = 1; + } else if (type == 2) { + // File is encrypted and may be compressed + int ret = TWFunc::Try_Decrypting_File(filename, password); + *archive_type = 2; + if (ret < 1) { + LOGERR("Failed to decrypt tar file '%s'\n", filename.c_str()); + total_size = TWFunc::Get_File_Size(filename); + } else if (ret == 1) { + LOGERR("Decrypted file is not in tar format.\n"); + total_size = TWFunc::Get_File_Size(filename); + } else if (ret == 3) { + *archive_type = 3; + Command = "openaes dec --key \"" + password + "\" --in '" + filename + "' | pigz -l"; + /* if we set Command = "pigz -l " + tarfn + " | sed '1d' | cut -f5 -d' '"; + we get the uncompressed size at once. */ + TWFunc::Exec_Cmd(Command, result); + if (!result.empty()) { + LOGINFO("result was: '%s'\n", result.c_str()); + /* Expected output: + compressed original reduced name + 95855838 179403776 -1.3% data.yaffs2.win + ^ + split[5] + */ + split = TWFunc::split_string(result, ' ', true); + if (split.size() > 4) + total_size = atoi(split[5].c_str()); + } + } else { + total_size = TWFunc::Get_File_Size(filename); + } + } + + return total_size; +} + extern "C" ssize_t write_tar(int fd, const void *buffer, size_t size) { return (ssize_t) write_libtar_buffer(fd, buffer, size); } diff --git a/twrpTar.hpp b/twrpTar.hpp index 443e5f4b3..799475234 100644 --- a/twrpTar.hpp +++ b/twrpTar.hpp @@ -45,12 +45,13 @@ class twrpTar { public: twrpTar(); virtual ~twrpTar(); - int createTarFork(); - int extractTarFork(); + int createTarFork(const unsigned long long *overall_size, const unsigned long long *other_backups_size); + int extractTarFork(const unsigned long long *overall_size, unsigned long long *other_backups_size); void setfn(string fn); void setdir(string dir); void setsize(unsigned long long backup_size); void setpassword(string pass); + unsigned long long get_size(); public: int use_encryption; @@ -59,6 +60,9 @@ public: int split_archives; int has_data_media; string backup_name; + int progress_pipe_fd; + string partition_name; + string backup_folder; private: int extract(); @@ -75,6 +79,7 @@ private: static void* createList(void *cookie); static void* extractMulti(void *cookie); int tarList(std::vector *TarList, unsigned thread_id); + unsigned long long uncompressedSize(string filename, int *archive_type); int Archive_Current_Type; unsigned long long Archive_Current_Size; @@ -84,6 +89,7 @@ private: int fd; pid_t pigz_pid; pid_t oaes_pid; + unsigned long long file_count; string tardir; string tarfn; diff --git a/twrpTarMain/twrpTarMain.cpp b/twrpTarMain/twrpTarMain.cpp index b28a42ea7..c1705c79c 100644 --- a/twrpTarMain/twrpTarMain.cpp +++ b/twrpTarMain/twrpTarMain.cpp @@ -47,6 +47,7 @@ int main(int argc, char **argv) { int i, action = 0; unsigned j; string Directory, Tar_Filename; + unsigned long long temp1 = 0, temp2 = 0; #ifndef TW_EXCLUDE_ENCRYPTED_BACKUPS string Password; #endif @@ -142,14 +143,14 @@ int main(int argc, char **argv) { } #endif if (action == 1) { - if (tar.createTarFork() != 0) { + if (tar.createTarFork(&temp1, &temp2) != 0) { sync(); return -1; } sync(); printf("\n\ntar created successfully.\n"); } else if (action == 2) { - if (tar.extractTarFork() != 0) { + if (tar.extractTarFork(&temp1, &temp2) != 0) { sync(); return -1; } -- cgit v1.2.3