Files
android_bootable_recovery/twrpTar.cpp
bigbiff bigbiff 8a68c31ffc This adds a 60 second screen timeout for TWRP. Might consider making this configurable in the future.
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
2013-02-13 13:16:03 -06:00

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);
}