blob: bc7f37055f2fd604a17dd58cca0b2ffb11aaca19 [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_Troy3263e922013-03-15 11:42:57 -0500662 char buf[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_Troy2673cec2013-04-02 20:22:16 +0000700 LOGINFO("adding '%s'\n", subfolder.c_str());
Dees_Troy3263e922013-03-15 11:42:57 -0500701 if (addFile(subfolder, include_root) != 0)
702 return -1;
703 continue;
704 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000705 LOGINFO("adding '%s'\n", subfolder.c_str());
Dees_Troye34c1332013-02-06 19:13:00 +0000706 strcpy(buf, subfolder.c_str());
707 if (de->d_type == DT_DIR) {
Dees_Troy3263e922013-03-15 11:42:57 -0500708 char* charTarPath;
709 if (include_root) {
710 charTarPath = NULL;
711 } else {
712 string temp = Strip_Root_Dir(buf);
713 charTarPath = (char*) temp.c_str();
714 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000715 if (tar_append_tree(t, buf, charTarPath, excl) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000716 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
Dees_Troye34c1332013-02-06 19:13:00 +0000717 return -1;
718 }
Dees_Troye34c1332013-02-06 19:13:00 +0000719 } else if (tardir != "/" && (de->d_type == DT_REG || de->d_type == DT_LNK)) {
Dees_Troy3263e922013-03-15 11:42:57 -0500720 if (addFile(buf, include_root) != 0)
721 return -1;
722 }
Dees_Troye34c1332013-02-06 19:13:00 +0000723 fflush(NULL);
724 }
725 closedir(d);
726 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500727 return 0;
728}
729
Dees_Troy83bd4832013-05-04 12:39:56 +0000730int twrpTar::tarList(bool include_root, std::vector<TarListStruct> *TarList, unsigned thread_id) {
731 struct stat st;
732 char buf[PATH_MAX];
733 int list_size = TarList->size(), i = 0, archive_count = 0;
734 string temp;
735 char actual_filename[PATH_MAX];
Dees_Troye34c1332013-02-06 19:13:00 +0000736
Dees_Troy83bd4832013-05-04 12:39:56 +0000737 basefn = tarfn;
738 temp = basefn + "%i%02i";
739 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
740 tarfn = actual_filename;
741 if (createTar() != 0) {
742 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
743 return -2;
744 }
745 Archive_Current_Size = 0;
746
747 while (i < list_size) {
748 if (TarList->at(i).thread_id == thread_id) {
749 strcpy(buf, TarList->at(i).fn.c_str());
750 stat(buf, &st);
751 if (st.st_mode & S_IFREG) { // item is a regular file
752 if (Archive_Current_Size + (unsigned long long)(st.st_size) > MAX_ARCHIVE_SIZE) {
753 if (closeTar() != 0) {
754 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
755 return -3;
756 }
757 archive_count++;
758 LOGINFO("Splitting thread ID %i into archive %i\n", thread_id, archive_count);
759 if (archive_count > 99) {
760 LOGINFO("BLAH!\n");
761 LOGERR("Too many archives for thread %i\n", thread_id);
762 return -4;
763 }
764 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
765 tarfn = actual_filename;
766 if (createTar() != 0) {
767 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
768 return -2;
769 }
770 Archive_Current_Size = 0;
771 }
772 Archive_Current_Size += (unsigned long long)(st.st_size);
773 }
774 if (addFile(buf, include_root) != 0) {
775 LOGERR("Error adding file '%s' to '%s'\n", buf, tarfn.c_str());
776 return -1;
777 }
778 }
779 i++;
780 }
781 if (closeTar() != 0) {
782 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
783 return -3;
784 }
785 LOGINFO("Thread id %i tarList done, %i archives.\n", thread_id, archive_count, i, list_size);
Dees_Troye34c1332013-02-06 19:13:00 +0000786 return 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500787}
788
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500789int twrpTar::create() {
Dees_Troye34c1332013-02-06 19:13:00 +0000790
791 init_libtar_buffer(0);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500792 if (createTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500793 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500794 if (tarDirs(false) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500795 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000796 if (closeTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500797 return -1;
Dees_Troye34c1332013-02-06 19:13:00 +0000798 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500799 return 0;
800}
801
Dees_Troy83bd4832013-05-04 12:39:56 +0000802void* twrpTar::createList(void *cookie) {
803
804 twrpTar* threadTar = (twrpTar*) cookie;
805 if (threadTar->tarList(true, threadTar->ItemList, threadTar->thread_id) == -1) {
806 LOGINFO("ERROR tarList for thread ID %i\n", threadTar->thread_id);
807 return (void*)-2;
808 }
809 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
810 return (void*)0;
811}
812
813void* twrpTar::extractMulti(void *cookie) {
814
815 twrpTar* threadTar = (twrpTar*) cookie;
816 int archive_count = 0;
817 string temp = threadTar->basefn + "%i%02i";
818 char actual_filename[255];
819 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
820 while (TWFunc::Path_Exists(actual_filename)) {
821 threadTar->tarfn = actual_filename;
822 if (threadTar->extract() != 0) {
823 LOGINFO("Error extracting '%s' in thread ID %i\n", actual_filename, threadTar->thread_id);
824 return (void*)-2;
825 }
826 archive_count++;
827 if (archive_count > 99)
828 break;
829 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
830 }
831 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
832 return (void*)0;
833}
834
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500835int twrpTar::addFilesToExistingTar(vector <string> files, string fn) {
836 char* charTarFile = (char*) fn.c_str();
837
Dees_Troy83bd4832013-05-04 12:39:56 +0000838 if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500839 return -1;
840 removeEOT(charTarFile);
Dees_Troy83bd4832013-05-04 12:39:56 +0000841 if (tar_open(&t, charTarFile, NULL, O_WRONLY | O_APPEND | O_LARGEFILE, 0644, TAR_GNU) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500842 return -1;
843 for (unsigned int i = 0; i < files.size(); ++i) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500844 char* file = (char*) files.at(i).c_str();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500845 if (tar_append_file(t, file, file) == -1)
846 return -1;
847 }
848 if (tar_append_eof(t) == -1)
849 return -1;
850 if (tar_close(t) == -1)
851 return -1;
852 return 0;
853}
854
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500855int twrpTar::createTar() {
856 char* charTarFile = (char*) tarfn.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000857 char* charRootDir = (char*) tardir.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000858 static tartype_t type = { open, close, read, write_tar };
Dees_Troy83bd4832013-05-04 12:39:56 +0000859 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500860
Dees_Troy83bd4832013-05-04 12:39:56 +0000861 if (use_encryption && use_compression) {
862 // Compressed and encrypted
863 Archive_Current_Type = 3;
864 LOGINFO("Using encryption and compression...\n");
865 DataManager::GetValue("tw_backup_password", Password);
866 int i, pipes[4];
867
868 if (pipe(pipes) < 0) {
869 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500870 return -1;
871 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000872 if (pipe(pipes + 2) < 0) {
873 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500874 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000875 }
876 pigz_pid = fork();
877
878 if (pigz_pid < 0) {
879 LOGERR("pigz fork() failed\n");
880 for (i = 0; i < 4; i++)
881 close(pipes[i]); // close all
882 return -1;
883 } else if (pigz_pid == 0) {
884 // pigz Child
885 close(pipes[1]);
886 close(pipes[2]);
887 close(0);
888 dup2(pipes[0], 0);
889 close(1);
890 dup2(pipes[3], 1);
891 if (execlp("pigz", "pigz", "-", NULL) < 0) {
892 LOGERR("execlp pigz ERROR!\n");
893 close(pipes[0]);
894 close(pipes[3]);
895 _exit(-1);
896 }
897 } else {
898 // Parent
899 oaes_pid = fork();
900
901 if (oaes_pid < 0) {
902 LOGERR("openaes fork() failed\n");
903 for (i = 0; i < 4; i++)
904 close(pipes[i]); // close all
905 return -1;
906 } else if (oaes_pid == 0) {
907 // openaes Child
908 int output_fd = open(tarfn.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
909 if (output_fd < 0) {
910 LOGERR("Failed to open '%s'\n", tarfn.c_str());
911 for (i = 0; i < 4; i++)
912 close(pipes[i]); // close all
913 return -1;
914 }
915 close(pipes[0]);
916 close(pipes[1]);
917 close(pipes[3]);
918 close(0);
919 dup2(pipes[2], 0);
920 close(1);
921 dup2(output_fd, 1);
922 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
923 LOGERR("execlp openaes ERROR!\n");
924 close(pipes[2]);
925 close(output_fd);
926 _exit(-1);
927 }
928 } else {
929 // Parent
930 close(pipes[0]);
931 close(pipes[2]);
932 close(pipes[3]);
933 fd = pipes[1];
934 if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, 0644, TAR_GNU) != 0) {
935 close(fd);
936 LOGERR("tar_fdopen failed\n");
937 return -1;
938 }
939 return 0;
940 }
941 }
942 } else if (use_compression) {
943 // Compressed
944 Archive_Current_Type = 1;
945 LOGINFO("Using compression...\n");
946 int pigzfd[2];
947
948 if (pipe(pigzfd) < 0) {
949 LOGERR("Error creating pipe\n");
950 return -1;
951 }
952 pigz_pid = fork();
953
954 if (pigz_pid < 0) {
955 LOGERR("fork() failed\n");
956 close(pigzfd[0]);
957 close(pigzfd[1]);
958 return -1;
959 } else if (pigz_pid == 0) {
960 // Child
961 close(pigzfd[1]); // close unused output pipe
962 int output_fd = open(tarfn.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
963 if (output_fd < 0) {
964 LOGERR("Failed to open '%s'\n", tarfn.c_str());
965 close(pigzfd[0]);
966 _exit(-1);
967 }
968 dup2(pigzfd[0], 0); // remap stdin
969 dup2(output_fd, 1); // remap stdout to output file
970 if (execlp("pigz", "pigz", "-", NULL) < 0) {
971 LOGERR("execlp pigz ERROR!\n");
972 close(output_fd);
973 close(pigzfd[0]);
974 _exit(-1);
975 }
976 } else {
977 // Parent
978 close(pigzfd[0]); // close parent input
979 fd = pigzfd[1]; // copy parent output
980 if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, 0644, TAR_GNU) != 0) {
981 close(fd);
982 LOGERR("tar_fdopen failed\n");
983 return -1;
984 }
985 }
986 } else if (use_encryption) {
987 // Encrypted
988 Archive_Current_Type = 2;
989 LOGINFO("Using encryption...\n");
990 DataManager::GetValue("tw_backup_password", Password);
991 int oaesfd[2];
992 pipe(oaesfd);
993 oaes_pid = fork();
994
995 if (oaes_pid < 0) {
996 LOGERR("fork() failed\n");
997 close(oaesfd[0]);
998 close(oaesfd[1]);
999 return -1;
1000 } else if (oaes_pid == 0) {
1001 // Child
1002 close(oaesfd[1]); // close unused
1003 int output_fd = open(tarfn.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1004 if (output_fd < 0) {
1005 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1006 _exit(-1);
1007 }
1008 dup2(oaesfd[0], 0); // remap stdin
1009 dup2(output_fd, 1); // remap stdout to output file
1010 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
1011 LOGERR("execlp openaes ERROR!\n");
1012 close(output_fd);
1013 close(oaesfd[0]);
1014 _exit(-1);
1015 }
1016 } else {
1017 // Parent
1018 close(oaesfd[0]); // close parent input
1019 fd = oaesfd[1]; // copy parent output
1020 if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, 0644, TAR_GNU) != 0) {
1021 close(fd);
1022 LOGERR("tar_fdopen failed\n");
1023 return -1;
1024 }
1025 return 0;
1026 }
1027 } else {
1028 // Not compressed or encrypted
1029 init_libtar_buffer(0);
1030 if (tar_open(&t, charTarFile, &type, O_WRONLY | O_CREAT | O_LARGEFILE, 0644, TAR_GNU) == -1) {
1031 LOGERR("tar_open error opening '%s'\n", tarfn.c_str());
1032 return -1;
1033 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001034 }
1035 return 0;
1036}
1037
Dees_Troy83bd4832013-05-04 12:39:56 +00001038int twrpTar::openTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001039 char* charRootDir = (char*) tardir.c_str();
1040 char* charTarFile = (char*) tarfn.c_str();
Dees_Troy83bd4832013-05-04 12:39:56 +00001041 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001042
Dees_Troy83bd4832013-05-04 12:39:56 +00001043 if (Archive_Current_Type == 3) {
1044 LOGINFO("Opening encrypted and compressed backup...\n");
1045 DataManager::GetValue("tw_restore_password", Password);
1046 int i, pipes[4];
1047
1048 if (pipe(pipes) < 0) {
1049 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001050 return -1;
1051 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001052 if (pipe(pipes + 2) < 0) {
1053 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001054 return -1;
1055 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001056 oaes_pid = fork();
1057
1058 if (oaes_pid < 0) {
1059 LOGERR("pigz fork() failed\n");
1060 for (i = 0; i < 4; i++)
1061 close(pipes[i]); // close all
1062 return -1;
1063 } else if (oaes_pid == 0) {
1064 // openaes Child
1065 close(pipes[0]); // Close pipes that are not used by this child
1066 close(pipes[2]);
1067 close(pipes[3]);
1068 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1069 if (input_fd < 0) {
1070 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1071 close(pipes[1]);
1072 _exit(-1);
1073 }
1074 close(0);
1075 dup2(input_fd, 0);
1076 close(1);
1077 dup2(pipes[1], 1);
1078 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1079 LOGERR("execlp openaes ERROR!\n");
1080 close(input_fd);
1081 close(pipes[1]);
1082 _exit(-1);
1083 }
1084 } else {
1085 // Parent
1086 pigz_pid = fork();
1087
1088 if (pigz_pid < 0) {
1089 LOGERR("openaes fork() failed\n");
1090 for (i = 0; i < 4; i++)
1091 close(pipes[i]); // close all
1092 return -1;
1093 } else if (pigz_pid == 0) {
1094 // pigz Child
1095 close(pipes[1]); // Close pipes not used by this child
1096 close(pipes[2]);
1097 close(0);
1098 dup2(pipes[0], 0);
1099 close(1);
1100 dup2(pipes[3], 1);
1101 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1102 LOGERR("execlp pigz ERROR!\n");
1103 close(pipes[0]);
1104 close(pipes[3]);
1105 _exit(-1);
1106 }
1107 } else {
1108 // Parent
1109 close(pipes[0]); // Close pipes not used by parent
1110 close(pipes[1]);
1111 close(pipes[3]);
1112 fd = pipes[2];
1113 if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) != 0) {
1114 close(fd);
1115 LOGERR("tar_fdopen failed\n");
1116 return -1;
1117 }
1118 }
1119 }
1120 } else if (Archive_Current_Type == 2) {
1121 LOGINFO("Opening encrypted backup...\n");
1122 DataManager::GetValue("tw_restore_password", Password);
1123 int oaesfd[2];
1124
1125 pipe(oaesfd);
1126 oaes_pid = fork();
1127 if (oaes_pid < 0) {
1128 LOGERR("fork() failed\n");
1129 close(oaesfd[0]);
1130 close(oaesfd[1]);
1131 return -1;
1132 } else if (oaes_pid == 0) {
1133 // Child
1134 close(oaesfd[0]); // Close unused pipe
1135 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1136 if (input_fd < 0) {
1137 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1138 close(oaesfd[1]);
1139 _exit(-1);
1140 }
1141 close(0); // close stdin
1142 dup2(oaesfd[1], 1); // remap stdout
1143 dup2(input_fd, 0); // remap input fd to stdin
1144 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1145 LOGERR("execlp openaes ERROR!\n");
1146 close(input_fd);
1147 close(oaesfd[1]);
1148 _exit(-1);
1149 }
1150 } else {
1151 // Parent
1152 close(oaesfd[1]); // close parent output
1153 fd = oaesfd[0]; // copy parent input
1154 if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) != 0) {
1155 close(fd);
1156 LOGERR("tar_fdopen failed\n");
1157 return -1;
1158 }
1159 }
1160 } else if (Archive_Current_Type == 1) {
1161 LOGINFO("Opening as a gzip...\n");
1162 int pigzfd[2];
1163 pipe(pigzfd);
1164
1165 pigz_pid = fork();
1166 if (pigz_pid < 0) {
1167 LOGERR("fork() failed\n");
1168 close(pigzfd[0]);
1169 close(pigzfd[1]);
1170 return -1;
1171 } else if (pigz_pid == 0) {
1172 // Child
1173 close(pigzfd[0]);
1174 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1175 if (input_fd < 0) {
1176 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1177 _exit(-1);
1178 }
1179 dup2(input_fd, 0); // remap input fd to stdin
1180 dup2(pigzfd[1], 1); // remap stdout
1181 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1182 close(pigzfd[1]);
1183 close(input_fd);
1184 LOGERR("execlp openaes ERROR!\n");
1185 _exit(-1);
1186 }
1187 } else {
1188 // Parent
1189 close(pigzfd[1]); // close parent output
1190 fd = pigzfd[0]; // copy parent input
1191 if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) != 0) {
1192 close(fd);
1193 LOGERR("tar_fdopen failed\n");
1194 return -1;
1195 }
1196 }
1197 } else if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) != 0) {
1198 LOGERR("Unable to open tar archive '%s'\n", charTarFile);
1199 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001200 }
1201 return 0;
1202}
1203
1204string twrpTar::Strip_Root_Dir(string Path) {
1205 string temp;
1206 size_t slash;
1207
1208 if (Path.substr(0, 1) == "/")
1209 temp = Path.substr(1, Path.size() - 1);
1210 else
1211 temp = Path;
1212 slash = temp.find("/");
1213 if (slash == string::npos)
1214 return temp;
1215 else {
1216 string stripped;
1217
1218 stripped = temp.substr(slash, temp.size() - slash);
1219 return stripped;
1220 }
1221 return temp;
1222}
1223
1224int twrpTar::addFile(string fn, bool include_root) {
1225 char* charTarFile = (char*) fn.c_str();
1226 if (include_root) {
1227 if (tar_append_file(t, charTarFile, NULL) == -1)
1228 return -1;
1229 } else {
1230 string temp = Strip_Root_Dir(fn);
1231 char* charTarPath = (char*) temp.c_str();
1232 if (tar_append_file(t, charTarFile, charTarPath) == -1)
1233 return -1;
1234 }
1235 return 0;
1236}
1237
Dees_Troy83bd4832013-05-04 12:39:56 +00001238int twrpTar::closeTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001239 flush_libtar_buffer(t->fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001240 if (tar_append_eof(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001241 LOGERR("tar_append_eof(): %s\n", strerror(errno));
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001242 tar_close(t);
1243 return -1;
1244 }
1245 if (tar_close(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001246 LOGERR("Unable to close tar archive: '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001247 return -1;
1248 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001249 if (Archive_Current_Type > 1) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001250 close(fd);
Dees_Troy83bd4832013-05-04 12:39:56 +00001251 int status;
1252 if (pigz_pid > 0 && TWFunc::Wait_For_Child(pigz_pid, &status, "pigz") != 0)
1253 return -1;
1254 if (oaes_pid > 0 && TWFunc::Wait_For_Child(oaes_pid, &status, "openaes") != 0)
1255 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001256 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001257 free_libtar_buffer();
1258 TWFunc::tw_chmod(tarfn, "644");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001259 return 0;
1260}
1261
1262int twrpTar::removeEOT(string tarFile) {
1263 char* charTarFile = (char*) tarFile.c_str();
1264 off_t tarFileEnd;
1265 while (th_read(t) == 0) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001266 if (TH_ISREG(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001267 tar_skip_regfile(t);
1268 tarFileEnd = lseek(t->fd, 0, SEEK_CUR);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001269 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001270 if (tar_close(t) == -1)
1271 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001272 if (truncate(charTarFile, tarFileEnd) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001273 return -1;
1274 return 0;
1275}
1276
n0d33b511632013-03-06 21:14:15 +02001277int twrpTar::entryExists(string entry) {
1278 char* searchstr = (char*)entry.c_str();
1279 int ret;
1280
Dees_Troy83bd4832013-05-04 12:39:56 +00001281 Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
n0d33b511632013-03-06 21:14:15 +02001282
Dees_Troy83bd4832013-05-04 12:39:56 +00001283 if (openTar() == -1)
n0d33b511632013-03-06 21:14:15 +02001284 ret = 0;
1285 else
1286 ret = tar_find(t, searchstr);
1287
Dees_Troy83bd4832013-05-04 12:39:56 +00001288 if (closeTar() != 0)
1289 LOGINFO("Unable to close tar after searching for entry.\n");
n0d33b511632013-03-06 21:14:15 +02001290
1291 return ret;
1292}
1293
Dees_Troy83bd4832013-05-04 12:39:56 +00001294unsigned long long twrpTar::uncompressedSize() {
1295 int type = 0;
1296 unsigned long long total_size = 0;
1297 string Tar, Command, result;
1298 vector<string> split;
1299
1300 Tar = TWFunc::Get_Filename(tarfn);
1301 type = TWFunc::Get_File_Type(tarfn);
1302 if (type == 0)
1303 total_size = TWFunc::Get_File_Size(tarfn);
1304 else {
1305 Command = "pigz -l " + tarfn;
1306 /* if we set Command = "pigz -l " + tarfn + " | sed '1d' | cut -f5 -d' '";
1307 we get the uncompressed size at once. */
1308 TWFunc::Exec_Cmd(Command, result);
1309 if (!result.empty()) {
1310 /* Expected output:
1311 compressed original reduced name
1312 95855838 179403776 -1.3% data.yaffs2.win
1313 ^
1314 split[5]
1315 */
1316 split = TWFunc::split_string(result, ' ', true);
1317 if (split.size() > 4)
1318 total_size = atoi(split[5].c_str());
1319 }
1320 }
1321 LOGINFO("%s's uncompressed size: %llu bytes\n", Tar.c_str(), total_size);
1322
1323 return total_size;
1324}
1325
Dees_Troye34c1332013-02-06 19:13:00 +00001326extern "C" ssize_t write_tar(int fd, const void *buffer, size_t size) {
1327 return (ssize_t) write_libtar_buffer(fd, buffer, size);
Dees_Troy40bbcf82013-02-12 15:01:53 +00001328}