blob: cf7aab87edbd80057e8b862ff3ffbfc95edd7d5b [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001/* Partition class for TWRP
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 *
17 * The code was written from scratch by Dees_Troy dees_troy at
18 * yahoo
19 *
20 * Copyright (c) 2012
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/stat.h>
27#include <sys/vfs.h>
Dees_Troy5bf43922012-09-07 16:07:55 -040028#include <sys/mount.h>
Dees_Troy51a0e822012-09-05 15:24:24 -040029#include <unistd.h>
Dees_Troy51127312012-09-08 13:08:49 -040030#include <dirent.h>
Dees_Troy51a0e822012-09-05 15:24:24 -040031
Dees_Troy657c3092012-09-10 20:32:10 -040032#ifdef TW_INCLUDE_CRYPTO
33 #include "cutils/properties.h"
34#endif
35
Dees_Troy51a0e822012-09-05 15:24:24 -040036#include "variables.h"
37#include "common.h"
38#include "partitions.hpp"
Dees_Troy5bf43922012-09-07 16:07:55 -040039#include "data.hpp"
Dees_Troy43d8b002012-09-17 16:00:01 -040040#include "twrp-functions.hpp"
Dees_Troy9df963c2012-09-26 08:58:12 -040041#include "makelist.hpp"
Dees_Troy5bf43922012-09-07 16:07:55 -040042extern "C" {
Dees_Troy38bd7602012-09-14 13:33:53 -040043 #include "mtdutils/mtdutils.h"
44 #include "mtdutils/mounts.h"
Dees_Troy5bf43922012-09-07 16:07:55 -040045}
Dees_Troy51a0e822012-09-05 15:24:24 -040046
47TWPartition::TWPartition(void) {
48 Can_Be_Mounted = false;
49 Can_Be_Wiped = false;
50 Wipe_During_Factory_Reset = false;
51 Wipe_Available_in_GUI = false;
52 Is_SubPartition = false;
Dees_Troy2691f9d2012-09-24 11:15:49 -040053 Has_SubPartition = false;
Dees_Troy51a0e822012-09-05 15:24:24 -040054 SubPartition_Of = "";
55 Symlink_Path = "";
56 Symlink_Mount_Point = "";
57 Mount_Point = "";
Dees_Troye58d5262012-09-21 12:27:57 -040058 Backup_Path = "";
Dees_Troy38bd7602012-09-14 13:33:53 -040059 Actual_Block_Device = "";
60 Primary_Block_Device = "";
Dees_Troy51a0e822012-09-05 15:24:24 -040061 Alternate_Block_Device = "";
62 Removable = false;
63 Is_Present = false;
64 Length = 0;
65 Size = 0;
66 Used = 0;
67 Free = 0;
68 Backup_Size = 0;
69 Can_Be_Encrypted = false;
70 Is_Encrypted = false;
71 Is_Decrypted = false;
72 Decrypted_Block_Device = "";
73 Display_Name = "";
74 Backup_Name = "";
Dees_Troy63c8df72012-09-10 14:02:05 -040075 Backup_FileName = "";
Dees_Troy38bd7602012-09-14 13:33:53 -040076 MTD_Name = "";
Dees_Troy51a0e822012-09-05 15:24:24 -040077 Backup_Method = NONE;
78 Has_Data_Media = false;
Dees_Troye58d5262012-09-21 12:27:57 -040079 Has_Android_Secure = false;
Dees_Troy51a0e822012-09-05 15:24:24 -040080 Is_Storage = false;
81 Storage_Path = "";
82 Current_File_System = "";
83 Fstab_File_System = "";
84 Format_Block_Size = 0;
85}
86
87TWPartition::~TWPartition(void) {
88 // Do nothing
89}
90
Dees_Troy5bf43922012-09-07 16:07:55 -040091bool TWPartition::Process_Fstab_Line(string Line, bool Display_Error) {
92 char full_line[MAX_FSTAB_LINE_LENGTH], item[MAX_FSTAB_LINE_LENGTH];
93 int line_len = Line.size(), index = 0, item_index = 0;
94 char* ptr;
Dees_Troy51127312012-09-08 13:08:49 -040095 string Flags;
Dees_Troy5bf43922012-09-07 16:07:55 -040096
97 strncpy(full_line, Line.c_str(), line_len);
98
Dees_Troy51127312012-09-08 13:08:49 -040099 for (index = 0; index < line_len; index++) {
Dees_Troy5bf43922012-09-07 16:07:55 -0400100 if (full_line[index] <= 32)
101 full_line[index] = '\0';
Dees_Troy5bf43922012-09-07 16:07:55 -0400102 }
Dees_Troy7c2dec82012-09-26 09:49:14 -0400103 Mount_Point = full_line;
104 LOGI("Processing '%s'\n", Mount_Point.c_str());
Dees_Troye58d5262012-09-21 12:27:57 -0400105 Backup_Path = Mount_Point;
Dees_Troy5bf43922012-09-07 16:07:55 -0400106 index = Mount_Point.size();
107 while (index < line_len) {
108 while (index < line_len && full_line[index] == '\0')
109 index++;
110 if (index >= line_len)
111 continue;
112 ptr = full_line + index;
113 if (item_index == 0) {
114 // File System
115 Fstab_File_System = ptr;
116 Current_File_System = ptr;
117 item_index++;
118 } else if (item_index == 1) {
119 // Primary Block Device
Dees_Troy38bd7602012-09-14 13:33:53 -0400120 if (Fstab_File_System == "mtd" || Fstab_File_System == "yaffs2") {
Dees_Troy094207a2012-09-26 12:00:39 -0400121 MTD_Name = ptr;
122 Find_MTD_Block_Device(MTD_Name);
Dees_Troy5fcd8f92012-10-16 12:22:05 -0400123 } else if (Fstab_File_System == "bml") {
124 if (Mount_Point == "/boot")
125 MTD_Name = "boot";
126 else if (Mount_Point == "/recovery")
127 MTD_Name = "recovery";
128 Primary_Block_Device = ptr;
129 if (*ptr != '/')
130 LOGE("Until we get better BML support, you will have to find and provide the full block device path to the BML devices e.g. /dev/block/bml9 instead of the partition name\n");
Dees_Troy38bd7602012-09-14 13:33:53 -0400131 } else if (*ptr != '/') {
Dees_Troy5bf43922012-09-07 16:07:55 -0400132 if (Display_Error)
133 LOGE("Invalid block device on '%s', '%s', %i\n", Line.c_str(), ptr, index);
134 else
135 LOGI("Invalid block device on '%s', '%s', %i\n", Line.c_str(), ptr, index);
136 return 0;
Dees_Troy38bd7602012-09-14 13:33:53 -0400137 } else {
138 Primary_Block_Device = ptr;
139 Find_Real_Block_Device(Primary_Block_Device, Display_Error);
Dees_Troy5bf43922012-09-07 16:07:55 -0400140 }
Dees_Troy5bf43922012-09-07 16:07:55 -0400141 item_index++;
142 } else if (item_index > 1) {
143 if (*ptr == '/') {
144 // Alternate Block Device
145 Alternate_Block_Device = ptr;
146 Find_Real_Block_Device(Alternate_Block_Device, Display_Error);
147 } else if (strlen(ptr) > 7 && strncmp(ptr, "length=", 7) == 0) {
148 // Partition length
149 ptr += 7;
150 Length = atoi(ptr);
Dees_Troy51127312012-09-08 13:08:49 -0400151 } else if (strlen(ptr) > 6 && strncmp(ptr, "flags=", 6) == 0) {
152 // Custom flags, save for later so that new values aren't overwritten by defaults
153 ptr += 6;
154 Flags = ptr;
Dees_Troy38bd7602012-09-14 13:33:53 -0400155 } else if (strlen(ptr) == 4 && (strncmp(ptr, "NULL", 4) == 0 || strncmp(ptr, "null", 4) == 0 || strncmp(ptr, "null", 4) == 0)) {
156 // Do nothing
Dees_Troy5bf43922012-09-07 16:07:55 -0400157 } else {
158 // Unhandled data
Dees_Troyab10ee22012-09-21 14:27:30 -0400159 LOGI("Unhandled fstab information: '%s', %i, line: '%s'\n", ptr, index, Line.c_str());
Dees_Troy5bf43922012-09-07 16:07:55 -0400160 }
161 }
162 while (index < line_len && full_line[index] != '\0')
163 index++;
164 }
165
166 if (!Is_File_System(Fstab_File_System) && !Is_Image(Fstab_File_System)) {
167 if (Display_Error)
168 LOGE("Unknown File System: '%s'\n", Fstab_File_System.c_str());
169 else
170 LOGI("Unknown File System: '%s'\n", Fstab_File_System.c_str());
171 return 0;
172 } else if (Is_File_System(Fstab_File_System)) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400173 Find_Actual_Block_Device();
Dees_Troy5bf43922012-09-07 16:07:55 -0400174 Setup_File_System(Display_Error);
175 if (Mount_Point == "/system") {
176 Display_Name = "System";
177 Wipe_Available_in_GUI = true;
Dees_Troy5bf43922012-09-07 16:07:55 -0400178 } else if (Mount_Point == "/data") {
179 Display_Name = "Data";
180 Wipe_Available_in_GUI = true;
Dees_Troy51127312012-09-08 13:08:49 -0400181 Wipe_During_Factory_Reset = true;
Dees_Troy5bf43922012-09-07 16:07:55 -0400182#ifdef RECOVERY_SDCARD_ON_DATA
183 Has_Data_Media = true;
Dees_Troy51127312012-09-08 13:08:49 -0400184 Is_Storage = true;
185 Storage_Path = "/data/media";
Dees_Troy657c3092012-09-10 20:32:10 -0400186 if (strcmp(EXPAND(TW_EXTERNAL_STORAGE_PATH), "/sdcard") == 0) {
187 Make_Dir("/emmc", Display_Error);
188 Symlink_Path = "/data/media";
189 Symlink_Mount_Point = "/emmc";
190 } else {
191 Make_Dir("/sdcard", Display_Error);
192 Symlink_Path = "/data/media";
193 Symlink_Mount_Point = "/sdcard";
194 }
Dees_Troy5bf43922012-09-07 16:07:55 -0400195#endif
196#ifdef TW_INCLUDE_CRYPTO
197 Can_Be_Encrypted = true;
Dees_Troy657c3092012-09-10 20:32:10 -0400198 char crypto_blkdev[255];
199 property_get("ro.crypto.fs_crypto_blkdev", crypto_blkdev, "error");
200 if (strcmp(crypto_blkdev, "error") != 0) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400201 DataManager::SetValue(TW_DATA_BLK_DEVICE, Primary_Block_Device);
Dees_Troy657c3092012-09-10 20:32:10 -0400202 DataManager::SetValue(TW_IS_DECRYPTED, 1);
203 Is_Encrypted = true;
204 Is_Decrypted = true;
205 Decrypted_Block_Device = crypto_blkdev;
206 LOGI("Data already decrypted, new block device: '%s'\n", crypto_blkdev);
207 } else if (!Mount(false)) {
Dees_Troy5bf43922012-09-07 16:07:55 -0400208 Is_Encrypted = true;
209 Is_Decrypted = false;
210 DataManager::SetValue(TW_IS_ENCRYPTED, 1);
211 DataManager::SetValue(TW_CRYPTO_PASSWORD, "");
212 DataManager::SetValue("tw_crypto_display", "");
Dees_Troy51127312012-09-08 13:08:49 -0400213 }
Dees_Troy9b21af72012-10-01 15:51:46 -0400214 #ifdef RECOVERY_SDCARD_ON_DATA
215 if (!Is_Encrypted || (Is_Encrypted && Is_Decrypted))
216 Recreate_Media_Folder();
217 #endif
218#else
219 #ifdef RECOVERY_SDCARD_ON_DATA
220 Recreate_Media_Folder();
221 #endif
Dees_Troy5bf43922012-09-07 16:07:55 -0400222#endif
Dees_Troy5bf43922012-09-07 16:07:55 -0400223 } else if (Mount_Point == "/cache") {
224 Display_Name = "Cache";
225 Wipe_Available_in_GUI = true;
Dees_Troy51127312012-09-08 13:08:49 -0400226 Wipe_During_Factory_Reset = true;
Dees_Troyce2fe772012-09-28 12:34:33 -0400227 if (Mount(false) && !TWFunc::Path_Exists("/cache/recovery/.")) {
228 string Recreate_Command = "cd /cache && mkdir recovery";
Dees_Troyb46a6842012-09-25 11:06:46 -0400229 LOGI("Recreating /cache/recovery folder.\n");
Dees_Troyce2fe772012-09-28 12:34:33 -0400230 system(Recreate_Command.c_str());
Dees_Troyb46a6842012-09-25 11:06:46 -0400231 }
Dees_Troy5bf43922012-09-07 16:07:55 -0400232 } else if (Mount_Point == "/datadata") {
Dees_Troy51127312012-09-08 13:08:49 -0400233 Wipe_During_Factory_Reset = true;
Dees_Troy5bf43922012-09-07 16:07:55 -0400234 Display_Name = "DataData";
235 Is_SubPartition = true;
236 SubPartition_Of = "/data";
Dees_Troy5bf43922012-09-07 16:07:55 -0400237 DataManager::SetValue(TW_HAS_DATADATA, 1);
238 } else if (Mount_Point == "/sd-ext") {
Dees_Troy51127312012-09-08 13:08:49 -0400239 Wipe_During_Factory_Reset = true;
Dees_Troy5bf43922012-09-07 16:07:55 -0400240 Display_Name = "SD-Ext";
241 Wipe_Available_in_GUI = true;
Dees_Troyc51f1f92012-09-20 15:32:13 -0400242 Removable = true;
Dees_Troy2c50e182012-09-26 20:05:28 -0400243 } else if (Mount_Point == "/boot") {
244 Display_Name = "Boot";
245 DataManager::SetValue("tw_boot_is_mountable", 1);
Dees_Troy8170a922012-09-18 15:40:25 -0400246 }
247#ifdef TW_EXTERNAL_STORAGE_PATH
248 if (Mount_Point == EXPAND(TW_EXTERNAL_STORAGE_PATH)) {
249 Is_Storage = true;
250 Storage_Path = EXPAND(TW_EXTERNAL_STORAGE_PATH);
Dees_Troyc51f1f92012-09-20 15:32:13 -0400251 Removable = true;
Dees_Troy8170a922012-09-18 15:40:25 -0400252 }
253#else
254 if (Mount_Point == "/sdcard") {
255 Is_Storage = true;
256 Storage_Path = "/sdcard";
Dees_Troyc51f1f92012-09-20 15:32:13 -0400257 Removable = true;
Dees_Troye58d5262012-09-21 12:27:57 -0400258#ifndef RECOVERY_SDCARD_ON_DATA
259 Setup_AndSec();
Dees_Troy8e337f32012-10-13 22:07:49 -0400260 Mount_Storage_Retry();
Dees_Troye58d5262012-09-21 12:27:57 -0400261#endif
Dees_Troy8170a922012-09-18 15:40:25 -0400262 }
263#endif
264#ifdef TW_INTERNAL_STORAGE_PATH
265 if (Mount_Point == EXPAND(TW_INTERNAL_STORAGE_PATH)) {
266 Is_Storage = true;
267 Storage_Path = EXPAND(TW_INTERNAL_STORAGE_PATH);
Dees_Troye58d5262012-09-21 12:27:57 -0400268#ifndef RECOVERY_SDCARD_ON_DATA
269 Setup_AndSec();
Dees_Troy8e337f32012-10-13 22:07:49 -0400270 Mount_Storage_Retry();
Dees_Troye58d5262012-09-21 12:27:57 -0400271#endif
Dees_Troy8170a922012-09-18 15:40:25 -0400272 }
273#else
274 if (Mount_Point == "/emmc") {
275 Is_Storage = true;
276 Storage_Path = "/emmc";
Dees_Troye58d5262012-09-21 12:27:57 -0400277#ifndef RECOVERY_SDCARD_ON_DATA
278 Setup_AndSec();
Dees_Troy8e337f32012-10-13 22:07:49 -0400279 Mount_Storage_Retry();
Dees_Troye58d5262012-09-21 12:27:57 -0400280#endif
Dees_Troy8170a922012-09-18 15:40:25 -0400281 }
282#endif
Dees_Troy5bf43922012-09-07 16:07:55 -0400283 } else if (Is_Image(Fstab_File_System)) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400284 Find_Actual_Block_Device();
Dees_Troy5bf43922012-09-07 16:07:55 -0400285 Setup_Image(Display_Error);
Dees_Troy5bf43922012-09-07 16:07:55 -0400286 }
287
Dees_Troy51127312012-09-08 13:08:49 -0400288 // Process any custom flags
289 if (Flags.size() > 0)
290 Process_Flags(Flags, Display_Error);
291
292 return true;
293}
294
295bool TWPartition::Process_Flags(string Flags, bool Display_Error) {
296 char flags[MAX_FSTAB_LINE_LENGTH];
297 int flags_len, index = 0;
298 char* ptr;
299
300 strcpy(flags, Flags.c_str());
301 flags_len = Flags.size();
302 for (index = 0; index < flags_len; index++) {
303 if (flags[index] == ';')
304 flags[index] = '\0';
305 }
306
307 index = 0;
308 while (index < flags_len) {
309 while (index < flags_len && flags[index] == '\0')
310 index++;
311 if (index >= flags_len)
312 continue;
313 ptr = flags + index;
314 if (strcmp(ptr, "removable") == 0) {
315 Removable = true;
316 } else if (strcmp(ptr, "storage") == 0) {
317 Is_Storage = true;
Dees_Troy63c8df72012-09-10 14:02:05 -0400318 } else if (strcmp(ptr, "canbewiped") == 0) {
319 Can_Be_Wiped = true;
320 } else if (strcmp(ptr, "wipeingui") == 0) {
321 Can_Be_Wiped = true;
322 Wipe_Available_in_GUI = true;
323 } else if (strcmp(ptr, "wipeduringfactoryreset") == 0) {
324 Can_Be_Wiped = true;
325 Wipe_Available_in_GUI = true;
326 Wipe_During_Factory_Reset = true;
Dees_Troy51127312012-09-08 13:08:49 -0400327 } else if (strlen(ptr) > 15 && strncmp(ptr, "subpartitionof=", 15) == 0) {
328 ptr += 13;
329 Is_SubPartition = true;
330 SubPartition_Of = ptr;
331 } else if (strlen(ptr) > 8 && strncmp(ptr, "symlink=", 8) == 0) {
332 ptr += 8;
333 Symlink_Path = ptr;
334 } else if (strlen(ptr) > 8 && strncmp(ptr, "display=", 8) == 0) {
335 ptr += 8;
336 Display_Name = ptr;
337 } else if (strlen(ptr) > 10 && strncmp(ptr, "blocksize=", 10) == 0) {
338 ptr += 10;
339 Format_Block_Size = atoi(ptr);
340 } else if (strlen(ptr) > 7 && strncmp(ptr, "length=", 7) == 0) {
341 ptr += 7;
342 Length = atoi(ptr);
343 } else {
344 if (Display_Error)
345 LOGE("Unhandled flag: '%s'\n", ptr);
346 else
347 LOGI("Unhandled flag: '%s'\n", ptr);
348 }
349 while (index < flags_len && flags[index] != '\0')
350 index++;
351 }
352 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400353}
354
Dees_Troy5bf43922012-09-07 16:07:55 -0400355bool TWPartition::Is_File_System(string File_System) {
356 if (File_System == "ext2" ||
Dees_Troy63c8df72012-09-10 14:02:05 -0400357 File_System == "ext3" ||
Dees_Troy5bf43922012-09-07 16:07:55 -0400358 File_System == "ext4" ||
359 File_System == "vfat" ||
360 File_System == "ntfs" ||
361 File_System == "yaffs2" ||
362 File_System == "auto")
363 return true;
364 else
365 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400366}
367
Dees_Troy5bf43922012-09-07 16:07:55 -0400368bool TWPartition::Is_Image(string File_System) {
Dees_Troy5fcd8f92012-10-16 12:22:05 -0400369 if (File_System == "emmc" || File_System == "mtd" || File_System == "bml")
Dees_Troy5bf43922012-09-07 16:07:55 -0400370 return true;
371 else
372 return false;
373}
374
Dees_Troy51127312012-09-08 13:08:49 -0400375bool TWPartition::Make_Dir(string Path, bool Display_Error) {
Dees_Troy43d8b002012-09-17 16:00:01 -0400376 if (!TWFunc::Path_Exists(Path)) {
Dees_Troy51127312012-09-08 13:08:49 -0400377 if (mkdir(Path.c_str(), 0777) == -1) {
378 if (Display_Error)
379 LOGE("Can not create '%s' folder.\n", Path.c_str());
380 else
381 LOGI("Can not create '%s' folder.\n", Path.c_str());
382 return false;
383 } else {
384 LOGI("Created '%s' folder.\n", Path.c_str());
385 return true;
386 }
387 }
388 return true;
389}
390
Dees_Troy5bf43922012-09-07 16:07:55 -0400391void TWPartition::Setup_File_System(bool Display_Error) {
392 struct statfs st;
393
394 Can_Be_Mounted = true;
395 Can_Be_Wiped = true;
396
Dees_Troy5bf43922012-09-07 16:07:55 -0400397 // Make the mount point folder if it doesn't exist
Dees_Troy51127312012-09-08 13:08:49 -0400398 Make_Dir(Mount_Point, Display_Error);
Dees_Troy5bf43922012-09-07 16:07:55 -0400399 Display_Name = Mount_Point.substr(1, Mount_Point.size() - 1);
400 Backup_Name = Display_Name;
401 Backup_Method = FILES;
402}
403
404void TWPartition::Setup_Image(bool Display_Error) {
Dees_Troy5bf43922012-09-07 16:07:55 -0400405 Display_Name = Mount_Point.substr(1, Mount_Point.size() - 1);
406 Backup_Name = Display_Name;
407 if (Fstab_File_System == "emmc")
408 Backup_Method = DD;
Dees_Troy5fcd8f92012-10-16 12:22:05 -0400409 else if (Fstab_File_System == "mtd" || Fstab_File_System == "bml")
Dees_Troy5bf43922012-09-07 16:07:55 -0400410 Backup_Method = FLASH_UTILS;
411 else
412 LOGI("Unhandled file system '%s' on image '%s'\n", Fstab_File_System.c_str(), Display_Name.c_str());
413 if (Find_Partition_Size()) {
414 Used = Size;
415 Backup_Size = Size;
Dees_Troy51a0e822012-09-05 15:24:24 -0400416 } else {
Dees_Troy5bf43922012-09-07 16:07:55 -0400417 if (Display_Error)
Dees_Troy38bd7602012-09-14 13:33:53 -0400418 LOGE("Unable to find parition size for '%s'\n", Mount_Point.c_str());
Dees_Troy5bf43922012-09-07 16:07:55 -0400419 else
Dees_Troy38bd7602012-09-14 13:33:53 -0400420 LOGI("Unable to find parition size for '%s'\n", Mount_Point.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400421 }
422}
423
Dees_Troye58d5262012-09-21 12:27:57 -0400424void TWPartition::Setup_AndSec(void) {
425 Backup_Name = "and-sec";
426 Has_Android_Secure = true;
427 Symlink_Path = Mount_Point + "/.android_secure";
428 Symlink_Mount_Point = "/and-sec";
429 Backup_Path = Symlink_Mount_Point;
430 Make_Dir("/and-sec", true);
431 Recreate_AndSec_Folder();
432}
433
Dees_Troy5bf43922012-09-07 16:07:55 -0400434void TWPartition::Find_Real_Block_Device(string& Block, bool Display_Error) {
435 char device[512], realDevice[512];
436
437 strcpy(device, Block.c_str());
438 memset(realDevice, 0, sizeof(realDevice));
439 while (readlink(device, realDevice, sizeof(realDevice)) > 0)
440 {
441 strcpy(device, realDevice);
442 memset(realDevice, 0, sizeof(realDevice));
443 }
444
445 if (device[0] != '/') {
446 if (Display_Error)
447 LOGE("Invalid symlink path '%s' found on block device '%s'\n", device, Block.c_str());
448 else
449 LOGI("Invalid symlink path '%s' found on block device '%s'\n", device, Block.c_str());
450 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400451 } else {
Dees_Troy5bf43922012-09-07 16:07:55 -0400452 Block = device;
453 return;
454 }
455}
456
Dees_Troy8e337f32012-10-13 22:07:49 -0400457void TWPartition::Mount_Storage_Retry(void) {
458 // On some devices, storage doesn't want to mount right away, retry and sleep
459 if (!Mount(false)) {
460 int retry_count = 5;
461 while (retry_count > 0 && !Mount(false)) {
462 usleep(500000);
463 retry_count--;
464 }
465 Mount(true);
466 }
467}
468
Dees_Troy38bd7602012-09-14 13:33:53 -0400469bool TWPartition::Find_MTD_Block_Device(string MTD_Name) {
470 FILE *fp = NULL;
471 char line[255];
472
473 fp = fopen("/proc/mtd", "rt");
474 if (fp == NULL) {
475 LOGE("Device does not support /proc/mtd\n");
476 return false;
477 }
478
479 while (fgets(line, sizeof(line), fp) != NULL)
480 {
481 char device[32], label[32];
482 unsigned long size = 0;
483 char* fstype = NULL;
484 int deviceId;
485
486 sscanf(line, "%s %lx %*s %*c%s", device, &size, label);
487
488 // Skip header and blank lines
489 if ((strcmp(device, "dev:") == 0) || (strlen(line) < 8))
490 continue;
491
492 // Strip off the trailing " from the label
493 label[strlen(label)-1] = '\0';
494
495 if (strcmp(label, MTD_Name.c_str()) == 0) {
496 // We found our device
497 // Strip off the trailing : from the device
498 device[strlen(device)-1] = '\0';
499 if (sscanf(device,"mtd%d", &deviceId) == 1) {
500 sprintf(device, "/dev/block/mtdblock%d", deviceId);
501 Primary_Block_Device = device;
502 }
503 }
504 }
505 fclose(fp);
506
507 return false;
508}
509
Dees_Troy51127312012-09-08 13:08:49 -0400510bool TWPartition::Get_Size_Via_statfs(bool Display_Error) {
511 struct statfs st;
512 string Local_Path = Mount_Point + "/.";
513
514 if (!Mount(Display_Error))
515 return false;
516
517 if (statfs(Local_Path.c_str(), &st) != 0) {
518 if (!Removable) {
519 if (Display_Error)
520 LOGE("Unable to statfs '%s'\n", Local_Path.c_str());
521 else
522 LOGI("Unable to statfs '%s'\n", Local_Path.c_str());
523 }
524 return false;
525 }
526 Size = (st.f_blocks * st.f_bsize);
527 Used = ((st.f_blocks - st.f_bfree) * st.f_bsize);
528 Free = (st.f_bfree * st.f_bsize);
529 Backup_Size = Used;
530 return true;
531}
532
533bool TWPartition::Get_Size_Via_df(bool Display_Error) {
Dees_Troy5bf43922012-09-07 16:07:55 -0400534 FILE* fp;
535 char command[255], line[512];
536 int include_block = 1;
537 unsigned int min_len;
538
539 if (!Mount(Display_Error))
540 return false;
541
Dees_Troy38bd7602012-09-14 13:33:53 -0400542 min_len = Actual_Block_Device.size() + 2;
Dees_Troy51127312012-09-08 13:08:49 -0400543 sprintf(command, "df %s > /tmp/dfoutput.txt", Mount_Point.c_str());
Dees_Troy43d8b002012-09-17 16:00:01 -0400544 system(command);
Dees_Troy51127312012-09-08 13:08:49 -0400545 fp = fopen("/tmp/dfoutput.txt", "rt");
546 if (fp == NULL) {
547 LOGI("Unable to open /tmp/dfoutput.txt.\n");
Dees_Troy5bf43922012-09-07 16:07:55 -0400548 return false;
Dees_Troy51127312012-09-08 13:08:49 -0400549 }
Dees_Troy5bf43922012-09-07 16:07:55 -0400550
551 while (fgets(line, sizeof(line), fp) != NULL)
552 {
553 unsigned long blocks, used, available;
554 char device[64];
555 char tmpString[64];
556
557 if (strncmp(line, "Filesystem", 10) == 0)
558 continue;
559 if (strlen(line) < min_len) {
560 include_block = 0;
561 continue;
562 }
563 if (include_block) {
564 sscanf(line, "%s %lu %lu %lu", device, &blocks, &used, &available);
565 } else {
566 // The device block string is so long that the df information is on the next line
567 int space_count = 0;
Dees_Troye58d5262012-09-21 12:27:57 -0400568 sprintf(tmpString, "/dev/block/%s", Actual_Block_Device.c_str());
Dees_Troy5bf43922012-09-07 16:07:55 -0400569 while (tmpString[space_count] == 32)
570 space_count++;
571 sscanf(line + space_count, "%lu %lu %lu", &blocks, &used, &available);
572 }
573
574 // Adjust block size to byte size
575 Size = blocks * 1024ULL;
576 Used = used * 1024ULL;
577 Free = available * 1024ULL;
578 Backup_Size = Used;
579 }
580 fclose(fp);
581 return true;
582}
583
Dees_Troy5bf43922012-09-07 16:07:55 -0400584bool TWPartition::Find_Partition_Size(void) {
585 FILE* fp;
586 char line[512];
587 string tmpdevice;
588
589 // In this case, we'll first get the partitions we care about (with labels)
590 fp = fopen("/proc/partitions", "rt");
591 if (fp == NULL)
592 return false;
593
594 while (fgets(line, sizeof(line), fp) != NULL)
595 {
596 unsigned long major, minor, blocks;
597 char device[512];
598 char tmpString[64];
599
Dees_Troy63c8df72012-09-10 14:02:05 -0400600 if (strlen(line) < 7 || line[0] == 'm') continue;
Dees_Troy5bf43922012-09-07 16:07:55 -0400601 sscanf(line + 1, "%lu %lu %lu %s", &major, &minor, &blocks, device);
602
603 tmpdevice = "/dev/block/";
604 tmpdevice += device;
Dees_Troy38bd7602012-09-14 13:33:53 -0400605 if (tmpdevice == Primary_Block_Device || tmpdevice == Alternate_Block_Device) {
Dees_Troy5bf43922012-09-07 16:07:55 -0400606 // Adjust block size to byte size
607 Size = blocks * 1024ULL;
608 fclose(fp);
609 return true;
610 }
611 }
612 fclose(fp);
613 return false;
614}
615
Dees_Troy5bf43922012-09-07 16:07:55 -0400616bool TWPartition::Is_Mounted(void) {
617 if (!Can_Be_Mounted)
618 return false;
619
620 struct stat st1, st2;
621 string test_path;
622
623 // Check to see if the mount point directory exists
624 test_path = Mount_Point + "/.";
625 if (stat(test_path.c_str(), &st1) != 0) return false;
626
627 // Check to see if the directory above the mount point exists
628 test_path = Mount_Point + "/../.";
629 if (stat(test_path.c_str(), &st2) != 0) return false;
630
631 // Compare the device IDs -- if they match then we're (probably) using tmpfs instead of an actual device
632 int ret = (st1.st_dev != st2.st_dev) ? true : false;
633
634 return ret;
635}
636
637bool TWPartition::Mount(bool Display_Error) {
638 if (Is_Mounted()) {
639 return true;
640 } else if (!Can_Be_Mounted) {
641 return false;
642 }
Dees_Troy38bd7602012-09-14 13:33:53 -0400643
644 Find_Actual_Block_Device();
645
646 // Check the current file system before mounting
647 Check_FS_Type();
648
649 if (mount(Actual_Block_Device.c_str(), Mount_Point.c_str(), Current_File_System.c_str(), 0, NULL) != 0) {
650 if (Display_Error)
651 LOGE("Unable to mount '%s'\n", Mount_Point.c_str());
652 else
653 LOGI("Unable to mount '%s'\n", Mount_Point.c_str());
Dees_Troy9350b8d2012-09-27 12:38:38 -0400654 LOGI("Actual block device: '%s', current file system: '%s'\n", Actual_Block_Device.c_str(), Current_File_System.c_str());
Dees_Troy38bd7602012-09-14 13:33:53 -0400655 return false;
656 } else {
657 if (Removable)
658 Update_Size(Display_Error);
659
660 if (!Symlink_Mount_Point.empty()) {
661 string Command;
662
663 Command = "mount " + Symlink_Path + " " + Symlink_Mount_Point;
Dees_Troy43d8b002012-09-17 16:00:01 -0400664 system(Command.c_str());
Dees_Troy51127312012-09-08 13:08:49 -0400665 }
Dees_Troy38bd7602012-09-14 13:33:53 -0400666 return true;
Dees_Troy5bf43922012-09-07 16:07:55 -0400667 }
Dees_Troy5bf43922012-09-07 16:07:55 -0400668 return true;
669}
670
671bool TWPartition::UnMount(bool Display_Error) {
672 if (Is_Mounted()) {
673 int never_unmount_system;
674
675 DataManager::GetValue(TW_DONT_UNMOUNT_SYSTEM, never_unmount_system);
676 if (never_unmount_system == 1 && Mount_Point == "/system")
677 return true; // Never unmount system if you're not supposed to unmount it
678
Dees_Troy38bd7602012-09-14 13:33:53 -0400679 if (!Symlink_Mount_Point.empty())
680 umount(Symlink_Mount_Point.c_str());
681
Dees_Troy5bf43922012-09-07 16:07:55 -0400682 if (umount(Mount_Point.c_str()) != 0) {
683 if (Display_Error)
684 LOGE("Unable to unmount '%s'\n", Mount_Point.c_str());
685 else
686 LOGI("Unable to unmount '%s'\n", Mount_Point.c_str());
687 return false;
688 } else
689 return true;
690 } else {
691 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400692 }
693}
694
695bool TWPartition::Wipe() {
Dees_Troy38bd7602012-09-14 13:33:53 -0400696 if (!Can_Be_Wiped) {
697 LOGE("Partition '%s' cannot be wiped.\n", Mount_Point.c_str());
698 return false;
699 }
700
Dees_Troyc51f1f92012-09-20 15:32:13 -0400701 if (Mount_Point == "/cache")
702 tmplog_offset = 0;
703
Dees_Troy38bd7602012-09-14 13:33:53 -0400704 if (Has_Data_Media)
705 return Wipe_Data_Without_Wiping_Media();
706
707 int check;
708 DataManager::GetValue(TW_RM_RF_VAR, check);
709 if (check)
710 return Wipe_RMRF();
711
712 if (Current_File_System == "ext4")
713 return Wipe_EXT4();
714
715 if (Current_File_System == "ext2" || Current_File_System == "ext3")
716 return Wipe_EXT23();
717
718 if (Current_File_System == "vfat")
719 return Wipe_FAT();
720
721 if (Current_File_System == "yaffs2")
722 return Wipe_MTD();
723
724 LOGE("Unable to wipe '%s' -- unknown file system '%s'\n", Mount_Point.c_str(), Current_File_System.c_str());
725 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400726}
727
Dees_Troye58d5262012-09-21 12:27:57 -0400728bool TWPartition::Wipe_AndSec(void) {
729 if (!Has_Android_Secure)
730 return false;
731
732 char cmd[512];
733
734 if (!Mount(true))
735 return false;
736
737 ui_print("Using rm -rf on .android_secure\n");
738 sprintf(cmd, "rm -rf %s/.android_secure/* && rm -rf %s/.android_secure/.*", Mount_Point.c_str(), Mount_Point.c_str());
739
740 LOGI("rm -rf command is: '%s'\n", cmd);
741 system(cmd);
742 return true;
743}
744
Dees_Troy51a0e822012-09-05 15:24:24 -0400745bool TWPartition::Backup(string backup_folder) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400746 if (Backup_Method == FILES)
747 return Backup_Tar(backup_folder);
748 else if (Backup_Method == DD)
749 return Backup_DD(backup_folder);
750 else if (Backup_Method == FLASH_UTILS)
751 return Backup_Dump_Image(backup_folder);
752 LOGE("Unknown backup method for '%s'\n", Mount_Point.c_str());
753 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400754}
755
Dees_Troy43d8b002012-09-17 16:00:01 -0400756bool TWPartition::Check_MD5(string restore_folder) {
757 string Full_Filename;
758 char split_filename[512];
759 int index = 0;
760
761 Full_Filename = restore_folder + "/" + Backup_FileName;
Dees_Troy43d8b002012-09-17 16:00:01 -0400762 if (!TWFunc::Path_Exists(Full_Filename)) {
763 // This is a split archive, we presume
764 sprintf(split_filename, "%s%03i", Full_Filename.c_str(), index);
765 while (index < 1000 && TWFunc::Path_Exists(split_filename)) {
766 if (TWFunc::Check_MD5(split_filename) == 0) {
767 LOGE("MD5 failed to match on '%s'.\n", split_filename);
768 return false;
769 }
770 index++;
771 sprintf(split_filename, "%s%03i", Full_Filename.c_str(), index);
Dees_Troy43d8b002012-09-17 16:00:01 -0400772 }
Dees_Troy4a2a1262012-09-18 09:33:47 -0400773 return true;
Dees_Troy43d8b002012-09-17 16:00:01 -0400774 } else {
775 // Single file archive
776 if (TWFunc::Check_MD5(Full_Filename) == 0) {
777 LOGE("MD5 failed to match on '%s'.\n", split_filename);
778 return false;
779 } else
780 return true;
781 }
782 return false;
783}
784
Dees_Troy51a0e822012-09-05 15:24:24 -0400785bool TWPartition::Restore(string restore_folder) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400786 if (Backup_Method == FILES)
787 return Restore_Tar(restore_folder);
788 else if (Backup_Method == DD)
789 return Restore_DD(restore_folder);
790 else if (Backup_Method == FLASH_UTILS)
791 return Restore_Flash_Image(restore_folder);
792 LOGE("Unknown restore method for '%s'\n", Mount_Point.c_str());
793 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400794}
795
796string TWPartition::Backup_Method_By_Name() {
Dees_Troy38bd7602012-09-14 13:33:53 -0400797 if (Backup_Method == NONE)
798 return "none";
799 else if (Backup_Method == FILES)
800 return "files";
801 else if (Backup_Method == DD)
802 return "dd";
803 else if (Backup_Method == FLASH_UTILS)
804 return "flash_utils";
805 else
806 return "undefined";
807 return "ERROR!";
Dees_Troy51a0e822012-09-05 15:24:24 -0400808}
809
810bool TWPartition::Decrypt(string Password) {
811 LOGI("STUB TWPartition::Decrypt, password: '%s'\n", Password.c_str());
Dees_Troy38bd7602012-09-14 13:33:53 -0400812 // Is this needed?
Dees_Troy51a0e822012-09-05 15:24:24 -0400813 return 1;
814}
815
816bool TWPartition::Wipe_Encryption() {
Dees_Troy38bd7602012-09-14 13:33:53 -0400817 bool Save_Data_Media = Has_Data_Media;
818
819 if (!UnMount(true))
820 return false;
821
822 Current_File_System = Fstab_File_System;
823 Is_Encrypted = false;
824 Is_Decrypted = false;
825 Decrypted_Block_Device = "";
826 Has_Data_Media = false;
827 if (Wipe()) {
828 Has_Data_Media = Save_Data_Media;
829 if (Has_Data_Media && !Symlink_Mount_Point.empty()) {
830 Recreate_Media_Folder();
831 }
Dees_Troyb46a6842012-09-25 11:06:46 -0400832 ui_print("You may need to reboot recovery to be able to use /data again.\n");
Dees_Troy38bd7602012-09-14 13:33:53 -0400833 return true;
834 } else {
835 Has_Data_Media = Save_Data_Media;
836 LOGE("Unable to format to remove encryption.\n");
837 return false;
838 }
839 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400840}
841
842void TWPartition::Check_FS_Type() {
Dees_Troy5bf43922012-09-07 16:07:55 -0400843 FILE *fp;
844 string blkCommand;
845 char blkOutput[255];
846 char* blk;
847 char* arg;
848 char* ptr;
849
Dees_Troy5fcd8f92012-10-16 12:22:05 -0400850 if (Fstab_File_System == "yaffs2" || Fstab_File_System == "mtd" || Fstab_File_System == "bml")
Dees_Troy5bf43922012-09-07 16:07:55 -0400851 return; // Running blkid on some mtd devices causes a massive crash
852
Dees_Troy38bd7602012-09-14 13:33:53 -0400853 Find_Actual_Block_Device();
Dees_Troy8170a922012-09-18 15:40:25 -0400854 if (!Is_Present)
855 return;
Dees_Troy51127312012-09-08 13:08:49 -0400856
Dees_Troy8170a922012-09-18 15:40:25 -0400857 if (TWFunc::Path_Exists("/tmp/blkidoutput.txt"))
858 system("rm /tmp/blkidoutput.txt");
859
860 blkCommand = "blkid " + Actual_Block_Device + " > /tmp/blkidoutput.txt";
Dees_Troy43d8b002012-09-17 16:00:01 -0400861 system(blkCommand.c_str());
Dees_Troy51127312012-09-08 13:08:49 -0400862 fp = fopen("/tmp/blkidoutput.txt", "rt");
Dees_Troy8170a922012-09-18 15:40:25 -0400863 if (fp == NULL)
864 return;
Dees_Troy5bf43922012-09-07 16:07:55 -0400865 while (fgets(blkOutput, sizeof(blkOutput), fp) != NULL)
866 {
867 blk = blkOutput;
868 ptr = blkOutput;
Dees_Troy63c8df72012-09-10 14:02:05 -0400869 while (*ptr > 32 && *ptr != ':') ptr++;
870 if (*ptr == 0) continue;
Dees_Troy5bf43922012-09-07 16:07:55 -0400871 *ptr = 0;
872
873 // Increment by two, but verify that we don't hit a NULL
874 ptr++;
Dees_Troy63c8df72012-09-10 14:02:05 -0400875 if (*ptr != 0) ptr++;
Dees_Troy5bf43922012-09-07 16:07:55 -0400876
877 // Now, find the TYPE field
878 while (1)
879 {
880 arg = ptr;
Dees_Troy63c8df72012-09-10 14:02:05 -0400881 while (*ptr > 32) ptr++;
Dees_Troy5bf43922012-09-07 16:07:55 -0400882 if (*ptr != 0)
883 {
884 *ptr = 0;
885 ptr++;
886 }
887
888 if (strlen(arg) > 6)
889 {
890 if (memcmp(arg, "TYPE=\"", 6) == 0) break;
891 }
892
893 if (*ptr == 0)
894 {
895 arg = NULL;
896 break;
897 }
898 }
899
900 if (arg && strlen(arg) > 7)
901 {
902 arg += 6; // Skip the TYPE=" portion
903 arg[strlen(arg)-1] = '\0'; // Drop the tail quote
904 }
905 else
906 continue;
907
Dees_Troy63c8df72012-09-10 14:02:05 -0400908 if (strcmp(Current_File_System.c_str(), arg) != 0) {
Dees_Troy5bf43922012-09-07 16:07:55 -0400909 LOGI("'%s' was '%s' now set to '%s'\n", Mount_Point.c_str(), Current_File_System.c_str(), arg);
910 Current_File_System = arg;
911 }
912 }
Dees_Troy43d8b002012-09-17 16:00:01 -0400913 fclose(fp);
Dees_Troy51a0e822012-09-05 15:24:24 -0400914 return;
915}
916
917bool TWPartition::Wipe_EXT23() {
Dees_Troy38bd7602012-09-14 13:33:53 -0400918 if (!UnMount(true))
919 return false;
920
Dees_Troy43d8b002012-09-17 16:00:01 -0400921 if (TWFunc::Path_Exists("/sbin/mke2fs")) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400922 char command[512];
923
924 ui_print("Formatting %s using mke2fs...\n", Display_Name.c_str());
925 Find_Actual_Block_Device();
926 sprintf(command, "mke2fs -t %s -m 0 %s", Current_File_System.c_str(), Actual_Block_Device.c_str());
927 LOGI("mke2fs command: %s\n", command);
Dees_Troy43d8b002012-09-17 16:00:01 -0400928 if (system(command) == 0) {
Dees_Troye58d5262012-09-21 12:27:57 -0400929 Recreate_AndSec_Folder();
Dees_Troy38bd7602012-09-14 13:33:53 -0400930 ui_print("Done.\n");
931 return true;
932 } else {
933 LOGE("Unable to wipe '%s'.\n", Mount_Point.c_str());
934 return false;
935 }
936 } else
937 return Wipe_RMRF();
938
939 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400940}
941
942bool TWPartition::Wipe_EXT4() {
Dees_Troy38bd7602012-09-14 13:33:53 -0400943 if (!UnMount(true))
944 return false;
945
Dees_Troy43d8b002012-09-17 16:00:01 -0400946 if (TWFunc::Path_Exists("/sbin/make_ext4fs")) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400947 string Command;
948
949 ui_print("Formatting %s using make_ext4fs...\n", Display_Name.c_str());
950 Find_Actual_Block_Device();
951 Command = "make_ext4fs";
952 if (!Is_Decrypted && Length != 0) {
953 // Only use length if we're not decrypted
954 char len[32];
955 sprintf(len, "%i", Length);
956 Command += " -l ";
957 Command += len;
958 }
959 Command += " " + Actual_Block_Device;
960 LOGI("make_ext4fs command: %s\n", Command.c_str());
Dees_Troy43d8b002012-09-17 16:00:01 -0400961 if (system(Command.c_str()) == 0) {
Dees_Troye58d5262012-09-21 12:27:57 -0400962 Recreate_AndSec_Folder();
Dees_Troy38bd7602012-09-14 13:33:53 -0400963 ui_print("Done.\n");
964 return true;
965 } else {
966 LOGE("Unable to wipe '%s'.\n", Mount_Point.c_str());
967 return false;
968 }
969 } else
970 return Wipe_EXT23();
971
972 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400973}
974
975bool TWPartition::Wipe_FAT() {
Dees_Troy38bd7602012-09-14 13:33:53 -0400976 char command[512];
977
Dees_Troy43d8b002012-09-17 16:00:01 -0400978 if (TWFunc::Path_Exists("/sbin/mkdosfs")) {
Dees_Troy38bd7602012-09-14 13:33:53 -0400979 if (!UnMount(true))
980 return false;
981
982 ui_print("Formatting %s using mkdosfs...\n", Display_Name.c_str());
983 Find_Actual_Block_Device();
984 sprintf(command,"mkdosfs %s", Actual_Block_Device.c_str()); // use mkdosfs to format it
Dees_Troy43d8b002012-09-17 16:00:01 -0400985 if (system(command) == 0) {
Dees_Troye58d5262012-09-21 12:27:57 -0400986 Recreate_AndSec_Folder();
Dees_Troy38bd7602012-09-14 13:33:53 -0400987 ui_print("Done.\n");
988 return true;
989 } else {
990 LOGE("Unable to wipe '%s'.\n", Mount_Point.c_str());
991 return false;
992 }
993 return true;
994 }
995 else
996 return Wipe_RMRF();
997
998 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400999}
1000
Dees_Troy38bd7602012-09-14 13:33:53 -04001001bool TWPartition::Wipe_MTD() {
1002 if (!UnMount(true))
1003 return false;
1004
1005 ui_print("MTD Formatting \"%s\"\n", MTD_Name.c_str());
1006
1007 mtd_scan_partitions();
1008 const MtdPartition* mtd = mtd_find_partition_by_name(MTD_Name.c_str());
1009 if (mtd == NULL) {
1010 LOGE("No mtd partition named '%s'", MTD_Name.c_str());
1011 return false;
1012 }
1013
1014 MtdWriteContext* ctx = mtd_write_partition(mtd);
1015 if (ctx == NULL) {
1016 LOGE("Can't write '%s', failed to format.", MTD_Name.c_str());
1017 return false;
1018 }
1019 if (mtd_erase_blocks(ctx, -1) == -1) {
1020 mtd_write_close(ctx);
1021 LOGE("Failed to format '%s'", MTD_Name.c_str());
1022 return false;
1023 }
1024 if (mtd_write_close(ctx) != 0) {
1025 LOGE("Failed to close '%s'", MTD_Name.c_str());
1026 return false;
1027 }
Dees_Troye58d5262012-09-21 12:27:57 -04001028 Recreate_AndSec_Folder();
Dees_Troy38bd7602012-09-14 13:33:53 -04001029 ui_print("Done.\n");
1030 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -04001031}
1032
1033bool TWPartition::Wipe_RMRF() {
Dees_Troy38bd7602012-09-14 13:33:53 -04001034 char cmd[512];
1035
1036 if (!Mount(true))
1037 return false;
1038
Dees_Troye58d5262012-09-21 12:27:57 -04001039 ui_print("Using rm -rf on '%s'\n", Mount_Point.c_str());
1040 sprintf(cmd, "rm -rf %s/* && rm -rf %s/.*", Mount_Point.c_str(), Mount_Point.c_str());
Dees_Troy38bd7602012-09-14 13:33:53 -04001041
1042 LOGI("rm -rf command is: '%s'\n", cmd);
Dees_Troy43d8b002012-09-17 16:00:01 -04001043 system(cmd);
Dees_Troye58d5262012-09-21 12:27:57 -04001044 Recreate_AndSec_Folder();
Dees_Troy38bd7602012-09-14 13:33:53 -04001045 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -04001046}
1047
1048bool TWPartition::Wipe_Data_Without_Wiping_Media() {
Dees_Troy38bd7602012-09-14 13:33:53 -04001049 char cmd[256];
1050
1051 // This handles wiping data on devices with "sdcard" in /data/media
1052 if (!Mount(true))
1053 return false;
1054
1055 ui_print("Wiping data without wiping /data/media ...\n");
Dees_Troy43d8b002012-09-17 16:00:01 -04001056 system("rm -f /data/*");
1057 system("rm -f /data/.*");
Dees_Troy38bd7602012-09-14 13:33:53 -04001058
1059 DIR* d;
1060 d = opendir("/data");
1061 if (d != NULL)
1062 {
1063 struct dirent* de;
1064 while ((de = readdir(d)) != NULL) {
1065 if (strcmp(de->d_name, "media") == 0) continue;
1066
1067 sprintf(cmd, "rm -fr /data/%s", de->d_name);
Dees_Troy43d8b002012-09-17 16:00:01 -04001068 system(cmd);
Dees_Troy38bd7602012-09-14 13:33:53 -04001069 }
1070 closedir(d);
1071 }
1072 ui_print("Done.\n");
1073 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -04001074}
1075
1076bool TWPartition::Backup_Tar(string backup_folder) {
Dees_Troy4a2a1262012-09-18 09:33:47 -04001077 char back_name[255], split_index[5];
1078 string Full_FileName, Split_FileName, Tar_Args, Command;
1079 int use_compression, index, backup_count;
1080 struct stat st;
Dees_Troy7c2dec82012-09-26 09:49:14 -04001081 unsigned long long total_bsize = 0, file_size;
Dees_Troy43d8b002012-09-17 16:00:01 -04001082
1083 if (!Mount(true))
1084 return false;
1085
Dees_Troy2c50e182012-09-26 20:05:28 -04001086 if (Backup_Path == "/and-sec") {
1087 TWFunc::GUI_Operation_Text(TW_BACKUP_TEXT, "Android Secure", "Backing Up");
1088 ui_print("Backing up %s...\n", "Android Secure");
1089 } else {
1090 TWFunc::GUI_Operation_Text(TW_BACKUP_TEXT, Display_Name, "Backing Up");
1091 ui_print("Backing up %s...\n", Display_Name.c_str());
1092 }
Dees_Troy43d8b002012-09-17 16:00:01 -04001093
1094 DataManager::GetValue(TW_USE_COMPRESSION_VAR, use_compression);
1095 if (use_compression)
1096 Tar_Args = "-cz";
1097 else
1098 Tar_Args = "-c";
1099
1100 sprintf(back_name, "%s.%s.win", Backup_Name.c_str(), Current_File_System.c_str());
1101 Backup_FileName = back_name;
1102
Dees_Troy43d8b002012-09-17 16:00:01 -04001103 if (Backup_Size > MAX_ARCHIVE_SIZE) {
1104 // This backup needs to be split into multiple archives
Dees_Troy4a2a1262012-09-18 09:33:47 -04001105 ui_print("Breaking backup file into multiple archives...\nGenerating file lists\n");
Dees_Troye58d5262012-09-21 12:27:57 -04001106 sprintf(back_name, "%s", Backup_Path.c_str());
Dees_Troy9df963c2012-09-26 08:58:12 -04001107 backup_count = MakeList::Make_File_List(back_name);
Dees_Troy4a2a1262012-09-18 09:33:47 -04001108 if (backup_count < 1) {
1109 LOGE("Error generating file list!\n");
1110 return false;
1111 }
1112 for (index=0; index<backup_count; index++) {
1113 sprintf(split_index, "%03i", index);
1114 Full_FileName = backup_folder + "/" + Backup_FileName + split_index;
1115 Command = "tar " + Tar_Args + " -f '" + Full_FileName + "' -T /tmp/list/filelist" + split_index;
1116 LOGI("Backup command: '%s'\n", Command.c_str());
1117 ui_print("Backup archive %i of %i...\n", (index + 1), backup_count);
1118 system(Command.c_str()); // sending backup command formed earlier above
1119
Dees_Troy7c2dec82012-09-26 09:49:14 -04001120 file_size = TWFunc::Get_File_Size(Full_FileName);
1121 if (file_size == 0) {
1122 LOGE("Backup file size for '%s' is 0 bytes.\n", Full_FileName.c_str()); // oh noes! file size is 0, abort! abort!
Dees_Troy4a2a1262012-09-18 09:33:47 -04001123 return false;
1124 }
Dees_Troy7c2dec82012-09-26 09:49:14 -04001125 total_bsize += file_size;
Dees_Troy4a2a1262012-09-18 09:33:47 -04001126 }
1127 ui_print(" * Total size: %llu bytes.\n", total_bsize);
1128 system("cd /tmp && rm -rf list");
Dees_Troy43d8b002012-09-17 16:00:01 -04001129 } else {
Dees_Troy4a2a1262012-09-18 09:33:47 -04001130 Full_FileName = backup_folder + "/" + Backup_FileName;
Dees_Troy43d8b002012-09-17 16:00:01 -04001131 if (Has_Data_Media)
Dees_Troye58d5262012-09-21 12:27:57 -04001132 Command = "cd " + Backup_Path + " && tar " + Tar_Args + " ./ --exclude='media*' -f '" + Full_FileName + "'";
Dees_Troy43d8b002012-09-17 16:00:01 -04001133 else
Dees_Troye58d5262012-09-21 12:27:57 -04001134 Command = "cd " + Backup_Path + " && tar " + Tar_Args + " -f '" + Full_FileName + "' ./*";
Dees_Troy43d8b002012-09-17 16:00:01 -04001135 LOGI("Backup command: '%s'\n", Command.c_str());
1136 system(Command.c_str());
Dees_Troy7c2dec82012-09-26 09:49:14 -04001137 if (TWFunc::Get_File_Size(Full_FileName) == 0) {
1138 LOGE("Backup file size for '%s' is 0 bytes.\n", Full_FileName.c_str());
1139 return false;
1140 }
Dees_Troy43d8b002012-09-17 16:00:01 -04001141 }
1142 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -04001143}
1144
1145bool TWPartition::Backup_DD(string backup_folder) {
Dees_Troy43d8b002012-09-17 16:00:01 -04001146 char back_name[255];
1147 string Full_FileName, Command;
1148 int use_compression;
1149
Dees_Troyb46a6842012-09-25 11:06:46 -04001150 TWFunc::GUI_Operation_Text(TW_BACKUP_TEXT, Display_Name, "Backing Up");
Dees_Troy43d8b002012-09-17 16:00:01 -04001151 ui_print("Backing up %s...\n", Display_Name.c_str());
1152
1153 sprintf(back_name, "%s.%s.win", Backup_Name.c_str(), Current_File_System.c_str());
1154 Backup_FileName = back_name;
1155
1156 Full_FileName = backup_folder + "/" + Backup_FileName;
1157
1158 Command = "dd if=" + Actual_Block_Device + " of='" + Full_FileName + "'";
1159 LOGI("Backup command: '%s'\n", Command.c_str());
1160 system(Command.c_str());
Dees_Troyc154ac22012-10-12 15:36:47 -04001161 if (TWFunc::Get_File_Size(Full_FileName) == 0) {
1162 LOGE("Backup file size for '%s' is 0 bytes.\n", Full_FileName.c_str());
Dees_Troy7c2dec82012-09-26 09:49:14 -04001163 return false;
1164 }
Dees_Troy43d8b002012-09-17 16:00:01 -04001165 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -04001166}
1167
1168bool TWPartition::Backup_Dump_Image(string backup_folder) {
Dees_Troy43d8b002012-09-17 16:00:01 -04001169 char back_name[255];
1170 string Full_FileName, Command;
1171 int use_compression;
1172
Dees_Troyb46a6842012-09-25 11:06:46 -04001173 TWFunc::GUI_Operation_Text(TW_BACKUP_TEXT, Display_Name, "Backing Up");
Dees_Troy43d8b002012-09-17 16:00:01 -04001174 ui_print("Backing up %s...\n", Display_Name.c_str());
1175
1176 sprintf(back_name, "%s.%s.win", Backup_Name.c_str(), Current_File_System.c_str());
1177 Backup_FileName = back_name;
1178
1179 Full_FileName = backup_folder + "/" + Backup_FileName;
1180
1181 Command = "dump_image " + MTD_Name + " '" + Full_FileName + "'";
1182 LOGI("Backup command: '%s'\n", Command.c_str());
1183 system(Command.c_str());
Dees_Troy7c2dec82012-09-26 09:49:14 -04001184 if (TWFunc::Get_File_Size(Full_FileName) == 0) {
1185 // Actual size may not match backup size due to bad blocks on MTD devices so just check for 0 bytes
1186 LOGE("Backup file size for '%s' is 0 bytes.\n", Full_FileName.c_str());
1187 return false;
1188 }
Dees_Troy43d8b002012-09-17 16:00:01 -04001189 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -04001190}
1191
1192bool TWPartition::Restore_Tar(string restore_folder) {
Dees_Troy43d8b002012-09-17 16:00:01 -04001193 size_t first_period, second_period;
1194 string Restore_File_System, Full_FileName, Command;
Dees_Troy4a2a1262012-09-18 09:33:47 -04001195 int index = 0;
1196 char split_index[5];
Dees_Troy43d8b002012-09-17 16:00:01 -04001197
Dees_Troyb46a6842012-09-25 11:06:46 -04001198 TWFunc::GUI_Operation_Text(TW_RESTORE_TEXT, Display_Name, "Restoring");
Dees_Troy43d8b002012-09-17 16:00:01 -04001199 LOGI("Restore filename is: %s\n", Backup_FileName.c_str());
1200
1201 // Parse backup filename to extract the file system before wiping
1202 first_period = Backup_FileName.find(".");
1203 if (first_period == string::npos) {
1204 LOGE("Unable to find file system (first period).\n");
1205 return false;
1206 }
1207 Restore_File_System = Backup_FileName.substr(first_period + 1, Backup_FileName.size() - first_period - 1);
1208 second_period = Restore_File_System.find(".");
1209 if (second_period == string::npos) {
1210 LOGE("Unable to find file system (second period).\n");
1211 return false;
1212 }
1213 Restore_File_System.resize(second_period);
1214 LOGI("Restore file system is: '%s'.\n", Restore_File_System.c_str());
1215 Current_File_System = Restore_File_System;
Dees_Troye58d5262012-09-21 12:27:57 -04001216 if (Has_Android_Secure) {
1217 ui_print("Wiping android secure...\n");
1218 if (!Wipe_AndSec())
1219 return false;
1220 } else if (!Wipe()) {
1221 ui_print("Wiping %s...\n", Display_Name.c_str());
Dees_Troy43d8b002012-09-17 16:00:01 -04001222 return false;
Dees_Troye58d5262012-09-21 12:27:57 -04001223 }
Dees_Troy43d8b002012-09-17 16:00:01 -04001224
1225 if (!Mount(true))
1226 return false;
1227
Dees_Troy43d8b002012-09-17 16:00:01 -04001228 ui_print("Restoring %s...\n", Display_Name.c_str());
Dees_Troy4a2a1262012-09-18 09:33:47 -04001229 Full_FileName = restore_folder + "/" + Backup_FileName;
Dees_Troy43d8b002012-09-17 16:00:01 -04001230 if (!TWFunc::Path_Exists(Full_FileName)) {
Dees_Troy4a2a1262012-09-18 09:33:47 -04001231 // Backup is multiple archives
1232 LOGI("Backup is multiple archives.\n");
1233 sprintf(split_index, "%03i", index);
1234 Full_FileName = restore_folder + "/" + Backup_FileName + split_index;
1235 while (TWFunc::Path_Exists(Full_FileName)) {
1236 ui_print("Restoring archive %i...\n", index + 1);
Dees_Troy6da522d2012-10-12 15:19:33 -04001237 Command = "tar -xf '" + Full_FileName + "'";
Dees_Troy4a2a1262012-09-18 09:33:47 -04001238 LOGI("Restore command: '%s'\n", Command.c_str());
1239 system(Command.c_str());
1240 index++;
1241 sprintf(split_index, "%03i", index);
1242 Full_FileName = restore_folder + "/" + Backup_FileName + split_index;
1243 }
1244 if (index == 0) {
1245 LOGE("Error locating restore file: '%s'\n", Full_FileName.c_str());
1246 return false;
1247 }
Dees_Troy43d8b002012-09-17 16:00:01 -04001248 } else {
Dees_Troye58d5262012-09-21 12:27:57 -04001249 Command = "cd " + Backup_Path + " && tar -xf '" + Full_FileName + "'";
Dees_Troy43d8b002012-09-17 16:00:01 -04001250 LOGI("Restore command: '%s'\n", Command.c_str());
1251 system(Command.c_str());
1252 }
1253 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -04001254}
1255
1256bool TWPartition::Restore_DD(string restore_folder) {
Dees_Troy43d8b002012-09-17 16:00:01 -04001257 string Full_FileName, Command;
1258
Dees_Troyb46a6842012-09-25 11:06:46 -04001259 TWFunc::GUI_Operation_Text(TW_RESTORE_TEXT, Display_Name, "Restoring");
Dees_Troy43d8b002012-09-17 16:00:01 -04001260 ui_print("Restoring %s...\n", Display_Name.c_str());
1261 Full_FileName = restore_folder + "/" + Backup_FileName;
1262 Command = "dd bs=4096 if='" + Full_FileName + "' of=" + Actual_Block_Device;
1263 LOGI("Restore command: '%s'\n", Command.c_str());
1264 system(Command.c_str());
1265 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -04001266}
1267
1268bool TWPartition::Restore_Flash_Image(string restore_folder) {
Dees_Troy43d8b002012-09-17 16:00:01 -04001269 string Full_FileName, Command;
1270
Dees_Troyb46a6842012-09-25 11:06:46 -04001271 TWFunc::GUI_Operation_Text(TW_RESTORE_TEXT, Display_Name, "Restoring");
Dees_Troy43d8b002012-09-17 16:00:01 -04001272 ui_print("Restoring %s...\n", Display_Name.c_str());
1273 Full_FileName = restore_folder + "/" + Backup_FileName;
1274 // Sometimes flash image doesn't like to flash due to the first 2KB matching, so we erase first to ensure that it flashes
1275 Command = "erase_image " + MTD_Name;
1276 LOGI("Erase command: '%s'\n", Command.c_str());
1277 system(Command.c_str());
1278 Command = "flash_image " + MTD_Name + " '" + Full_FileName + "'";
1279 LOGI("Restore command: '%s'\n", Command.c_str());
1280 system(Command.c_str());
1281 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -04001282}
Dees_Troy5bf43922012-09-07 16:07:55 -04001283
1284bool TWPartition::Update_Size(bool Display_Error) {
Dees_Troy0550cfb2012-10-13 11:56:13 -04001285 bool ret = false, Was_Already_Mounted = false;
Dees_Troy51127312012-09-08 13:08:49 -04001286
Dees_Troyab10ee22012-09-21 14:27:30 -04001287 if (!Can_Be_Mounted && !Is_Encrypted)
Dees_Troy5bf43922012-09-07 16:07:55 -04001288 return false;
1289
Dees_Troy0550cfb2012-10-13 11:56:13 -04001290 Was_Already_Mounted = Is_Mounted();
Dees_Troy38bd7602012-09-14 13:33:53 -04001291 if (Removable || Is_Encrypted) {
1292 if (!Mount(false))
1293 return true;
1294 } else if (!Mount(Display_Error))
Dees_Troy5bf43922012-09-07 16:07:55 -04001295 return false;
Dees_Troy51127312012-09-08 13:08:49 -04001296
1297 ret = Get_Size_Via_statfs(Display_Error);
Dees_Troy0550cfb2012-10-13 11:56:13 -04001298 if (!ret || Size == 0) {
1299 if (!Get_Size_Via_df(Display_Error)) {
1300 if (!Was_Already_Mounted)
1301 UnMount(false);
Dees_Troy51127312012-09-08 13:08:49 -04001302 return false;
Dees_Troy0550cfb2012-10-13 11:56:13 -04001303 }
1304 }
Dees_Troy51127312012-09-08 13:08:49 -04001305
Dees_Troy5bf43922012-09-07 16:07:55 -04001306 if (Has_Data_Media) {
1307 if (Mount(Display_Error)) {
Dees_Troy51127312012-09-08 13:08:49 -04001308 unsigned long long data_media_used, actual_data;
Dees_Troy43d8b002012-09-17 16:00:01 -04001309 Used = TWFunc::Get_Folder_Size("/data", Display_Error);
1310 data_media_used = TWFunc::Get_Folder_Size("/data/media", Display_Error);
Dees_Troy51127312012-09-08 13:08:49 -04001311 actual_data = Used - data_media_used;
Dees_Troy5bf43922012-09-07 16:07:55 -04001312 Backup_Size = actual_data;
Dees_Troy51127312012-09-08 13:08:49 -04001313 int bak = (int)(Backup_Size / 1048576LLU);
1314 int total = (int)(Size / 1048576LLU);
1315 int us = (int)(Used / 1048576LLU);
1316 int fre = (int)(Free / 1048576LLU);
1317 int datmed = (int)(data_media_used / 1048576LLU);
1318 LOGI("Data backup size is %iMB, size: %iMB, used: %iMB, free: %iMB, in data/media: %iMB.\n", bak, total, us, fre, datmed);
Dees_Troy0550cfb2012-10-13 11:56:13 -04001319 } else {
1320 if (!Was_Already_Mounted)
1321 UnMount(false);
Dees_Troy5bf43922012-09-07 16:07:55 -04001322 return false;
Dees_Troy0550cfb2012-10-13 11:56:13 -04001323 }
Dees_Troye58d5262012-09-21 12:27:57 -04001324 } else if (Has_Android_Secure) {
1325 if (Mount(Display_Error))
1326 Backup_Size = TWFunc::Get_Folder_Size(Backup_Path, Display_Error);
Dees_Troy0550cfb2012-10-13 11:56:13 -04001327 else {
1328 if (!Was_Already_Mounted)
1329 UnMount(false);
Dees_Troye58d5262012-09-21 12:27:57 -04001330 return false;
Dees_Troy0550cfb2012-10-13 11:56:13 -04001331 }
Dees_Troy5bf43922012-09-07 16:07:55 -04001332 }
Dees_Troy0550cfb2012-10-13 11:56:13 -04001333 if (!Was_Already_Mounted)
1334 UnMount(false);
Dees_Troy5bf43922012-09-07 16:07:55 -04001335 return true;
Dees_Troy51127312012-09-08 13:08:49 -04001336}
Dees_Troy38bd7602012-09-14 13:33:53 -04001337
1338void TWPartition::Find_Actual_Block_Device(void) {
1339 if (Is_Decrypted) {
1340 Actual_Block_Device = Decrypted_Block_Device;
Dees_Troy43d8b002012-09-17 16:00:01 -04001341 if (TWFunc::Path_Exists(Primary_Block_Device))
Dees_Troy38bd7602012-09-14 13:33:53 -04001342 Is_Present = true;
Dees_Troy43d8b002012-09-17 16:00:01 -04001343 } else if (TWFunc::Path_Exists(Primary_Block_Device)) {
Dees_Troy38bd7602012-09-14 13:33:53 -04001344 Is_Present = true;
1345 Actual_Block_Device = Primary_Block_Device;
Dees_Troy43d8b002012-09-17 16:00:01 -04001346 } else if (!Alternate_Block_Device.empty() && TWFunc::Path_Exists(Alternate_Block_Device)) {
Dees_Troy3f04d032012-10-07 18:20:09 -04001347 Actual_Block_Device = Alternate_Block_Device;
Dees_Troy38bd7602012-09-14 13:33:53 -04001348 Is_Present = true;
1349 } else
1350 Is_Present = false;
1351}
1352
1353void TWPartition::Recreate_Media_Folder(void) {
1354 string Command;
1355
1356 if (!Mount(true)) {
1357 LOGE("Unable to recreate /data/media folder.\n");
Dees_Troyb46a6842012-09-25 11:06:46 -04001358 } else if (!TWFunc::Path_Exists("/data/media")) {
Dees_Troy38bd7602012-09-14 13:33:53 -04001359 LOGI("Recreating /data/media folder.\n");
Dees_Troy43d8b002012-09-17 16:00:01 -04001360 system("cd /data && mkdir media && chmod 755 media");
Dees_Troy38bd7602012-09-14 13:33:53 -04001361 Command = "umount " + Symlink_Mount_Point;
Dees_Troy43d8b002012-09-17 16:00:01 -04001362 system(Command.c_str());
Dees_Troy38bd7602012-09-14 13:33:53 -04001363 Command = "mount " + Symlink_Path + " " + Symlink_Mount_Point;
Dees_Troy43d8b002012-09-17 16:00:01 -04001364 system(Command.c_str());
Dees_Troy38bd7602012-09-14 13:33:53 -04001365 }
Dees_Troy43d8b002012-09-17 16:00:01 -04001366}
Dees_Troye58d5262012-09-21 12:27:57 -04001367
1368void TWPartition::Recreate_AndSec_Folder(void) {
1369 string Command;
1370
1371 if (!Has_Android_Secure)
1372 return;
1373
1374 if (!Mount(true)) {
1375 LOGE("Unable to recreate android secure folder.\n");
1376 } else if (!TWFunc::Path_Exists(Symlink_Path)) {
1377 LOGI("Recreating android secure folder.\n");
Dees_Troye58d5262012-09-21 12:27:57 -04001378 Command = "umount " + Symlink_Mount_Point;
1379 system(Command.c_str());
Dees_Troyce2fe772012-09-28 12:34:33 -04001380 Command = "cd " + Mount_Point + " && mkdir .android_secure";
1381 system(Command.c_str());
Dees_Troye58d5262012-09-21 12:27:57 -04001382 Command = "mount " + Symlink_Path + " " + Symlink_Mount_Point;
1383 system(Command.c_str());
1384 }
1385}