blob: 48d529b637678861ada9f430966d413f97113f23 [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;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500717#endif
bigbiff bigbiff34684ff2013-12-01 21:03:45 -0500718 dir = de->d_name;
719 skip_dir = du.check_skip_dirs(dir);
720 if (de->d_type == DT_BLK || de->d_type == DT_CHR || skip_dir)
Dees_Troy3263e922013-03-15 11:42:57 -0500721 continue;
Dees_Troy83bd4832013-05-04 12:39:56 +0000722
723 // Skip excluded stuff
724 if (split.size() > 0) {
725 skip = false;
726 for (i = 0; i < split.size(); i++) {
727 if (strcmp(de->d_name, split[i].c_str()) == 0) {
728 LOGINFO("excluding %s\n", de->d_name);
729 skip = true;
730 break;
731 }
732 }
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400733 if (skip) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000734 continue;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400735 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000736 }
737
Dees_Troye34c1332013-02-06 19:13:00 +0000738 subfolder = mainfolder;
Dees_Troy3263e922013-03-15 11:42:57 -0500739 if (strcmp(de->d_name, ".") != 0) {
740 subfolder += de->d_name;
741 } else {
bigbiff bigbiffc49d7062013-10-11 20:28:00 -0400742 std::string parentDir = basename(subfolder.c_str());
743 LOGINFO("parentDir: %s\n", parentDir.c_str());
744 if (!parentDir.compare("lost+found"))
745 continue;
Dees Troyed400772013-10-09 14:45:24 +0000746 LOGINFO("tarDirs addFile '%s' including root: %i\n", subfolder.c_str(), include_root);
Dees_Troy3263e922013-03-15 11:42:57 -0500747 if (addFile(subfolder, include_root) != 0)
748 return -1;
749 continue;
750 }
Dees_Troye34c1332013-02-06 19:13:00 +0000751 strcpy(buf, subfolder.c_str());
752 if (de->d_type == DT_DIR) {
Dees_Troy3263e922013-03-15 11:42:57 -0500753 if (include_root) {
Dees_Troy59df9262013-06-19 14:53:57 -0500754 charTarPath[0] = NULL;
755 LOGINFO("tar_append_tree '%s' as NULL\n", buf, charTarPath);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400756 if (tar_append_tree(t, buf, NULL, &excl[0]) != 0) {
Dees_Troy59df9262013-06-19 14:53:57 -0500757 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
758 return -1;
759 }
Dees_Troy3263e922013-03-15 11:42:57 -0500760 } else {
761 string temp = Strip_Root_Dir(buf);
Dees_Troy59df9262013-06-19 14:53:57 -0500762 strcpy(charTarPath, temp.c_str());
763 LOGINFO("tar_append_tree '%s' as '%s'\n", buf, charTarPath);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400764 if (tar_append_tree(t, buf, charTarPath, &excl[0]) != 0) {
Dees_Troy59df9262013-06-19 14:53:57 -0500765 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
766 return -1;
767 }
Dees_Troye34c1332013-02-06 19:13:00 +0000768 }
Dees_Troye34c1332013-02-06 19:13:00 +0000769 } else if (tardir != "/" && (de->d_type == DT_REG || de->d_type == DT_LNK)) {
Dees_Troy59df9262013-06-19 14:53:57 -0500770 LOGINFO("addFile '%s' including root: %i\n", buf, include_root);
Dees_Troy3263e922013-03-15 11:42:57 -0500771 if (addFile(buf, include_root) != 0)
772 return -1;
773 }
Dees_Troye34c1332013-02-06 19:13:00 +0000774 fflush(NULL);
775 }
776 closedir(d);
777 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500778 return 0;
779}
780
Dees_Troy83bd4832013-05-04 12:39:56 +0000781int twrpTar::tarList(bool include_root, std::vector<TarListStruct> *TarList, unsigned thread_id) {
782 struct stat st;
783 char buf[PATH_MAX];
784 int list_size = TarList->size(), i = 0, archive_count = 0;
785 string temp;
786 char actual_filename[PATH_MAX];
Dees_Troye34c1332013-02-06 19:13:00 +0000787
Dees_Troy83bd4832013-05-04 12:39:56 +0000788 basefn = tarfn;
789 temp = basefn + "%i%02i";
790 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
791 tarfn = actual_filename;
792 if (createTar() != 0) {
793 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
794 return -2;
795 }
796 Archive_Current_Size = 0;
797
798 while (i < list_size) {
799 if (TarList->at(i).thread_id == thread_id) {
800 strcpy(buf, TarList->at(i).fn.c_str());
801 stat(buf, &st);
802 if (st.st_mode & S_IFREG) { // item is a regular file
803 if (Archive_Current_Size + (unsigned long long)(st.st_size) > MAX_ARCHIVE_SIZE) {
804 if (closeTar() != 0) {
805 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
806 return -3;
807 }
808 archive_count++;
809 LOGINFO("Splitting thread ID %i into archive %i\n", thread_id, archive_count);
810 if (archive_count > 99) {
811 LOGINFO("BLAH!\n");
812 LOGERR("Too many archives for thread %i\n", thread_id);
813 return -4;
814 }
815 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
816 tarfn = actual_filename;
817 if (createTar() != 0) {
818 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
819 return -2;
820 }
821 Archive_Current_Size = 0;
822 }
823 Archive_Current_Size += (unsigned long long)(st.st_size);
824 }
825 if (addFile(buf, include_root) != 0) {
826 LOGERR("Error adding file '%s' to '%s'\n", buf, tarfn.c_str());
827 return -1;
828 }
829 }
830 i++;
831 }
832 if (closeTar() != 0) {
833 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
834 return -3;
835 }
836 LOGINFO("Thread id %i tarList done, %i archives.\n", thread_id, archive_count, i, list_size);
Dees_Troye34c1332013-02-06 19:13:00 +0000837 return 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500838}
839
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500840int twrpTar::create() {
Dees_Troye34c1332013-02-06 19:13:00 +0000841
842 init_libtar_buffer(0);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500843 if (createTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500844 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500845 if (tarDirs(false) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500846 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000847 if (closeTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500848 return -1;
Dees_Troye34c1332013-02-06 19:13:00 +0000849 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500850 return 0;
851}
852
Dees_Troy83bd4832013-05-04 12:39:56 +0000853void* twrpTar::createList(void *cookie) {
854
855 twrpTar* threadTar = (twrpTar*) cookie;
856 if (threadTar->tarList(true, threadTar->ItemList, threadTar->thread_id) == -1) {
857 LOGINFO("ERROR tarList for thread ID %i\n", threadTar->thread_id);
858 return (void*)-2;
859 }
860 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
861 return (void*)0;
862}
863
864void* twrpTar::extractMulti(void *cookie) {
865
866 twrpTar* threadTar = (twrpTar*) cookie;
867 int archive_count = 0;
868 string temp = threadTar->basefn + "%i%02i";
869 char actual_filename[255];
870 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
871 while (TWFunc::Path_Exists(actual_filename)) {
872 threadTar->tarfn = actual_filename;
873 if (threadTar->extract() != 0) {
874 LOGINFO("Error extracting '%s' in thread ID %i\n", actual_filename, threadTar->thread_id);
875 return (void*)-2;
876 }
877 archive_count++;
878 if (archive_count > 99)
879 break;
880 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
881 }
882 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
883 return (void*)0;
884}
885
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500886int twrpTar::addFilesToExistingTar(vector <string> files, string fn) {
887 char* charTarFile = (char*) fn.c_str();
888
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200889 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 -0500890 return -1;
891 removeEOT(charTarFile);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200892 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 -0500893 return -1;
894 for (unsigned int i = 0; i < files.size(); ++i) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500895 char* file = (char*) files.at(i).c_str();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500896 if (tar_append_file(t, file, file) == -1)
897 return -1;
898 }
899 if (tar_append_eof(t) == -1)
900 return -1;
901 if (tar_close(t) == -1)
902 return -1;
903 return 0;
904}
905
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500906int twrpTar::createTar() {
907 char* charTarFile = (char*) tarfn.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000908 char* charRootDir = (char*) tardir.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000909 static tartype_t type = { open, close, read, write_tar };
Dees_Troy83bd4832013-05-04 12:39:56 +0000910 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500911
Dees_Troy83bd4832013-05-04 12:39:56 +0000912 if (use_encryption && use_compression) {
913 // Compressed and encrypted
914 Archive_Current_Type = 3;
915 LOGINFO("Using encryption and compression...\n");
916 DataManager::GetValue("tw_backup_password", Password);
917 int i, pipes[4];
918
919 if (pipe(pipes) < 0) {
920 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500921 return -1;
922 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000923 if (pipe(pipes + 2) < 0) {
924 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500925 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000926 }
927 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400928
Dees_Troy83bd4832013-05-04 12:39:56 +0000929 if (pigz_pid < 0) {
930 LOGERR("pigz fork() failed\n");
931 for (i = 0; i < 4; i++)
932 close(pipes[i]); // close all
933 return -1;
934 } else if (pigz_pid == 0) {
935 // pigz Child
936 close(pipes[1]);
937 close(pipes[2]);
938 close(0);
939 dup2(pipes[0], 0);
940 close(1);
941 dup2(pipes[3], 1);
942 if (execlp("pigz", "pigz", "-", NULL) < 0) {
943 LOGERR("execlp pigz ERROR!\n");
944 close(pipes[0]);
945 close(pipes[3]);
946 _exit(-1);
947 }
948 } else {
949 // Parent
950 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400951
Dees_Troy83bd4832013-05-04 12:39:56 +0000952 if (oaes_pid < 0) {
953 LOGERR("openaes fork() failed\n");
954 for (i = 0; i < 4; i++)
955 close(pipes[i]); // close all
956 return -1;
957 } else if (oaes_pid == 0) {
958 // openaes Child
Dees_Troy5612cc82013-07-24 19:45:58 +0000959 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 +0000960 if (output_fd < 0) {
961 LOGERR("Failed to open '%s'\n", tarfn.c_str());
962 for (i = 0; i < 4; i++)
963 close(pipes[i]); // close all
964 return -1;
965 }
966 close(pipes[0]);
967 close(pipes[1]);
968 close(pipes[3]);
969 close(0);
970 dup2(pipes[2], 0);
971 close(1);
972 dup2(output_fd, 1);
973 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
974 LOGERR("execlp openaes ERROR!\n");
975 close(pipes[2]);
976 close(output_fd);
977 _exit(-1);
978 }
979 } else {
980 // Parent
981 close(pipes[0]);
982 close(pipes[2]);
983 close(pipes[3]);
984 fd = pipes[1];
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200985 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 +0000986 close(fd);
987 LOGERR("tar_fdopen failed\n");
988 return -1;
989 }
990 return 0;
991 }
992 }
993 } else if (use_compression) {
994 // Compressed
995 Archive_Current_Type = 1;
996 LOGINFO("Using compression...\n");
997 int pigzfd[2];
998
999 if (pipe(pigzfd) < 0) {
1000 LOGERR("Error creating pipe\n");
1001 return -1;
1002 }
1003 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001004
Dees_Troy83bd4832013-05-04 12:39:56 +00001005 if (pigz_pid < 0) {
1006 LOGERR("fork() failed\n");
1007 close(pigzfd[0]);
1008 close(pigzfd[1]);
1009 return -1;
1010 } else if (pigz_pid == 0) {
1011 // Child
1012 close(pigzfd[1]); // close unused output pipe
Dees_Troy5612cc82013-07-24 19:45:58 +00001013 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 +00001014 if (output_fd < 0) {
1015 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1016 close(pigzfd[0]);
1017 _exit(-1);
1018 }
1019 dup2(pigzfd[0], 0); // remap stdin
1020 dup2(output_fd, 1); // remap stdout to output file
1021 if (execlp("pigz", "pigz", "-", NULL) < 0) {
1022 LOGERR("execlp pigz ERROR!\n");
1023 close(output_fd);
1024 close(pigzfd[0]);
1025 _exit(-1);
1026 }
1027 } else {
1028 // Parent
1029 close(pigzfd[0]); // close parent input
1030 fd = pigzfd[1]; // copy parent output
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001031 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 +00001032 close(fd);
1033 LOGERR("tar_fdopen failed\n");
1034 return -1;
1035 }
1036 }
1037 } else if (use_encryption) {
1038 // Encrypted
1039 Archive_Current_Type = 2;
1040 LOGINFO("Using encryption...\n");
1041 DataManager::GetValue("tw_backup_password", Password);
1042 int oaesfd[2];
1043 pipe(oaesfd);
1044 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001045
Dees_Troy83bd4832013-05-04 12:39:56 +00001046 if (oaes_pid < 0) {
1047 LOGERR("fork() failed\n");
1048 close(oaesfd[0]);
1049 close(oaesfd[1]);
1050 return -1;
1051 } else if (oaes_pid == 0) {
1052 // Child
1053 close(oaesfd[1]); // close unused
Dees_Troy5612cc82013-07-24 19:45:58 +00001054 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 +00001055 if (output_fd < 0) {
1056 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1057 _exit(-1);
1058 }
1059 dup2(oaesfd[0], 0); // remap stdin
1060 dup2(output_fd, 1); // remap stdout to output file
1061 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
1062 LOGERR("execlp openaes ERROR!\n");
1063 close(output_fd);
1064 close(oaesfd[0]);
1065 _exit(-1);
1066 }
1067 } else {
1068 // Parent
1069 close(oaesfd[0]); // close parent input
1070 fd = oaesfd[1]; // copy parent output
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001071 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 +00001072 close(fd);
1073 LOGERR("tar_fdopen failed\n");
1074 return -1;
1075 }
1076 return 0;
1077 }
1078 } else {
1079 // Not compressed or encrypted
1080 init_libtar_buffer(0);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001081 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 +00001082 LOGERR("tar_open error opening '%s'\n", tarfn.c_str());
1083 return -1;
1084 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001085 }
1086 return 0;
1087}
1088
Dees_Troy83bd4832013-05-04 12:39:56 +00001089int twrpTar::openTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001090 char* charRootDir = (char*) tardir.c_str();
1091 char* charTarFile = (char*) tarfn.c_str();
Dees_Troy83bd4832013-05-04 12:39:56 +00001092 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001093
Dees_Troy83bd4832013-05-04 12:39:56 +00001094 if (Archive_Current_Type == 3) {
1095 LOGINFO("Opening encrypted and compressed backup...\n");
1096 DataManager::GetValue("tw_restore_password", Password);
1097 int i, pipes[4];
1098
1099 if (pipe(pipes) < 0) {
1100 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001101 return -1;
1102 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001103 if (pipe(pipes + 2) < 0) {
1104 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001105 return -1;
1106 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001107 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001108
Dees_Troy83bd4832013-05-04 12:39:56 +00001109 if (oaes_pid < 0) {
1110 LOGERR("pigz fork() failed\n");
1111 for (i = 0; i < 4; i++)
1112 close(pipes[i]); // close all
1113 return -1;
1114 } else if (oaes_pid == 0) {
1115 // openaes Child
1116 close(pipes[0]); // Close pipes that are not used by this child
1117 close(pipes[2]);
1118 close(pipes[3]);
1119 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1120 if (input_fd < 0) {
1121 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1122 close(pipes[1]);
1123 _exit(-1);
1124 }
1125 close(0);
1126 dup2(input_fd, 0);
1127 close(1);
1128 dup2(pipes[1], 1);
1129 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1130 LOGERR("execlp openaes ERROR!\n");
1131 close(input_fd);
1132 close(pipes[1]);
1133 _exit(-1);
1134 }
1135 } else {
1136 // Parent
1137 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001138
Dees_Troy83bd4832013-05-04 12:39:56 +00001139 if (pigz_pid < 0) {
1140 LOGERR("openaes fork() failed\n");
1141 for (i = 0; i < 4; i++)
1142 close(pipes[i]); // close all
1143 return -1;
1144 } else if (pigz_pid == 0) {
1145 // pigz Child
1146 close(pipes[1]); // Close pipes not used by this child
1147 close(pipes[2]);
1148 close(0);
1149 dup2(pipes[0], 0);
1150 close(1);
1151 dup2(pipes[3], 1);
1152 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1153 LOGERR("execlp pigz ERROR!\n");
1154 close(pipes[0]);
1155 close(pipes[3]);
1156 _exit(-1);
1157 }
1158 } else {
1159 // Parent
1160 close(pipes[0]); // Close pipes not used by parent
1161 close(pipes[1]);
1162 close(pipes[3]);
1163 fd = pipes[2];
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001164 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 +00001165 close(fd);
1166 LOGERR("tar_fdopen failed\n");
1167 return -1;
1168 }
1169 }
1170 }
1171 } else if (Archive_Current_Type == 2) {
1172 LOGINFO("Opening encrypted backup...\n");
1173 DataManager::GetValue("tw_restore_password", Password);
1174 int oaesfd[2];
1175
1176 pipe(oaesfd);
1177 oaes_pid = fork();
1178 if (oaes_pid < 0) {
1179 LOGERR("fork() failed\n");
1180 close(oaesfd[0]);
1181 close(oaesfd[1]);
1182 return -1;
1183 } else if (oaes_pid == 0) {
1184 // Child
1185 close(oaesfd[0]); // Close unused pipe
1186 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1187 if (input_fd < 0) {
1188 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1189 close(oaesfd[1]);
1190 _exit(-1);
1191 }
1192 close(0); // close stdin
1193 dup2(oaesfd[1], 1); // remap stdout
1194 dup2(input_fd, 0); // remap input fd to stdin
1195 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1196 LOGERR("execlp openaes ERROR!\n");
1197 close(input_fd);
1198 close(oaesfd[1]);
1199 _exit(-1);
1200 }
1201 } else {
1202 // Parent
1203 close(oaesfd[1]); // close parent output
1204 fd = oaesfd[0]; // copy parent input
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001205 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 +00001206 close(fd);
1207 LOGERR("tar_fdopen failed\n");
1208 return -1;
1209 }
1210 }
1211 } else if (Archive_Current_Type == 1) {
1212 LOGINFO("Opening as a gzip...\n");
1213 int pigzfd[2];
1214 pipe(pigzfd);
1215
1216 pigz_pid = fork();
1217 if (pigz_pid < 0) {
1218 LOGERR("fork() failed\n");
1219 close(pigzfd[0]);
1220 close(pigzfd[1]);
1221 return -1;
1222 } else if (pigz_pid == 0) {
1223 // Child
1224 close(pigzfd[0]);
1225 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1226 if (input_fd < 0) {
1227 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1228 _exit(-1);
1229 }
1230 dup2(input_fd, 0); // remap input fd to stdin
1231 dup2(pigzfd[1], 1); // remap stdout
1232 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1233 close(pigzfd[1]);
1234 close(input_fd);
1235 LOGERR("execlp openaes ERROR!\n");
1236 _exit(-1);
1237 }
1238 } else {
1239 // Parent
1240 close(pigzfd[1]); // close parent output
1241 fd = pigzfd[0]; // copy parent input
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001242 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 +00001243 close(fd);
1244 LOGERR("tar_fdopen failed\n");
1245 return -1;
1246 }
1247 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001248 } 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 +00001249 LOGERR("Unable to open tar archive '%s'\n", charTarFile);
1250 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001251 }
1252 return 0;
1253}
1254
1255string twrpTar::Strip_Root_Dir(string Path) {
1256 string temp;
1257 size_t slash;
1258
1259 if (Path.substr(0, 1) == "/")
1260 temp = Path.substr(1, Path.size() - 1);
1261 else
1262 temp = Path;
1263 slash = temp.find("/");
1264 if (slash == string::npos)
1265 return temp;
1266 else {
1267 string stripped;
1268
1269 stripped = temp.substr(slash, temp.size() - slash);
1270 return stripped;
1271 }
1272 return temp;
1273}
1274
1275int twrpTar::addFile(string fn, bool include_root) {
1276 char* charTarFile = (char*) fn.c_str();
1277 if (include_root) {
1278 if (tar_append_file(t, charTarFile, NULL) == -1)
1279 return -1;
1280 } else {
1281 string temp = Strip_Root_Dir(fn);
1282 char* charTarPath = (char*) temp.c_str();
1283 if (tar_append_file(t, charTarFile, charTarPath) == -1)
1284 return -1;
1285 }
1286 return 0;
1287}
1288
Dees_Troy83bd4832013-05-04 12:39:56 +00001289int twrpTar::closeTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001290 flush_libtar_buffer(t->fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001291 if (tar_append_eof(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001292 LOGERR("tar_append_eof(): %s\n", strerror(errno));
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001293 tar_close(t);
1294 return -1;
1295 }
1296 if (tar_close(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001297 LOGERR("Unable to close tar archive: '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001298 return -1;
1299 }
Dees_Troy2727b992013-08-14 20:09:30 +00001300 if (Archive_Current_Type > 0) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001301 close(fd);
Dees_Troy83bd4832013-05-04 12:39:56 +00001302 int status;
1303 if (pigz_pid > 0 && TWFunc::Wait_For_Child(pigz_pid, &status, "pigz") != 0)
1304 return -1;
1305 if (oaes_pid > 0 && TWFunc::Wait_For_Child(oaes_pid, &status, "openaes") != 0)
1306 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001307 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001308 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001309 return 0;
1310}
1311
1312int twrpTar::removeEOT(string tarFile) {
1313 char* charTarFile = (char*) tarFile.c_str();
1314 off_t tarFileEnd;
1315 while (th_read(t) == 0) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001316 if (TH_ISREG(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001317 tar_skip_regfile(t);
1318 tarFileEnd = lseek(t->fd, 0, SEEK_CUR);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001319 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001320 if (tar_close(t) == -1)
1321 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001322 if (truncate(charTarFile, tarFileEnd) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001323 return -1;
1324 return 0;
1325}
1326
n0d33b511632013-03-06 21:14:15 +02001327int twrpTar::entryExists(string entry) {
1328 char* searchstr = (char*)entry.c_str();
1329 int ret;
1330
Dees_Troy83bd4832013-05-04 12:39:56 +00001331 Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
n0d33b511632013-03-06 21:14:15 +02001332
Dees_Troy83bd4832013-05-04 12:39:56 +00001333 if (openTar() == -1)
n0d33b511632013-03-06 21:14:15 +02001334 ret = 0;
1335 else
1336 ret = tar_find(t, searchstr);
1337
Dees_Troy83bd4832013-05-04 12:39:56 +00001338 if (closeTar() != 0)
1339 LOGINFO("Unable to close tar after searching for entry.\n");
n0d33b511632013-03-06 21:14:15 +02001340
1341 return ret;
1342}
1343
Dees_Troy83bd4832013-05-04 12:39:56 +00001344unsigned long long twrpTar::uncompressedSize() {
1345 int type = 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001346 unsigned long long total_size = 0;
Dees_Troy83bd4832013-05-04 12:39:56 +00001347 string Tar, Command, result;
1348 vector<string> split;
1349
1350 Tar = TWFunc::Get_Filename(tarfn);
1351 type = TWFunc::Get_File_Type(tarfn);
1352 if (type == 0)
1353 total_size = TWFunc::Get_File_Size(tarfn);
1354 else {
1355 Command = "pigz -l " + tarfn;
1356 /* if we set Command = "pigz -l " + tarfn + " | sed '1d' | cut -f5 -d' '";
1357 we get the uncompressed size at once. */
1358 TWFunc::Exec_Cmd(Command, result);
1359 if (!result.empty()) {
1360 /* Expected output:
1361 compressed original reduced name
1362 95855838 179403776 -1.3% data.yaffs2.win
1363 ^
1364 split[5]
1365 */
1366 split = TWFunc::split_string(result, ' ', true);
1367 if (split.size() > 4)
1368 total_size = atoi(split[5].c_str());
1369 }
1370 }
1371 LOGINFO("%s's uncompressed size: %llu bytes\n", Tar.c_str(), total_size);
1372
1373 return total_size;
1374}
1375
Dees_Troye34c1332013-02-06 19:13:00 +00001376extern "C" ssize_t write_tar(int fd, const void *buffer, size_t size) {
1377 return (ssize_t) write_libtar_buffer(fd, buffer, size);
Dees_Troy40bbcf82013-02-12 15:01:53 +00001378}