Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 472f5068 authored by Ethan Yonker's avatar Ethan Yonker Committed by Dees Troy
Browse files

Improve progress bar handling for backup / restore / image flash

The progress bar will now be updated during image backups, restores
and during image flashing (except for sparse images which will require
significant changes to libsparse, and except for mtd nand using
flash_utils).

The progress bar will now be updated mid-file for file systems (tar) so
the user will see changes even during large file backup / restore.

Add a new progress tracking class to simplify handling of progress bar
updates. The class will only update the progress bar 5 times a second to
reduce the CPU load from updating the GUI frequently which does affect
backup times.

Change-Id: Iff382faef3df1f86604af336c1a8ce8993cd12c5
parent fe91611c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ LOCAL_SRC_FILES += \
    data.cpp \
    partition.cpp \
    partitionmanager.cpp \
    progresstracking.cpp \
    twinstall.cpp \
    twrp-functions.cpp \
    openrecoveryscript.cpp \
+6 −1
Original line number Diff line number Diff line
@@ -89,13 +89,16 @@ public:
			resname = name.substr(0, pos);
			default_value = name.substr(pos + 1);
		}
#ifndef BUILD_TWRPTAR_MAIN
		const ResourceManager* res = PageManager::GetResources();
		if (res) {
			if (default_value.empty())
				return res->FindString(resname);
			else
				return res->FindString(resname, default_value);
		} else if (!default_value.empty()) {
		}
#endif
		if (!default_value.empty()) {
			return default_value;
		}
		return name;
@@ -112,10 +115,12 @@ class DataLookup : public StringLookup
public:
	virtual std::string operator()(const std::string& name) const
	{
#ifndef BUILD_TWRPTAR_MAIN
		std::string value;
		if (DataManager::GetValue(name, value) == 0)
			return value;
		else
#endif
			return "";
	}
};
+7 −6
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@
# include "selinux/selinux.h"
#endif

const unsigned long long progress_size = (unsigned long long)(T_BLOCKSIZE);

static int
tar_set_file_perms(TAR *t, const char *realname)
{
@@ -245,6 +247,11 @@ tar_extract_regfile(TAR *t, const char *realname, const int *progress_fd)
			close(fdout);
			return -1;
		}
		else
		{
			if (*progress_fd != 0)
				write(*progress_fd, &progress_size, sizeof(progress_size));
		}
	}

	/* close output file */
@@ -255,12 +262,6 @@ tar_extract_regfile(TAR *t, const char *realname, const int *progress_fd)
	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;
}

