blob: 0008de4574751e6d4db4864f88fcddc8c5d10d3b [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/*
2 Copyright 2012 bigbiff/Dees_Troy TeamWin
3 This file is part of TWRP/TeamWin Recovery Project.
4
5 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.
9
10 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.
14
15 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19extern "C" {
20 #include "libtar/libtar.h"
21}
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <string.h>
25#include <errno.h>
26#include <fcntl.h>
27#include <fstream>
28#include <fstream>
29#include <iostream>
30#include <string>
31#include <dirent.h>
32#include <sys/mman.h>
33#include "twrpTar.hpp"
34#include "common.h"
35#include "data.hpp"
36#include "variables.h"
37#include <sstream>
38#include "twrp-functions.hpp"
39
40using namespace std;
41
42int twrpTar::Generate_Multiple_Archives(string Path, string fn) {
43 DIR* d;
44 struct dirent* de;
45 struct stat st;
46 string FileName;
47 char actual_filename[255];
48
49 sprintf(actual_filename, fn.c_str(), Archive_File_Count);
50
51 if (has_data_media == 1 && Path.size() >= 11 && strncmp(Path.c_str(), "/data/media", 11) == 0)
52 return 0; // Skip /data/media
53 LOGI("Path: '%s', archive filename: '%s'\n", Path.c_str(), actual_filename);
54
55 d = opendir(Path.c_str());
56 if (d == NULL)
57 {
58 LOGE("error opening '%s' -- error: %s\n", Path.c_str(), strerror(errno));
59 closedir(d);
60 return -1;
61 }
62 while ((de = readdir(d)) != NULL)
63 {
64 FileName = Path + "/";
65 FileName += de->d_name;
66 if (has_data_media == 1 && FileName.size() >= 11 && strncmp(FileName.c_str(), "/data/media", 11) == 0)
67 continue; // Skip /data/media
68 if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
69 {
70 unsigned long long folder_size = TWFunc::Get_Folder_Size(FileName, false);
71 if (Archive_Current_Size + folder_size > MAX_ARCHIVE_SIZE) {
72 if (Generate_Multiple_Archives(FileName, fn) < 0)
73 return -1;
74 } else {
75 //FileName += "/";
76 LOGI("Adding folder '%s'\n", FileName.c_str());
77 if (tarDirs(FileName, actual_filename, true) < 0)
78 return -1;
79 Archive_Current_Size += folder_size;
80 }
81 }
82 else if (de->d_type == DT_REG || de->d_type == DT_LNK)
83 {
84 stat(FileName.c_str(), &st);
85
86 if (Archive_Current_Size != 0 && Archive_Current_Size + st.st_size > MAX_ARCHIVE_SIZE) {
87 LOGI("Closing tar '%s', ", actual_filename);
88 closeTar(actual_filename, false);
89 Archive_File_Count++;
90 if (TWFunc::Get_File_Size(actual_filename) == 0) {
91 LOGE("Backup file size for '%s' is 0 bytes.\n", actual_filename);
92 return false;
93 }
94 if (Archive_File_Count > 999) {
95 LOGE("Archive count is too large!\n");
96 return -1;
97 }
98 Archive_Current_Size = 0;
99 sprintf(actual_filename, fn.c_str(), Archive_File_Count);
100 LOGI("Creating tar '%s'\n", actual_filename);
101 ui_print("Creating archive %i...\n", Archive_File_Count + 1);
102 createTar(Path, actual_filename);
103 }
104 LOGI("Adding file: '%s'... ", FileName.c_str());
105 if (addFile(FileName, true) < 0)
106 return -1;
107 Archive_Current_Size += st.st_size;
108 LOGI("added successfully, archive size: %llu\n", Archive_Current_Size);
109 if (st.st_size > 2147483648LL)
110 LOGE("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());
111 }
112 }
113 closedir(d);
114 return 0;
115}
116
117int twrpTar::Split_Archive(string Path, string fn)
118{
119 string temp = fn + "%03i";
120 char actual_filename[255];
121
122 Archive_File_Count = 0;
123 Archive_Current_Size = 0;
124 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
125 createTar(Path, actual_filename);
126 DataManager::GetValue(TW_HAS_DATA_MEDIA, has_data_media);
127 ui_print("Creating archive 1...\n");
128 if (Generate_Multiple_Archives(Path, temp) < 0) {
129 LOGE("Error generating file list\n");
130 return -1;
131 }
132 sprintf(actual_filename, temp.c_str(), Archive_File_Count);
133 closeTar(actual_filename, false);
134 LOGI("Done, created %i archives.\n", (Archive_File_Count++));
135 return (Archive_File_Count);
136}
137
138int twrpTar::extractTar(string rootdir, string fn) {
139 char* charRootDir = (char*) rootdir.c_str();
140 bool gzip = false;
141 if (openTar(rootdir, fn, gzip) == -1)
142 return -1;
143 if (tar_extract_all(t, charRootDir) != 0) {
144 LOGE("Unable to extract tar archive '%s'\n", fn.c_str());
145 return -1;
146 }
147 if (tar_close(t) != 0) {
148 LOGE("Unable to close tar file\n");
149 return -1;
150 }
151 return 0;
152}
153
154int twrpTar::extract(string rootdir, string fn) {
155 int len = 3;
156 char header[len];
157 string::size_type i = 0;
158 int firstbyte = 0;
159 int secondbyte = 0;
160 int ret;
161 ifstream f;
162 f.open(fn.c_str(), ios::in | ios::binary);
163 f.get(header, len);
164 firstbyte = header[i] & 0xff;
165 secondbyte = header[++i] & 0xff;
166 f.close();
167 if (firstbyte == 0x1f && secondbyte == 0x8b) {
168 //if you return the extractTGZ function directly, stack crashes happen
169 LOGI("Extracting gzipped tar\n");
170 ret = extractTGZ(rootdir, fn);
171 return ret;
172 }
173 else {
174 LOGI("Extracting uncompressed tar\n");
175 return extractTar(rootdir, fn);
176 }
177}
178
179int twrpTar::tarDirs(string dir, string fn, bool include_root) {
180 DIR* d;
181 string mainfolder = dir + "/", subfolder;
182 char buf[1024];
183 char* charTarFile = (char*) fn.c_str();
184 d = opendir(dir.c_str());
185 if (d != NULL) {
186 struct dirent* de;
187 while ((de = readdir(d)) != NULL) {
188 LOGI("adding %s\n", de->d_name);
189#ifdef RECOVERY_SDCARD_ON_DATA
190 if ((dir == "/data" || dir == "/data/") && strcmp(de->d_name, "media") == 0) continue;
191#endif
192 if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue;
193
194 subfolder = mainfolder;
195 subfolder += de->d_name;
196 strcpy(buf, subfolder.c_str());
197 if (de->d_type == DT_DIR) {
198 if (include_root) {
199 if (tar_append_tree(t, buf, NULL) != 0) {
200 LOGE("Error appending '%s' to tar archive '%s'\n", buf, charTarFile);
201 return -1;
202 }
203 } else {
204 string temp = Strip_Root_Dir(buf);
205 char* charTarPath = (char*) temp.c_str();
206 if (tar_append_tree(t, buf, charTarPath) != 0) {
207 LOGE("Error appending '%s' to tar archive '%s'\n", buf, charTarFile);
208 return -1;
209 }
210 }
211 } else if (dir != "/" && (de->d_type == DT_REG || de->d_type == DT_LNK)) {
212 if (addFile(buf, include_root) != 0)
213 return -1;
214 }
215 fflush(NULL);
216 }
217 closedir(d);
218 }
219 return 0;
220}
221
222int twrpTar::createTGZ(string dir, string fn) {
223 bool gzip = true;
224 if (createTar(dir, fn) == -1)
225 return -1;
226 if (tarDirs(dir, fn, false) == -1)
227 return -1;
228 if (closeTar(fn, gzip) == -1)
229 return -1;
230 return 0;
231}
232
233int twrpTar::create(string dir, string fn) {
234 bool gzip = false;
235 if (createTar(dir, fn) == -1)
236 return -1;
237 if (tarDirs(dir, fn, false) == -1)
238 return -1;
239 if (closeTar(fn, gzip) == -1)
240 return -1;
241 return 0;
242}
243
244int twrpTar::addFilesToExistingTar(vector <string> files, string fn) {
245 char* charTarFile = (char*) fn.c_str();
246
247 if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) == -1)
248 return -1;
249 removeEOT(charTarFile);
250 if (tar_open(&t, charTarFile, NULL, O_WRONLY | O_APPEND | O_LARGEFILE, 0644, TAR_GNU) == -1)
251 return -1;
252 for (unsigned int i = 0; i < files.size(); ++i) {
253 char* file = (char*) files.at(i).c_str();
254 if (tar_append_file(t, file, file) == -1)
255 return -1;
256 }
257 if (tar_append_eof(t) == -1)
258 return -1;
259 if (tar_close(t) == -1)
260 return -1;
261 return 0;
262}
263
264int twrpTar::createTar(string rootdir, string fn) {
265 char* charTarFile = (char*) fn.c_str();
266 char* charRootDir = (char*) rootdir.c_str();
267 int use_compression = 0;
268
269 DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression);
270 LOGI("2nd compression\n");
271 if (use_compression) {
272 string cmd = "pigz - > '" + fn + "'";
273 p = popen(cmd.c_str(), "w");
274 fd = fileno(p);
275 if (!p) return -1;
276 if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) != 0) {
277 pclose(p);
278 return -1;
279 }
280 }
281 else {
282 if (tar_open(&t, charTarFile, NULL, O_WRONLY | O_CREAT | O_LARGEFILE, 0644, TAR_GNU) == -1)
283 return -1;
284 }
285 return 0;
286}
287
288int twrpTar::openTar(string rootdir, string fn, bool gzip) {
289 char* charRootDir = (char*) rootdir.c_str();
290 char* charTarFile = (char*) fn.c_str();
291
292 if (gzip) {
293 LOGI("Opening as a gzip\n");
294 string cmd = "pigz -d -c '" + fn + "'";
295 FILE* pipe = popen(cmd.c_str(), "r");
296 int fd = fileno(pipe);
297 if (!pipe) return -1;
298 if(tar_fdopen(&t, fd, charRootDir, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) != 0) {
299 LOGI("tar_fdopen returned error\n");
300 pclose(pipe);
301 return -1;
302 }
303 }
304 else {
305 if (tar_open(&t, charTarFile, NULL, O_RDONLY | O_LARGEFILE, 0644, TAR_GNU) != 0) {
306 LOGE("Unable to open tar archive '%s'\n", charTarFile);
307 return -1;
308 }
309 }
310 return 0;
311}
312
313string twrpTar::Strip_Root_Dir(string Path) {
314 string temp;
315 size_t slash;
316
317 if (Path.substr(0, 1) == "/")
318 temp = Path.substr(1, Path.size() - 1);
319 else
320 temp = Path;
321 slash = temp.find("/");
322 if (slash == string::npos)
323 return temp;
324 else {
325 string stripped;
326
327 stripped = temp.substr(slash, temp.size() - slash);
328 return stripped;
329 }
330 return temp;
331}
332
333int twrpTar::addFile(string fn, bool include_root) {
334 char* charTarFile = (char*) fn.c_str();
335 if (include_root) {
336 if (tar_append_file(t, charTarFile, NULL) == -1)
337 return -1;
338 } else {
339 string temp = Strip_Root_Dir(fn);
340 char* charTarPath = (char*) temp.c_str();
341 if (tar_append_file(t, charTarFile, charTarPath) == -1)
342 return -1;
343 }
344 return 0;
345}
346
347int twrpTar::closeTar(string fn, bool gzip) {
348 int use_compression;
349 DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression);
350
351 if (tar_append_eof(t) != 0) {
352 LOGE("tar_append_eof(): %s\n", strerror(errno));
353 tar_close(t);
354 return -1;
355 }
356 if (tar_close(t) != 0) {
357 LOGE("Unable to close tar archive: '%s'\n", fn.c_str());
358 return -1;
359 }
360 if (use_compression || gzip) {
361 LOGI("Closing popen and fd\n");
362 pclose(p);
363 close(fd);
364 }
365 return 0;
366}
367
368int twrpTar::removeEOT(string tarFile) {
369 char* charTarFile = (char*) tarFile.c_str();
370 off_t tarFileEnd;
371 while (th_read(t) == 0) {
372 if (TH_ISREG(t))
373 tar_skip_regfile(t);
374 tarFileEnd = lseek(t->fd, 0, SEEK_CUR);
375 }
376 if (tar_close(t) == -1)
377 return -1;
378 if (truncate(charTarFile, tarFileEnd) == -1)
379 return -1;
380 return 0;
381}
382
383int twrpTar::compress(string fn) {
384 string cmd = "pigz " + fn;
385 p = popen(cmd.c_str(), "r");
386 if (!p) return -1;
387 char buffer[128];
388 string result = "";
389 while(!feof(p)) {
390 if(fgets(buffer, 128, p) != NULL)
391 result += buffer;
392 }
393 pclose(p);
394 return 0;
395}
396
397int twrpTar::extractTGZ(string rootdir, string fn) {
398 string splatrootdir(rootdir);
399 bool gzip = true;
400 char* splatCharRootDir = (char*) splatrootdir.c_str();
401 if (openTar(rootdir, fn, gzip) == -1)
402 return -1;
403 int ret = tar_extract_all(t, splatCharRootDir);
404 if (tar_close(t) != 0) {
405 LOGE("Unable to close tar file\n");
406 return -1;
407 }
408 return 0;
409}