blob: eba482ee734265b2bbcf459b6c560b49583566c5 [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>
bigbiff bigbiffc49d7062013-10-11 20:28:00 -040037#include <libgen.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050038#include <sys/mman.h>
39#include "twrpTar.hpp"
Dees_Troy2673cec2013-04-02 20:22:16 +000040#include "twcommon.h"
bigbiff bigbiff9c754052013-01-09 09:09:08 -050041#include "data.hpp"
42#include "variables.h"
bigbiff bigbiff9c754052013-01-09 09:09:08 -050043#include "twrp-functions.hpp"
44
45using namespace std;
46
Dees_Troy83bd4832013-05-04 12:39:56 +000047twrpTar::twrpTar(void) {
48 use_encryption = 0;
49 userdata_encryption = 0;
50 use_compression = 0;
51 split_archives = 0;
52 has_data_media = 0;
53 pigz_pid = 0;
54 oaes_pid = 0;
55}
56
57twrpTar::~twrpTar(void) {
58 // Do nothing
59}
60
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050061void twrpTar::setfn(string fn) {
62 tarfn = fn;
63}
64
65void twrpTar::setdir(string dir) {
66 tardir = dir;
67}
68
Dees_Troy83bd4832013-05-04 12:39:56 +000069void twrpTar::setexcl(string exclude) {
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -040070 tarexclude.push_back(exclude);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050071}
72
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -050073int twrpTar::createTarFork() {
Dees_Troy83bd4832013-05-04 12:39:56 +000074 int status = 0;
75 pid_t pid, rc_pid;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -050076 if ((pid = fork()) == -1) {
Dees_Troy2673cec2013-04-02 20:22:16 +000077 LOGINFO("create tar failed to fork.\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -050078 return -1;
79 }
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -050080 if (pid == 0) {
Dees_Troy83bd4832013-05-04 12:39:56 +000081 // Child process
82 if (use_encryption || userdata_encryption) {
83 LOGINFO("Using encryption\n");
84 DIR* d;
85 struct dirent* de;
86 unsigned long long regular_size = 0, encrypt_size = 0, target_size = 0, core_count = 1;
87 unsigned enc_thread_id = 1, regular_thread_id = 0, i, start_thread_id = 1;
88 int item_len, ret, thread_error = 0;
89 std::vector<TarListStruct> RegularList;
90 std::vector<TarListStruct> EncryptList;
91 string FileName;
92 struct TarListStruct TarItem;
93 twrpTar reg, enc[9];
94 struct stat st;
95 pthread_t enc_thread[9];
96 pthread_attr_t tattr;
97 void *thread_return;
98
99 core_count = sysconf(_SC_NPROCESSORS_CONF);
100 if (core_count > 8)
101 core_count = 8;
102 LOGINFO(" Core Count : %llu\n", core_count);
103 Archive_Current_Size = 0;
104
105 d = opendir(tardir.c_str());
106 if (d == NULL) {
107 LOGERR("error opening '%s'\n", tardir.c_str());
108 _exit(-1);
109 }
110 // Figure out the size of all data to be encrypted and create a list of unencrypted files
111 while ((de = readdir(d)) != NULL) {
112 FileName = tardir + "/";
113 FileName += de->d_name;
114 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
115 continue; // Skip /data/media
116 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
117 continue;
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400118 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 +0000119 item_len = strlen(de->d_name);
120 if (userdata_encryption && ((item_len >= 3 && strncmp(de->d_name, "app", 3) == 0) || (item_len >= 6 && strncmp(de->d_name, "dalvik", 6) == 0))) {
121 if (Generate_TarList(FileName, &RegularList, &target_size, &regular_thread_id) < 0) {
122 LOGERR("Error in Generate_TarList with regular list!\n");
123 closedir(d);
124 _exit(-1);
125 }
126 regular_size += TWFunc::Get_Folder_Size(FileName, false);
127 } else {
128 encrypt_size += TWFunc::Get_Folder_Size(FileName, false);
129 }
130 } else if (de->d_type == DT_REG) {
131 stat(FileName.c_str(), &st);
132 encrypt_size += (unsigned long long)(st.st_size);
133 }
134 }
135 closedir(d);
136
137 target_size = encrypt_size / core_count;
138 target_size++;
139 LOGINFO(" Unencrypted size: %llu\n", regular_size);
140 LOGINFO(" Encrypted size : %llu\n", encrypt_size);
141 LOGINFO(" Target size : %llu\n", target_size);
142 if (!userdata_encryption) {
143 enc_thread_id = 0;
144 start_thread_id = 0;
145 core_count--;
146 }
147 Archive_Current_Size = 0;
148
149 d = opendir(tardir.c_str());
150 if (d == NULL) {
151 LOGERR("error opening '%s'\n", tardir.c_str());
152 _exit(-1);
153 }
154 // Divide up the encrypted file list for threading
155 while ((de = readdir(d)) != NULL) {
156 FileName = tardir + "/";
157 FileName += de->d_name;
158 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
159 continue; // Skip /data/media
160 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
161 continue;
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400162 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 +0000163 item_len = strlen(de->d_name);
164 if (userdata_encryption && ((item_len >= 3 && strncmp(de->d_name, "app", 3) == 0) || (item_len >= 6 && strncmp(de->d_name, "dalvik", 6) == 0))) {
165 // Do nothing, we added these to RegularList earlier
166 } else {
167 FileName = tardir + "/";
168 FileName += de->d_name;
169 if (Generate_TarList(FileName, &EncryptList, &target_size, &enc_thread_id) < 0) {
170 LOGERR("Error in Generate_TarList with encrypted list!\n");
171 closedir(d);
172 _exit(-1);
173 }
174 }
175 } else if (de->d_type == DT_REG || de->d_type == DT_LNK) {
176 stat(FileName.c_str(), &st);
177 if (de->d_type == DT_REG)
178 Archive_Current_Size += (unsigned long long)(st.st_size);
179 TarItem.fn = FileName;
180 TarItem.thread_id = enc_thread_id;
181 EncryptList.push_back(TarItem);
182 }
183 }
184 closedir(d);
185 if (enc_thread_id != core_count) {
186 LOGERR("Error dividing up threads for encryption, %i threads for %i cores!\n", enc_thread_id, core_count);
187 if (enc_thread_id > core_count)
188 _exit(-1);
189 else
190 LOGERR("Continuining anyway.");
191 }
192
193 if (userdata_encryption) {
194 // Create a backup of unencrypted data
195 reg.setfn(tarfn);
196 reg.ItemList = &RegularList;
197 reg.thread_id = 0;
198 reg.use_encryption = 0;
199 reg.use_compression = use_compression;
200 LOGINFO("Creating unencrypted backup...\n");
201 if (createList((void*)&reg) != 0) {
202 LOGERR("Error creating unencrypted backup.\n");
203 _exit(-1);
204 }
205 }
206
207 if (pthread_attr_init(&tattr)) {
208 LOGERR("Unable to pthread_attr_init\n");
209 _exit(-1);
210 }
211 if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
212 LOGERR("Error setting pthread_attr_setdetachstate\n");
213 _exit(-1);
214 }
215 if (pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM)) {
216 LOGERR("Error setting pthread_attr_setscope\n");
217 _exit(-1);
218 }
219 /*if (pthread_attr_setstacksize(&tattr, 524288)) {
220 LOGERR("Error setting pthread_attr_setstacksize\n");
221 _exit(-1);
222 }*/
223
224 // Create threads for the divided up encryption lists
225 for (i = start_thread_id; i <= core_count; i++) {
226 enc[i].setdir(tardir);
227 enc[i].setfn(tarfn);
228 enc[i].ItemList = &EncryptList;
229 enc[i].thread_id = i;
230 enc[i].use_encryption = use_encryption;
231 enc[i].use_compression = use_compression;
232 LOGINFO("Start encryption thread %i\n", i);
233 ret = pthread_create(&enc_thread[i], &tattr, createList, (void*)&enc[i]);
234 if (ret) {
235 LOGINFO("Unable to create %i thread for encryption! %i\nContinuing in same thread (backup will be slower).", i, ret);
236 if (createList((void*)&enc[i]) != 0) {
237 LOGERR("Error creating encrypted backup %i.\n", i);
238 _exit(-1);
239 } else {
240 enc[i].thread_id = i + 1;
241 }
242 }
243 usleep(100000); // Need a short delay before starting the next thread or the threads will never finish for some reason.
244 }
245 if (pthread_attr_destroy(&tattr)) {
246 LOGERR("Failed to pthread_attr_destroy\n");
247 }
248 for (i = start_thread_id; i <= core_count; i++) {
249 if (enc[i].thread_id == i) {
250 if (pthread_join(enc_thread[i], &thread_return)) {
251 LOGERR("Error joining thread %i\n", i);
252 _exit(-1);
253 } else {
254 LOGINFO("Joined thread %i.\n", i);
255 ret = (int)thread_return;
256 if (ret != 0) {
257 thread_error = 1;
258 LOGERR("Thread %i returned an error %i.\n", i, ret);
259 _exit(-1);
260 }
261 }
262 } else {
263 LOGINFO("Skipping joining thread %i because of pthread failure.\n", i);
264 }
265 }
266 if (thread_error) {
267 LOGERR("Error returned by one or more threads.\n");
268 _exit(-1);
269 }
270 LOGINFO("Finished encrypted backup.\n");
271 _exit(0);
272 } else {
273 if (create() != 0)
274 _exit(-1);
275 else
276 _exit(0);
277 }
278 } else {
279 if (TWFunc::Wait_For_Child(pid, &status, "createTarFork()") != 0)
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500280 return -1;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500281 }
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500282 return 0;
283}
284
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500285int twrpTar::extractTarFork() {
Dees_Troy83bd4832013-05-04 12:39:56 +0000286 int status = 0;
287 pid_t pid, rc_pid;
288
289 pid = fork();
290 if (pid >= 0) // fork was successful
291 {
292 if (pid == 0) // child process
293 {
294 if (TWFunc::Path_Exists(tarfn)) {
295 LOGINFO("Single archive\n");
296 if (extract() != 0)
297 _exit(-1);
298 else
299 _exit(0);
300 } else {
301 LOGINFO("Multiple archives\n");
302 string temp;
303 char actual_filename[255];
304 twrpTar tars[9];
305 pthread_t tar_thread[9];
306 pthread_attr_t tattr;
307 int thread_count = 0, i, start_thread_id = 1, ret, thread_error = 0;
308 void *thread_return;
309
310 basefn = tarfn;
311 temp = basefn + "%i%02i";
312 tarfn += "000";
313 if (!TWFunc::Path_Exists(tarfn)) {
314 LOGERR("Unable to locate '%s' or '%s'\n", basefn.c_str(), tarfn.c_str());
315 _exit(-1);
316 }
317 if (TWFunc::Get_File_Type(tarfn) != 2) {
318 LOGINFO("First tar file '%s' not encrypted\n", tarfn.c_str());
319 tars[0].basefn = basefn;
320 tars[0].thread_id = 0;
321 if (extractMulti((void*)&tars[0]) != 0) {
322 LOGERR("Error extracting split archive.\n");
323 _exit(-1);
324 }
325 } else {
326 start_thread_id = 0;
327 }
328 // Start threading encrypted restores
329 if (pthread_attr_init(&tattr)) {
330 LOGERR("Unable to pthread_attr_init\n");
331 _exit(-1);
332 }
333 if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
334 LOGERR("Error setting pthread_attr_setdetachstate\n");
335 _exit(-1);
336 }
337 if (pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM)) {
338 LOGERR("Error setting pthread_attr_setscope\n");
339 _exit(-1);
340 }
341 /*if (pthread_attr_setstacksize(&tattr, 524288)) {
342 LOGERR("Error setting pthread_attr_setstacksize\n");
343 _exit(-1);
344 }*/
345 for (i = start_thread_id; i < 9; i++) {
346 sprintf(actual_filename, temp.c_str(), i, 0);
347 if (TWFunc::Path_Exists(actual_filename)) {
348 thread_count++;
349 tars[i].basefn = basefn;
350 tars[i].thread_id = i;
351 LOGINFO("Creating extract thread ID %i\n", i);
352 ret = pthread_create(&tar_thread[i], &tattr, extractMulti, (void*)&tars[i]);
353 if (ret) {
354 LOGINFO("Unable to create %i thread for extraction! %i\nContinuing in same thread (restore will be slower).", i, ret);
355 if (extractMulti((void*)&tars[i]) != 0) {
356 LOGERR("Error extracting backup in thread %i.\n", i);
357 _exit(-1);
358 } else {
359 tars[i].thread_id = i + 1;
360 }
361 }
362 usleep(100000); // Need a short delay before starting the next thread or the threads will never finish for some reason.
363 } else {
364 break;
365 }
366 }
367 for (i = start_thread_id; i < thread_count + start_thread_id; i++) {
368 if (tars[i].thread_id == i) {
369 if (pthread_join(tar_thread[i], &thread_return)) {
370 LOGERR("Error joining thread %i\n", i);
371 _exit(-1);
372 } else {
373 LOGINFO("Joined thread %i.\n", i);
374 ret = (int)thread_return;
375 if (ret != 0) {
376 thread_error = 1;
377 LOGERR("Thread %i returned an error %i.\n", i, ret);
378 _exit(-1);
379 }
380 }
381 } else {
382 LOGINFO("Skipping joining thread %i because of pthread failure.\n", i);
383 }
384 }
385 if (thread_error) {
386 LOGERR("Error returned by one or more threads.\n");
387 _exit(-1);
388 }
389 LOGINFO("Finished encrypted backup.\n");
390 _exit(0);
391 }
392 }
393 else // parent process
394 {
395 if (TWFunc::Wait_For_Child(pid, &status, "extractTarFork()") != 0)
396 return -1;
397 }
398 }
399 else // fork has failed
400 {
Dees_Troy2673cec2013-04-02 20:22:16 +0000401 LOGINFO("extract tar failed to fork.\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500402 return -1;
403 }
404 return 0;
405}
406
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500407int twrpTar::splitArchiveFork() {
Dees_Troy83bd4832013-05-04 12:39:56 +0000408 int status = 0;
409 pid_t pid, rc_pid;
410
411 pid = fork();
412 if (pid >= 0) // fork was successful
413 {
414 if (pid == 0) // child process
415 {
416 if (Split_Archive() <= 0)
417 _exit(-1);
418 else
419 _exit(0);
420 }
421 else // parent process
422 {
423 if (TWFunc::Wait_For_Child(pid, &status, "splitArchiveFork()") != 0)
424 return -1;
425 }
426 }
427 else // fork has failed
428 {
429 LOGINFO("split archive failed to fork.\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500430 return -1;
431 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000432 return 0;
433}
434
435int twrpTar::Generate_TarList(string Path, std::vector<TarListStruct> *TarList, unsigned long long *Target_Size, unsigned *thread_id) {
436 DIR* d;
437 struct dirent* de;
438 struct stat st;
439 string FileName;
440 struct TarListStruct TarItem;
441 string::size_type i;
442 bool skip;
443
444 if (has_data_media == 1 && Path.size() >= 11 && strncmp(Path.c_str(), "/data/media", 11) == 0)
445 return 0; // Skip /data/media
446
447 d = opendir(Path.c_str());
448 if (d == NULL) {
449 LOGERR("error opening '%s' -- error: %s\n", Path.c_str(), strerror(errno));
450 closedir(d);
451 return -1;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500452 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000453 while ((de = readdir(d)) != NULL) {
454 // Skip excluded stuff
455 if (split.size() > 0) {
456 skip = false;
457 for (i = 0; i < split.size(); i++) {
458 if (strcmp(de->d_name, split[i].c_str()) == 0) {
459 LOGINFO("excluding %s\n", de->d_name);
460 skip = true;
461 break;
462 }
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500463 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000464 if (skip)
465 continue;
466 }
467 FileName = Path + "/";
468 FileName += de->d_name;
469 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
470 continue; // Skip /data/media
471 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
472 continue;
473 TarItem.fn = FileName;
474 TarItem.thread_id = *thread_id;
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400475 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 +0000476 TarList->push_back(TarItem);
477 if (Generate_TarList(FileName, TarList, Target_Size, thread_id) < 0)
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500478 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000479 } else if (de->d_type == DT_REG || de->d_type == DT_LNK) {
480 stat(FileName.c_str(), &st);
481 TarList->push_back(TarItem);
482 if (de->d_type == DT_REG)
483 Archive_Current_Size += st.st_size;
484 if (Archive_Current_Size != 0 && *Target_Size != 0 && Archive_Current_Size > *Target_Size) {
485 *thread_id = *thread_id + 1;
486 Archive_Current_Size = 0;
bigbiff bigbiffe6594ab2013-02-17 20:18:31 -0500487 }
488 }
489 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000490 closedir(d);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500491 return 0;
492}
493
494int twrpTar::Generate_Multiple_Archives(string Path) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500495 DIR* d;
496 struct dirent* de;
497 struct stat st;
498 string FileName;
499 char actual_filename[255];
500
Dees_Troy83bd4832013-05-04 12:39:56 +0000501 string::size_type i;
502 bool skip;
503
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500504 if (has_data_media == 1 && Path.size() >= 11 && strncmp(Path.c_str(), "/data/media", 11) == 0)
505 return 0; // Skip /data/media
Dees_Troy2673cec2013-04-02 20:22:16 +0000506 LOGINFO("Path: '%s', archive filename: '%s'\n", Path.c_str(), tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500507
508 d = opendir(Path.c_str());
509 if (d == NULL)
510 {
Dees_Troy2673cec2013-04-02 20:22:16 +0000511 LOGERR("error opening '%s' -- error: %s\n", Path.c_str(), strerror(errno));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500512 closedir(d);
513 return -1;
514 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000515 while ((de = readdir(d)) != NULL) {
516 // Skip excluded stuff
517 if (split.size() > 0) {
518 skip = false;
519 for (i = 0; i < split.size(); i++) {
520 if (strcmp(de->d_name, split[i].c_str()) == 0) {
521 LOGINFO("excluding %s\n", de->d_name);
522 skip = true;
523 break;
524 }
525 }
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400526 if (skip) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000527 continue;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400528 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000529 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500530 FileName = Path + "/";
531 FileName += de->d_name;
532 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
533 continue; // Skip /data/media
bigbiff bigbiff71e5aa42013-02-26 20:10:16 -0500534 if (de->d_type == DT_BLK || de->d_type == DT_CHR)
535 continue;
bigbiff bigbiffc49d7062013-10-11 20:28:00 -0400536 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500537 {
538 unsigned long long folder_size = TWFunc::Get_Folder_Size(FileName, false);
539 if (Archive_Current_Size + folder_size > MAX_ARCHIVE_SIZE) {
Dees Troyed400772013-10-09 14:45:24 +0000540 // Add the root folder first
541 LOGINFO("Adding root folder '%s' before splitting.\n", FileName.c_str());
542 if (addFile(FileName, true) != 0) {
543 LOGERR("Error adding folder '%s' to split archive.\n", FileName.c_str());
544 return -1;
545 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000546 LOGINFO("Calling Generate_Multiple_Archives\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500547 if (Generate_Multiple_Archives(FileName) < 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500548 return -1;
549 } else {
550 //FileName += "/";
Dees_Troy2673cec2013-04-02 20:22:16 +0000551 LOGINFO("Adding folder '%s'\n", FileName.c_str());
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500552 tardir = FileName;
553 if (tarDirs(true) < 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500554 return -1;
555 Archive_Current_Size += folder_size;
556 }
557 }
558 else if (de->d_type == DT_REG || de->d_type == DT_LNK)
559 {
560 stat(FileName.c_str(), &st);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400561 if (de->d_type != DT_LNK) {
562 if (Archive_Current_Size != 0 && Archive_Current_Size + st.st_size > MAX_ARCHIVE_SIZE) {
563 LOGINFO("Closing tar '%s', ", tarfn.c_str());
564 closeTar();
565 if (TWFunc::Get_File_Size(tarfn) == 0) {
566 LOGERR("Backup file size for '%s' is 0 bytes.\n", tarfn.c_str());
567 return -1;
568 }
569 Archive_File_Count++;
570 if (Archive_File_Count > 999) {
571 LOGERR("Archive count is too large!\n");
572 return -1;
573 }
574 string temp = basefn + "%03i";
575 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
576 tarfn = actual_filename;
577 Archive_Current_Size = 0;
578 LOGINFO("Creating tar '%s'\n", tarfn.c_str());
579 gui_print("Creating archive %i...\n", Archive_File_Count + 1);
580 if (createTar() != 0)
581 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500582 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500583 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000584 LOGINFO("Adding file: '%s'... ", FileName.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500585 if (addFile(FileName, true) < 0)
586 return -1;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400587 if (de->d_type != DT_LNK) {
588 Archive_Current_Size += st.st_size;
589 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000590 LOGINFO("added successfully, archive size: %llu\n", Archive_Current_Size);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400591 if (de->d_type != DT_LNK) {
592 if (st.st_size > 2147483648LL)
593 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());
594 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500595 }
596 }
597 closedir(d);
598 return 0;
599}
600
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500601int twrpTar::Split_Archive()
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500602{
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500603 string temp = tarfn + "%03i";
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500604 char actual_filename[255];
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400605 string tarsplit;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500606
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500607 basefn = tarfn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500608 Archive_File_Count = 0;
609 Archive_Current_Size = 0;
610 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500611 tarfn = actual_filename;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400612
613 for (int i = 0; i < tarexclude.size(); ++i) {
614 tarsplit = tarexclude[i];
615 tarsplit += " ";
616 }
617
Dees_Troy83bd4832013-05-04 12:39:56 +0000618 if (!tarexclude.empty())
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400619 split = TWFunc::split_string(tarsplit, ' ', true);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500620 createTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500621 DataManager::GetValue(TW_HAS_DATA_MEDIA, has_data_media);
Dees_Troy2673cec2013-04-02 20:22:16 +0000622 gui_print("Creating archive 1...\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500623 if (Generate_Multiple_Archives(tardir) < 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000624 LOGERR("Error generating multiple archives\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500625 return -1;
626 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000627 closeTar();
628 LOGINFO("Done, created %i archives.\n", (++Archive_File_Count));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500629 return (Archive_File_Count);
630}
631
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500632int twrpTar::extractTar() {
Dees_Troye34c1332013-02-06 19:13:00 +0000633 char* charRootDir = (char*) tardir.c_str();
Dees_Troy83bd4832013-05-04 12:39:56 +0000634 if (openTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500635 return -1;
636 if (tar_extract_all(t, charRootDir) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000637 LOGERR("Unable to extract tar archive '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500638 return -1;
639 }
640 if (tar_close(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000641 LOGERR("Unable to close tar file\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500642 return -1;
643 }
644 return 0;
645}
646
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500647int twrpTar::extract() {
Dees_Troy83bd4832013-05-04 12:39:56 +0000648 Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
n0d33b511632013-03-06 21:14:15 +0200649
650 if (Archive_Current_Type == 1) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500651 //if you return the extractTGZ function directly, stack crashes happen
Dees_Troy2673cec2013-04-02 20:22:16 +0000652 LOGINFO("Extracting gzipped tar\n");
Dees_Troy83bd4832013-05-04 12:39:56 +0000653 int ret = extractTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500654 return ret;
Dees_Troy83bd4832013-05-04 12:39:56 +0000655 } else if (Archive_Current_Type == 2) {
656 string Password;
657 DataManager::GetValue("tw_restore_password", Password);
658 int ret = TWFunc::Try_Decrypting_File(tarfn, Password);
659 if (ret < 1) {
660 LOGERR("Failed to decrypt tar file '%s'\n", tarfn.c_str());
661 return -1;
662 }
663 if (ret == 1) {
664 LOGERR("Decrypted file is not in tar format.\n");
665 return -1;
666 }
667 if (ret == 3) {
668 LOGINFO("Extracting encrypted and compressed tar.\n");
669 Archive_Current_Type = 3;
670 } else
671 LOGINFO("Extracting encrypted tar.\n");
672 return extractTar();
673 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000674 LOGINFO("Extracting uncompressed tar\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500675 return extractTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500676 }
677}
678
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500679int twrpTar::tarDirs(bool include_root) {
Dees_Troye34c1332013-02-06 19:13:00 +0000680 DIR* d;
681 string mainfolder = tardir + "/", subfolder;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400682 string tarsplit;
Dees_Troy59df9262013-06-19 14:53:57 -0500683 char buf[PATH_MAX], charTarPath[PATH_MAX];
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400684 string excl;
Dees_Troy83bd4832013-05-04 12:39:56 +0000685 string::size_type i;
686 bool skip;
687
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400688 //set exclude directories for libtar
689 for (int i = 0; i < tarexclude.size(); ++i) {
690 excl += tarexclude.at(i);
691 tarsplit = tarexclude.at(i);
692 excl += " ";
693 tarsplit += " ";
694 }
Dees_Troye34c1332013-02-06 19:13:00 +0000695 d = opendir(tardir.c_str());
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400696 if (d != NULL) {
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400697 if (!tarsplit.empty()) {
698 split = TWFunc::split_string(tarsplit, ' ', true);
Dees_Troy83bd4832013-05-04 12:39:56 +0000699 }
Dees_Troye34c1332013-02-06 19:13:00 +0000700 struct dirent* de;
701 while ((de = readdir(d)) != NULL) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500702#ifdef RECOVERY_SDCARD_ON_DATA
Dees_Troye34c1332013-02-06 19:13:00 +0000703 if ((tardir == "/data" || tardir == "/data/") && strcmp(de->d_name, "media") == 0) continue;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500704#endif
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400705 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 -0500706 continue;
Dees_Troy83bd4832013-05-04 12:39:56 +0000707
708 // Skip excluded stuff
709 if (split.size() > 0) {
710 skip = false;
711 for (i = 0; i < split.size(); i++) {
712 if (strcmp(de->d_name, split[i].c_str()) == 0) {
713 LOGINFO("excluding %s\n", de->d_name);
714 skip = true;
715 break;
716 }
717 }
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400718 if (skip) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000719 continue;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400720 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000721 }
722
Dees_Troye34c1332013-02-06 19:13:00 +0000723 subfolder = mainfolder;
Dees_Troy3263e922013-03-15 11:42:57 -0500724 if (strcmp(de->d_name, ".") != 0) {
725 subfolder += de->d_name;
726 } else {
bigbiff bigbiffc49d7062013-10-11 20:28:00 -0400727 std::string parentDir = basename(subfolder.c_str());
728 LOGINFO("parentDir: %s\n", parentDir.c_str());
729 if (!parentDir.compare("lost+found"))
730 continue;
Dees Troyed400772013-10-09 14:45:24 +0000731 LOGINFO("tarDirs addFile '%s' including root: %i\n", subfolder.c_str(), include_root);
Dees_Troy3263e922013-03-15 11:42:57 -0500732 if (addFile(subfolder, include_root) != 0)
733 return -1;
734 continue;
735 }
Dees_Troye34c1332013-02-06 19:13:00 +0000736 strcpy(buf, subfolder.c_str());
737 if (de->d_type == DT_DIR) {
Dees_Troy3263e922013-03-15 11:42:57 -0500738 if (include_root) {
Dees_Troy59df9262013-06-19 14:53:57 -0500739 charTarPath[0] = NULL;
740 LOGINFO("tar_append_tree '%s' as NULL\n", buf, charTarPath);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400741 if (tar_append_tree(t, buf, NULL, &excl[0]) != 0) {
Dees_Troy59df9262013-06-19 14:53:57 -0500742 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
743 return -1;
744 }
Dees_Troy3263e922013-03-15 11:42:57 -0500745 } else {
746 string temp = Strip_Root_Dir(buf);
Dees_Troy59df9262013-06-19 14:53:57 -0500747 strcpy(charTarPath, temp.c_str());
748 LOGINFO("tar_append_tree '%s' as '%s'\n", buf, charTarPath);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400749 if (tar_append_tree(t, buf, charTarPath, &excl[0]) != 0) {
Dees_Troy59df9262013-06-19 14:53:57 -0500750 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
751 return -1;
752 }
Dees_Troye34c1332013-02-06 19:13:00 +0000753 }
Dees_Troye34c1332013-02-06 19:13:00 +0000754 } else if (tardir != "/" && (de->d_type == DT_REG || de->d_type == DT_LNK)) {
Dees_Troy59df9262013-06-19 14:53:57 -0500755 LOGINFO("addFile '%s' including root: %i\n", buf, include_root);
Dees_Troy3263e922013-03-15 11:42:57 -0500756 if (addFile(buf, include_root) != 0)
757 return -1;
758 }
Dees_Troye34c1332013-02-06 19:13:00 +0000759 fflush(NULL);
760 }
761 closedir(d);
762 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500763 return 0;
764}
765
Dees_Troy83bd4832013-05-04 12:39:56 +0000766int twrpTar::tarList(bool include_root, std::vector<TarListStruct> *TarList, unsigned thread_id) {
767 struct stat st;
768 char buf[PATH_MAX];
769 int list_size = TarList->size(), i = 0, archive_count = 0;
770 string temp;
771 char actual_filename[PATH_MAX];
Dees_Troye34c1332013-02-06 19:13:00 +0000772
Dees_Troy83bd4832013-05-04 12:39:56 +0000773 basefn = tarfn;
774 temp = basefn + "%i%02i";
775 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
776 tarfn = actual_filename;
777 if (createTar() != 0) {
778 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
779 return -2;
780 }
781 Archive_Current_Size = 0;
782
783 while (i < list_size) {
784 if (TarList->at(i).thread_id == thread_id) {
785 strcpy(buf, TarList->at(i).fn.c_str());
786 stat(buf, &st);
787 if (st.st_mode & S_IFREG) { // item is a regular file
788 if (Archive_Current_Size + (unsigned long long)(st.st_size) > MAX_ARCHIVE_SIZE) {
789 if (closeTar() != 0) {
790 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
791 return -3;
792 }
793 archive_count++;
794 LOGINFO("Splitting thread ID %i into archive %i\n", thread_id, archive_count);
795 if (archive_count > 99) {
796 LOGINFO("BLAH!\n");
797 LOGERR("Too many archives for thread %i\n", thread_id);
798 return -4;
799 }
800 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
801 tarfn = actual_filename;
802 if (createTar() != 0) {
803 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
804 return -2;
805 }
806 Archive_Current_Size = 0;
807 }
808 Archive_Current_Size += (unsigned long long)(st.st_size);
809 }
810 if (addFile(buf, include_root) != 0) {
811 LOGERR("Error adding file '%s' to '%s'\n", buf, tarfn.c_str());
812 return -1;
813 }
814 }
815 i++;
816 }
817 if (closeTar() != 0) {
818 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
819 return -3;
820 }
821 LOGINFO("Thread id %i tarList done, %i archives.\n", thread_id, archive_count, i, list_size);
Dees_Troye34c1332013-02-06 19:13:00 +0000822 return 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500823}
824
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500825int twrpTar::create() {
Dees_Troye34c1332013-02-06 19:13:00 +0000826
827 init_libtar_buffer(0);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500828 if (createTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500829 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500830 if (tarDirs(false) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500831 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000832 if (closeTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500833 return -1;
Dees_Troye34c1332013-02-06 19:13:00 +0000834 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500835 return 0;
836}
837
Dees_Troy83bd4832013-05-04 12:39:56 +0000838void* twrpTar::createList(void *cookie) {
839
840 twrpTar* threadTar = (twrpTar*) cookie;
841 if (threadTar->tarList(true, threadTar->ItemList, threadTar->thread_id) == -1) {
842 LOGINFO("ERROR tarList for thread ID %i\n", threadTar->thread_id);
843 return (void*)-2;
844 }
845 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
846 return (void*)0;
847}
848
849void* twrpTar::extractMulti(void *cookie) {
850
851 twrpTar* threadTar = (twrpTar*) cookie;
852 int archive_count = 0;
853 string temp = threadTar->basefn + "%i%02i";
854 char actual_filename[255];
855 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
856 while (TWFunc::Path_Exists(actual_filename)) {
857 threadTar->tarfn = actual_filename;
858 if (threadTar->extract() != 0) {
859 LOGINFO("Error extracting '%s' in thread ID %i\n", actual_filename, threadTar->thread_id);
860 return (void*)-2;
861 }
862 archive_count++;
863 if (archive_count > 99)
864 break;
865 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
866 }
867 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
868 return (void*)0;
869}
870
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500871int twrpTar::addFilesToExistingTar(vector <string> files, string fn) {
872 char* charTarFile = (char*) fn.c_str();
873
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200874 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 -0500875 return -1;
876 removeEOT(charTarFile);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200877 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 -0500878 return -1;
879 for (unsigned int i = 0; i < files.size(); ++i) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500880 char* file = (char*) files.at(i).c_str();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500881 if (tar_append_file(t, file, file) == -1)
882 return -1;
883 }
884 if (tar_append_eof(t) == -1)
885 return -1;
886 if (tar_close(t) == -1)
887 return -1;
888 return 0;
889}
890
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500891int twrpTar::createTar() {
892 char* charTarFile = (char*) tarfn.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000893 char* charRootDir = (char*) tardir.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000894 static tartype_t type = { open, close, read, write_tar };
Dees_Troy83bd4832013-05-04 12:39:56 +0000895 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500896
Dees_Troy83bd4832013-05-04 12:39:56 +0000897 if (use_encryption && use_compression) {
898 // Compressed and encrypted
899 Archive_Current_Type = 3;
900 LOGINFO("Using encryption and compression...\n");
901 DataManager::GetValue("tw_backup_password", Password);
902 int i, pipes[4];
903
904 if (pipe(pipes) < 0) {
905 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500906 return -1;
907 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000908 if (pipe(pipes + 2) < 0) {
909 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500910 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000911 }
912 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400913
Dees_Troy83bd4832013-05-04 12:39:56 +0000914 if (pigz_pid < 0) {
915 LOGERR("pigz fork() failed\n");
916 for (i = 0; i < 4; i++)
917 close(pipes[i]); // close all
918 return -1;
919 } else if (pigz_pid == 0) {
920 // pigz Child
921 close(pipes[1]);
922 close(pipes[2]);
923 close(0);
924 dup2(pipes[0], 0);
925 close(1);
926 dup2(pipes[3], 1);
927 if (execlp("pigz", "pigz", "-", NULL) < 0) {
928 LOGERR("execlp pigz ERROR!\n");
929 close(pipes[0]);
930 close(pipes[3]);
931 _exit(-1);
932 }
933 } else {
934 // Parent
935 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400936
Dees_Troy83bd4832013-05-04 12:39:56 +0000937 if (oaes_pid < 0) {
938 LOGERR("openaes fork() failed\n");
939 for (i = 0; i < 4; i++)
940 close(pipes[i]); // close all
941 return -1;
942 } else if (oaes_pid == 0) {
943 // openaes Child
Dees_Troy5612cc82013-07-24 19:45:58 +0000944 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 +0000945 if (output_fd < 0) {
946 LOGERR("Failed to open '%s'\n", tarfn.c_str());
947 for (i = 0; i < 4; i++)
948 close(pipes[i]); // close all
949 return -1;
950 }
951 close(pipes[0]);
952 close(pipes[1]);
953 close(pipes[3]);
954 close(0);
955 dup2(pipes[2], 0);
956 close(1);
957 dup2(output_fd, 1);
958 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
959 LOGERR("execlp openaes ERROR!\n");
960 close(pipes[2]);
961 close(output_fd);
962 _exit(-1);
963 }
964 } else {
965 // Parent
966 close(pipes[0]);
967 close(pipes[2]);
968 close(pipes[3]);
969 fd = pipes[1];
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200970 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 +0000971 close(fd);
972 LOGERR("tar_fdopen failed\n");
973 return -1;
974 }
975 return 0;
976 }
977 }
978 } else if (use_compression) {
979 // Compressed
980 Archive_Current_Type = 1;
981 LOGINFO("Using compression...\n");
982 int pigzfd[2];
983
984 if (pipe(pigzfd) < 0) {
985 LOGERR("Error creating pipe\n");
986 return -1;
987 }
988 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400989
Dees_Troy83bd4832013-05-04 12:39:56 +0000990 if (pigz_pid < 0) {
991 LOGERR("fork() failed\n");
992 close(pigzfd[0]);
993 close(pigzfd[1]);
994 return -1;
995 } else if (pigz_pid == 0) {
996 // Child
997 close(pigzfd[1]); // close unused output pipe
Dees_Troy5612cc82013-07-24 19:45:58 +0000998 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 +0000999 if (output_fd < 0) {
1000 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1001 close(pigzfd[0]);
1002 _exit(-1);
1003 }
1004 dup2(pigzfd[0], 0); // remap stdin
1005 dup2(output_fd, 1); // remap stdout to output file
1006 if (execlp("pigz", "pigz", "-", NULL) < 0) {
1007 LOGERR("execlp pigz ERROR!\n");
1008 close(output_fd);
1009 close(pigzfd[0]);
1010 _exit(-1);
1011 }
1012 } else {
1013 // Parent
1014 close(pigzfd[0]); // close parent input
1015 fd = pigzfd[1]; // copy parent output
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001016 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 +00001017 close(fd);
1018 LOGERR("tar_fdopen failed\n");
1019 return -1;
1020 }
1021 }
1022 } else if (use_encryption) {
1023 // Encrypted
1024 Archive_Current_Type = 2;
1025 LOGINFO("Using encryption...\n");
1026 DataManager::GetValue("tw_backup_password", Password);
1027 int oaesfd[2];
1028 pipe(oaesfd);
1029 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001030
Dees_Troy83bd4832013-05-04 12:39:56 +00001031 if (oaes_pid < 0) {
1032 LOGERR("fork() failed\n");
1033 close(oaesfd[0]);
1034 close(oaesfd[1]);
1035 return -1;
1036 } else if (oaes_pid == 0) {
1037 // Child
1038 close(oaesfd[1]); // close unused
Dees_Troy5612cc82013-07-24 19:45:58 +00001039 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 +00001040 if (output_fd < 0) {
1041 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1042 _exit(-1);
1043 }
1044 dup2(oaesfd[0], 0); // remap stdin
1045 dup2(output_fd, 1); // remap stdout to output file
1046 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
1047 LOGERR("execlp openaes ERROR!\n");
1048 close(output_fd);
1049 close(oaesfd[0]);
1050 _exit(-1);
1051 }
1052 } else {
1053 // Parent
1054 close(oaesfd[0]); // close parent input
1055 fd = oaesfd[1]; // copy parent output
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001056 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 +00001057 close(fd);
1058 LOGERR("tar_fdopen failed\n");
1059 return -1;
1060 }
1061 return 0;
1062 }
1063 } else {
1064 // Not compressed or encrypted
1065 init_libtar_buffer(0);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001066 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 +00001067 LOGERR("tar_open error opening '%s'\n", tarfn.c_str());
1068 return -1;
1069 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001070 }
1071 return 0;
1072}
1073
Dees_Troy83bd4832013-05-04 12:39:56 +00001074int twrpTar::openTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001075 char* charRootDir = (char*) tardir.c_str();
1076 char* charTarFile = (char*) tarfn.c_str();
Dees_Troy83bd4832013-05-04 12:39:56 +00001077 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001078
Dees_Troy83bd4832013-05-04 12:39:56 +00001079 if (Archive_Current_Type == 3) {
1080 LOGINFO("Opening encrypted and compressed backup...\n");
1081 DataManager::GetValue("tw_restore_password", Password);
1082 int i, pipes[4];
1083
1084 if (pipe(pipes) < 0) {
1085 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001086 return -1;
1087 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001088 if (pipe(pipes + 2) < 0) {
1089 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001090 return -1;
1091 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001092 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001093
Dees_Troy83bd4832013-05-04 12:39:56 +00001094 if (oaes_pid < 0) {
1095 LOGERR("pigz fork() failed\n");
1096 for (i = 0; i < 4; i++)
1097 close(pipes[i]); // close all
1098 return -1;
1099 } else if (oaes_pid == 0) {
1100 // openaes Child
1101 close(pipes[0]); // Close pipes that are not used by this child
1102 close(pipes[2]);
1103 close(pipes[3]);
1104 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1105 if (input_fd < 0) {
1106 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1107 close(pipes[1]);
1108 _exit(-1);
1109 }
1110 close(0);
1111 dup2(input_fd, 0);
1112 close(1);
1113 dup2(pipes[1], 1);
1114 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1115 LOGERR("execlp openaes ERROR!\n");
1116 close(input_fd);
1117 close(pipes[1]);
1118 _exit(-1);
1119 }
1120 } else {
1121 // Parent
1122 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001123
Dees_Troy83bd4832013-05-04 12:39:56 +00001124 if (pigz_pid < 0) {
1125 LOGERR("openaes fork() failed\n");
1126 for (i = 0; i < 4; i++)
1127 close(pipes[i]); // close all
1128 return -1;
1129 } else if (pigz_pid == 0) {
1130 // pigz Child
1131 close(pipes[1]); // Close pipes not used by this child
1132 close(pipes[2]);
1133 close(0);
1134 dup2(pipes[0], 0);
1135 close(1);
1136 dup2(pipes[3], 1);
1137 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1138 LOGERR("execlp pigz ERROR!\n");
1139 close(pipes[0]);
1140 close(pipes[3]);
1141 _exit(-1);
1142 }
1143 } else {
1144 // Parent
1145 close(pipes[0]); // Close pipes not used by parent
1146 close(pipes[1]);
1147 close(pipes[3]);
1148 fd = pipes[2];
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001149 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 +00001150 close(fd);
1151 LOGERR("tar_fdopen failed\n");
1152 return -1;
1153 }
1154 }
1155 }
1156 } else if (Archive_Current_Type == 2) {
1157 LOGINFO("Opening encrypted backup...\n");
1158 DataManager::GetValue("tw_restore_password", Password);
1159 int oaesfd[2];
1160
1161 pipe(oaesfd);
1162 oaes_pid = fork();
1163 if (oaes_pid < 0) {
1164 LOGERR("fork() failed\n");
1165 close(oaesfd[0]);
1166 close(oaesfd[1]);
1167 return -1;
1168 } else if (oaes_pid == 0) {
1169 // Child
1170 close(oaesfd[0]); // Close unused pipe
1171 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1172 if (input_fd < 0) {
1173 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1174 close(oaesfd[1]);
1175 _exit(-1);
1176 }
1177 close(0); // close stdin
1178 dup2(oaesfd[1], 1); // remap stdout
1179 dup2(input_fd, 0); // remap input fd to stdin
1180 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1181 LOGERR("execlp openaes ERROR!\n");
1182 close(input_fd);
1183 close(oaesfd[1]);
1184 _exit(-1);
1185 }
1186 } else {
1187 // Parent
1188 close(oaesfd[1]); // close parent output
1189 fd = oaesfd[0]; // copy parent input
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001190 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 +00001191 close(fd);
1192 LOGERR("tar_fdopen failed\n");
1193 return -1;
1194 }
1195 }
1196 } else if (Archive_Current_Type == 1) {
1197 LOGINFO("Opening as a gzip...\n");
1198 int pigzfd[2];
1199 pipe(pigzfd);
1200
1201 pigz_pid = fork();
1202 if (pigz_pid < 0) {
1203 LOGERR("fork() failed\n");
1204 close(pigzfd[0]);
1205 close(pigzfd[1]);
1206 return -1;
1207 } else if (pigz_pid == 0) {
1208 // Child
1209 close(pigzfd[0]);
1210 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1211 if (input_fd < 0) {
1212 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1213 _exit(-1);
1214 }
1215 dup2(input_fd, 0); // remap input fd to stdin
1216 dup2(pigzfd[1], 1); // remap stdout
1217 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1218 close(pigzfd[1]);
1219 close(input_fd);
1220 LOGERR("execlp openaes ERROR!\n");
1221 _exit(-1);
1222 }
1223 } else {
1224 // Parent
1225 close(pigzfd[1]); // close parent output
1226 fd = pigzfd[0]; // copy parent input
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001227 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 +00001228 close(fd);
1229 LOGERR("tar_fdopen failed\n");
1230 return -1;
1231 }
1232 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001233 } 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 +00001234 LOGERR("Unable to open tar archive '%s'\n", charTarFile);
1235 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001236 }
1237 return 0;
1238}
1239
1240string twrpTar::Strip_Root_Dir(string Path) {
1241 string temp;
1242 size_t slash;
1243
1244 if (Path.substr(0, 1) == "/")
1245 temp = Path.substr(1, Path.size() - 1);
1246 else
1247 temp = Path;
1248 slash = temp.find("/");
1249 if (slash == string::npos)
1250 return temp;
1251 else {
1252 string stripped;
1253
1254 stripped = temp.substr(slash, temp.size() - slash);
1255 return stripped;
1256 }
1257 return temp;
1258}
1259
1260int twrpTar::addFile(string fn, bool include_root) {
1261 char* charTarFile = (char*) fn.c_str();
1262 if (include_root) {
1263 if (tar_append_file(t, charTarFile, NULL) == -1)
1264 return -1;
1265 } else {
1266 string temp = Strip_Root_Dir(fn);
1267 char* charTarPath = (char*) temp.c_str();
1268 if (tar_append_file(t, charTarFile, charTarPath) == -1)
1269 return -1;
1270 }
1271 return 0;
1272}
1273
Dees_Troy83bd4832013-05-04 12:39:56 +00001274int twrpTar::closeTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001275 flush_libtar_buffer(t->fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001276 if (tar_append_eof(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001277 LOGERR("tar_append_eof(): %s\n", strerror(errno));
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001278 tar_close(t);
1279 return -1;
1280 }
1281 if (tar_close(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001282 LOGERR("Unable to close tar archive: '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001283 return -1;
1284 }
Dees_Troy2727b992013-08-14 20:09:30 +00001285 if (Archive_Current_Type > 0) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001286 close(fd);
Dees_Troy83bd4832013-05-04 12:39:56 +00001287 int status;
1288 if (pigz_pid > 0 && TWFunc::Wait_For_Child(pigz_pid, &status, "pigz") != 0)
1289 return -1;
1290 if (oaes_pid > 0 && TWFunc::Wait_For_Child(oaes_pid, &status, "openaes") != 0)
1291 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001292 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001293 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001294 return 0;
1295}
1296
1297int twrpTar::removeEOT(string tarFile) {
1298 char* charTarFile = (char*) tarFile.c_str();
1299 off_t tarFileEnd;
1300 while (th_read(t) == 0) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001301 if (TH_ISREG(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001302 tar_skip_regfile(t);
1303 tarFileEnd = lseek(t->fd, 0, SEEK_CUR);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001304 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001305 if (tar_close(t) == -1)
1306 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001307 if (truncate(charTarFile, tarFileEnd) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001308 return -1;
1309 return 0;
1310}
1311
n0d33b511632013-03-06 21:14:15 +02001312int twrpTar::entryExists(string entry) {
1313 char* searchstr = (char*)entry.c_str();
1314 int ret;
1315
Dees_Troy83bd4832013-05-04 12:39:56 +00001316 Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
n0d33b511632013-03-06 21:14:15 +02001317
Dees_Troy83bd4832013-05-04 12:39:56 +00001318 if (openTar() == -1)
n0d33b511632013-03-06 21:14:15 +02001319 ret = 0;
1320 else
1321 ret = tar_find(t, searchstr);
1322
Dees_Troy83bd4832013-05-04 12:39:56 +00001323 if (closeTar() != 0)
1324 LOGINFO("Unable to close tar after searching for entry.\n");
n0d33b511632013-03-06 21:14:15 +02001325
1326 return ret;
1327}
1328
Dees_Troy83bd4832013-05-04 12:39:56 +00001329unsigned long long twrpTar::uncompressedSize() {
1330 int type = 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001331 unsigned long long total_size = 0;
Dees_Troy83bd4832013-05-04 12:39:56 +00001332 string Tar, Command, result;
1333 vector<string> split;
1334
1335 Tar = TWFunc::Get_Filename(tarfn);
1336 type = TWFunc::Get_File_Type(tarfn);
1337 if (type == 0)
1338 total_size = TWFunc::Get_File_Size(tarfn);
1339 else {
1340 Command = "pigz -l " + tarfn;
1341 /* if we set Command = "pigz -l " + tarfn + " | sed '1d' | cut -f5 -d' '";
1342 we get the uncompressed size at once. */
1343 TWFunc::Exec_Cmd(Command, result);
1344 if (!result.empty()) {
1345 /* Expected output:
1346 compressed original reduced name
1347 95855838 179403776 -1.3% data.yaffs2.win
1348 ^
1349 split[5]
1350 */
1351 split = TWFunc::split_string(result, ' ', true);
1352 if (split.size() > 4)
1353 total_size = atoi(split[5].c_str());
1354 }
1355 }
1356 LOGINFO("%s's uncompressed size: %llu bytes\n", Tar.c_str(), total_size);
1357
1358 return total_size;
1359}
1360
Dees_Troye34c1332013-02-06 19:13:00 +00001361extern "C" ssize_t write_tar(int fd, const void *buffer, size_t size) {
1362 return (ssize_t) write_libtar_buffer(fd, buffer, size);
Dees_Troy40bbcf82013-02-12 15:01:53 +00001363}