blob: 534049f973d372fdcb02e4c75c1238b9cad56c40 [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 bigbiffd0c24c52013-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 bigbiffd0c24c52013-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_Troy2673cec2013-04-02 20:22:16 +0000540 LOGINFO("Calling Generate_Multiple_Archives\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500541 if (Generate_Multiple_Archives(FileName) < 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500542 return -1;
543 } else {
544 //FileName += "/";
Dees_Troy2673cec2013-04-02 20:22:16 +0000545 LOGINFO("Adding folder '%s'\n", FileName.c_str());
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500546 tardir = FileName;
547 if (tarDirs(true) < 0)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500548 return -1;
549 Archive_Current_Size += folder_size;
550 }
551 }
552 else if (de->d_type == DT_REG || de->d_type == DT_LNK)
553 {
554 stat(FileName.c_str(), &st);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400555 if (de->d_type != DT_LNK) {
556 if (Archive_Current_Size != 0 && Archive_Current_Size + st.st_size > MAX_ARCHIVE_SIZE) {
557 LOGINFO("Closing tar '%s', ", tarfn.c_str());
558 closeTar();
559 if (TWFunc::Get_File_Size(tarfn) == 0) {
560 LOGERR("Backup file size for '%s' is 0 bytes.\n", tarfn.c_str());
561 return -1;
562 }
563 Archive_File_Count++;
564 if (Archive_File_Count > 999) {
565 LOGERR("Archive count is too large!\n");
566 return -1;
567 }
568 string temp = basefn + "%03i";
569 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
570 tarfn = actual_filename;
571 Archive_Current_Size = 0;
572 LOGINFO("Creating tar '%s'\n", tarfn.c_str());
573 gui_print("Creating archive %i...\n", Archive_File_Count + 1);
574 if (createTar() != 0)
575 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500576 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500577 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000578 LOGINFO("Adding file: '%s'... ", FileName.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500579 if (addFile(FileName, true) < 0)
580 return -1;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400581 if (de->d_type != DT_LNK) {
582 Archive_Current_Size += st.st_size;
583 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000584 LOGINFO("added successfully, archive size: %llu\n", Archive_Current_Size);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400585 if (de->d_type != DT_LNK) {
586 if (st.st_size > 2147483648LL)
587 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());
588 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500589 }
590 }
591 closedir(d);
592 return 0;
593}
594
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500595int twrpTar::Split_Archive()
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500596{
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500597 string temp = tarfn + "%03i";
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500598 char actual_filename[255];
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400599 string tarsplit;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500600
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500601 basefn = tarfn;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500602 Archive_File_Count = 0;
603 Archive_Current_Size = 0;
604 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500605 tarfn = actual_filename;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400606
607 for (int i = 0; i < tarexclude.size(); ++i) {
608 tarsplit = tarexclude[i];
609 tarsplit += " ";
610 }
611
Dees_Troy83bd4832013-05-04 12:39:56 +0000612 if (!tarexclude.empty())
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400613 split = TWFunc::split_string(tarsplit, ' ', true);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500614 createTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500615 DataManager::GetValue(TW_HAS_DATA_MEDIA, has_data_media);
Dees_Troy2673cec2013-04-02 20:22:16 +0000616 gui_print("Creating archive 1...\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500617 if (Generate_Multiple_Archives(tardir) < 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000618 LOGERR("Error generating multiple archives\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500619 return -1;
620 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000621 closeTar();
622 LOGINFO("Done, created %i archives.\n", (++Archive_File_Count));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500623 return (Archive_File_Count);
624}
625
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500626int twrpTar::extractTar() {
Dees_Troye34c1332013-02-06 19:13:00 +0000627 char* charRootDir = (char*) tardir.c_str();
Dees_Troy83bd4832013-05-04 12:39:56 +0000628 if (openTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500629 return -1;
630 if (tar_extract_all(t, charRootDir) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000631 LOGERR("Unable to extract tar archive '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500632 return -1;
633 }
634 if (tar_close(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000635 LOGERR("Unable to close tar file\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500636 return -1;
637 }
638 return 0;
639}
640
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500641int twrpTar::extract() {
Dees_Troy83bd4832013-05-04 12:39:56 +0000642 Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
n0d33b511632013-03-06 21:14:15 +0200643
644 if (Archive_Current_Type == 1) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500645 //if you return the extractTGZ function directly, stack crashes happen
Dees_Troy2673cec2013-04-02 20:22:16 +0000646 LOGINFO("Extracting gzipped tar\n");
Dees_Troy83bd4832013-05-04 12:39:56 +0000647 int ret = extractTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500648 return ret;
Dees_Troy83bd4832013-05-04 12:39:56 +0000649 } else if (Archive_Current_Type == 2) {
650 string Password;
651 DataManager::GetValue("tw_restore_password", Password);
652 int ret = TWFunc::Try_Decrypting_File(tarfn, Password);
653 if (ret < 1) {
654 LOGERR("Failed to decrypt tar file '%s'\n", tarfn.c_str());
655 return -1;
656 }
657 if (ret == 1) {
658 LOGERR("Decrypted file is not in tar format.\n");
659 return -1;
660 }
661 if (ret == 3) {
662 LOGINFO("Extracting encrypted and compressed tar.\n");
663 Archive_Current_Type = 3;
664 } else
665 LOGINFO("Extracting encrypted tar.\n");
666 return extractTar();
667 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000668 LOGINFO("Extracting uncompressed tar\n");
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500669 return extractTar();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500670 }
671}
672
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500673int twrpTar::tarDirs(bool include_root) {
Dees_Troye34c1332013-02-06 19:13:00 +0000674 DIR* d;
675 string mainfolder = tardir + "/", subfolder;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400676 string tarsplit;
Dees_Troy59df9262013-06-19 14:53:57 -0500677 char buf[PATH_MAX], charTarPath[PATH_MAX];
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400678 string excl;
Dees_Troy83bd4832013-05-04 12:39:56 +0000679 string::size_type i;
680 bool skip;
681
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400682 //set exclude directories for libtar
683 for (int i = 0; i < tarexclude.size(); ++i) {
684 excl += tarexclude.at(i);
685 tarsplit = tarexclude.at(i);
686 excl += " ";
687 tarsplit += " ";
688 }
Dees_Troye34c1332013-02-06 19:13:00 +0000689 d = opendir(tardir.c_str());
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400690 if (d != NULL) {
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400691 if (!tarsplit.empty()) {
692 split = TWFunc::split_string(tarsplit, ' ', true);
Dees_Troy83bd4832013-05-04 12:39:56 +0000693 }
Dees_Troye34c1332013-02-06 19:13:00 +0000694 struct dirent* de;
695 while ((de = readdir(d)) != NULL) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500696#ifdef RECOVERY_SDCARD_ON_DATA
Dees_Troye34c1332013-02-06 19:13:00 +0000697 if ((tardir == "/data" || tardir == "/data/") && strcmp(de->d_name, "media") == 0) continue;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500698#endif
bigbiff bigbiff616afed2013-07-11 18:50:29 -0400699 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 -0500700 continue;
Dees_Troy83bd4832013-05-04 12:39:56 +0000701
702 // Skip excluded stuff
703 if (split.size() > 0) {
704 skip = false;
705 for (i = 0; i < split.size(); i++) {
706 if (strcmp(de->d_name, split[i].c_str()) == 0) {
707 LOGINFO("excluding %s\n", de->d_name);
708 skip = true;
709 break;
710 }
711 }
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400712 if (skip) {
Dees_Troy83bd4832013-05-04 12:39:56 +0000713 continue;
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400714 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000715 }
716
Dees_Troye34c1332013-02-06 19:13:00 +0000717 subfolder = mainfolder;
Dees_Troy3263e922013-03-15 11:42:57 -0500718 if (strcmp(de->d_name, ".") != 0) {
719 subfolder += de->d_name;
720 } else {
bigbiff bigbiffd0c24c52013-10-11 20:28:00 -0400721 std::string parentDir = basename(subfolder.c_str());
722 LOGINFO("parentDir: %s\n", parentDir.c_str());
723 if (!parentDir.compare("lost+found"))
724 continue;
725 LOGINFO("tarDirs addFile '%s' including root: %i\n", subfolder.c_str(), include_root);
Dees_Troy3263e922013-03-15 11:42:57 -0500726 if (addFile(subfolder, include_root) != 0)
727 return -1;
728 continue;
729 }
Dees_Troye34c1332013-02-06 19:13:00 +0000730 strcpy(buf, subfolder.c_str());
731 if (de->d_type == DT_DIR) {
Dees_Troy3263e922013-03-15 11:42:57 -0500732 if (include_root) {
Dees_Troy59df9262013-06-19 14:53:57 -0500733 charTarPath[0] = NULL;
734 LOGINFO("tar_append_tree '%s' as NULL\n", buf, charTarPath);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400735 if (tar_append_tree(t, buf, NULL, &excl[0]) != 0) {
Dees_Troy59df9262013-06-19 14:53:57 -0500736 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
737 return -1;
738 }
Dees_Troy3263e922013-03-15 11:42:57 -0500739 } else {
740 string temp = Strip_Root_Dir(buf);
Dees_Troy59df9262013-06-19 14:53:57 -0500741 strcpy(charTarPath, temp.c_str());
742 LOGINFO("tar_append_tree '%s' as '%s'\n", buf, charTarPath);
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400743 if (tar_append_tree(t, buf, charTarPath, &excl[0]) != 0) {
Dees_Troy59df9262013-06-19 14:53:57 -0500744 LOGERR("Error appending '%s' to tar archive '%s'\n", buf, tarfn.c_str());
745 return -1;
746 }
Dees_Troye34c1332013-02-06 19:13:00 +0000747 }
Dees_Troye34c1332013-02-06 19:13:00 +0000748 } else if (tardir != "/" && (de->d_type == DT_REG || de->d_type == DT_LNK)) {
Dees_Troy59df9262013-06-19 14:53:57 -0500749 LOGINFO("addFile '%s' including root: %i\n", buf, include_root);
Dees_Troy3263e922013-03-15 11:42:57 -0500750 if (addFile(buf, include_root) != 0)
751 return -1;
752 }
Dees_Troye34c1332013-02-06 19:13:00 +0000753 fflush(NULL);
754 }
755 closedir(d);
756 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500757 return 0;
758}
759
Dees_Troy83bd4832013-05-04 12:39:56 +0000760int twrpTar::tarList(bool include_root, std::vector<TarListStruct> *TarList, unsigned thread_id) {
761 struct stat st;
762 char buf[PATH_MAX];
763 int list_size = TarList->size(), i = 0, archive_count = 0;
764 string temp;
765 char actual_filename[PATH_MAX];
Dees_Troye34c1332013-02-06 19:13:00 +0000766
Dees_Troy83bd4832013-05-04 12:39:56 +0000767 basefn = tarfn;
768 temp = basefn + "%i%02i";
769 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
770 tarfn = actual_filename;
771 if (createTar() != 0) {
772 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
773 return -2;
774 }
775 Archive_Current_Size = 0;
776
777 while (i < list_size) {
778 if (TarList->at(i).thread_id == thread_id) {
779 strcpy(buf, TarList->at(i).fn.c_str());
780 stat(buf, &st);
781 if (st.st_mode & S_IFREG) { // item is a regular file
782 if (Archive_Current_Size + (unsigned long long)(st.st_size) > MAX_ARCHIVE_SIZE) {
783 if (closeTar() != 0) {
784 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
785 return -3;
786 }
787 archive_count++;
788 LOGINFO("Splitting thread ID %i into archive %i\n", thread_id, archive_count);
789 if (archive_count > 99) {
790 LOGINFO("BLAH!\n");
791 LOGERR("Too many archives for thread %i\n", thread_id);
792 return -4;
793 }
794 sprintf(actual_filename, temp.c_str(), thread_id, archive_count);
795 tarfn = actual_filename;
796 if (createTar() != 0) {
797 LOGERR("Error creating tar '%s' for thread %i\n", tarfn.c_str(), thread_id);
798 return -2;
799 }
800 Archive_Current_Size = 0;
801 }
802 Archive_Current_Size += (unsigned long long)(st.st_size);
803 }
804 if (addFile(buf, include_root) != 0) {
805 LOGERR("Error adding file '%s' to '%s'\n", buf, tarfn.c_str());
806 return -1;
807 }
808 }
809 i++;
810 }
811 if (closeTar() != 0) {
812 LOGERR("Error closing '%s' on thread %i\n", tarfn.c_str(), thread_id);
813 return -3;
814 }
815 LOGINFO("Thread id %i tarList done, %i archives.\n", thread_id, archive_count, i, list_size);
Dees_Troye34c1332013-02-06 19:13:00 +0000816 return 0;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500817}
818
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500819int twrpTar::create() {
Dees_Troye34c1332013-02-06 19:13:00 +0000820
821 init_libtar_buffer(0);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500822 if (createTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500823 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500824 if (tarDirs(false) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500825 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000826 if (closeTar() == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500827 return -1;
Dees_Troye34c1332013-02-06 19:13:00 +0000828 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500829 return 0;
830}
831
Dees_Troy83bd4832013-05-04 12:39:56 +0000832void* twrpTar::createList(void *cookie) {
833
834 twrpTar* threadTar = (twrpTar*) cookie;
835 if (threadTar->tarList(true, threadTar->ItemList, threadTar->thread_id) == -1) {
836 LOGINFO("ERROR tarList for thread ID %i\n", threadTar->thread_id);
837 return (void*)-2;
838 }
839 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
840 return (void*)0;
841}
842
843void* twrpTar::extractMulti(void *cookie) {
844
845 twrpTar* threadTar = (twrpTar*) cookie;
846 int archive_count = 0;
847 string temp = threadTar->basefn + "%i%02i";
848 char actual_filename[255];
849 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
850 while (TWFunc::Path_Exists(actual_filename)) {
851 threadTar->tarfn = actual_filename;
852 if (threadTar->extract() != 0) {
853 LOGINFO("Error extracting '%s' in thread ID %i\n", actual_filename, threadTar->thread_id);
854 return (void*)-2;
855 }
856 archive_count++;
857 if (archive_count > 99)
858 break;
859 sprintf(actual_filename, temp.c_str(), threadTar->thread_id, archive_count);
860 }
861 LOGINFO("Thread ID %i finished successfully.\n", threadTar->thread_id);
862 return (void*)0;
863}
864
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500865int twrpTar::addFilesToExistingTar(vector <string> files, string fn) {
866 char* charTarFile = (char*) fn.c_str();
867
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200868 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 -0500869 return -1;
870 removeEOT(charTarFile);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200871 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 -0500872 return -1;
873 for (unsigned int i = 0; i < files.size(); ++i) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500874 char* file = (char*) files.at(i).c_str();
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500875 if (tar_append_file(t, file, file) == -1)
876 return -1;
877 }
878 if (tar_append_eof(t) == -1)
879 return -1;
880 if (tar_close(t) == -1)
881 return -1;
882 return 0;
883}
884
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -0500885int twrpTar::createTar() {
886 char* charTarFile = (char*) tarfn.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000887 char* charRootDir = (char*) tardir.c_str();
Dees_Troye34c1332013-02-06 19:13:00 +0000888 static tartype_t type = { open, close, read, write_tar };
Dees_Troy83bd4832013-05-04 12:39:56 +0000889 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500890
Dees_Troy83bd4832013-05-04 12:39:56 +0000891 if (use_encryption && use_compression) {
892 // Compressed and encrypted
893 Archive_Current_Type = 3;
894 LOGINFO("Using encryption and compression...\n");
895 DataManager::GetValue("tw_backup_password", Password);
896 int i, pipes[4];
897
898 if (pipe(pipes) < 0) {
899 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500900 return -1;
901 }
Dees_Troy83bd4832013-05-04 12:39:56 +0000902 if (pipe(pipes + 2) < 0) {
903 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500904 return -1;
Dees_Troy83bd4832013-05-04 12:39:56 +0000905 }
906 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400907
Dees_Troy83bd4832013-05-04 12:39:56 +0000908 if (pigz_pid < 0) {
909 LOGERR("pigz fork() failed\n");
910 for (i = 0; i < 4; i++)
911 close(pipes[i]); // close all
912 return -1;
913 } else if (pigz_pid == 0) {
914 // pigz Child
915 close(pipes[1]);
916 close(pipes[2]);
917 close(0);
918 dup2(pipes[0], 0);
919 close(1);
920 dup2(pipes[3], 1);
921 if (execlp("pigz", "pigz", "-", NULL) < 0) {
922 LOGERR("execlp pigz ERROR!\n");
923 close(pipes[0]);
924 close(pipes[3]);
925 _exit(-1);
926 }
927 } else {
928 // Parent
929 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400930
Dees_Troy83bd4832013-05-04 12:39:56 +0000931 if (oaes_pid < 0) {
932 LOGERR("openaes fork() failed\n");
933 for (i = 0; i < 4; i++)
934 close(pipes[i]); // close all
935 return -1;
936 } else if (oaes_pid == 0) {
937 // openaes Child
Dees_Troy5612cc82013-07-24 19:45:58 +0000938 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 +0000939 if (output_fd < 0) {
940 LOGERR("Failed to open '%s'\n", tarfn.c_str());
941 for (i = 0; i < 4; i++)
942 close(pipes[i]); // close all
943 return -1;
944 }
945 close(pipes[0]);
946 close(pipes[1]);
947 close(pipes[3]);
948 close(0);
949 dup2(pipes[2], 0);
950 close(1);
951 dup2(output_fd, 1);
952 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
953 LOGERR("execlp openaes ERROR!\n");
954 close(pipes[2]);
955 close(output_fd);
956 _exit(-1);
957 }
958 } else {
959 // Parent
960 close(pipes[0]);
961 close(pipes[2]);
962 close(pipes[3]);
963 fd = pipes[1];
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200964 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 +0000965 close(fd);
966 LOGERR("tar_fdopen failed\n");
967 return -1;
968 }
969 return 0;
970 }
971 }
972 } else if (use_compression) {
973 // Compressed
974 Archive_Current_Type = 1;
975 LOGINFO("Using compression...\n");
976 int pigzfd[2];
977
978 if (pipe(pigzfd) < 0) {
979 LOGERR("Error creating pipe\n");
980 return -1;
981 }
982 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -0400983
Dees_Troy83bd4832013-05-04 12:39:56 +0000984 if (pigz_pid < 0) {
985 LOGERR("fork() failed\n");
986 close(pigzfd[0]);
987 close(pigzfd[1]);
988 return -1;
989 } else if (pigz_pid == 0) {
990 // Child
991 close(pigzfd[1]); // close unused output pipe
Dees_Troy5612cc82013-07-24 19:45:58 +0000992 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 +0000993 if (output_fd < 0) {
994 LOGERR("Failed to open '%s'\n", tarfn.c_str());
995 close(pigzfd[0]);
996 _exit(-1);
997 }
998 dup2(pigzfd[0], 0); // remap stdin
999 dup2(output_fd, 1); // remap stdout to output file
1000 if (execlp("pigz", "pigz", "-", NULL) < 0) {
1001 LOGERR("execlp pigz ERROR!\n");
1002 close(output_fd);
1003 close(pigzfd[0]);
1004 _exit(-1);
1005 }
1006 } else {
1007 // Parent
1008 close(pigzfd[0]); // close parent input
1009 fd = pigzfd[1]; // copy parent output
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001010 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 +00001011 close(fd);
1012 LOGERR("tar_fdopen failed\n");
1013 return -1;
1014 }
1015 }
1016 } else if (use_encryption) {
1017 // Encrypted
1018 Archive_Current_Type = 2;
1019 LOGINFO("Using encryption...\n");
1020 DataManager::GetValue("tw_backup_password", Password);
1021 int oaesfd[2];
1022 pipe(oaesfd);
1023 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001024
Dees_Troy83bd4832013-05-04 12:39:56 +00001025 if (oaes_pid < 0) {
1026 LOGERR("fork() failed\n");
1027 close(oaesfd[0]);
1028 close(oaesfd[1]);
1029 return -1;
1030 } else if (oaes_pid == 0) {
1031 // Child
1032 close(oaesfd[1]); // close unused
Dees_Troy5612cc82013-07-24 19:45:58 +00001033 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 +00001034 if (output_fd < 0) {
1035 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1036 _exit(-1);
1037 }
1038 dup2(oaesfd[0], 0); // remap stdin
1039 dup2(output_fd, 1); // remap stdout to output file
1040 if (execlp("openaes", "openaes", "enc", "--key", Password.c_str(), NULL) < 0) {
1041 LOGERR("execlp openaes ERROR!\n");
1042 close(output_fd);
1043 close(oaesfd[0]);
1044 _exit(-1);
1045 }
1046 } else {
1047 // Parent
1048 close(oaesfd[0]); // close parent input
1049 fd = oaesfd[1]; // copy parent output
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001050 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 +00001051 close(fd);
1052 LOGERR("tar_fdopen failed\n");
1053 return -1;
1054 }
1055 return 0;
1056 }
1057 } else {
1058 // Not compressed or encrypted
1059 init_libtar_buffer(0);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001060 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 +00001061 LOGERR("tar_open error opening '%s'\n", tarfn.c_str());
1062 return -1;
1063 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001064 }
1065 return 0;
1066}
1067
Dees_Troy83bd4832013-05-04 12:39:56 +00001068int twrpTar::openTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001069 char* charRootDir = (char*) tardir.c_str();
1070 char* charTarFile = (char*) tarfn.c_str();
Dees_Troy83bd4832013-05-04 12:39:56 +00001071 string Password;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001072
Dees_Troy83bd4832013-05-04 12:39:56 +00001073 if (Archive_Current_Type == 3) {
1074 LOGINFO("Opening encrypted and compressed backup...\n");
1075 DataManager::GetValue("tw_restore_password", Password);
1076 int i, pipes[4];
1077
1078 if (pipe(pipes) < 0) {
1079 LOGERR("Error creating first pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001080 return -1;
1081 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001082 if (pipe(pipes + 2) < 0) {
1083 LOGERR("Error creating second pipe\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001084 return -1;
1085 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001086 oaes_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001087
Dees_Troy83bd4832013-05-04 12:39:56 +00001088 if (oaes_pid < 0) {
1089 LOGERR("pigz fork() failed\n");
1090 for (i = 0; i < 4; i++)
1091 close(pipes[i]); // close all
1092 return -1;
1093 } else if (oaes_pid == 0) {
1094 // openaes Child
1095 close(pipes[0]); // Close pipes that are not used by this child
1096 close(pipes[2]);
1097 close(pipes[3]);
1098 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1099 if (input_fd < 0) {
1100 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1101 close(pipes[1]);
1102 _exit(-1);
1103 }
1104 close(0);
1105 dup2(input_fd, 0);
1106 close(1);
1107 dup2(pipes[1], 1);
1108 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1109 LOGERR("execlp openaes ERROR!\n");
1110 close(input_fd);
1111 close(pipes[1]);
1112 _exit(-1);
1113 }
1114 } else {
1115 // Parent
1116 pigz_pid = fork();
bigbiff bigbiff86e77bc2013-08-26 21:36:23 -04001117
Dees_Troy83bd4832013-05-04 12:39:56 +00001118 if (pigz_pid < 0) {
1119 LOGERR("openaes fork() failed\n");
1120 for (i = 0; i < 4; i++)
1121 close(pipes[i]); // close all
1122 return -1;
1123 } else if (pigz_pid == 0) {
1124 // pigz Child
1125 close(pipes[1]); // Close pipes not used by this child
1126 close(pipes[2]);
1127 close(0);
1128 dup2(pipes[0], 0);
1129 close(1);
1130 dup2(pipes[3], 1);
1131 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1132 LOGERR("execlp pigz ERROR!\n");
1133 close(pipes[0]);
1134 close(pipes[3]);
1135 _exit(-1);
1136 }
1137 } else {
1138 // Parent
1139 close(pipes[0]); // Close pipes not used by parent
1140 close(pipes[1]);
1141 close(pipes[3]);
1142 fd = pipes[2];
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001143 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 +00001144 close(fd);
1145 LOGERR("tar_fdopen failed\n");
1146 return -1;
1147 }
1148 }
1149 }
1150 } else if (Archive_Current_Type == 2) {
1151 LOGINFO("Opening encrypted backup...\n");
1152 DataManager::GetValue("tw_restore_password", Password);
1153 int oaesfd[2];
1154
1155 pipe(oaesfd);
1156 oaes_pid = fork();
1157 if (oaes_pid < 0) {
1158 LOGERR("fork() failed\n");
1159 close(oaesfd[0]);
1160 close(oaesfd[1]);
1161 return -1;
1162 } else if (oaes_pid == 0) {
1163 // Child
1164 close(oaesfd[0]); // Close unused pipe
1165 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1166 if (input_fd < 0) {
1167 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1168 close(oaesfd[1]);
1169 _exit(-1);
1170 }
1171 close(0); // close stdin
1172 dup2(oaesfd[1], 1); // remap stdout
1173 dup2(input_fd, 0); // remap input fd to stdin
1174 if (execlp("openaes", "openaes", "dec", "--key", Password.c_str(), NULL) < 0) {
1175 LOGERR("execlp openaes ERROR!\n");
1176 close(input_fd);
1177 close(oaesfd[1]);
1178 _exit(-1);
1179 }
1180 } else {
1181 // Parent
1182 close(oaesfd[1]); // close parent output
1183 fd = oaesfd[0]; // copy parent input
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001184 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 +00001185 close(fd);
1186 LOGERR("tar_fdopen failed\n");
1187 return -1;
1188 }
1189 }
1190 } else if (Archive_Current_Type == 1) {
1191 LOGINFO("Opening as a gzip...\n");
1192 int pigzfd[2];
1193 pipe(pigzfd);
1194
1195 pigz_pid = fork();
1196 if (pigz_pid < 0) {
1197 LOGERR("fork() failed\n");
1198 close(pigzfd[0]);
1199 close(pigzfd[1]);
1200 return -1;
1201 } else if (pigz_pid == 0) {
1202 // Child
1203 close(pigzfd[0]);
1204 int input_fd = open(tarfn.c_str(), O_RDONLY | O_LARGEFILE);
1205 if (input_fd < 0) {
1206 LOGERR("Failed to open '%s'\n", tarfn.c_str());
1207 _exit(-1);
1208 }
1209 dup2(input_fd, 0); // remap input fd to stdin
1210 dup2(pigzfd[1], 1); // remap stdout
1211 if (execlp("pigz", "pigz", "-d", "-c", NULL) < 0) {
1212 close(pigzfd[1]);
1213 close(input_fd);
1214 LOGERR("execlp openaes ERROR!\n");
1215 _exit(-1);
1216 }
1217 } else {
1218 // Parent
1219 close(pigzfd[1]); // close parent output
1220 fd = pigzfd[0]; // copy parent input
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001221 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 +00001222 close(fd);
1223 LOGERR("tar_fdopen failed\n");
1224 return -1;
1225 }
1226 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +02001227 } 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 +00001228 LOGERR("Unable to open tar archive '%s'\n", charTarFile);
1229 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001230 }
1231 return 0;
1232}
1233
1234string twrpTar::Strip_Root_Dir(string Path) {
1235 string temp;
1236 size_t slash;
1237
1238 if (Path.substr(0, 1) == "/")
1239 temp = Path.substr(1, Path.size() - 1);
1240 else
1241 temp = Path;
1242 slash = temp.find("/");
1243 if (slash == string::npos)
1244 return temp;
1245 else {
1246 string stripped;
1247
1248 stripped = temp.substr(slash, temp.size() - slash);
1249 return stripped;
1250 }
1251 return temp;
1252}
1253
1254int twrpTar::addFile(string fn, bool include_root) {
1255 char* charTarFile = (char*) fn.c_str();
1256 if (include_root) {
1257 if (tar_append_file(t, charTarFile, NULL) == -1)
1258 return -1;
1259 } else {
1260 string temp = Strip_Root_Dir(fn);
1261 char* charTarPath = (char*) temp.c_str();
1262 if (tar_append_file(t, charTarFile, charTarPath) == -1)
1263 return -1;
1264 }
1265 return 0;
1266}
1267
Dees_Troy83bd4832013-05-04 12:39:56 +00001268int twrpTar::closeTar() {
Dees_Troye34c1332013-02-06 19:13:00 +00001269 flush_libtar_buffer(t->fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001270 if (tar_append_eof(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001271 LOGERR("tar_append_eof(): %s\n", strerror(errno));
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001272 tar_close(t);
1273 return -1;
1274 }
1275 if (tar_close(t) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001276 LOGERR("Unable to close tar archive: '%s'\n", tarfn.c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001277 return -1;
1278 }
Dees_Troy2727b992013-08-14 20:09:30 +00001279 if (Archive_Current_Type > 0) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001280 close(fd);
Dees_Troy83bd4832013-05-04 12:39:56 +00001281 int status;
1282 if (pigz_pid > 0 && TWFunc::Wait_For_Child(pigz_pid, &status, "pigz") != 0)
1283 return -1;
1284 if (oaes_pid > 0 && TWFunc::Wait_For_Child(oaes_pid, &status, "openaes") != 0)
1285 return -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001286 }
Dees_Troy83bd4832013-05-04 12:39:56 +00001287 free_libtar_buffer();
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001288 return 0;
1289}
1290
1291int twrpTar::removeEOT(string tarFile) {
1292 char* charTarFile = (char*) tarFile.c_str();
1293 off_t tarFileEnd;
1294 while (th_read(t) == 0) {
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001295 if (TH_ISREG(t))
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001296 tar_skip_regfile(t);
1297 tarFileEnd = lseek(t->fd, 0, SEEK_CUR);
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001298 }
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001299 if (tar_close(t) == -1)
1300 return -1;
bigbiff bigbiff3bf2b0e2013-01-21 21:26:43 -05001301 if (truncate(charTarFile, tarFileEnd) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001302 return -1;
1303 return 0;
1304}
1305
n0d33b511632013-03-06 21:14:15 +02001306int twrpTar::entryExists(string entry) {
1307 char* searchstr = (char*)entry.c_str();
1308 int ret;
1309
Dees_Troy83bd4832013-05-04 12:39:56 +00001310 Archive_Current_Type = TWFunc::Get_File_Type(tarfn);
n0d33b511632013-03-06 21:14:15 +02001311
Dees_Troy83bd4832013-05-04 12:39:56 +00001312 if (openTar() == -1)
n0d33b511632013-03-06 21:14:15 +02001313 ret = 0;
1314 else
1315 ret = tar_find(t, searchstr);
1316
Dees_Troy83bd4832013-05-04 12:39:56 +00001317 if (closeTar() != 0)
1318 LOGINFO("Unable to close tar after searching for entry.\n");
n0d33b511632013-03-06 21:14:15 +02001319
1320 return ret;
1321}
1322
Dees_Troy83bd4832013-05-04 12:39:56 +00001323unsigned long long twrpTar::uncompressedSize() {
1324 int type = 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001325 unsigned long long total_size = 0;
Dees_Troy83bd4832013-05-04 12:39:56 +00001326 string Tar, Command, result;
1327 vector<string> split;
1328
1329 Tar = TWFunc::Get_Filename(tarfn);
1330 type = TWFunc::Get_File_Type(tarfn);
1331 if (type == 0)
1332 total_size = TWFunc::Get_File_Size(tarfn);
1333 else {
1334 Command = "pigz -l " + tarfn;
1335 /* if we set Command = "pigz -l " + tarfn + " | sed '1d' | cut -f5 -d' '";
1336 we get the uncompressed size at once. */
1337 TWFunc::Exec_Cmd(Command, result);
1338 if (!result.empty()) {
1339 /* Expected output:
1340 compressed original reduced name
1341 95855838 179403776 -1.3% data.yaffs2.win
1342 ^
1343 split[5]
1344 */
1345 split = TWFunc::split_string(result, ' ', true);
1346 if (split.size() > 4)
1347 total_size = atoi(split[5].c_str());
1348 }
1349 }
1350 LOGINFO("%s's uncompressed size: %llu bytes\n", Tar.c_str(), total_size);
1351
1352 return total_size;
1353}
1354
Dees_Troye34c1332013-02-06 19:13:00 +00001355extern "C" ssize_t write_tar(int fd, const void *buffer, size_t size) {
1356 return (ssize_t) write_libtar_buffer(fd, buffer, size);
Dees_Troy40bbcf82013-02-12 15:01:53 +00001357}