blob: c50435c2dc037916143a79fc5d1729b9aeaf2e07 [file] [log] [blame]
bigbiff56b02eb2020-07-06 20:24:34 -04001/*
2 Copyright 2013 to 2020 TeamWin
3 This file is part of TWRP/TeamWin Recovery Project.
4
5 TWRP is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 TWRP is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
17*/
18
Captain Throwback0c4e6b82021-11-19 19:23:15 -050019#include <algorithm>
bigbiff56b02eb2020-07-06 20:24:34 -040020#include <string>
21
22#include "data.hpp"
23#include "partitions.hpp"
24#include "twrp-functions.hpp"
25#include "twrpRepacker.hpp"
26#include "twcommon.h"
27#include "variables.h"
28#include "gui/gui.hpp"
29
30bool twrpRepacker::Prepare_Empty_Folder(const std::string& Folder) {
31 if (TWFunc::Path_Exists(Folder))
32 TWFunc::removeDir(Folder, false);
33 return TWFunc::Recursive_Mkdir(Folder);
34}
35
36bool twrpRepacker::Backup_Image_For_Repack(TWPartition* Part, const std::string& Temp_Folder_Destination,
37 const bool Create_Backup, const std::string& Backup_Name) {
38 if (!Part) {
39 LOGERR("Partition was null!\n");
40 return false;
41 }
42 if (!Prepare_Empty_Folder(Temp_Folder_Destination))
43 return false;
44 std::string target_image = Temp_Folder_Destination + "boot.img";
45 PartitionSettings part_settings;
46 part_settings.Part = Part;
47 if (Create_Backup) {
48 if (PartitionManager.Check_Backup_Name(Backup_Name, true, false) != 0)
49 return false;
50 DataManager::GetValue(TW_BACKUPS_FOLDER_VAR, part_settings.Backup_Folder);
51 part_settings.Backup_Folder = part_settings.Backup_Folder + "/" + TWFunc::Get_Current_Date() + " " + Backup_Name + "/";
52 if (!TWFunc::Recursive_Mkdir(part_settings.Backup_Folder))
53 return false;
54 } else
55 part_settings.Backup_Folder = Temp_Folder_Destination;
56 part_settings.adbbackup = false;
57 part_settings.generate_digest = false;
58 part_settings.generate_md5 = false;
59 part_settings.PM_Method = PM_BACKUP;
60 part_settings.progress = NULL;
61 pid_t not_a_pid = 0;
62 if (!Part->Backup(&part_settings, &not_a_pid))
63 return false;
64 std::string backed_up_image = part_settings.Backup_Folder;
65 backed_up_image += Part->Get_Backup_FileName();
66 target_image = Temp_Folder_Destination + "boot.img";
67 if (Create_Backup) {
68 std::string source = part_settings.Backup_Folder + Part->Get_Backup_FileName();
69 if (TWFunc::copy_file(source, target_image, 0644) != 0) {
70 LOGERR("Failed to copy backup file '%s' to temp folder target '%s'\n", source.c_str(), target_image.c_str());
71 return false;
72 }
73 } else {
74 if (rename(backed_up_image.c_str(), target_image.c_str()) != 0) {
75 LOGERR("Failed to rename '%s' to '%s'\n", backed_up_image.c_str(), target_image.c_str());
76 return false;
77 }
78 }
79 original_ramdisk_format = Unpack_Image(target_image, Temp_Folder_Destination, false, false);
80 return !original_ramdisk_format.empty();
81}
82
83std::string twrpRepacker::Unpack_Image(const std::string& Source_Path, const std::string& Temp_Folder_Destination,
84 const bool Copy_Source, const bool Create_Destination) {
85 std::string txt_to_find = "RAMDISK_FMT";
86 if (Create_Destination) {
87 if (!Prepare_Empty_Folder(Temp_Folder_Destination))
88 return std::string();
89 }
90 if (Copy_Source) {
91 std::string destination = Temp_Folder_Destination + "/boot.img";
92 if (TWFunc::copy_file(Source_Path, destination, 0644))
93 return std::string();
94 }
95 std::string command = "cd " + Temp_Folder_Destination + " && /sbin/magiskboot unpack -h ";
96 command = command + "'" + Source_Path +"'";
97
98 std::string magisk_unpack_output;
99 int ret;
100 if ((ret = TWFunc::Exec_Cmd(command, magisk_unpack_output, true)) != 0) {
101 LOGINFO("Error unpacking %s, ret: %d!\n", Source_Path.c_str(), ret);
102 gui_msg(Msg(msg::kError, "unpack_error=Error unpacking image."));
103 return std::string();
104 }
105 size_t pos = magisk_unpack_output.find(txt_to_find) + txt_to_find.size();
106 std::string ramdisk_format = magisk_unpack_output.substr(pos, magisk_unpack_output.size() - 1);
107 ramdisk_format.erase(std::remove(ramdisk_format.begin(), ramdisk_format.end(), '['), ramdisk_format.end());
108 ramdisk_format.erase(std::remove(ramdisk_format.begin(), ramdisk_format.end(), ']'), ramdisk_format.end());
109 ramdisk_format.erase(std::remove(ramdisk_format.begin(), ramdisk_format.end(), ' '), ramdisk_format.end());
110 ramdisk_format.erase(std::remove(ramdisk_format.begin(), ramdisk_format.end(), '\n'), ramdisk_format.end());
111 return ramdisk_format;
112}
113
114bool twrpRepacker::Repack_Image_And_Flash(const std::string& Target_Image, const struct Repack_Options_struct& Repack_Options) {
115 bool recompress = false;
116
117 if (!TWFunc::Path_Exists("/sbin/magiskboot")) {
118 LOGERR("Image repacking tool not present in this TWRP build!");
119 return false;
120 }
121 DataManager::SetProgress(0);
nebrassy774f7a12021-07-26 22:34:24 +0200122 PartitionManager.Update_System_Details();
bigbiff56b02eb2020-07-06 20:24:34 -0400123 TWPartition* part = PartitionManager.Find_Partition_By_Path("/boot");
124 if (part)
125 gui_msg(Msg("unpacking_image=Unpacking {1}...")(part->Get_Display_Name()));
126 else {
127 gui_msg(Msg(msg::kError, "unable_to_locate=Unable to locate {1}.")("/boot"));
128 return false;
129 }
130 if (!Backup_Image_For_Repack(part, REPACK_ORIG_DIR, Repack_Options.Backup_First, gui_lookup("repack", "Repack")))
131 return false;
132 DataManager::SetProgress(.25);
nebrassyfe1c2372021-05-20 13:03:30 +0200133 if (Repack_Options.Type == REPLACE_RAMDISK_UNPACKED) {
134 if (!Prepare_Empty_Folder(REPACK_NEW_DIR))
135 return false;
136 image_ramdisk_format = "gzip";
137 } else {
138 gui_msg(Msg("unpacking_image=Unpacking {1}...")(Target_Image));
139 image_ramdisk_format = Unpack_Image(Target_Image, REPACK_NEW_DIR, true);
140 }
bigbiff56b02eb2020-07-06 20:24:34 -0400141 if (image_ramdisk_format.empty())
142 return false;
143 DataManager::SetProgress(.5);
144 gui_msg(Msg("repacking_image=Repacking {1}...")(part->Get_Display_Name()));
145 std::string path = REPACK_NEW_DIR;
146 if (Repack_Options.Type == REPLACE_KERNEL) {
147 // When we replace the kernel, what we really do is copy the boot partition ramdisk into the new image's folder
148 if (TWFunc::copy_file(REPACK_ORIG_DIR "ramdisk.cpio", REPACK_NEW_DIR "ramdisk.cpio", 0644)) {
149 LOGERR("Failed to copy ramdisk\n");
150 return false;
151 }
nebrassyfe1c2372021-05-20 13:03:30 +0200152 } else if (Repack_Options.Type == REPLACE_RAMDISK_UNPACKED) {
153 if (TWFunc::copy_file(Target_Image, REPACK_ORIG_DIR "ramdisk.cpio", 0644)) {
154 LOGERR("Failed to copy ramdisk\n");
155 return false;
156 }
157 if (TWFunc::copy_file(Target_Image, REPACK_NEW_DIR "ramdisk.cpio", 0644)) {
158 LOGERR("Failed to copy ramdisk\n");
159 return false;
160 }
161 path = REPACK_ORIG_DIR;
bigbiff56b02eb2020-07-06 20:24:34 -0400162 } else if (Repack_Options.Type == REPLACE_RAMDISK) {
163 // Repack the ramdisk
164 if (TWFunc::copy_file(REPACK_NEW_DIR "ramdisk.cpio", REPACK_ORIG_DIR "ramdisk.cpio", 0644)) {
165 LOGERR("Failed to copy ramdisk\n");
166 return false;
167 }
168 path = REPACK_ORIG_DIR;
169 } else {
170 LOGERR("Invalid repacking options specified\n");
171 return false;
172 }
173 if (Repack_Options.Disable_Verity)
174 LOGERR("Disabling verity is not implemented yet\n");
175 if (Repack_Options.Disable_Force_Encrypt)
176 LOGERR("Disabling force encrypt is not implemented yet\n");
177 std::string command = "cd " + path + " && /sbin/magiskboot repack ";
178 if (original_ramdisk_format != image_ramdisk_format) {
bigbiff56b02eb2020-07-06 20:24:34 -0400179 recompress = true;
180 }
181
182 command += path + "boot.img";
183
184 std::string orig_compressed_image(REPACK_ORIG_DIR);
185 orig_compressed_image += "ramdisk.cpio";
186 std::string copy_compressed_image(REPACK_ORIG_DIR);
187 copy_compressed_image += "ramdisk-1.cpio";
188
189 if (recompress) {
nebrassy363497b2021-08-07 00:37:30 +0200190 std::string decompress_cmd = "/sbin/magiskboot decompress " + orig_compressed_image + " " + copy_compressed_image;
191 if (TWFunc::Exec_Cmd(decompress_cmd) != 0) {
bigbiff56b02eb2020-07-06 20:24:34 -0400192 gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
193 return false;
194 }
195 std::rename(copy_compressed_image.c_str(), orig_compressed_image.c_str());
196 }
197
198 if (TWFunc::Exec_Cmd(command) != 0) {
199 gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
200 return false;
201 }
202
203 DataManager::SetProgress(.75);
204 std::string file = "new-boot.img";
205 DataManager::SetValue("tw_flash_partition", "/boot;");
206 if (!PartitionManager.Flash_Image(path, file)) {
207 LOGINFO("Error flashing new image\n");
208 return false;
209 }
210 DataManager::SetProgress(1);
211 TWFunc::removeDir(REPACK_ORIG_DIR, false);
nebrassyfe1c2372021-05-20 13:03:30 +0200212 if (part->Is_SlotSelect()) { if (Repack_Options.Type == REPLACE_RAMDISK || Repack_Options.Type == REPLACE_RAMDISK_UNPACKED) {
bigbiff56b02eb2020-07-06 20:24:34 -0400213 LOGINFO("Switching slots to flash ramdisk to both partitions\n");
214 string Current_Slot = PartitionManager.Get_Active_Slot_Display();
215 if (Current_Slot == "A")
bigbiff6e2f3662021-07-31 19:02:26 -0400216 PartitionManager.Override_Active_Slot("B");
bigbiff56b02eb2020-07-06 20:24:34 -0400217 else
bigbiff6e2f3662021-07-31 19:02:26 -0400218 PartitionManager.Override_Active_Slot("A");
bigbiff56b02eb2020-07-06 20:24:34 -0400219 DataManager::SetProgress(.25);
220 if (!Backup_Image_For_Repack(part, REPACK_ORIG_DIR, Repack_Options.Backup_First, gui_lookup("repack", "Repack")))
221 return false;
222 if (TWFunc::copy_file(REPACK_NEW_DIR "ramdisk.cpio", REPACK_ORIG_DIR "ramdisk.cpio", 0644)) {
223 LOGERR("Failed to copy ramdisk\n");
224 return false;
225 }
226 path = REPACK_ORIG_DIR;
227 std::string command = "cd " + path + " && /sbin/magiskboot repack ";
228
229 if (original_ramdisk_format != image_ramdisk_format) {
bigbiff56b02eb2020-07-06 20:24:34 -0400230 recompress = true;
231 }
232 command += path + "boot.img";
233
234 if (recompress) {
nebrassy363497b2021-08-07 00:37:30 +0200235 std::string decompress_cmd = "/sbin/magiskboot decompress " + orig_compressed_image + " " + copy_compressed_image;
236 if (TWFunc::Exec_Cmd(decompress_cmd) != 0) {
bigbiff56b02eb2020-07-06 20:24:34 -0400237 gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
238 return false;
239 }
240 std::rename(copy_compressed_image.c_str(), orig_compressed_image.c_str());
241 }
242
243 if (TWFunc::Exec_Cmd(command) != 0) {
244 gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
245 return false;
246 }
247
248 if (TWFunc::Exec_Cmd(command) != 0) {
249 gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
250 return false;
251 }
252 DataManager::SetProgress(.75);
253 std::string file = "new-boot.img";
254 DataManager::SetValue("tw_flash_partition", "/boot;");
255 if (!PartitionManager.Flash_Image(path, file)) {
256 LOGINFO("Error flashing new image\n");
257 return false;
258 }
259 DataManager::SetProgress(1);
260 TWFunc::removeDir(REPACK_ORIG_DIR, false);
nebrassyfe1c2372021-05-20 13:03:30 +0200261 }}
bigbifffc9e4382021-08-07 14:34:06 -0400262 TWFunc::removeDir(REPACK_NEW_DIR, false);
Captain Throwback5c1c24e2021-10-03 01:30:44 -0400263 gui_msg(Msg(msg::kWarning, "repack_overwrite_warning=If device was previously rooted, then root has been overwritten and will need to be reinstalled."));
nebrassy66c9fb42021-11-21 03:32:47 +0100264 string Current_Slot = PartitionManager.Get_Active_Slot_Display();
265 if (Current_Slot == "A")
266 PartitionManager.Override_Active_Slot("B");
267 else
268 PartitionManager.Override_Active_Slot("A");
bigbifffc9e4382021-08-07 14:34:06 -0400269 return true;
bigbiff56b02eb2020-07-06 20:24:34 -0400270}
nebrassyfe1c2372021-05-20 13:03:30 +0200271
272bool twrpRepacker::Flash_Current_Twrp() {
273if (!TWFunc::Path_Exists("/ramdisk-files.txt")) {
274 LOGERR("can not find ramdisk-files.txt");
275 return false;
276 }
277 Repack_Options_struct Repack_Options;
278 Repack_Options.Disable_Verity = false;
279 Repack_Options.Disable_Force_Encrypt = false;
280 Repack_Options.Type = REPLACE_RAMDISK_UNPACKED;
281 Repack_Options.Backup_First = DataManager::GetIntValue("tw_repack_backup_first") != 0;
282 std::string verifyfiles = "cd / && sha256sum -c ramdisk-files.sha256sum";
283 if (TWFunc::Exec_Cmd(verifyfiles) != 0) {
284 gui_msg(Msg(msg::kError, "modified_ramdisk_error=ramdisk files have been modified, unable to create ramdisk to flash, fastboot boot twrp and try this option again or use the Install Recovery Ramdisk option."));
285 return false;
286 }
287 std::string command = "cd / && /sbin/cpio -H newc -o < ramdisk-files.txt > /tmp/currentramdisk.cpio && /sbin/gzip -f /tmp/currentramdisk.cpio";
288 if (TWFunc::Exec_Cmd(command) != 0) {
289 gui_msg(Msg(msg::kError, "create_ramdisk_error=failed to create ramdisk to flash."));
290 return false;
291 }
292 if (!Repack_Image_And_Flash("/tmp/currentramdisk.cpio.gz", Repack_Options))
293 return false;
294 else
295 return true;
296}