blob: 78409c7e11e928e34c0017e69f5b3d2b0aee1e16 [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/*
2 Copyright 2012 bigbiff/Dees_Troy TeamWin
3 This file is part of TWRP/TeamWin Recovery Project.
4
5 TWRP is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 TWRP is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19extern "C" {
20 #include "libtar/libtar.h"
21}
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <string.h>
25#include <errno.h>
26#include <fcntl.h>
27#include <fstream>
28#include <fstream>
29#include <iostream>
30#include <string>
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050031#include <sstream>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050032#include <dirent.h>
33#include <sys/mman.h>
34#include "twrpTar.hpp"
35#include "common.h"
36#include "data.hpp"
37#include "variables.h"
bigbiff bigbiff9c754052013-01-09 09:09:08 -050038#include "twrp-functions.hpp"
39
40using namespace std;
41
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050042void twrpTar::setfn(string fn) {
43 tarfn = fn;
44}
45
46void twrpTar::setdir(string dir) {
47 tardir = dir;
48}
49
50int twrpTar::createTarGZThread() {
51 pthread_t thread;
52 ThreadPtr tarptr = &twrpTar::createTGZ;
53 PThreadPtr p = *(PThreadPtr*)&tarptr;
54 pthread_create(&thread, NULL, p, this);
55 if(pthread_join(thread, NULL)) {
56 return -1;
57 }
58 return 0;
59}
60
61int twrpTar::createTarThread() {
62 pthread_t thread;
63 ThreadPtr tarptr = &twrpTar::create;
64 PThreadPtr p = *(PThreadPtr*)&tarptr;
65 pthread_create(&thread, NULL, p, this);
66 if(pthread_join(thread, NULL)) {
67 return -1;
68 }
69 return 0;
70}
71
72int twrpTar::extractTarThread() {
73 pthread_t thread;
74 ThreadPtr tarptr = &twrpTar::extract;
75 PThreadPtr p = *(PThreadPtr*)&tarptr;
76 pthread_create(&thread, NULL, p, this);
77 if(pthread_join(thread, NULL)) {
78 return -1;
79 }
80 return 0;
81}
82
83int twrpTar::splitArchiveThread() {
84 pthread_t thread;
85 ThreadPtr tarptr = &twrpTar::Split_Archive;
86 PThreadPtr p = *(PThreadPtr*)&tarptr;
87 pthread_create(&thread, NULL, p, this);
88 if(pthread_join(thread, NULL)) {
89 return -1;
90 }
91 return 0;
92}
93
94int twrpTar::Generate_Multiple_Archives(string Path) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -050095 DIR* d;
96 struct dirent* de;
97 struct stat st;
98 string FileName;
99 char actual_filename[255];
100
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500101 if (has_data_media == 1 && Path.size() >= 11 && strncmp(Path.c_str(), "/data/media", 11) == 0)
102 return 0; // Skip /data/media
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500103 LOGI("Path: '%s', archive filename: '%s'\n", Path.c_str(), tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500104
105 d = opendir(Path.c_str());
106 if (d == NULL)
107 {
108 LOGE("error opening '%s' -- error: %s\n", Path.c_str(), strerror(errno));
109 closedir(d);
110 return -1;
111 }
112 while ((de = readdir(d)) != NULL)
113 {
114 FileName = Path + "/";
115 FileName += de->d_name;
116 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
117 continue; // Skip /data/media
118 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
119 {
120 unsigned long long folder_size = TWFunc::Get_Folder_Size(FileName, false);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500121 tardir = FileName;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500122 if (Archive_Current_Size + folder_size > MAX_ARCHIVE_SIZE) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500123 LOGI("Calling Generate_Multiple_Archives\n");
124 if (Generate_Multiple_Archives(FileName) < 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500125 return -1;
126 } else {
127 //FileName += "/";
128 LOGI("Adding folder '%s'\n", FileName.c_str());
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500129 tardir = FileName;
130 if (tarDirs(true) < 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500131 return -1;
132 Archive_Current_Size += folder_size;
133 }
134 }
135 else if (de->d_type == DT_REG || de->d_type == DT_LNK)
136 {
137 stat(FileName.c_str(), &st);
138
139 if (Archive_Current_Size != 0 && Archive_Current_Size + st.st_size > MAX_ARCHIVE_SIZE) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500140 LOGI("Closing tar '%s', ", tarfn.c_str());
141 closeTar(false);
142 if (TWFunc::Get_File_Size(tarfn) == 0) {
143 LOGE("Backup file size for '%s' is 0 bytes.\n", tarfn.c_str());
144 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500145 }
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500146 Archive_File_Count++;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500147 if (Archive_File_Count > 999) {
148 LOGE("Archive count is too large!\n");
149 return -1;
150 }
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500151 string temp = basefn + "%03i";
152 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
153 tarfn = actual_filename;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500154 Archive_Current_Size = 0;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500155 LOGI("Creating tar '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500156 ui_print("Creating archive %i...\n", Archive_File_Count + 1);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500157 if (createTar() != 0)
158 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500159 }
160 LOGI("Adding file: '%s'... ", FileName.c_str());
161 if (addFile(FileName, true) < 0)
162 return -1;
163 Archive_Current_Size += st.st_size;
164 LOGI("added successfully, archive size: %llu\n", Archive_Current_Size);
165 if (st.st_size > 2147483648LL)
166 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());
167 }
168 }
169 closedir(d);
170 return 0;
171}
172
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500173int twrpTar::Split_Archive()
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500174{
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500175 string temp = tarfn + "%03i";
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500176 char actual_filename[255];
177
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500178 basefn = tarfn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500179 Archive_File_Count = 0;
180 Archive_Current_Size = 0;
181 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500182 tarfn = actual_filename;
183 createTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500184 DataManager::GetValue(TW_HAS_DATA_MEDIA, has_data_media);
185 ui_print("Creating archive 1...\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500186 if (Generate_Multiple_Archives(tardir) < 0) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500187 LOGE("Error generating file list\n");
188 return -1;
189 }
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500190 closeTar(false);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500191 LOGI("Done, created %i archives.\n", (Archive_File_Count++));
192 return (Archive_File_Count);
193}
194
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500195int twrpTar::extractTar() {
196 char* charRootDir = (char*) tardir.c_str();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500197 bool gzip = false;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500198 if (openTar(gzip) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500199 return -1;
200 if (tar_extract_all(t, charRootDir) != 0) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500201 LOGE("Unable to extract tar archive '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500202 return -1;
203 }
204 if (tar_close(t) != 0) {
205 LOGE("Unable to close tar file\n");
206 return -1;
207 }
208 return 0;
209}
210
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500211int twrpTar::extract() {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500212 int len = 3;
213 char header[len];
214 string::size_type i = 0;
215 int firstbyte = 0;
216 int secondbyte = 0;
217 int ret;
218 ifstream f;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500219 f.open(tarfn.c_str(), ios::in | ios::binary);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500220 f.get(header, len);
221 firstbyte = header[i] & 0xff;
222 secondbyte = header[++i] & 0xff;
223 f.close();
224 if (firstbyte == 0x1f && secondbyte == 0x8b) {
225 //if you return the extractTGZ function directly, stack crashes happen
226 LOGI("Extracting gzipped tar\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500227 ret = extractTGZ();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500228 return ret;
229 }
230 else {
231 LOGI("Extracting uncompressed tar\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500232 return extractTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500233 }
234}
235
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500236int twrpTar::tarDirs(bool include_root) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500237 DIR* d;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500238 string mainfolder = tardir + "/", subfolder;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500239 char buf[1024];
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500240 char* charTarFile = (char*) tarfn.c_str();
241 d = opendir(tardir.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500242 if (d != NULL) {
243 struct dirent* de;
244 while ((de = readdir(d)) != NULL) {
245 LOGI("adding %s\n", de->d_name);
246#ifdef RECOVERY_SDCARD_ON_DATA
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500247 if ((tardir == "/data" || tardir == "/data/") && strcmp(de->d_name, "media") == 0) continue;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500248#endif
249 if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue;
250
251 subfolder = mainfolder;
252 subfolder += de->d_name;
253 strcpy(buf, subfolder.c_str());
254 if (de->d_type == DT_DIR) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500255 if (include_root) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500256 if (tar_append_tree(t, buf, NULL) != 0) {
257 LOGE("Error appending '%s' to tar archive '%s'\n", buf, charTarFile);
258 return -1;
259 }
260 } else {
261 string temp = Strip_Root_Dir(buf);
262 char* charTarPath = (char*) temp.c_str();
263 if (tar_append_tree(t, buf, charTarPath) != 0) {
264 LOGE("Error appending '%s' to tar archive '%s'\n", buf, charTarFile);
265 return -1;
266 }
267 }
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500268 } else if (tardir != "/" && (de->d_type == DT_REG || de->d_type == DT_LNK)) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500269 if (addFile(buf, include_root) != 0)
270 return -1;
271 }
272 fflush(NULL);
273 }
274 closedir(d);
275 }
276 return 0;
277}
278
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500279int twrpTar::createTGZ() {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500280 bool gzip = true;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500281 if (createTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500282 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500283 if (tarDirs(false) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500284 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500285 if (closeTar(gzip) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500286 return -1;
287 return 0;
288}
289
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500290int twrpTar::create() {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500291 bool gzip = false;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500292 if (createTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500293 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500294 if (tarDirs(false) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500295 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500296 if (closeTar(gzip) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500297 return -1;
298 return 0;
299}
300
301int twrpTar::addFilesToExistingTar(vector <string> files, string fn) {
302 char* charTarFile = (char*) fn.c_str();
303
304 if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) == -1)
305 return -1;
306 removeEOT(charTarFile);
307 if (tar_open(&t, charTarFile, NULL, O_WRONLY | O_APPEND | O_LARGEFILE, 0644, TAR_GNU) == -1)
308 return -1;
309 for (unsigned int i = 0; i < files.size(); ++i) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500310 char* file = (char*) files.at(i).c_str();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500311 if (tar_append_file(t, file, file) == -1)
312 return -1;
313 }
314 if (tar_append_eof(t) == -1)
315 return -1;
316 if (tar_close(t) == -1)
317 return -1;
318 return 0;
319}
320
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500321int twrpTar::createTar() {
322 char* charTarFile = (char*) tarfn.c_str();
323 char* charRootDir = (char*) tardir.c_str();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500324 int use_compression = 0;
325
326 DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500327 if (use_compression) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500328 string cmd = "pigz - > '" + tarfn + "'";
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500329 p = popen(cmd.c_str(), "w");
330 fd = fileno(p);
331 if (!p) return -1;
332 if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) != 0) {
333 pclose(p);
334 return -1;
335 }
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500336 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500337 else {
338 if (tar_open(&t, charTarFile, NULL, O_WRONLY | O_CREAT | O_LARGEFILE, 0644, TAR_GNU) == -1)
339 return -1;
340 }
341 return 0;
342}
343
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500344int twrpTar::openTar(bool gzip) {
345 char* charRootDir = (char*) tardir.c_str();
346 char* charTarFile = (char*) tarfn.c_str();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500347
348 if (gzip) {
349 LOGI("Opening as a gzip\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500350 string cmd = "pigz -d -c '" + tarfn + "'";
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500351 FILE* pipe = popen(cmd.c_str(), "r");
352 int fd = fileno(pipe);
353 if (!pipe) return -1;
354 if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) != 0) {
355 LOGI("tar_fdopen returned error\n");
356 pclose(pipe);
357 return -1;
358 }
359 }
360 else {
361 if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) != 0) {
362 LOGE("Unable to open tar archive '%s'\n", charTarFile);
363 return -1;
364 }
365 }
366 return 0;
367}
368
369string twrpTar::Strip_Root_Dir(string Path) {
370 string temp;
371 size_t slash;
372
373 if (Path.substr(0, 1) == "/")
374 temp = Path.substr(1, Path.size() - 1);
375 else
376 temp = Path;
377 slash = temp.find("/");
378 if (slash == string::npos)
379 return temp;
380 else {
381 string stripped;
382
383 stripped = temp.substr(slash, temp.size() - slash);
384 return stripped;
385 }
386 return temp;
387}
388
389int twrpTar::addFile(string fn, bool include_root) {
390 char* charTarFile = (char*) fn.c_str();
391 if (include_root) {
392 if (tar_append_file(t, charTarFile, NULL) == -1)
393 return -1;
394 } else {
395 string temp = Strip_Root_Dir(fn);
396 char* charTarPath = (char*) temp.c_str();
397 if (tar_append_file(t, charTarFile, charTarPath) == -1)
398 return -1;
399 }
400 return 0;
401}
402
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500403int twrpTar::closeTar(bool gzip) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500404 int use_compression;
405 DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression);
406
407 if (tar_append_eof(t) != 0) {
408 LOGE("tar_append_eof(): %s\n", strerror(errno));
409 tar_close(t);
410 return -1;
411 }
412 if (tar_close(t) != 0) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500413 LOGE("Unable to close tar archive: '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500414 return -1;
415 }
416 if (use_compression || gzip) {
417 LOGI("Closing popen and fd\n");
418 pclose(p);
419 close(fd);
420 }
421 return 0;
422}
423
424int twrpTar::removeEOT(string tarFile) {
425 char* charTarFile = (char*) tarFile.c_str();
426 off_t tarFileEnd;
427 while (th_read(t) == 0) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500428 if (TH_ISREG(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500429 tar_skip_regfile(t);
430 tarFileEnd = lseek(t->fd, 0, SEEK_CUR);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500431 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500432 if (tar_close(t) == -1)
433 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500434 if (truncate(charTarFile, tarFileEnd) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500435 return -1;
436 return 0;
437}
438
439int twrpTar::compress(string fn) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500440 string cmd = "pigz " + fn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500441 p = popen(cmd.c_str(), "r");
442 if (!p) return -1;
443 char buffer[128];
444 string result = "";
445 while(!feof(p)) {
446 if(fgets(buffer, 128, p) != NULL)
447 result += buffer;
448 }
449 pclose(p);
450 return 0;
451}
452
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500453int twrpTar::extractTGZ() {
454 string splatrootdir(tardir);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500455 bool gzip = true;
456 char* splatCharRootDir = (char*) splatrootdir.c_str();
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500457 if (openTar(gzip) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500458 return -1;
459 int ret = tar_extract_all(t, splatCharRootDir);
460 if (tar_close(t) != 0) {
461 LOGE("Unable to close tar file\n");
462 return -1;
463 }
464 return 0;
465}