Commit 7abc5fe1 authored by bigbiff's avatar bigbiff Committed by Dees Troy

Add cancel backup capability.

This will stop the iteration of the partition objects, kill the
current twrpTar thread and remove the backup directory.

Implement TWAtomicInt class to give us a wrapper that automatically
uses mutexes before the read and write to help ensure that the
reads and writes will be atomic based on documentation.

Change-Id: I645b22bc980a292e9c7202acb24ffd22ebe68c63
parent 3454ade9
......@@ -454,7 +454,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := libaosprecovery
LOCAL_MODULE_TAGS := eng optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/libmincrypt/includes
LOCAL_SRC_FILES := adb_install.cpp asn1_decoder.cpp bootloader.cpp legacy_property_service.c verifier.cpp set_metadata.c
LOCAL_SRC_FILES := adb_install.cpp asn1_decoder.cpp bootloader.cpp legacy_property_service.c verifier.cpp set_metadata.c tw_atomic.cpp
LOCAL_SHARED_LIBRARIES += libc liblog libcutils libmtdutils libfusesideload libmincrypttwrp libselinux
ifneq ($(BOARD_RECOVERY_BLDRMSG_OFFSET),)
......
......@@ -56,6 +56,7 @@ extern "C" {
#include "rapidxml.hpp"
#include "objects.hpp"
#include "../tw_atomic.hpp"
void curtainClose(void);
......@@ -169,6 +170,7 @@ GUIAction::GUIAction(xml_node<>* node)
mf["fixsu"] = &GUIAction::fixsu;
mf["startmtp"] = &GUIAction::startmtp;
mf["stopmtp"] = &GUIAction::stopmtp;
mf["cancelbackup"] = &GUIAction::cancelbackup;
// remember actions that run in the caller thread
for (mapFunc::const_iterator it = mf.begin(); it != mf.end(); ++it)
......@@ -314,6 +316,13 @@ void GUIAction::simulate_progress_bar(void)
gui_print("Simulating actions...\n");
for (int i = 0; i < 5; i++)
{
if (PartitionManager.stop_backup.get_value()) {
DataManager::SetValue("tw_cancel_backup", 1);
gui_print("Backup Canceled.\n");
DataManager::SetValue("ui_progress", 0);
PartitionManager.stop_backup.set_value(0);
return;
}
usleep(500000);
DataManager::SetValue("ui_progress", i * 20);
}
......@@ -1087,13 +1096,13 @@ int GUIAction::refreshsizes(std::string arg)
int GUIAction::nandroid(std::string arg)
{
operation_start("Nandroid");
int ret = 0;
if (simulate) {
DataManager::SetValue("tw_partition", "Simulation");
simulate_progress_bar();
} else {
operation_start("Nandroid");
int ret = 0;
if (arg == "backup") {
string Backup_Name;
DataManager::GetValue(TW_BACKUP_NAME, Backup_Name);
......@@ -1103,7 +1112,6 @@ int GUIAction::nandroid(std::string arg)
else {
operation_end(1);
return -1;
}
DataManager::SetValue(TW_BACKUP_NAME, "(Auto Generate)");
} else if (arg == "restore") {
......@@ -1112,16 +1120,42 @@ int GUIAction::nandroid(std::string arg)
ret = PartitionManager.Run_Restore(Restore_Name);
} else {
operation_end(1);
return -1;
}
}
DataManager::SetValue("tw_encrypt_backup", 0);
return -1;
}
DataManager::SetValue("tw_encrypt_backup", 0);
if (!PartitionManager.stop_backup.get_value()) {
if (ret == false)
ret = 1; // 1 for failure
else
ret = 0; // 0 for success
DataManager::SetValue("tw_cancel_backup", 0);
operation_end(ret);
return 0;
}
else {
DataManager::SetValue("tw_cancel_backup", 1);
gui_print("Backup Canceled.\n");
ret = 0;
}
return ret;
}
return 0;
}
int GUIAction::cancelbackup(std::string arg) {
if (simulate) {
simulate_progress_bar();
PartitionManager.stop_backup.set_value(1);
operation_end(0);
}
else {
operation_start("Cancel Backup");
int op_status = PartitionManager.Cancel_Backup();
if (op_status != 0)
op_status = 1; // failure
operation_end(op_status);
}
return 0;
}
int GUIAction::fixpermissions(std::string arg)
......
......@@ -50,6 +50,7 @@
<variable name="col1_x" value="10" />
<variable name="col2_x" value="240" />
<variable name="col_center_x" value="128" />
<variable name="col_center_medium_x" value="183" />
<variable name="center_x" value="240" />
<variable name="row1_y" value="140" />
<variable name="row2_y" value="290" />
......
......@@ -670,7 +670,7 @@
<object type="button">
<highlight color="%highlight_color%" />
<condition var1="tw_has_cancel" var2="1" />
<placement x="%col4_x%" y="%slider_y%" />
<placement x="%col_center_x%" y="%cancel_button_y%" />
<font resource="font" color="%button_text_color%" />
<text>Cancel</text>
<image resource="main_button" />
......@@ -2157,6 +2157,17 @@
<object type="template" name="action_page_console" />
<object type="button">
<highlight color="%highlight_color%" />
<placement x="%col_center_medium_x%" y="%row3_y%" />
<font resource="font" color="%button_text_color%" />
<text>Cancel</text>
<image resource="medium_button" />
<actions>
<action function="cancelbackup"></action>
</actions>
</object>
<object type="template" name="progress_bar" />
<object type="action">
......@@ -2165,6 +2176,7 @@
<object type="action">
<condition var1="tw_operation_state" var2="1" />
<condition var1="tw_cancel_backup" var2="0" />
<actions>
<action function="set">tw_back=backup</action>
<action function="set">tw_complete_text1=Backup Complete</action>
......@@ -2173,6 +2185,17 @@
</actions>
</object>
<object type="action">
<condition var1="tw_operation_state" var2="1" />
<condition var1="tw_cancel_backup" var2="1" />
<actions>
<action function="set">tw_back=backup</action>
<action function="set">tw_complete_text1=Backup Cancelled</action>
<action function="set">tw_show_reboot=1</action>
<action function="page">action_complete</action>
</actions>
</object>
<object type="template" name="footer" />
</page>
......
......@@ -1867,6 +1867,17 @@
<object type="template" name="action_page_console" />
<object type="button">
<highlight color="%highlight_color%" />
<placement x="%col_center_medium_x%" y="%row4_y%" />
<font resource="font" color="%button_text_color%" />
<text>Cancel</text>
<image resource="medium_button" />
<actions>
<action function="cancelbackup"></action>
</actions>
</object>
<object type="template" name="progress_bar" />
<object type="action">
......@@ -1875,6 +1886,7 @@
<object type="action">
<condition var1="tw_operation_state" var2="1" />
<condition var1="tw_cancel_backup" var2="0" />
<actions>
<action function="set">tw_back=backup</action>
<action function="set">tw_complete_text1=Backup Complete</action>
......@@ -1882,6 +1894,17 @@
<action function="page">action_complete</action>
</actions>
</object>
<object type="action">
<condition var1="tw_operation_state" var2="1" />
<condition var1="tw_cancel_backup" var2="1" />
<actions>
<action function="set">tw_back=backup</action>
<action function="set">tw_complete_text1=Backup Cancelled</action>
<action function="set">tw_show_reboot=1</action>
<action function="page">action_complete</action>
</actions>
</object>
</page>
<page name="restore">
......
......@@ -1859,6 +1859,21 @@
<object type="template" name="action_page_console" />
<object type="template" name="progress_bar" />
<object type="button">
<highlight color="%highlight_color%" />
<placement x="%col_center_medium_x%" y="%row4_y%" />
<font resource="font" color="%button_text_color%" />
<text>Cancel</text>
<image resource="medium_button" />
<actions>
<action function="cancelbackup"></action>
</actions>
</object>
<object type="template" name="progress_bar" />
<object type="action">
......@@ -1867,6 +1882,7 @@
<object type="action">
<condition var1="tw_operation_state" var2="1" />
<condition var1="tw_cancel_backup" var2="0" />
<actions>
<action function="set">tw_back=backup</action>
<action function="set">tw_complete_text1=Backup Complete</action>
......@@ -1874,6 +1890,17 @@
<action function="page">action_complete</action>
</actions>
</object>
<object type="action">
<condition var1="tw_operation_state" var2="1" />
<condition var1="tw_cancel_backup" var2="1" />
<actions>
<action function="set">tw_back=backup</action>
<action function="set">tw_complete_text1=Backup Cancelled</action>
<action function="set">tw_show_reboot=1</action>
<action function="page">action_complete</action>
</actions>
</object>
</page>
<page name="restore">
......
......@@ -360,6 +360,7 @@ protected:
int startmtp(std::string arg);
int stopmtp(std::string arg);
int flashimage(std::string arg);
int cancelbackup(std::string arg);
int simulate;
};
......
......@@ -1253,9 +1253,10 @@ bool TWPartition::Repair() {
return false;
}
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, overall_size, other_backups_size);
bool TWPartition::Backup(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size, pid_t &tar_fork_pid) {
if (Backup_Method == FILES) {
return Backup_Tar(backup_folder, overall_size, other_backups_size, tar_fork_pid);
}
else if (Backup_Method == DD)
return Backup_DD(backup_folder);
else if (Backup_Method == FLASH_UTILS)
......@@ -1702,7 +1703,7 @@ bool TWPartition::Wipe_Data_Without_Wiping_Media() {
#endif // ifdef TW_OEM_BUILD
}
bool TWPartition::Backup_Tar(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size) {
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;
......@@ -1744,7 +1745,7 @@ 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) != 0)
if (tar.createTarFork(overall_size, other_backups_size, tar_fork_pid) != 0)
return false;
return true;
}
......
/*
Copyright 2012 bigbiff/Dees_Troy TeamWin
Copyright 2014 TeamWin
This file is part of TWRP/TeamWin Recovery Project.
TWRP is free software: you can redistribute it and/or modify
......@@ -39,6 +39,7 @@
#include "twrpDigest.hpp"
#include "twrpDU.hpp"
#include "set_metadata.h"
#include "tw_atomic.hpp"
#ifdef TW_HAS_MTP
#include "mtp/mtp_MtpServer.hpp"
......@@ -59,6 +60,8 @@ extern bool datamedia;
TWPartitionManager::TWPartitionManager(void) {
mtp_was_enabled = false;
mtp_write_fd = -1;
stop_backup.set_value(0);
tar_fork_pid = 0;
}
int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error) {
......@@ -559,7 +562,7 @@ bool TWPartitionManager::Backup_Partition(TWPartition* Part, string Backup_Folde
TWFunc::SetPerformanceMode(true);
time(&start);
if (Part->Backup(Backup_Folder, &total_size, &current_size)) {
if (Part->Backup(Backup_Folder, &total_size, &current_size, tar_fork_pid)) {
bool md5Success = false;
current_size += Part->Backup_Size;
pos = (float)((float)(current_size) / (float)(total_size));
......@@ -569,7 +572,7 @@ bool TWPartitionManager::Backup_Partition(TWPartition* Part, string Backup_Folde
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)) {
if (!(*subpart)->Backup(Backup_Folder, &total_size, &current_size, tar_fork_pid)) {
TWFunc::SetPerformanceMode(false);
return false;
}
......@@ -608,6 +611,30 @@ bool TWPartitionManager::Backup_Partition(TWPartition* Part, string Backup_Folde
TWFunc::SetPerformanceMode(false);
return false;
}
return 0;
}
int TWPartitionManager::Cancel_Backup() {
string Backup_Folder, Backup_Name, Full_Backup_Path;
stop_backup.set_value(1);
if (tar_fork_pid != 0) {
DataManager::GetValue(TW_BACKUP_NAME, Backup_Name);
DataManager::GetValue(TW_BACKUPS_FOLDER_VAR, Backup_Folder);
Full_Backup_Path = Backup_Folder + "/" + Backup_Name + "/";
LOGINFO("Killing pid: %d\n", tar_fork_pid);
kill(tar_fork_pid, SIGUSR2);
while (kill(tar_fork_pid, 0) == 0) {
usleep(1000);
}
LOGINFO("Backup_Run stopped and returning false, backup cancelled.\n");
LOGINFO("Removing directory %s\n", Full_Backup_Path.c_str());
TWFunc::removeDir(Full_Backup_Path, false);
tar_fork_pid = 0;
}
return 0;
}
int TWPartitionManager::Run_Backup(void) {
......@@ -621,6 +648,7 @@ int TWPartitionManager::Run_Backup(void) {
struct tm *t;
time_t start, stop, seconds, total_start, total_stop;
size_t start_pos = 0, end_pos = 0;
stop_backup.set_value(0);
seconds = time(0);
t = localtime(&seconds);
......@@ -718,6 +746,8 @@ int TWPartitionManager::Run_Backup(void) {
start_pos = 0;
end_pos = Backup_List.find(";", start_pos);
while (end_pos != string::npos && start_pos < Backup_List.size()) {
if (stop_backup.get_value() != 0)
return -1;
backup_path = Backup_List.substr(start_pos, end_pos - start_pos);
backup_part = Find_Partition_By_Path(backup_path);
if (backup_part != NULL) {
......
/*
Copyright 2012 bigbiff/Dees_Troy TeamWin
Copyright 2014 TeamWin
This file is part of TWRP/TeamWin Recovery Project.
TWRP is free software: you can redistribute it and/or modify
......@@ -22,6 +22,7 @@
#include <vector>
#include <string>
#include "twrpDU.hpp"
#include "tw_atomic.hpp"
#define MAX_FSTAB_LINE_LENGTH 2048
......@@ -58,7 +59,7 @@ public:
bool Can_Repair(); // Checks to see if we have everything needed to be able to repair the current file system
uint64_t Get_Max_FileSize(); //get partition maxFileSie
bool Repair(); // Repairs the current file system
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 Backup(string backup_folder, const unsigned long long *overall_size, const unsigned long long *other_backups_size, pid_t &tar_fork_pid); // Backs up the partition to the folder specified
bool Check_MD5(string restore_folder); // Checks MD5 of a backup
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
......@@ -104,7 +105,7 @@ 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, const unsigned long long *overall_size, const unsigned long long *other_backups_size); // 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, pid_t &tar_fork_pid); // 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
string Get_Restore_File_System(string restore_folder); // Returns the file system that was in place at the time of the backup
......@@ -211,6 +212,7 @@ public:
void UnMount_Main_Partitions(void); // Unmounts system and data if not data/media and boot if boot is mountable
int Partition_SDCard(void); // Repartitions the sdcard
TWPartition *Get_Default_Storage_Partition(); // Returns a pointer to a default storage partition
int Cancel_Backup(); // Signals partition backup to cancel
int Fix_Permissions();
void Get_Partition_List(string ListType, std::vector<PartitionList> *Partition_List);
......@@ -224,6 +226,8 @@ public:
bool Remove_MTP_Storage(unsigned int Storage_ID); // Adds or removes an MTP Storage partition
bool Flash_Image(string Filename); // Flashes an image to a selected partition from the partition list
TWAtomicInt stop_backup;
private:
void Setup_Settings_Storage_Partition(TWPartition* Part); // Sets up settings storage
void Setup_Android_Secure_Location(TWPartition* Part); // Sets up .android_secure if needed
......@@ -238,6 +242,7 @@ private:
pid_t mtppid;
bool mtp_was_enabled;
int mtp_write_fd;
pid_t tar_fork_pid;
private:
std::vector<TWPartition*> Partitions; // Vector list of all partitions
......
/*
* Copyright (C) 2015 The Team Win Recovery Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <pthread.h>
#include <stdio.h>
#include "tw_atomic.hpp"
/*
* According to this documentation:
* https://developer.android.com/training/articles/smp.html
* it is recommended to use mutexes instead of atomics. This class
* provides us with a wrapper to make "atomic" variables easy to use.
*/
TWAtomicInt::TWAtomicInt(int initial_value /* = 0 */) {
if (pthread_mutex_init(&mutex_lock, NULL) != 0) {
// This should hopefully never happen. If it does, the
// operations will not be atomic, but we will allow things to
// continue anyway after logging the issue and just hope for
// the best.
printf("TWAtomic error initializing mutex.\n");
use_mutex = false;
} else {
use_mutex = true;
}
value = initial_value;
}
TWAtomicInt::~TWAtomicInt() {
if (use_mutex)
pthread_mutex_destroy(&mutex_lock);
}
void TWAtomicInt::set_value(int new_value) {
if (use_mutex) {
pthread_mutex_lock(&mutex_lock);
value = new_value;
pthread_mutex_unlock(&mutex_lock);
} else {
value = new_value;
}
}
int TWAtomicInt::get_value(void) {
int ret_val;
if (use_mutex) {
pthread_mutex_lock(&mutex_lock);
ret_val = value;
pthread_mutex_unlock(&mutex_lock);
} else {
ret_val = value;
}
return ret_val;
}
/*
* Copyright (C) 2015 The Team Win Recovery Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _TWATOMIC_HPP_HEADER
#define _TWATOMIC_HPP_HEADER
#include <pthread.h>
class TWAtomicInt
{
public:
TWAtomicInt(int initial_value = 0);
~TWAtomicInt();
void set_value(int new_value);
int get_value();
private:
int value;
bool use_mutex;
pthread_mutex_t mutex_lock;
};
#endif //_TWATOMIC_HPP_HEADER
......@@ -585,7 +585,7 @@ int TWFunc::removeDir(const string path, bool skipParent) {
string new_path;
if (d == NULL) {
LOGERR("Error opening '%s'\n", path.c_str());
LOGERR("Error opening dir: '%s'\n", path.c_str());
return -1;
}
......
......@@ -34,6 +34,7 @@ extern "C" {
#include <string>
#include <sstream>
#include <vector>
#include <csignal>
#include <dirent.h>
#include <libgen.h>
#include <sys/mman.h>
......@@ -83,9 +84,13 @@ void twrpTar::setpassword(string pass) {
password = pass;
}
int twrpTar::createTarFork(const unsigned long long *overall_size, const unsigned long long *other_backups_size) {
void twrpTar::Signal_Kill(int signum) {
_exit(255);
}
int twrpTar::createTarFork(const unsigned long long *overall_size, const unsigned long long *other_backups_size, pid_t &fork_pid) {
int status = 0;
pid_t pid, rc_pid;
pid_t rc_pid, tar_fork_pid;
int progress_pipe[2], ret;
file_count = 0;
......@@ -94,16 +99,17 @@ int twrpTar::createTarFork(const unsigned long long *overall_size, const unsigne
LOGERR("Error creating progress tracking pipe\n");
return -1;
}
if ((pid = fork()) == -1) {
if ((tar_fork_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
if (tar_fork_pid == 0) {
// Child process
// Child closes input side of progress pipe
signal(SIGUSR2, twrpTar::Signal_Kill);
close(progress_pipe[0]);
progress_pipe_fd = progress_pipe[1];
......@@ -375,6 +381,8 @@ int twrpTar::createTarFork(const unsigned long long *overall_size, const unsigne
files_backup = 0;
size_backup = 0;
fork_pid = tar_fork_pid;
// Parent closes output side
close(progress_pipe[1]);
......@@ -422,7 +430,7 @@ int twrpTar::createTarFork(const unsigned long long *overall_size, const unsigne
backup_info.SetValue("file_count", files_backup);
backup_info.SaveValues();
#endif //ndef BUILD_TWRPTAR_MAIN
if (TWFunc::Wait_For_Child(pid, &status, "createTarFork()") != 0)
if (TWFunc::Wait_For_Child(tar_fork_pid, &status, "createTarFork()") != 0)
return -1;
}
return 0;
......@@ -430,7 +438,7 @@ int twrpTar::createTarFork(const unsigned long long *overall_size, const unsigne
int twrpTar::extractTarFork(const unsigned long long *overall_size, unsigned long long *other_backups_size) {
int status = 0;
pid_t pid, rc_pid;
pid_t rc_pid, tar_fork_pid;
int progress_pipe[2], ret;
if (pipe(progress_pipe) < 0) {
......@@ -438,10 +446,10 @@ int twrpTar::extractTarFork(const unsigned long long *overall_size, unsigned lon
return -1;
}
pid = fork();
if (pid >= 0) // fork was successful
tar_fork_pid = fork();
if (tar_fork_pid >= 0) // fork was successful
{
if (pid == 0) // child process
if (tar_fork_pid == 0) // child process
{
close(progress_pipe[0]);
progress_pipe_fd = progress_pipe[1];
......@@ -585,7 +593,7 @@ int twrpTar::extractTarFork(const unsigned long long *overall_size, unsigned lon
#endif //ndef BUILD_TWRPTAR_MAIN
*other_backups_size += size_backup;
if (TWFunc::Wait_For_Child(pid, &status, "extractTarFork()") != 0)
if (TWFunc::Wait_For_Child(tar_fork_pid, &status, "extractTarFork()") != 0)
return -1;
}
}
......
......@@ -45,7 +45,7 @@ class twrpTar {
public:
twrpTar();
virtual ~twrpTar();
int createTarFork(const unsigned long long *overall_size, const unsigned long long *other_backups_size);
int createTarFork(const unsigned long long *overall_size, const unsigned long long *other_backups_size, pid_t &fork_pid);
int extractTarFork(const unsigned long long *overall_size, unsigned long long *other_backups_size);
void setfn(string fn);
void setdir(string dir);
......@@ -80,6 +80,7 @@ private:
static void* extractMulti(void *cookie);
int tarList(std::vector<TarListStruct> *TarList, unsigned thread_id);
unsigned long long uncompressedSize(string filename, int *archive_type);
static void Signal_Kill(int signum);
int Archive_Current_Type;
unsigned long long Archive_Current_Size;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment