blob: 04dbee967c9777f8c1e6a2e01a68757dec152550 [file] [log] [blame]
Dees Troy3be70a82013-10-22 14:25:12 +00001/*
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*/
Dees_Troy51a0e822012-09-05 15:24:24 -040018
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <sys/stat.h>
23#include <sys/vfs.h>
24#include <unistd.h>
Dees_Troy5bf43922012-09-07 16:07:55 -040025#include <vector>
Dees_Troy63c8df72012-09-10 14:02:05 -040026#include <dirent.h>
27#include <time.h>
Dees_Troy8170a922012-09-18 15:40:25 -040028#include <errno.h>
29#include <fcntl.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050030#include <iostream>
31#include <iomanip>
Dees_Troy51a0e822012-09-05 15:24:24 -040032#include "variables.h"
Dees_Troy2673cec2013-04-02 20:22:16 +000033#include "twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040034#include "partitions.hpp"
Dees_Troy5bf43922012-09-07 16:07:55 -040035#include "data.hpp"
Dees_Troy38bd7602012-09-14 13:33:53 -040036#include "twrp-functions.hpp"
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -040037#include "fixPermissions.hpp"
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -050038#include "twrpDigest.hpp"
bigbiff bigbiff34684ff2013-12-01 21:03:45 -050039#include "twrpDU.hpp"
Dees_Troy38bd7602012-09-14 13:33:53 -040040
Dees Troy6f6441d2014-01-23 02:07:03 +000041extern "C" {
42 #include "cutils/properties.h"
43}
44
Dees_Troy5bf43922012-09-07 16:07:55 -040045#ifdef TW_INCLUDE_CRYPTO
46 #ifdef TW_INCLUDE_JB_CRYPTO
47 #include "crypto/jb/cryptfs.h"
48 #else
49 #include "crypto/ics/cryptfs.h"
50 #endif
Dees_Troy5bf43922012-09-07 16:07:55 -040051#endif
Dees_Troy51a0e822012-09-05 15:24:24 -040052
bigbiff bigbiff34684ff2013-12-01 21:03:45 -050053TWPartitionManager::TWPartitionManager(void) {
54}
55
Dees_Troy51a0e822012-09-05 15:24:24 -040056int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error) {
Dees_Troy5bf43922012-09-07 16:07:55 -040057 FILE *fstabFile;
58 char fstab_line[MAX_FSTAB_LINE_LENGTH];
Dees_Troya13d74f2013-03-24 08:54:55 -050059 bool Found_Settings_Storage = false;
Dees_Troy5bf43922012-09-07 16:07:55 -040060
61 fstabFile = fopen(Fstab_Filename.c_str(), "rt");
62 if (fstabFile == NULL) {
Dees_Troy2673cec2013-04-02 20:22:16 +000063 LOGERR("Critical Error: Unable to open fstab at '%s'.\n", Fstab_Filename.c_str());
Dees_Troy5bf43922012-09-07 16:07:55 -040064 return false;
65 }
66
67 while (fgets(fstab_line, sizeof(fstab_line), fstabFile) != NULL) {
68 if (fstab_line[0] != '/')
69 continue;
70
Dees_Troy2a923582012-09-20 12:13:34 -040071 if (fstab_line[strlen(fstab_line) - 1] != '\n')
72 fstab_line[strlen(fstab_line)] = '\n';
73
Dees_Troy5bf43922012-09-07 16:07:55 -040074 TWPartition* partition = new TWPartition();
Dees_Troy2a923582012-09-20 12:13:34 -040075 string line = fstab_line;
Dees_Troyab10ee22012-09-21 14:27:30 -040076 memset(fstab_line, 0, sizeof(fstab_line));
Dees_Troy2a923582012-09-20 12:13:34 -040077
Dees_Troy5bf43922012-09-07 16:07:55 -040078 if (partition->Process_Fstab_Line(line, Display_Error)) {
Dees_Troya13d74f2013-03-24 08:54:55 -050079 if (!Found_Settings_Storage && partition->Is_Settings_Storage) {
80 Found_Settings_Storage = true;
81 Partitions.push_back(partition);
82 DataManager::SetValue("tw_settings_path", partition->Storage_Path);
83 DataManager::SetValue("tw_storage_path", partition->Storage_Path);
Dees_Troy2673cec2013-04-02 20:22:16 +000084 LOGINFO("Settings storage is '%s'\n", partition->Storage_Path.c_str());
Dees_Troya13d74f2013-03-24 08:54:55 -050085 } else {
86 partition->Is_Settings_Storage = false;
87 Partitions.push_back(partition);
88 }
Dees_Troy5bf43922012-09-07 16:07:55 -040089 } else {
90 delete partition;
91 }
92 }
93 fclose(fstabFile);
Dees_Troya13d74f2013-03-24 08:54:55 -050094 if (!Found_Settings_Storage) {
95 std::vector<TWPartition*>::iterator iter;
96 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
97 if ((*iter)->Is_Storage) {
98 (*iter)->Is_Settings_Storage = true;
Ethan Yonkerd4d10732014-02-03 15:27:52 -060099#ifndef RECOVERY_SDCARD_ON_DATA
100 (*iter)->Setup_AndSec();
101#endif
Dees_Troya13d74f2013-03-24 08:54:55 -0500102 Found_Settings_Storage = true;
103 DataManager::SetValue("tw_settings_path", (*iter)->Storage_Path);
104 DataManager::SetValue("tw_storage_path", (*iter)->Storage_Path);
Dees_Troy2673cec2013-04-02 20:22:16 +0000105 LOGINFO("Settings storage is '%s'\n", (*iter)->Storage_Path.c_str());
Dees_Troya13d74f2013-03-24 08:54:55 -0500106 break;
107 }
108 }
109 if (!Found_Settings_Storage)
Dees_Troy2673cec2013-04-02 20:22:16 +0000110 LOGERR("Unable to locate storage partition for storing settings file.\n");
Dees_Troya13d74f2013-03-24 08:54:55 -0500111 }
Dees_Troy5bf43922012-09-07 16:07:55 -0400112 if (!Write_Fstab()) {
113 if (Display_Error)
Dees_Troy2673cec2013-04-02 20:22:16 +0000114 LOGERR("Error creating fstab\n");
Dees_Troy5bf43922012-09-07 16:07:55 -0400115 else
Dees_Troy2673cec2013-04-02 20:22:16 +0000116 LOGINFO("Error creating fstab\n");
Dees_Troy5bf43922012-09-07 16:07:55 -0400117 }
Dees_Troy51127312012-09-08 13:08:49 -0400118 Update_System_Details();
Dees_Troyd0384ef2012-10-12 12:15:42 -0400119 UnMount_Main_Partitions();
Dees_Troy5bf43922012-09-07 16:07:55 -0400120 return true;
121}
122
123int TWPartitionManager::Write_Fstab(void) {
124 FILE *fp;
125 std::vector<TWPartition*>::iterator iter;
126 string Line;
127
128 fp = fopen("/etc/fstab", "w");
129 if (fp == NULL) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000130 LOGINFO("Can not open /etc/fstab.\n");
Dees_Troy5bf43922012-09-07 16:07:55 -0400131 return false;
132 }
Dees_Troy63c8df72012-09-10 14:02:05 -0400133 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
Dees_Troy51127312012-09-08 13:08:49 -0400134 if ((*iter)->Can_Be_Mounted) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400135 Line = (*iter)->Actual_Block_Device + " " + (*iter)->Mount_Point + " " + (*iter)->Current_File_System + " rw\n";
Dees_Troy5bf43922012-09-07 16:07:55 -0400136 fputs(Line.c_str(), fp);
Dees_Troy91862e62013-04-04 23:48:21 +0000137 }
138 // Handle subpartition tracking
139 if ((*iter)->Is_SubPartition) {
140 TWPartition* ParentPartition = Find_Partition_By_Path((*iter)->SubPartition_Of);
141 if (ParentPartition)
142 ParentPartition->Has_SubPartition = true;
143 else
144 LOGERR("Unable to locate parent partition '%s' of '%s'\n", (*iter)->SubPartition_Of.c_str(), (*iter)->Mount_Point.c_str());
Dees_Troy5bf43922012-09-07 16:07:55 -0400145 }
146 }
147 fclose(fp);
148 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400149}
150
Dees_Troy8170a922012-09-18 15:40:25 -0400151void TWPartitionManager::Output_Partition_Logging(void) {
152 std::vector<TWPartition*>::iterator iter;
153
154 printf("\n\nPartition Logs:\n");
155 for (iter = Partitions.begin(); iter != Partitions.end(); iter++)
156 Output_Partition((*iter));
157}
158
159void TWPartitionManager::Output_Partition(TWPartition* Part) {
160 unsigned long long mb = 1048576;
161
Gary Peck004d48b2012-11-21 16:28:18 -0800162 printf("%s | %s | Size: %iMB", Part->Mount_Point.c_str(), Part->Actual_Block_Device.c_str(), (int)(Part->Size / mb));
Dees_Troy8170a922012-09-18 15:40:25 -0400163 if (Part->Can_Be_Mounted) {
Gary Peck004d48b2012-11-21 16:28:18 -0800164 printf(" Used: %iMB Free: %iMB Backup Size: %iMB", (int)(Part->Used / mb), (int)(Part->Free / mb), (int)(Part->Backup_Size / mb));
Dees_Troy8170a922012-09-18 15:40:25 -0400165 }
Gary Peck004d48b2012-11-21 16:28:18 -0800166 printf("\n Flags: ");
Dees_Troya13d74f2013-03-24 08:54:55 -0500167 if (Part->Can_Be_Mounted)
168 printf("Can_Be_Mounted ");
Gary Peck004d48b2012-11-21 16:28:18 -0800169 if (Part->Can_Be_Wiped)
170 printf("Can_Be_Wiped ");
Hashcodedabfd492013-08-29 22:45:30 -0700171 if (Part->Use_Rm_Rf)
172 printf("Use_Rm_Rf ");
Dees_Troya13d74f2013-03-24 08:54:55 -0500173 if (Part->Can_Be_Backed_Up)
174 printf("Can_Be_Backed_Up ");
Gary Peck004d48b2012-11-21 16:28:18 -0800175 if (Part->Wipe_During_Factory_Reset)
176 printf("Wipe_During_Factory_Reset ");
177 if (Part->Wipe_Available_in_GUI)
178 printf("Wipe_Available_in_GUI ");
179 if (Part->Is_SubPartition)
180 printf("Is_SubPartition ");
181 if (Part->Has_SubPartition)
182 printf("Has_SubPartition ");
183 if (Part->Removable)
184 printf("Removable ");
185 if (Part->Is_Present)
186 printf("IsPresent ");
187 if (Part->Can_Be_Encrypted)
188 printf("Can_Be_Encrypted ");
189 if (Part->Is_Encrypted)
190 printf("Is_Encrypted ");
191 if (Part->Is_Decrypted)
192 printf("Is_Decrypted ");
193 if (Part->Has_Data_Media)
194 printf("Has_Data_Media ");
Dees_Troy83bd4832013-05-04 12:39:56 +0000195 if (Part->Can_Encrypt_Backup)
196 printf("Can_Encrypt_Backup ");
197 if (Part->Use_Userdata_Encryption)
198 printf("Use_Userdata_Encryption ");
Gary Peck004d48b2012-11-21 16:28:18 -0800199 if (Part->Has_Android_Secure)
200 printf("Has_Android_Secure ");
201 if (Part->Is_Storage)
202 printf("Is_Storage ");
Dees_Troya13d74f2013-03-24 08:54:55 -0500203 if (Part->Is_Settings_Storage)
204 printf("Is_Settings_Storage ");
Dees_Troy68cab492012-12-12 19:29:35 +0000205 if (Part->Ignore_Blkid)
206 printf("Ignore_Blkid ");
Dees_Troy16c2b312013-01-15 16:51:18 +0000207 if (Part->Retain_Layout_Version)
208 printf("Retain_Layout_Version ");
Gary Peck004d48b2012-11-21 16:28:18 -0800209 printf("\n");
210 if (!Part->SubPartition_Of.empty())
211 printf(" SubPartition_Of: %s\n", Part->SubPartition_Of.c_str());
212 if (!Part->Symlink_Path.empty())
213 printf(" Symlink_Path: %s\n", Part->Symlink_Path.c_str());
214 if (!Part->Symlink_Mount_Point.empty())
215 printf(" Symlink_Mount_Point: %s\n", Part->Symlink_Mount_Point.c_str());
216 if (!Part->Primary_Block_Device.empty())
217 printf(" Primary_Block_Device: %s\n", Part->Primary_Block_Device.c_str());
218 if (!Part->Alternate_Block_Device.empty())
219 printf(" Alternate_Block_Device: %s\n", Part->Alternate_Block_Device.c_str());
220 if (!Part->Decrypted_Block_Device.empty())
221 printf(" Decrypted_Block_Device: %s\n", Part->Decrypted_Block_Device.c_str());
222 if (Part->Length != 0)
223 printf(" Length: %i\n", Part->Length);
224 if (!Part->Display_Name.empty())
225 printf(" Display_Name: %s\n", Part->Display_Name.c_str());
Dees_Troya13d74f2013-03-24 08:54:55 -0500226 if (!Part->Storage_Name.empty())
227 printf(" Storage_Name: %s\n", Part->Storage_Name.c_str());
Gary Peck004d48b2012-11-21 16:28:18 -0800228 if (!Part->Backup_Path.empty())
229 printf(" Backup_Path: %s\n", Part->Backup_Path.c_str());
230 if (!Part->Backup_Name.empty())
231 printf(" Backup_Name: %s\n", Part->Backup_Name.c_str());
Dees_Troya13d74f2013-03-24 08:54:55 -0500232 if (!Part->Backup_Display_Name.empty())
233 printf(" Backup_Display_Name: %s\n", Part->Backup_Display_Name.c_str());
Gary Peck004d48b2012-11-21 16:28:18 -0800234 if (!Part->Backup_FileName.empty())
235 printf(" Backup_FileName: %s\n", Part->Backup_FileName.c_str());
236 if (!Part->Storage_Path.empty())
237 printf(" Storage_Path: %s\n", Part->Storage_Path.c_str());
238 if (!Part->Current_File_System.empty())
239 printf(" Current_File_System: %s\n", Part->Current_File_System.c_str());
240 if (!Part->Fstab_File_System.empty())
241 printf(" Fstab_File_System: %s\n", Part->Fstab_File_System.c_str());
242 if (Part->Format_Block_Size != 0)
243 printf(" Format_Block_Size: %i\n", Part->Format_Block_Size);
Dees_Troy094207a2012-09-26 12:00:39 -0400244 if (!Part->MTD_Name.empty())
245 printf(" MTD_Name: %s\n", Part->MTD_Name.c_str());
Dees_Troy8170a922012-09-18 15:40:25 -0400246 string back_meth = Part->Backup_Method_By_Name();
247 printf(" Backup_Method: %s\n\n", back_meth.c_str());
Hashcode62bd9e02013-11-19 21:59:42 -0800248 if (Part->Mount_Flags || !Part->Mount_Options.empty())
249 printf(" Mount_Flags=0x%8x, Mount_Options=%s\n", Part->Mount_Flags, Part->Mount_Options.c_str());
Dees_Troy8170a922012-09-18 15:40:25 -0400250}
251
Dees_Troy51a0e822012-09-05 15:24:24 -0400252int TWPartitionManager::Mount_By_Path(string Path, bool Display_Error) {
Dees_Troy5bf43922012-09-07 16:07:55 -0400253 std::vector<TWPartition*>::iterator iter;
254 int ret = false;
255 bool found = false;
Dees_Troy38bd7602012-09-14 13:33:53 -0400256 string Local_Path = TWFunc::Get_Root_Path(Path);
Dees_Troy5bf43922012-09-07 16:07:55 -0400257
Dees_Troyd93bda52013-07-03 19:55:19 +0000258 if (Local_Path == "/tmp" || Local_Path == "/")
Dees_Troy43d8b002012-09-17 16:00:01 -0400259 return true;
260
Dees_Troy5bf43922012-09-07 16:07:55 -0400261 // Iterate through all partitions
262 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
Dees_Troy657c3092012-09-10 20:32:10 -0400263 if ((*iter)->Mount_Point == Local_Path || (!(*iter)->Symlink_Mount_Point.empty() && (*iter)->Symlink_Mount_Point == Local_Path)) {
Dees_Troy5bf43922012-09-07 16:07:55 -0400264 ret = (*iter)->Mount(Display_Error);
265 found = true;
Dees_Troy51127312012-09-08 13:08:49 -0400266 } else if ((*iter)->Is_SubPartition && (*iter)->SubPartition_Of == Local_Path) {
Dees_Troy5bf43922012-09-07 16:07:55 -0400267 (*iter)->Mount(Display_Error);
Dees_Troy51127312012-09-08 13:08:49 -0400268 }
Dees_Troy5bf43922012-09-07 16:07:55 -0400269 }
270 if (found) {
271 return ret;
272 } else if (Display_Error) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000273 LOGERR("Mount: Unable to find partition for path '%s'\n", Local_Path.c_str());
Dees_Troy5bf43922012-09-07 16:07:55 -0400274 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000275 LOGINFO("Mount: Unable to find partition for path '%s'\n", Local_Path.c_str());
Dees_Troy5bf43922012-09-07 16:07:55 -0400276 }
277 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400278}
279
280int TWPartitionManager::Mount_By_Block(string Block, bool Display_Error) {
Dees_Troy51127312012-09-08 13:08:49 -0400281 TWPartition* Part = Find_Partition_By_Block(Block);
Dees_Troy5bf43922012-09-07 16:07:55 -0400282
Dees_Troy51127312012-09-08 13:08:49 -0400283 if (Part) {
284 if (Part->Has_SubPartition) {
285 std::vector<TWPartition*>::iterator subpart;
286
287 for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
288 if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point)
289 (*subpart)->Mount(Display_Error);
290 }
291 return Part->Mount(Display_Error);
292 } else
293 return Part->Mount(Display_Error);
Dees_Troy5bf43922012-09-07 16:07:55 -0400294 }
295 if (Display_Error)
Dees_Troy2673cec2013-04-02 20:22:16 +0000296 LOGERR("Mount: Unable to find partition for block '%s'\n", Block.c_str());
Dees_Troy5bf43922012-09-07 16:07:55 -0400297 else
Dees_Troy2673cec2013-04-02 20:22:16 +0000298 LOGINFO("Mount: Unable to find partition for block '%s'\n", Block.c_str());
Dees_Troy5bf43922012-09-07 16:07:55 -0400299 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400300}
301
302int TWPartitionManager::Mount_By_Name(string Name, bool Display_Error) {
Dees_Troy51127312012-09-08 13:08:49 -0400303 TWPartition* Part = Find_Partition_By_Name(Name);
Dees_Troy5bf43922012-09-07 16:07:55 -0400304
Dees_Troy51127312012-09-08 13:08:49 -0400305 if (Part) {
306 if (Part->Has_SubPartition) {
307 std::vector<TWPartition*>::iterator subpart;
308
309 for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
310 if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point)
311 (*subpart)->Mount(Display_Error);
312 }
313 return Part->Mount(Display_Error);
314 } else
315 return Part->Mount(Display_Error);
Dees_Troy5bf43922012-09-07 16:07:55 -0400316 }
317 if (Display_Error)
Dees_Troy2673cec2013-04-02 20:22:16 +0000318 LOGERR("Mount: Unable to find partition for name '%s'\n", Name.c_str());
Dees_Troy5bf43922012-09-07 16:07:55 -0400319 else
Dees_Troy2673cec2013-04-02 20:22:16 +0000320 LOGINFO("Mount: Unable to find partition for name '%s'\n", Name.c_str());
Dees_Troy5bf43922012-09-07 16:07:55 -0400321 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400322}
323
324int TWPartitionManager::UnMount_By_Path(string Path, bool Display_Error) {
Dees_Troy51127312012-09-08 13:08:49 -0400325 std::vector<TWPartition*>::iterator iter;
326 int ret = false;
327 bool found = false;
Dees_Troy38bd7602012-09-14 13:33:53 -0400328 string Local_Path = TWFunc::Get_Root_Path(Path);
Dees_Troy51127312012-09-08 13:08:49 -0400329
330 // Iterate through all partitions
331 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
Dees_Troy657c3092012-09-10 20:32:10 -0400332 if ((*iter)->Mount_Point == Local_Path || (!(*iter)->Symlink_Mount_Point.empty() && (*iter)->Symlink_Mount_Point == Local_Path)) {
Dees_Troy51127312012-09-08 13:08:49 -0400333 ret = (*iter)->UnMount(Display_Error);
334 found = true;
335 } else if ((*iter)->Is_SubPartition && (*iter)->SubPartition_Of == Local_Path) {
336 (*iter)->UnMount(Display_Error);
337 }
338 }
339 if (found) {
340 return ret;
341 } else if (Display_Error) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000342 LOGERR("UnMount: Unable to find partition for path '%s'\n", Local_Path.c_str());
Dees_Troy51127312012-09-08 13:08:49 -0400343 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000344 LOGINFO("UnMount: Unable to find partition for path '%s'\n", Local_Path.c_str());
Dees_Troy51127312012-09-08 13:08:49 -0400345 }
346 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400347}
348
349int TWPartitionManager::UnMount_By_Block(string Block, bool Display_Error) {
Dees_Troy51127312012-09-08 13:08:49 -0400350 TWPartition* Part = Find_Partition_By_Block(Block);
351
352 if (Part) {
353 if (Part->Has_SubPartition) {
354 std::vector<TWPartition*>::iterator subpart;
355
356 for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
357 if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point)
358 (*subpart)->UnMount(Display_Error);
359 }
360 return Part->UnMount(Display_Error);
361 } else
362 return Part->UnMount(Display_Error);
363 }
364 if (Display_Error)
Dees_Troy2673cec2013-04-02 20:22:16 +0000365 LOGERR("UnMount: Unable to find partition for block '%s'\n", Block.c_str());
Dees_Troy51127312012-09-08 13:08:49 -0400366 else
Dees_Troy2673cec2013-04-02 20:22:16 +0000367 LOGINFO("UnMount: Unable to find partition for block '%s'\n", Block.c_str());
Dees_Troy51127312012-09-08 13:08:49 -0400368 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400369}
370
371int TWPartitionManager::UnMount_By_Name(string Name, bool Display_Error) {
Dees_Troy51127312012-09-08 13:08:49 -0400372 TWPartition* Part = Find_Partition_By_Name(Name);
373
374 if (Part) {
375 if (Part->Has_SubPartition) {
376 std::vector<TWPartition*>::iterator subpart;
377
378 for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
379 if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point)
380 (*subpart)->UnMount(Display_Error);
381 }
382 return Part->UnMount(Display_Error);
383 } else
384 return Part->UnMount(Display_Error);
385 }
386 if (Display_Error)
Dees_Troy2673cec2013-04-02 20:22:16 +0000387 LOGERR("UnMount: Unable to find partition for name '%s'\n", Name.c_str());
Dees_Troy51127312012-09-08 13:08:49 -0400388 else
Dees_Troy2673cec2013-04-02 20:22:16 +0000389 LOGINFO("UnMount: Unable to find partition for name '%s'\n", Name.c_str());
Dees_Troy51127312012-09-08 13:08:49 -0400390 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400391}
392
393int TWPartitionManager::Is_Mounted_By_Path(string Path) {
Dees_Troy51127312012-09-08 13:08:49 -0400394 TWPartition* Part = Find_Partition_By_Path(Path);
395
396 if (Part)
397 return Part->Is_Mounted();
398 else
Dees_Troy2673cec2013-04-02 20:22:16 +0000399 LOGINFO("Is_Mounted: Unable to find partition for path '%s'\n", Path.c_str());
Dees_Troy51127312012-09-08 13:08:49 -0400400 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400401}
402
403int TWPartitionManager::Is_Mounted_By_Block(string Block) {
Dees_Troy51127312012-09-08 13:08:49 -0400404 TWPartition* Part = Find_Partition_By_Block(Block);
405
406 if (Part)
407 return Part->Is_Mounted();
408 else
Dees_Troy2673cec2013-04-02 20:22:16 +0000409 LOGINFO("Is_Mounted: Unable to find partition for block '%s'\n", Block.c_str());
Dees_Troy51127312012-09-08 13:08:49 -0400410 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400411}
412
413int TWPartitionManager::Is_Mounted_By_Name(string Name) {
Dees_Troy51127312012-09-08 13:08:49 -0400414 TWPartition* Part = Find_Partition_By_Name(Name);
415
416 if (Part)
417 return Part->Is_Mounted();
418 else
Dees_Troy2673cec2013-04-02 20:22:16 +0000419 LOGINFO("Is_Mounted: Unable to find partition for name '%s'\n", Name.c_str());
Dees_Troy51127312012-09-08 13:08:49 -0400420 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400421}
422
Dees_Troy5bf43922012-09-07 16:07:55 -0400423int TWPartitionManager::Mount_Current_Storage(bool Display_Error) {
Dees_Troy51127312012-09-08 13:08:49 -0400424 string current_storage_path = DataManager::GetCurrentStoragePath();
425
426 if (Mount_By_Path(current_storage_path, Display_Error)) {
427 TWPartition* FreeStorage = Find_Partition_By_Path(current_storage_path);
428 if (FreeStorage)
429 DataManager::SetValue(TW_STORAGE_FREE_SIZE, (int)(FreeStorage->Free / 1048576LLU));
430 return true;
431 }
432 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400433}
434
Dees_Troy5bf43922012-09-07 16:07:55 -0400435int TWPartitionManager::Mount_Settings_Storage(bool Display_Error) {
436 return Mount_By_Path(DataManager::GetSettingsStoragePath(), Display_Error);
437}
438
439TWPartition* TWPartitionManager::Find_Partition_By_Path(string Path) {
440 std::vector<TWPartition*>::iterator iter;
Dees_Troy38bd7602012-09-14 13:33:53 -0400441 string Local_Path = TWFunc::Get_Root_Path(Path);
Dees_Troy5bf43922012-09-07 16:07:55 -0400442
443 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
Dees_Troy657c3092012-09-10 20:32:10 -0400444 if ((*iter)->Mount_Point == Local_Path || (!(*iter)->Symlink_Mount_Point.empty() && (*iter)->Symlink_Mount_Point == Local_Path))
Dees_Troy5bf43922012-09-07 16:07:55 -0400445 return (*iter);
446 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400447 return NULL;
448}
449
Dees_Troy5bf43922012-09-07 16:07:55 -0400450TWPartition* TWPartitionManager::Find_Partition_By_Block(string Block) {
Dees_Troy51127312012-09-08 13:08:49 -0400451 std::vector<TWPartition*>::iterator iter;
452
453 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400454 if ((*iter)->Primary_Block_Device == Block || (*iter)->Alternate_Block_Device == Block || ((*iter)->Is_Decrypted && (*iter)->Decrypted_Block_Device == Block))
Dees_Troy51127312012-09-08 13:08:49 -0400455 return (*iter);
456 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400457 return NULL;
Dees_Troy5bf43922012-09-07 16:07:55 -0400458}
459
460TWPartition* TWPartitionManager::Find_Partition_By_Name(string Name) {
Dees_Troy51127312012-09-08 13:08:49 -0400461 std::vector<TWPartition*>::iterator iter;
462
463 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
464 if ((*iter)->Display_Name == Name)
465 return (*iter);
466 }
Dees_Troy5bf43922012-09-07 16:07:55 -0400467 return NULL;
468}
Dees_Troy51a0e822012-09-05 15:24:24 -0400469
Dees_Troyc9ff7a32012-09-27 10:09:41 -0400470int TWPartitionManager::Check_Backup_Name(bool Display_Error) {
471 // Check the backup name to ensure that it is the correct size and contains only valid characters
472 // and that a backup with that name doesn't already exist
473 char backup_name[MAX_BACKUP_NAME_LEN];
474 char backup_loc[255], tw_image_dir[255];
475 int copy_size;
476 int index, cur_char;
477 string Backup_Name, Backup_Loc;
478
479 DataManager::GetValue(TW_BACKUP_NAME, Backup_Name);
480 copy_size = Backup_Name.size();
481 // Check size
482 if (copy_size > MAX_BACKUP_NAME_LEN) {
483 if (Display_Error)
Dees_Troy2673cec2013-04-02 20:22:16 +0000484 LOGERR("Backup name is too long.\n");
Dees_Troyc9ff7a32012-09-27 10:09:41 -0400485 return -2;
486 }
487
488 // Check each character
489 strncpy(backup_name, Backup_Name.c_str(), copy_size);
Dees_Troya13d74f2013-03-24 08:54:55 -0500490 if (copy_size == 1 && strncmp(backup_name, "0", 1) == 0)
Dees_Troyc9ff7a32012-09-27 10:09:41 -0400491 return 0; // A "0" (zero) means to use the current timestamp for the backup name
492 for (index=0; index<copy_size; index++) {
493 cur_char = (int)backup_name[index];
494 if (cur_char == 32 || (cur_char >= 48 && cur_char <= 57) || (cur_char >= 65 && cur_char <= 91) || cur_char == 93 || cur_char == 95 || (cur_char >= 97 && cur_char <= 123) || cur_char == 125 || cur_char == 45 || cur_char == 46) {
495 // These are valid characters
496 // Numbers
497 // Upper case letters
498 // Lower case letters
499 // Space
500 // and -_.{}[]
501 } else {
502 if (Display_Error)
Dees_Troy2673cec2013-04-02 20:22:16 +0000503 LOGERR("Backup name '%s' contains invalid character: '%c'\n", backup_name, (char)cur_char);
Dees_Troyc9ff7a32012-09-27 10:09:41 -0400504 return -3;
505 }
506 }
507
508 // Check to make sure that a backup with this name doesn't already exist
509 DataManager::GetValue(TW_BACKUPS_FOLDER_VAR, Backup_Loc);
510 strcpy(backup_loc, Backup_Loc.c_str());
Dees_Troya13d74f2013-03-24 08:54:55 -0500511 sprintf(tw_image_dir,"%s/%s", backup_loc, Backup_Name.c_str());
Dees_Troyc9ff7a32012-09-27 10:09:41 -0400512 if (TWFunc::Path_Exists(tw_image_dir)) {
513 if (Display_Error)
Dees_Troy2673cec2013-04-02 20:22:16 +0000514 LOGERR("A backup with this name already exists.\n");
Dees_Troyc9ff7a32012-09-27 10:09:41 -0400515 return -4;
516 }
Dees_Troyc9ff7a32012-09-27 10:09:41 -0400517 // No problems found, return 0
518 return 0;
519}
520
Dees_Troy43d8b002012-09-17 16:00:01 -0400521bool TWPartitionManager::Make_MD5(bool generate_md5, string Backup_Folder, string Backup_Filename)
522{
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500523 string command;
Dees_Troy43d8b002012-09-17 16:00:01 -0400524 string Full_File = Backup_Folder + Backup_Filename;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500525 string result;
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500526 twrpDigest md5sum;
Dees_Troy43d8b002012-09-17 16:00:01 -0400527
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500528 if (!generate_md5)
Dees_Troy43d8b002012-09-17 16:00:01 -0400529 return true;
Dees_Troy43d8b002012-09-17 16:00:01 -0400530
Dees_Troyb46a6842012-09-25 11:06:46 -0400531 TWFunc::GUI_Operation_Text(TW_GENERATE_MD5_TEXT, "Generating MD5");
Dees_Troy2673cec2013-04-02 20:22:16 +0000532 gui_print(" * Generating md5...\n");
Dees_Troy43d8b002012-09-17 16:00:01 -0400533
534 if (TWFunc::Path_Exists(Full_File)) {
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500535 md5sum.setfn(Backup_Folder + Backup_Filename);
536 if (md5sum.computeMD5() == 0)
537 if (md5sum.write_md5digest() == 0)
Dees_Troy2673cec2013-04-02 20:22:16 +0000538 gui_print(" * MD5 Created.\n");
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500539 else
540 return -1;
541 else
Dees_Troy2673cec2013-04-02 20:22:16 +0000542 gui_print(" * MD5 Error!\n");
Dees_Troy43d8b002012-09-17 16:00:01 -0400543 } else {
544 char filename[512];
545 int index = 0;
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500546 string strfn;
Dees_Troy43d8b002012-09-17 16:00:01 -0400547 sprintf(filename, "%s%03i", Full_File.c_str(), index);
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500548 strfn = filename;
Dees_Troy83bd4832013-05-04 12:39:56 +0000549 while (index < 1000) {
bigbiff bigbiff65a4c732013-03-15 15:17:50 -0400550 md5sum.setfn(filename);
Dees_Troy83bd4832013-05-04 12:39:56 +0000551 if (TWFunc::Path_Exists(filename)) {
552 if (md5sum.computeMD5() == 0) {
553 if (md5sum.write_md5digest() != 0)
554 {
555 gui_print(" * MD5 Error.\n");
556 return false;
557 }
558 } else {
559 gui_print(" * Error computing MD5.\n");
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500560 return false;
561 }
562 }
Dees_Troy43d8b002012-09-17 16:00:01 -0400563 index++;
Dees_Troy4a2a1262012-09-18 09:33:47 -0400564 sprintf(filename, "%s%03i", Full_File.c_str(), index);
bigbiff bigbiffcdcfee42013-02-27 21:11:26 -0500565 strfn = filename;
Dees_Troy43d8b002012-09-17 16:00:01 -0400566 }
567 if (index == 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000568 LOGERR("Backup file: '%s' not found!\n", filename);
Dees_Troy43d8b002012-09-17 16:00:01 -0400569 return false;
570 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000571 gui_print(" * MD5 Created.\n");
Dees_Troy43d8b002012-09-17 16:00:01 -0400572 }
573 return true;
574}
575
Dees_Troy093b7642012-09-21 15:59:38 -0400576bool TWPartitionManager::Backup_Partition(TWPartition* Part, string Backup_Folder, bool generate_md5, unsigned long long* img_bytes_remaining, unsigned long long* file_bytes_remaining, unsigned long *img_time, unsigned long *file_time, unsigned long long *img_bytes, unsigned long long *file_bytes) {
Dees_Troy43d8b002012-09-17 16:00:01 -0400577 time_t start, stop;
bigbiff bigbiff2c57d782013-02-19 10:09:21 -0500578 int img_bps;
579 unsigned long long file_bps;
Dees_Troy093b7642012-09-21 15:59:38 -0400580 unsigned long total_time, remain_time, section_time;
581 int use_compression, backup_time;
582 float pos;
Dees_Troy43d8b002012-09-17 16:00:01 -0400583
584 if (Part == NULL)
585 return true;
586
Dees_Troy093b7642012-09-21 15:59:38 -0400587 DataManager::GetValue(TW_BACKUP_AVG_IMG_RATE, img_bps);
588
589 DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression);
590 if (use_compression)
591 DataManager::GetValue(TW_BACKUP_AVG_FILE_COMP_RATE, file_bps);
592 else
593 DataManager::GetValue(TW_BACKUP_AVG_FILE_RATE, file_bps);
594
595 // We know the speed for both, how far into the whole backup are we, based on time
596 total_time = (*img_bytes / (unsigned long)img_bps) + (*file_bytes / (unsigned long)file_bps);
597 remain_time = (*img_bytes_remaining / (unsigned long)img_bps) + (*file_bytes_remaining / (unsigned long)file_bps);
598
599 pos = (total_time - remain_time) / (float) total_time;
Dees_Troy2673cec2013-04-02 20:22:16 +0000600 DataManager::SetProgress(pos);
Dees_Troy093b7642012-09-21 15:59:38 -0400601
Dees_Troy2673cec2013-04-02 20:22:16 +0000602 LOGINFO("Estimated Total time: %lu Estimated remaining time: %lu\n", total_time, remain_time);
Dees_Troy093b7642012-09-21 15:59:38 -0400603
604 // And get the time
605 if (Part->Backup_Method == 1)
606 section_time = Part->Backup_Size / file_bps;
607 else
608 section_time = Part->Backup_Size / img_bps;
609
610 // Set the position
611 pos = section_time / (float) total_time;
Dees_Troy2673cec2013-04-02 20:22:16 +0000612 DataManager::ShowProgress(pos, section_time);
Dees_Troy093b7642012-09-21 15:59:38 -0400613
Dees_Troy43d8b002012-09-17 16:00:01 -0400614 time(&start);
615
616 if (Part->Backup(Backup_Folder)) {
Dees_Troy8170a922012-09-18 15:40:25 -0400617 if (Part->Has_SubPartition) {
618 std::vector<TWPartition*>::iterator subpart;
619
620 for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
Dees_Troya13d74f2013-03-24 08:54:55 -0500621 if ((*subpart)->Can_Be_Backed_Up && (*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point) {
Dees_Troy8170a922012-09-18 15:40:25 -0400622 if (!(*subpart)->Backup(Backup_Folder))
623 return false;
Dees_Troy2727b992013-08-14 20:09:30 +0000624 sync();
625 sync();
Dees_Troy8170a922012-09-18 15:40:25 -0400626 if (!Make_MD5(generate_md5, Backup_Folder, (*subpart)->Backup_FileName))
627 return false;
Dees_Troy093b7642012-09-21 15:59:38 -0400628 if (Part->Backup_Method == 1) {
629 *file_bytes_remaining -= (*subpart)->Backup_Size;
630 } else {
631 *img_bytes_remaining -= (*subpart)->Backup_Size;
632 }
Dees_Troy8170a922012-09-18 15:40:25 -0400633 }
634 }
635 }
Dees_Troy43d8b002012-09-17 16:00:01 -0400636 time(&stop);
Dees_Troy093b7642012-09-21 15:59:38 -0400637 backup_time = (int) difftime(stop, start);
Dees_Troy2673cec2013-04-02 20:22:16 +0000638 LOGINFO("Partition Backup time: %d\n", backup_time);
Dees_Troy43d8b002012-09-17 16:00:01 -0400639 if (Part->Backup_Method == 1) {
640 *file_bytes_remaining -= Part->Backup_Size;
Dees_Troy093b7642012-09-21 15:59:38 -0400641 *file_time += backup_time;
Dees_Troy43d8b002012-09-17 16:00:01 -0400642 } else {
643 *img_bytes_remaining -= Part->Backup_Size;
Dees_Troy093b7642012-09-21 15:59:38 -0400644 *img_time += backup_time;
Dees_Troy43d8b002012-09-17 16:00:01 -0400645 }
646 return Make_MD5(generate_md5, Backup_Folder, Part->Backup_FileName);
647 } else {
648 return false;
649 }
650}
651
652int TWPartitionManager::Run_Backup(void) {
653 int check, do_md5, partition_count = 0;
Dees_Troya13d74f2013-03-24 08:54:55 -0500654 string Backup_Folder, Backup_Name, Full_Backup_Path, Backup_List, backup_path;
Dees_Troy8170a922012-09-18 15:40:25 -0400655 unsigned long long total_bytes = 0, file_bytes = 0, img_bytes = 0, free_space = 0, img_bytes_remaining, file_bytes_remaining, subpart_size;
Dees_Troy43d8b002012-09-17 16:00:01 -0400656 unsigned long img_time = 0, file_time = 0;
Dees_Troya13d74f2013-03-24 08:54:55 -0500657 TWPartition* backup_part = NULL;
Dees_Troy43d8b002012-09-17 16:00:01 -0400658 TWPartition* storage = NULL;
Dees_Troy8170a922012-09-18 15:40:25 -0400659 std::vector<TWPartition*>::iterator subpart;
Dees_Troy43d8b002012-09-17 16:00:01 -0400660 struct tm *t;
661 time_t start, stop, seconds, total_start, total_stop;
Dees_Troya13d74f2013-03-24 08:54:55 -0500662 size_t start_pos = 0, end_pos = 0;
Dees_Troy43d8b002012-09-17 16:00:01 -0400663 seconds = time(0);
664 t = localtime(&seconds);
665
666 time(&total_start);
667
668 Update_System_Details();
669
670 if (!Mount_Current_Storage(true))
671 return false;
672
673 DataManager::GetValue(TW_SKIP_MD5_GENERATE_VAR, do_md5);
Dees_Troy4a2a1262012-09-18 09:33:47 -0400674 if (do_md5 == 0)
Dees_Troy43d8b002012-09-17 16:00:01 -0400675 do_md5 = true;
Dees_Troyc5865ab2012-09-24 15:08:04 -0400676 else
677 do_md5 = false;
Dees_Troy4a2a1262012-09-18 09:33:47 -0400678
Dees_Troy43d8b002012-09-17 16:00:01 -0400679 DataManager::GetValue(TW_BACKUPS_FOLDER_VAR, Backup_Folder);
680 DataManager::GetValue(TW_BACKUP_NAME, Backup_Name);
Dees Troyb21cc642013-09-10 17:36:41 +0000681 if (Backup_Name == "(Current Date)") {
682 Backup_Name = TWFunc::Get_Current_Date();
683 } else if (Backup_Name == "(Auto Generate)" || Backup_Name == "0" || Backup_Name.empty()) {
684 TWFunc::Auto_Generate_Backup_Name();
685 DataManager::GetValue(TW_BACKUP_NAME, Backup_Name);
Dees_Troy43d8b002012-09-17 16:00:01 -0400686 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000687 LOGINFO("Backup Name is: '%s'\n", Backup_Name.c_str());
Dees_Troy43d8b002012-09-17 16:00:01 -0400688 Full_Backup_Path = Backup_Folder + "/" + Backup_Name + "/";
Dees_Troy2673cec2013-04-02 20:22:16 +0000689 LOGINFO("Full_Backup_Path is: '%s'\n", Full_Backup_Path.c_str());
Dees_Troy43d8b002012-09-17 16:00:01 -0400690
Dees_Troy2673cec2013-04-02 20:22:16 +0000691 LOGINFO("Calculating backup details...\n");
Dees_Troya13d74f2013-03-24 08:54:55 -0500692 DataManager::GetValue("tw_backup_list", Backup_List);
693 if (!Backup_List.empty()) {
694 end_pos = Backup_List.find(";", start_pos);
695 while (end_pos != string::npos && start_pos < Backup_List.size()) {
696 backup_path = Backup_List.substr(start_pos, end_pos - start_pos);
697 backup_part = Find_Partition_By_Path(backup_path);
698 if (backup_part != NULL) {
699 partition_count++;
700 if (backup_part->Backup_Method == 1)
701 file_bytes += backup_part->Backup_Size;
702 else
703 img_bytes += backup_part->Backup_Size;
704 if (backup_part->Has_SubPartition) {
705 std::vector<TWPartition*>::iterator subpart;
706
707 for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
Dees_Troy9e0b71c2013-04-08 13:35:37 +0000708 if ((*subpart)->Can_Be_Backed_Up && (*subpart)->Is_Present && (*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == backup_part->Mount_Point) {
Dees_Troya13d74f2013-03-24 08:54:55 -0500709 partition_count++;
710 if ((*subpart)->Backup_Method == 1)
711 file_bytes += (*subpart)->Backup_Size;
712 else
713 img_bytes += (*subpart)->Backup_Size;
714 }
715 }
Dees_Troy8170a922012-09-18 15:40:25 -0400716 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500717 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000718 LOGERR("Unable to locate '%s' partition for backup calculations.\n", backup_path.c_str());
Dees_Troy8170a922012-09-18 15:40:25 -0400719 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500720 start_pos = end_pos + 1;
721 end_pos = Backup_List.find(";", start_pos);
Dees_Troy43d8b002012-09-17 16:00:01 -0400722 }
723 }
Dees_Troy43d8b002012-09-17 16:00:01 -0400724
725 if (partition_count == 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000726 gui_print("No partitions selected for backup.\n");
Dees_Troy43d8b002012-09-17 16:00:01 -0400727 return false;
728 }
729 total_bytes = file_bytes + img_bytes;
Dees_Troy2673cec2013-04-02 20:22:16 +0000730 gui_print(" * Total number of partitions to back up: %d\n", partition_count);
731 gui_print(" * Total size of all data: %lluMB\n", total_bytes / 1024 / 1024);
Dees_Troy43d8b002012-09-17 16:00:01 -0400732 storage = Find_Partition_By_Path(DataManager::GetCurrentStoragePath());
733 if (storage != NULL) {
734 free_space = storage->Free;
Dees_Troy2673cec2013-04-02 20:22:16 +0000735 gui_print(" * Available space: %lluMB\n", free_space / 1024 / 1024);
Dees_Troy43d8b002012-09-17 16:00:01 -0400736 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000737 LOGERR("Unable to locate storage device.\n");
Dees_Troy43d8b002012-09-17 16:00:01 -0400738 return false;
739 }
Dees_Troyd4b22b02013-01-18 17:17:58 +0000740 if (free_space - (32 * 1024 * 1024) < total_bytes) {
Dees_Troy43d8b002012-09-17 16:00:01 -0400741 // We require an extra 32MB just in case
Dees_Troy2673cec2013-04-02 20:22:16 +0000742 LOGERR("Not enough free space on storage.\n");
Dees_Troy43d8b002012-09-17 16:00:01 -0400743 return false;
744 }
745 img_bytes_remaining = img_bytes;
746 file_bytes_remaining = file_bytes;
747
Dees_Troy2673cec2013-04-02 20:22:16 +0000748 gui_print("\n[BACKUP STARTED]\n");
749 gui_print(" * Backup Folder: %s\n", Full_Backup_Path.c_str());
Dees_Troyd4b22b02013-01-18 17:17:58 +0000750 if (!TWFunc::Recursive_Mkdir(Full_Backup_Path)) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000751 LOGERR("Failed to make backup folder.\n");
Dees_Troyd4b22b02013-01-18 17:17:58 +0000752 return false;
753 }
754
Dees_Troy2673cec2013-04-02 20:22:16 +0000755 DataManager::SetProgress(0.0);
Dees_Troy093b7642012-09-21 15:59:38 -0400756
Dees_Troya13d74f2013-03-24 08:54:55 -0500757 start_pos = 0;
758 end_pos = Backup_List.find(";", start_pos);
759 while (end_pos != string::npos && start_pos < Backup_List.size()) {
760 backup_path = Backup_List.substr(start_pos, end_pos - start_pos);
761 backup_part = Find_Partition_By_Path(backup_path);
762 if (backup_part != NULL) {
763 if (!Backup_Partition(backup_part, Full_Backup_Path, do_md5, &img_bytes_remaining, &file_bytes_remaining, &img_time, &file_time, &img_bytes, &file_bytes))
764 return false;
765 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000766 LOGERR("Unable to locate '%s' partition for backup process.\n", backup_path.c_str());
Dees_Troya13d74f2013-03-24 08:54:55 -0500767 }
768 start_pos = end_pos + 1;
769 end_pos = Backup_List.find(";", start_pos);
770 }
Dees_Troy43d8b002012-09-17 16:00:01 -0400771
772 // Average BPS
773 if (img_time == 0)
774 img_time = 1;
775 if (file_time == 0)
776 file_time = 1;
Dees_Troy093b7642012-09-21 15:59:38 -0400777 int img_bps = (int)img_bytes / (int)img_time;
bigbiff bigbiff2c57d782013-02-19 10:09:21 -0500778 unsigned long long file_bps = file_bytes / (int)file_time;
Dees_Troy43d8b002012-09-17 16:00:01 -0400779
Dees_Troy2673cec2013-04-02 20:22:16 +0000780 gui_print("Average backup rate for file systems: %llu MB/sec\n", (file_bps / (1024 * 1024)));
781 gui_print("Average backup rate for imaged drives: %lu MB/sec\n", (img_bps / (1024 * 1024)));
Dees_Troy43d8b002012-09-17 16:00:01 -0400782
783 time(&total_stop);
784 int total_time = (int) difftime(total_stop, total_start);
bigbiff bigbiff34684ff2013-12-01 21:03:45 -0500785 uint64_t actual_backup_size = du.Get_Folder_Size(Full_Backup_Path);
Dees_Troy43d8b002012-09-17 16:00:01 -0400786 actual_backup_size /= (1024LLU * 1024LLU);
787
bigbiff bigbiff2c57d782013-02-19 10:09:21 -0500788 int prev_img_bps, use_compression;
789 unsigned long long prev_file_bps;
Dees_Troy093b7642012-09-21 15:59:38 -0400790 DataManager::GetValue(TW_BACKUP_AVG_IMG_RATE, prev_img_bps);
791 img_bps += (prev_img_bps * 4);
792 img_bps /= 5;
793
794 DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression);
795 if (use_compression)
796 DataManager::GetValue(TW_BACKUP_AVG_FILE_COMP_RATE, prev_file_bps);
797 else
798 DataManager::GetValue(TW_BACKUP_AVG_FILE_RATE, prev_file_bps);
799 file_bps += (prev_file_bps * 4);
800 file_bps /= 5;
801
802 DataManager::SetValue(TW_BACKUP_AVG_IMG_RATE, img_bps);
803 if (use_compression)
804 DataManager::SetValue(TW_BACKUP_AVG_FILE_COMP_RATE, file_bps);
805 else
806 DataManager::SetValue(TW_BACKUP_AVG_FILE_RATE, file_bps);
807
Dees_Troy2673cec2013-04-02 20:22:16 +0000808 gui_print("[%llu MB TOTAL BACKED UP]\n", actual_backup_size);
Dees_Troy43d8b002012-09-17 16:00:01 -0400809 Update_System_Details();
Dees_Troyd0384ef2012-10-12 12:15:42 -0400810 UnMount_Main_Partitions();
Dees_Troy2673cec2013-04-02 20:22:16 +0000811 gui_print("[BACKUP COMPLETED IN %d SECONDS]\n\n", total_time); // the end
Dees_Troy3f5c4e82013-02-01 15:16:59 +0000812 string backup_log = Full_Backup_Path + "recovery.log";
813 TWFunc::copy_file("/tmp/recovery.log", backup_log, 0644);
814 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400815}
816
Dees_Troy093b7642012-09-21 15:59:38 -0400817bool TWPartitionManager::Restore_Partition(TWPartition* Part, string Restore_Name, int partition_count) {
Dees_Troy4a2a1262012-09-18 09:33:47 -0400818 time_t Start, Stop;
819 time(&Start);
Dees_Troy2673cec2013-04-02 20:22:16 +0000820 DataManager::ShowProgress(1.0 / (float)partition_count, 150);
Dees_Troy4a2a1262012-09-18 09:33:47 -0400821 if (!Part->Restore(Restore_Name))
822 return false;
Dees_Troy8170a922012-09-18 15:40:25 -0400823 if (Part->Has_SubPartition) {
824 std::vector<TWPartition*>::iterator subpart;
825
826 for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
827 if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point) {
828 if (!(*subpart)->Restore(Restore_Name))
829 return false;
830 }
831 }
832 }
Dees_Troy4a2a1262012-09-18 09:33:47 -0400833 time(&Stop);
Dees_Troy2673cec2013-04-02 20:22:16 +0000834 gui_print("[%s done (%d seconds)]\n\n", Part->Backup_Display_Name.c_str(), (int)difftime(Stop, Start));
Dees_Troy4a2a1262012-09-18 09:33:47 -0400835 return true;
836}
837
Dees_Troy51a0e822012-09-05 15:24:24 -0400838int TWPartitionManager::Run_Restore(string Restore_Name) {
Dees_Troy4a2a1262012-09-18 09:33:47 -0400839 int check_md5, check, partition_count = 0;
Dees_Troya13d74f2013-03-24 08:54:55 -0500840 TWPartition* restore_part = NULL;
Dees_Troy4a2a1262012-09-18 09:33:47 -0400841 time_t rStart, rStop;
842 time(&rStart);
Dees_Troya13d74f2013-03-24 08:54:55 -0500843 string Restore_List, restore_path;
844 size_t start_pos = 0, end_pos;
Dees_Troy43d8b002012-09-17 16:00:01 -0400845
Dees_Troy2673cec2013-04-02 20:22:16 +0000846 gui_print("\n[RESTORE STARTED]\n\n");
847 gui_print("Restore folder: '%s'\n", Restore_Name.c_str());
Dees_Troy43d8b002012-09-17 16:00:01 -0400848
Dees_Troy4a2a1262012-09-18 09:33:47 -0400849 if (!Mount_Current_Storage(true))
850 return false;
851
852 DataManager::GetValue(TW_SKIP_MD5_CHECK_VAR, check_md5);
Dees_Troya13d74f2013-03-24 08:54:55 -0500853 if (check_md5 > 0) {
854 // Check MD5 files first before restoring to ensure that all of them match before starting a restore
855 TWFunc::GUI_Operation_Text(TW_VERIFY_MD5_TEXT, "Verifying MD5");
Dees_Troy2673cec2013-04-02 20:22:16 +0000856 gui_print("Verifying MD5...\n");
Dees_Troya13d74f2013-03-24 08:54:55 -0500857 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000858 gui_print("Skipping MD5 check based on user setting.\n");
Dees_Troya13d74f2013-03-24 08:54:55 -0500859 }
860 DataManager::GetValue("tw_restore_selected", Restore_List);
861 if (!Restore_List.empty()) {
862 end_pos = Restore_List.find(";", start_pos);
863 while (end_pos != string::npos && start_pos < Restore_List.size()) {
864 restore_path = Restore_List.substr(start_pos, end_pos - start_pos);
865 restore_part = Find_Partition_By_Path(restore_path);
866 if (restore_part != NULL) {
867 partition_count++;
868 if (check_md5 > 0 && !restore_part->Check_MD5(Restore_Name))
869 return false;
870 if (restore_part->Has_SubPartition) {
871 std::vector<TWPartition*>::iterator subpart;
872
873 for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
874 if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == restore_part->Mount_Point) {
875 if (!(*subpart)->Check_MD5(Restore_Name))
876 return false;
877 }
878 }
879 }
880 } else {
Dees_Troy59df9262013-06-19 14:53:57 -0500881 LOGERR("Unable to locate '%s' partition for restoring (restore list).\n", restore_path.c_str());
Dees_Troya13d74f2013-03-24 08:54:55 -0500882 }
883 start_pos = end_pos + 1;
884 end_pos = Restore_List.find(";", start_pos);
Dees_Troy4a2a1262012-09-18 09:33:47 -0400885 }
Dees_Troy4a2a1262012-09-18 09:33:47 -0400886 }
Dees_Troy4a2a1262012-09-18 09:33:47 -0400887
888 if (partition_count == 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +0000889 LOGERR("No partitions selected for restore.\n");
Dees_Troy4a2a1262012-09-18 09:33:47 -0400890 return false;
891 }
892
Dees_Troy2673cec2013-04-02 20:22:16 +0000893 gui_print("Restoring %i partitions...\n", partition_count);
894 DataManager::SetProgress(0.0);
Dees_Troya13d74f2013-03-24 08:54:55 -0500895 start_pos = 0;
896 if (!Restore_List.empty()) {
897 end_pos = Restore_List.find(";", start_pos);
898 while (end_pos != string::npos && start_pos < Restore_List.size()) {
899 restore_path = Restore_List.substr(start_pos, end_pos - start_pos);
900 restore_part = Find_Partition_By_Path(restore_path);
901 if (restore_part != NULL) {
902 partition_count++;
903 if (!Restore_Partition(restore_part, Restore_Name, partition_count))
904 return false;
905 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +0000906 LOGERR("Unable to locate '%s' partition for restoring.\n", restore_path.c_str());
Dees_Troya13d74f2013-03-24 08:54:55 -0500907 }
908 start_pos = end_pos + 1;
909 end_pos = Restore_List.find(";", start_pos);
910 }
911 }
Dees_Troyb46a6842012-09-25 11:06:46 -0400912 TWFunc::GUI_Operation_Text(TW_UPDATE_SYSTEM_DETAILS_TEXT, "Updating System Details");
Dees_Troy43d8b002012-09-17 16:00:01 -0400913 Update_System_Details();
Dees_Troyd0384ef2012-10-12 12:15:42 -0400914 UnMount_Main_Partitions();
Dees_Troy4a2a1262012-09-18 09:33:47 -0400915 time(&rStop);
Dees_Troy2673cec2013-04-02 20:22:16 +0000916 gui_print("[RESTORE COMPLETED IN %d SECONDS]\n\n",(int)difftime(rStop,rStart));
Dees_Troy63c8df72012-09-10 14:02:05 -0400917 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400918}
919
920void TWPartitionManager::Set_Restore_Files(string Restore_Name) {
Dees_Troy63c8df72012-09-10 14:02:05 -0400921 // Start with the default values
Dees_Troya13d74f2013-03-24 08:54:55 -0500922 string Restore_List;
Dees_Troy83bd4832013-05-04 12:39:56 +0000923 bool get_date = true, check_encryption = true;
924
925 DataManager::SetValue("tw_restore_encrypted", 0);
Dees_Troy63c8df72012-09-10 14:02:05 -0400926
927 DIR* d;
928 d = opendir(Restore_Name.c_str());
929 if (d == NULL)
930 {
Dees_Troy2673cec2013-04-02 20:22:16 +0000931 LOGERR("Error opening %s\n", Restore_Name.c_str());
Dees_Troy63c8df72012-09-10 14:02:05 -0400932 return;
933 }
934
935 struct dirent* de;
936 while ((de = readdir(d)) != NULL)
937 {
938 // Strip off three components
939 char str[256];
940 char* label;
941 char* fstype = NULL;
942 char* extn = NULL;
943 char* ptr;
944
945 strcpy(str, de->d_name);
946 if (strlen(str) <= 2)
947 continue;
948
949 if (get_date) {
950 char file_path[255];
951 struct stat st;
952
953 strcpy(file_path, Restore_Name.c_str());
954 strcat(file_path, "/");
955 strcat(file_path, str);
956 stat(file_path, &st);
957 string backup_date = ctime((const time_t*)(&st.st_mtime));
958 DataManager::SetValue(TW_RESTORE_FILE_DATE, backup_date);
959 get_date = false;
960 }
961
962 label = str;
963 ptr = label;
964 while (*ptr && *ptr != '.') ptr++;
965 if (*ptr == '.')
966 {
967 *ptr = 0x00;
968 ptr++;
969 fstype = ptr;
970 }
971 while (*ptr && *ptr != '.') ptr++;
972 if (*ptr == '.')
973 {
974 *ptr = 0x00;
975 ptr++;
976 extn = ptr;
977 }
978
Dees_Troy83bd4832013-05-04 12:39:56 +0000979 if (fstype == NULL || extn == NULL || strcmp(fstype, "log") == 0) continue;
Dees_Troya13d74f2013-03-24 08:54:55 -0500980 int extnlength = strlen(extn);
Dees_Troy83bd4832013-05-04 12:39:56 +0000981 if (extnlength != 3 && extnlength != 6) continue;
982 if (extnlength >= 3 && strncmp(extn, "win", 3) != 0) continue;
983 //if (extnlength == 6 && strncmp(extn, "win000", 6) != 0) continue;
984
985 if (check_encryption) {
986 string filename = Restore_Name + "/";
987 filename += de->d_name;
988 if (TWFunc::Get_File_Type(filename) == 2) {
989 LOGINFO("'%s' is encrypted\n", filename.c_str());
990 DataManager::SetValue("tw_restore_encrypted", 1);
991 }
992 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500993 if (extnlength == 6 && strncmp(extn, "win000", 6) != 0) continue;
Dees_Troy63c8df72012-09-10 14:02:05 -0400994
995 TWPartition* Part = Find_Partition_By_Path(label);
996 if (Part == NULL)
997 {
Dees_Troy2673cec2013-04-02 20:22:16 +0000998 LOGERR(" Unable to locate partition by backup name: '%s'\n", label);
Dees_Troy63c8df72012-09-10 14:02:05 -0400999 continue;
1000 }
1001
1002 Part->Backup_FileName = de->d_name;
1003 if (strlen(extn) > 3) {
1004 Part->Backup_FileName.resize(Part->Backup_FileName.size() - strlen(extn) + 3);
1005 }
1006
Dees_Troya13d74f2013-03-24 08:54:55 -05001007 Restore_List += Part->Backup_Path + ";";
Dees_Troy63c8df72012-09-10 14:02:05 -04001008 }
1009 closedir(d);
1010
Dees_Troya13d74f2013-03-24 08:54:55 -05001011 // Set the final value
1012 DataManager::SetValue("tw_restore_list", Restore_List);
1013 DataManager::SetValue("tw_restore_selected", Restore_List);
Dees_Troy51a0e822012-09-05 15:24:24 -04001014 return;
1015}
1016
1017int TWPartitionManager::Wipe_By_Path(string Path) {
Dees_Troy63c8df72012-09-10 14:02:05 -04001018 std::vector<TWPartition*>::iterator iter;
1019 int ret = false;
1020 bool found = false;
Dees_Troy38bd7602012-09-14 13:33:53 -04001021 string Local_Path = TWFunc::Get_Root_Path(Path);
Dees_Troy63c8df72012-09-10 14:02:05 -04001022
1023 // Iterate through all partitions
1024 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
Dees_Troy657c3092012-09-10 20:32:10 -04001025 if ((*iter)->Mount_Point == Local_Path || (!(*iter)->Symlink_Mount_Point.empty() && (*iter)->Symlink_Mount_Point == Local_Path)) {
Dees_Troye58d5262012-09-21 12:27:57 -04001026 if (Path == "/and-sec")
1027 ret = (*iter)->Wipe_AndSec();
1028 else
1029 ret = (*iter)->Wipe();
Dees_Troy63c8df72012-09-10 14:02:05 -04001030 found = true;
1031 } else if ((*iter)->Is_SubPartition && (*iter)->SubPartition_Of == Local_Path) {
1032 (*iter)->Wipe();
1033 }
1034 }
1035 if (found) {
1036 return ret;
1037 } else
Dees_Troy2673cec2013-04-02 20:22:16 +00001038 LOGERR("Wipe: Unable to find partition for path '%s'\n", Local_Path.c_str());
Dees_Troy63c8df72012-09-10 14:02:05 -04001039 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -04001040}
1041
1042int TWPartitionManager::Wipe_By_Block(string Block) {
Dees_Troy63c8df72012-09-10 14:02:05 -04001043 TWPartition* Part = Find_Partition_By_Block(Block);
1044
1045 if (Part) {
1046 if (Part->Has_SubPartition) {
1047 std::vector<TWPartition*>::iterator subpart;
1048
1049 for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
1050 if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point)
1051 (*subpart)->Wipe();
1052 }
1053 return Part->Wipe();
1054 } else
1055 return Part->Wipe();
1056 }
Dees_Troy2673cec2013-04-02 20:22:16 +00001057 LOGERR("Wipe: Unable to find partition for block '%s'\n", Block.c_str());
Dees_Troy63c8df72012-09-10 14:02:05 -04001058 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -04001059}
1060
1061int TWPartitionManager::Wipe_By_Name(string Name) {
Dees_Troy63c8df72012-09-10 14:02:05 -04001062 TWPartition* Part = Find_Partition_By_Name(Name);
1063
1064 if (Part) {
1065 if (Part->Has_SubPartition) {
1066 std::vector<TWPartition*>::iterator subpart;
1067
1068 for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
1069 if ((*subpart)->Is_SubPartition && (*subpart)->SubPartition_Of == Part->Mount_Point)
1070 (*subpart)->Wipe();
1071 }
1072 return Part->Wipe();
1073 } else
1074 return Part->Wipe();
1075 }
Dees_Troy2673cec2013-04-02 20:22:16 +00001076 LOGERR("Wipe: Unable to find partition for name '%s'\n", Name.c_str());
Dees_Troy63c8df72012-09-10 14:02:05 -04001077 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -04001078}
1079
1080int TWPartitionManager::Factory_Reset(void) {
Dees_Troy63c8df72012-09-10 14:02:05 -04001081 std::vector<TWPartition*>::iterator iter;
1082 int ret = true;
1083
1084 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
Dees_Troy38bd7602012-09-14 13:33:53 -04001085 if ((*iter)->Wipe_During_Factory_Reset && (*iter)->Is_Present) {
Dees_Troy63c8df72012-09-10 14:02:05 -04001086 if (!(*iter)->Wipe())
1087 ret = false;
Dees_Troy094207a2012-09-26 12:00:39 -04001088 } else if ((*iter)->Has_Android_Secure) {
1089 if (!(*iter)->Wipe_AndSec())
1090 ret = false;
Dees_Troy63c8df72012-09-10 14:02:05 -04001091 }
1092 }
1093 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001094}
1095
Dees_Troy38bd7602012-09-14 13:33:53 -04001096int TWPartitionManager::Wipe_Dalvik_Cache(void) {
1097 struct stat st;
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001098 vector <string> dir;
Dees_Troy38bd7602012-09-14 13:33:53 -04001099
1100 if (!Mount_By_Path("/data", true))
1101 return false;
1102
1103 if (!Mount_By_Path("/cache", true))
1104 return false;
1105
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001106 dir.push_back("/data/dalvik-cache");
1107 dir.push_back("/cache/dalvik-cache");
1108 dir.push_back("/cache/dc");
Dees_Troy2673cec2013-04-02 20:22:16 +00001109 gui_print("\nWiping Dalvik Cache Directories...\n");
Dees_Troya13d74f2013-03-24 08:54:55 -05001110 for (unsigned i = 0; i < dir.size(); ++i) {
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001111 if (stat(dir.at(i).c_str(), &st) == 0) {
1112 TWFunc::removeDir(dir.at(i), false);
Dees_Troy2673cec2013-04-02 20:22:16 +00001113 gui_print("Cleaned: %s...\n", dir.at(i).c_str());
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001114 }
1115 }
Dees_Troy38bd7602012-09-14 13:33:53 -04001116 TWPartition* sdext = Find_Partition_By_Path("/sd-ext");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001117 if (sdext && sdext->Is_Present && sdext->Mount(false))
1118 {
1119 if (stat("/sd-ext/dalvik-cache", &st) == 0)
1120 {
1121 TWFunc::removeDir("/sd-ext/dalvik-cache", false);
1122 gui_print("Cleaned: /sd-ext/dalvik-cache...\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001123 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001124 }
Dees_Troy2673cec2013-04-02 20:22:16 +00001125 gui_print("-- Dalvik Cache Directories Wipe Complete!\n\n");
Dees_Troy38bd7602012-09-14 13:33:53 -04001126 return true;
1127}
1128
1129int TWPartitionManager::Wipe_Rotate_Data(void) {
1130 if (!Mount_By_Path("/data", true))
1131 return false;
1132
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001133 unlink("/data/misc/akmd*");
1134 unlink("/data/misc/rild*");
Dees_Troy2673cec2013-04-02 20:22:16 +00001135 gui_print("Rotation data wiped.\n");
Dees_Troy38bd7602012-09-14 13:33:53 -04001136 return true;
1137}
1138
1139int TWPartitionManager::Wipe_Battery_Stats(void) {
1140 struct stat st;
1141
1142 if (!Mount_By_Path("/data", true))
1143 return false;
1144
1145 if (0 != stat("/data/system/batterystats.bin", &st)) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001146 gui_print("No Battery Stats Found. No Need To Wipe.\n");
Dees_Troy38bd7602012-09-14 13:33:53 -04001147 } else {
1148 remove("/data/system/batterystats.bin");
Dees_Troy2673cec2013-04-02 20:22:16 +00001149 gui_print("Cleared battery stats.\n");
Dees_Troy38bd7602012-09-14 13:33:53 -04001150 }
1151 return true;
1152}
1153
Dees_Troy2ff5a8d2012-09-26 14:53:02 -04001154int TWPartitionManager::Wipe_Android_Secure(void) {
1155 std::vector<TWPartition*>::iterator iter;
1156 int ret = false;
1157 bool found = false;
1158
1159 // Iterate through all partitions
1160 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
1161 if ((*iter)->Has_Android_Secure) {
1162 ret = (*iter)->Wipe_AndSec();
1163 found = true;
1164 }
1165 }
1166 if (found) {
1167 return ret;
1168 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +00001169 LOGERR("No android secure partitions found.\n");
Dees_Troy2ff5a8d2012-09-26 14:53:02 -04001170 }
1171 return false;
1172}
1173
Dees_Troy38bd7602012-09-14 13:33:53 -04001174int TWPartitionManager::Format_Data(void) {
1175 TWPartition* dat = Find_Partition_By_Path("/data");
1176
1177 if (dat != NULL) {
1178 if (!dat->UnMount(true))
1179 return false;
1180
1181 return dat->Wipe_Encryption();
1182 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +00001183 LOGERR("Unable to locate /data.\n");
Dees_Troy38bd7602012-09-14 13:33:53 -04001184 return false;
1185 }
1186 return false;
1187}
1188
1189int TWPartitionManager::Wipe_Media_From_Data(void) {
1190 TWPartition* dat = Find_Partition_By_Path("/data");
1191
1192 if (dat != NULL) {
1193 if (!dat->Has_Data_Media) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001194 LOGERR("This device does not have /data/media\n");
Dees_Troy38bd7602012-09-14 13:33:53 -04001195 return false;
1196 }
1197 if (!dat->Mount(true))
1198 return false;
1199
Dees_Troy2673cec2013-04-02 20:22:16 +00001200 gui_print("Wiping internal storage -- /data/media...\n");
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001201 TWFunc::removeDir("/data/media", false);
1202 if (mkdir("/data/media", S_IRWXU | S_IRWXG | S_IWGRP | S_IXGRP) != 0)
1203 return -1;
Dees_Troy38bd7602012-09-14 13:33:53 -04001204 if (dat->Has_Data_Media) {
1205 dat->Recreate_Media_Folder();
Dees_Troy74fb2e92013-04-15 14:35:47 +00001206 // Unmount and remount - slightly hackish way to ensure that the "/sdcard" folder is still mounted properly after wiping
1207 dat->UnMount(false);
1208 dat->Mount(false);
Dees_Troy38bd7602012-09-14 13:33:53 -04001209 }
1210 return true;
1211 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +00001212 LOGERR("Unable to locate /data.\n");
Dees_Troy38bd7602012-09-14 13:33:53 -04001213 return false;
1214 }
1215 return false;
1216}
1217
Dees_Troy51a0e822012-09-05 15:24:24 -04001218void TWPartitionManager::Refresh_Sizes(void) {
Dees_Troy51127312012-09-08 13:08:49 -04001219 Update_System_Details();
Dees_Troy51a0e822012-09-05 15:24:24 -04001220 return;
1221}
1222
1223void TWPartitionManager::Update_System_Details(void) {
Dees_Troy5bf43922012-09-07 16:07:55 -04001224 std::vector<TWPartition*>::iterator iter;
Dees_Troy51127312012-09-08 13:08:49 -04001225 int data_size = 0;
Dees_Troy5bf43922012-09-07 16:07:55 -04001226
Dees_Troy2673cec2013-04-02 20:22:16 +00001227 gui_print("Updating partition details...\n");
Dees_Troy5bf43922012-09-07 16:07:55 -04001228 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
Dees_Troy51127312012-09-08 13:08:49 -04001229 if ((*iter)->Can_Be_Mounted) {
1230 (*iter)->Update_Size(true);
1231 if ((*iter)->Mount_Point == "/system") {
1232 int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
1233 DataManager::SetValue(TW_BACKUP_SYSTEM_SIZE, backup_display_size);
1234 } else if ((*iter)->Mount_Point == "/data" || (*iter)->Mount_Point == "/datadata") {
1235 data_size += (int)((*iter)->Backup_Size / 1048576LLU);
1236 } else if ((*iter)->Mount_Point == "/cache") {
1237 int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
1238 DataManager::SetValue(TW_BACKUP_CACHE_SIZE, backup_display_size);
1239 } else if ((*iter)->Mount_Point == "/sd-ext") {
1240 int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
1241 DataManager::SetValue(TW_BACKUP_SDEXT_SIZE, backup_display_size);
1242 if ((*iter)->Backup_Size == 0) {
1243 DataManager::SetValue(TW_HAS_SDEXT_PARTITION, 0);
1244 DataManager::SetValue(TW_BACKUP_SDEXT_VAR, 0);
1245 } else
1246 DataManager::SetValue(TW_HAS_SDEXT_PARTITION, 1);
Dees_Troye58d5262012-09-21 12:27:57 -04001247 } else if ((*iter)->Has_Android_Secure) {
Dees_Troy8170a922012-09-18 15:40:25 -04001248 int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
Dees_Troye58d5262012-09-21 12:27:57 -04001249 DataManager::SetValue(TW_BACKUP_ANDSEC_SIZE, backup_display_size);
Dees_Troy8170a922012-09-18 15:40:25 -04001250 if ((*iter)->Backup_Size == 0) {
1251 DataManager::SetValue(TW_HAS_ANDROID_SECURE, 0);
1252 DataManager::SetValue(TW_BACKUP_ANDSEC_VAR, 0);
1253 } else
1254 DataManager::SetValue(TW_HAS_ANDROID_SECURE, 1);
Dees_Troy2c50e182012-09-26 20:05:28 -04001255 } else if ((*iter)->Mount_Point == "/boot") {
1256 int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
1257 DataManager::SetValue(TW_BACKUP_BOOT_SIZE, backup_display_size);
1258 if ((*iter)->Backup_Size == 0) {
1259 DataManager::SetValue("tw_has_boot_partition", 0);
1260 DataManager::SetValue(TW_BACKUP_BOOT_VAR, 0);
1261 } else
1262 DataManager::SetValue("tw_has_boot_partition", 1);
Dees_Troy51127312012-09-08 13:08:49 -04001263 }
Dees_Troyab10ee22012-09-21 14:27:30 -04001264#ifdef SP1_NAME
1265 if ((*iter)->Backup_Name == EXPAND(SP1_NAME)) {
1266 int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
1267 DataManager::SetValue(TW_BACKUP_SP1_SIZE, backup_display_size);
1268 }
1269#endif
1270#ifdef SP2_NAME
1271 if ((*iter)->Backup_Name == EXPAND(SP2_NAME)) {
1272 int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
1273 DataManager::SetValue(TW_BACKUP_SP2_SIZE, backup_display_size);
1274 }
1275#endif
1276#ifdef SP3_NAME
1277 if ((*iter)->Backup_Name == EXPAND(SP3_NAME)) {
1278 int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
1279 DataManager::SetValue(TW_BACKUP_SP3_SIZE, backup_display_size);
1280 }
1281#endif
Dees_Troyaa9cc402012-10-13 12:14:05 -04001282 } else {
1283 // Handle unmountable partitions in case we reset defaults
1284 if ((*iter)->Mount_Point == "/boot") {
1285 int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
1286 DataManager::SetValue(TW_BACKUP_BOOT_SIZE, backup_display_size);
1287 if ((*iter)->Backup_Size == 0) {
1288 DataManager::SetValue(TW_HAS_BOOT_PARTITION, 0);
1289 DataManager::SetValue(TW_BACKUP_BOOT_VAR, 0);
1290 } else
1291 DataManager::SetValue(TW_HAS_BOOT_PARTITION, 1);
1292 } else if ((*iter)->Mount_Point == "/recovery") {
1293 int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
1294 DataManager::SetValue(TW_BACKUP_RECOVERY_SIZE, backup_display_size);
1295 if ((*iter)->Backup_Size == 0) {
1296 DataManager::SetValue(TW_HAS_RECOVERY_PARTITION, 0);
1297 DataManager::SetValue(TW_BACKUP_RECOVERY_VAR, 0);
1298 } else
1299 DataManager::SetValue(TW_HAS_RECOVERY_PARTITION, 1);
Gary Peck82599a82012-11-21 16:23:12 -08001300 } else if ((*iter)->Mount_Point == "/data") {
1301 data_size += (int)((*iter)->Backup_Size / 1048576LLU);
Dees_Troyaa9cc402012-10-13 12:14:05 -04001302 }
1303#ifdef SP1_NAME
1304 if ((*iter)->Backup_Name == EXPAND(SP1_NAME)) {
1305 int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
1306 DataManager::SetValue(TW_BACKUP_SP1_SIZE, backup_display_size);
1307 }
1308#endif
1309#ifdef SP2_NAME
1310 if ((*iter)->Backup_Name == EXPAND(SP2_NAME)) {
1311 int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
1312 DataManager::SetValue(TW_BACKUP_SP2_SIZE, backup_display_size);
1313 }
1314#endif
1315#ifdef SP3_NAME
1316 if ((*iter)->Backup_Name == EXPAND(SP3_NAME)) {
1317 int backup_display_size = (int)((*iter)->Backup_Size / 1048576LLU);
1318 DataManager::SetValue(TW_BACKUP_SP3_SIZE, backup_display_size);
1319 }
1320#endif
Dees_Troy51127312012-09-08 13:08:49 -04001321 }
Dees_Troy5bf43922012-09-07 16:07:55 -04001322 }
Dees_Troy51127312012-09-08 13:08:49 -04001323 DataManager::SetValue(TW_BACKUP_DATA_SIZE, data_size);
1324 string current_storage_path = DataManager::GetCurrentStoragePath();
1325 TWPartition* FreeStorage = Find_Partition_By_Path(current_storage_path);
Dees_Troy8170a922012-09-18 15:40:25 -04001326 if (FreeStorage != NULL) {
1327 // Attempt to mount storage
1328 if (!FreeStorage->Mount(false)) {
1329 // We couldn't mount storage... check to see if we have dual storage
1330 int has_dual_storage;
1331 DataManager::GetValue(TW_HAS_DUAL_STORAGE, has_dual_storage);
1332 if (has_dual_storage == 1) {
1333 // We have dual storage, see if we're using the internal storage that should always be present
1334 if (current_storage_path == DataManager::GetSettingsStoragePath()) {
Dees_Troyab10ee22012-09-21 14:27:30 -04001335 if (!FreeStorage->Is_Encrypted) {
1336 // Not able to use internal, so error!
Dees_Troy2673cec2013-04-02 20:22:16 +00001337 LOGERR("Unable to mount internal storage.\n");
Dees_Troyab10ee22012-09-21 14:27:30 -04001338 }
Dees_Troy8170a922012-09-18 15:40:25 -04001339 DataManager::SetValue(TW_STORAGE_FREE_SIZE, 0);
1340 } else {
1341 // We were using external, flip to internal
1342 DataManager::SetValue(TW_USE_EXTERNAL_STORAGE, 0);
1343 current_storage_path = DataManager::GetCurrentStoragePath();
1344 FreeStorage = Find_Partition_By_Path(current_storage_path);
1345 if (FreeStorage != NULL) {
1346 DataManager::SetValue(TW_STORAGE_FREE_SIZE, (int)(FreeStorage->Free / 1048576LLU));
1347 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +00001348 LOGERR("Unable to locate internal storage partition.\n");
Dees_Troy8170a922012-09-18 15:40:25 -04001349 DataManager::SetValue(TW_STORAGE_FREE_SIZE, 0);
1350 }
1351 }
1352 } else {
1353 // No dual storage and unable to mount storage, error!
Dees_Troy2673cec2013-04-02 20:22:16 +00001354 LOGERR("Unable to mount storage.\n");
Dees_Troy8170a922012-09-18 15:40:25 -04001355 DataManager::SetValue(TW_STORAGE_FREE_SIZE, 0);
1356 }
1357 } else {
1358 DataManager::SetValue(TW_STORAGE_FREE_SIZE, (int)(FreeStorage->Free / 1048576LLU));
1359 }
1360 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +00001361 LOGINFO("Unable to find storage partition '%s'.\n", current_storage_path.c_str());
Dees_Troy8170a922012-09-18 15:40:25 -04001362 }
Dees_Troy5bf43922012-09-07 16:07:55 -04001363 if (!Write_Fstab())
Dees_Troy2673cec2013-04-02 20:22:16 +00001364 LOGERR("Error creating fstab\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001365 return;
1366}
1367
1368int TWPartitionManager::Decrypt_Device(string Password) {
Dees_Troy5bf43922012-09-07 16:07:55 -04001369#ifdef TW_INCLUDE_CRYPTO
1370 int ret_val, password_len;
1371 char crypto_blkdev[255], cPassword[255];
1372 size_t result;
1373
1374 property_set("ro.crypto.state", "encrypted");
1375#ifdef TW_INCLUDE_JB_CRYPTO
1376 // No extra flags needed
1377#else
1378 property_set("ro.crypto.fs_type", CRYPTO_FS_TYPE);
1379 property_set("ro.crypto.fs_real_blkdev", CRYPTO_REAL_BLKDEV);
1380 property_set("ro.crypto.fs_mnt_point", CRYPTO_MNT_POINT);
1381 property_set("ro.crypto.fs_options", CRYPTO_FS_OPTIONS);
1382 property_set("ro.crypto.fs_flags", CRYPTO_FS_FLAGS);
1383 property_set("ro.crypto.keyfile.userdata", CRYPTO_KEY_LOC);
a39552696ff55ce2013-01-08 16:14:56 +00001384
1385#ifdef CRYPTO_SD_FS_TYPE
1386 property_set("ro.crypto.sd_fs_type", CRYPTO_SD_FS_TYPE);
1387 property_set("ro.crypto.sd_fs_real_blkdev", CRYPTO_SD_REAL_BLKDEV);
1388 property_set("ro.crypto.sd_fs_mnt_point", EXPAND(TW_INTERNAL_STORAGE_PATH));
Dees_Troy5bf43922012-09-07 16:07:55 -04001389#endif
a39552696ff55ce2013-01-08 16:14:56 +00001390
1391 property_set("rw.km_fips_status", "ready");
1392
1393#endif
1394
1395 // some samsung devices store "footer" on efs partition
1396 TWPartition *efs = Find_Partition_By_Path("/efs");
1397 if(efs && !efs->Is_Mounted())
1398 efs->Mount(false);
1399 else
1400 efs = 0;
1401#ifdef TW_EXTERNAL_STORAGE_PATH
Dees_Troy20c02c02013-01-10 14:14:10 +00001402#ifdef TW_INCLUDE_CRYPTO_SAMSUNG
a39552696ff55ce2013-01-08 16:14:56 +00001403 TWPartition* sdcard = Find_Partition_By_Path(EXPAND(TW_EXTERNAL_STORAGE_PATH));
Dees_Troy85f44ed2013-01-09 18:42:36 +00001404 if (sdcard && sdcard->Mount(false)) {
a39552696ff55ce2013-01-08 16:14:56 +00001405 property_set("ro.crypto.external_encrypted", "1");
1406 property_set("ro.crypto.external_blkdev", sdcard->Actual_Block_Device.c_str());
1407 } else {
1408 property_set("ro.crypto.external_encrypted", "0");
1409 }
1410#endif
Dees_Troy20c02c02013-01-10 14:14:10 +00001411#endif
a39552696ff55ce2013-01-08 16:14:56 +00001412
Dees_Troy5bf43922012-09-07 16:07:55 -04001413 strcpy(cPassword, Password.c_str());
a39552696ff55ce2013-01-08 16:14:56 +00001414 int pwret = cryptfs_check_passwd(cPassword);
1415
1416 if (pwret != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001417 LOGERR("Failed to decrypt data.\n");
Dees_Troy5bf43922012-09-07 16:07:55 -04001418 return -1;
1419 }
a39552696ff55ce2013-01-08 16:14:56 +00001420
1421 if(efs)
1422 efs->UnMount(false);
1423
Dees_Troy5bf43922012-09-07 16:07:55 -04001424 property_get("ro.crypto.fs_crypto_blkdev", crypto_blkdev, "error");
1425 if (strcmp(crypto_blkdev, "error") == 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001426 LOGERR("Error retrieving decrypted data block device.\n");
Dees_Troy5bf43922012-09-07 16:07:55 -04001427 } else {
1428 TWPartition* dat = Find_Partition_By_Path("/data");
1429 if (dat != NULL) {
Dees_Troy38bd7602012-09-14 13:33:53 -04001430 DataManager::SetValue(TW_DATA_BLK_DEVICE, dat->Primary_Block_Device);
Dees_Troy5bf43922012-09-07 16:07:55 -04001431 DataManager::SetValue(TW_IS_DECRYPTED, 1);
1432 dat->Is_Decrypted = true;
1433 dat->Decrypted_Block_Device = crypto_blkdev;
Gary Peck82599a82012-11-21 16:23:12 -08001434 dat->Setup_File_System(false);
Dees_Troy74fb2e92013-04-15 14:35:47 +00001435 dat->Current_File_System = dat->Fstab_File_System; // Needed if we're ignoring blkid because encrypted devices start out as emmc
Dees_Troy2673cec2013-04-02 20:22:16 +00001436 gui_print("Data successfully decrypted, new block device: '%s'\n", crypto_blkdev);
a39552696ff55ce2013-01-08 16:14:56 +00001437
1438#ifdef CRYPTO_SD_FS_TYPE
1439 char crypto_blkdev_sd[255];
1440 property_get("ro.crypto.sd_fs_crypto_blkdev", crypto_blkdev_sd, "error");
1441 if (strcmp(crypto_blkdev_sd, "error") == 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001442 LOGERR("Error retrieving decrypted data block device.\n");
Dees_Troyc8bafa12013-01-10 15:43:00 +00001443 } else if(TWPartition* emmc = Find_Partition_By_Path(EXPAND(TW_INTERNAL_STORAGE_PATH))){
a39552696ff55ce2013-01-08 16:14:56 +00001444 emmc->Is_Decrypted = true;
1445 emmc->Decrypted_Block_Device = crypto_blkdev_sd;
1446 emmc->Setup_File_System(false);
Dees_Troy2673cec2013-04-02 20:22:16 +00001447 gui_print("Internal SD successfully decrypted, new block device: '%s'\n", crypto_blkdev_sd);
a39552696ff55ce2013-01-08 16:14:56 +00001448 }
a39552696ff55ce2013-01-08 16:14:56 +00001449#endif //ifdef CRYPTO_SD_FS_TYPE
Dees_Troy85f44ed2013-01-09 18:42:36 +00001450#ifdef TW_EXTERNAL_STORAGE_PATH
Dees_Troy20c02c02013-01-10 14:14:10 +00001451#ifdef TW_INCLUDE_CRYPTO_SAMSUNG
Dees_Troy85f44ed2013-01-09 18:42:36 +00001452 char is_external_decrypted[255];
1453 property_get("ro.crypto.external_use_ecryptfs", is_external_decrypted, "0");
1454 if (strcmp(is_external_decrypted, "1") == 0) {
1455 sdcard->Is_Decrypted = true;
1456 sdcard->EcryptFS_Password = Password;
1457 sdcard->Decrypted_Block_Device = sdcard->Actual_Block_Device;
Dees_Troy999b39d2013-01-14 15:36:13 +00001458 string MetaEcfsFile = EXPAND(TW_EXTERNAL_STORAGE_PATH);
1459 MetaEcfsFile += "/.MetaEcfsFile";
1460 if (!TWFunc::Path_Exists(MetaEcfsFile)) {
1461 // External storage isn't actually encrypted so unmount and remount without ecryptfs
1462 sdcard->UnMount(false);
1463 sdcard->Mount(false);
1464 }
Dees_Troy85f44ed2013-01-09 18:42:36 +00001465 } else {
Dees_Troy066eb302013-08-23 17:20:32 +00001466 LOGINFO("External storage '%s' is not encrypted.\n", sdcard->Mount_Point.c_str());
Dees_Troy85f44ed2013-01-09 18:42:36 +00001467 sdcard->Is_Decrypted = false;
1468 sdcard->Decrypted_Block_Device = "";
1469 }
Dees_Troy20c02c02013-01-10 14:14:10 +00001470#endif
Dees_Troy85f44ed2013-01-09 18:42:36 +00001471#endif //ifdef TW_EXTERNAL_STORAGE_PATH
a39552696ff55ce2013-01-08 16:14:56 +00001472
Dees_Troy5bf43922012-09-07 16:07:55 -04001473 // Sleep for a bit so that the device will be ready
1474 sleep(1);
Dees_Troy16b74352012-11-14 22:27:31 +00001475#ifdef RECOVERY_SDCARD_ON_DATA
1476 if (dat->Mount(false) && TWFunc::Path_Exists("/data/media/0")) {
1477 dat->Storage_Path = "/data/media/0";
1478 dat->Symlink_Path = dat->Storage_Path;
Dees Troy98fb46c2013-12-04 16:56:45 +00001479 DataManager::SetValue("tw_storage_path", "/data/media/0");
Dees_Troy16b74352012-11-14 22:27:31 +00001480 dat->UnMount(false);
Dees_Troydc8bc1b2013-01-17 01:39:28 +00001481 Output_Partition(dat);
Dees_Troy16b74352012-11-14 22:27:31 +00001482 }
1483#endif
Dees_Troy5bf43922012-09-07 16:07:55 -04001484 Update_System_Details();
Dees_Troyd0384ef2012-10-12 12:15:42 -04001485 UnMount_Main_Partitions();
Dees_Troy5bf43922012-09-07 16:07:55 -04001486 } else
Dees_Troy2673cec2013-04-02 20:22:16 +00001487 LOGERR("Unable to locate data partition.\n");
Dees_Troy5bf43922012-09-07 16:07:55 -04001488 }
1489 return 0;
1490#else
Dees_Troy2673cec2013-04-02 20:22:16 +00001491 LOGERR("No crypto support was compiled into this build.\n");
Dees_Troy5bf43922012-09-07 16:07:55 -04001492 return -1;
1493#endif
Dees_Troy51a0e822012-09-05 15:24:24 -04001494 return 1;
Dees_Troy51127312012-09-08 13:08:49 -04001495}
1496
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -04001497int TWPartitionManager::Fix_Permissions(void) {
1498 int result = 0;
1499 if (!Mount_By_Path("/data", true))
1500 return false;
1501
1502 if (!Mount_By_Path("/system", true))
1503 return false;
1504
1505 Mount_By_Path("/sd-ext", false);
1506
1507 fixPermissions perms;
1508 result = perms.fixPerms(true, false);
Dees_Troy1a650e62012-10-19 20:54:32 -04001509 UnMount_Main_Partitions();
Dees_Troy2673cec2013-04-02 20:22:16 +00001510 gui_print("Done.\n\n");
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -04001511 return result;
1512}
1513
Dees_Troyd21618c2012-10-14 18:48:49 -04001514int TWPartitionManager::Open_Lun_File(string Partition_Path, string Lun_File) {
Dees_Troyd21618c2012-10-14 18:48:49 -04001515 TWPartition* Part = Find_Partition_By_Path(Partition_Path);
1516
1517 if (Part == NULL) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001518 LOGERR("Unable to locate volume information for USB storage mode.");
Dees_Troyd21618c2012-10-14 18:48:49 -04001519 return false;
1520 }
1521 if (!Part->UnMount(true))
1522 return false;
1523
Dees_Troy2673cec2013-04-02 20:22:16 +00001524 if (TWFunc::write_file(Lun_File, Part->Actual_Block_Device)) {
1525 LOGERR("Unable to write to ums lunfile '%s': (%s)\n", Lun_File.c_str(), strerror(errno));
Dees_Troyd21618c2012-10-14 18:48:49 -04001526 return false;
1527 }
Matt Mowerd9cb9062013-12-14 20:34:45 -06001528 property_set("sys.storage.ums_enabled", "1");
Dees_Troyd21618c2012-10-14 18:48:49 -04001529 return true;
1530}
1531
Dees_Troy8170a922012-09-18 15:40:25 -04001532int TWPartitionManager::usb_storage_enable(void) {
Dees_Troyd21618c2012-10-14 18:48:49 -04001533 int has_dual, has_data_media;
Dees_Troy8170a922012-09-18 15:40:25 -04001534 char lun_file[255];
Dees_Troy8170a922012-09-18 15:40:25 -04001535 string ext_path;
Dees_Troyd21618c2012-10-14 18:48:49 -04001536 bool has_multiple_lun = false;
Dees_Troy8170a922012-09-18 15:40:25 -04001537
1538 DataManager::GetValue(TW_HAS_DUAL_STORAGE, has_dual);
1539 DataManager::GetValue(TW_HAS_DATA_MEDIA, has_data_media);
1540 if (has_dual == 1 && has_data_media == 0) {
Dees_Troyd21618c2012-10-14 18:48:49 -04001541 string Lun_File_str = CUSTOM_LUN_FILE;
1542 size_t found = Lun_File_str.find("%");
1543 if (found != string::npos) {
1544 sprintf(lun_file, CUSTOM_LUN_FILE, 1);
1545 if (TWFunc::Path_Exists(lun_file))
1546 has_multiple_lun = true;
1547 }
1548 if (!has_multiple_lun) {
Dees_Troyf4ca6122012-10-13 22:17:20 -04001549 // Device doesn't have multiple lun files, mount current storage
Dees_Troyf4ca6122012-10-13 22:17:20 -04001550 sprintf(lun_file, CUSTOM_LUN_FILE, 0);
Dees_Troyd21618c2012-10-14 18:48:49 -04001551 return Open_Lun_File(DataManager::GetCurrentStoragePath(), lun_file);
Dees_Troyf4ca6122012-10-13 22:17:20 -04001552 } else {
1553 // Device has multiple lun files
Dees_Troyf4ca6122012-10-13 22:17:20 -04001554 sprintf(lun_file, CUSTOM_LUN_FILE, 0);
Dees_Troyd21618c2012-10-14 18:48:49 -04001555 if (!Open_Lun_File(DataManager::GetSettingsStoragePath(), lun_file))
Dees_Troyf4ca6122012-10-13 22:17:20 -04001556 return false;
Dees_Troyf4ca6122012-10-13 22:17:20 -04001557 DataManager::GetValue(TW_EXTERNAL_PATH, ext_path);
Dees_Troyf4ca6122012-10-13 22:17:20 -04001558 sprintf(lun_file, CUSTOM_LUN_FILE, 1);
Dees_Troyd21618c2012-10-14 18:48:49 -04001559 return Open_Lun_File(ext_path, lun_file);
Dees_Troy8170a922012-09-18 15:40:25 -04001560 }
Dees_Troy8170a922012-09-18 15:40:25 -04001561 } else {
1562 if (has_data_media == 0)
1563 ext_path = DataManager::GetCurrentStoragePath();
1564 else
1565 DataManager::GetValue(TW_EXTERNAL_PATH, ext_path);
Dees_Troy8170a922012-09-18 15:40:25 -04001566 sprintf(lun_file, CUSTOM_LUN_FILE, 0);
Dees_Troyd21618c2012-10-14 18:48:49 -04001567 return Open_Lun_File(ext_path, lun_file);
Dees_Troy8170a922012-09-18 15:40:25 -04001568 }
1569 return true;
1570}
1571
1572int TWPartitionManager::usb_storage_disable(void) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001573 int index, ret;
1574 char lun_file[255], ch[2] = {0, 0};
1575 string str = ch;
Dees_Troy8170a922012-09-18 15:40:25 -04001576
1577 for (index=0; index<2; index++) {
1578 sprintf(lun_file, CUSTOM_LUN_FILE, index);
Dees_Troy2673cec2013-04-02 20:22:16 +00001579 ret = TWFunc::write_file(lun_file, str);
1580 Mount_All_Storage();
1581 Update_System_Details();
1582 if (ret < 0) {
1583 break;
Dees_Troy8170a922012-09-18 15:40:25 -04001584 }
Dees_Troy8170a922012-09-18 15:40:25 -04001585 }
Dees_Troye58d5262012-09-21 12:27:57 -04001586 Mount_All_Storage();
1587 Update_System_Details();
Dees_Troycfd73ef2012-10-12 16:52:00 -04001588 UnMount_Main_Partitions();
Matt Mowerd9cb9062013-12-14 20:34:45 -06001589 property_set("sys.storage.ums_enabled", "0");
Dees_Troy2673cec2013-04-02 20:22:16 +00001590 if (ret < 0 && index == 0) {
1591 LOGERR("Unable to write to ums lunfile '%s'.", lun_file);
1592 return false;
1593 } else {
1594 return true;
1595 }
Dees_Troy8170a922012-09-18 15:40:25 -04001596 return true;
Dees_Troy812660f2012-09-20 09:55:17 -04001597}
1598
1599void TWPartitionManager::Mount_All_Storage(void) {
1600 std::vector<TWPartition*>::iterator iter;
1601
1602 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
1603 if ((*iter)->Is_Storage)
1604 (*iter)->Mount(false);
1605 }
Dees_Troy2c50e182012-09-26 20:05:28 -04001606}
Dees_Troy9350b8d2012-09-27 12:38:38 -04001607
Dees_Troyd0384ef2012-10-12 12:15:42 -04001608void TWPartitionManager::UnMount_Main_Partitions(void) {
1609 // Unmounts system and data if data is not data/media
1610 // Also unmounts boot if boot is mountable
Dees_Troy2673cec2013-04-02 20:22:16 +00001611 LOGINFO("Unmounting main partitions...\n");
Dees_Troyd0384ef2012-10-12 12:15:42 -04001612
1613 TWPartition* Boot_Partition = Find_Partition_By_Path("/boot");
1614
1615 UnMount_By_Path("/system", true);
1616#ifndef RECOVERY_SDCARD_ON_DATA
1617 UnMount_By_Path("/data", true);
1618#endif
1619 if (Boot_Partition != NULL && Boot_Partition->Can_Be_Mounted)
1620 Boot_Partition->UnMount(true);
1621}
1622
Dees_Troy9350b8d2012-09-27 12:38:38 -04001623int TWPartitionManager::Partition_SDCard(void) {
1624 char mkdir_path[255], temp[255], line[512];
1625 string Command, Device, fat_str, ext_str, swap_str, start_loc, end_loc, ext_format, sd_path, tmpdevice;
1626 int ext, swap, total_size = 0, fat_size;
1627 FILE* fp;
1628
Dees_Troy2673cec2013-04-02 20:22:16 +00001629 gui_print("Partitioning SD Card...\n");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001630#ifdef TW_EXTERNAL_STORAGE_PATH
1631 TWPartition* SDCard = Find_Partition_By_Path(EXPAND(TW_EXTERNAL_STORAGE_PATH));
1632#else
1633 TWPartition* SDCard = Find_Partition_By_Path("/sdcard");
1634#endif
1635 if (SDCard == NULL) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001636 LOGERR("Unable to locate device to partition.\n");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001637 return false;
1638 }
1639 if (!SDCard->UnMount(true))
1640 return false;
1641 TWPartition* SDext = Find_Partition_By_Path("/sd-ext");
1642 if (SDext != NULL) {
1643 if (!SDext->UnMount(true))
1644 return false;
1645 }
Vojtech Bocek05534202013-09-11 08:11:56 +02001646
1647 TWFunc::Exec_Cmd("umount \"$SWAPPATH\"");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001648 Device = SDCard->Actual_Block_Device;
1649 // Just use the root block device
1650 Device.resize(strlen("/dev/block/mmcblkX"));
1651
1652 // Find the size of the block device:
1653 fp = fopen("/proc/partitions", "rt");
1654 if (fp == NULL) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001655 LOGERR("Unable to open /proc/partitions\n");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001656 return false;
1657 }
1658
1659 while (fgets(line, sizeof(line), fp) != NULL)
1660 {
1661 unsigned long major, minor, blocks;
1662 char device[512];
1663 char tmpString[64];
1664
1665 if (strlen(line) < 7 || line[0] == 'm') continue;
1666 sscanf(line + 1, "%lu %lu %lu %s", &major, &minor, &blocks, device);
1667
1668 tmpdevice = "/dev/block/";
1669 tmpdevice += device;
1670 if (tmpdevice == Device) {
1671 // Adjust block size to byte size
1672 total_size = (int)(blocks * 1024ULL / 1000000LLU);
1673 break;
1674 }
1675 }
1676 fclose(fp);
1677
1678 DataManager::GetValue("tw_sdext_size", ext);
1679 DataManager::GetValue("tw_swap_size", swap);
1680 DataManager::GetValue("tw_sdpart_file_system", ext_format);
1681 fat_size = total_size - ext - swap;
Dees_Troy2673cec2013-04-02 20:22:16 +00001682 LOGINFO("sd card block device is '%s', sdcard size is: %iMB, fat size: %iMB, ext size: %iMB, ext system: '%s', swap size: %iMB\n", Device.c_str(), total_size, fat_size, ext, ext_format.c_str(), swap);
Dees_Troy9350b8d2012-09-27 12:38:38 -04001683 memset(temp, 0, sizeof(temp));
1684 sprintf(temp, "%i", fat_size);
1685 fat_str = temp;
1686 memset(temp, 0, sizeof(temp));
1687 sprintf(temp, "%i", fat_size + ext);
1688 ext_str = temp;
1689 memset(temp, 0, sizeof(temp));
1690 sprintf(temp, "%i", fat_size + ext + swap);
1691 swap_str = temp;
1692 if (ext + swap > total_size) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001693 LOGERR("EXT + Swap size is larger than sdcard size.\n");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001694 return false;
1695 }
Dees_Troy2673cec2013-04-02 20:22:16 +00001696 gui_print("Removing partition table...\n");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001697 Command = "parted -s " + Device + " mklabel msdos";
Dees_Troy2673cec2013-04-02 20:22:16 +00001698 LOGINFO("Command is: '%s'\n", Command.c_str());
Vojtech Bocek05534202013-09-11 08:11:56 +02001699 if (TWFunc::Exec_Cmd(Command) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001700 LOGERR("Unable to remove partition table.\n");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001701 Update_System_Details();
1702 return false;
1703 }
Dees_Troy2673cec2013-04-02 20:22:16 +00001704 gui_print("Creating FAT32 partition...\n");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001705 Command = "parted " + Device + " mkpartfs primary fat32 0 " + fat_str + "MB";
Dees_Troy2673cec2013-04-02 20:22:16 +00001706 LOGINFO("Command is: '%s'\n", Command.c_str());
Vojtech Bocek05534202013-09-11 08:11:56 +02001707 if (TWFunc::Exec_Cmd(Command) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001708 LOGERR("Unable to create FAT32 partition.\n");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001709 return false;
1710 }
1711 if (ext > 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001712 gui_print("Creating EXT partition...\n");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001713 Command = "parted " + Device + " mkpartfs primary ext2 " + fat_str + "MB " + ext_str + "MB";
Dees_Troy2673cec2013-04-02 20:22:16 +00001714 LOGINFO("Command is: '%s'\n", Command.c_str());
Vojtech Bocek05534202013-09-11 08:11:56 +02001715 if (TWFunc::Exec_Cmd(Command) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001716 LOGERR("Unable to create EXT partition.\n");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001717 Update_System_Details();
1718 return false;
1719 }
1720 }
1721 if (swap > 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001722 gui_print("Creating swap partition...\n");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001723 Command = "parted " + Device + " mkpartfs primary linux-swap " + ext_str + "MB " + swap_str + "MB";
Dees_Troy2673cec2013-04-02 20:22:16 +00001724 LOGINFO("Command is: '%s'\n", Command.c_str());
Vojtech Bocek05534202013-09-11 08:11:56 +02001725 if (TWFunc::Exec_Cmd(Command) != 0) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001726 LOGERR("Unable to create swap partition.\n");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001727 Update_System_Details();
1728 return false;
1729 }
1730 }
1731 // recreate TWRP folder and rewrite settings - these will be gone after sdcard is partitioned
1732#ifdef TW_EXTERNAL_STORAGE_PATH
1733 Mount_By_Path(EXPAND(TW_EXTERNAL_STORAGE_PATH), 1);
1734 DataManager::GetValue(TW_EXTERNAL_PATH, sd_path);
1735 memset(mkdir_path, 0, sizeof(mkdir_path));
1736 sprintf(mkdir_path, "%s/TWRP", sd_path.c_str());
1737#else
1738 Mount_By_Path("/sdcard", 1);
1739 strcpy(mkdir_path, "/sdcard/TWRP");
1740#endif
1741 mkdir(mkdir_path, 0777);
1742 DataManager::Flush();
1743#ifdef TW_EXTERNAL_STORAGE_PATH
1744 DataManager::SetValue(TW_ZIP_EXTERNAL_VAR, EXPAND(TW_EXTERNAL_STORAGE_PATH));
1745 if (DataManager::GetIntValue(TW_USE_EXTERNAL_STORAGE) == 1)
1746 DataManager::SetValue(TW_ZIP_LOCATION_VAR, EXPAND(TW_EXTERNAL_STORAGE_PATH));
1747#else
1748 DataManager::SetValue(TW_ZIP_EXTERNAL_VAR, "/sdcard");
1749 if (DataManager::GetIntValue(TW_USE_EXTERNAL_STORAGE) == 1)
1750 DataManager::SetValue(TW_ZIP_LOCATION_VAR, "/sdcard");
1751#endif
1752 if (ext > 0) {
1753 if (SDext == NULL) {
Dees_Troy2673cec2013-04-02 20:22:16 +00001754 LOGERR("Unable to locate sd-ext partition.\n");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001755 return false;
1756 }
1757 Command = "mke2fs -t " + ext_format + " -m 0 " + SDext->Actual_Block_Device;
Dees_Troy2673cec2013-04-02 20:22:16 +00001758 gui_print("Formatting sd-ext as %s...\n", ext_format.c_str());
1759 LOGINFO("Formatting sd-ext after partitioning, command: '%s'\n", Command.c_str());
Vojtech Bocek05534202013-09-11 08:11:56 +02001760 TWFunc::Exec_Cmd(Command);
Dees_Troy9350b8d2012-09-27 12:38:38 -04001761 }
1762
1763 Update_System_Details();
Dees_Troy2673cec2013-04-02 20:22:16 +00001764 gui_print("Partitioning complete.\n");
Dees_Troy9350b8d2012-09-27 12:38:38 -04001765 return true;
bigbiff bigbiffa0f8a592012-10-09 21:01:03 -04001766}
Dees_Troya13d74f2013-03-24 08:54:55 -05001767
1768void TWPartitionManager::Get_Partition_List(string ListType, std::vector<PartitionList> *Partition_List) {
1769 std::vector<TWPartition*>::iterator iter;
1770 if (ListType == "mount") {
1771 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
1772 if ((*iter)->Can_Be_Mounted && !(*iter)->Is_SubPartition) {
1773 struct PartitionList part;
1774 part.Display_Name = (*iter)->Display_Name;
1775 part.Mount_Point = (*iter)->Mount_Point;
1776 part.selected = (*iter)->Is_Mounted();
1777 Partition_List->push_back(part);
1778 }
1779 }
1780 } else if (ListType == "storage") {
1781 char free_space[255];
1782 string Current_Storage = DataManager::GetCurrentStoragePath();
1783 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
1784 if ((*iter)->Is_Storage) {
1785 struct PartitionList part;
1786 sprintf(free_space, "%llu", (*iter)->Free / 1024 / 1024);
1787 part.Display_Name = (*iter)->Storage_Name + " (";
1788 part.Display_Name += free_space;
1789 part.Display_Name += "MB)";
1790 part.Mount_Point = (*iter)->Storage_Path;
1791 if ((*iter)->Storage_Path == Current_Storage)
1792 part.selected = 1;
1793 else
1794 part.selected = 0;
1795 Partition_List->push_back(part);
1796 }
1797 }
1798 } else if (ListType == "backup") {
1799 char backup_size[255];
Dees_Troy9e0b71c2013-04-08 13:35:37 +00001800 unsigned long long Backup_Size;
Dees_Troya13d74f2013-03-24 08:54:55 -05001801 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
Dees_Troy9e0b71c2013-04-08 13:35:37 +00001802 if ((*iter)->Can_Be_Backed_Up && !(*iter)->Is_SubPartition && (*iter)->Is_Present) {
Dees_Troya13d74f2013-03-24 08:54:55 -05001803 struct PartitionList part;
Dees_Troy9e0b71c2013-04-08 13:35:37 +00001804 Backup_Size = (*iter)->Backup_Size;
1805 if ((*iter)->Has_SubPartition) {
1806 std::vector<TWPartition*>::iterator subpart;
1807
1808 for (subpart = Partitions.begin(); subpart != Partitions.end(); subpart++) {
1809 if ((*subpart)->Is_SubPartition && (*subpart)->Can_Be_Backed_Up && (*subpart)->Is_Present && (*subpart)->SubPartition_Of == (*iter)->Mount_Point)
1810 Backup_Size += (*subpart)->Backup_Size;
1811 }
1812 }
1813 sprintf(backup_size, "%llu", Backup_Size / 1024 / 1024);
Dees_Troya13d74f2013-03-24 08:54:55 -05001814 part.Display_Name = (*iter)->Backup_Display_Name + " (";
1815 part.Display_Name += backup_size;
1816 part.Display_Name += "MB)";
1817 part.Mount_Point = (*iter)->Backup_Path;
1818 part.selected = 0;
1819 Partition_List->push_back(part);
1820 }
1821 }
1822 } else if (ListType == "restore") {
1823 string Restore_List, restore_path;
1824 TWPartition* restore_part = NULL;
1825
1826 DataManager::GetValue("tw_restore_list", Restore_List);
1827 if (!Restore_List.empty()) {
1828 size_t start_pos = 0, end_pos = Restore_List.find(";", start_pos);
1829 while (end_pos != string::npos && start_pos < Restore_List.size()) {
1830 restore_path = Restore_List.substr(start_pos, end_pos - start_pos);
Dees_Troy59df9262013-06-19 14:53:57 -05001831 if ((restore_part = Find_Partition_By_Path(restore_path)) != NULL) {
1832 if (restore_part->Backup_Name == "recovery" || restore_part->Is_SubPartition) {
Dees_Troya13d74f2013-03-24 08:54:55 -05001833 // Don't allow restore of recovery (causes problems on some devices)
Dees_Troy59df9262013-06-19 14:53:57 -05001834 // Don't add subpartitions to the list of items
Dees_Troya13d74f2013-03-24 08:54:55 -05001835 } else {
1836 struct PartitionList part;
1837 part.Display_Name = restore_part->Backup_Display_Name;
1838 part.Mount_Point = restore_part->Backup_Path;
1839 part.selected = 1;
1840 Partition_List->push_back(part);
1841 }
1842 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +00001843 LOGERR("Unable to locate '%s' partition for restore.\n", restore_path.c_str());
Dees_Troya13d74f2013-03-24 08:54:55 -05001844 }
1845 start_pos = end_pos + 1;
1846 end_pos = Restore_List.find(";", start_pos);
1847 }
1848 }
1849 } else if (ListType == "wipe") {
1850 struct PartitionList dalvik;
1851 dalvik.Display_Name = "Dalvik Cache";
1852 dalvik.Mount_Point = "DALVIK";
1853 dalvik.selected = 0;
1854 Partition_List->push_back(dalvik);
1855 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
1856 if ((*iter)->Wipe_Available_in_GUI && !(*iter)->Is_SubPartition) {
1857 struct PartitionList part;
1858 part.Display_Name = (*iter)->Display_Name;
1859 part.Mount_Point = (*iter)->Mount_Point;
1860 part.selected = 0;
1861 Partition_List->push_back(part);
1862 }
1863 if ((*iter)->Has_Android_Secure) {
1864 struct PartitionList part;
1865 part.Display_Name = (*iter)->Backup_Display_Name;
1866 part.Mount_Point = (*iter)->Backup_Path;
1867 part.selected = 0;
1868 Partition_List->push_back(part);
1869 }
Dees_Troy74fb2e92013-04-15 14:35:47 +00001870 if ((*iter)->Has_Data_Media) {
1871 struct PartitionList datamedia;
1872 datamedia.Display_Name = (*iter)->Storage_Name;
1873 datamedia.Mount_Point = "INTERNAL";
1874 datamedia.selected = 0;
1875 Partition_List->push_back(datamedia);
1876 }
Dees_Troya13d74f2013-03-24 08:54:55 -05001877 }
1878 } else {
Dees_Troy2673cec2013-04-02 20:22:16 +00001879 LOGERR("Unknown list type '%s' requested for TWPartitionManager::Get_Partition_List\n", ListType.c_str());
Dees_Troya13d74f2013-03-24 08:54:55 -05001880 }
1881}
1882
1883int TWPartitionManager::Fstab_Processed(void) {
1884 return Partitions.size();
1885}
Dees_Troyd93bda52013-07-03 19:55:19 +00001886
1887void TWPartitionManager::Output_Storage_Fstab(void) {
1888 std::vector<TWPartition*>::iterator iter;
1889 char storage_partition[255];
1890 string Temp;
1891 FILE *fp = fopen("/cache/recovery/storage.fstab", "w");
1892
1893 if (fp == NULL) {
1894 LOGERR("Unable to open '/cache/recovery/storage.fstab'.\n");
1895 return;
1896 }
1897
1898 // Iterate through all partitions
1899 for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
1900 if ((*iter)->Is_Storage) {
1901 Temp = (*iter)->Storage_Path + ";" + (*iter)->Storage_Name + ";\n";
1902 strcpy(storage_partition, Temp.c_str());
1903 fwrite(storage_partition, sizeof(storage_partition[0]), strlen(storage_partition) / sizeof(storage_partition[0]), fp);
1904 }
1905 }
1906 fclose(fp);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001907}