blob: e77e1d059f35c128ea65eed392f94c7740b8bf2b [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/*
bigbiff bigbiff34684ff2013-12-01 21:03:45 -05002 Copyright 2013 TeamWin
Dees_Troye34c1332013-02-06 19:13:00 +00003 This file is part of TWRP/TeamWin Recovery Project.
bigbiff bigbiff9c754052013-01-09 09:09:08 -05004
Dees_Troye34c1332013-02-06 19:13:00 +00005 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.
bigbiff bigbiff9c754052013-01-09 09:09:08 -05009
Dees_Troye34c1332013-02-06 19:13:00 +000010 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.
bigbiff bigbiff9c754052013-01-09 09:09:08 -050014
Dees_Troye34c1332013-02-06 19:13:00 +000015 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
bigbiff bigbiff9c754052013-01-09 09:09:08 -050017*/
18
19extern "C" {
20 #include "libtar/libtar.h"
Dees_Troye34c1332013-02-06 19:13:00 +000021 #include "twrpTar.h"
22 #include "tarWrite.h"
Dees_Troy40bbcf82013-02-12 15:01:53 +000023 #include "libcrecovery/common.h"
bigbiff bigbiff9c754052013-01-09 09:09:08 -050024}
25#include <sys/types.h>
26#include <sys/stat.h>
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -050027#include <sys/wait.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050028#include <string.h>
29#include <errno.h>
30#include <fcntl.h>
31#include <fstream>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050032#include <iostream>
33#include <string>
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050034#include <sstream>
Dees_Troy83bd4832013-05-04 12:39:56 +000035#include <vector>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050036#include <dirent.h>
bigbiff bigbiffc49d7062013-10-11 20:28:00 -040037#include <libgen.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050038#include <sys/mman.h>
39#include "twrpTar.hpp"
Dees_Troy2673cec2013-04-02 20:22:16 +000040#include "twcommon.h"
bigbiff bigbiff9c754052013-01-09 09:09:08 -050041#include "data.hpp"
42#include "variables.h"
bigbiff bigbiff9c754052013-01-09 09:09:08 -050043#include "twrp-functions.hpp"
44
45using namespace std;
46
Dees_Troy83bd4832013-05-04 12:39:56 +000047twrpTar::twrpTar(void) {
48 use_encryption = 0;
49 userdata_encryption = 0;
50 use_compression = 0;
51 split_archives = 0;
52 has_data_media = 0;
53 pigz_pid = 0;
54 oaes_pid = 0;
55}
56
57twrpTar::~twrpTar(void) {
58 // Do nothing
59}
60
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050061void twrpTar::setfn(string fn) {
62 tarfn = fn;
63}
64
65void twrpTar::setdir(string dir) {
66 tardir = dir;
67}
68
Dees_Troy83bd4832013-05-04 12:39:56 +000069void twrpTar::setexcl(string exclude) {
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -040070 tarexclude.push_back(exclude);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050071}
72
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -050073int twrpTar::createTarFork() {
Dees_Troy83bd4832013-05-04 12:39:56 +000074 int status = 0;
75 pid_t pid, rc_pid;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -050076 if ((pid = fork()) == -1) {
Dees_Troy2673cec2013-04-02 20:22:16 +000077 LOGINFO("create tar failed to fork.\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050078 return -1;
79 }
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -050080 if (pid == 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +000081 // Child process
82 if (use_encryption || userdata_encryption) {
83 LOGINFO("Using encryption\n");
84 DIR* d;
85 struct dirent* de;
86 unsigned long long regular_size = 0, encrypt_size = 0, target_size = 0, core_count = 1;
87 unsigned enc_thread_id = 1, regular_thread_id = 0, i, start_thread_id = 1;
88 int item_len, ret, thread_error = 0;
89 std::vector<TarListStruct> RegularList;
90 std::vector<TarListStruct> EncryptList;
91 string FileName;
92 struct TarListStruct TarItem;
93 twrpTar reg, enc[9];
94 struct stat st;
95 pthread_t enc_thread[9];
96 pthread_attr_t tattr;
97 void *thread_return;
98
99 core_count = sysconf(_SC_NPROCESSORS_CONF);
100 if (core_count > 8)
101 core_count = 8;
102 LOGINFO(" Core Count : %llu\n", core_count);
103 Archive_Current_Size = 0;
104
105 d = opendir(tardir.c_str());
106 if (d == NULL) {
107 LOGERR("error opening '%s'\n", tardir.c_str());
108 _exit(-1);
109 }
110 // Figure out the size of all data to be encrypted and create a list of unencrypted files
111 while ((de = readdir(d)) != NULL) {
112 FileName = tardir + "/";
113 FileName += de->d_name;
114 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
115 continue; // Skip /data/media
116 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
117 continue;
bigbiff bigbiff34684ff2013-12-01 21:03:45 -0500118 bool skip_dir = false;
119 string dir(de->d_name);
120 skip_dir = du.check_skip_dirs(dir);
121 if (de->d_type == DT_DIR && !skip_dir) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000122 item_len = strlen(de->d_name);
123 if (userdata_encryption && ((item_len >= 3 && strncmp(de->d_name, "app", 3) == 0) || (item_len >= 6 && strncmp(de->d_name, "dalvik", 6) == 0))) {
124 if (Generate_TarList(FileName, &RegularList, &target_size, &regular_thread_id) < 0) {
125 LOGERR("Error in Generate_TarList with regular list!\n");
126 closedir(d);
127 _exit(-1);
128 }
bigbiff bigbiff34684ff2013-12-01 21:03:45 -0500129 regular_size += du.Get_Folder_Size(FileName);
Dees_Troy83bd4832013-05-04 12:39:56 +0000130 } else {
bigbiff bigbiff34684ff2013-12-01 21:03:45 -0500131 encrypt_size += du.Get_Folder_Size(FileName);
Dees_Troy83bd4832013-05-04 12:39:56 +0000132 }
133 } else if (de->d_type == DT_REG) {
134 stat(FileName.c_str(), &st);
135 encrypt_size += (unsigned long long)(st.st_size);
136 }
137 }
138 closedir(d);
139
140 target_size = encrypt_size / core_count;
141 target_size++;
142 LOGINFO(" Unencrypted size: %llu\n", regular_size);
143 LOGINFO(" Encrypted size : %llu\n", encrypt_size);
144 LOGINFO(" Target size : %llu\n", target_size);
145 if (!userdata_encryption) {
146 enc_thread_id = 0;
147 start_thread_id = 0;
148 core_count--;
149 }
150 Archive_Current_Size = 0;
151
152 d = opendir(tardir.c_str());
153 if (d == NULL) {
154 LOGERR("error opening '%s'\n", tardir.c_str());
155 _exit(-1);
156 }
157 // Divide up the encrypted file list for threading
158 while ((de = readdir(d)) != NULL) {
159 FileName = tardir + "/";
160 FileName += de->d_name;
161 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
162 continue; // Skip /data/media
163 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
164 continue;
bigbiff bigbiff34684ff2013-12-01 21:03:45 -0500165 bool skip_dir = false;
166 string dir(de->d_name);
167 skip_dir = du.check_skip_dirs(dir);
168 if (de->d_type == DT_DIR && !skip_dir) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000169 item_len = strlen(de->d_name);
170 if (userdata_encryption && ((item_len >= 3 && strncmp(de->d_name, "app", 3) == 0) || (item_len >= 6 && strncmp(de->d_name, "dalvik", 6) == 0))) {
171 // Do nothing, we added these to RegularList earlier
172 } else {
173 FileName = tardir + "/";
174 FileName += de->d_name;
175 if (Generate_TarList(FileName, &EncryptList, &target_size, &enc_thread_id) < 0) {
176 LOGERR("Error in Generate_TarList with encrypted list!\n");
177 closedir(d);
178 _exit(-1);
179 }
180 }
181 } else if (de->d_type == DT_REG || de->d_type == DT_LNK) {
182 stat(FileName.c_str(), &st);
183 if (de->d_type == DT_REG)
184 Archive_Current_Size += (unsigned long long)(st.st_size);
185 TarItem.fn = FileName;
186 TarItem.thread_id = enc_thread_id;
187 EncryptList.push_back(TarItem);
188 }
189 }
190 closedir(d);
191 if (enc_thread_id != core_count) {
192 LOGERR("Error dividing up threads for encryption, %i threads for %i cores!\n", enc_thread_id, core_count);
193 if (enc_thread_id > core_count)
194 _exit(-1);
195 else
196 LOGERR("Continuining anyway.");
197 }
198
199 if (userdata_encryption) {
200 // Create a backup of unencrypted data
201 reg.setfn(tarfn);
202 reg.ItemList = &RegularList;
203 reg.thread_id = 0;
204 reg.use_encryption = 0;
205 reg.use_compression = use_compression;
206 LOGINFO("Creating unencrypted backup...\n");
207 if (createList((void*)&reg) != 0) {
208 LOGERR("Error creating unencrypted backup.\n");
209 _exit(-1);
210 }
211 }
212
213 if (pthread_attr_init(&tattr)) {
214 LOGERR("Unable to pthread_attr_init\n");
215 _exit(-1);
216 }
217 if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
218 LOGERR("Error setting pthread_attr_setdetachstate\n");
219 _exit(-1);
220 }
221 if (pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM)) {
222 LOGERR("Error setting pthread_attr_setscope\n");
223 _exit(-1);
224 }
225 /*if (pthread_attr_setstacksize(&tattr, 524288)) {
226 LOGERR("Error setting pthread_attr_setstacksize\n");
227 _exit(-1);
228 }*/
229
230 // Create threads for the divided up encryption lists
231 for (i = start_thread_id; i <= core_count; i++) {
232 enc[i].setdir(tardir);
233 enc[i].setfn(tarfn);
234 enc[i].ItemList = &EncryptList;
235 enc[i].thread_id = i;
236 enc[i].use_encryption = use_encryption;
237 enc[i].use_compression = use_compression;
238 LOGINFO("Start encryption thread %i\n", i);
239 ret = pthread_create(&enc_thread[i], &tattr, createList, (void*)&enc[i]);
240 if (ret) {
241 LOGINFO("Unable to create %i thread for encryption! %i\nContinuing in same thread (backup will be slower).", i, ret);
242 if (createList((void*)&enc[i]) != 0) {
243 LOGERR("Error creating encrypted backup %i.\n", i);
244 _exit(-1);
245 } else {
246 enc[i].thread_id = i + 1;
247 }
248 }
249 usleep(100000); // Need a short delay before starting the next thread or the threads will never finish for some reason.
250 }
251 if (pthread_attr_destroy(&tattr)) {
252 LOGERR("Failed to pthread_attr_destroy\n");
253 }
254 for (i = start_thread_id; i <= core_count; i++) {
255 if (enc[i].thread_id == i) {
256 if (pthread_join(enc_thread[i], &thread_return)) {
257 LOGERR("Error joining thread %i\n", i);
258 _exit(-1);
259 } else {
260 LOGINFO("Joined thread %i.\n", i);
261 ret = (int)thread_return;
262 if (ret != 0) {
263 thread_error = 1;
264 LOGERR("Thread %i returned an error %i.\n", i, ret);
265 _exit(-1);
266 }
267 }
268 } else {
269 LOGINFO("Skipping joining thread %i because of pthread failure.\n", i);
270 }
271 }
272 if (thread_error) {
273 LOGERR("Error returned by one or more threads.\n");
274 _exit(-1);
275 }
276 LOGINFO("Finished encrypted backup.\n");
277 _exit(0);
278 } else {
279 if (create() != 0)
280 _exit(-1);
281 else
282 _exit(0);
283 }
284 } else {
285 if (TWFunc::Wait_For_Child(pid, &status, "createTarFork()") != 0)
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500286 return -1;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500287 }
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500288 return 0;
289}
290
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500291int twrpTar::extractTarFork() {
Dees_Troy83bd4832013-05-04 12:39:56 +0000292 int status = 0;
293 pid_t pid, rc_pid;
294
295 pid = fork();
296 if (pid >= 0) // fork was successful
297 {
298 if (pid == 0) // child process
299 {
300 if (TWFunc::Path_Exists(tarfn)) {
301 LOGINFO("Single archive\n");
302 if (extract() != 0)
303 _exit(-1);
304 else
305 _exit(0);
306 } else {
307 LOGINFO("Multiple archives\n");
308 string temp;
309 char actual_filename[255];
310 twrpTar tars[9];
311 pthread_t tar_thread[9];
312 pthread_attr_t tattr;
313 int thread_count = 0, i, start_thread_id = 1, ret, thread_error = 0;
314 void *thread_return;
315
316 basefn = tarfn;
317 temp = basefn + "%i%02i";
318 tarfn += "000";
319 if (!TWFunc::Path_Exists(tarfn)) {
320 LOGERR("Unable to locate '%s' or '%s'\n", basefn.c_str(), tarfn.c_str());
321 _exit(-1);
322 }
323 if (TWFunc::Get_File_Type(tarfn) != 2) {
324 LOGINFO("First tar file '%s' not encrypted\n", tarfn.c_str());
325 tars[0].basefn = basefn;
326 tars[0].thread_id = 0;
327 if (extractMulti((void*)&tars[0]) != 0) {
328 LOGERR("Error extracting split archive.\n");
329 _exit(-1);
330 }
331 } else {
332 start_thread_id = 0;
333 }
334 // Start threading encrypted restores
335 if (pthread_attr_init(&tattr)) {
336 LOGERR("Unable to pthread_attr_init\n");
337 _exit(-1);
338 }
339 if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
340 LOGERR("Error setting pthread_attr_setdetachstate\n");
341 _exit(-1);
342 }
343 if (pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM)) {
344 LOGERR("Error setting pthread_attr_setscope\n");
345 _exit(-1);
346 }
347 /*if (pthread_attr_setstacksize(&tattr, 524288)) {
348 LOGERR("Error setting pthread_attr_setstacksize\n");
349 _exit(-1);
350 }*/
351 for (i = start_thread_id; i < 9; i++) {
352 sprintf(actual_filename, temp.c_str(), i, 0);
353 if (TWFunc::Path_Exists(actual_filename)) {
354 thread_count++;
355 tars[i].basefn = basefn;
356 tars[i].thread_id = i;
357 LOGINFO("Creating extract thread ID %i\n", i);
358 ret = pthread_create(&tar_thread[i], &tattr, extractMulti, (void*)&tars[i]);
359 if (ret) {
360 LOGINFO("Unable to create %i thread for extraction! %i\nContinuing in same thread (restore will be slower).", i, ret);
361 if (extractMulti((void*)&tars[i]) != 0) {
362 LOGERR("Error extracting backup in thread %i.\n", i);
363 _exit(-1);
364 } else {
365 tars[i].thread_id = i + 1;
366 }
367 }
368 usleep(100000); // Need a short delay before starting the next thread or the threads will never finish for some reason.
369 } else {
370 break;
371 }
372 }
373 for (i = start_thread_id; i < thread_count + start_thread_id; i++) {
374 if (tars[i].thread_id == i) {
375 if (pthread_join(tar_thread[i], &thread_return)) {
376 LOGERR("Error joining thread %i\n", i);
377 _exit(-1);
378 } else {
379 LOGINFO("Joined thread %i.\n", i);
380 ret = (int)thread_return;
381 if (ret != 0) {
382 thread_error = 1;
383 LOGERR("Thread %i returned an error %i.\n", i, ret);
384 _exit(-1);
385 }
386 }
387 } else {
388 LOGINFO("Skipping joining thread %i because of pthread failure.\n", i);
389 }
390 }
391 if (thread_error) {
392 LOGERR("Error returned by one or more threads.\n");
393 _exit(-1);
394 }
395 LOGINFO("Finished encrypted backup.\n");
396 _exit(0);
397 }
398 }
399 else // parent process
400 {
401 if (TWFunc::Wait_For_Child(pid, &status, "extractTarFork()") != 0)
402 return -1;
403 }
404 }
405 else // fork has failed
406 {
Dees_Troy2673cec2013-04-02 20:22:16 +0000407 LOGINFO("extract tar failed to fork.\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500408 return -1;
409 }
410 return 0;
411}
412
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500413int twrpTar::splitArchiveFork() {
Dees_Troy83bd4832013-05-04 12:39:56 +0000414 int status = 0;
415 pid_t pid, rc_pid;
416
417 pid = fork();
418 if (pid >= 0) // fork was successful
419 {
420 if (pid == 0) // child process
421 {
422 if (Split_Archive() <= 0)
423 _exit(-1);
424 else
425 _exit(0);
426 }
427 else // parent process
428 {
429 if (TWFunc::Wait_For_Child(pid, &status, "splitArchiveFork()") != 0)
430 return -1;
431 }
432 }
433 else // fork has failed
434 {
435 LOGINFO("split archive failed to fork.\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500436 return -1;
437 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000438 return 0;
439}
440
441int twrpTar::Generate_TarList(string Path, std::vector<TarListStruct> *TarList, unsigned long long *Target_Size, unsigned *thread_id) {
442 DIR* d;
443 struct dirent* de;
444 struct stat st;
445 string FileName;
446 struct TarListStruct TarItem;
447 string::size_type i;
448 bool skip;
449
450 if (has_data_media == 1 && Path.size() >= 11 && strncmp(Path.c_str(), "/data/media", 11) == 0)
451 return 0; // Skip /data/media
452
453 d = opendir(Path.c_str());
454 if (d == NULL) {
455 LOGERR("error opening '%s' -- error: %s\n", Path.c_str(), strerror(errno));
456 closedir(d);
457 return -1;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500458 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000459 while ((de = readdir(d)) != NULL) {
460 // Skip excluded stuff
461 if (split.size() > 0) {
462 skip = false;
463 for (i = 0; i < split.size(); i++) {
464 if (strcmp(de->d_name, split[i].c_str()) == 0) {
465 LOGINFO("excluding %s\n", de->d_name);
466 skip = true;
467 break;
468 }
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500469 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000470 if (skip)
471 continue;
472 }
473 FileName = Path + "/";
474 FileName += de->d_name;
475 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
476 continue; // Skip /data/media
477 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
478 continue;
479 TarItem.fn = FileName;
480 TarItem.thread_id = *thread_id;
bigbiff bigbiff34684ff2013-12-01 21:03:45 -0500481 bool skip_dir = false;
482 string dir(de->d_name);
483 skip_dir = du.check_skip_dirs(dir);
484 if (de->d_type == DT_DIR && !skip_dir) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000485 TarList->push_back(TarItem);
486 if (Generate_TarList(FileName, TarList, Target_Size, thread_id) < 0)
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500487 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000488 } else if (de->d_type == DT_REG || de->d_type == DT_LNK) {
489 stat(FileName.c_str(), &st);
490 TarList->push_back(TarItem);
491 if (de->d_type == DT_REG)
492 Archive_Current_Size += st.st_size;
493 if (Archive_Current_Size != 0 && *Target_Size != 0 && Archive_Current_Size > *Target_Size) {
494 *thread_id = *thread_id + 1;
495 Archive_Current_Size = 0;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500496 }
497 }
498 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000499 closedir(d);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500500 return 0;
501}
502
503int twrpTar::Generate_Multiple_Archives(string Path) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500504 DIR* d;
505 struct dirent* de;
506 struct stat st;
507 string FileName;
508 char actual_filename[255];
509
Dees_Troy83bd4832013-05-04 12:39:56 +0000510 string::size_type i;
511 bool skip;
512
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500513 if (has_data_media == 1 && Path.size() >= 11 && strncmp(Path.c_str(), "/data/media", 11) == 0)
514 return 0; // Skip /data/media
Dees_Troy2673cec2013-04-02 20:22:16 +0000515 LOGINFO("Path: '%s', archive filename: '%s'\n", Path.c_str(), tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500516
517 d = opendir(Path.c_str());
518 if (d == NULL)
519 {
Dees_Troy2673cec2013-04-02 20:22:16 +0000520 LOGERR("error opening '%s' -- error: %s\n", Path.c_str(), strerror(errno));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500521 closedir(d);
522 return -1;
523 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000524 while ((de = readdir(d)) != NULL) {
525 // Skip excluded stuff
526 if (split.size() > 0) {
527 skip = false;
528 for (i = 0; i < split.size(); i++) {
529 if (strcmp(de->d_name, split[i].c_str()) == 0) {
530 LOGINFO("excluding %s\n", de->d_name);
531 skip = true;
532 break;
533 }
534 }
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400535 if (skip) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000536 continue;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400537 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000538 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500539 FileName = Path + "/";
540 FileName += de->d_name;
541 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
542 continue; // Skip /data/media
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500543 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
544 continue;
bigbiff bigbiffc49d7062013-10-11 20:28:00 -0400545 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500546 {
bigbiff bigbiff34684ff2013-12-01 21:03:45 -0500547 uint64_t folder_size = du.Get_Folder_Size(FileName);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500548 if (Archive_Current_Size + folder_size > MAX_ARCHIVE_SIZE) {
Dees Troyed400772013-10-09 14:45:24 +0000549 // Add the root folder first
550 LOGINFO("Adding root folder '%s' before splitting.\n", FileName.c_str());
551 if (addFile(FileName, true) != 0) {
552 LOGERR("Error adding folder '%s' to split archive.\n", FileName.c_str());
553 return -1;
554 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000555 LOGINFO("Calling Generate_Multiple_Archives\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500556 if (Generate_Multiple_Archives(FileName) < 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500557 return -1;
558 } else {
559 //FileName += "/";
Dees_Troy2673cec2013-04-02 20:22:16 +0000560 LOGINFO("Adding folder '%s'\n", FileName.c_str());
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500561 tardir = FileName;
562 if (tarDirs(true) < 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500563 return -1;
564 Archive_Current_Size += folder_size;
565 }
566 }
567 else if (de->d_type == DT_REG || de->d_type == DT_LNK)
568 {
569 stat(FileName.c_str(), &st);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400570 if (de->d_type != DT_LNK) {
571 if (Archive_Current_Size != 0 && Archive_Current_Size + st.st_size > MAX_ARCHIVE_SIZE) {
572 LOGINFO("Closing tar '%s', ", tarfn.c_str());
573 closeTar();
574 if (TWFunc::Get_File_Size(tarfn) == 0) {
575 LOGERR("Backup file size for '%s' is 0 bytes.\n", tarfn.c_str());
576 return -1;
577 }
578 Archive_File_Count++;
579 if (Archive_File_Count > 999) {
580 LOGERR("Archive count is too large!\n");
581 return -1;
582 }
583 string temp = basefn + "%03i";
584 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
585 tarfn = actual_filename;
586 Archive_Current_Size = 0;
587 LOGINFO("Creating tar '%s'\n", tarfn.c_str());
588 gui_print("Creating archive %i...\n", Archive_File_Count + 1);
589 if (createTar() != 0)
590 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500591 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500592 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000593 LOGINFO("Adding file: '%s'... ", FileName.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500594 if (addFile(FileName, true) < 0)
595 return -1;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400596 if (de->d_type != DT_LNK) {
597 Archive_Current_Size += st.st_size;
598 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000599 LOGINFO("added successfully, archive size: %llu\n", Archive_Current_Size);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400600 if (de->d_type != DT_LNK) {
601 if (st.st_size > 2147483648LL)
602 LOGERR("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());
603 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500604 }
605 }
606 closedir(d);
607 return 0;
608}
609
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500610int twrpTar::Split_Archive()
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500611{
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500612 string temp = tarfn + "%03i";
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500613 char actual_filename[255];
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400614 string tarsplit;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500615
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500616 basefn = tarfn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500617 Archive_File_Count = 0;
618 Archive_Current_Size = 0;
619 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500620 tarfn = actual_filename;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400621
622 for (int i = 0; i < tarexclude.size(); ++i) {
623 tarsplit = tarexclude[i];
624 tarsplit += " ";
625 }
626
Dees_Troy83bd4832013-05-04 12:39:56 +0000627 if (!tarexclude.empty())
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400628 split = TWFunc::split_string(tarsplit, ' ', true);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500629 createTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500630 DataManager::GetValue(TW_HAS_DATA_MEDIA, has_data_media);
Dees_Troy2673cec2013-04-02 20:22:16 +0000631 gui_print("Creating archive 1...\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500632 if (Generate_Multiple_Archives(tardir) < 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000633 LOGERR("Error generating multiple archives\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500634 return -1;
635 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000636 closeTar();
637 LOGINFO("Done, created %i archives.\n", (++Archive_File_Count));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500638 return (Archive_File_Count);
639}
640
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500641int twrpTar::extractTar() {
Dees_Troye34c1332013-02-06 19:13:00 +0000642 char* charRootDir = (char*) tardir.c_str();
Dees_Troy83bd4832013-05-04 12:39:56 +0000643 if (openTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500644 return -1;
645 if (tar_extract_all(t, charRootDir) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000646 LOGERR("Unable to extract tar archive '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500647 return -1;
648 }
649 if (tar_close(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000650 LOGERR("Unable to close tar file\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500651 return -1;
652 }
653 return 0;
654}
655
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500656int twrpTar::extract() {
Dees_Troy83bd4832013-05-04 12:39:56 +0000657 Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
n0d33b511632013-03-06 21:14:15 +0200658
659 if (Archive_Current_Type == 1) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500660 //if you return the extractTGZ function directly, stack crashes happen
Dees_Troy2673cec2013-04-02 20:22:16 +0000661 LOGINFO("Extracting gzipped tar\n");
Dees_Troy83bd4832013-05-04 12:39:56 +0000662 int ret = extractTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500663 return ret;
Dees_Troy83bd4832013-05-04 12:39:56 +0000664 } else if (Archive_Current_Type == 2) {
665 string Password;
666 DataManager::GetValue("tw_restore_password", Password);
667 int ret = TWFunc::Try_Decrypting_File(tarfn, Password);
668 if (ret < 1) {
669 LOGERR("Failed to decrypt tar file '%s'\n", tarfn.c_str());
670 return -1;
671 }
672 if (ret == 1) {
673 LOGERR("Decrypted file is not in tar format.\n");
674 return -1;
675 }
676 if (ret == 3) {
677 LOGINFO("Extracting encrypted and compressed tar.\n");
678 Archive_Current_Type = 3;
679 } else
680 LOGINFO("Extracting encrypted tar.\n");
681 return extractTar();
682 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000683 LOGINFO("Extracting uncompressed tar\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500684 return extractTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500685 }
686}
687
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500688int twrpTar::tarDirs(bool include_root) {
Dees_Troye34c1332013-02-06 19:13:00 +0000689 DIR* d;
690 string mainfolder = tardir + "/", subfolder;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400691 string tarsplit;
Dees_Troy59df9262013-06-19 14:53:57 -0500692 char buf[PATH_MAX], charTarPath[PATH_MAX];
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400693 string excl;
Dees_Troy83bd4832013-05-04 12:39:56 +0000694 string::size_type i;
695 bool skip;
696
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400697 //set exclude directories for libtar
698 for (int i = 0; i < tarexclude.size(); ++i) {
699 excl += tarexclude.at(i);
700 tarsplit = tarexclude.at(i);
701 excl += " ";
702 tarsplit += " ";
703 }
Dees_Troye34c1332013-02-06 19:13:00 +0000704 d = opendir(tardir.c_str());
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400705 if (d != NULL) {
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400706 if (!tarsplit.empty()) {
707 split = TWFunc::split_string(tarsplit, ' ', true);
Dees_Troy83bd4832013-05-04 12:39:56 +0000708 }
Dees_Troye34c1332013-02-06 19:13:00 +0000709 struct dirent* de;
710 while ((de = readdir(d)) != NULL) {
bigbiff bigbiff34684ff2013-12-01 21:03:45 -0500711 bool skip_dir = false;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500712#ifdef RECOVERY_SDCARD_ON_DATA
bigbiff bigbiff34684ff2013-12-01 21:03:45 -0500713 du.add_absolute_dir("/data/media");
714 string dir(tardir + "/" + de->d_name);
715 skip_dir = du.check_skip_dirs(dir);
716 if (skip_dir) continue;
Dees Troy42f40f52013-12-20 05:08:36 +0000717#else
718 string dir;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500719#endif
bigbiff bigbiff34684ff2013-12-01 21:03:45 -0500720 dir = de->d_name;
721 skip_dir = du.check_skip_dirs(dir);
722 if (de->d_type == DT_BLK || de->d_type == DT_CHR || skip_dir)
Dees_Troy3263e922013-03-15 11:42:57 -0500723 continue;
Dees_Troy83bd4832013-05-04 12:39:56 +0000724
725 // Skip excluded stuff
726 if (split.size() > 0) {
727 skip = false;
728 for (i = 0; i < split.size(); i++) {
729 if (strcmp(de->d_name, split[i].c_str()) == 0) {
730 LOGINFO("excluding %s\n", de->d_name);
731 skip = true;
732 break;
733 }
734 }
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400735 if (skip) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000736 continue;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400737 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000738 }
739
Dees_Troye34c1332013-02-06 19:13:00 +0000740 subfolder = mainfolder;
Dees_Troy3263e922013-03-15 11:42:57 -0500741 if (strcmp(de->d_name, ".") != 0) {
742 subfolder += de->d_name;
743 } else {
bigbiff bigbiffc49d7062013-10-11 20:28:00 -0400744 std::string parentDir = basename(subfolder.c_str());
745 LOGINFO("parentDir: %s\n", parentDir.c_str());
746 if (!parentDir.compare("lost+found"))
747 continue;
Dees Troyed400772013-10-09 14:45:24 +0000748 LOGINFO("tarDirs addFile '%s' including root: %i\n", subfolder.c_str(), include_root);
Dees_Troy3263e922013-03-15 11:42:57 -0500749 if (addFile(subfolder, include_root) != 0)
750 return -1;
751 continue;
752 }
Dees_Troye34c1332013-02-06 19:13:00 +0000753 strcpy(buf, subfolder.c_str());
754 if (de->d_type == DT_DIR) {
Dees_Troy3263e922013-03-15 11:42:57 -0500755 if (include_root) {
Dees_Troy59df9262013-06-19 14:53:57 -0500756 charTarPath[0] = NULL;
757 LOGINFO("tar_append_tree '%s' as NULL\n", buf, charTarPath);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400758 if (tar_append_tree(t, buf, NULL, &excl[0]) != 0) {
Dees_Troy59df9262013-06-19 14:53:57 -0500759 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
760 return -1;
761 }
Dees_Troy3263e922013-03-15 11:42:57 -0500762 } else {
763 string temp = Strip_Root_Dir(buf);
Dees_Troy59df9262013-06-19 14:53:57 -0500764 strcpy(charTarPath, temp.c_str());
765 LOGINFO("tar_append_tree '%s' as '%s'\n", buf, charTarPath);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400766 if (tar_append_tree(t, buf, charTarPath, &excl[0]) != 0) {
Dees_Troy59df9262013-06-19 14:53:57 -0500767 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
768 return -1;
769 }
Dees_Troye34c1332013-02-06 19:13:00 +0000770 }
Dees_Troye34c1332013-02-06 19:13:00 +0000771 } else if (tardir != "/" && (de->d_type == DT_REG || de->d_type == DT_LNK)) {
Dees_Troy59df9262013-06-19 14:53:57 -0500772 LOGINFO("addFile '%s' including root: %i\n", buf, include_root);
Dees_Troy3263e922013-03-15 11:42:57 -0500773 if (addFile(buf, include_root) != 0)
774 return -1;
775 }
Dees_Troye34c1332013-02-06 19:13:00 +0000776 fflush(NULL);
777 }
778 closedir(d);
779 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500780 return 0;
781}
782
Dees_Troy83bd4832013-05-04 12:39:56 +0000783int twrpTar::tarList(bool include_root, std::vector<TarListStruct> *TarList, unsigned thread_id) {
784 struct stat st;
785 char buf[PATH_MAX];
786 int list_size = TarList->size(), i = 0, archive_count = 0;
787 string temp;
788 char actual_filename[PATH_MAX];
Dees_Troye34c1332013-02-06 19:13:00 +0000789
Dees_Troy83bd4832013-05-04 12:39:56 +0000790 basefn = tarfn;
791 temp = basefn + "%i%02i";
792 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
793 tarfn = actual_filename;
794 if (createTar() != 0) {
795 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
796 return -2;
797 }
798 Archive_Current_Size = 0;
799
800 while (i < list_size) {
801 if (TarList->at(i).thread_id == thread_id) {
802 strcpy(buf, TarList->at(i).fn.c_str());
803 stat(buf, &st);
804 if (st.st_mode & S_IFREG) { // item is a regular file
805 if (Archive_Current_Size + (unsigned long long)(st.st_size) > MAX_ARCHIVE_SIZE) {
806 if (closeTar() != 0) {
807 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
808 return -3;
809 }
810 archive_count++;
811 LOGINFO("Splitting thread ID %i into archive %i\n", thread_id, archive_count);
812 if (archive_count > 99) {
813 LOGINFO("BLAH!\n");
814 LOGERR("Too many archives for thread %i\n", thread_id);
815 return -4;
816 }
817 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
818 tarfn = actual_filename;
819 if (createTar() != 0) {
820 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
821 return -2;
822 }
823 Archive_Current_Size = 0;
824 }
825 Archive_Current_Size += (unsigned long long)(st.st_size);
826 }
827 if (addFile(buf, include_root) != 0) {
828 LOGERR("Error adding file '%s' to '%s'\n", buf, tarfn.c_str());
829 return -1;
830 }
831 }
832 i++;
833 }
834 if (closeTar() != 0) {
835 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
836 return -3;
837 }
838 LOGINFO("Thread id %i tarList done, %i archives.\n", thread_id, archive_count, i, list_size);
Dees_Troye34c1332013-02-06 19:13:00 +0000839 return 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500840}
841
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500842int twrpTar::create() {
Dees_Troye34c1332013-02-06 19:13:00 +0000843
844 init_libtar_buffer(0);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500845 if (createTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500846 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500847 if (tarDirs(false) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500848 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000849 if (closeTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500850 return -1;
Dees_Troye34c1332013-02-06 19:13:00 +0000851 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500852 return 0;
853}
854
Dees_Troy83bd4832013-05-04 12:39:56 +0000855void* twrpTar::createList(void *cookie) {
856
857 twrpTar* threadTar = (twrpTar*) cookie;
858 if (threadTar->tarList(true, threadTar->ItemList, threadTar->thread_id) == -1) {
859 LOGINFO("ERROR tarList for thread ID %i\n", threadTar->thread_id);
860 return (void*)-2;
861 }
862 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
863 return (void*)0;
864}
865
866void* twrpTar::extractMulti(void *cookie) {
867
868 twrpTar* threadTar = (twrpTar*) cookie;
869 int archive_count = 0;
870 string temp = threadTar->basefn + "%i%02i";
871 char actual_filename[255];
872 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
873 while (TWFunc::Path_Exists(actual_filename)) {
874 threadTar->tarfn = actual_filename;
875 if (threadTar->extract() != 0) {
876 LOGINFO("Error extracting '%s' in thread ID %i\n", actual_filename, threadTar->thread_id);
877 return (void*)-2;
878 }
879 archive_count++;
880 if (archive_count > 99)
881 break;
882 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
883 }
884 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
885 return (void*)0;
886}
887
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500888int twrpTar::addFilesToExistingTar(vector <string> files, string fn) {
889 char* charTarFile = (char*) fn.c_str();
890
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200891 if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500892 return -1;
893 removeEOT(charTarFile);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200894 if (tar_open(&t, charTarFile, NULL, O_WRONLY | O_APPEND | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500895 return -1;
896 for (unsigned int i = 0; i < files.size(); ++i) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500897 char* file = (char*) files.at(i).c_str();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500898 if (tar_append_file(t, file, file) == -1)
899 return -1;
900 }
901 if (tar_append_eof(t) == -1)
902 return -1;
903 if (tar_close(t) == -1)
904 return -1;
905 return 0;
906}
907
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500908int twrpTar::createTar() {
909 char* charTarFile = (char*) tarfn.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000910 char* charRootDir = (char*) tardir.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000911 static tartype_t type = { open, close, read, write_tar };
Dees_Troy83bd4832013-05-04 12:39:56 +0000912 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500913
Dees_Troy83bd4832013-05-04 12:39:56 +0000914 if (use_encryption && use_compression) {
915 // Compressed and encrypted
916 Archive_Current_Type = 3;
917 LOGINFO("Using encryption and compression...\n");
918 DataManager::GetValue("tw_backup_password", Password);
919 int i, pipes[4];
920
921 if (pipe(pipes) < 0) {
922 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500923 return -1;
924 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000925 if (pipe(pipes + 2) < 0) {
926 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500927 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000928 }
929 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400930
Dees_Troy83bd4832013-05-04 12:39:56 +0000931 if (pigz_pid < 0) {
932 LOGERR("pigz fork() failed\n");
933 for (i = 0; i < 4; i++)
934 close(pipes[i]); // close all
935 return -1;
936 } else if (pigz_pid == 0) {
937 // pigz Child
938 close(pipes[1]);
939 close(pipes[2]);
940 close(0);
941 dup2(pipes[0], 0);
942 close(1);
943 dup2(pipes[3], 1);
944 if (execlp("pigz", "pigz", "-", NULL) < 0) {
945 LOGERR("execlp pigz ERROR!\n");
946 close(pipes[0]);
947 close(pipes[3]);
948 _exit(-1);
949 }
950 } else {
951 // Parent
952 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400953
Dees_Troy83bd4832013-05-04 12:39:56 +0000954 if (oaes_pid < 0) {
955 LOGERR("openaes fork() failed\n");
956 for (i = 0; i < 4; i++)
957 close(pipes[i]); // close all
958 return -1;
959 } else if (oaes_pid == 0) {
960 // openaes Child
Dees_Troy5612cc82013-07-24 19:45:58 +0000961 int output_fd = open(tarfn.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
Dees_Troy83bd4832013-05-04 12:39:56 +0000962 if (output_fd < 0) {
963 LOGERR("Failed to open '%s'\n", tarfn.c_str());
964 for (i = 0; i < 4; i++)
965 close(pipes[i]); // close all
966 return -1;
967 }
968 close(pipes[0]);
969 close(pipes[1]);
970 close(pipes[3]);
971 close(0);
972 dup2(pipes[2], 0);
973 close(1);
974 dup2(output_fd, 1);
975 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
976 LOGERR("execlp openaes ERROR!\n");
977 close(pipes[2]);
978 close(output_fd);
979 _exit(-1);
980 }
981 } else {
982 // Parent
983 close(pipes[0]);
984 close(pipes[2]);
985 close(pipes[3]);
986 fd = pipes[1];
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200987 if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000988 close(fd);
989 LOGERR("tar_fdopen failed\n");
990 return -1;
991 }
992 return 0;
993 }
994 }
995 } else if (use_compression) {
996 // Compressed
997 Archive_Current_Type = 1;
998 LOGINFO("Using compression...\n");
999 int pigzfd[2];
1000
1001 if (pipe(pigzfd) < 0) {
1002 LOGERR("Error creating pipe\n");
1003 return -1;
1004 }
1005 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001006
Dees_Troy83bd4832013-05-04 12:39:56 +00001007 if (pigz_pid < 0) {
1008 LOGERR("fork() failed\n");
1009 close(pigzfd[0]);
1010 close(pigzfd[1]);
1011 return -1;
1012 } else if (pigz_pid == 0) {
1013 // Child
1014 close(pigzfd[1]); // close unused output pipe
Dees_Troy5612cc82013-07-24 19:45:58 +00001015 int output_fd = open(tarfn.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
Dees_Troy83bd4832013-05-04 12:39:56 +00001016 if (output_fd < 0) {
1017 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1018 close(pigzfd[0]);
1019 _exit(-1);
1020 }
1021 dup2(pigzfd[0], 0); // remap stdin
1022 dup2(output_fd, 1); // remap stdout to output file
1023 if (execlp("pigz", "pigz", "-", NULL) < 0) {
1024 LOGERR("execlp pigz ERROR!\n");
1025 close(output_fd);
1026 close(pigzfd[0]);
1027 _exit(-1);
1028 }
1029 } else {
1030 // Parent
1031 close(pigzfd[0]); // close parent input
1032 fd = pigzfd[1]; // copy parent output
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001033 if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001034 close(fd);
1035 LOGERR("tar_fdopen failed\n");
1036 return -1;
1037 }
1038 }
1039 } else if (use_encryption) {
1040 // Encrypted
1041 Archive_Current_Type = 2;
1042 LOGINFO("Using encryption...\n");
1043 DataManager::GetValue("tw_backup_password", Password);
1044 int oaesfd[2];
1045 pipe(oaesfd);
1046 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001047
Dees_Troy83bd4832013-05-04 12:39:56 +00001048 if (oaes_pid < 0) {
1049 LOGERR("fork() failed\n");
1050 close(oaesfd[0]);
1051 close(oaesfd[1]);
1052 return -1;
1053 } else if (oaes_pid == 0) {
1054 // Child
1055 close(oaesfd[1]); // close unused
Dees_Troy5612cc82013-07-24 19:45:58 +00001056 int output_fd = open(tarfn.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
Dees_Troy83bd4832013-05-04 12:39:56 +00001057 if (output_fd < 0) {
1058 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1059 _exit(-1);
1060 }
1061 dup2(oaesfd[0], 0); // remap stdin
1062 dup2(output_fd, 1); // remap stdout to output file
1063 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
1064 LOGERR("execlp openaes ERROR!\n");
1065 close(output_fd);
1066 close(oaesfd[0]);
1067 _exit(-1);
1068 }
1069 } else {
1070 // Parent
1071 close(oaesfd[0]); // close parent input
1072 fd = oaesfd[1]; // copy parent output
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001073 if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001074 close(fd);
1075 LOGERR("tar_fdopen failed\n");
1076 return -1;
1077 }
1078 return 0;
1079 }
1080 } else {
1081 // Not compressed or encrypted
1082 init_libtar_buffer(0);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001083 if (tar_open(&t, charTarFile, &type, O_WRONLY | O_CREAT | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) == -1) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001084 LOGERR("tar_open error opening '%s'\n", tarfn.c_str());
1085 return -1;
1086 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001087 }
1088 return 0;
1089}
1090
Dees_Troy83bd4832013-05-04 12:39:56 +00001091int twrpTar::openTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001092 char* charRootDir = (char*) tardir.c_str();
1093 char* charTarFile = (char*) tarfn.c_str();
Dees_Troy83bd4832013-05-04 12:39:56 +00001094 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001095
Dees_Troy83bd4832013-05-04 12:39:56 +00001096 if (Archive_Current_Type == 3) {
1097 LOGINFO("Opening encrypted and compressed backup...\n");
1098 DataManager::GetValue("tw_restore_password", Password);
1099 int i, pipes[4];
1100
1101 if (pipe(pipes) < 0) {
1102 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001103 return -1;
1104 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001105 if (pipe(pipes + 2) < 0) {
1106 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001107 return -1;
1108 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001109 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001110
Dees_Troy83bd4832013-05-04 12:39:56 +00001111 if (oaes_pid < 0) {
1112 LOGERR("pigz fork() failed\n");
1113 for (i = 0; i < 4; i++)
1114 close(pipes[i]); // close all
1115 return -1;
1116 } else if (oaes_pid == 0) {
1117 // openaes Child
1118 close(pipes[0]); // Close pipes that are not used by this child
1119 close(pipes[2]);
1120 close(pipes[3]);
1121 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1122 if (input_fd < 0) {
1123 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1124 close(pipes[1]);
1125 _exit(-1);
1126 }
1127 close(0);
1128 dup2(input_fd, 0);
1129 close(1);
1130 dup2(pipes[1], 1);
1131 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1132 LOGERR("execlp openaes ERROR!\n");
1133 close(input_fd);
1134 close(pipes[1]);
1135 _exit(-1);
1136 }
1137 } else {
1138 // Parent
1139 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001140
Dees_Troy83bd4832013-05-04 12:39:56 +00001141 if (pigz_pid < 0) {
1142 LOGERR("openaes fork() failed\n");
1143 for (i = 0; i < 4; i++)
1144 close(pipes[i]); // close all
1145 return -1;
1146 } else if (pigz_pid == 0) {
1147 // pigz Child
1148 close(pipes[1]); // Close pipes not used by this child
1149 close(pipes[2]);
1150 close(0);
1151 dup2(pipes[0], 0);
1152 close(1);
1153 dup2(pipes[3], 1);
1154 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1155 LOGERR("execlp pigz ERROR!\n");
1156 close(pipes[0]);
1157 close(pipes[3]);
1158 _exit(-1);
1159 }
1160 } else {
1161 // Parent
1162 close(pipes[0]); // Close pipes not used by parent
1163 close(pipes[1]);
1164 close(pipes[3]);
1165 fd = pipes[2];
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001166 if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001167 close(fd);
1168 LOGERR("tar_fdopen failed\n");
1169 return -1;
1170 }
1171 }
1172 }
1173 } else if (Archive_Current_Type == 2) {
1174 LOGINFO("Opening encrypted backup...\n");
1175 DataManager::GetValue("tw_restore_password", Password);
1176 int oaesfd[2];
1177
1178 pipe(oaesfd);
1179 oaes_pid = fork();
1180 if (oaes_pid < 0) {
1181 LOGERR("fork() failed\n");
1182 close(oaesfd[0]);
1183 close(oaesfd[1]);
1184 return -1;
1185 } else if (oaes_pid == 0) {
1186 // Child
1187 close(oaesfd[0]); // Close unused pipe
1188 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1189 if (input_fd < 0) {
1190 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1191 close(oaesfd[1]);
1192 _exit(-1);
1193 }
1194 close(0); // close stdin
1195 dup2(oaesfd[1], 1); // remap stdout
1196 dup2(input_fd, 0); // remap input fd to stdin
1197 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1198 LOGERR("execlp openaes ERROR!\n");
1199 close(input_fd);
1200 close(oaesfd[1]);
1201 _exit(-1);
1202 }
1203 } else {
1204 // Parent
1205 close(oaesfd[1]); // close parent output
1206 fd = oaesfd[0]; // copy parent input
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001207 if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001208 close(fd);
1209 LOGERR("tar_fdopen failed\n");
1210 return -1;
1211 }
1212 }
1213 } else if (Archive_Current_Type == 1) {
1214 LOGINFO("Opening as a gzip...\n");
1215 int pigzfd[2];
1216 pipe(pigzfd);
1217
1218 pigz_pid = fork();
1219 if (pigz_pid < 0) {
1220 LOGERR("fork() failed\n");
1221 close(pigzfd[0]);
1222 close(pigzfd[1]);
1223 return -1;
1224 } else if (pigz_pid == 0) {
1225 // Child
1226 close(pigzfd[0]);
1227 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1228 if (input_fd < 0) {
1229 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1230 _exit(-1);
1231 }
1232 dup2(input_fd, 0); // remap input fd to stdin
1233 dup2(pigzfd[1], 1); // remap stdout
1234 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1235 close(pigzfd[1]);
1236 close(input_fd);
1237 LOGERR("execlp openaes ERROR!\n");
1238 _exit(-1);
1239 }
1240 } else {
1241 // Parent
1242 close(pigzfd[1]); // close parent output
1243 fd = pigzfd[0]; // copy parent input
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001244 if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001245 close(fd);
1246 LOGERR("tar_fdopen failed\n");
1247 return -1;
1248 }
1249 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001250 } else if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001251 LOGERR("Unable to open tar archive '%s'\n", charTarFile);
1252 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001253 }
1254 return 0;
1255}
1256
1257string twrpTar::Strip_Root_Dir(string Path) {
1258 string temp;
1259 size_t slash;
1260
1261 if (Path.substr(0, 1) == "/")
1262 temp = Path.substr(1, Path.size() - 1);
1263 else
1264 temp = Path;
1265 slash = temp.find("/");
1266 if (slash == string::npos)
1267 return temp;
1268 else {
1269 string stripped;
1270
1271 stripped = temp.substr(slash, temp.size() - slash);
1272 return stripped;
1273 }
1274 return temp;
1275}
1276
1277int twrpTar::addFile(string fn, bool include_root) {
1278 char* charTarFile = (char*) fn.c_str();
1279 if (include_root) {
1280 if (tar_append_file(t, charTarFile, NULL) == -1)
1281 return -1;
1282 } else {
1283 string temp = Strip_Root_Dir(fn);
1284 char* charTarPath = (char*) temp.c_str();
1285 if (tar_append_file(t, charTarFile, charTarPath) == -1)
1286 return -1;
1287 }
1288 return 0;
1289}
1290
Dees_Troy83bd4832013-05-04 12:39:56 +00001291int twrpTar::closeTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001292 flush_libtar_buffer(t->fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001293 if (tar_append_eof(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001294 LOGERR("tar_append_eof(): %s\n", strerror(errno));
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001295 tar_close(t);
1296 return -1;
1297 }
1298 if (tar_close(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001299 LOGERR("Unable to close tar archive: '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001300 return -1;
1301 }
Dees_Troy2727b992013-08-14 20:09:30 +00001302 if (Archive_Current_Type > 0) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001303 close(fd);
Dees_Troy83bd4832013-05-04 12:39:56 +00001304 int status;
1305 if (pigz_pid > 0 && TWFunc::Wait_For_Child(pigz_pid, &status, "pigz") != 0)
1306 return -1;
1307 if (oaes_pid > 0 && TWFunc::Wait_For_Child(oaes_pid, &status, "openaes") != 0)
1308 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001309 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001310 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001311 return 0;
1312}
1313
1314int twrpTar::removeEOT(string tarFile) {
1315 char* charTarFile = (char*) tarFile.c_str();
1316 off_t tarFileEnd;
1317 while (th_read(t) == 0) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001318 if (TH_ISREG(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001319 tar_skip_regfile(t);
1320 tarFileEnd = lseek(t->fd, 0, SEEK_CUR);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001321 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001322 if (tar_close(t) == -1)
1323 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001324 if (truncate(charTarFile, tarFileEnd) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001325 return -1;
1326 return 0;
1327}
1328
n0d33b511632013-03-06 21:14:15 +02001329int twrpTar::entryExists(string entry) {
1330 char* searchstr = (char*)entry.c_str();
1331 int ret;
1332
Dees_Troy83bd4832013-05-04 12:39:56 +00001333 Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
n0d33b511632013-03-06 21:14:15 +02001334
Dees_Troy83bd4832013-05-04 12:39:56 +00001335 if (openTar() == -1)
n0d33b511632013-03-06 21:14:15 +02001336 ret = 0;
1337 else
1338 ret = tar_find(t, searchstr);
1339
Dees_Troy83bd4832013-05-04 12:39:56 +00001340 if (closeTar() != 0)
1341 LOGINFO("Unable to close tar after searching for entry.\n");
n0d33b511632013-03-06 21:14:15 +02001342
1343 return ret;
1344}
1345
Dees_Troy83bd4832013-05-04 12:39:56 +00001346unsigned long long twrpTar::uncompressedSize() {
1347 int type = 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001348 unsigned long long total_size = 0;
Dees_Troy83bd4832013-05-04 12:39:56 +00001349 string Tar, Command, result;
1350 vector<string> split;
1351
1352 Tar = TWFunc::Get_Filename(tarfn);
1353 type = TWFunc::Get_File_Type(tarfn);
1354 if (type == 0)
1355 total_size = TWFunc::Get_File_Size(tarfn);
1356 else {
1357 Command = "pigz -l " + tarfn;
1358 /* if we set Command = "pigz -l " + tarfn + " | sed '1d' | cut -f5 -d' '";
1359 we get the uncompressed size at once. */
1360 TWFunc::Exec_Cmd(Command, result);
1361 if (!result.empty()) {
1362 /* Expected output:
1363 compressed original reduced name
1364 95855838 179403776 -1.3% data.yaffs2.win
1365 ^
1366 split[5]
1367 */
1368 split = TWFunc::split_string(result, ' ', true);
1369 if (split.size() > 4)
1370 total_size = atoi(split[5].c_str());
1371 }
1372 }
1373 LOGINFO("%s's uncompressed size: %llu bytes\n", Tar.c_str(), total_size);
1374
1375 return total_size;
1376}
1377
Dees_Troye34c1332013-02-06 19:13:00 +00001378extern "C" ssize_t write_tar(int fd, const void *buffer, size_t size) {
1379 return (ssize_t) write_libtar_buffer(fd, buffer, size);
Dees_Troy40bbcf82013-02-12 15:01:53 +00001380}