blob: 5964f2f881d03a4d605ffce0fa3389eb0253b58c [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) {
69 tarexclude = 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;
117 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) {
118 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;
161 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) {
162 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;
474 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) {
475 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 }
525 if (skip)
526 continue;
527 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500528 FileName = Path + "/";
529 FileName += de->d_name;
530 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
531 continue; // Skip /data/media
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500532 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
533 continue;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500534 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
535 {
536 unsigned long long folder_size = TWFunc::Get_Folder_Size(FileName, false);
537 if (Archive_Current_Size + folder_size > MAX_ARCHIVE_SIZE) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000538 LOGINFO("Calling Generate_Multiple_Archives\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500539 if (Generate_Multiple_Archives(FileName) < 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500540 return -1;
541 } else {
542 //FileName += "/";
Dees_Troy2673cec2013-04-02 20:22:16 +0000543 LOGINFO("Adding folder '%s'\n", FileName.c_str());
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500544 tardir = FileName;
545 if (tarDirs(true) < 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500546 return -1;
547 Archive_Current_Size += folder_size;
548 }
549 }
550 else if (de->d_type == DT_REG || de->d_type == DT_LNK)
551 {
552 stat(FileName.c_str(), &st);
553
554 if (Archive_Current_Size != 0 && Archive_Current_Size + st.st_size > MAX_ARCHIVE_SIZE) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000555 LOGINFO("Closing tar '%s', ", tarfn.c_str());
Dees_Troy83bd4832013-05-04 12:39:56 +0000556 closeTar();
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500557 if (TWFunc::Get_File_Size(tarfn) == 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000558 LOGERR("Backup file size for '%s' is 0 bytes.\n", tarfn.c_str());
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500559 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500560 }
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500561 Archive_File_Count++;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500562 if (Archive_File_Count > 999) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000563 LOGERR("Archive count is too large!\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500564 return -1;
565 }
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500566 string temp = basefn + "%03i";
567 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
568 tarfn = actual_filename;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500569 Archive_Current_Size = 0;
Dees_Troy2673cec2013-04-02 20:22:16 +0000570 LOGINFO("Creating tar '%s'\n", tarfn.c_str());
571 gui_print("Creating archive %i...\n", Archive_File_Count + 1);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500572 if (createTar() != 0)
573 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500574 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000575 LOGINFO("Adding file: '%s'... ", FileName.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500576 if (addFile(FileName, true) < 0)
577 return -1;
578 Archive_Current_Size += st.st_size;
Dees_Troy2673cec2013-04-02 20:22:16 +0000579 LOGINFO("added successfully, archive size: %llu\n", Archive_Current_Size);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500580 if (st.st_size > 2147483648LL)
Dees_Troy2673cec2013-04-02 20:22:16 +0000581 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());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500582 }
583 }
584 closedir(d);
585 return 0;
586}
587
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500588int twrpTar::Split_Archive()
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500589{
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500590 string temp = tarfn + "%03i";
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500591 char actual_filename[255];
592
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500593 basefn = tarfn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500594 Archive_File_Count = 0;
595 Archive_Current_Size = 0;
596 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500597 tarfn = actual_filename;
Dees_Troy83bd4832013-05-04 12:39:56 +0000598 if (!tarexclude.empty())
599 split = TWFunc::split_string(tarexclude, ' ', true);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500600 createTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500601 DataManager::GetValue(TW_HAS_DATA_MEDIA, has_data_media);
Dees_Troy2673cec2013-04-02 20:22:16 +0000602 gui_print("Creating archive 1...\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500603 if (Generate_Multiple_Archives(tardir) < 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000604 LOGERR("Error generating multiple archives\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500605 return -1;
606 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000607 closeTar();
608 LOGINFO("Done, created %i archives.\n", (++Archive_File_Count));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500609 return (Archive_File_Count);
610}
611
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500612int twrpTar::extractTar() {
Dees_Troye34c1332013-02-06 19:13:00 +0000613 char* charRootDir = (char*) tardir.c_str();
Dees_Troy83bd4832013-05-04 12:39:56 +0000614 if (openTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500615 return -1;
616 if (tar_extract_all(t, charRootDir) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000617 LOGERR("Unable to extract tar archive '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500618 return -1;
619 }
620 if (tar_close(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000621 LOGERR("Unable to close tar file\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500622 return -1;
623 }
624 return 0;
625}
626
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500627int twrpTar::extract() {
Dees_Troy83bd4832013-05-04 12:39:56 +0000628 Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
n0d33b511632013-03-06 21:14:15 +0200629
630 if (Archive_Current_Type == 1) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500631 //if you return the extractTGZ function directly, stack crashes happen
Dees_Troy2673cec2013-04-02 20:22:16 +0000632 LOGINFO("Extracting gzipped tar\n");
Dees_Troy83bd4832013-05-04 12:39:56 +0000633 int ret = extractTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500634 return ret;
Dees_Troy83bd4832013-05-04 12:39:56 +0000635 } else if (Archive_Current_Type == 2) {
636 string Password;
637 DataManager::GetValue("tw_restore_password", Password);
638 int ret = TWFunc::Try_Decrypting_File(tarfn, Password);
639 if (ret < 1) {
640 LOGERR("Failed to decrypt tar file '%s'\n", tarfn.c_str());
641 return -1;
642 }
643 if (ret == 1) {
644 LOGERR("Decrypted file is not in tar format.\n");
645 return -1;
646 }
647 if (ret == 3) {
648 LOGINFO("Extracting encrypted and compressed tar.\n");
649 Archive_Current_Type = 3;
650 } else
651 LOGINFO("Extracting encrypted tar.\n");
652 return extractTar();
653 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000654 LOGINFO("Extracting uncompressed tar\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500655 return extractTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500656 }
657}
658
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500659int twrpTar::tarDirs(bool include_root) {
Dees_Troye34c1332013-02-06 19:13:00 +0000660 DIR* d;
661 string mainfolder = tardir + "/", subfolder;
Dees_Troy59df9262013-06-19 14:53:57 -0500662 char buf[PATH_MAX], charTarPath[PATH_MAX];
Dees_Troy83bd4832013-05-04 12:39:56 +0000663
664 char excl[1024];
665 string::size_type i;
666 bool skip;
667
Dees_Troye34c1332013-02-06 19:13:00 +0000668 d = opendir(tardir.c_str());
Dees_Troy83bd4832013-05-04 12:39:56 +0000669 if (d != NULL) {
670 if (!tarexclude.empty()) {
671 strcpy(excl, tarexclude.c_str());
672 split = TWFunc::split_string(tarexclude, ' ', true);
673 }
Dees_Troye34c1332013-02-06 19:13:00 +0000674 struct dirent* de;
675 while ((de = readdir(d)) != NULL) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500676#ifdef RECOVERY_SDCARD_ON_DATA
Dees_Troye34c1332013-02-06 19:13:00 +0000677 if ((tardir == "/data" || tardir == "/data/") && strcmp(de->d_name, "media") == 0) continue;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500678#endif
Dees_Troy3263e922013-03-15 11:42:57 -0500679 if (de->d_type == DT_BLK || de->d_type == DT_CHR || strcmp(de->d_name, "..") == 0)
680 continue;
Dees_Troy83bd4832013-05-04 12:39:56 +0000681
682 // Skip excluded stuff
683 if (split.size() > 0) {
684 skip = false;
685 for (i = 0; i < split.size(); i++) {
686 if (strcmp(de->d_name, split[i].c_str()) == 0) {
687 LOGINFO("excluding %s\n", de->d_name);
688 skip = true;
689 break;
690 }
691 }
692 if (skip)
693 continue;
694 }
695
Dees_Troye34c1332013-02-06 19:13:00 +0000696 subfolder = mainfolder;
Dees_Troy3263e922013-03-15 11:42:57 -0500697 if (strcmp(de->d_name, ".") != 0) {
698 subfolder += de->d_name;
699 } else {
Dees_Troy59df9262013-06-19 14:53:57 -0500700 LOGINFO("addFile '%s' including root: %i\n", buf, include_root);
Dees_Troy3263e922013-03-15 11:42:57 -0500701 if (addFile(subfolder, include_root) != 0)
702 return -1;
703 continue;
704 }
Dees_Troye34c1332013-02-06 19:13:00 +0000705 strcpy(buf, subfolder.c_str());
706 if (de->d_type == DT_DIR) {
Dees_Troy3263e922013-03-15 11:42:57 -0500707 if (include_root) {
Dees_Troy59df9262013-06-19 14:53:57 -0500708 charTarPath[0] = NULL;
709 LOGINFO("tar_append_tree '%s' as NULL\n", buf, charTarPath);
710 if (tar_append_tree(t, buf, NULL, excl) != 0) {
711 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
712 return -1;
713 }
Dees_Troy3263e922013-03-15 11:42:57 -0500714 } else {
715 string temp = Strip_Root_Dir(buf);
Dees_Troy59df9262013-06-19 14:53:57 -0500716 strcpy(charTarPath, temp.c_str());
717 LOGINFO("tar_append_tree '%s' as '%s'\n", buf, charTarPath);
718 if (tar_append_tree(t, buf, charTarPath, excl) != 0) {
719 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
720 return -1;
721 }
Dees_Troye34c1332013-02-06 19:13:00 +0000722 }
Dees_Troye34c1332013-02-06 19:13:00 +0000723 } else if (tardir != "/" && (de->d_type == DT_REG || de->d_type == DT_LNK)) {
Dees_Troy59df9262013-06-19 14:53:57 -0500724 LOGINFO("addFile '%s' including root: %i\n", buf, include_root);
Dees_Troy3263e922013-03-15 11:42:57 -0500725 if (addFile(buf, include_root) != 0)
726 return -1;
727 }
Dees_Troye34c1332013-02-06 19:13:00 +0000728 fflush(NULL);
729 }
730 closedir(d);
731 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500732 return 0;
733}
734
Dees_Troy83bd4832013-05-04 12:39:56 +0000735int twrpTar::tarList(bool include_root, std::vector<TarListStruct> *TarList, unsigned thread_id) {
736 struct stat st;
737 char buf[PATH_MAX];
738 int list_size = TarList->size(), i = 0, archive_count = 0;
739 string temp;
740 char actual_filename[PATH_MAX];
Dees_Troye34c1332013-02-06 19:13:00 +0000741
Dees_Troy83bd4832013-05-04 12:39:56 +0000742 basefn = tarfn;
743 temp = basefn + "%i%02i";
744 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
745 tarfn = actual_filename;
746 if (createTar() != 0) {
747 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
748 return -2;
749 }
750 Archive_Current_Size = 0;
751
752 while (i < list_size) {
753 if (TarList->at(i).thread_id == thread_id) {
754 strcpy(buf, TarList->at(i).fn.c_str());
755 stat(buf, &st);
756 if (st.st_mode & S_IFREG) { // item is a regular file
757 if (Archive_Current_Size + (unsigned long long)(st.st_size) > MAX_ARCHIVE_SIZE) {
758 if (closeTar() != 0) {
759 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
760 return -3;
761 }
762 archive_count++;
763 LOGINFO("Splitting thread ID %i into archive %i\n", thread_id, archive_count);
764 if (archive_count > 99) {
765 LOGINFO("BLAH!\n");
766 LOGERR("Too many archives for thread %i\n", thread_id);
767 return -4;
768 }
769 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
770 tarfn = actual_filename;
771 if (createTar() != 0) {
772 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
773 return -2;
774 }
775 Archive_Current_Size = 0;
776 }
777 Archive_Current_Size += (unsigned long long)(st.st_size);
778 }
779 if (addFile(buf, include_root) != 0) {
780 LOGERR("Error adding file '%s' to '%s'\n", buf, tarfn.c_str());
781 return -1;
782 }
783 }
784 i++;
785 }
786 if (closeTar() != 0) {
787 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
788 return -3;
789 }
790 LOGINFO("Thread id %i tarList done, %i archives.\n", thread_id, archive_count, i, list_size);
Dees_Troye34c1332013-02-06 19:13:00 +0000791 return 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500792}
793
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500794int twrpTar::create() {
Dees_Troye34c1332013-02-06 19:13:00 +0000795
796 init_libtar_buffer(0);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500797 if (createTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500798 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500799 if (tarDirs(false) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500800 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000801 if (closeTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500802 return -1;
Dees_Troye34c1332013-02-06 19:13:00 +0000803 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500804 return 0;
805}
806
Dees_Troy83bd4832013-05-04 12:39:56 +0000807void* twrpTar::createList(void *cookie) {
808
809 twrpTar* threadTar = (twrpTar*) cookie;
810 if (threadTar->tarList(true, threadTar->ItemList, threadTar->thread_id) == -1) {
811 LOGINFO("ERROR tarList for thread ID %i\n", threadTar->thread_id);
812 return (void*)-2;
813 }
814 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
815 return (void*)0;
816}
817
818void* twrpTar::extractMulti(void *cookie) {
819
820 twrpTar* threadTar = (twrpTar*) cookie;
821 int archive_count = 0;
822 string temp = threadTar->basefn + "%i%02i";
823 char actual_filename[255];
824 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
825 while (TWFunc::Path_Exists(actual_filename)) {
826 threadTar->tarfn = actual_filename;
827 if (threadTar->extract() != 0) {
828 LOGINFO("Error extracting '%s' in thread ID %i\n", actual_filename, threadTar->thread_id);
829 return (void*)-2;
830 }
831 archive_count++;
832 if (archive_count > 99)
833 break;
834 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
835 }
836 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
837 return (void*)0;
838}
839
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500840int twrpTar::addFilesToExistingTar(vector <string> files, string fn) {
841 char* charTarFile = (char*) fn.c_str();
842
Dees_Troy5612cc82013-07-24 19:45:58 +0000843 if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500844 return -1;
845 removeEOT(charTarFile);
Dees_Troy5612cc82013-07-24 19:45:58 +0000846 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) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500847 return -1;
848 for (unsigned int i = 0; i < files.size(); ++i) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500849 char* file = (char*) files.at(i).c_str();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500850 if (tar_append_file(t, file, file) == -1)
851 return -1;
852 }
853 if (tar_append_eof(t) == -1)
854 return -1;
855 if (tar_close(t) == -1)
856 return -1;
857 return 0;
858}
859
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500860int twrpTar::createTar() {
861 char* charTarFile = (char*) tarfn.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000862 char* charRootDir = (char*) tardir.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000863 static tartype_t type = { open, close, read, write_tar };
Dees_Troy83bd4832013-05-04 12:39:56 +0000864 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500865
Dees_Troy83bd4832013-05-04 12:39:56 +0000866 if (use_encryption && use_compression) {
867 // Compressed and encrypted
868 Archive_Current_Type = 3;
869 LOGINFO("Using encryption and compression...\n");
870 DataManager::GetValue("tw_backup_password", Password);
871 int i, pipes[4];
872
873 if (pipe(pipes) < 0) {
874 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500875 return -1;
876 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000877 if (pipe(pipes + 2) < 0) {
878 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500879 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000880 }
881 pigz_pid = fork();
882
883 if (pigz_pid < 0) {
884 LOGERR("pigz fork() failed\n");
885 for (i = 0; i < 4; i++)
886 close(pipes[i]); // close all
887 return -1;
888 } else if (pigz_pid == 0) {
889 // pigz Child
890 close(pipes[1]);
891 close(pipes[2]);
892 close(0);
893 dup2(pipes[0], 0);
894 close(1);
895 dup2(pipes[3], 1);
896 if (execlp("pigz", "pigz", "-", NULL) < 0) {
897 LOGERR("execlp pigz ERROR!\n");
898 close(pipes[0]);
899 close(pipes[3]);
900 _exit(-1);
901 }
902 } else {
903 // Parent
904 oaes_pid = fork();
905
906 if (oaes_pid < 0) {
907 LOGERR("openaes fork() failed\n");
908 for (i = 0; i < 4; i++)
909 close(pipes[i]); // close all
910 return -1;
911 } else if (oaes_pid == 0) {
912 // openaes Child
Dees_Troy5612cc82013-07-24 19:45:58 +0000913 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 +0000914 if (output_fd < 0) {
915 LOGERR("Failed to open '%s'\n", tarfn.c_str());
916 for (i = 0; i < 4; i++)
917 close(pipes[i]); // close all
918 return -1;
919 }
920 close(pipes[0]);
921 close(pipes[1]);
922 close(pipes[3]);
923 close(0);
924 dup2(pipes[2], 0);
925 close(1);
926 dup2(output_fd, 1);
927 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
928 LOGERR("execlp openaes ERROR!\n");
929 close(pipes[2]);
930 close(output_fd);
931 _exit(-1);
932 }
933 } else {
934 // Parent
935 close(pipes[0]);
936 close(pipes[2]);
937 close(pipes[3]);
938 fd = pipes[1];
Dees_Troy5612cc82013-07-24 19:45:58 +0000939 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) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000940 close(fd);
941 LOGERR("tar_fdopen failed\n");
942 return -1;
943 }
944 return 0;
945 }
946 }
947 } else if (use_compression) {
948 // Compressed
949 Archive_Current_Type = 1;
950 LOGINFO("Using compression...\n");
951 int pigzfd[2];
952
953 if (pipe(pigzfd) < 0) {
954 LOGERR("Error creating pipe\n");
955 return -1;
956 }
957 pigz_pid = fork();
958
959 if (pigz_pid < 0) {
960 LOGERR("fork() failed\n");
961 close(pigzfd[0]);
962 close(pigzfd[1]);
963 return -1;
964 } else if (pigz_pid == 0) {
965 // Child
966 close(pigzfd[1]); // close unused output pipe
Dees_Troy5612cc82013-07-24 19:45:58 +0000967 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 +0000968 if (output_fd < 0) {
969 LOGERR("Failed to open '%s'\n", tarfn.c_str());
970 close(pigzfd[0]);
971 _exit(-1);
972 }
973 dup2(pigzfd[0], 0); // remap stdin
974 dup2(output_fd, 1); // remap stdout to output file
975 if (execlp("pigz", "pigz", "-", NULL) < 0) {
976 LOGERR("execlp pigz ERROR!\n");
977 close(output_fd);
978 close(pigzfd[0]);
979 _exit(-1);
980 }
981 } else {
982 // Parent
983 close(pigzfd[0]); // close parent input
984 fd = pigzfd[1]; // copy parent output
Dees_Troy5612cc82013-07-24 19:45:58 +0000985 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) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000986 close(fd);
987 LOGERR("tar_fdopen failed\n");
988 return -1;
989 }
990 }
991 } else if (use_encryption) {
992 // Encrypted
993 Archive_Current_Type = 2;
994 LOGINFO("Using encryption...\n");
995 DataManager::GetValue("tw_backup_password", Password);
996 int oaesfd[2];
997 pipe(oaesfd);
998 oaes_pid = fork();
999
1000 if (oaes_pid < 0) {
1001 LOGERR("fork() failed\n");
1002 close(oaesfd[0]);
1003 close(oaesfd[1]);
1004 return -1;
1005 } else if (oaes_pid == 0) {
1006 // Child
1007 close(oaesfd[1]); // close unused
Dees_Troy5612cc82013-07-24 19:45:58 +00001008 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 +00001009 if (output_fd < 0) {
1010 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1011 _exit(-1);
1012 }
1013 dup2(oaesfd[0], 0); // remap stdin
1014 dup2(output_fd, 1); // remap stdout to output file
1015 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
1016 LOGERR("execlp openaes ERROR!\n");
1017 close(output_fd);
1018 close(oaesfd[0]);
1019 _exit(-1);
1020 }
1021 } else {
1022 // Parent
1023 close(oaesfd[0]); // close parent input
1024 fd = oaesfd[1]; // copy parent output
Dees_Troy5612cc82013-07-24 19:45:58 +00001025 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) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001026 close(fd);
1027 LOGERR("tar_fdopen failed\n");
1028 return -1;
1029 }
1030 return 0;
1031 }
1032 } else {
1033 // Not compressed or encrypted
1034 init_libtar_buffer(0);
Dees_Troy5612cc82013-07-24 19:45:58 +00001035 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) == -1) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001036 LOGERR("tar_open error opening '%s'\n", tarfn.c_str());
1037 return -1;
1038 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001039 }
1040 return 0;
1041}
1042
Dees_Troy83bd4832013-05-04 12:39:56 +00001043int twrpTar::openTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001044 char* charRootDir = (char*) tardir.c_str();
1045 char* charTarFile = (char*) tarfn.c_str();
Dees_Troy83bd4832013-05-04 12:39:56 +00001046 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001047
Dees_Troy83bd4832013-05-04 12:39:56 +00001048 if (Archive_Current_Type == 3) {
1049 LOGINFO("Opening encrypted and compressed backup...\n");
1050 DataManager::GetValue("tw_restore_password", Password);
1051 int i, pipes[4];
1052
1053 if (pipe(pipes) < 0) {
1054 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001055 return -1;
1056 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001057 if (pipe(pipes + 2) < 0) {
1058 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001059 return -1;
1060 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001061 oaes_pid = fork();
1062
1063 if (oaes_pid < 0) {
1064 LOGERR("pigz fork() failed\n");
1065 for (i = 0; i < 4; i++)
1066 close(pipes[i]); // close all
1067 return -1;
1068 } else if (oaes_pid == 0) {
1069 // openaes Child
1070 close(pipes[0]); // Close pipes that are not used by this child
1071 close(pipes[2]);
1072 close(pipes[3]);
1073 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1074 if (input_fd < 0) {
1075 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1076 close(pipes[1]);
1077 _exit(-1);
1078 }
1079 close(0);
1080 dup2(input_fd, 0);
1081 close(1);
1082 dup2(pipes[1], 1);
1083 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1084 LOGERR("execlp openaes ERROR!\n");
1085 close(input_fd);
1086 close(pipes[1]);
1087 _exit(-1);
1088 }
1089 } else {
1090 // Parent
1091 pigz_pid = fork();
1092
1093 if (pigz_pid < 0) {
1094 LOGERR("openaes fork() failed\n");
1095 for (i = 0; i < 4; i++)
1096 close(pipes[i]); // close all
1097 return -1;
1098 } else if (pigz_pid == 0) {
1099 // pigz Child
1100 close(pipes[1]); // Close pipes not used by this child
1101 close(pipes[2]);
1102 close(0);
1103 dup2(pipes[0], 0);
1104 close(1);
1105 dup2(pipes[3], 1);
1106 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1107 LOGERR("execlp pigz ERROR!\n");
1108 close(pipes[0]);
1109 close(pipes[3]);
1110 _exit(-1);
1111 }
1112 } else {
1113 // Parent
1114 close(pipes[0]); // Close pipes not used by parent
1115 close(pipes[1]);
1116 close(pipes[3]);
1117 fd = pipes[2];
Dees_Troy5612cc82013-07-24 19:45:58 +00001118 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) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001119 close(fd);
1120 LOGERR("tar_fdopen failed\n");
1121 return -1;
1122 }
1123 }
1124 }
1125 } else if (Archive_Current_Type == 2) {
1126 LOGINFO("Opening encrypted backup...\n");
1127 DataManager::GetValue("tw_restore_password", Password);
1128 int oaesfd[2];
1129
1130 pipe(oaesfd);
1131 oaes_pid = fork();
1132 if (oaes_pid < 0) {
1133 LOGERR("fork() failed\n");
1134 close(oaesfd[0]);
1135 close(oaesfd[1]);
1136 return -1;
1137 } else if (oaes_pid == 0) {
1138 // Child
1139 close(oaesfd[0]); // Close unused pipe
1140 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1141 if (input_fd < 0) {
1142 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1143 close(oaesfd[1]);
1144 _exit(-1);
1145 }
1146 close(0); // close stdin
1147 dup2(oaesfd[1], 1); // remap stdout
1148 dup2(input_fd, 0); // remap input fd to stdin
1149 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1150 LOGERR("execlp openaes ERROR!\n");
1151 close(input_fd);
1152 close(oaesfd[1]);
1153 _exit(-1);
1154 }
1155 } else {
1156 // Parent
1157 close(oaesfd[1]); // close parent output
1158 fd = oaesfd[0]; // copy parent input
Dees_Troy5612cc82013-07-24 19:45:58 +00001159 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) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001160 close(fd);
1161 LOGERR("tar_fdopen failed\n");
1162 return -1;
1163 }
1164 }
1165 } else if (Archive_Current_Type == 1) {
1166 LOGINFO("Opening as a gzip...\n");
1167 int pigzfd[2];
1168 pipe(pigzfd);
1169
1170 pigz_pid = fork();
1171 if (pigz_pid < 0) {
1172 LOGERR("fork() failed\n");
1173 close(pigzfd[0]);
1174 close(pigzfd[1]);
1175 return -1;
1176 } else if (pigz_pid == 0) {
1177 // Child
1178 close(pigzfd[0]);
1179 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1180 if (input_fd < 0) {
1181 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1182 _exit(-1);
1183 }
1184 dup2(input_fd, 0); // remap input fd to stdin
1185 dup2(pigzfd[1], 1); // remap stdout
1186 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1187 close(pigzfd[1]);
1188 close(input_fd);
1189 LOGERR("execlp openaes ERROR!\n");
1190 _exit(-1);
1191 }
1192 } else {
1193 // Parent
1194 close(pigzfd[1]); // close parent output
1195 fd = pigzfd[0]; // copy parent input
Dees_Troy5612cc82013-07-24 19:45:58 +00001196 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) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001197 close(fd);
1198 LOGERR("tar_fdopen failed\n");
1199 return -1;
1200 }
1201 }
Dees_Troy5612cc82013-07-24 19:45:58 +00001202 } 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) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001203 LOGERR("Unable to open tar archive '%s'\n", charTarFile);
1204 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001205 }
1206 return 0;
1207}
1208
1209string twrpTar::Strip_Root_Dir(string Path) {
1210 string temp;
1211 size_t slash;
1212
1213 if (Path.substr(0, 1) == "/")
1214 temp = Path.substr(1, Path.size() - 1);
1215 else
1216 temp = Path;
1217 slash = temp.find("/");
1218 if (slash == string::npos)
1219 return temp;
1220 else {
1221 string stripped;
1222
1223 stripped = temp.substr(slash, temp.size() - slash);
1224 return stripped;
1225 }
1226 return temp;
1227}
1228
1229int twrpTar::addFile(string fn, bool include_root) {
1230 char* charTarFile = (char*) fn.c_str();
1231 if (include_root) {
1232 if (tar_append_file(t, charTarFile, NULL) == -1)
1233 return -1;
1234 } else {
1235 string temp = Strip_Root_Dir(fn);
1236 char* charTarPath = (char*) temp.c_str();
1237 if (tar_append_file(t, charTarFile, charTarPath) == -1)
1238 return -1;
1239 }
1240 return 0;
1241}
1242
Dees_Troy83bd4832013-05-04 12:39:56 +00001243int twrpTar::closeTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001244 flush_libtar_buffer(t->fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001245 if (tar_append_eof(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001246 LOGERR("tar_append_eof(): %s\n", strerror(errno));
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001247 tar_close(t);
1248 return -1;
1249 }
1250 if (tar_close(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001251 LOGERR("Unable to close tar archive: '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001252 return -1;
1253 }
Dees_Troy2727b992013-08-14 20:09:30 +00001254 if (Archive_Current_Type > 0) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001255 close(fd);
Dees_Troy83bd4832013-05-04 12:39:56 +00001256 int status;
1257 if (pigz_pid > 0 && TWFunc::Wait_For_Child(pigz_pid, &status, "pigz") != 0)
1258 return -1;
1259 if (oaes_pid > 0 && TWFunc::Wait_For_Child(oaes_pid, &status, "openaes") != 0)
1260 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001261 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001262 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001263 return 0;
1264}
1265
1266int twrpTar::removeEOT(string tarFile) {
1267 char* charTarFile = (char*) tarFile.c_str();
1268 off_t tarFileEnd;
1269 while (th_read(t) == 0) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001270 if (TH_ISREG(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001271 tar_skip_regfile(t);
1272 tarFileEnd = lseek(t->fd, 0, SEEK_CUR);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001273 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001274 if (tar_close(t) == -1)
1275 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001276 if (truncate(charTarFile, tarFileEnd) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001277 return -1;
1278 return 0;
1279}
1280
n0d33b511632013-03-06 21:14:15 +02001281int twrpTar::entryExists(string entry) {
1282 char* searchstr = (char*)entry.c_str();
1283 int ret;
1284
Dees_Troy83bd4832013-05-04 12:39:56 +00001285 Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
n0d33b511632013-03-06 21:14:15 +02001286
Dees_Troy83bd4832013-05-04 12:39:56 +00001287 if (openTar() == -1)
n0d33b511632013-03-06 21:14:15 +02001288 ret = 0;
1289 else
1290 ret = tar_find(t, searchstr);
1291
Dees_Troy83bd4832013-05-04 12:39:56 +00001292 if (closeTar() != 0)
1293 LOGINFO("Unable to close tar after searching for entry.\n");
n0d33b511632013-03-06 21:14:15 +02001294
1295 return ret;
1296}
1297
Dees_Troy83bd4832013-05-04 12:39:56 +00001298unsigned long long twrpTar::uncompressedSize() {
1299 int type = 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001300 unsigned long long total_size = 0;
Dees_Troy83bd4832013-05-04 12:39:56 +00001301 string Tar, Command, result;
1302 vector<string> split;
1303
1304 Tar = TWFunc::Get_Filename(tarfn);
1305 type = TWFunc::Get_File_Type(tarfn);
1306 if (type == 0)
1307 total_size = TWFunc::Get_File_Size(tarfn);
1308 else {
1309 Command = "pigz -l " + tarfn;
1310 /* if we set Command = "pigz -l " + tarfn + " | sed '1d' | cut -f5 -d' '";
1311 we get the uncompressed size at once. */
1312 TWFunc::Exec_Cmd(Command, result);
1313 if (!result.empty()) {
1314 /* Expected output:
1315 compressed original reduced name
1316 95855838 179403776 -1.3% data.yaffs2.win
1317 ^
1318 split[5]
1319 */
1320 split = TWFunc::split_string(result, ' ', true);
1321 if (split.size() > 4)
1322 total_size = atoi(split[5].c_str());
1323 }
1324 }
1325 LOGINFO("%s's uncompressed size: %llu bytes\n", Tar.c_str(), total_size);
1326
1327 return total_size;
1328}
1329
Dees_Troye34c1332013-02-06 19:13:00 +00001330extern "C" ssize_t write_tar(int fd, const void *buffer, size_t size) {
1331 return (ssize_t) write_libtar_buffer(fd, buffer, size);
Dees_Troy40bbcf82013-02-12 15:01:53 +00001332}