+140 −91
Original line number Diff line number Diff line
/*
	Copyright 2013 TeamWin
	Copyright 2013 to 2016 TeamWin
	This file is part of TWRP/TeamWin Recovery Project.

	TWRP is free software: you can redistribute it and/or modify
@@ -28,6 +28,7 @@
#include <iostream>
#include <sstream>
#include <sys/param.h>
#include <fcntl.h>

#ifdef TW_INCLUDE_CRYPTO
	#include "cutils/properties.h"
@@ -69,6 +70,7 @@ extern "C" {
#include <linux/xattr.h>
#endif
#include <sparse_format.h>
#include "progresstracking.hpp"

using namespace std;

@@ -1466,14 +1468,14 @@ bool TWPartition::Resize() {
	return false;
}

bool TWPartition::Backup(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size, pid_t &tar_fork_pid) {
bool TWPartition::Backup(const string& backup_folder, pid_t &tar_fork_pid, ProgressTracking *progress) {
	if (Backup_Method == FILES) {
		return Backup_Tar(backup_folder, overall_size, other_backups_size, tar_fork_pid);
		return Backup_Tar(backup_folder, progress, tar_fork_pid);
	}
	else if (Backup_Method == DD)
		return Backup_DD(backup_folder);
		return Backup_Image(backup_folder, progress);
	else if (Backup_Method == FLASH_UTILS)
		return Backup_Dump_Image(backup_folder);
		return Backup_Dump_Image(backup_folder, progress);
	LOGERR("Unknown backup method for '%s'\n", Mount_Point.c_str());
	return false;
}
@@ -1526,7 +1528,7 @@ bool TWPartition::Check_MD5(string restore_folder) {
	return false;
}

bool TWPartition::Restore(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size) {
bool TWPartition::Restore(const string& restore_folder, ProgressTracking *progress) {
	string Restore_File_System;

	TWFunc::GUI_Operation_Text(TW_RESTORE_TEXT, Display_Name, gui_parse_text("{@restoring_hdr}"));
@@ -1535,16 +1537,16 @@ bool TWPartition::Restore(string restore_folder, const unsigned long long *total
	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);
		return Restore_Tar(restore_folder, Restore_File_System, progress);
	else if (Is_Image(Restore_File_System)) {
		return Restore_Image(restore_folder, total_restore_size, already_restored_size, Restore_File_System);
		return Restore_Image(restore_folder, Restore_File_System, progress);
	}

	LOGERR("Unknown restore method for '%s'\n", Mount_Point.c_str());
	return false;
}

string TWPartition::Get_Restore_File_System(string restore_folder) {
string TWPartition::Get_Restore_File_System(const string& restore_folder) {
	size_t first_period, second_period;
	string Restore_File_System;

@@ -2009,14 +2011,9 @@ bool TWPartition::Wipe_Data_Without_Wiping_Media_Func(const string& parent __unu
	return false;
}

bool TWPartition::Backup_Tar(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size, pid_t &tar_fork_pid) {
	char back_name[255], split_index[5];
	string Full_FileName, Split_FileName, Tar_Args, Command;
	int use_compression, use_encryption = 0, index, backup_count;
	struct stat st;
	unsigned long long total_bsize = 0, file_size;
bool TWPartition::Backup_Tar(const string& backup_folder, ProgressTracking *progress, pid_t &tar_fork_pid) {
	string Full_FileName;
	twrpTar tar;
	vector <string> files;

	if (!Mount(true))
		return false;
@@ -2024,25 +2021,24 @@ bool TWPartition::Backup_Tar(string backup_folder, const unsigned long long *ove
	TWFunc::GUI_Operation_Text(TW_BACKUP_TEXT, Backup_Display_Name, "Backing Up");
	gui_msg(Msg("backing_up=Backing up {1}...")(Backup_Display_Name));

	DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression);
	tar.use_compression = use_compression;
	DataManager::GetValue(TW_USE_COMPRESSION_VAR, tar.use_compression);

#ifndef TW_EXCLUDE_ENCRYPTED_BACKUPS
	DataManager::GetValue("tw_encrypt_backup", use_encryption);
	if (use_encryption && Can_Encrypt_Backup) {
		tar.use_encryption = use_encryption;
	if (Can_Encrypt_Backup) {
		DataManager::GetValue("tw_encrypt_backup", tar.use_encryption);
		if (tar.use_encryption) {
			if (Use_Userdata_Encryption)
			tar.userdata_encryption = use_encryption;
				tar.userdata_encryption = tar.use_encryption;
			string Password;
			DataManager::GetValue("tw_backup_password", Password);
			tar.setpassword(Password);
		} else {
		use_encryption = false;
			tar.use_encryption = 0;
		}
	}
#endif

	sprintf(back_name, "%s.%s.win", Backup_Name.c_str(), Current_File_System.c_str());
	Backup_FileName = back_name;
	Backup_FileName = Backup_Name + "." + Current_File_System + ".win";
	Full_FileName = backup_folder + "/" + Backup_FileName;
	tar.has_data_media = Has_Data_Media;
	Full_FileName = backup_folder + "/" + Backup_FileName;
@@ -2051,39 +2047,23 @@ bool TWPartition::Backup_Tar(string backup_folder, const unsigned long long *ove
	tar.setsize(Backup_Size);
	tar.partition_name = Backup_Name;
	tar.backup_folder = backup_folder;
	if (tar.createTarFork(overall_size, other_backups_size, tar_fork_pid) != 0)
	if (tar.createTarFork(progress, tar_fork_pid) != 0)
		return false;
	return true;
}

bool TWPartition::Backup_DD(string backup_folder) {
	char back_name[255], block_size[32], dd_count[32];
	string Full_FileName, Command, DD_BS, DD_COUNT;
	int use_compression;
	unsigned long long DD_Block_Size, DD_Count;

	DD_Block_Size = 16 * 1024 * 1024;
	while (Backup_Size % DD_Block_Size != 0) DD_Block_Size >>= 1;

	DD_Count = Backup_Size / DD_Block_Size;

	sprintf(dd_count, "%llu", DD_Count);
	DD_COUNT = dd_count;

	sprintf(block_size, "%llu", DD_Block_Size);
	DD_BS = block_size;
bool TWPartition::Backup_Image(const string& backup_folder, ProgressTracking *progress) {
	string Full_FileName;

	TWFunc::GUI_Operation_Text(TW_BACKUP_TEXT, Display_Name, gui_parse_text("{@backing}"));
	gui_msg(Msg("backing_up=Backing up {1}...")(Backup_Display_Name));

	sprintf(back_name, "%s.%s.win", Backup_Name.c_str(), Current_File_System.c_str());
	Backup_FileName = back_name;

	Backup_FileName = Backup_Name + "." + Current_File_System + ".win";
	Full_FileName = backup_folder + "/" + Backup_FileName;

	Command = "dd if=" + Actual_Block_Device + " of='" + Full_FileName + "'" + " bs=" + DD_BS + " count=" + DD_COUNT;
	LOGINFO("Backup command: '%s'\n", Command.c_str());
	TWFunc::Exec_Cmd(Command);
	if (!Raw_Read_Write(Actual_Block_Device, Full_FileName, Backup_Size, progress))
		return false;

	tw_set_default_metadata(Full_FileName.c_str());
	if (TWFunc::Get_File_Size(Full_FileName) == 0) {
		gui_msg(Msg(msg::kError, "backup_size=Backup file size for '{1}' is 0 bytes.")(Full_FileName));
@@ -2092,17 +2072,77 @@ bool TWPartition::Backup_DD(string backup_folder) {
	return true;
}

bool TWPartition::Backup_Dump_Image(string backup_folder) {
	char back_name[255];
bool TWPartition::Raw_Read_Write(const string& input_file, const string& output_file, const unsigned long long input_size, ProgressTracking *progress) {
	unsigned long long RW_Block_Size, Remain;
	int src_fd = -1, dest_fd = -1, bs;
	bool ret = false;
	void* buffer = NULL;
	unsigned long long backedup_size = 0;

	RW_Block_Size = 1048576LLU; // 1MB
	Remain = input_size;

	src_fd = open(input_file.c_str(), O_RDONLY | O_LARGEFILE);
	if (src_fd < 0) {
		gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(input_file)(strerror(errno)));
		return false;
	}
	dest_fd = open(output_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, S_IRUSR | S_IWUSR);
	if (dest_fd < 0) {
		gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(output_file)(strerror(errno)));
		goto exit;
	}
	bs = (int)(RW_Block_Size);
	buffer = malloc((size_t)bs);
	if (!buffer) {
		LOGINFO("Raw_Read_Write failed to malloc\n");
		goto exit;
	}
	LOGINFO("Reading '%s', writing '%s'\n", input_file.c_str(), output_file.c_str());
	if (progress)
		progress->SetPartitionSize(input_size);
	while (Remain > 0) {
		if (Remain < RW_Block_Size)
			bs = (int)(Remain);
		if (read(src_fd, buffer, bs) != bs) {
			LOGINFO("Error reading source fd (%s)\n", strerror(errno));
			goto exit;
		}
		if (write(dest_fd, buffer, bs) != bs) {
			LOGINFO("Error writing destination fd (%s)\n", strerror(errno));
			goto exit;
		}
		backedup_size += (unsigned long long)(bs);
		Remain -= (unsigned long long)(bs);
		if (progress)
			progress->UpdateSize(backedup_size);
		if (PartitionManager.Check_Backup_Cancel() != 0)
			goto exit;
	}
	if (progress)
		progress->UpdateDisplayDetails(true);
	fsync(dest_fd);
	ret = true;
exit:
	if (src_fd >= 0)
		close(src_fd);
	if (dest_fd >= 0)
		close(dest_fd);
	if (buffer)
		free(buffer);
	return ret;
}

bool TWPartition::Backup_Dump_Image(const string& backup_folder, ProgressTracking *progress) {
	string Full_FileName, Command;
	int use_compression;

	TWFunc::GUI_Operation_Text(TW_BACKUP_TEXT, Display_Name, gui_parse_text("{@backing}"));
	gui_msg(Msg("backing_up=Backing up {1}...")(Backup_Display_Name));

	sprintf(back_name, "%s.%s.win", Backup_Name.c_str(), Current_File_System.c_str());
	Backup_FileName = back_name;
	if (progress)
		progress->SetPartitionSize(Backup_Size);

	Backup_FileName = Backup_Name + "." + Current_File_System + ".win";
	Full_FileName = backup_folder + "/" + Backup_FileName;

	Command = "dump_image " + MTD_Name + " '" + Full_FileName + "'";
@@ -2114,10 +2154,12 @@ bool TWPartition::Backup_Dump_Image(string backup_folder) {
		gui_msg(Msg(msg::kError, "backup_size=Backup file size for '{1}' is 0 bytes.")(Full_FileName));
		return false;
	}
	if (progress)
		progress->UpdateSize(Backup_Size);
	return true;
}

unsigned long long TWPartition::Get_Restore_Size(string restore_folder) {
unsigned long long TWPartition::Get_Restore_Size(const 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) {
@@ -2150,10 +2192,8 @@ unsigned long long TWPartition::Get_Restore_Size(string restore_folder) {
	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];
bool TWPartition::Restore_Tar(const string& restore_folder, const string& Restore_File_System, ProgressTracking *progress) {
	string Full_FileName;
	bool ret = false;

	if (Has_Android_Secure) {
@@ -2188,7 +2228,8 @@ bool TWPartition::Restore_Tar(string restore_folder, string Restore_File_System,
	if (!Password.empty())
		tar.setpassword(Password);
#endif
	if (tar.extractTarFork(total_restore_size, already_restored_size) != 0)
	progress->SetPartitionSize(Get_Restore_Size(restore_folder));
	if (tar.extractTarFork(progress) != 0)
		ret = false;
	else
		ret = true;
@@ -2218,28 +2259,21 @@ bool TWPartition::Restore_Tar(string restore_folder, string Restore_File_System,
	return ret;
}

bool TWPartition::Restore_Image(string restore_folder, const unsigned long long *total_restore_size, unsigned long long *already_restored_size, string Restore_File_System) {
bool TWPartition::Restore_Image(const string& restore_folder, const string& Restore_File_System, ProgressTracking *progress) {
	string Full_FileName;
	double display_percent, progress_percent;
	char size_progress[1024];

	TWFunc::GUI_Operation_Text(TW_RESTORE_TEXT, Backup_Display_Name, gui_parse_text("{@restoring_hdr}"));
	gui_msg(Msg("restoring=Restoring {1}...")(Backup_Display_Name));
	Full_FileName = restore_folder + "/" + Backup_FileName;

	if (Restore_File_System == "emmc") {
		if (!Flash_Image_DD(Full_FileName))
		unsigned long long file_size = (unsigned long long)(TWFunc::Get_File_Size(Full_FileName));
		if (!Raw_Read_Write(Full_FileName, Actual_Block_Device, file_size, progress))
			return false;
	} else if (Restore_File_System == "mtd" || Restore_File_System == "bml") {
		if (!Flash_Image_FI(Full_FileName))
		if (!Flash_Image_FI(Full_FileName, progress))
			return false;
	}
	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;
}

@@ -2380,7 +2414,7 @@ uint64_t TWPartition::Get_Max_FileSize() {
	return maxFileSize - 1;
}

bool TWPartition::Flash_Image(string Filename) {
bool TWPartition::Flash_Image(const string& Filename) {
	string Restore_File_System;

	LOGINFO("Image filename is: %s\n", Filename.c_str());
@@ -2403,21 +2437,23 @@ bool TWPartition::Flash_Image(string Filename) {
			gui_err("img_size_err=Size of image is larger than target device");
			return false;
		}
		if (Backup_Method == DD)
			return Flash_Image_DD(Filename);
		else if (Backup_Method == FLASH_UTILS)
			return Flash_Image_FI(Filename);
		if (Backup_Method == DD) {
			if (Is_Sparse_Image(Filename)) {
				return Flash_Sparse_Image(Filename);
			}
			unsigned long long file_size = (unsigned long long)(TWFunc::Get_File_Size(Filename));
			ProgressTracking pt(file_size);
			return Raw_Read_Write(Filename, Actual_Block_Device, file_size, &pt);
		} else if (Backup_Method == FLASH_UTILS) {
			return Flash_Image_FI(Filename, NULL);
		}
	}

	LOGERR("Unknown flash method for '%s'\n", Mount_Point.c_str());
	return false;
}

bool TWPartition::Flash_Image_DD(string Filename) {
	string Command;

	gui_msg(Msg("flashing=Flashing {1}...")(Display_Name));

bool TWPartition::Is_Sparse_Image(const string& Filename) {
	uint32_t magic = 0;
	int fd = open(Filename.c_str(), O_RDONLY);
	if (fd < 0) {
@@ -2430,20 +2466,31 @@ bool TWPartition::Flash_Image_DD(string Filename) {
		return false;
	}
	close(fd);
	if (magic == SPARSE_HEADER_MAGIC) {
		Command = "simg2img '" + Filename + "' " + Actual_Block_Device;
	} else {
		Command = "dd bs=8388608 if='" + Filename + "' of=" + Actual_Block_Device;
	if (magic == SPARSE_HEADER_MAGIC)
		return true;
	return false;
}

bool TWPartition::Flash_Sparse_Image(const string& Filename) {
	string Command;

	gui_msg(Msg("flashing=Flashing {1}...")(Display_Name));

	Command = "simg2img '" + Filename + "' '" + Actual_Block_Device + "'";
	LOGINFO("Flash command: '%s'\n", Command.c_str());
	TWFunc::Exec_Cmd(Command);
	return true;
}

bool TWPartition::Flash_Image_FI(string Filename) {
bool TWPartition::Flash_Image_FI(const string& Filename, ProgressTracking *progress) {
	string Command;
	unsigned long long file_size;

	gui_msg(Msg("flashing=Flashing {1}...")(Display_Name));
	if (progress) {
		file_size = (unsigned long long)(TWFunc::Get_File_Size(Filename));
		progress->SetPartitionSize(file_size);
	}
	// Sometimes flash image doesn't like to flash due to the first 2KB matching, so we erase first to ensure that it flashes
	Command = "erase_image " + MTD_Name;
	LOGINFO("Erase command: '%s'\n", Command.c_str());
@@ -2451,6 +2498,8 @@ bool TWPartition::Flash_Image_FI(string Filename) {
	Command = "flash_image " + MTD_Name + " '" + Filename + "'";
	LOGINFO("Flash command: '%s'\n", Command.c_str());
	TWFunc::Exec_Cmd(Command);
	if (progress)
		progress->UpdateSize(file_size);
	return true;
}

+22 −34
Original line number Diff line number Diff line
/*
	Copyright 2014 TeamWin
	Copyright 2014 to 2016 TeamWin
	This file is part of TWRP/TeamWin Recovery Project.

	TWRP is free software: you can redistribute it and/or modify
@@ -43,6 +43,7 @@
#include "set_metadata.h"
#include "tw_atomic.hpp"
#include "gui/gui.hpp"
#include "progresstracking.hpp"

#ifdef TW_HAS_MTP
#include "mtp/mtp_MtpServer.hpp"
@@ -527,11 +528,9 @@ bool TWPartitionManager::Make_MD5(bool generate_md5, string Backup_Folder, strin
	return true;
}

bool TWPartitionManager::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 TWPartitionManager::Backup_Partition(TWPartition* Part, const string& Backup_Folder, bool generate_md5, unsigned long *img_time, unsigned long *file_time, ProgressTracking *progress) {
	time_t start, stop;
	int use_compression;
	float pos;
	unsigned long long total_size, current_size;

	string backup_log = Backup_Folder + "recovery.log";

@@ -540,26 +539,17 @@ bool TWPartitionManager::Backup_Partition(TWPartition* Part, string Backup_Folde

	DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression);

	total_size = *file_bytes + *img_bytes;
	current_size = *file_bytes + *img_bytes - *file_bytes_remaining - *img_bytes_remaining;
	// Set the position
	pos = ((float)(current_size) / (float)(total_size));
	DataManager::SetProgress(pos);

	TWFunc::SetPerformanceMode(true);
	time(&start);

	if (Part->Backup(Backup_Folder, &total_size, &current_size, tar_fork_pid)) {
	if (Part->Backup(Backup_Folder, tar_fork_pid, progress)) {
		bool md5Success = false;
		current_size += Part->Backup_Size;
		pos = (float)((float)(current_size) / (float)(total_size));
		DataManager::SetProgress(pos);
		if (Part->Has_SubPartition) {
			std::vector<TWPartition*>::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, &total_size, &current_size, tar_fork_pid)) {
					if (!(*subpart)->Backup(Backup_Folder, tar_fork_pid, progress)) {
						TWFunc::SetPerformanceMode(false);
						Clean_Backup_Folder(Backup_Folder);
						TWFunc::copy_file("/tmp/recovery.log", backup_log, 0644);
@@ -572,14 +562,6 @@ bool TWPartitionManager::Backup_Partition(TWPartition* Part, string Backup_Folde
						TWFunc::SetPerformanceMode(false);
						return false;
					}
					if (Part->Backup_Method == 1) {
						*file_bytes_remaining -= (*subpart)->Backup_Size;
					} else {
						*img_bytes_remaining -= (*subpart)->Backup_Size;
					}
					current_size += Part->Backup_Size;
					pos = (float)(current_size / total_size);
					DataManager::SetProgress(pos);
				}
			}
		}
@@ -587,10 +569,8 @@ bool TWPartitionManager::Backup_Partition(TWPartition* Part, string Backup_Folde
		int backup_time = (int) difftime(stop, start);
		LOGINFO("Partition Backup time: %d\n", backup_time);
		if (Part->Backup_Method == 1) {
			*file_bytes_remaining -= Part->Backup_Size;
			*file_time += backup_time;
		} else {
			*img_bytes_remaining -= Part->Backup_Size;
			*img_time += backup_time;
		}

@@ -636,6 +616,10 @@ void TWPartitionManager::Clean_Backup_Folder(string Backup_Folder) {
	closedir(d);
}

int TWPartitionManager::Check_Backup_Cancel() {
	return stop_backup.get_value();
}

int TWPartitionManager::Cancel_Backup() {
	string Backup_Folder, Backup_Name, Full_Backup_Path;

@@ -738,6 +722,7 @@ int TWPartitionManager::Run_Backup(void) {
		return false;
	}
	total_bytes = file_bytes + img_bytes;
	ProgressTracking progress(total_bytes);
	gui_msg(Msg("total_partitions_backup= * Total number of partitions to back up: {1}")(partition_count));
	gui_msg(Msg("total_backup_size= * Total size of all data: {1}MB")(total_bytes / 1024 / 1024));
	storage = Find_Partition_By_Path(DataManager::GetCurrentStoragePath());
@@ -777,7 +762,7 @@ int TWPartitionManager::Run_Backup(void) {
		backup_path = Backup_List.substr(start_pos, end_pos - start_pos);
		backup_part = Find_Partition_By_Path(backup_path);
		if (backup_part != NULL) {
			if (!Backup_Partition(backup_part, Full_Backup_Path, do_md5, &img_bytes_remaining, &file_bytes_remaining, &img_time, &file_time, &img_bytes, &file_bytes))
			if (!Backup_Partition(backup_part, Full_Backup_Path, do_md5, &img_time, &file_time, &progress))
				return false;
		} else {
			gui_msg(Msg(msg::kError, "unable_to_locate_partition=Unable to locate '{1}' partition for backup calculations.")(backup_path));
@@ -794,7 +779,9 @@ int TWPartitionManager::Run_Backup(void) {
	int img_bps = (int)img_bytes / (int)img_time;
	unsigned long long file_bps = file_bytes / (int)file_time;

	if (file_bytes != 0)
		gui_msg(Msg("avg_backup_fs=Average backup rate for file systems: {1} MB/sec")(file_bps / (1024 * 1024)));
	if (img_bytes != 0)
		gui_msg(Msg("avg_backup_img=Average backup rate for imaged drives: {1} MB/sec")(img_bps / (1024 * 1024)));

	time(&total_stop);
@@ -832,12 +819,12 @@ int TWPartitionManager::Run_Backup(void) {
	return true;
}

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) {
bool TWPartitionManager::Restore_Partition(TWPartition* Part, const string& Restore_Name, ProgressTracking *progress) {
	time_t Start, Stop;
	TWFunc::SetPerformanceMode(true);
	time(&Start);
	//DataManager::ShowProgress(1.0 / (float)partition_count, 150);
	if (!Part->Restore(Restore_Name, total_restore_size, already_restored_size)) {

	if (!Part->Restore(Restore_Name, progress)) {
		TWFunc::SetPerformanceMode(false);
		return false;
	}
@@ -846,7 +833,7 @@ bool TWPartitionManager::Restore_Partition(TWPartition* Part, string Restore_Nam

		for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
			if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point) {
				if (!(*subpart)->Restore(Restore_Name, total_restore_size, already_restored_size)) {
				if (!(*subpart)->Restore(Restore_Name, progress)) {
					TWFunc::SetPerformanceMode(false);
					return false;
				}
@@ -859,7 +846,7 @@ bool TWPartitionManager::Restore_Partition(TWPartition* Part, string Restore_Nam
	return true;
}

int TWPartitionManager::Run_Restore(string Restore_Name) {
int TWPartitionManager::Run_Restore(const string& Restore_Name) {
	int check_md5, check, partition_count = 0;
	TWPartition* restore_part = NULL;
	time_t rStart, rStop;
@@ -925,6 +912,7 @@ int TWPartitionManager::Run_Restore(string Restore_Name) {
	gui_msg(Msg("restore_part_count=Restoring {1} partitions...")(partition_count));
	gui_msg(Msg("total_restore_size=Total restore size is {1}MB")(total_restore_size / 1048576));
	DataManager::SetProgress(0.0);
	ProgressTracking progress(total_restore_size);

	start_pos = 0;
	if (!Restore_List.empty()) {
@@ -934,7 +922,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, &total_restore_size, &already_restored_size))
				if (!Restore_Partition(restore_part, Restore_Name, &progress))
					return false;
			} else {
				gui_msg(Msg(msg::kError, "restore_unable_locate=Unable to locate '{1}' partition for restoring.")(restore_path));
Loading