blob: 8a17508eb17f5ac2306bf7cefcd1f199cabedf2d [file] [log] [blame]
bigbiffad58e1b2020-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
19#include <string>
20
21#include "data.hpp"
22#include "partitions.hpp"
23#include "twrp-functions.hpp"
24#include "twrpRepacker.hpp"
25#include "twcommon.h"
26#include "variables.h"
27#include "gui/gui.hpp"
28
29bool twrpRepacker::Prepare_Empty_Folder(const std::string& Folder) {
30 if (TWFunc::Path_Exists(Folder))
31 TWFunc::removeDir(Folder, false);
32 return TWFunc::Recursive_Mkdir(Folder);
33}
34
35bool twrpRepacker::Backup_Image_For_Repack(TWPartition* Part, const std::string& Temp_Folder_Destination,
36 const bool Create_Backup, const std::string& Backup_Name) {
37 if (!Part) {
38 LOGERR("Partition was null!\n");
39 return false;
40 }
41 if (!Prepare_Empty_Folder(Temp_Folder_Destination))
42 return false;
43 std::string target_image = Temp_Folder_Destination + "boot.img";
44 PartitionSettings part_settings;
45 part_settings.Part = Part;
46 if (Create_Backup) {
47 if (PartitionManager.Check_Backup_Name(Backup_Name, true, false) != 0)
48 return false;
49 DataManager::GetValue(TW_BACKUPS_FOLDER_VAR, part_settings.Backup_Folder);
50 part_settings.Backup_Folder = part_settings.Backup_Folder + "/" + TWFunc::Get_Current_Date() + " " + Backup_Name + "/";
51 if (!TWFunc::Recursive_Mkdir(part_settings.Backup_Folder))
52 return false;
53 } else
54 part_settings.Backup_Folder = Temp_Folder_Destination;
55 part_settings.adbbackup = false;
56 part_settings.generate_digest = false;
57 part_settings.generate_md5 = false;
58 part_settings.PM_Method = PM_BACKUP;
59 part_settings.progress = NULL;
60 pid_t not_a_pid = 0;
61 if (!Part->Backup(&part_settings, &not_a_pid))
62 return false;
63 std::string backed_up_image = part_settings.Backup_Folder;
64 backed_up_image += Part->Get_Backup_FileName();
65 target_image = Temp_Folder_Destination + "boot.img";
66 if (Create_Backup) {
67 std::string source = part_settings.Backup_Folder + Part->Get_Backup_FileName();
68 if (TWFunc::copy_file(source, target_image, 0644) != 0) {
69 LOGERR("Failed to copy backup file '%s' to temp folder target '%s'\n", source.c_str(), target_image.c_str());
70 return false;
71 }
72 } else {
73 if (rename(backed_up_image.c_str(), target_image.c_str()) != 0) {
74 LOGERR("Failed to rename '%s' to '%s'\n", backed_up_image.c_str(), target_image.c_str());
75 return false;
76 }
77 }
78 original_ramdisk_format = Unpack_Image(target_image, Temp_Folder_Destination, false, false);
79 return !original_ramdisk_format.empty();
80}
81
82std::string twrpRepacker::Unpack_Image(const std::string& Source_Path, const std::string& Temp_Folder_Destination,
83 const bool Copy_Source, const bool Create_Destination) {
84 std::string txt_to_find = "RAMDISK_FMT";
85 if (Create_Destination) {
86 if (!Prepare_Empty_Folder(Temp_Folder_Destination))
87 return std::string();
88 }
89 if (Copy_Source) {
90 std::string destination = Temp_Folder_Destination + "/boot.img";
91 if (TWFunc::copy_file(Source_Path, destination, 0644))
92 return std::string();
93 }
94 std::string command = "cd " + Temp_Folder_Destination + " && /system/bin/magiskboot unpack -h ";
95 command = command + "'" + Source_Path +"'";
96
97 std::string magisk_unpack_output;
98 int ret;
99 if ((ret = TWFunc::Exec_Cmd(command, magisk_unpack_output, true)) != 0) {
100 LOGINFO("Error unpacking %s, ret: %d!\n", Source_Path.c_str(), ret);
101 gui_msg(Msg(msg::kError, "unpack_error=Error unpacking image."));
102 return std::string();
103 }
104 size_t pos = magisk_unpack_output.find(txt_to_find) + txt_to_find.size();
105 std::string ramdisk_format = magisk_unpack_output.substr(pos, magisk_unpack_output.size() - 1);
106 ramdisk_format.erase(std::remove(ramdisk_format.begin(), ramdisk_format.end(), '['), ramdisk_format.end());
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(), '\n'), ramdisk_format.end());
110 return ramdisk_format;
111}
112
113bool twrpRepacker::Repack_Image_And_Flash(const std::string& Target_Image, const struct Repack_Options_struct& Repack_Options) {
114 bool recompress = false;
115
116 if (!TWFunc::Path_Exists("/system/bin/magiskboot")) {
117 LOGERR("Image repacking tool not present in this TWRP build!");
118 return false;
119 }
120 DataManager::SetProgress(0);
nebrassy45f66b22021-07-26 22:34:24 +0200121 PartitionManager.Update_System_Details();
bigbiffad58e1b2020-07-06 20:24:34 -0400122 TWPartition* part = PartitionManager.Find_Partition_By_Path("/boot");
123 if (part)
124 gui_msg(Msg("unpacking_image=Unpacking {1}...")(part->Get_Display_Name()));
125 else {
126 gui_msg(Msg(msg::kError, "unable_to_locate=Unable to locate {1}.")("/boot"));
127 return false;
128 }
129 if (!Backup_Image_For_Repack(part, REPACK_ORIG_DIR, Repack_Options.Backup_First, gui_lookup("repack", "Repack")))
130 return false;
131 DataManager::SetProgress(.25);
132 gui_msg(Msg("unpacking_image=Unpacking {1}...")(Target_Image));
133 image_ramdisk_format = Unpack_Image(Target_Image, REPACK_NEW_DIR, true);
134 if (image_ramdisk_format.empty())
135 return false;
136 DataManager::SetProgress(.5);
137 gui_msg(Msg("repacking_image=Repacking {1}...")(part->Get_Display_Name()));
138 std::string path = REPACK_NEW_DIR;
139 if (Repack_Options.Type == REPLACE_KERNEL) {
140 // When we replace the kernel, what we really do is copy the boot partition ramdisk into the new image's folder
141 if (TWFunc::copy_file(REPACK_ORIG_DIR "ramdisk.cpio", REPACK_NEW_DIR "ramdisk.cpio", 0644)) {
142 LOGERR("Failed to copy ramdisk\n");
143 return false;
144 }
145 } else if (Repack_Options.Type == REPLACE_RAMDISK) {
146 // Repack the ramdisk
147 if (TWFunc::copy_file(REPACK_NEW_DIR "ramdisk.cpio", REPACK_ORIG_DIR "ramdisk.cpio", 0644)) {
148 LOGERR("Failed to copy ramdisk\n");
149 return false;
150 }
151 path = REPACK_ORIG_DIR;
152 } else {
153 LOGERR("Invalid repacking options specified\n");
154 return false;
155 }
156 if (Repack_Options.Disable_Verity)
157 LOGERR("Disabling verity is not implemented yet\n");
158 if (Repack_Options.Disable_Force_Encrypt)
159 LOGERR("Disabling force encrypt is not implemented yet\n");
160 std::string command = "cd " + path + " && /system/bin/magiskboot repack ";
161 if (original_ramdisk_format != image_ramdisk_format) {
162 command = command + "-n ";
163 recompress = true;
164 }
165
166 command += path + "boot.img";
167
168 std::string orig_compressed_image(REPACK_ORIG_DIR);
169 orig_compressed_image += "ramdisk.cpio";
170 std::string copy_compressed_image(REPACK_ORIG_DIR);
171 copy_compressed_image += "ramdisk-1.cpio";
172
173 if (recompress) {
174 std::string compress_cmd = "/system/bin/magiskboot compress=" + image_ramdisk_format + " " + orig_compressed_image + " " + copy_compressed_image;
175 if (TWFunc::Exec_Cmd(compress_cmd) != 0) {
176 gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
177 return false;
178 }
179 std::rename(copy_compressed_image.c_str(), orig_compressed_image.c_str());
180 }
181
182 if (TWFunc::Exec_Cmd(command) != 0) {
183 gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
184 return false;
185 }
186
187 DataManager::SetProgress(.75);
188 std::string file = "new-boot.img";
189 DataManager::SetValue("tw_flash_partition", "/boot;");
190 if (!PartitionManager.Flash_Image(path, file)) {
191 LOGINFO("Error flashing new image\n");
192 return false;
193 }
194 DataManager::SetProgress(1);
195 TWFunc::removeDir(REPACK_ORIG_DIR, false);
196 if (part->Is_SlotSelect() && Repack_Options.Type == REPLACE_RAMDISK) {
197 LOGINFO("Switching slots to flash ramdisk to both partitions\n");
198 string Current_Slot = PartitionManager.Get_Active_Slot_Display();
199 if (Current_Slot == "A")
200 PartitionManager.Set_Active_Slot("B");
201 else
202 PartitionManager.Set_Active_Slot("A");
203 DataManager::SetProgress(.25);
204 if (!Backup_Image_For_Repack(part, REPACK_ORIG_DIR, Repack_Options.Backup_First, gui_lookup("repack", "Repack")))
205 return false;
206 if (TWFunc::copy_file(REPACK_NEW_DIR "ramdisk.cpio", REPACK_ORIG_DIR "ramdisk.cpio", 0644)) {
207 LOGERR("Failed to copy ramdisk\n");
208 return false;
209 }
210 path = REPACK_ORIG_DIR;
211 std::string command = "cd " + path + " && /system/bin/magiskboot repack ";
212
213 if (original_ramdisk_format != image_ramdisk_format) {
214 command = command + "-n ";
215 recompress = true;
216 }
217 command += path + "boot.img";
218
219 if (recompress) {
220 std::string compress_cmd = "/system/bin/magiskboot compress=" + image_ramdisk_format + " " + orig_compressed_image + " " + copy_compressed_image;
221 if (TWFunc::Exec_Cmd(compress_cmd) != 0) {
222 gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
223 return false;
224 }
225 std::rename(copy_compressed_image.c_str(), orig_compressed_image.c_str());
226 }
227
228 if (TWFunc::Exec_Cmd(command) != 0) {
229 gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
230 return false;
231 }
232
233 if (TWFunc::Exec_Cmd(command) != 0) {
234 gui_msg(Msg(msg::kError, "repack_error=Error repacking image."));
235 return false;
236 }
237 DataManager::SetProgress(.75);
238 std::string file = "new-boot.img";
239 DataManager::SetValue("tw_flash_partition", "/boot;");
240 if (!PartitionManager.Flash_Image(path, file)) {
241 LOGINFO("Error flashing new image\n");
242 return false;
243 }
244 DataManager::SetProgress(1);
245 TWFunc::removeDir(REPACK_ORIG_DIR, false);
246 PartitionManager.Set_Active_Slot(Current_Slot);
247 }
248 TWFunc::removeDir(REPACK_NEW_DIR, false);
249 return true;
250}