blob: 76c23c868672a82dbeca579fbc8ed1ac594de245 [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/*
Dees_Troye34c1332013-02-06 19:13:00 +00002 Copyright 2012 bigbiff/Dees_Troy TeamWin
3 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>
37#include <sys/mman.h>
38#include "twrpTar.hpp"
Dees_Troy2673cec2013-04-02 20:22:16 +000039#include "twcommon.h"
bigbiff bigbiff9c754052013-01-09 09:09:08 -050040#include "data.hpp"
41#include "variables.h"
bigbiff bigbiff9c754052013-01-09 09:09:08 -050042#include "twrp-functions.hpp"
43
44using namespace std;
45
Dees_Troy83bd4832013-05-04 12:39:56 +000046twrpTar::twrpTar(void) {
47 use_encryption = 0;
48 userdata_encryption = 0;
49 use_compression = 0;
50 split_archives = 0;
51 has_data_media = 0;
52 pigz_pid = 0;
53 oaes_pid = 0;
54}
55
56twrpTar::~twrpTar(void) {
57 // Do nothing
58}
59
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050060void twrpTar::setfn(string fn) {
61 tarfn = fn;
62}
63
64void twrpTar::setdir(string dir) {
65 tardir = dir;
66}
67
Dees_Troy83bd4832013-05-04 12:39:56 +000068void twrpTar::setexcl(string exclude) {
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -040069 tarexclude.push_back(exclude);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050070}
71
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -050072int twrpTar::createTarFork() {
Dees_Troy83bd4832013-05-04 12:39:56 +000073 int status = 0;
74 pid_t pid, rc_pid;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -050075 if ((pid = fork()) == -1) {
Dees_Troy2673cec2013-04-02 20:22:16 +000076 LOGINFO("create tar failed to fork.\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050077 return -1;
78 }
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -050079 if (pid == 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +000080 // Child process
81 if (use_encryption || userdata_encryption) {
82 LOGINFO("Using encryption\n");
83 DIR* d;
84 struct dirent* de;
85 unsigned long long regular_size = 0, encrypt_size = 0, target_size = 0, core_count = 1;
86 unsigned enc_thread_id = 1, regular_thread_id = 0, i, start_thread_id = 1;
87 int item_len, ret, thread_error = 0;
88 std::vector<TarListStruct> RegularList;
89 std::vector<TarListStruct> EncryptList;
90 string FileName;
91 struct TarListStruct TarItem;
92 twrpTar reg, enc[9];
93 struct stat st;
94 pthread_t enc_thread[9];
95 pthread_attr_t tattr;
96 void *thread_return;
97
98 core_count = sysconf(_SC_NPROCESSORS_CONF);
99 if (core_count > 8)
100 core_count = 8;
101 LOGINFO(" Core Count : %llu\n", core_count);
102 Archive_Current_Size = 0;
103
104 d = opendir(tardir.c_str());
105 if (d == NULL) {
106 LOGERR("error opening '%s'\n", tardir.c_str());
107 _exit(-1);
108 }
109 // Figure out the size of all data to be encrypted and create a list of unencrypted files
110 while ((de = readdir(d)) != NULL) {
111 FileName = tardir + "/";
112 FileName += de->d_name;
113 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
114 continue; // Skip /data/media
115 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
116 continue;
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400117 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0 && strcmp(de->d_name, "lost+found") != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000118 item_len = strlen(de->d_name);
119 if (userdata_encryption && ((item_len >= 3 && strncmp(de->d_name, "app", 3) == 0) || (item_len >= 6 && strncmp(de->d_name, "dalvik", 6) == 0))) {
120 if (Generate_TarList(FileName, &RegularList, &target_size, &regular_thread_id) < 0) {
121 LOGERR("Error in Generate_TarList with regular list!\n");
122 closedir(d);
123 _exit(-1);
124 }
125 regular_size += TWFunc::Get_Folder_Size(FileName, false);
126 } else {
127 encrypt_size += TWFunc::Get_Folder_Size(FileName, false);
128 }
129 } else if (de->d_type == DT_REG) {
130 stat(FileName.c_str(), &st);
131 encrypt_size += (unsigned long long)(st.st_size);
132 }
133 }
134 closedir(d);
135
136 target_size = encrypt_size / core_count;
137 target_size++;
138 LOGINFO(" Unencrypted size: %llu\n", regular_size);
139 LOGINFO(" Encrypted size : %llu\n", encrypt_size);
140 LOGINFO(" Target size : %llu\n", target_size);
141 if (!userdata_encryption) {
142 enc_thread_id = 0;
143 start_thread_id = 0;
144 core_count--;
145 }
146 Archive_Current_Size = 0;
147
148 d = opendir(tardir.c_str());
149 if (d == NULL) {
150 LOGERR("error opening '%s'\n", tardir.c_str());
151 _exit(-1);
152 }
153 // Divide up the encrypted file list for threading
154 while ((de = readdir(d)) != NULL) {
155 FileName = tardir + "/";
156 FileName += de->d_name;
157 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
158 continue; // Skip /data/media
159 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
160 continue;
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400161 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0 && strcmp(de->d_name, "lost+found") != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000162 item_len = strlen(de->d_name);
163 if (userdata_encryption && ((item_len >= 3 && strncmp(de->d_name, "app", 3) == 0) || (item_len >= 6 && strncmp(de->d_name, "dalvik", 6) == 0))) {
164 // Do nothing, we added these to RegularList earlier
165 } else {
166 FileName = tardir + "/";
167 FileName += de->d_name;
168 if (Generate_TarList(FileName, &EncryptList, &target_size, &enc_thread_id) < 0) {
169 LOGERR("Error in Generate_TarList with encrypted list!\n");
170 closedir(d);
171 _exit(-1);
172 }
173 }
174 } else if (de->d_type == DT_REG || de->d_type == DT_LNK) {
175 stat(FileName.c_str(), &st);
176 if (de->d_type == DT_REG)
177 Archive_Current_Size += (unsigned long long)(st.st_size);
178 TarItem.fn = FileName;
179 TarItem.thread_id = enc_thread_id;
180 EncryptList.push_back(TarItem);
181 }
182 }
183 closedir(d);
184 if (enc_thread_id != core_count) {
185 LOGERR("Error dividing up threads for encryption, %i threads for %i cores!\n", enc_thread_id, core_count);
186 if (enc_thread_id > core_count)
187 _exit(-1);
188 else
189 LOGERR("Continuining anyway.");
190 }
191
192 if (userdata_encryption) {
193 // Create a backup of unencrypted data
194 reg.setfn(tarfn);
195 reg.ItemList = &RegularList;
196 reg.thread_id = 0;
197 reg.use_encryption = 0;
198 reg.use_compression = use_compression;
199 LOGINFO("Creating unencrypted backup...\n");
200 if (createList((void*)&reg) != 0) {
201 LOGERR("Error creating unencrypted backup.\n");
202 _exit(-1);
203 }
204 }
205
206 if (pthread_attr_init(&tattr)) {
207 LOGERR("Unable to pthread_attr_init\n");
208 _exit(-1);
209 }
210 if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
211 LOGERR("Error setting pthread_attr_setdetachstate\n");
212 _exit(-1);
213 }
214 if (pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM)) {
215 LOGERR("Error setting pthread_attr_setscope\n");
216 _exit(-1);
217 }
218 /*if (pthread_attr_setstacksize(&tattr, 524288)) {
219 LOGERR("Error setting pthread_attr_setstacksize\n");
220 _exit(-1);
221 }*/
222
223 // Create threads for the divided up encryption lists
224 for (i = start_thread_id; i <= core_count; i++) {
225 enc[i].setdir(tardir);
226 enc[i].setfn(tarfn);
227 enc[i].ItemList = &EncryptList;
228 enc[i].thread_id = i;
229 enc[i].use_encryption = use_encryption;
230 enc[i].use_compression = use_compression;
231 LOGINFO("Start encryption thread %i\n", i);
232 ret = pthread_create(&enc_thread[i], &tattr, createList, (void*)&enc[i]);
233 if (ret) {
234 LOGINFO("Unable to create %i thread for encryption! %i\nContinuing in same thread (backup will be slower).", i, ret);
235 if (createList((void*)&enc[i]) != 0) {
236 LOGERR("Error creating encrypted backup %i.\n", i);
237 _exit(-1);
238 } else {
239 enc[i].thread_id = i + 1;
240 }
241 }
242 usleep(100000); // Need a short delay before starting the next thread or the threads will never finish for some reason.
243 }
244 if (pthread_attr_destroy(&tattr)) {
245 LOGERR("Failed to pthread_attr_destroy\n");
246 }
247 for (i = start_thread_id; i <= core_count; i++) {
248 if (enc[i].thread_id == i) {
249 if (pthread_join(enc_thread[i], &thread_return)) {
250 LOGERR("Error joining thread %i\n", i);
251 _exit(-1);
252 } else {
253 LOGINFO("Joined thread %i.\n", i);
254 ret = (int)thread_return;
255 if (ret != 0) {
256 thread_error = 1;
257 LOGERR("Thread %i returned an error %i.\n", i, ret);
258 _exit(-1);
259 }
260 }
261 } else {
262 LOGINFO("Skipping joining thread %i because of pthread failure.\n", i);
263 }
264 }
265 if (thread_error) {
266 LOGERR("Error returned by one or more threads.\n");
267 _exit(-1);
268 }
269 LOGINFO("Finished encrypted backup.\n");
270 _exit(0);
271 } else {
272 if (create() != 0)
273 _exit(-1);
274 else
275 _exit(0);
276 }
277 } else {
278 if (TWFunc::Wait_For_Child(pid, &status, "createTarFork()") != 0)
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500279 return -1;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500280 }
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500281 return 0;
282}
283
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500284int twrpTar::extractTarFork() {
Dees_Troy83bd4832013-05-04 12:39:56 +0000285 int status = 0;
286 pid_t pid, rc_pid;
287
288 pid = fork();
289 if (pid >= 0) // fork was successful
290 {
291 if (pid == 0) // child process
292 {
293 if (TWFunc::Path_Exists(tarfn)) {
294 LOGINFO("Single archive\n");
295 if (extract() != 0)
296 _exit(-1);
297 else
298 _exit(0);
299 } else {
300 LOGINFO("Multiple archives\n");
301 string temp;
302 char actual_filename[255];
303 twrpTar tars[9];
304 pthread_t tar_thread[9];
305 pthread_attr_t tattr;
306 int thread_count = 0, i, start_thread_id = 1, ret, thread_error = 0;
307 void *thread_return;
308
309 basefn = tarfn;
310 temp = basefn + "%i%02i";
311 tarfn += "000";
312 if (!TWFunc::Path_Exists(tarfn)) {
313 LOGERR("Unable to locate '%s' or '%s'\n", basefn.c_str(), tarfn.c_str());
314 _exit(-1);
315 }
316 if (TWFunc::Get_File_Type(tarfn) != 2) {
317 LOGINFO("First tar file '%s' not encrypted\n", tarfn.c_str());
318 tars[0].basefn = basefn;
319 tars[0].thread_id = 0;
320 if (extractMulti((void*)&tars[0]) != 0) {
321 LOGERR("Error extracting split archive.\n");
322 _exit(-1);
323 }
324 } else {
325 start_thread_id = 0;
326 }
327 // Start threading encrypted restores
328 if (pthread_attr_init(&tattr)) {
329 LOGERR("Unable to pthread_attr_init\n");
330 _exit(-1);
331 }
332 if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
333 LOGERR("Error setting pthread_attr_setdetachstate\n");
334 _exit(-1);
335 }
336 if (pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM)) {
337 LOGERR("Error setting pthread_attr_setscope\n");
338 _exit(-1);
339 }
340 /*if (pthread_attr_setstacksize(&tattr, 524288)) {
341 LOGERR("Error setting pthread_attr_setstacksize\n");
342 _exit(-1);
343 }*/
344 for (i = start_thread_id; i < 9; i++) {
345 sprintf(actual_filename, temp.c_str(), i, 0);
346 if (TWFunc::Path_Exists(actual_filename)) {
347 thread_count++;
348 tars[i].basefn = basefn;
349 tars[i].thread_id = i;
350 LOGINFO("Creating extract thread ID %i\n", i);
351 ret = pthread_create(&tar_thread[i], &tattr, extractMulti, (void*)&tars[i]);
352 if (ret) {
353 LOGINFO("Unable to create %i thread for extraction! %i\nContinuing in same thread (restore will be slower).", i, ret);
354 if (extractMulti((void*)&tars[i]) != 0) {
355 LOGERR("Error extracting backup in thread %i.\n", i);
356 _exit(-1);
357 } else {
358 tars[i].thread_id = i + 1;
359 }
360 }
361 usleep(100000); // Need a short delay before starting the next thread or the threads will never finish for some reason.
362 } else {
363 break;
364 }
365 }
366 for (i = start_thread_id; i < thread_count + start_thread_id; i++) {
367 if (tars[i].thread_id == i) {
368 if (pthread_join(tar_thread[i], &thread_return)) {
369 LOGERR("Error joining thread %i\n", i);
370 _exit(-1);
371 } else {
372 LOGINFO("Joined thread %i.\n", i);
373 ret = (int)thread_return;
374 if (ret != 0) {
375 thread_error = 1;
376 LOGERR("Thread %i returned an error %i.\n", i, ret);
377 _exit(-1);
378 }
379 }
380 } else {
381 LOGINFO("Skipping joining thread %i because of pthread failure.\n", i);
382 }
383 }
384 if (thread_error) {
385 LOGERR("Error returned by one or more threads.\n");
386 _exit(-1);
387 }
388 LOGINFO("Finished encrypted backup.\n");
389 _exit(0);
390 }
391 }
392 else // parent process
393 {
394 if (TWFunc::Wait_For_Child(pid, &status, "extractTarFork()") != 0)
395 return -1;
396 }
397 }
398 else // fork has failed
399 {
Dees_Troy2673cec2013-04-02 20:22:16 +0000400 LOGINFO("extract tar failed to fork.\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500401 return -1;
402 }
403 return 0;
404}
405
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500406int twrpTar::splitArchiveFork() {
Dees_Troy83bd4832013-05-04 12:39:56 +0000407 int status = 0;
408 pid_t pid, rc_pid;
409
410 pid = fork();
411 if (pid >= 0) // fork was successful
412 {
413 if (pid == 0) // child process
414 {
415 if (Split_Archive() <= 0)
416 _exit(-1);
417 else
418 _exit(0);
419 }
420 else // parent process
421 {
422 if (TWFunc::Wait_For_Child(pid, &status, "splitArchiveFork()") != 0)
423 return -1;
424 }
425 }
426 else // fork has failed
427 {
428 LOGINFO("split archive failed to fork.\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500429 return -1;
430 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000431 return 0;
432}
433
434int twrpTar::Generate_TarList(string Path, std::vector<TarListStruct> *TarList, unsigned long long *Target_Size, unsigned *thread_id) {
435 DIR* d;
436 struct dirent* de;
437 struct stat st;
438 string FileName;
439 struct TarListStruct TarItem;
440 string::size_type i;
441 bool skip;
442
443 if (has_data_media == 1 && Path.size() >= 11 && strncmp(Path.c_str(), "/data/media", 11) == 0)
444 return 0; // Skip /data/media
445
446 d = opendir(Path.c_str());
447 if (d == NULL) {
448 LOGERR("error opening '%s' -- error: %s\n", Path.c_str(), strerror(errno));
449 closedir(d);
450 return -1;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500451 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000452 while ((de = readdir(d)) != NULL) {
453 // Skip excluded stuff
454 if (split.size() > 0) {
455 skip = false;
456 for (i = 0; i < split.size(); i++) {
457 if (strcmp(de->d_name, split[i].c_str()) == 0) {
458 LOGINFO("excluding %s\n", de->d_name);
459 skip = true;
460 break;
461 }
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500462 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000463 if (skip)
464 continue;
465 }
466 FileName = Path + "/";
467 FileName += de->d_name;
468 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
469 continue; // Skip /data/media
470 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
471 continue;
472 TarItem.fn = FileName;
473 TarItem.thread_id = *thread_id;
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400474 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0 && strcmp(de->d_name, "lost+found") != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000475 TarList->push_back(TarItem);
476 if (Generate_TarList(FileName, TarList, Target_Size, thread_id) < 0)
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500477 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000478 } else if (de->d_type == DT_REG || de->d_type == DT_LNK) {
479 stat(FileName.c_str(), &st);
480 TarList->push_back(TarItem);
481 if (de->d_type == DT_REG)
482 Archive_Current_Size += st.st_size;
483 if (Archive_Current_Size != 0 && *Target_Size != 0 && Archive_Current_Size > *Target_Size) {
484 *thread_id = *thread_id + 1;
485 Archive_Current_Size = 0;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500486 }
487 }
488 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000489 closedir(d);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500490 return 0;
491}
492
493int twrpTar::Generate_Multiple_Archives(string Path) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500494 DIR* d;
495 struct dirent* de;
496 struct stat st;
497 string FileName;
498 char actual_filename[255];
499
Dees_Troy83bd4832013-05-04 12:39:56 +0000500 string::size_type i;
501 bool skip;
502
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500503 if (has_data_media == 1 && Path.size() >= 11 && strncmp(Path.c_str(), "/data/media", 11) == 0)
504 return 0; // Skip /data/media
Dees_Troy2673cec2013-04-02 20:22:16 +0000505 LOGINFO("Path: '%s', archive filename: '%s'\n", Path.c_str(), tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500506
507 d = opendir(Path.c_str());
508 if (d == NULL)
509 {
Dees_Troy2673cec2013-04-02 20:22:16 +0000510 LOGERR("error opening '%s' -- error: %s\n", Path.c_str(), strerror(errno));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500511 closedir(d);
512 return -1;
513 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000514 while ((de = readdir(d)) != NULL) {
515 // Skip excluded stuff
516 if (split.size() > 0) {
517 skip = false;
518 for (i = 0; i < split.size(); i++) {
519 if (strcmp(de->d_name, split[i].c_str()) == 0) {
520 LOGINFO("excluding %s\n", de->d_name);
521 skip = true;
522 break;
523 }
524 }
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400525 if (skip) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000526 continue;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400527 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000528 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500529 FileName = Path + "/";
530 FileName += de->d_name;
531 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
532 continue; // Skip /data/media
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500533 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
534 continue;
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400535 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0 && strcmp(de->d_name, "lost+foud") != 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500536 {
537 unsigned long long folder_size = TWFunc::Get_Folder_Size(FileName, false);
538 if (Archive_Current_Size + folder_size > MAX_ARCHIVE_SIZE) {
Dees Troyed400772013-10-09 14:45:24 +0000539 // Add the root folder first
540 LOGINFO("Adding root folder '%s' before splitting.\n", FileName.c_str());
541 if (addFile(FileName, true) != 0) {
542 LOGERR("Error adding folder '%s' to split archive.\n", FileName.c_str());
543 return -1;
544 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000545 LOGINFO("Calling Generate_Multiple_Archives\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500546 if (Generate_Multiple_Archives(FileName) < 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500547 return -1;
548 } else {
549 //FileName += "/";
Dees_Troy2673cec2013-04-02 20:22:16 +0000550 LOGINFO("Adding folder '%s'\n", FileName.c_str());
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500551 tardir = FileName;
552 if (tarDirs(true) < 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500553 return -1;
554 Archive_Current_Size += folder_size;
555 }
556 }
557 else if (de->d_type == DT_REG || de->d_type == DT_LNK)
558 {
559 stat(FileName.c_str(), &st);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400560 if (de->d_type != DT_LNK) {
561 if (Archive_Current_Size != 0 && Archive_Current_Size + st.st_size > MAX_ARCHIVE_SIZE) {
562 LOGINFO("Closing tar '%s', ", tarfn.c_str());
563 closeTar();
564 if (TWFunc::Get_File_Size(tarfn) == 0) {
565 LOGERR("Backup file size for '%s' is 0 bytes.\n", tarfn.c_str());
566 return -1;
567 }
568 Archive_File_Count++;
569 if (Archive_File_Count > 999) {
570 LOGERR("Archive count is too large!\n");
571 return -1;
572 }
573 string temp = basefn + "%03i";
574 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
575 tarfn = actual_filename;
576 Archive_Current_Size = 0;
577 LOGINFO("Creating tar '%s'\n", tarfn.c_str());
578 gui_print("Creating archive %i...\n", Archive_File_Count + 1);
579 if (createTar() != 0)
580 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500581 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500582 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000583 LOGINFO("Adding file: '%s'... ", FileName.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500584 if (addFile(FileName, true) < 0)
585 return -1;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400586 if (de->d_type != DT_LNK) {
587 Archive_Current_Size += st.st_size;
588 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000589 LOGINFO("added successfully, archive size: %llu\n", Archive_Current_Size);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400590 if (de->d_type != DT_LNK) {
591 if (st.st_size > 2147483648LL)
592 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());
593 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500594 }
595 }
596 closedir(d);
597 return 0;
598}
599
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500600int twrpTar::Split_Archive()
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500601{
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500602 string temp = tarfn + "%03i";
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500603 char actual_filename[255];
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400604 string tarsplit;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500605
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500606 basefn = tarfn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500607 Archive_File_Count = 0;
608 Archive_Current_Size = 0;
609 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500610 tarfn = actual_filename;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400611
612 for (int i = 0; i < tarexclude.size(); ++i) {
613 tarsplit = tarexclude[i];
614 tarsplit += " ";
615 }
616
Dees_Troy83bd4832013-05-04 12:39:56 +0000617 if (!tarexclude.empty())
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400618 split = TWFunc::split_string(tarsplit, ' ', true);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500619 createTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500620 DataManager::GetValue(TW_HAS_DATA_MEDIA, has_data_media);
Dees_Troy2673cec2013-04-02 20:22:16 +0000621 gui_print("Creating archive 1...\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500622 if (Generate_Multiple_Archives(tardir) < 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000623 LOGERR("Error generating multiple archives\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500624 return -1;
625 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000626 closeTar();
627 LOGINFO("Done, created %i archives.\n", (++Archive_File_Count));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500628 return (Archive_File_Count);
629}
630
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500631int twrpTar::extractTar() {
Dees_Troye34c1332013-02-06 19:13:00 +0000632 char* charRootDir = (char*) tardir.c_str();
Dees_Troy83bd4832013-05-04 12:39:56 +0000633 if (openTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500634 return -1;
635 if (tar_extract_all(t, charRootDir) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000636 LOGERR("Unable to extract tar archive '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500637 return -1;
638 }
639 if (tar_close(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000640 LOGERR("Unable to close tar file\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500641 return -1;
642 }
643 return 0;
644}
645
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500646int twrpTar::extract() {
Dees_Troy83bd4832013-05-04 12:39:56 +0000647 Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
n0d33b511632013-03-06 21:14:15 +0200648
649 if (Archive_Current_Type == 1) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500650 //if you return the extractTGZ function directly, stack crashes happen
Dees_Troy2673cec2013-04-02 20:22:16 +0000651 LOGINFO("Extracting gzipped tar\n");
Dees_Troy83bd4832013-05-04 12:39:56 +0000652 int ret = extractTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500653 return ret;
Dees_Troy83bd4832013-05-04 12:39:56 +0000654 } else if (Archive_Current_Type == 2) {
655 string Password;
656 DataManager::GetValue("tw_restore_password", Password);
657 int ret = TWFunc::Try_Decrypting_File(tarfn, Password);
658 if (ret < 1) {
659 LOGERR("Failed to decrypt tar file '%s'\n", tarfn.c_str());
660 return -1;
661 }
662 if (ret == 1) {
663 LOGERR("Decrypted file is not in tar format.\n");
664 return -1;
665 }
666 if (ret == 3) {
667 LOGINFO("Extracting encrypted and compressed tar.\n");
668 Archive_Current_Type = 3;
669 } else
670 LOGINFO("Extracting encrypted tar.\n");
671 return extractTar();
672 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000673 LOGINFO("Extracting uncompressed tar\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500674 return extractTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500675 }
676}
677
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500678int twrpTar::tarDirs(bool include_root) {
Dees_Troye34c1332013-02-06 19:13:00 +0000679 DIR* d;
680 string mainfolder = tardir + "/", subfolder;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400681 string tarsplit;
Dees_Troy59df9262013-06-19 14:53:57 -0500682 char buf[PATH_MAX], charTarPath[PATH_MAX];
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400683 string excl;
Dees_Troy83bd4832013-05-04 12:39:56 +0000684 string::size_type i;
685 bool skip;
686
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400687 //set exclude directories for libtar
688 for (int i = 0; i < tarexclude.size(); ++i) {
689 excl += tarexclude.at(i);
690 tarsplit = tarexclude.at(i);
691 excl += " ";
692 tarsplit += " ";
693 }
Dees_Troye34c1332013-02-06 19:13:00 +0000694 d = opendir(tardir.c_str());
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400695 if (d != NULL) {
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400696 if (!tarsplit.empty()) {
697 split = TWFunc::split_string(tarsplit, ' ', true);
Dees_Troy83bd4832013-05-04 12:39:56 +0000698 }
Dees_Troye34c1332013-02-06 19:13:00 +0000699 struct dirent* de;
700 while ((de = readdir(d)) != NULL) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500701#ifdef RECOVERY_SDCARD_ON_DATA
Dees_Troye34c1332013-02-06 19:13:00 +0000702 if ((tardir == "/data" || tardir == "/data/") && strcmp(de->d_name, "media") == 0) continue;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500703#endif
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400704 if (de->d_type == DT_BLK || de->d_type == DT_CHR || strcmp(de->d_name, "..") == 0 || strcmp(de->d_name, "lost+found") == 0)
Dees_Troy3263e922013-03-15 11:42:57 -0500705 continue;
Dees_Troy83bd4832013-05-04 12:39:56 +0000706
707 // Skip excluded stuff
708 if (split.size() > 0) {
709 skip = false;
710 for (i = 0; i < split.size(); i++) {
711 if (strcmp(de->d_name, split[i].c_str()) == 0) {
712 LOGINFO("excluding %s\n", de->d_name);
713 skip = true;
714 break;
715 }
716 }
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400717 if (skip) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000718 continue;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400719 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000720 }
721
Dees_Troye34c1332013-02-06 19:13:00 +0000722 subfolder = mainfolder;
Dees_Troy3263e922013-03-15 11:42:57 -0500723 if (strcmp(de->d_name, ".") != 0) {
724 subfolder += de->d_name;
725 } else {
Dees Troyed400772013-10-09 14:45:24 +0000726 LOGINFO("tarDirs addFile '%s' including root: %i\n", subfolder.c_str(), include_root);
Dees_Troy3263e922013-03-15 11:42:57 -0500727 if (addFile(subfolder, include_root) != 0)
728 return -1;
729 continue;
730 }
Dees_Troye34c1332013-02-06 19:13:00 +0000731 strcpy(buf, subfolder.c_str());
732 if (de->d_type == DT_DIR) {
Dees_Troy3263e922013-03-15 11:42:57 -0500733 if (include_root) {
Dees_Troy59df9262013-06-19 14:53:57 -0500734 charTarPath[0] = NULL;
735 LOGINFO("tar_append_tree '%s' as NULL\n", buf, charTarPath);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400736 if (tar_append_tree(t, buf, NULL, &excl[0]) != 0) {
Dees_Troy59df9262013-06-19 14:53:57 -0500737 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
738 return -1;
739 }
Dees_Troy3263e922013-03-15 11:42:57 -0500740 } else {
741 string temp = Strip_Root_Dir(buf);
Dees_Troy59df9262013-06-19 14:53:57 -0500742 strcpy(charTarPath, temp.c_str());
743 LOGINFO("tar_append_tree '%s' as '%s'\n", buf, charTarPath);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400744 if (tar_append_tree(t, buf, charTarPath, &excl[0]) != 0) {
Dees_Troy59df9262013-06-19 14:53:57 -0500745 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
746 return -1;
747 }
Dees_Troye34c1332013-02-06 19:13:00 +0000748 }
Dees_Troye34c1332013-02-06 19:13:00 +0000749 } else if (tardir != "/" && (de->d_type == DT_REG || de->d_type == DT_LNK)) {
Dees_Troy59df9262013-06-19 14:53:57 -0500750 LOGINFO("addFile '%s' including root: %i\n", buf, include_root);
Dees_Troy3263e922013-03-15 11:42:57 -0500751 if (addFile(buf, include_root) != 0)
752 return -1;
753 }
Dees_Troye34c1332013-02-06 19:13:00 +0000754 fflush(NULL);
755 }
756 closedir(d);
757 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500758 return 0;
759}
760
Dees_Troy83bd4832013-05-04 12:39:56 +0000761int twrpTar::tarList(bool include_root, std::vector<TarListStruct> *TarList, unsigned thread_id) {
762 struct stat st;
763 char buf[PATH_MAX];
764 int list_size = TarList->size(), i = 0, archive_count = 0;
765 string temp;
766 char actual_filename[PATH_MAX];
Dees_Troye34c1332013-02-06 19:13:00 +0000767
Dees_Troy83bd4832013-05-04 12:39:56 +0000768 basefn = tarfn;
769 temp = basefn + "%i%02i";
770 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
771 tarfn = actual_filename;
772 if (createTar() != 0) {
773 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
774 return -2;
775 }
776 Archive_Current_Size = 0;
777
778 while (i < list_size) {
779 if (TarList->at(i).thread_id == thread_id) {
780 strcpy(buf, TarList->at(i).fn.c_str());
781 stat(buf, &st);
782 if (st.st_mode & S_IFREG) { // item is a regular file
783 if (Archive_Current_Size + (unsigned long long)(st.st_size) > MAX_ARCHIVE_SIZE) {
784 if (closeTar() != 0) {
785 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
786 return -3;
787 }
788 archive_count++;
789 LOGINFO("Splitting thread ID %i into archive %i\n", thread_id, archive_count);
790 if (archive_count > 99) {
791 LOGINFO("BLAH!\n");
792 LOGERR("Too many archives for thread %i\n", thread_id);
793 return -4;
794 }
795 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
796 tarfn = actual_filename;
797 if (createTar() != 0) {
798 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
799 return -2;
800 }
801 Archive_Current_Size = 0;
802 }
803 Archive_Current_Size += (unsigned long long)(st.st_size);
804 }
805 if (addFile(buf, include_root) != 0) {
806 LOGERR("Error adding file '%s' to '%s'\n", buf, tarfn.c_str());
807 return -1;
808 }
809 }
810 i++;
811 }
812 if (closeTar() != 0) {
813 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
814 return -3;
815 }
816 LOGINFO("Thread id %i tarList done, %i archives.\n", thread_id, archive_count, i, list_size);
Dees_Troye34c1332013-02-06 19:13:00 +0000817 return 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500818}
819
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500820int twrpTar::create() {
Dees_Troye34c1332013-02-06 19:13:00 +0000821
822 init_libtar_buffer(0);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500823 if (createTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500824 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500825 if (tarDirs(false) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500826 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000827 if (closeTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500828 return -1;
Dees_Troye34c1332013-02-06 19:13:00 +0000829 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500830 return 0;
831}
832
Dees_Troy83bd4832013-05-04 12:39:56 +0000833void* twrpTar::createList(void *cookie) {
834
835 twrpTar* threadTar = (twrpTar*) cookie;
836 if (threadTar->tarList(true, threadTar->ItemList, threadTar->thread_id) == -1) {
837 LOGINFO("ERROR tarList for thread ID %i\n", threadTar->thread_id);
838 return (void*)-2;
839 }
840 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
841 return (void*)0;
842}
843
844void* twrpTar::extractMulti(void *cookie) {
845
846 twrpTar* threadTar = (twrpTar*) cookie;
847 int archive_count = 0;
848 string temp = threadTar->basefn + "%i%02i";
849 char actual_filename[255];
850 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
851 while (TWFunc::Path_Exists(actual_filename)) {
852 threadTar->tarfn = actual_filename;
853 if (threadTar->extract() != 0) {
854 LOGINFO("Error extracting '%s' in thread ID %i\n", actual_filename, threadTar->thread_id);
855 return (void*)-2;
856 }
857 archive_count++;
858 if (archive_count > 99)
859 break;
860 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
861 }
862 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
863 return (void*)0;
864}
865
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500866int twrpTar::addFilesToExistingTar(vector <string> files, string fn) {
867 char* charTarFile = (char*) fn.c_str();
868
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200869 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 -0500870 return -1;
871 removeEOT(charTarFile);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200872 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 -0500873 return -1;
874 for (unsigned int i = 0; i < files.size(); ++i) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500875 char* file = (char*) files.at(i).c_str();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500876 if (tar_append_file(t, file, file) == -1)
877 return -1;
878 }
879 if (tar_append_eof(t) == -1)
880 return -1;
881 if (tar_close(t) == -1)
882 return -1;
883 return 0;
884}
885
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500886int twrpTar::createTar() {
887 char* charTarFile = (char*) tarfn.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000888 char* charRootDir = (char*) tardir.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000889 static tartype_t type = { open, close, read, write_tar };
Dees_Troy83bd4832013-05-04 12:39:56 +0000890 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500891
Dees_Troy83bd4832013-05-04 12:39:56 +0000892 if (use_encryption && use_compression) {
893 // Compressed and encrypted
894 Archive_Current_Type = 3;
895 LOGINFO("Using encryption and compression...\n");
896 DataManager::GetValue("tw_backup_password", Password);
897 int i, pipes[4];
898
899 if (pipe(pipes) < 0) {
900 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500901 return -1;
902 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000903 if (pipe(pipes + 2) < 0) {
904 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500905 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000906 }
907 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400908
Dees_Troy83bd4832013-05-04 12:39:56 +0000909 if (pigz_pid < 0) {
910 LOGERR("pigz fork() failed\n");
911 for (i = 0; i < 4; i++)
912 close(pipes[i]); // close all
913 return -1;
914 } else if (pigz_pid == 0) {
915 // pigz Child
916 close(pipes[1]);
917 close(pipes[2]);
918 close(0);
919 dup2(pipes[0], 0);
920 close(1);
921 dup2(pipes[3], 1);
922 if (execlp("pigz", "pigz", "-", NULL) < 0) {
923 LOGERR("execlp pigz ERROR!\n");
924 close(pipes[0]);
925 close(pipes[3]);
926 _exit(-1);
927 }
928 } else {
929 // Parent
930 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400931
Dees_Troy83bd4832013-05-04 12:39:56 +0000932 if (oaes_pid < 0) {
933 LOGERR("openaes fork() failed\n");
934 for (i = 0; i < 4; i++)
935 close(pipes[i]); // close all
936 return -1;
937 } else if (oaes_pid == 0) {
938 // openaes Child
Dees_Troy5612cc82013-07-24 19:45:58 +0000939 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 +0000940 if (output_fd < 0) {
941 LOGERR("Failed to open '%s'\n", tarfn.c_str());
942 for (i = 0; i < 4; i++)
943 close(pipes[i]); // close all
944 return -1;
945 }
946 close(pipes[0]);
947 close(pipes[1]);
948 close(pipes[3]);
949 close(0);
950 dup2(pipes[2], 0);
951 close(1);
952 dup2(output_fd, 1);
953 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
954 LOGERR("execlp openaes ERROR!\n");
955 close(pipes[2]);
956 close(output_fd);
957 _exit(-1);
958 }
959 } else {
960 // Parent
961 close(pipes[0]);
962 close(pipes[2]);
963 close(pipes[3]);
964 fd = pipes[1];
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200965 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 +0000966 close(fd);
967 LOGERR("tar_fdopen failed\n");
968 return -1;
969 }
970 return 0;
971 }
972 }
973 } else if (use_compression) {
974 // Compressed
975 Archive_Current_Type = 1;
976 LOGINFO("Using compression...\n");
977 int pigzfd[2];
978
979 if (pipe(pigzfd) < 0) {
980 LOGERR("Error creating pipe\n");
981 return -1;
982 }
983 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400984
Dees_Troy83bd4832013-05-04 12:39:56 +0000985 if (pigz_pid < 0) {
986 LOGERR("fork() failed\n");
987 close(pigzfd[0]);
988 close(pigzfd[1]);
989 return -1;
990 } else if (pigz_pid == 0) {
991 // Child
992 close(pigzfd[1]); // close unused output pipe
Dees_Troy5612cc82013-07-24 19:45:58 +0000993 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 +0000994 if (output_fd < 0) {
995 LOGERR("Failed to open '%s'\n", tarfn.c_str());
996 close(pigzfd[0]);
997 _exit(-1);
998 }
999 dup2(pigzfd[0], 0); // remap stdin
1000 dup2(output_fd, 1); // remap stdout to output file
1001 if (execlp("pigz", "pigz", "-", NULL) < 0) {
1002 LOGERR("execlp pigz ERROR!\n");
1003 close(output_fd);
1004 close(pigzfd[0]);
1005 _exit(-1);
1006 }
1007 } else {
1008 // Parent
1009 close(pigzfd[0]); // close parent input
1010 fd = pigzfd[1]; // copy parent output
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001011 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 +00001012 close(fd);
1013 LOGERR("tar_fdopen failed\n");
1014 return -1;
1015 }
1016 }
1017 } else if (use_encryption) {
1018 // Encrypted
1019 Archive_Current_Type = 2;
1020 LOGINFO("Using encryption...\n");
1021 DataManager::GetValue("tw_backup_password", Password);
1022 int oaesfd[2];
1023 pipe(oaesfd);
1024 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001025
Dees_Troy83bd4832013-05-04 12:39:56 +00001026 if (oaes_pid < 0) {
1027 LOGERR("fork() failed\n");
1028 close(oaesfd[0]);
1029 close(oaesfd[1]);
1030 return -1;
1031 } else if (oaes_pid == 0) {
1032 // Child
1033 close(oaesfd[1]); // close unused
Dees_Troy5612cc82013-07-24 19:45:58 +00001034 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 +00001035 if (output_fd < 0) {
1036 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1037 _exit(-1);
1038 }
1039 dup2(oaesfd[0], 0); // remap stdin
1040 dup2(output_fd, 1); // remap stdout to output file
1041 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
1042 LOGERR("execlp openaes ERROR!\n");
1043 close(output_fd);
1044 close(oaesfd[0]);
1045 _exit(-1);
1046 }
1047 } else {
1048 // Parent
1049 close(oaesfd[0]); // close parent input
1050 fd = oaesfd[1]; // copy parent output
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001051 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 +00001052 close(fd);
1053 LOGERR("tar_fdopen failed\n");
1054 return -1;
1055 }
1056 return 0;
1057 }
1058 } else {
1059 // Not compressed or encrypted
1060 init_libtar_buffer(0);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001061 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 +00001062 LOGERR("tar_open error opening '%s'\n", tarfn.c_str());
1063 return -1;
1064 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001065 }
1066 return 0;
1067}
1068
Dees_Troy83bd4832013-05-04 12:39:56 +00001069int twrpTar::openTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001070 char* charRootDir = (char*) tardir.c_str();
1071 char* charTarFile = (char*) tarfn.c_str();
Dees_Troy83bd4832013-05-04 12:39:56 +00001072 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001073
Dees_Troy83bd4832013-05-04 12:39:56 +00001074 if (Archive_Current_Type == 3) {
1075 LOGINFO("Opening encrypted and compressed backup...\n");
1076 DataManager::GetValue("tw_restore_password", Password);
1077 int i, pipes[4];
1078
1079 if (pipe(pipes) < 0) {
1080 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001081 return -1;
1082 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001083 if (pipe(pipes + 2) < 0) {
1084 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001085 return -1;
1086 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001087 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001088
Dees_Troy83bd4832013-05-04 12:39:56 +00001089 if (oaes_pid < 0) {
1090 LOGERR("pigz fork() failed\n");
1091 for (i = 0; i < 4; i++)
1092 close(pipes[i]); // close all
1093 return -1;
1094 } else if (oaes_pid == 0) {
1095 // openaes Child
1096 close(pipes[0]); // Close pipes that are not used by this child
1097 close(pipes[2]);
1098 close(pipes[3]);
1099 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1100 if (input_fd < 0) {
1101 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1102 close(pipes[1]);
1103 _exit(-1);
1104 }
1105 close(0);
1106 dup2(input_fd, 0);
1107 close(1);
1108 dup2(pipes[1], 1);
1109 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1110 LOGERR("execlp openaes ERROR!\n");
1111 close(input_fd);
1112 close(pipes[1]);
1113 _exit(-1);
1114 }
1115 } else {
1116 // Parent
1117 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001118
Dees_Troy83bd4832013-05-04 12:39:56 +00001119 if (pigz_pid < 0) {
1120 LOGERR("openaes fork() failed\n");
1121 for (i = 0; i < 4; i++)
1122 close(pipes[i]); // close all
1123 return -1;
1124 } else if (pigz_pid == 0) {
1125 // pigz Child
1126 close(pipes[1]); // Close pipes not used by this child
1127 close(pipes[2]);
1128 close(0);
1129 dup2(pipes[0], 0);
1130 close(1);
1131 dup2(pipes[3], 1);
1132 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1133 LOGERR("execlp pigz ERROR!\n");
1134 close(pipes[0]);
1135 close(pipes[3]);
1136 _exit(-1);
1137 }
1138 } else {
1139 // Parent
1140 close(pipes[0]); // Close pipes not used by parent
1141 close(pipes[1]);
1142 close(pipes[3]);
1143 fd = pipes[2];
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001144 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 +00001145 close(fd);
1146 LOGERR("tar_fdopen failed\n");
1147 return -1;
1148 }
1149 }
1150 }
1151 } else if (Archive_Current_Type == 2) {
1152 LOGINFO("Opening encrypted backup...\n");
1153 DataManager::GetValue("tw_restore_password", Password);
1154 int oaesfd[2];
1155
1156 pipe(oaesfd);
1157 oaes_pid = fork();
1158 if (oaes_pid < 0) {
1159 LOGERR("fork() failed\n");
1160 close(oaesfd[0]);
1161 close(oaesfd[1]);
1162 return -1;
1163 } else if (oaes_pid == 0) {
1164 // Child
1165 close(oaesfd[0]); // Close unused pipe
1166 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1167 if (input_fd < 0) {
1168 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1169 close(oaesfd[1]);
1170 _exit(-1);
1171 }
1172 close(0); // close stdin
1173 dup2(oaesfd[1], 1); // remap stdout
1174 dup2(input_fd, 0); // remap input fd to stdin
1175 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1176 LOGERR("execlp openaes ERROR!\n");
1177 close(input_fd);
1178 close(oaesfd[1]);
1179 _exit(-1);
1180 }
1181 } else {
1182 // Parent
1183 close(oaesfd[1]); // close parent output
1184 fd = oaesfd[0]; // copy parent input
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001185 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 +00001186 close(fd);
1187 LOGERR("tar_fdopen failed\n");
1188 return -1;
1189 }
1190 }
1191 } else if (Archive_Current_Type == 1) {
1192 LOGINFO("Opening as a gzip...\n");
1193 int pigzfd[2];
1194 pipe(pigzfd);
1195
1196 pigz_pid = fork();
1197 if (pigz_pid < 0) {
1198 LOGERR("fork() failed\n");
1199 close(pigzfd[0]);
1200 close(pigzfd[1]);
1201 return -1;
1202 } else if (pigz_pid == 0) {
1203 // Child
1204 close(pigzfd[0]);
1205 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1206 if (input_fd < 0) {
1207 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1208 _exit(-1);
1209 }
1210 dup2(input_fd, 0); // remap input fd to stdin
1211 dup2(pigzfd[1], 1); // remap stdout
1212 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1213 close(pigzfd[1]);
1214 close(input_fd);
1215 LOGERR("execlp openaes ERROR!\n");
1216 _exit(-1);
1217 }
1218 } else {
1219 // Parent
1220 close(pigzfd[1]); // close parent output
1221 fd = pigzfd[0]; // copy parent input
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001222 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 +00001223 close(fd);
1224 LOGERR("tar_fdopen failed\n");
1225 return -1;
1226 }
1227 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001228 } 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 +00001229 LOGERR("Unable to open tar archive '%s'\n", charTarFile);
1230 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001231 }
1232 return 0;
1233}
1234
1235string twrpTar::Strip_Root_Dir(string Path) {
1236 string temp;
1237 size_t slash;
1238
1239 if (Path.substr(0, 1) == "/")
1240 temp = Path.substr(1, Path.size() - 1);
1241 else
1242 temp = Path;
1243 slash = temp.find("/");
1244 if (slash == string::npos)
1245 return temp;
1246 else {
1247 string stripped;
1248
1249 stripped = temp.substr(slash, temp.size() - slash);
1250 return stripped;
1251 }
1252 return temp;
1253}
1254
1255int twrpTar::addFile(string fn, bool include_root) {
1256 char* charTarFile = (char*) fn.c_str();
1257 if (include_root) {
1258 if (tar_append_file(t, charTarFile, NULL) == -1)
1259 return -1;
1260 } else {
1261 string temp = Strip_Root_Dir(fn);
1262 char* charTarPath = (char*) temp.c_str();
1263 if (tar_append_file(t, charTarFile, charTarPath) == -1)
1264 return -1;
1265 }
1266 return 0;
1267}
1268
Dees_Troy83bd4832013-05-04 12:39:56 +00001269int twrpTar::closeTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001270 flush_libtar_buffer(t->fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001271 if (tar_append_eof(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001272 LOGERR("tar_append_eof(): %s\n", strerror(errno));
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001273 tar_close(t);
1274 return -1;
1275 }
1276 if (tar_close(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001277 LOGERR("Unable to close tar archive: '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001278 return -1;
1279 }
Dees_Troy2727b992013-08-14 20:09:30 +00001280 if (Archive_Current_Type > 0) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001281 close(fd);
Dees_Troy83bd4832013-05-04 12:39:56 +00001282 int status;
1283 if (pigz_pid > 0 && TWFunc::Wait_For_Child(pigz_pid, &status, "pigz") != 0)
1284 return -1;
1285 if (oaes_pid > 0 && TWFunc::Wait_For_Child(oaes_pid, &status, "openaes") != 0)
1286 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001287 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001288 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001289 return 0;
1290}
1291
1292int twrpTar::removeEOT(string tarFile) {
1293 char* charTarFile = (char*) tarFile.c_str();
1294 off_t tarFileEnd;
1295 while (th_read(t) == 0) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001296 if (TH_ISREG(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001297 tar_skip_regfile(t);
1298 tarFileEnd = lseek(t->fd, 0, SEEK_CUR);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001299 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001300 if (tar_close(t) == -1)
1301 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001302 if (truncate(charTarFile, tarFileEnd) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001303 return -1;
1304 return 0;
1305}
1306
n0d33b511632013-03-06 21:14:15 +02001307int twrpTar::entryExists(string entry) {
1308 char* searchstr = (char*)entry.c_str();
1309 int ret;
1310
Dees_Troy83bd4832013-05-04 12:39:56 +00001311 Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
n0d33b511632013-03-06 21:14:15 +02001312
Dees_Troy83bd4832013-05-04 12:39:56 +00001313 if (openTar() == -1)
n0d33b511632013-03-06 21:14:15 +02001314 ret = 0;
1315 else
1316 ret = tar_find(t, searchstr);
1317
Dees_Troy83bd4832013-05-04 12:39:56 +00001318 if (closeTar() != 0)
1319 LOGINFO("Unable to close tar after searching for entry.\n");
n0d33b511632013-03-06 21:14:15 +02001320
1321 return ret;
1322}
1323
Dees_Troy83bd4832013-05-04 12:39:56 +00001324unsigned long long twrpTar::uncompressedSize() {
1325 int type = 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001326 unsigned long long total_size = 0;
Dees_Troy83bd4832013-05-04 12:39:56 +00001327 string Tar, Command, result;
1328 vector<string> split;
1329
1330 Tar = TWFunc::Get_Filename(tarfn);
1331 type = TWFunc::Get_File_Type(tarfn);
1332 if (type == 0)
1333 total_size = TWFunc::Get_File_Size(tarfn);
1334 else {
1335 Command = "pigz -l " + tarfn;
1336 /* if we set Command = "pigz -l " + tarfn + " | sed '1d' | cut -f5 -d' '";
1337 we get the uncompressed size at once. */
1338 TWFunc::Exec_Cmd(Command, result);
1339 if (!result.empty()) {
1340 /* Expected output:
1341 compressed original reduced name
1342 95855838 179403776 -1.3% data.yaffs2.win
1343 ^
1344 split[5]
1345 */
1346 split = TWFunc::split_string(result, ' ', true);
1347 if (split.size() > 4)
1348 total_size = atoi(split[5].c_str());
1349 }
1350 }
1351 LOGINFO("%s's uncompressed size: %llu bytes\n", Tar.c_str(), total_size);
1352
1353 return total_size;
1354}
1355
Dees_Troye34c1332013-02-06 19:13:00 +00001356extern "C" ssize_t write_tar(int fd, const void *buffer, size_t size) {
1357 return (ssize_t) write_libtar_buffer(fd, buffer, size);
Dees_Troy40bbcf82013-02-12 15:01:53 +00001358}