Will also set overlay to lockscreen so we don't have inadvetent screen selections. Touching the screen will bring the display back up. add back check script for poweroff move diff time function to twrp-functions.cpp make sure we chmod after copy_file add read_file and write_file functions to twrp-functions.cpp make single thread try to force update screen add forceRender drop caches after tar processing Change-Id: I3c5c509dd39dbb05451bbfe5d8b56d53c90d8d1b
492 lines
12 KiB
C++
492 lines
12 KiB
C++
/*
|
|
Copyright 2012 bigbiff/Dees_Troy TeamWin
|
|
This file is part of TWRP/TeamWin Recovery Project.
|
|
|
|
TWRP is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
TWRP is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with TWRP. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
extern "C" {
|
|
#include "libtar/libtar.h"
|
|
#include "twrpTar.h"
|
|
#include "tarWrite.h"
|
|
#include "libcrecovery/common.h"
|
|
}
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <dirent.h>
|
|
#include <sys/mman.h>
|
|
#include "twrpTar.hpp"
|
|
#include "common.h"
|
|
#include "data.hpp"
|
|
#include "variables.h"
|
|
#include "twrp-functions.hpp"
|
|
|
|
using namespace std;
|
|
|
|
void twrpTar::setfn(string fn) {
|
|
tarfn = fn;
|
|
}
|
|
|
|
void twrpTar::setdir(string dir) {
|
|
tardir = dir;
|
|
}
|
|
|
|
int twrpTar::createTarGZThread() {
|
|
pthread_t thread;
|
|
ThreadPtr tarptr = &twrpTar::createTGZ;
|
|
PThreadPtr p = *(PThreadPtr*)&tarptr;
|
|
pthread_create(&thread, NULL, p, this);
|
|
if(pthread_join(thread, NULL)) {
|
|
return -1;
|
|
}
|
|
TWFunc::drop_caches();
|
|
return 0;
|
|
}
|
|
|
|
int twrpTar::createTarThread() {
|
|
pthread_t thread;
|
|
ThreadPtr tarptr = &twrpTar::create;
|
|
PThreadPtr p = *(PThreadPtr*)&tarptr;
|
|
pthread_create(&thread, NULL, p, this);
|
|
if(pthread_join(thread, NULL)) {
|
|
return -1;
|
|
}
|
|
TWFunc::drop_caches();
|
|
return 0;
|
|
}
|
|
|
|
int twrpTar::extractTarThread() {
|
|
pthread_t thread;
|
|
ThreadPtr tarptr = &twrpTar::extract;
|
|
PThreadPtr p = *(PThreadPtr*)&tarptr;
|
|
pthread_create(&thread, NULL, p, this);
|
|
if(pthread_join(thread, NULL)) {
|
|
return -1;
|
|
}
|
|
TWFunc::drop_caches();
|
|
return 0;
|
|
}
|
|
|
|
int twrpTar::splitArchiveThread() {
|
|
pthread_t thread;
|
|
ThreadPtr tarptr = &twrpTar::Split_Archive;
|
|
PThreadPtr p = *(PThreadPtr*)&tarptr;
|
|
pthread_create(&thread, NULL, p, this);
|
|
if(pthread_join(thread, NULL)) {
|
|
return -1;
|
|
}
|
|
TWFunc::drop_caches();
|
|
return 0;
|
|
}
|
|
|
|
int twrpTar::Generate_Multiple_Archives(string Path) {
|
|
DIR* d;
|
|
struct dirent* de;
|
|
struct stat st;
|
|
string FileName;
|
|
char actual_filename[255];
|
|
|
|
if (has_data_media == 1 && Path.size() >= 11 && strncmp(Path.c_str(), "/data/media", 11) == 0)
|
|
return 0; // Skip /data/media
|
|
LOGI("Path: '%s', archive filename: '%s'\n", Path.c_str(), tarfn.c_str());
|
|
|
|
d = opendir(Path.c_str());
|
|
if (d == NULL)
|
|
{
|
|
LOGE("error opening '%s' -- error: %s\n", Path.c_str(), strerror(errno));
|
|
closedir(d);
|
|
return -1;
|
|
}
|
|
while ((de = readdir(d)) != NULL)
|
|
{
|
|
FileName = Path + "/";
|
|
FileName += de->d_name;
|
|
if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
|
|
continue; // Skip /data/media
|
|
if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
|
|
{
|
|
unsigned long long folder_size = TWFunc::Get_Folder_Size(FileName, false);
|
|
tardir = FileName;
|
|
if (Archive_Current_Size + folder_size > MAX_ARCHIVE_SIZE) {
|
|
LOGI("Calling Generate_Multiple_Archives\n");
|
|
if (Generate_Multiple_Archives(FileName) < 0)
|
|
return -1;
|
|
} else {
|
|
//FileName += "/";
|
|
LOGI("Adding folder '%s'\n", FileName.c_str());
|
|
tardir = FileName;
|
|
if (tarDirs(true) < 0)
|
|
return -1;
|
|
Archive_Current_Size += folder_size;
|
|
}
|
|
}
|
|
else if (de->d_type == DT_REG || de->d_type == DT_LNK)
|
|
{
|
|
stat(FileName.c_str(), &st);
|
|
|
|
if (Archive_Current_Size != 0 && Archive_Current_Size + st.st_size > MAX_ARCHIVE_SIZE) {
|
|
LOGI("Closing tar '%s', ", tarfn.c_str());
|
|
closeTar(false);
|
|
reinit_libtar_buffer();
|
|
if (TWFunc::Get_File_Size(tarfn) == 0) {
|
|
LOGE("Backup file size for '%s' is 0 bytes.\n", tarfn.c_str());
|
|
return -1;
|
|
}
|
|
Archive_File_Count++;
|
|
if (Archive_File_Count > 999) {
|
|
LOGE("Archive count is too large!\n");
|
|
return -1;
|
|
}
|
|
string temp = basefn + "%03i";
|
|
sprintf(actual_filename, temp.c_str(), Archive_File_Count);
|
|
tarfn = actual_filename;
|
|
Archive_Current_Size = 0;
|
|
LOGI("Creating tar '%s'\n", tarfn.c_str());
|
|
ui_print("Creating archive %i...\n", Archive_File_Count + 1);
|
|
if (createTar() != 0)
|
|
return -1;
|
|
}
|
|
LOGI("Adding file: '%s'... ", FileName.c_str());
|
|
if (addFile(FileName, true) < 0)
|
|
return -1;
|
|
Archive_Current_Size += st.st_size;
|
|
LOGI("added successfully, archive size: %llu\n", Archive_Current_Size);
|
|
if (st.st_size > 2147483648LL)
|
|
LOGE("There is a file that is larger than 2GB in the file system\n'%s'\nThis file may not restore properly\n", FileName.c_str());
|
|
}
|
|
}
|
|
closedir(d);
|
|
return 0;
|
|
}
|
|
|
|
int twrpTar::Split_Archive()
|
|
{
|
|
string temp = tarfn + "%03i";
|
|
char actual_filename[255];
|
|
|
|
basefn = tarfn;
|
|
Archive_File_Count = 0;
|
|
Archive_Current_Size = 0;
|
|
sprintf(actual_filename, temp.c_str(), Archive_File_Count);
|
|
tarfn = actual_filename;
|
|
init_libtar_buffer(0);
|
|
createTar();
|
|
DataManager::GetValue(TW_HAS_DATA_MEDIA, has_data_media);
|
|
ui_print("Creating archive 1...\n");
|
|
if (Generate_Multiple_Archives(tardir) < 0) {
|
|
LOGE("Error generating multiple archives\n");
|
|
free_libtar_buffer();
|
|
return -1;
|
|
}
|
|
closeTar(false);
|
|
free_libtar_buffer();
|
|
LOGI("Done, created %i archives.\n", (Archive_File_Count++));
|
|
return (Archive_File_Count);
|
|
}
|
|
|
|
int twrpTar::extractTar() {
|
|
char* charRootDir = (char*) tardir.c_str();
|
|
bool gzip = false;
|
|
if (openTar(gzip) == -1)
|
|
return -1;
|
|
if (tar_extract_all(t, charRootDir) != 0) {
|
|
LOGE("Unable to extract tar archive '%s'\n", tarfn.c_str());
|
|
return -1;
|
|
}
|
|
if (tar_close(t) != 0) {
|
|
LOGE("Unable to close tar file\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int twrpTar::extract() {
|
|
int len = 3;
|
|
char header[len];
|
|
string::size_type i = 0;
|
|
int firstbyte = 0;
|
|
int secondbyte = 0;
|
|
int ret;
|
|
ifstream f;
|
|
f.open(tarfn.c_str(), ios::in | ios::binary);
|
|
f.get(header, len);
|
|
firstbyte = header[i] & 0xff;
|
|
secondbyte = header[++i] & 0xff;
|
|
f.close();
|
|
if (firstbyte == 0x1f && secondbyte == 0x8b) {
|
|
//if you return the extractTGZ function directly, stack crashes happen
|
|
LOGI("Extracting gzipped tar\n");
|
|
ret = extractTGZ();
|
|
return ret;
|
|
}
|
|
else {
|
|
LOGI("Extracting uncompressed tar\n");
|
|
return extractTar();
|
|
}
|
|
}
|
|
|
|
int twrpTar::tarDirs(bool include_root) {
|
|
DIR* d;
|
|
string mainfolder = tardir + "/", subfolder;
|
|
char buf[1024];
|
|
char* charTarFile = (char*) tarfn.c_str();
|
|
d = opendir(tardir.c_str());
|
|
if (d != NULL) {
|
|
struct dirent* de;
|
|
while ((de = readdir(d)) != NULL) {
|
|
LOGI("adding %s\n", de->d_name);
|
|
#ifdef RECOVERY_SDCARD_ON_DATA
|
|
if ((tardir == "/data" || tardir == "/data/") && strcmp(de->d_name, "media") == 0) continue;
|
|
#endif
|
|
if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue;
|
|
|
|
subfolder = mainfolder;
|
|
subfolder += de->d_name;
|
|
strcpy(buf, subfolder.c_str());
|
|
if (de->d_type == DT_DIR) {
|
|
if (include_root) {
|
|
if (tar_append_tree(t, buf, NULL) != 0) {
|
|
LOGE("Error appending '%s' to tar archive '%s'\n", buf, charTarFile);
|
|
return -1;
|
|
}
|
|
} else {
|
|
string temp = Strip_Root_Dir(buf);
|
|
char* charTarPath = (char*) temp.c_str();
|
|
if (tar_append_tree(t, buf, charTarPath) != 0) {
|
|
LOGE("Error appending '%s' to tar archive '%s'\n", buf, charTarFile);
|
|
return -1;
|
|
}
|
|
}
|
|
} else if (tardir != "/" && (de->d_type == DT_REG || de->d_type == DT_LNK)) {
|
|
if (addFile(buf, include_root) != 0)
|
|
return -1;
|
|
}
|
|
fflush(NULL);
|
|
}
|
|
closedir(d);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int twrpTar::createTGZ() {
|
|
bool gzip = true;
|
|
|
|
init_libtar_buffer(0);
|
|
if (createTar() == -1)
|
|
return -1;
|
|
if (tarDirs(false) == -1)
|
|
return -1;
|
|
if (closeTar(gzip) == -1)
|
|
return -1;
|
|
free_libtar_buffer();
|
|
return 0;
|
|
}
|
|
|
|
int twrpTar::create() {
|
|
bool gzip = false;
|
|
|
|
init_libtar_buffer(0);
|
|
if (createTar() == -1)
|
|
return -1;
|
|
if (tarDirs(false) == -1)
|
|
return -1;
|
|
if (closeTar(gzip) == -1)
|
|
return -1;
|
|
free_libtar_buffer();
|
|
return 0;
|
|
}
|
|
|
|
int twrpTar::addFilesToExistingTar(vector <string> files, string fn) {
|
|
char* charTarFile = (char*) fn.c_str();
|
|
static tartype_t type = { open, close, read, write_tar };
|
|
|
|
init_libtar_buffer(0);
|
|
if (tar_open(&t, charTarFile, &type, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) == -1)
|
|
return -1;
|
|
removeEOT(charTarFile);
|
|
if (tar_open(&t, charTarFile, &type, O_WRONLY | O_APPEND | O_LARGEFILE, 0644, TAR_GNU) == -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;
|
|
}
|
|
flush_libtar_buffer(t->fd);
|
|
if (tar_append_eof(t) == -1)
|
|
return -1;
|
|
if (tar_close(t) == -1)
|
|
return -1;
|
|
free_libtar_buffer();
|
|
return 0;
|
|
}
|
|
|
|
int twrpTar::createTar() {
|
|
char* charTarFile = (char*) tarfn.c_str();
|
|
char* charRootDir = (char*) tardir.c_str();
|
|
int use_compression = 0;
|
|
static tartype_t type = { open, close, read, write_tar };
|
|
|
|
DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression);
|
|
if (use_compression) {
|
|
string cmd = "pigz - > '" + tarfn + "'";
|
|
p = __popen(cmd.c_str(), "w");
|
|
fd = fileno(p);
|
|
if (!p) return -1;
|
|
if(tar_fdopen(&t, fd, charRootDir, &type, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) != 0) {
|
|
pclose(p);
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
if (tar_open(&t, charTarFile, &type, O_WRONLY | O_CREAT | O_LARGEFILE, 0644, TAR_GNU) == -1)
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int twrpTar::openTar(bool gzip) {
|
|
char* charRootDir = (char*) tardir.c_str();
|
|
char* charTarFile = (char*) tarfn.c_str();
|
|
|
|
if (gzip) {
|
|
LOGI("Opening as a gzip\n");
|
|
string cmd = "pigz -d -c '" + tarfn + "'";
|
|
FILE* pipe = __popen(cmd.c_str(), "r");
|
|
int fd = fileno(pipe);
|
|
if (!pipe) return -1;
|
|
if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) != 0) {
|
|
LOGI("tar_fdopen returned error\n");
|
|
__pclose(pipe);
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) != 0) {
|
|
LOGE("Unable to open tar archive '%s'\n", charTarFile);
|
|
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(bool gzip) {
|
|
int use_compression;
|
|
DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression);
|
|
|
|
flush_libtar_buffer(t->fd);
|
|
if (tar_append_eof(t) != 0) {
|
|
LOGE("tar_append_eof(): %s\n", strerror(errno));
|
|
tar_close(t);
|
|
return -1;
|
|
}
|
|
if (tar_close(t) != 0) {
|
|
LOGE("Unable to close tar archive: '%s'\n", tarfn.c_str());
|
|
return -1;
|
|
}
|
|
if (use_compression || gzip) {
|
|
LOGI("Closing popen and fd\n");
|
|
pclose(p);
|
|
close(fd);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int twrpTar::removeEOT(string tarFile) {
|
|
char* charTarFile = (char*) tarFile.c_str();
|
|
off_t tarFileEnd;
|
|
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 (truncate(charTarFile, tarFileEnd) == -1)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
int twrpTar::compress(string fn) {
|
|
string cmd = "pigz " + fn;
|
|
p = __popen(cmd.c_str(), "r");
|
|
if (!p) return -1;
|
|
char buffer[128];
|
|
string result = "";
|
|
while(!feof(p)) {
|
|
if(fgets(buffer, 128, p) != NULL)
|
|
result += buffer;
|
|
}
|
|
__pclose(p);
|
|
return 0;
|
|
}
|
|
|
|
int twrpTar::extractTGZ() {
|
|
string splatrootdir(tardir);
|
|
bool gzip = true;
|
|
char* splatCharRootDir = (char*) splatrootdir.c_str();
|
|
if (openTar(gzip) == -1)
|
|
return -1;
|
|
int ret = tar_extract_all(t, splatCharRootDir);
|
|
if (tar_close(t) != 0) {
|
|
LOGE("Unable to close tar file\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
extern "C" ssize_t write_tar(int fd, const void *buffer, size_t size) {
|
|
return (ssize_t) write_libtar_buffer(fd, buffer, size);
|
|
}
|