blob: 9c151b939258d85b03c9fa9d60d2222c8273e5c1 [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/*
Dees_Troye34c1332013-02-06 19:13:00 +00002 Copyright 2012 bigbiff/Dees_Troy TeamWin
3 This file is part of TWRP/TeamWin Recovery Project.
bigbiff bigbiff9c754052013-01-09 09:09:08 -05004
Dees_Troye34c1332013-02-06 19:13:00 +00005 TWRP is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
bigbiff bigbiff9c754052013-01-09 09:09:08 -05009
Dees_Troye34c1332013-02-06 19:13:00 +000010 TWRP is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
bigbiff bigbiff9c754052013-01-09 09:09:08 -050014
Dees_Troye34c1332013-02-06 19:13:00 +000015 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
bigbiff bigbiff9c754052013-01-09 09:09:08 -050017*/
18
19extern "C" {
20 #include "libtar/libtar.h"
Dees_Troye34c1332013-02-06 19:13:00 +000021 #include "twrpTar.h"
22 #include "tarWrite.h"
Dees_Troy40bbcf82013-02-12 15:01:53 +000023 #include "libcrecovery/common.h"
bigbiff bigbiff9c754052013-01-09 09:09:08 -050024}
25#include <sys/types.h>
26#include <sys/stat.h>
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -050027#include <sys/wait.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050028#include <string.h>
29#include <errno.h>
30#include <fcntl.h>
31#include <fstream>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050032#include <iostream>
33#include <string>
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050034#include <sstream>
Dees_Troy83bd4832013-05-04 12:39:56 +000035#include <vector>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050036#include <dirent.h>
37#include <sys/mman.h>
38#include "twrpTar.hpp"
Dees_Troy2673cec2013-04-02 20:22:16 +000039#include "twcommon.h"
bigbiff bigbiff9c754052013-01-09 09:09:08 -050040#include "data.hpp"
41#include "variables.h"
bigbiff bigbiff9c754052013-01-09 09:09:08 -050042#include "twrp-functions.hpp"
43
44using namespace std;
45
Dees_Troy83bd4832013-05-04 12:39:56 +000046twrpTar::twrpTar(void) {
47 use_encryption = 0;
48 userdata_encryption = 0;
49 use_compression = 0;
50 split_archives = 0;
51 has_data_media = 0;
52 pigz_pid = 0;
53 oaes_pid = 0;
54}
55
56twrpTar::~twrpTar(void) {
57 // Do nothing
58}
59
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050060void twrpTar::setfn(string fn) {
61 tarfn = fn;
62}
63
64void twrpTar::setdir(string dir) {
65 tardir = dir;
66}
67
Dees_Troy83bd4832013-05-04 12:39:56 +000068void twrpTar::setexcl(string exclude) {
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -040069 tarexclude.push_back(exclude);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050070}
71
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -050072int twrpTar::createTarFork() {
Dees_Troy83bd4832013-05-04 12:39:56 +000073 int status = 0;
74 pid_t pid, rc_pid;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -050075 if ((pid = fork()) == -1) {
Dees_Troy2673cec2013-04-02 20:22:16 +000076 LOGINFO("create tar failed to fork.\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050077 return -1;
78 }
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -050079 if (pid == 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +000080 // Child process
81 if (use_encryption || userdata_encryption) {
82 LOGINFO("Using encryption\n");
83 DIR* d;
84 struct dirent* de;
85 unsigned long long regular_size = 0, encrypt_size = 0, target_size = 0, core_count = 1;
86 unsigned enc_thread_id = 1, regular_thread_id = 0, i, start_thread_id = 1;
87 int item_len, ret, thread_error = 0;
88 std::vector<TarListStruct> RegularList;
89 std::vector<TarListStruct> EncryptList;
90 string FileName;
91 struct TarListStruct TarItem;
92 twrpTar reg, enc[9];
93 struct stat st;
94 pthread_t enc_thread[9];
95 pthread_attr_t tattr;
96 void *thread_return;
97
98 core_count = sysconf(_SC_NPROCESSORS_CONF);
99 if (core_count > 8)
100 core_count = 8;
101 LOGINFO(" Core Count : %llu\n", core_count);
102 Archive_Current_Size = 0;
103
104 d = opendir(tardir.c_str());
105 if (d == NULL) {
106 LOGERR("error opening '%s'\n", tardir.c_str());
107 _exit(-1);
108 }
109 // Figure out the size of all data to be encrypted and create a list of unencrypted files
110 while ((de = readdir(d)) != NULL) {
111 FileName = tardir + "/";
112 FileName += de->d_name;
113 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
114 continue; // Skip /data/media
115 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
116 continue;
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400117 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0 && strcmp(de->d_name, "lost+found") != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000118 item_len = strlen(de->d_name);
119 if (userdata_encryption && ((item_len >= 3 && strncmp(de->d_name, "app", 3) == 0) || (item_len >= 6 && strncmp(de->d_name, "dalvik", 6) == 0))) {
120 if (Generate_TarList(FileName, &RegularList, &target_size, &regular_thread_id) < 0) {
121 LOGERR("Error in Generate_TarList with regular list!\n");
122 closedir(d);
123 _exit(-1);
124 }
125 regular_size += TWFunc::Get_Folder_Size(FileName, false);
126 } else {
127 encrypt_size += TWFunc::Get_Folder_Size(FileName, false);
128 }
129 } else if (de->d_type == DT_REG) {
130 stat(FileName.c_str(), &st);
131 encrypt_size += (unsigned long long)(st.st_size);
132 }
133 }
134 closedir(d);
135
136 target_size = encrypt_size / core_count;
137 target_size++;
138 LOGINFO(" Unencrypted size: %llu\n", regular_size);
139 LOGINFO(" Encrypted size : %llu\n", encrypt_size);
140 LOGINFO(" Target size : %llu\n", target_size);
141 if (!userdata_encryption) {
142 enc_thread_id = 0;
143 start_thread_id = 0;
144 core_count--;
145 }
146 Archive_Current_Size = 0;
147
148 d = opendir(tardir.c_str());
149 if (d == NULL) {
150 LOGERR("error opening '%s'\n", tardir.c_str());
151 _exit(-1);
152 }
153 // Divide up the encrypted file list for threading
154 while ((de = readdir(d)) != NULL) {
155 FileName = tardir + "/";
156 FileName += de->d_name;
157 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
158 continue; // Skip /data/media
159 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
160 continue;
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400161 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0 && strcmp(de->d_name, "lost+found") != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000162 item_len = strlen(de->d_name);
163 if (userdata_encryption && ((item_len >= 3 && strncmp(de->d_name, "app", 3) == 0) || (item_len >= 6 && strncmp(de->d_name, "dalvik", 6) == 0))) {
164 // Do nothing, we added these to RegularList earlier
165 } else {
166 FileName = tardir + "/";
167 FileName += de->d_name;
168 if (Generate_TarList(FileName, &EncryptList, &target_size, &enc_thread_id) < 0) {
169 LOGERR("Error in Generate_TarList with encrypted list!\n");
170 closedir(d);
171 _exit(-1);
172 }
173 }
174 } else if (de->d_type == DT_REG || de->d_type == DT_LNK) {
175 stat(FileName.c_str(), &st);
176 if (de->d_type == DT_REG)
177 Archive_Current_Size += (unsigned long long)(st.st_size);
178 TarItem.fn = FileName;
179 TarItem.thread_id = enc_thread_id;
180 EncryptList.push_back(TarItem);
181 }
182 }
183 closedir(d);
184 if (enc_thread_id != core_count) {
185 LOGERR("Error dividing up threads for encryption, %i threads for %i cores!\n", enc_thread_id, core_count);
186 if (enc_thread_id > core_count)
187 _exit(-1);
188 else
189 LOGERR("Continuining anyway.");
190 }
191
192 if (userdata_encryption) {
193 // Create a backup of unencrypted data
194 reg.setfn(tarfn);
195 reg.ItemList = &RegularList;
196 reg.thread_id = 0;
197 reg.use_encryption = 0;
198 reg.use_compression = use_compression;
199 LOGINFO("Creating unencrypted backup...\n");
200 if (createList((void*)&reg) != 0) {
201 LOGERR("Error creating unencrypted backup.\n");
202 _exit(-1);
203 }
204 }
205
206 if (pthread_attr_init(&tattr)) {
207 LOGERR("Unable to pthread_attr_init\n");
208 _exit(-1);
209 }
210 if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
211 LOGERR("Error setting pthread_attr_setdetachstate\n");
212 _exit(-1);
213 }
214 if (pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM)) {
215 LOGERR("Error setting pthread_attr_setscope\n");
216 _exit(-1);
217 }
218 /*if (pthread_attr_setstacksize(&tattr, 524288)) {
219 LOGERR("Error setting pthread_attr_setstacksize\n");
220 _exit(-1);
221 }*/
222
223 // Create threads for the divided up encryption lists
224 for (i = start_thread_id; i <= core_count; i++) {
225 enc[i].setdir(tardir);
226 enc[i].setfn(tarfn);
227 enc[i].ItemList = &EncryptList;
228 enc[i].thread_id = i;
229 enc[i].use_encryption = use_encryption;
230 enc[i].use_compression = use_compression;
231 LOGINFO("Start encryption thread %i\n", i);
232 ret = pthread_create(&enc_thread[i], &tattr, createList, (void*)&enc[i]);
233 if (ret) {
234 LOGINFO("Unable to create %i thread for encryption! %i\nContinuing in same thread (backup will be slower).", i, ret);
235 if (createList((void*)&enc[i]) != 0) {
236 LOGERR("Error creating encrypted backup %i.\n", i);
237 _exit(-1);
238 } else {
239 enc[i].thread_id = i + 1;
240 }
241 }
242 usleep(100000); // Need a short delay before starting the next thread or the threads will never finish for some reason.
243 }
244 if (pthread_attr_destroy(&tattr)) {
245 LOGERR("Failed to pthread_attr_destroy\n");
246 }
247 for (i = start_thread_id; i <= core_count; i++) {
248 if (enc[i].thread_id == i) {
249 if (pthread_join(enc_thread[i], &thread_return)) {
250 LOGERR("Error joining thread %i\n", i);
251 _exit(-1);
252 } else {
253 LOGINFO("Joined thread %i.\n", i);
254 ret = (int)thread_return;
255 if (ret != 0) {
256 thread_error = 1;
257 LOGERR("Thread %i returned an error %i.\n", i, ret);
258 _exit(-1);
259 }
260 }
261 } else {
262 LOGINFO("Skipping joining thread %i because of pthread failure.\n", i);
263 }
264 }
265 if (thread_error) {
266 LOGERR("Error returned by one or more threads.\n");
267 _exit(-1);
268 }
269 LOGINFO("Finished encrypted backup.\n");
270 _exit(0);
271 } else {
272 if (create() != 0)
273 _exit(-1);
274 else
275 _exit(0);
276 }
277 } else {
278 if (TWFunc::Wait_For_Child(pid, &status, "createTarFork()") != 0)
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500279 return -1;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500280 }
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500281 return 0;
282}
283
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500284int twrpTar::extractTarFork() {
Dees_Troy83bd4832013-05-04 12:39:56 +0000285 int status = 0;
286 pid_t pid, rc_pid;
287
288 pid = fork();
289 if (pid >= 0) // fork was successful
290 {
291 if (pid == 0) // child process
292 {
293 if (TWFunc::Path_Exists(tarfn)) {
294 LOGINFO("Single archive\n");
295 if (extract() != 0)
296 _exit(-1);
297 else
298 _exit(0);
299 } else {
300 LOGINFO("Multiple archives\n");
301 string temp;
302 char actual_filename[255];
303 twrpTar tars[9];
304 pthread_t tar_thread[9];
305 pthread_attr_t tattr;
306 int thread_count = 0, i, start_thread_id = 1, ret, thread_error = 0;
307 void *thread_return;
308
309 basefn = tarfn;
310 temp = basefn + "%i%02i";
311 tarfn += "000";
312 if (!TWFunc::Path_Exists(tarfn)) {
313 LOGERR("Unable to locate '%s' or '%s'\n", basefn.c_str(), tarfn.c_str());
314 _exit(-1);
315 }
316 if (TWFunc::Get_File_Type(tarfn) != 2) {
317 LOGINFO("First tar file '%s' not encrypted\n", tarfn.c_str());
318 tars[0].basefn = basefn;
319 tars[0].thread_id = 0;
320 if (extractMulti((void*)&tars[0]) != 0) {
321 LOGERR("Error extracting split archive.\n");
322 _exit(-1);
323 }
324 } else {
325 start_thread_id = 0;
326 }
327 // Start threading encrypted restores
328 if (pthread_attr_init(&tattr)) {
329 LOGERR("Unable to pthread_attr_init\n");
330 _exit(-1);
331 }
332 if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
333 LOGERR("Error setting pthread_attr_setdetachstate\n");
334 _exit(-1);
335 }
336 if (pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM)) {
337 LOGERR("Error setting pthread_attr_setscope\n");
338 _exit(-1);
339 }
340 /*if (pthread_attr_setstacksize(&tattr, 524288)) {
341 LOGERR("Error setting pthread_attr_setstacksize\n");
342 _exit(-1);
343 }*/
344 for (i = start_thread_id; i < 9; i++) {
345 sprintf(actual_filename, temp.c_str(), i, 0);
346 if (TWFunc::Path_Exists(actual_filename)) {
347 thread_count++;
348 tars[i].basefn = basefn;
349 tars[i].thread_id = i;
350 LOGINFO("Creating extract thread ID %i\n", i);
351 ret = pthread_create(&tar_thread[i], &tattr, extractMulti, (void*)&tars[i]);
352 if (ret) {
353 LOGINFO("Unable to create %i thread for extraction! %i\nContinuing in same thread (restore will be slower).", i, ret);
354 if (extractMulti((void*)&tars[i]) != 0) {
355 LOGERR("Error extracting backup in thread %i.\n", i);
356 _exit(-1);
357 } else {
358 tars[i].thread_id = i + 1;
359 }
360 }
361 usleep(100000); // Need a short delay before starting the next thread or the threads will never finish for some reason.
362 } else {
363 break;
364 }
365 }
366 for (i = start_thread_id; i < thread_count + start_thread_id; i++) {
367 if (tars[i].thread_id == i) {
368 if (pthread_join(tar_thread[i], &thread_return)) {
369 LOGERR("Error joining thread %i\n", i);
370 _exit(-1);
371 } else {
372 LOGINFO("Joined thread %i.\n", i);
373 ret = (int)thread_return;
374 if (ret != 0) {
375 thread_error = 1;
376 LOGERR("Thread %i returned an error %i.\n", i, ret);
377 _exit(-1);
378 }
379 }
380 } else {
381 LOGINFO("Skipping joining thread %i because of pthread failure.\n", i);
382 }
383 }
384 if (thread_error) {
385 LOGERR("Error returned by one or more threads.\n");
386 _exit(-1);
387 }
388 LOGINFO("Finished encrypted backup.\n");
389 _exit(0);
390 }
391 }
392 else // parent process
393 {
394 if (TWFunc::Wait_For_Child(pid, &status, "extractTarFork()") != 0)
395 return -1;
396 }
397 }
398 else // fork has failed
399 {
Dees_Troy2673cec2013-04-02 20:22:16 +0000400 LOGINFO("extract tar failed to fork.\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500401 return -1;
402 }
403 return 0;
404}
405
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500406int twrpTar::splitArchiveFork() {
Dees_Troy83bd4832013-05-04 12:39:56 +0000407 int status = 0;
408 pid_t pid, rc_pid;
409
410 pid = fork();
411 if (pid >= 0) // fork was successful
412 {
413 if (pid == 0) // child process
414 {
415 if (Split_Archive() <= 0)
416 _exit(-1);
417 else
418 _exit(0);
419 }
420 else // parent process
421 {
422 if (TWFunc::Wait_For_Child(pid, &status, "splitArchiveFork()") != 0)
423 return -1;
424 }
425 }
426 else // fork has failed
427 {
428 LOGINFO("split archive failed to fork.\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500429 return -1;
430 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000431 return 0;
432}
433
434int twrpTar::Generate_TarList(string Path, std::vector<TarListStruct> *TarList, unsigned long long *Target_Size, unsigned *thread_id) {
435 DIR* d;
436 struct dirent* de;
437 struct stat st;
438 string FileName;
439 struct TarListStruct TarItem;
440 string::size_type i;
441 bool skip;
442
443 if (has_data_media == 1 && Path.size() >= 11 && strncmp(Path.c_str(), "/data/media", 11) == 0)
444 return 0; // Skip /data/media
445
446 d = opendir(Path.c_str());
447 if (d == NULL) {
448 LOGERR("error opening '%s' -- error: %s\n", Path.c_str(), strerror(errno));
449 closedir(d);
450 return -1;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500451 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000452 while ((de = readdir(d)) != NULL) {
453 // Skip excluded stuff
454 if (split.size() > 0) {
455 skip = false;
456 for (i = 0; i < split.size(); i++) {
457 if (strcmp(de->d_name, split[i].c_str()) == 0) {
458 LOGINFO("excluding %s\n", de->d_name);
459 skip = true;
460 break;
461 }
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500462 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000463 if (skip)
464 continue;
465 }
466 FileName = Path + "/";
467 FileName += de->d_name;
468 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
469 continue; // Skip /data/media
470 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
471 continue;
472 TarItem.fn = FileName;
473 TarItem.thread_id = *thread_id;
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400474 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0 && strcmp(de->d_name, "lost+found") != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000475 TarList->push_back(TarItem);
476 if (Generate_TarList(FileName, TarList, Target_Size, thread_id) < 0)
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500477 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000478 } else if (de->d_type == DT_REG || de->d_type == DT_LNK) {
479 stat(FileName.c_str(), &st);
480 TarList->push_back(TarItem);
481 if (de->d_type == DT_REG)
482 Archive_Current_Size += st.st_size;
483 if (Archive_Current_Size != 0 && *Target_Size != 0 && Archive_Current_Size > *Target_Size) {
484 *thread_id = *thread_id + 1;
485 Archive_Current_Size = 0;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500486 }
487 }
488 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000489 closedir(d);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500490 return 0;
491}
492
493int twrpTar::Generate_Multiple_Archives(string Path) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500494 DIR* d;
495 struct dirent* de;
496 struct stat st;
497 string FileName;
498 char actual_filename[255];
499
Dees_Troy83bd4832013-05-04 12:39:56 +0000500 string::size_type i;
501 bool skip;
502
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500503 if (has_data_media == 1 && Path.size() >= 11 && strncmp(Path.c_str(), "/data/media", 11) == 0)
504 return 0; // Skip /data/media
Dees_Troy2673cec2013-04-02 20:22:16 +0000505 LOGINFO("Path: '%s', archive filename: '%s'\n", Path.c_str(), tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500506
507 d = opendir(Path.c_str());
508 if (d == NULL)
509 {
Dees_Troy2673cec2013-04-02 20:22:16 +0000510 LOGERR("error opening '%s' -- error: %s\n", Path.c_str(), strerror(errno));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500511 closedir(d);
512 return -1;
513 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000514 while ((de = readdir(d)) != NULL) {
515 // Skip excluded stuff
516 if (split.size() > 0) {
517 skip = false;
518 for (i = 0; i < split.size(); i++) {
519 if (strcmp(de->d_name, split[i].c_str()) == 0) {
520 LOGINFO("excluding %s\n", de->d_name);
521 skip = true;
522 break;
523 }
524 }
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400525 if (skip) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000526 continue;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400527 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000528 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500529 FileName = Path + "/";
530 FileName += de->d_name;
531 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
532 continue; // Skip /data/media
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500533 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
534 continue;
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400535 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0 && strcmp(de->d_name, "lost+foud") != 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500536 {
537 unsigned long long folder_size = TWFunc::Get_Folder_Size(FileName, false);
538 if (Archive_Current_Size + folder_size > MAX_ARCHIVE_SIZE) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000539 LOGINFO("Calling Generate_Multiple_Archives\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500540 if (Generate_Multiple_Archives(FileName) < 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500541 return -1;
542 } else {
543 //FileName += "/";
Dees_Troy2673cec2013-04-02 20:22:16 +0000544 LOGINFO("Adding folder '%s'\n", FileName.c_str());
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500545 tardir = FileName;
546 if (tarDirs(true) < 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500547 return -1;
548 Archive_Current_Size += folder_size;
549 }
550 }
551 else if (de->d_type == DT_REG || de->d_type == DT_LNK)
552 {
553 stat(FileName.c_str(), &st);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400554 if (de->d_type != DT_LNK) {
555 if (Archive_Current_Size != 0 && Archive_Current_Size + st.st_size > MAX_ARCHIVE_SIZE) {
556 LOGINFO("Closing tar '%s', ", tarfn.c_str());
557 closeTar();
558 if (TWFunc::Get_File_Size(tarfn) == 0) {
559 LOGERR("Backup file size for '%s' is 0 bytes.\n", tarfn.c_str());
560 return -1;
561 }
562 Archive_File_Count++;
563 if (Archive_File_Count > 999) {
564 LOGERR("Archive count is too large!\n");
565 return -1;
566 }
567 string temp = basefn + "%03i";
568 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
569 tarfn = actual_filename;
570 Archive_Current_Size = 0;
571 LOGINFO("Creating tar '%s'\n", tarfn.c_str());
572 gui_print("Creating archive %i...\n", Archive_File_Count + 1);
573 if (createTar() != 0)
574 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500575 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500576 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000577 LOGINFO("Adding file: '%s'... ", FileName.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500578 if (addFile(FileName, true) < 0)
579 return -1;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400580 if (de->d_type != DT_LNK) {
581 Archive_Current_Size += st.st_size;
582 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000583 LOGINFO("added successfully, archive size: %llu\n", Archive_Current_Size);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400584 if (de->d_type != DT_LNK) {
585 if (st.st_size > 2147483648LL)
586 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());
587 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500588 }
589 }
590 closedir(d);
591 return 0;
592}
593
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500594int twrpTar::Split_Archive()
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500595{
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500596 string temp = tarfn + "%03i";
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500597 char actual_filename[255];
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400598 string tarsplit;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500599
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500600 basefn = tarfn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500601 Archive_File_Count = 0;
602 Archive_Current_Size = 0;
603 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500604 tarfn = actual_filename;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400605
606 for (int i = 0; i < tarexclude.size(); ++i) {
607 tarsplit = tarexclude[i];
608 tarsplit += " ";
609 }
610
Dees_Troy83bd4832013-05-04 12:39:56 +0000611 if (!tarexclude.empty())
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400612 split = TWFunc::split_string(tarsplit, ' ', true);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500613 createTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500614 DataManager::GetValue(TW_HAS_DATA_MEDIA, has_data_media);
Dees_Troy2673cec2013-04-02 20:22:16 +0000615 gui_print("Creating archive 1...\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500616 if (Generate_Multiple_Archives(tardir) < 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000617 LOGERR("Error generating multiple archives\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500618 return -1;
619 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000620 closeTar();
621 LOGINFO("Done, created %i archives.\n", (++Archive_File_Count));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500622 return (Archive_File_Count);
623}
624
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500625int twrpTar::extractTar() {
Dees_Troye34c1332013-02-06 19:13:00 +0000626 char* charRootDir = (char*) tardir.c_str();
Dees_Troy83bd4832013-05-04 12:39:56 +0000627 if (openTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500628 return -1;
629 if (tar_extract_all(t, charRootDir) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000630 LOGERR("Unable to extract tar archive '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500631 return -1;
632 }
633 if (tar_close(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000634 LOGERR("Unable to close tar file\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500635 return -1;
636 }
637 return 0;
638}
639
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500640int twrpTar::extract() {
Dees_Troy83bd4832013-05-04 12:39:56 +0000641 Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
n0d33b511632013-03-06 21:14:15 +0200642
643 if (Archive_Current_Type == 1) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500644 //if you return the extractTGZ function directly, stack crashes happen
Dees_Troy2673cec2013-04-02 20:22:16 +0000645 LOGINFO("Extracting gzipped tar\n");
Dees_Troy83bd4832013-05-04 12:39:56 +0000646 int ret = extractTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500647 return ret;
Dees_Troy83bd4832013-05-04 12:39:56 +0000648 } else if (Archive_Current_Type == 2) {
649 string Password;
650 DataManager::GetValue("tw_restore_password", Password);
651 int ret = TWFunc::Try_Decrypting_File(tarfn, Password);
652 if (ret < 1) {
653 LOGERR("Failed to decrypt tar file '%s'\n", tarfn.c_str());
654 return -1;
655 }
656 if (ret == 1) {
657 LOGERR("Decrypted file is not in tar format.\n");
658 return -1;
659 }
660 if (ret == 3) {
661 LOGINFO("Extracting encrypted and compressed tar.\n");
662 Archive_Current_Type = 3;
663 } else
664 LOGINFO("Extracting encrypted tar.\n");
665 return extractTar();
666 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000667 LOGINFO("Extracting uncompressed tar\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500668 return extractTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500669 }
670}
671
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500672int twrpTar::tarDirs(bool include_root) {
Dees_Troye34c1332013-02-06 19:13:00 +0000673 DIR* d;
674 string mainfolder = tardir + "/", subfolder;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400675 string tarsplit;
Dees_Troy59df9262013-06-19 14:53:57 -0500676 char buf[PATH_MAX], charTarPath[PATH_MAX];
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400677 string excl;
Dees_Troy83bd4832013-05-04 12:39:56 +0000678 string::size_type i;
679 bool skip;
680
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400681 //set exclude directories for libtar
682 for (int i = 0; i < tarexclude.size(); ++i) {
683 excl += tarexclude.at(i);
684 tarsplit = tarexclude.at(i);
685 excl += " ";
686 tarsplit += " ";
687 }
Dees_Troye34c1332013-02-06 19:13:00 +0000688 d = opendir(tardir.c_str());
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400689 if (d != NULL) {
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400690 if (!tarsplit.empty()) {
691 split = TWFunc::split_string(tarsplit, ' ', true);
Dees_Troy83bd4832013-05-04 12:39:56 +0000692 }
Dees_Troye34c1332013-02-06 19:13:00 +0000693 struct dirent* de;
694 while ((de = readdir(d)) != NULL) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500695#ifdef RECOVERY_SDCARD_ON_DATA
Dees_Troye34c1332013-02-06 19:13:00 +0000696 if ((tardir == "/data" || tardir == "/data/") && strcmp(de->d_name, "media") == 0) continue;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500697#endif
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400698 if (de->d_type == DT_BLK || de->d_type == DT_CHR || strcmp(de->d_name, "..") == 0 || strcmp(de->d_name, "lost+found") == 0)
Dees_Troy3263e922013-03-15 11:42:57 -0500699 continue;
Dees_Troy83bd4832013-05-04 12:39:56 +0000700
701 // Skip excluded stuff
702 if (split.size() > 0) {
703 skip = false;
704 for (i = 0; i < split.size(); i++) {
705 if (strcmp(de->d_name, split[i].c_str()) == 0) {
706 LOGINFO("excluding %s\n", de->d_name);
707 skip = true;
708 break;
709 }
710 }
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400711 if (skip) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000712 continue;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400713 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000714 }
715
Dees_Troye34c1332013-02-06 19:13:00 +0000716 subfolder = mainfolder;
Dees_Troy3263e922013-03-15 11:42:57 -0500717 if (strcmp(de->d_name, ".") != 0) {
718 subfolder += de->d_name;
719 } else {
Dees_Troy59df9262013-06-19 14:53:57 -0500720 LOGINFO("addFile '%s' including root: %i\n", buf, include_root);
Dees_Troy3263e922013-03-15 11:42:57 -0500721 if (addFile(subfolder, include_root) != 0)
722 return -1;
723 continue;
724 }
Dees_Troye34c1332013-02-06 19:13:00 +0000725 strcpy(buf, subfolder.c_str());
726 if (de->d_type == DT_DIR) {
Dees_Troy3263e922013-03-15 11:42:57 -0500727 if (include_root) {
Dees_Troy59df9262013-06-19 14:53:57 -0500728 charTarPath[0] = NULL;
729 LOGINFO("tar_append_tree '%s' as NULL\n", buf, charTarPath);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400730 if (tar_append_tree(t, buf, NULL, &excl[0]) != 0) {
Dees_Troy59df9262013-06-19 14:53:57 -0500731 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
732 return -1;
733 }
Dees_Troy3263e922013-03-15 11:42:57 -0500734 } else {
735 string temp = Strip_Root_Dir(buf);
Dees_Troy59df9262013-06-19 14:53:57 -0500736 strcpy(charTarPath, temp.c_str());
737 LOGINFO("tar_append_tree '%s' as '%s'\n", buf, charTarPath);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400738 if (tar_append_tree(t, buf, charTarPath, &excl[0]) != 0) {
Dees_Troy59df9262013-06-19 14:53:57 -0500739 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
740 return -1;
741 }
Dees_Troye34c1332013-02-06 19:13:00 +0000742 }
Dees_Troye34c1332013-02-06 19:13:00 +0000743 } else if (tardir != "/" && (de->d_type == DT_REG || de->d_type == DT_LNK)) {
Dees_Troy59df9262013-06-19 14:53:57 -0500744 LOGINFO("addFile '%s' including root: %i\n", buf, include_root);
Dees_Troy3263e922013-03-15 11:42:57 -0500745 if (addFile(buf, include_root) != 0)
746 return -1;
747 }
Dees_Troye34c1332013-02-06 19:13:00 +0000748 fflush(NULL);
749 }
750 closedir(d);
751 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500752 return 0;
753}
754
Dees_Troy83bd4832013-05-04 12:39:56 +0000755int twrpTar::tarList(bool include_root, std::vector<TarListStruct> *TarList, unsigned thread_id) {
756 struct stat st;
757 char buf[PATH_MAX];
758 int list_size = TarList->size(), i = 0, archive_count = 0;
759 string temp;
760 char actual_filename[PATH_MAX];
Dees_Troye34c1332013-02-06 19:13:00 +0000761
Dees_Troy83bd4832013-05-04 12:39:56 +0000762 basefn = tarfn;
763 temp = basefn + "%i%02i";
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 while (i < list_size) {
773 if (TarList->at(i).thread_id == thread_id) {
774 strcpy(buf, TarList->at(i).fn.c_str());
775 stat(buf, &st);
776 if (st.st_mode & S_IFREG) { // item is a regular file
777 if (Archive_Current_Size + (unsigned long long)(st.st_size) > MAX_ARCHIVE_SIZE) {
778 if (closeTar() != 0) {
779 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
780 return -3;
781 }
782 archive_count++;
783 LOGINFO("Splitting thread ID %i into archive %i\n", thread_id, archive_count);
784 if (archive_count > 99) {
785 LOGINFO("BLAH!\n");
786 LOGERR("Too many archives for thread %i\n", thread_id);
787 return -4;
788 }
789 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
790 tarfn = actual_filename;
791 if (createTar() != 0) {
792 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
793 return -2;
794 }
795 Archive_Current_Size = 0;
796 }
797 Archive_Current_Size += (unsigned long long)(st.st_size);
798 }
799 if (addFile(buf, include_root) != 0) {
800 LOGERR("Error adding file '%s' to '%s'\n", buf, tarfn.c_str());
801 return -1;
802 }
803 }
804 i++;
805 }
806 if (closeTar() != 0) {
807 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
808 return -3;
809 }
810 LOGINFO("Thread id %i tarList done, %i archives.\n", thread_id, archive_count, i, list_size);
Dees_Troye34c1332013-02-06 19:13:00 +0000811 return 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500812}
813
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500814int twrpTar::create() {
Dees_Troye34c1332013-02-06 19:13:00 +0000815
816 init_libtar_buffer(0);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500817 if (createTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500818 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500819 if (tarDirs(false) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500820 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000821 if (closeTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500822 return -1;
Dees_Troye34c1332013-02-06 19:13:00 +0000823 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500824 return 0;
825}
826
Dees_Troy83bd4832013-05-04 12:39:56 +0000827void* twrpTar::createList(void *cookie) {
828
829 twrpTar* threadTar = (twrpTar*) cookie;
830 if (threadTar->tarList(true, threadTar->ItemList, threadTar->thread_id) == -1) {
831 LOGINFO("ERROR tarList for thread ID %i\n", threadTar->thread_id);
832 return (void*)-2;
833 }
834 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
835 return (void*)0;
836}
837
838void* twrpTar::extractMulti(void *cookie) {
839
840 twrpTar* threadTar = (twrpTar*) cookie;
841 int archive_count = 0;
842 string temp = threadTar->basefn + "%i%02i";
843 char actual_filename[255];
844 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
845 while (TWFunc::Path_Exists(actual_filename)) {
846 threadTar->tarfn = actual_filename;
847 if (threadTar->extract() != 0) {
848 LOGINFO("Error extracting '%s' in thread ID %i\n", actual_filename, threadTar->thread_id);
849 return (void*)-2;
850 }
851 archive_count++;
852 if (archive_count > 99)
853 break;
854 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
855 }
856 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
857 return (void*)0;
858}
859
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500860int twrpTar::addFilesToExistingTar(vector <string> files, string fn) {
861 char* charTarFile = (char*) fn.c_str();
862
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200863 if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500864 return -1;
865 removeEOT(charTarFile);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200866 if (tar_open(&t, charTarFile, NULL, O_WRONLY | O_APPEND | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500867 return -1;
868 for (unsigned int i = 0; i < files.size(); ++i) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500869 char* file = (char*) files.at(i).c_str();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500870 if (tar_append_file(t, file, file) == -1)
871 return -1;
872 }
873 if (tar_append_eof(t) == -1)
874 return -1;
875 if (tar_close(t) == -1)
876 return -1;
877 return 0;
878}
879
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500880int twrpTar::createTar() {
881 char* charTarFile = (char*) tarfn.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000882 char* charRootDir = (char*) tardir.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000883 static tartype_t type = { open, close, read, write_tar };
Dees_Troy83bd4832013-05-04 12:39:56 +0000884 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500885
Dees_Troy83bd4832013-05-04 12:39:56 +0000886 if (use_encryption && use_compression) {
887 // Compressed and encrypted
888 Archive_Current_Type = 3;
889 LOGINFO("Using encryption and compression...\n");
890 DataManager::GetValue("tw_backup_password", Password);
891 int i, pipes[4];
892
893 if (pipe(pipes) < 0) {
894 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500895 return -1;
896 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000897 if (pipe(pipes + 2) < 0) {
898 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500899 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000900 }
901 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400902
Dees_Troy83bd4832013-05-04 12:39:56 +0000903 if (pigz_pid < 0) {
904 LOGERR("pigz fork() failed\n");
905 for (i = 0; i < 4; i++)
906 close(pipes[i]); // close all
907 return -1;
908 } else if (pigz_pid == 0) {
909 // pigz Child
910 close(pipes[1]);
911 close(pipes[2]);
912 close(0);
913 dup2(pipes[0], 0);
914 close(1);
915 dup2(pipes[3], 1);
916 if (execlp("pigz", "pigz", "-", NULL) < 0) {
917 LOGERR("execlp pigz ERROR!\n");
918 close(pipes[0]);
919 close(pipes[3]);
920 _exit(-1);
921 }
922 } else {
923 // Parent
924 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400925
Dees_Troy83bd4832013-05-04 12:39:56 +0000926 if (oaes_pid < 0) {
927 LOGERR("openaes fork() failed\n");
928 for (i = 0; i < 4; i++)
929 close(pipes[i]); // close all
930 return -1;
931 } else if (oaes_pid == 0) {
932 // openaes Child
Dees_Troy5612cc82013-07-24 19:45:58 +0000933 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 +0000934 if (output_fd < 0) {
935 LOGERR("Failed to open '%s'\n", tarfn.c_str());
936 for (i = 0; i < 4; i++)
937 close(pipes[i]); // close all
938 return -1;
939 }
940 close(pipes[0]);
941 close(pipes[1]);
942 close(pipes[3]);
943 close(0);
944 dup2(pipes[2], 0);
945 close(1);
946 dup2(output_fd, 1);
947 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
948 LOGERR("execlp openaes ERROR!\n");
949 close(pipes[2]);
950 close(output_fd);
951 _exit(-1);
952 }
953 } else {
954 // Parent
955 close(pipes[0]);
956 close(pipes[2]);
957 close(pipes[3]);
958 fd = pipes[1];
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200959 if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000960 close(fd);
961 LOGERR("tar_fdopen failed\n");
962 return -1;
963 }
964 return 0;
965 }
966 }
967 } else if (use_compression) {
968 // Compressed
969 Archive_Current_Type = 1;
970 LOGINFO("Using compression...\n");
971 int pigzfd[2];
972
973 if (pipe(pigzfd) < 0) {
974 LOGERR("Error creating pipe\n");
975 return -1;
976 }
977 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400978
Dees_Troy83bd4832013-05-04 12:39:56 +0000979 if (pigz_pid < 0) {
980 LOGERR("fork() failed\n");
981 close(pigzfd[0]);
982 close(pigzfd[1]);
983 return -1;
984 } else if (pigz_pid == 0) {
985 // Child
986 close(pigzfd[1]); // close unused output pipe
Dees_Troy5612cc82013-07-24 19:45:58 +0000987 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 +0000988 if (output_fd < 0) {
989 LOGERR("Failed to open '%s'\n", tarfn.c_str());
990 close(pigzfd[0]);
991 _exit(-1);
992 }
993 dup2(pigzfd[0], 0); // remap stdin
994 dup2(output_fd, 1); // remap stdout to output file
995 if (execlp("pigz", "pigz", "-", NULL) < 0) {
996 LOGERR("execlp pigz ERROR!\n");
997 close(output_fd);
998 close(pigzfd[0]);
999 _exit(-1);
1000 }
1001 } else {
1002 // Parent
1003 close(pigzfd[0]); // close parent input
1004 fd = pigzfd[1]; // copy parent output
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001005 if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001006 close(fd);
1007 LOGERR("tar_fdopen failed\n");
1008 return -1;
1009 }
1010 }
1011 } else if (use_encryption) {
1012 // Encrypted
1013 Archive_Current_Type = 2;
1014 LOGINFO("Using encryption...\n");
1015 DataManager::GetValue("tw_backup_password", Password);
1016 int oaesfd[2];
1017 pipe(oaesfd);
1018 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001019
Dees_Troy83bd4832013-05-04 12:39:56 +00001020 if (oaes_pid < 0) {
1021 LOGERR("fork() failed\n");
1022 close(oaesfd[0]);
1023 close(oaesfd[1]);
1024 return -1;
1025 } else if (oaes_pid == 0) {
1026 // Child
1027 close(oaesfd[1]); // close unused
Dees_Troy5612cc82013-07-24 19:45:58 +00001028 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 +00001029 if (output_fd < 0) {
1030 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1031 _exit(-1);
1032 }
1033 dup2(oaesfd[0], 0); // remap stdin
1034 dup2(output_fd, 1); // remap stdout to output file
1035 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
1036 LOGERR("execlp openaes ERROR!\n");
1037 close(output_fd);
1038 close(oaesfd[0]);
1039 _exit(-1);
1040 }
1041 } else {
1042 // Parent
1043 close(oaesfd[0]); // close parent input
1044 fd = oaesfd[1]; // copy parent output
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001045 if(tar_fdopen(&t, fd, charRootDir, NULL, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001046 close(fd);
1047 LOGERR("tar_fdopen failed\n");
1048 return -1;
1049 }
1050 return 0;
1051 }
1052 } else {
1053 // Not compressed or encrypted
1054 init_libtar_buffer(0);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001055 if (tar_open(&t, charTarFile, &type, O_WRONLY | O_CREAT | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) == -1) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001056 LOGERR("tar_open error opening '%s'\n", tarfn.c_str());
1057 return -1;
1058 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001059 }
1060 return 0;
1061}
1062
Dees_Troy83bd4832013-05-04 12:39:56 +00001063int twrpTar::openTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001064 char* charRootDir = (char*) tardir.c_str();
1065 char* charTarFile = (char*) tarfn.c_str();
Dees_Troy83bd4832013-05-04 12:39:56 +00001066 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001067
Dees_Troy83bd4832013-05-04 12:39:56 +00001068 if (Archive_Current_Type == 3) {
1069 LOGINFO("Opening encrypted and compressed backup...\n");
1070 DataManager::GetValue("tw_restore_password", Password);
1071 int i, pipes[4];
1072
1073 if (pipe(pipes) < 0) {
1074 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001075 return -1;
1076 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001077 if (pipe(pipes + 2) < 0) {
1078 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001079 return -1;
1080 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001081 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001082
Dees_Troy83bd4832013-05-04 12:39:56 +00001083 if (oaes_pid < 0) {
1084 LOGERR("pigz fork() failed\n");
1085 for (i = 0; i < 4; i++)
1086 close(pipes[i]); // close all
1087 return -1;
1088 } else if (oaes_pid == 0) {
1089 // openaes Child
1090 close(pipes[0]); // Close pipes that are not used by this child
1091 close(pipes[2]);
1092 close(pipes[3]);
1093 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1094 if (input_fd < 0) {
1095 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1096 close(pipes[1]);
1097 _exit(-1);
1098 }
1099 close(0);
1100 dup2(input_fd, 0);
1101 close(1);
1102 dup2(pipes[1], 1);
1103 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1104 LOGERR("execlp openaes ERROR!\n");
1105 close(input_fd);
1106 close(pipes[1]);
1107 _exit(-1);
1108 }
1109 } else {
1110 // Parent
1111 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001112
Dees_Troy83bd4832013-05-04 12:39:56 +00001113 if (pigz_pid < 0) {
1114 LOGERR("openaes fork() failed\n");
1115 for (i = 0; i < 4; i++)
1116 close(pipes[i]); // close all
1117 return -1;
1118 } else if (pigz_pid == 0) {
1119 // pigz Child
1120 close(pipes[1]); // Close pipes not used by this child
1121 close(pipes[2]);
1122 close(0);
1123 dup2(pipes[0], 0);
1124 close(1);
1125 dup2(pipes[3], 1);
1126 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1127 LOGERR("execlp pigz ERROR!\n");
1128 close(pipes[0]);
1129 close(pipes[3]);
1130 _exit(-1);
1131 }
1132 } else {
1133 // Parent
1134 close(pipes[0]); // Close pipes not used by parent
1135 close(pipes[1]);
1136 close(pipes[3]);
1137 fd = pipes[2];
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001138 if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001139 close(fd);
1140 LOGERR("tar_fdopen failed\n");
1141 return -1;
1142 }
1143 }
1144 }
1145 } else if (Archive_Current_Type == 2) {
1146 LOGINFO("Opening encrypted backup...\n");
1147 DataManager::GetValue("tw_restore_password", Password);
1148 int oaesfd[2];
1149
1150 pipe(oaesfd);
1151 oaes_pid = fork();
1152 if (oaes_pid < 0) {
1153 LOGERR("fork() failed\n");
1154 close(oaesfd[0]);
1155 close(oaesfd[1]);
1156 return -1;
1157 } else if (oaes_pid == 0) {
1158 // Child
1159 close(oaesfd[0]); // Close unused pipe
1160 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1161 if (input_fd < 0) {
1162 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1163 close(oaesfd[1]);
1164 _exit(-1);
1165 }
1166 close(0); // close stdin
1167 dup2(oaesfd[1], 1); // remap stdout
1168 dup2(input_fd, 0); // remap input fd to stdin
1169 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1170 LOGERR("execlp openaes ERROR!\n");
1171 close(input_fd);
1172 close(oaesfd[1]);
1173 _exit(-1);
1174 }
1175 } else {
1176 // Parent
1177 close(oaesfd[1]); // close parent output
1178 fd = oaesfd[0]; // copy parent input
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001179 if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001180 close(fd);
1181 LOGERR("tar_fdopen failed\n");
1182 return -1;
1183 }
1184 }
1185 } else if (Archive_Current_Type == 1) {
1186 LOGINFO("Opening as a gzip...\n");
1187 int pigzfd[2];
1188 pipe(pigzfd);
1189
1190 pigz_pid = fork();
1191 if (pigz_pid < 0) {
1192 LOGERR("fork() failed\n");
1193 close(pigzfd[0]);
1194 close(pigzfd[1]);
1195 return -1;
1196 } else if (pigz_pid == 0) {
1197 // Child
1198 close(pigzfd[0]);
1199 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1200 if (input_fd < 0) {
1201 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1202 _exit(-1);
1203 }
1204 dup2(input_fd, 0); // remap input fd to stdin
1205 dup2(pigzfd[1], 1); // remap stdout
1206 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1207 close(pigzfd[1]);
1208 close(input_fd);
1209 LOGERR("execlp openaes ERROR!\n");
1210 _exit(-1);
1211 }
1212 } else {
1213 // Parent
1214 close(pigzfd[1]); // close parent output
1215 fd = pigzfd[0]; // copy parent input
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001216 if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001217 close(fd);
1218 LOGERR("tar_fdopen failed\n");
1219 return -1;
1220 }
1221 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001222 } else if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, TAR_GNU | TAR_STORE_SELINUX) != 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +00001223 LOGERR("Unable to open tar archive '%s'\n", charTarFile);
1224 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001225 }
1226 return 0;
1227}
1228
1229string twrpTar::Strip_Root_Dir(string Path) {
1230 string temp;
1231 size_t slash;
1232
1233 if (Path.substr(0, 1) == "/")
1234 temp = Path.substr(1, Path.size() - 1);
1235 else
1236 temp = Path;
1237 slash = temp.find("/");
1238 if (slash == string::npos)
1239 return temp;
1240 else {
1241 string stripped;
1242
1243 stripped = temp.substr(slash, temp.size() - slash);
1244 return stripped;
1245 }
1246 return temp;
1247}
1248
1249int twrpTar::addFile(string fn, bool include_root) {
1250 char* charTarFile = (char*) fn.c_str();
1251 if (include_root) {
1252 if (tar_append_file(t, charTarFile, NULL) == -1)
1253 return -1;
1254 } else {
1255 string temp = Strip_Root_Dir(fn);
1256 char* charTarPath = (char*) temp.c_str();
1257 if (tar_append_file(t, charTarFile, charTarPath) == -1)
1258 return -1;
1259 }
1260 return 0;
1261}
1262
Dees_Troy83bd4832013-05-04 12:39:56 +00001263int twrpTar::closeTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001264 flush_libtar_buffer(t->fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001265 if (tar_append_eof(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001266 LOGERR("tar_append_eof(): %s\n", strerror(errno));
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001267 tar_close(t);
1268 return -1;
1269 }
1270 if (tar_close(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001271 LOGERR("Unable to close tar archive: '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001272 return -1;
1273 }
Dees_Troy2727b992013-08-14 20:09:30 +00001274 if (Archive_Current_Type > 0) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001275 close(fd);
Dees_Troy83bd4832013-05-04 12:39:56 +00001276 int status;
1277 if (pigz_pid > 0 && TWFunc::Wait_For_Child(pigz_pid, &status, "pigz") != 0)
1278 return -1;
1279 if (oaes_pid > 0 && TWFunc::Wait_For_Child(oaes_pid, &status, "openaes") != 0)
1280 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001281 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001282 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001283 return 0;
1284}
1285
1286int twrpTar::removeEOT(string tarFile) {
1287 char* charTarFile = (char*) tarFile.c_str();
1288 off_t tarFileEnd;
1289 while (th_read(t) == 0) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001290 if (TH_ISREG(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001291 tar_skip_regfile(t);
1292 tarFileEnd = lseek(t->fd, 0, SEEK_CUR);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001293 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001294 if (tar_close(t) == -1)
1295 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001296 if (truncate(charTarFile, tarFileEnd) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001297 return -1;
1298 return 0;
1299}
1300
n0d33b511632013-03-06 21:14:15 +02001301int twrpTar::entryExists(string entry) {
1302 char* searchstr = (char*)entry.c_str();
1303 int ret;
1304
Dees_Troy83bd4832013-05-04 12:39:56 +00001305 Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
n0d33b511632013-03-06 21:14:15 +02001306
Dees_Troy83bd4832013-05-04 12:39:56 +00001307 if (openTar() == -1)
n0d33b511632013-03-06 21:14:15 +02001308 ret = 0;
1309 else
1310 ret = tar_find(t, searchstr);
1311
Dees_Troy83bd4832013-05-04 12:39:56 +00001312 if (closeTar() != 0)
1313 LOGINFO("Unable to close tar after searching for entry.\n");
n0d33b511632013-03-06 21:14:15 +02001314
1315 return ret;
1316}
1317
Dees_Troy83bd4832013-05-04 12:39:56 +00001318unsigned long long twrpTar::uncompressedSize() {
1319 int type = 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001320 unsigned long long total_size = 0;
Dees_Troy83bd4832013-05-04 12:39:56 +00001321 string Tar, Command, result;
1322 vector<string> split;
1323
1324 Tar = TWFunc::Get_Filename(tarfn);
1325 type = TWFunc::Get_File_Type(tarfn);
1326 if (type == 0)
1327 total_size = TWFunc::Get_File_Size(tarfn);
1328 else {
1329 Command = "pigz -l " + tarfn;
1330 /* if we set Command = "pigz -l " + tarfn + " | sed '1d' | cut -f5 -d' '";
1331 we get the uncompressed size at once. */
1332 TWFunc::Exec_Cmd(Command, result);
1333 if (!result.empty()) {
1334 /* Expected output:
1335 compressed original reduced name
1336 95855838 179403776 -1.3% data.yaffs2.win
1337 ^
1338 split[5]
1339 */
1340 split = TWFunc::split_string(result, ' ', true);
1341 if (split.size() > 4)
1342 total_size = atoi(split[5].c_str());
1343 }
1344 }
1345 LOGINFO("%s's uncompressed size: %llu bytes\n", Tar.c_str(), total_size);
1346
1347 return total_size;
1348}
1349
Dees_Troye34c1332013-02-06 19:13:00 +00001350extern "C" ssize_t write_tar(int fd, const void *buffer, size_t size) {
1351 return (ssize_t) write_libtar_buffer(fd, buffer, size);
Dees_Troy40bbcf82013-02-12 15:01:53 +00001352}