Files
android_bootable_recovery/twrpTar.cpp
bigbiff ad58e1bfae repack: move sbin to /system ramdisk and update repacking
for android-10

This will support updating the ramdisk to a different
compression format and co-exist with magisk.

We are also cleaning up and removing non android-10
api makefile actions.

We are also moving twrp repacking to its own class. We
check the new ramdisk format and if it's different
we have magisk compress using the new ramdisk format.

Change-Id: I770030aae7797e75817178b2f0fccd9f39dc23af
2020-09-08 10:08:33 -04:00

1543 lines
47 KiB
C++
Executable File

/*
Copyright 2013 to 2020 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 <http://www.gnu.org/licenses/>.
*/
extern "C" {
#include "libtar/libtar.h"
#include "twrpTar.h"
#include "tarWrite.h"
}
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <csignal>
#include <dirent.h>
#include <libgen.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <zlib.h>
#include <semaphore.h>
#include "twrpTar.hpp"
#include "twcommon.h"
#include "variables.h"
#include "adbbu/libtwadbbu.hpp"
#include "twrp-functions.hpp"
#include "gui/gui.hpp"
#include "progresstracking.hpp"
#ifndef BUILD_TWRPTAR_MAIN
#include "data.hpp"
#include "infomanager.hpp"
#include "set_metadata.h"
#endif //ndef BUILD_TWRPTAR_MAIN
#ifdef TW_INCLUDE_FBE
#ifdef USE_FSCRYPT
#include "fscrypt_policy.h"
#else
#include "crypto/ext4crypt/ext4crypt_tar.h"
#endif
#endif
#ifdef TW_INCLUDE_FBE
#ifdef USE_FSCRYPT
#define TWTAR_FLAGS TAR_GNU | TAR_STORE_SELINUX | TAR_STORE_POSIX_CAP | TAR_STORE_ANDROID_USER_XATTR | TAR_STORE_FSCRYPT_POL
#else
#define TWTAR_FLAGS TAR_GNU | TAR_STORE_SELINUX | TAR_STORE_POSIX_CAP | TAR_STORE_ANDROID_USER_XATTR | TAR_STORE_EXT4_POL
#endif
#else
#define TWTAR_FLAGS TAR_GNU | TAR_STORE_SELINUX | TAR_STORE_POSIX_CAP | TAR_STORE_ANDROID_USER_XATTR
#endif
using namespace std;
twrpTar::twrpTar(void) {
use_encryption = 0;
userdata_encryption = 0;
use_compression = 0;
split_archives = 0;
pigz_pid = 0;
oaes_pid = 0;
Total_Backup_Size = 0;
Archive_Current_Size = 0;
include_root_dir = true;
tar_type.openfunc = open;
tar_type.closefunc = close;
tar_type.readfunc = read;
input_fd = -1;
output_fd = -1;
backup_exclusions = NULL;
#ifdef TW_INCLUDE_FBE
#ifdef USE_FSCRYPT
fscrypt_set_mode();
#else
e4crypt_set_mode();
#endif
#endif
}
twrpTar::~twrpTar(void) {
// Do nothing
}
void twrpTar::setfn(string fn) {
tarfn = fn;
}
void twrpTar::setdir(string dir) {
tardir = dir;
}
void twrpTar::setsize(unsigned long long backup_size) {
Total_Backup_Size = backup_size;
}
void twrpTar::setpassword(string pass) {
password = pass;
}
void twrpTar::Signal_Kill(int signum) {
_exit(255);
}
void twrpTar::Set_Archive_Type(Archive_Type archive_type) {
current_archive_type = archive_type;
}
int twrpTar::createTarFork(pid_t *tar_fork_pid) {
int status = 0;
int progress_pipe[2];
file_count = 0;
if (backup_exclusions == NULL) {
LOGINFO("backup_exclusions is NULL\n");
return -1;
}
#ifndef BUILD_TWRPTAR_MAIN
if (part_settings->adbbackup) {
std::string Backup_FileName(tarfn);
if (!twadbbu::Write_TWFN(Backup_FileName, Total_Backup_Size, use_compression))
return -1;
}
#endif
if (pipe(progress_pipe) < 0) {
LOGINFO("Error creating progress tracking pipe\n");
gui_err("backup_error=Error creating backup.");
return -1;
}
if ((*tar_fork_pid = fork()) == -1) {
LOGINFO("create tar failed to fork.\n");
gui_err("backup_error=Error creating backup.");
close(progress_pipe[0]);
close(progress_pipe[1]);
return -1;
}
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];
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, total_size;
unsigned enc_thread_id = 1, regular_thread_id = 0, i, start_thread_id = 1, core_count = 1;
int item_len, ret, thread_error = 0;
std::vector<TarListStruct> RegularList;
std::vector<TarListStruct> EncryptList;
string FileName;
struct TarListStruct TarItem;
twrpTar reg, enc[9];
struct stat st;
pthread_t enc_thread[9];
pthread_attr_t tattr;
void *thread_return;
core_count = sysconf(_SC_NPROCESSORS_CONF);
if (core_count > 8)
core_count = 8;
LOGINFO(" Core Count : %u\n", core_count);
Archive_Current_Size = 0;
d = opendir(tardir.c_str());
if (d == NULL) {
gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(tardir)(strerror(errno)));
close(progress_pipe[1]);
_exit(-1);
}
// Figure out the size of all data to be encrypted and create a list of unencrypted files
while ((de = readdir(d)) != NULL) {
FileName = tardir + "/" + de->d_name;
if (de->d_type == DT_BLK || de->d_type == DT_CHR || backup_exclusions->check_skip_dirs(FileName))
continue;
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))) {
ret = Generate_TarList(FileName, &RegularList, &target_size, &regular_thread_id);
if (ret < 0) {
LOGINFO("Error in Generate_TarList with regular list!\n");
gui_err("backup_error=Error creating backup.");
closedir(d);
close(progress_pipe_fd);
close(progress_pipe[1]);
_exit(-1);
}
file_count = (unsigned long long)(ret);
regular_size += backup_exclusions->Get_Folder_Size(FileName);
} else {
encrypt_size += backup_exclusions->Get_Folder_Size(FileName);
}
} else if (de->d_type == DT_REG) {
stat(FileName.c_str(), &st);
encrypt_size += (unsigned long long)(st.st_size);
}
}
closedir(d);
target_size = encrypt_size / core_count;
target_size++;
LOGINFO(" Unencrypted size: %llu\n", regular_size);
LOGINFO(" Encrypted size : %llu\n", encrypt_size);
LOGINFO(" Target size : %llu\n", target_size);
if (!userdata_encryption) {
enc_thread_id = 0;
start_thread_id = 0;
core_count--;
}
Archive_Current_Size = 0;
d = opendir(tardir.c_str());
if (d == NULL) {
gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(tardir)(strerror(errno)));
close(progress_pipe[1]);
_exit(-1);
}
// Divide up the encrypted file list for threading
while ((de = readdir(d)) != NULL) {
FileName = tardir + "/" + de->d_name;
if (de->d_type == DT_BLK || de->d_type == DT_CHR || backup_exclusions->check_skip_dirs(FileName))
continue;
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))) {
// Do nothing, we added these to RegularList earlier
} else {
FileName = tardir + "/" + de->d_name;
ret = Generate_TarList(FileName, &EncryptList, &target_size, &enc_thread_id);
if (ret < 0) {
LOGINFO("Error in Generate_TarList with encrypted list!\n");
gui_err("backup_error=Error creating backup.");
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);
if (de->d_type == DT_REG)
Archive_Current_Size += (unsigned long long)(st.st_size);
TarItem.fn = FileName;
TarItem.thread_id = enc_thread_id;
EncryptList.push_back(TarItem);
file_count++;
}
}
closedir(d);
if (enc_thread_id != core_count) {
LOGINFO("Error dividing up threads for encryption, %u threads for %u cores!\n", enc_thread_id, core_count);
if (enc_thread_id > core_count) {
gui_err("backup_error=Error creating backup.");
close(progress_pipe[1]);
_exit(-1);
} else {
LOGINFO("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);
reg.ItemList = &RegularList;
reg.thread_id = 0;
reg.use_encryption = 0;
reg.use_compression = use_compression;
reg.split_archives = 1;
reg.progress_pipe_fd = progress_pipe_fd;
reg.part_settings = part_settings;
LOGINFO("Creating unencrypted backup...\n");
if (createList((void*)&reg) != 0) {
LOGINFO("Error creating unencrypted backup.\n");
gui_err("backup_error=Error creating backup.");
close(progress_pipe[1]);
_exit(-1);
}
}
if (pthread_attr_init(&tattr)) {
LOGINFO("Unable to pthread_attr_init\n");
gui_err("backup_error=Error creating backup.");
close(progress_pipe[1]);
_exit(-1);
}
if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
LOGINFO("Error setting pthread_attr_setdetachstate\n");
gui_err("backup_error=Error creating backup.");
close(progress_pipe[1]);
_exit(-1);
}
if (pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM)) {
LOGINFO("Error setting pthread_attr_setscope\n");
gui_err("backup_error=Error creating backup.");
close(progress_pipe[1]);
_exit(-1);
}
/*if (pthread_attr_setstacksize(&tattr, 524288)) {
LOGERR("Error setting pthread_attr_setstacksize\n");
close(progress_pipe[1]);
_exit(-1);
}*/
// Create threads for the divided up encryption lists
for (i = start_thread_id; i <= core_count; i++) {
enc[i].setdir(tardir);
enc[i].setfn(tarfn);
enc[i].ItemList = &EncryptList;
enc[i].thread_id = i;
enc[i].use_encryption = use_encryption;
enc[i].setpassword(password);
enc[i].use_compression = use_compression;
enc[i].split_archives = 1;
enc[i].progress_pipe_fd = progress_pipe_fd;
enc[i].part_settings = part_settings;
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).\n", i, ret);
if (createList((void*)&enc[i]) != 0) {
LOGINFO("Error creating encrypted backup %i.\n", i);
gui_err("backup_error=Error creating backup.");
close(progress_pipe[1]);
_exit(-1);
} else {
enc[i].thread_id = i + 1;
}
}
usleep(100000); // Need a short delay before starting the next thread or the threads will never finish for some reason.
}
if (pthread_attr_destroy(&tattr)) {
LOGINFO("Failed to pthread_attr_destroy\n");
}
for (i = start_thread_id; i <= core_count; i++) {
if (enc[i].thread_id == i) {
if (pthread_join(enc_thread[i], &thread_return)) {
LOGINFO("Error joining thread %i\n", i);
gui_err("backup_error=Error creating backup.");
close(progress_pipe[1]);
_exit(-1);
} else {
LOGINFO("Joined thread %i.\n", i);
ret = (int)(intptr_t)thread_return;
if (ret != 0) {
thread_error = 1;
LOGINFO("Thread %i returned an error %i.\n", i, ret);
gui_err("backup_error=Error creating backup.");
close(progress_pipe[1]);
_exit(-1);
}
}
} else {
LOGINFO("Skipping joining thread %i because of pthread failure.\n", i);
}
}
if (thread_error) {
LOGINFO("Error returned by one or more threads.\n");
gui_err("backup_error=Error creating backup.");
close(progress_pipe[1]);
_exit(-1);
}
LOGINFO("Finished encrypted backup.\n");
close(progress_pipe[1]);
_exit(0);
} else {
// Not encrypted
std::vector<TarListStruct> FileList;
unsigned thread_id = 0;
unsigned long long target_size = 0;
twrpTar reg;
int ret;
// Generate list of files to back up
ret = Generate_TarList(tardir, &FileList, &target_size, &thread_id);
if (ret < 0) {
LOGINFO("Error in Generate_TarList!\n");
gui_err("backup_error=Error creating backup.");
close(progress_pipe[1]);
_exit(-1);
}
file_count = (unsigned long long)(ret);
// Create a backup
reg.setfn(tarfn);
reg.ItemList = &FileList;
reg.thread_id = 0;
reg.use_encryption = 0;
reg.use_compression = use_compression;
reg.setsize(Total_Backup_Size);
reg.progress_pipe_fd = progress_pipe_fd;
reg.part_settings = part_settings;
if (Total_Backup_Size > MAX_ARCHIVE_SIZE && !part_settings->adbbackup) {
gui_msg("split_backup=Breaking backup file into multiple archives...");
reg.split_archives = 1;
} else {
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*)&reg) != 0) {
gui_err("backup_error=Error creating backup.");
close(progress_pipe[1]);
_exit(-1);
}
close(progress_pipe[1]);
_exit(0);
}
} else {
// Parent side
unsigned long long fs, size_backup = 0, files_backup = 0, file_count = 0;
int first_data = 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
first_data = 2;
part_settings->progress->SetSizeCount(fs, file_count);
} else {
if (fs > 0) {
size_backup += fs;
part_settings->progress->UpdateSize(size_backup);
} else { // fs == 0 increments the file counter
files_backup++;
part_settings->progress->UpdateSizeCount(size_backup, files_backup);
}
}
}
close(progress_pipe[0]);
#ifndef BUILD_TWRPTAR_MAIN
DataManager::SetValue("tw_file_progress", "");
DataManager::SetValue("tw_size_progress", "");
part_settings->progress->DisplayFileCount(false);
part_settings->progress->UpdateDisplayDetails(true);
if (!part_settings->adbbackup) {
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", COMPRESSED_ENCRYPTED);
else if (use_encryption)
backup_info.SetValue("backup_type", ENCRYPTED);
else if (use_compression)
backup_info.SetValue("backup_type", COMPRESSED);
else
backup_info.SetValue("backup_type", UNCOMPRESSED);
backup_info.SetValue("file_count", files_backup);
backup_info.SaveValues();
}
#endif //ndef BUILD_TWRPTAR_MAIN
if (TWFunc::Wait_For_Child(*tar_fork_pid, &status, "createTarFork()") != 0)
return -1;
}
return 0;
}
int twrpTar::extractTarFork() {
int status = 0;
pid_t tar_fork_pid;
int progress_pipe[2];
if (pipe(progress_pipe) < 0) {
LOGINFO("Error creating progress tracking pipe\n");
gui_err("restore_error=Error during restore process.");
return -1;
}
tar_fork_pid = fork();
if (tar_fork_pid >= 0) // fork was successful
{
if (tar_fork_pid == 0) // child process
{
close(progress_pipe[0]);
progress_pipe_fd = progress_pipe[1];
if (TWFunc::Path_Exists(tarfn) || part_settings->adbbackup) {
LOGINFO("Single archive\n");
if (extract() != 0)
_exit(-1);
else {
_exit(0);
}
} else {
LOGINFO("Multiple archives\n");
string temp;
char actual_filename[255];
twrpTar tars[9];
pthread_t tar_thread[9];
pthread_attr_t tattr;
unsigned thread_count = 0, i, start_thread_id = 1;
int ret, thread_error = 0;
void *thread_return;
basefn = tarfn;
temp = basefn + "%i%02i";
tarfn += "000";
if (!TWFunc::Path_Exists(tarfn)) {
LOGINFO("Unable to locate '%s' or '%s'\n", basefn.c_str(), tarfn.c_str());
gui_err("restore_error=Error during restore process.");
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;
tars[0].part_settings = part_settings;
if (extractMulti((void*)&tars[0]) != 0) {
LOGINFO("Error extracting split archive.\n");
gui_err("restore_error=Error during restore process.");
close(progress_pipe_fd);
_exit(-1);
}
} else {
start_thread_id = 0;
}
// Start threading encrypted restores
if (pthread_attr_init(&tattr)) {
LOGINFO("Unable to pthread_attr_init\n");
gui_err("restore_error=Error during restore process.");
close(progress_pipe_fd);
_exit(-1);
}
if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
LOGINFO("Error setting pthread_attr_setdetachstate\n");
gui_err("restore_error=Error during restore process.");
close(progress_pipe_fd);
_exit(-1);
}
if (pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM)) {
LOGINFO("Error setting pthread_attr_setscope\n");
gui_err("restore_error=Error during restore process.");
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++) {
sprintf(actual_filename, temp.c_str(), i, 0);
if (TWFunc::Path_Exists(actual_filename)) {
thread_count++;
tars[i].basefn = basefn;
tars[i].setpassword(password);
tars[i].thread_id = i;
tars[i].progress_pipe_fd = progress_pipe_fd;
tars[i].part_settings = part_settings;
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).\n", i, ret);
if (extractMulti((void*)&tars[i]) != 0) {
LOGINFO("Error extracting backup in thread %i.\n", i);
gui_err("restore_error=Error during restore process.");
close(progress_pipe_fd);
_exit(-1);
} else {
tars[i].thread_id = i + 1;
}
}
usleep(100000); // Need a short delay before starting the next thread or the threads will never finish for some reason.
} else {
break;
}
}
for (i = start_thread_id; i < thread_count + start_thread_id; i++) {
if (tars[i].thread_id == i) {
if (pthread_join(tar_thread[i], &thread_return)) {
LOGINFO("Error joining thread %i\n", i);
gui_err("restore_error=Error during restore process.");
close(progress_pipe_fd);
_exit(-1);
} else {
LOGINFO("Joined thread %i.\n", i);
ret = (int)(intptr_t)thread_return;
if (ret != 0) {
thread_error = 1;
LOGINFO("Thread %i returned an error %i.\n", i, ret);
gui_err("restore_error=Error during restore process.");
close(progress_pipe_fd);
_exit(-1);
}
}
} else {
LOGINFO("Skipping joining thread %i because of pthread failure.\n", i);
}
}
if (thread_error) {
LOGINFO("Error returned by one or more threads.\n");
gui_err("restore_error=Error during restore process.");
close(progress_pipe_fd);
_exit(-1);
}
LOGINFO("Finished encrypted restore.\n");
close(progress_pipe_fd);
_exit(0);
}
}
else // parent process
{
unsigned long long fs, 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;
part_settings->progress->UpdateSize(size_backup);
}
close(progress_pipe[0]);
part_settings->progress->UpdateDisplayDetails(true);
if (TWFunc::Wait_For_Child(tar_fork_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;
}
return 0;
}
int twrpTar::Generate_TarList(string Path, std::vector<TarListStruct> *TarList, unsigned long long *Target_Size, unsigned *thread_id) {
DIR* d;
struct dirent* de;
struct stat st;
string FileName;
struct TarListStruct TarItem;
int ret, file_count;
file_count = 0;
d = opendir(Path.c_str());
if (d == NULL) {
gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(Path)(strerror(errno)));
closedir(d);
return -1;
}
while ((de = readdir(d)) != NULL) {
FileName = Path + "/" + de->d_name;
if (de->d_type == DT_BLK || de->d_type == DT_CHR || backup_exclusions->check_skip_dirs(FileName))
continue;
TarItem.fn = FileName;
TarItem.thread_id = *thread_id;
if (de->d_type == DT_DIR) {
TarList->push_back(TarItem);
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) {
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;
}
}
}
closedir(d);
return file_count;
}
int twrpTar::extractTar() {
char* charRootDir = (char*) tardir.c_str();
if (openTar() == -1)
return -1;
if (tar_extract_all(t, charRootDir, &progress_pipe_fd) != 0) {
LOGINFO("Unable to extract tar archive '%s'\n", tarfn.c_str());
gui_err("restore_error=Error during restore process.");
return -1;
}
if (tar_close(t) != 0) {
LOGINFO("Unable to close tar file\n");
gui_err("restore_error=Error during restore process.");
return -1;
}
#ifndef BUILD_TWRPTAR_MAIN
if (part_settings->adbbackup) {
if (!twadbbu::Write_TWEOF())
return -1;
}
#endif
return 0;
}
int twrpTar::extract() {
if (!part_settings->adbbackup) {
LOGINFO("Setting archive type\n");
Set_Archive_Type(TWFunc::Get_File_Type(tarfn));
}
else {
if (part_settings->adb_compression == 1)
current_archive_type = COMPRESSED;
else
current_archive_type = UNCOMPRESSED;
}
if (current_archive_type == COMPRESSED) {
//if you return the extractTGZ function directly, stack crashes happen
LOGINFO("Extracting gzipped tar\n");
int ret = extractTar();
return ret;
} else if (current_archive_type == ENCRYPTED) {
int ret = TWFunc::Try_Decrypting_File(tarfn, password);
if (ret < 1) {
gui_msg(Msg(msg::kError, "fail_decrypt_tar=Failed to decrypt tar file '{1}'")(tarfn));
return -1;
}
if (ret == 1) {
LOGINFO("Decrypted file is not in tar format.\n");
gui_err("restore_error=Error during restore process.");
return -1;
}
if (ret == 3) {
LOGINFO("Extracting encrypted and compressed tar.\n");
current_archive_type = COMPRESSED_ENCRYPTED;
} else
LOGINFO("Extracting encrypted tar.\n");
return extractTar();
} else {
LOGINFO("Extracting uncompressed tar\n");
return extractTar();
}
}
int twrpTar::tarList(std::vector<TarListStruct> *TarList, unsigned thread_id) {
struct stat st;
char buf[PATH_MAX];
int list_size = TarList->size(), i = 0, archive_count = 0;
string temp;
char actual_filename[PATH_MAX];
unsigned long long fs;
if (split_archives) {
basefn = tarfn;
temp = basefn + "%i%02i";
sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
tarfn = actual_filename;
include_root_dir = true;
} else {
include_root_dir = false;
}
if (part_settings->adbbackup)
LOGINFO("Writing tar file '%s' to adb backup\n", tarfn.c_str());
else
LOGINFO("Creating tar file '%s'\n", tarfn.c_str());
if (createTar() != 0) {
LOGINFO("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
gui_err("backup_error=Error creating backup.");
return -2;
}
Archive_Current_Size = 0;
while (i < list_size) {
if (TarList->at(i).thread_id == thread_id) {
strcpy(buf, TarList->at(i).fn.c_str());
lstat(buf, &st);
if (S_ISREG(st.st_mode)) { // item is a regular file
fs = (unsigned long long)(st.st_size);
if (split_archives && Archive_Current_Size + fs > MAX_ARCHIVE_SIZE) {
if (closeTar() != 0) {
LOGINFO("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
gui_err("backup_error=Error creating backup.");
return -3;
}
archive_count++;
gui_msg(Msg("split_thread=Splitting thread ID {1} into archive {2}")(thread_id)(archive_count + 1));
if (archive_count > 99) {
LOGINFO("Too many archives for thread %i\n", thread_id);
gui_err("backup_error=Error creating backup.");
return -4;
}
sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
tarfn = actual_filename;
if (createTar() != 0) {
LOGINFO("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
gui_err("backup_error=Error creating backup.");
return -2;
}
Archive_Current_Size = 0;
}
Archive_Current_Size += fs;
fs = 0; // Sending a 0 size to the pipe tells it to increment the file counter
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) {
LOGINFO("Error adding file '%s' to '%s'\n", buf, tarfn.c_str());
gui_err("backup_error=Error creating backup.");
return -1;
}
}
i++;
}
if (closeTar() != 0) {
LOGINFO("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
gui_err("backup_error=Error creating backup.");
return -3;
}
LOGINFO("Thread id %i tarList done, %i archives.\n", thread_id, archive_count);
return 0;
}
void* twrpTar::createList(void *cookie) {
twrpTar* threadTar = (twrpTar*) cookie;
if (threadTar->tarList(threadTar->ItemList, threadTar->thread_id) != 0) {
LOGINFO("ERROR tarList for thread ID %i\n", threadTar->thread_id);
return (void*)-2;
}
LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
return (void*)0;
}
void* twrpTar::extractMulti(void *cookie) {
twrpTar* threadTar = (twrpTar*) cookie;
int archive_count = 0;
string temp = threadTar->basefn + "%i%02i";
char actual_filename[255];
sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
while (TWFunc::Path_Exists(actual_filename)) {
threadTar->tarfn = actual_filename;
if (threadTar->extract() != 0) {
LOGINFO("Error extracting '%s' in thread ID %i\n", actual_filename, threadTar->thread_id);
return (void*)-2;
}
archive_count++;
if (archive_count > 99)
break;
sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
}
LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
return (void*)0;
}
int twrpTar::addFilesToExistingTar(vector <string> files, string fn) {
char* charTarFile = (char*) fn.c_str();
if (tar_open(&t, charTarFile, NULL, O_CLOEXEC | O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) == -1)
return -1;
removeEOT(charTarFile);
if (tar_open(&t, charTarFile, NULL, O_CLOEXEC | O_WRONLY | O_APPEND | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) == -1)
return -1;
for (unsigned int i = 0; i < files.size(); ++i) {
char* file = (char*) files.at(i).c_str();
if (tar_append_file(t, file, file) == -1)
return -1;
}
if (tar_append_eof(t) == -1)
return -1;
if (tar_close(t) == -1)
return -1;
return 0;
}
int twrpTar::createTar() {
char* charTarFile = (char*) tarfn.c_str();
char* charRootDir = (char*) tardir.c_str();
if (use_encryption && use_compression) {
// Compressed and encrypted
current_archive_type = COMPRESSED_ENCRYPTED;
LOGINFO("Using encryption and compression...\n");
int i, pipes[4];
if (pipe2(pipes, O_CLOEXEC) < 0) {
LOGINFO("Error creating first pipe\n");
gui_err("backup_error=Error creating backup.");
return -1;
}
if (pipe2(pipes + 2, O_CLOEXEC) < 0) {
LOGINFO("Error creating second pipe\n");
gui_err("backup_error=Error creating backup.");
return -1;
}
output_fd = open(tarfn.c_str(), O_CLOEXEC | O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (output_fd < 0) {
gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(tarfn)(strerror(errno)));
for (i = 0; i < 4; i++)
close(pipes[i]); // close all
return -1;
}
pigz_pid = fork();
if (pigz_pid < 0) {
LOGINFO("pigz fork() failed\n");
gui_err("backup_error=Error creating backup.");
close(output_fd);
for (i = 0; i < 4; i++)
close(pipes[i]); // close all
return -1;
} else if (pigz_pid == 0) {
// pigz Child
dup2(pipes[0], STDIN_FILENO);
dup2(pipes[3], STDOUT_FILENO);
if (execlp("pigz", "pigz", "-", NULL) < 0) {
LOGINFO("execlp pigz ERROR!\n");
gui_err("backup_error=Error creating backup.");
_exit(-1);
}
} else {
// Parent
oaes_pid = fork();
if (oaes_pid < 0) {
LOGINFO("openaes fork() failed\n");
gui_err("backup_error=Error creating backup.");
close(output_fd);
for (i = 0; i < 4; i++)
close(pipes[i]); // close all
return -1;
} else if (oaes_pid == 0) {
// openaes Child
dup2(pipes[2], STDIN_FILENO);
dup2(output_fd, STDOUT_FILENO);
if (execlp("openaes", "openaes", "enc", "--key", password.c_str(), NULL) < 0) {
LOGINFO("execlp openaes ERROR!\n");
gui_err("backup_error=Error creating backup.");
_exit(-1);
}
} else {
// Parent
close(pipes[0]);
close(pipes[2]);
close(pipes[3]);
fd = pipes[1];
init_libtar_no_buffer(progress_pipe_fd);
tar_type.writefunc = write_tar_no_buffer;
if (tar_fdopen(&t, fd, charRootDir, &tar_type, O_CLOEXEC | O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) != 0) {
close(fd);
LOGINFO("tar_fdopen failed\n");
gui_err("backup_error=Error creating backup.");
return -1;
}
return 0;
}
}
} else if (use_compression) {
// Compressed
current_archive_type = COMPRESSED;
LOGINFO("Using compression...\n");
int pigzfd[2];
if (part_settings->adbbackup) {
LOGINFO("opening TW_ADB_BACKUP compressed stream\n");
output_fd = open(TW_ADB_BACKUP, O_WRONLY);
}
else {
output_fd = open(tarfn.c_str(), O_CLOEXEC | O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
}
if (output_fd < 0) {
gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(tarfn)(strerror(errno)));
return -1;
}
if (pipe2(pigzfd, O_CLOEXEC) < 0) {
LOGINFO("Error creating pipe\n");
gui_err("backup_error=Error creating backup.");
close(output_fd);
return -1;
}
pigz_pid = fork();
if (pigz_pid < 0) {
LOGINFO("fork() failed\n");
gui_err("backup_error=Error creating backup.");
close(output_fd);
close(pigzfd[0]);
close(pigzfd[1]);
return -1;
} else if (pigz_pid == 0) {
// Child
dup2(pigzfd[0], STDIN_FILENO); // remap stdin
dup2(output_fd, STDOUT_FILENO); // remap stdout to output file
if (execlp("pigz", "pigz", "-", NULL) < 0) {
LOGINFO("execlp pigz ERROR!\n");
gui_err("backup_error=Error creating backup.");
_exit(-1);
}
} else {
// Parent
close(pigzfd[0]); // close parent input
fd = pigzfd[1]; // copy parent output
init_libtar_no_buffer(progress_pipe_fd);
tar_type.writefunc = write_tar_no_buffer;
if (tar_fdopen(&t, fd, charRootDir, &tar_type, O_CLOEXEC | O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) != 0) {
close(fd);
LOGINFO("tar_fdopen failed\n");
gui_err("backup_error=Error creating backup.");
return -1;
}
}
} else if (use_encryption) {
// Encrypted
current_archive_type = ENCRYPTED;
LOGINFO("Using encryption...\n");
int oaesfd[2];
output_fd = open(tarfn.c_str(), O_CLOEXEC | O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (output_fd < 0) {
gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(tarfn)(strerror(errno)));
return -1;
}
if (pipe2(oaesfd, O_CLOEXEC) < 0) {
LOGINFO("Error creating pipe\n");
gui_err("backup_error=Error creating backup.");
close(output_fd);
return -1;
}
oaes_pid = fork();
if (oaes_pid < 0) {
LOGINFO("fork() failed\n");
gui_err("backup_error=Error creating backup.");
close(output_fd);
close(oaesfd[0]);
close(oaesfd[1]);
return -1;
} else if (oaes_pid == 0) {
// Child
dup2(oaesfd[0], STDIN_FILENO); // remap stdin
dup2(output_fd, STDOUT_FILENO); // remap stdout to output file
if (execlp("openaes", "openaes", "enc", "--key", password.c_str(), NULL) < 0) {
LOGINFO("execlp openaes ERROR!\n");
gui_err("backup_error=Error creating backup.");
_exit(-1);
}
} else {
// Parent
close(oaesfd[0]); // close parent input
fd = oaesfd[1]; // copy parent output
init_libtar_no_buffer(progress_pipe_fd);
tar_type.writefunc = write_tar_no_buffer;
if (tar_fdopen(&t, fd, charRootDir, &tar_type, O_CLOEXEC | O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) != 0) {
close(fd);
LOGINFO("tar_fdopen failed\n");
gui_err("backup_error=Error creating backup.");
return -1;
}
return 0;
}
} else {
// Not compressed or encrypted
current_archive_type = UNCOMPRESSED;
init_libtar_buffer(0, progress_pipe_fd);
if (part_settings->adbbackup) {
LOGINFO("Opening TW_ADB_BACKUP uncompressed stream\n");
tar_type.writefunc = write_tar_no_buffer;
output_fd = open(TW_ADB_BACKUP, O_WRONLY);
if(tar_fdopen(&t, output_fd, charRootDir, &tar_type, O_CLOEXEC | O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) != 0) {
close(output_fd);
LOGERR("tar_fdopen failed\n");
return -1;
}
}
else {
tar_type.writefunc = write_tar;
if (tar_open(&t, charTarFile, &tar_type, O_CLOEXEC | O_WRONLY | O_CREAT | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) == -1) {
LOGERR("tar_open error opening '%s'\n", tarfn.c_str());
gui_err("backup_error=Error creating backup.");
return -1;
}
}
}
return 0;
}
int twrpTar::openTar() {
char* charRootDir = (char*) tardir.c_str();
char* charTarFile = (char*) tarfn.c_str();
string Password;
if (current_archive_type == COMPRESSED_ENCRYPTED) {
LOGINFO("Opening encrypted and compressed backup...\n");
int i, pipes[4];
input_fd = open(tarfn.c_str(), O_CLOEXEC | O_RDONLY | O_LARGEFILE);
if (input_fd < 0) {
gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(tarfn)(strerror(errno)));
return -1;
}
if (pipe2(pipes, O_CLOEXEC) < 0) {
LOGINFO("Error creating first pipe\n");
gui_err("restore_error=Error during restore process.");
close(input_fd);
return -1;
}
if (pipe2(pipes + 2, O_CLOEXEC) < 0) {
LOGINFO("Error creating second pipe\n");
gui_err("restore_error=Error during restore process.");
close(pipes[0]);
close(pipes[1]);
close(input_fd);
return -1;
}
oaes_pid = fork();
if (oaes_pid < 0) {
LOGINFO("pigz fork() failed\n");
gui_err("restore_error=Error during restore process.");
close(input_fd);
for (i = 0; i < 4; i++)
close(pipes[i]); // close all
return -1;
} else if (oaes_pid == 0) {
// openaes Child
dup2(input_fd, STDIN_FILENO);
dup2(pipes[1], STDOUT_FILENO);
if (execlp("openaes", "openaes", "dec", "--key", password.c_str(), NULL) < 0) {
LOGINFO("execlp openaes ERROR!\n");
gui_err("restore_error=Error during restore process.");
_exit(-1);
}
} else {
// Parent
pigz_pid = fork();
if (pigz_pid < 0) {
LOGINFO("openaes fork() failed\n");
gui_err("restore_error=Error during restore process.");
close(input_fd);
for (i = 0; i < 4; i++)
close(pipes[i]); // close all
return -1;
} else if (pigz_pid == 0) {
// pigz Child
dup2(pipes[0], STDIN_FILENO);
dup2(pipes[3], STDOUT_FILENO);
if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
LOGINFO("execlp pigz ERROR!\n");
gui_err("restore_error=Error during restore process.");
_exit(-1);
}
} else {
// Parent
close(pipes[0]); // Close pipes not used by parent
close(pipes[1]);
close(pipes[3]);
fd = pipes[2];
if (tar_fdopen(&t, fd, charRootDir, NULL, O_CLOEXEC | O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) != 0) {
close(fd);
LOGINFO("tar_fdopen failed\n");
gui_err("restore_error=Error during restore process.");
return -1;
}
}
}
} else if (current_archive_type == ENCRYPTED) {
LOGINFO("Opening encrypted backup...\n");
int oaesfd[2];
input_fd = open(tarfn.c_str(), O_CLOEXEC | O_RDONLY | O_LARGEFILE);
if (input_fd < 0) {
gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(tarfn)(strerror(errno)));
return -1;
}
if (pipe2(oaesfd, O_CLOEXEC) < 0) {
LOGINFO("Error creating pipe\n");
gui_err("restore_error=Error during restore process.");
close(input_fd);
return -1;
}
oaes_pid = fork();
if (oaes_pid < 0) {
LOGINFO("fork() failed\n");
gui_err("restore_error=Error during restore process.");
close(input_fd);
close(oaesfd[0]);
close(oaesfd[1]);
return -1;
} else if (oaes_pid == 0) {
// Child
dup2(oaesfd[1], STDOUT_FILENO); // remap stdout
dup2(input_fd, STDIN_FILENO); // remap input fd to stdin
if (execlp("openaes", "openaes", "dec", "--key", password.c_str(), NULL) < 0) {
LOGINFO("execlp openaes ERROR!\n");
gui_err("restore_error=Error during restore process.");
_exit(-1);
}
} else {
// Parent
close(oaesfd[1]); // close parent output
fd = oaesfd[0]; // copy parent input
if (tar_fdopen(&t, fd, charRootDir, NULL, O_CLOEXEC | O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) != 0) {
close(fd);
LOGINFO("tar_fdopen failed\n");
gui_err("restore_error=Error during restore process.");
return -1;
}
}
} else if (current_archive_type == COMPRESSED) {
int pigzfd[2];
LOGINFO("Opening gzip compressed tar...\n");
if (part_settings->adbbackup) {
LOGINFO("opening TW_ADB_RESTORE compressed stream\n");
input_fd = open(TW_ADB_RESTORE, O_CLOEXEC | O_RDONLY | O_LARGEFILE);
}
else
input_fd = open(tarfn.c_str(), O_CLOEXEC | O_RDONLY | O_LARGEFILE);
if (input_fd < 0) {
gui_msg(Msg(msg::kError, "error_opening_strerr=Error opening: '{1}' ({2})")(tarfn)(strerror(errno)));
return -1;
}
if (pipe2(pigzfd, O_CLOEXEC) < 0) {
LOGINFO("Error creating pipe\n");
gui_err("restore_error=Error during restore process.");
close(input_fd);
return -1;
}
pigz_pid = fork();
if (pigz_pid < 0) {
LOGINFO("fork() failed\n");
gui_err("restore_error=Error during restore process.");
close(input_fd);
close(pigzfd[0]);
close(pigzfd[1]);
return -1;
} else if (pigz_pid == 0) {
// Child
dup2(pigzfd[1], STDOUT_FILENO); // remap stdout
dup2(input_fd, STDIN_FILENO); // remap input fd to stdin
if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
LOGINFO("execlp pigz ERROR!\n");
gui_err("restore_error=Error during restore process.");
_exit(-1);
}
} else {
// Parent
close(pigzfd[1]); // close parent output
fd = pigzfd[0]; // copy parent input
if (tar_fdopen(&t, fd, charRootDir, NULL, O_CLOEXEC | O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) != 0) {
close(fd);
LOGINFO("tar_fdopen failed\n");
gui_err("restore_error=Error during restore process.");
return -1;
}
}
} else {
if (part_settings->adbbackup) {
LOGINFO("Opening TW_ADB_RESTORE uncompressed stream\n");
input_fd = open(TW_ADB_RESTORE, O_RDONLY);
if (tar_fdopen(&t, input_fd, charRootDir, NULL, O_CLOEXEC | O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) != 0) {
LOGERR("Unable to open tar archive '%s'\n", charTarFile);
gui_err("restore_error=Error during restore process.");
return -1;
}
}
else {
if (tar_open(&t, charTarFile, NULL, O_CLOEXEC | O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TWTAR_FLAGS) != 0) {
LOGERR("Unable to open tar archive '%s'\n", charTarFile);
gui_err("restore_error=Error during restore process.");
return -1;
}
}
}
return 0;
}
string twrpTar::Strip_Root_Dir(string Path) {
string temp;
size_t slash;
if (Path.substr(0, 1) == "/")
temp = Path.substr(1, Path.size() - 1);
else
temp = Path;
slash = temp.find("/");
if (slash == string::npos)
return temp;
else {
string stripped;
stripped = temp.substr(slash, temp.size() - slash);
return stripped;
}
return temp;
}
int twrpTar::addFile(string fn, bool include_root) {
char* charTarFile = (char*) fn.c_str();
if (include_root) {
if (tar_append_file(t, charTarFile, NULL) == -1)
return -1;
} else {
string temp = Strip_Root_Dir(fn);
char* charTarPath = (char*) temp.c_str();
if (tar_append_file(t, charTarFile, charTarPath) == -1)
return -1;
}
return 0;
}
int twrpTar::closeTar() {
LOGINFO("Closing tar\n");
flush_libtar_buffer(t->fd);
if (tar_append_eof(t) != 0) {
LOGINFO("tar_append_eof(): %s\n", strerror(errno));
tar_close(t);
return -1;
}
if (tar_close(t) != 0) {
LOGINFO("Unable to close tar archive: '%s'\n", tarfn.c_str());
return -1;
}
if (current_archive_type > 0) {
int status;
if (pigz_pid > 0 && TWFunc::Wait_For_Child(pigz_pid, &status, "pigz") != 0)
return -1;
if (oaes_pid > 0 && TWFunc::Wait_For_Child(oaes_pid, &status, "openaes") != 0)
return -1;
}
free_libtar_buffer();
if (!part_settings->adbbackup) {
if (use_compression && !use_encryption) {
string gzname = tarfn + ".gz";
if (TWFunc::Path_Exists(gzname)) {
rename(gzname.c_str(), tarfn.c_str());
}
}
if (TWFunc::Get_File_Size(tarfn) == 0) {
gui_msg(Msg(msg::kError, "backup_size=Backup file size for '{1}' is 0 bytes.")(tarfn));
return -1;
}
#ifndef BUILD_TWRPTAR_MAIN
tw_set_default_metadata(tarfn.c_str());
#endif
}
else {
#ifndef BUILD_TWRPTAR_MAIN
if (!twadbbu::Write_TWEOF())
return -1;
#endif
}
if (input_fd >= 0)
close(input_fd);
if (output_fd >= 0)
close(output_fd);
return 0;
}
int twrpTar::removeEOT(string tarFile) {
char* charTarFile = (char*) tarFile.c_str();
off_t tarFileEnd = 0;
while (th_read(t) == 0) {
if (TH_ISREG(t))
tar_skip_regfile(t);
tarFileEnd = lseek(t->fd, 0, SEEK_CUR);
}
if (tar_close(t) == -1)
return -1;
if (tarFileEnd > 0 && truncate(charTarFile, tarFileEnd) == -1)
return -1;
return 0;
}
int twrpTar::entryExists(string entry) {
char* searchstr = (char*)entry.c_str();
int ret;
Set_Archive_Type(TWFunc::Get_File_Type(tarfn));
if (openTar() == -1)
ret = 0;
else
ret = tar_find(t, searchstr);
if (closeTar() != 0)
LOGINFO("Unable to close tar after searching for entry.\n");
return ret;
}
unsigned long long twrpTar::get_size() {
if (part_settings->adbbackup || TWFunc::Path_Exists(tarfn)) {
LOGINFO("Single archive\n");
return uncompressedSize(tarfn);
} else {
LOGINFO("Multiple archives\n");
string temp;
char actual_filename[255];
int archive_count = 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 (!part_settings->adbbackup) {
if (!TWFunc::Path_Exists(actual_filename)) {
LOGERR("Unable to locate '%s' or '%s'\n", basefn.c_str(), tarfn.c_str());
return 0;
}
for (int 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);
archive_count++;
if (archive_count > 99)
break;
sprintf(actual_filename, temp.c_str(), i, archive_count);
}
}
#ifndef BUILD_TWRPTAR_MAIN
if (!part_settings->adbbackup) {
InfoManager backup_info(tarfn + ".info");
backup_info.SetValue("backup_size", total_restore_size);
backup_info.SetValue("backup_type", current_archive_type);
backup_info.SaveValues();
}
#endif //ndef BUILD_TWRPTAR_MAIN
}
return total_restore_size;
}
return 0;
}
unsigned long long twrpTar::uncompressedSize(string filename) {
unsigned long long total_size = 0;
string Tar, Command, result;
vector<string> split;
Set_Archive_Type(TWFunc::Get_File_Type(tarfn));
if (current_archive_type == UNCOMPRESSED) {
total_size = TWFunc::Get_File_Size(filename);
} else if (current_archive_type == COMPRESSED) {
// 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, false);
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());
}
} else if (current_archive_type == COMPRESSED_ENCRYPTED) {
// File is encrypted and may be compressed
int ret = TWFunc::Try_Decrypting_File(filename, password);
if (ret < 1) {
gui_msg(Msg(msg::kError, "fail_decrypt_tar=Failed to decrypt tar file '{1}'")(tarfn));
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) {
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, false);
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);
}
extern "C" ssize_t write_tar_no_buffer(int fd, const void *buffer, size_t size) {
return (ssize_t) write_libtar_no_buffer(fd, buffer, size);
}