blob: b0b6f3d170239e58388788300047f38d1f671ec4 [file] [log] [blame]
Dees Troy3be70a82013-10-22 14:25:12 +00001/*
Ethan Yonker20eb0bc2016-03-22 14:23:28 -05002 Copyright 2012 to 2016 bigbiff/Dees_Troy TeamWin
Dees Troy3be70a82013-10-22 14:25:12 +00003 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_Troy32c8eb82012-09-11 15:28:06 -040018
19#include <ctype.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <limits.h>
23#include <sys/stat.h>
24#include <sys/wait.h>
25#include <unistd.h>
26
27#include <string.h>
28#include <stdio.h>
29
Dees_Troy2673cec2013-04-02 20:22:16 +000030#include "twcommon.h"
Ethan Yonker75bf0412014-11-21 13:54:27 -060031#include "mtdutils/mounts.h"
32#include "mtdutils/mtdutils.h"
Ethan Yonker8373cfe2017-09-08 06:50:54 -050033
34#ifdef USE_MINZIP
Dees_Troy32c8eb82012-09-11 15:28:06 -040035#include "minzip/SysUtil.h"
Ethan Yonker8373cfe2017-09-08 06:50:54 -050036#else
37#include "otautil/SysUtil.h"
38#include <ziparchive/zip_archive.h>
39#endif
40#include "zipwrap.hpp"
Ethan Yonkerf1179622016-08-25 15:32:21 -050041#ifdef USE_OLD_VERIFIER
Ethan Yonker4bf259f2016-08-29 11:50:34 -050042#include "verifier24/verifier.h"
Ethan Yonkerf1179622016-08-25 15:32:21 -050043#else
Ethan Yonker75bf0412014-11-21 13:54:27 -060044#include "verifier.h"
Ethan Yonkerf1179622016-08-25 15:32:21 -050045#endif
Dees_Troy32c8eb82012-09-11 15:28:06 -040046#include "variables.h"
47#include "data.hpp"
48#include "partitions.hpp"
bigbiff bigbiff56cf5642016-08-19 17:43:45 -040049#include "twrpDigestDriver.hpp"
50#include "twrpDigest/twrpDigest.hpp"
51#include "twrpDigest/twrpMD5.hpp"
Dees_Troy38bd7602012-09-14 13:33:53 -040052#include "twrp-functions.hpp"
Ethan Yonker74db1572015-10-28 12:44:49 -050053#include "gui/gui.hpp"
Ethan Yonker20eb0bc2016-03-22 14:23:28 -050054#include "gui/pages.hpp"
Ethan Yonkerf1179622016-08-25 15:32:21 -050055#include "legacy_property_service.h"
Ethan Yonker941a8992016-12-05 09:04:30 -060056#include "twinstall.h"
57#include "installcommand.h"
Dees_Troy2673cec2013-04-02 20:22:16 +000058extern "C" {
59 #include "gui/gui.h"
that7e303cf2014-03-06 07:57:43 +010060}
61
Ethan Yonker941a8992016-12-05 09:04:30 -060062#define AB_OTA "payload_properties.txt"
63
that7e303cf2014-03-06 07:57:43 +010064static const char* properties_path = "/dev/__properties__";
65static const char* properties_path_renamed = "/dev/__properties_kk__";
Matt Mowercdd3b332014-03-27 14:38:48 -050066static bool legacy_props_env_initd = false;
67static bool legacy_props_path_modified = false;
that7e303cf2014-03-06 07:57:43 +010068
Ethan Yonker941a8992016-12-05 09:04:30 -060069enum zip_type {
70 UNKNOWN_ZIP_TYPE = 0,
71 UPDATE_BINARY_ZIP_TYPE,
72 AB_OTA_ZIP_TYPE,
73 TWRP_THEME_ZIP_TYPE
74};
75
that50640482015-08-30 12:08:05 +020076// to support pre-KitKat update-binaries that expect properties in the legacy format
Matt Mowercdd3b332014-03-27 14:38:48 -050077static int switch_to_legacy_properties()
that7e303cf2014-03-06 07:57:43 +010078{
Matt Mowercdd3b332014-03-27 14:38:48 -050079 if (!legacy_props_env_initd) {
80 if (legacy_properties_init() != 0)
81 return -1;
82
83 char tmp[32];
84 int propfd, propsz;
85 legacy_get_property_workspace(&propfd, &propsz);
86 sprintf(tmp, "%d,%d", dup(propfd), propsz);
87 setenv("ANDROID_PROPERTY_WORKSPACE", tmp, 1);
88 legacy_props_env_initd = true;
89 }
that7e303cf2014-03-06 07:57:43 +010090
91 if (TWFunc::Path_Exists(properties_path)) {
92 // hide real properties so that the updater uses the envvar to find the legacy format properties
Matt Mowercdd3b332014-03-27 14:38:48 -050093 if (rename(properties_path, properties_path_renamed) != 0) {
94 LOGERR("Renaming %s failed: %s\n", properties_path, strerror(errno));
95 return -1;
96 } else {
97 legacy_props_path_modified = true;
98 }
that7e303cf2014-03-06 07:57:43 +010099 }
Matt Mowercdd3b332014-03-27 14:38:48 -0500100
101 return 0;
that7e303cf2014-03-06 07:57:43 +0100102}
103
Matt Mowercdd3b332014-03-27 14:38:48 -0500104static int switch_to_new_properties()
that7e303cf2014-03-06 07:57:43 +0100105{
106 if (TWFunc::Path_Exists(properties_path_renamed)) {
Matt Mowercdd3b332014-03-27 14:38:48 -0500107 if (rename(properties_path_renamed, properties_path) != 0) {
108 LOGERR("Renaming %s failed: %s\n", properties_path_renamed, strerror(errno));
109 return -1;
110 } else {
111 legacy_props_path_modified = false;
112 }
that7e303cf2014-03-06 07:57:43 +0100113 }
Matt Mowercdd3b332014-03-27 14:38:48 -0500114
115 return 0;
Dees_Troy2673cec2013-04-02 20:22:16 +0000116}
Dees_Troy32c8eb82012-09-11 15:28:06 -0400117
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500118static int Install_Theme(const char* path, ZipWrap *Zip) {
Ethan Yonker20eb0bc2016-03-22 14:23:28 -0500119#ifdef TW_OEM_BUILD // We don't do custom themes in OEM builds
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500120 Zip->Close();
Ethan Yonker20eb0bc2016-03-22 14:23:28 -0500121 return INSTALL_CORRUPT;
122#else
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500123 if (!Zip->EntryExists("ui.xml")) {
Ethan Yonker20eb0bc2016-03-22 14:23:28 -0500124 return INSTALL_CORRUPT;
125 }
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500126 Zip->Close();
Ethan Yonker20eb0bc2016-03-22 14:23:28 -0500127 if (!PartitionManager.Mount_Settings_Storage(true))
128 return INSTALL_ERROR;
129 string theme_path = DataManager::GetSettingsStoragePath();
130 theme_path += "/TWRP/theme";
131 if (!TWFunc::Path_Exists(theme_path)) {
132 if (!TWFunc::Recursive_Mkdir(theme_path)) {
133 return INSTALL_ERROR;
134 }
135 }
136 theme_path += "/ui.zip";
137 if (TWFunc::copy_file(path, theme_path, 0644) != 0) {
138 return INSTALL_ERROR;
139 }
140 LOGINFO("Installing custom theme '%s' to '%s'\n", path, theme_path.c_str());
141 PageManager::RequestReload();
142 return INSTALL_SUCCESS;
143#endif
144}
145
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500146static int Prepare_Update_Binary(const char *path, ZipWrap *Zip, int* wipe_cache) {
147 if (!Zip->ExtractEntry(ASSUMED_UPDATE_BINARY_NAME, TMP_UPDATER_BINARY_PATH, 0755)) {
148 Zip->Close();
Dees_Troy2673cec2013-04-02 20:22:16 +0000149 LOGERR("Could not extract '%s'\n", ASSUMED_UPDATE_BINARY_NAME);
150 return INSTALL_ERROR;
151 }
Dees_Troy32c8eb82012-09-11 15:28:06 -0400152
Dees_Troy512376c2013-09-03 19:39:41 +0000153 // If exists, extract file_contexts from the zip file
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500154 if (!Zip->EntryExists("file_contexts")) {
155 Zip->Close();
Dees_Troy512376c2013-09-03 19:39:41 +0000156 LOGINFO("Zip does not contain SELinux file_contexts file in its root.\n");
157 } else {
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500158 const string output_filename = "/file_contexts";
Dees_Troy512376c2013-09-03 19:39:41 +0000159 LOGINFO("Zip contains SELinux file_contexts file in its root. Extracting to %s\n", output_filename.c_str());
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500160 if (!Zip->ExtractEntry("file_contexts", output_filename, 0644)) {
161 Zip->Close();
that50640482015-08-30 12:08:05 +0200162 LOGERR("Could not extract '%s'\n", output_filename.c_str());
Dees_Troy512376c2013-09-03 19:39:41 +0000163 return INSTALL_ERROR;
164 }
165 }
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500166 Zip->Close();
Ethan Yonker941a8992016-12-05 09:04:30 -0600167 return INSTALL_SUCCESS;
168}
169
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500170static int Run_Update_Binary(const char *path, ZipWrap *Zip, int* wipe_cache, zip_type ztype) {
Ethan Yonker941a8992016-12-05 09:04:30 -0600171 int ret_val, pipe_fd[2], status, zip_verify;
172 char buffer[1024];
173 FILE* child_data;
Dees_Troy512376c2013-09-03 19:39:41 +0000174
Matt Mower6883d732014-03-20 17:28:13 -0500175#ifndef TW_NO_LEGACY_PROPS
Ethan Yonker75aa6152017-09-08 12:17:03 -0500176 if (DataManager::GetIntValue("tw_enable_legacy_props") != 0) {
177 /* Set legacy properties */
178 if (switch_to_legacy_properties() != 0) {
179 LOGERR("Legacy property environment did not initialize successfully. Properties may not be detected.\n");
180 } else {
181 LOGINFO("Legacy property environment initialized.\n");
182 }
Matt Mowercdd3b332014-03-27 14:38:48 -0500183 }
Matt Mower6883d732014-03-20 17:28:13 -0500184#endif
Matt Mowercdd3b332014-03-27 14:38:48 -0500185
Dees_Troy2673cec2013-04-02 20:22:16 +0000186 pipe(pipe_fd);
Dees_Troy32c8eb82012-09-11 15:28:06 -0400187
Ethan Yonker941a8992016-12-05 09:04:30 -0600188 std::vector<std::string> args;
189 if (ztype == UPDATE_BINARY_ZIP_TYPE) {
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500190 ret_val = update_binary_command(path, 0, pipe_fd[1], &args);
Ethan Yonker941a8992016-12-05 09:04:30 -0600191 } else if (ztype == AB_OTA_ZIP_TYPE) {
192 ret_val = abupdate_binary_command(path, Zip, 0, pipe_fd[1], &args);
193 } else {
194 LOGERR("Unknown zip type %i\n", ztype);
195 ret_val = INSTALL_CORRUPT;
196 }
197 if (ret_val) {
198 close(pipe_fd[0]);
199 close(pipe_fd[1]);
200 return ret_val;
201 }
202
203 // Convert the vector to a NULL-terminated char* array suitable for execv.
204 const char* chr_args[args.size() + 1];
205 chr_args[args.size()] = NULL;
206 for (size_t i = 0; i < args.size(); i++)
207 chr_args[i] = args[i].c_str();
Dees_Troy32c8eb82012-09-11 15:28:06 -0400208
Dees_Troy2673cec2013-04-02 20:22:16 +0000209 pid_t pid = fork();
210 if (pid == 0) {
211 close(pipe_fd[0]);
Ethan Yonker941a8992016-12-05 09:04:30 -0600212 execve(chr_args[0], const_cast<char**>(chr_args), environ);
213 printf("E:Can't execute '%s': %s\n", chr_args[0], strerror(errno));
Dees_Troy2673cec2013-04-02 20:22:16 +0000214 _exit(-1);
215 }
216 close(pipe_fd[1]);
Dees_Troy32c8eb82012-09-11 15:28:06 -0400217
Dees_Troy2673cec2013-04-02 20:22:16 +0000218 *wipe_cache = 0;
Dees_Troy32c8eb82012-09-11 15:28:06 -0400219
Dees_Troy2673cec2013-04-02 20:22:16 +0000220 DataManager::GetValue(TW_SIGNED_ZIP_VERIFY_VAR, zip_verify);
221 child_data = fdopen(pipe_fd[0], "r");
222 while (fgets(buffer, sizeof(buffer), child_data) != NULL) {
223 char* command = strtok(buffer, " \n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200224 if (command == NULL) {
225 continue;
226 } else if (strcmp(command, "progress") == 0) {
227 char* fraction_char = strtok(NULL, " \n");
228 char* seconds_char = strtok(NULL, " \n");
Dees_Troy32c8eb82012-09-11 15:28:06 -0400229
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200230 float fraction_float = strtof(fraction_char, NULL);
231 int seconds_float = strtol(seconds_char, NULL, 10);
Dees_Troy32c8eb82012-09-11 15:28:06 -0400232
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200233 if (zip_verify)
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500234 DataManager::ShowProgress(fraction_float * (1 - VERIFICATION_PROGRESS_FRAC), seconds_float);
Dees_Troy2673cec2013-04-02 20:22:16 +0000235 else
236 DataManager::ShowProgress(fraction_float, seconds_float);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200237 } else if (strcmp(command, "set_progress") == 0) {
238 char* fraction_char = strtok(NULL, " \n");
239 float fraction_float = strtof(fraction_char, NULL);
240 DataManager::SetProgress(fraction_float);
241 } else if (strcmp(command, "ui_print") == 0) {
242 char* display_value = strtok(NULL, "\n");
243 if (display_value) {
244 gui_print("%s", display_value);
245 } else {
246 gui_print("\n");
247 }
248 } else if (strcmp(command, "wipe_cache") == 0) {
249 *wipe_cache = 1;
250 } else if (strcmp(command, "clear_display") == 0) {
251 // Do nothing, not supported by TWRP
Ethan Yonker072c8d82016-08-26 22:22:24 -0500252 } else if (strcmp(command, "log") == 0) {
253 printf("%s\n", strtok(NULL, "\n"));
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200254 } else {
255 LOGERR("unknown command [%s]\n", command);
256 }
Dees_Troy2673cec2013-04-02 20:22:16 +0000257 }
258 fclose(child_data);
Dees_Troy32c8eb82012-09-11 15:28:06 -0400259
that50640482015-08-30 12:08:05 +0200260 int waitrc = TWFunc::Wait_For_Child(pid, &status, "Updater");
Matt Mowercdd3b332014-03-27 14:38:48 -0500261
Matt Mower6883d732014-03-20 17:28:13 -0500262#ifndef TW_NO_LEGACY_PROPS
Ethan Yonker75aa6152017-09-08 12:17:03 -0500263 if (DataManager::GetIntValue("tw_enable_legacy_props") != 0) {
264 /* Unset legacy properties */
265 if (legacy_props_path_modified) {
266 if (switch_to_new_properties() != 0) {
267 LOGERR("Legacy property environment did not disable successfully. Legacy properties may still be in use.\n");
268 } else {
269 LOGINFO("Legacy property environment disabled.\n");
270 }
Matt Mowercdd3b332014-03-27 14:38:48 -0500271 }
272 }
Matt Mower6883d732014-03-20 17:28:13 -0500273#endif
Matt Mowercdd3b332014-03-27 14:38:48 -0500274
that50640482015-08-30 12:08:05 +0200275 if (waitrc != 0)
Dees_Troy2673cec2013-04-02 20:22:16 +0000276 return INSTALL_ERROR;
Dees_Troy32c8eb82012-09-11 15:28:06 -0400277
Dees_Troy2673cec2013-04-02 20:22:16 +0000278 return INSTALL_SUCCESS;
Dees_Troy32c8eb82012-09-11 15:28:06 -0400279}
280
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500281int TWinstall_zip(const char* path, int* wipe_cache) {
that50640482015-08-30 12:08:05 +0200282 int ret_val, zip_verify = 1;
Dees_Troy32c8eb82012-09-11 15:28:06 -0400283
Ethan Yonker24813422014-11-07 17:19:07 -0600284 if (strcmp(path, "error") == 0) {
285 LOGERR("Failed to get adb sideload file: '%s'\n", path);
Dees_Troy32c8eb82012-09-11 15:28:06 -0400286 return INSTALL_CORRUPT;
Matt Mowerd5c1a922014-04-15 12:50:58 -0500287 }
Dees_Troy32c8eb82012-09-11 15:28:06 -0400288
Ethan Yonker74db1572015-10-28 12:44:49 -0500289 gui_msg(Msg("installing_zip=Installing zip file '{1}'")(path));
Ethan Yonker24813422014-11-07 17:19:07 -0600290 if (strlen(path) < 9 || strncmp(path, "/sideload", 9) != 0) {
bigbiff bigbiff56cf5642016-08-19 17:43:45 -0400291 string digest_str;
292 string Full_Filename = path;
293 string digest_file = path;
294 digest_file += ".md5";
295
296 gui_msg("check_for_digest=Checking for Digest file...");
297 if (!TWFunc::Path_Exists(digest_file)) {
298 gui_msg("no_digest=Skipping Digest check: no Digest file found");
299 }
300 else {
301 if (TWFunc::read_file(digest_file, digest_str) != 0) {
302 LOGERR("Skipping MD5 check: MD5 file unreadable\n");
303 }
304 else {
305 twrpDigest *digest = new twrpMD5();
306 if (!twrpDigestDriver::stream_file_to_digest(Full_Filename, digest)) {
307 delete digest;
308 return INSTALL_CORRUPT;
309 }
310 string digest_check = digest->return_digest_string();
311 if (digest_str == digest_check) {
312 gui_msg(Msg("digest_matched=Digest matched for '{1}'.")(path));
313 }
314 else {
315 LOGERR("Aborting zip install: Digest verification failed\n");
316 delete digest;
317 return INSTALL_CORRUPT;
318 }
319 delete digest;
320 }
Ethan Yonker24813422014-11-07 17:19:07 -0600321 }
322 }
323
Ethan Yonkerd5801c52014-04-14 08:59:35 -0500324#ifndef TW_OEM_BUILD
Dees_Troy32c8eb82012-09-11 15:28:06 -0400325 DataManager::GetValue(TW_SIGNED_ZIP_VERIFY_VAR, zip_verify);
Ethan Yonkerd5801c52014-04-14 08:59:35 -0500326#endif
Dees_Troy2673cec2013-04-02 20:22:16 +0000327 DataManager::SetProgress(0);
Ethan Yonkerf96087e2014-11-07 10:38:51 -0600328
329 MemMapping map;
330 if (sysMapFile(path, &map) != 0) {
Ethan Yonker74db1572015-10-28 12:44:49 -0500331 gui_msg(Msg(msg::kError, "fail_sysmap=Failed to map file '{1}'")(path));
that50640482015-08-30 12:08:05 +0200332 return -1;
333 }
Ethan Yonkerf96087e2014-11-07 10:38:51 -0600334
Dees_Troy32c8eb82012-09-11 15:28:06 -0400335 if (zip_verify) {
Ethan Yonker74db1572015-10-28 12:44:49 -0500336 gui_msg("verify_zip_sig=Verifying zip signature...");
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500337#ifdef USE_OLD_VERIFIER
Ethan Yonkerf96087e2014-11-07 10:38:51 -0600338 ret_val = verify_file(map.addr, map.length);
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500339#else
340 std::vector<Certificate> loadedKeys;
341 if (!load_keys("/res/keys", loadedKeys)) {
342 LOGINFO("Failed to load keys");
343 gui_err("verify_zip_fail=Zip signature verification failed!");
344 return -1;
345 }
346 ret_val = verify_file(map.addr, map.length, loadedKeys, std::bind(&DataManager::SetProgress, std::placeholders::_1));
347#endif
Dees_Troy2673cec2013-04-02 20:22:16 +0000348 if (ret_val != VERIFY_SUCCESS) {
Ethan Yonker74db1572015-10-28 12:44:49 -0500349 LOGINFO("Zip signature verification failed: %i\n", ret_val);
350 gui_err("verify_zip_fail=Zip signature verification failed!");
Ethan Yonkerf9796a42014-11-08 07:28:03 -0600351 sysReleaseMap(&map);
Dees_Troy32c8eb82012-09-11 15:28:06 -0400352 return -1;
Ethan Yonker738be7a2014-12-10 11:40:43 -0600353 } else {
Ethan Yonker74db1572015-10-28 12:44:49 -0500354 gui_msg("verify_zip_done=Zip signature verified successfully.");
Dees_Troy32c8eb82012-09-11 15:28:06 -0400355 }
356 }
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500357 ZipWrap Zip;
358 if (!Zip.Open(path, &map)) {
Ethan Yonker74db1572015-10-28 12:44:49 -0500359 gui_err("zip_corrupt=Zip file is corrupt!");
Ethan Yonkerf9796a42014-11-08 07:28:03 -0600360 sysReleaseMap(&map);
Dees_Troy2673cec2013-04-02 20:22:16 +0000361 return INSTALL_CORRUPT;
362 }
Ethan Yonker941a8992016-12-05 09:04:30 -0600363
Ethan Yonker072c8d82016-08-26 22:22:24 -0500364 time_t start, stop;
365 time(&start);
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500366 if (Zip.EntryExists(ASSUMED_UPDATE_BINARY_NAME)) {
Ethan Yonker941a8992016-12-05 09:04:30 -0600367 LOGINFO("Update binary zip\n");
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500368 // Additionally verify the compatibility of the package.
369 if (!verify_package_compatibility(&Zip)) {
370 gui_err("zip_compatible_err=Zip Treble compatibility error!");
371 sysReleaseMap(&map);
372 Zip.Close();
373 ret_val = INSTALL_CORRUPT;
374 } else {
375 ret_val = Prepare_Update_Binary(path, &Zip, wipe_cache);
376 if (ret_val == INSTALL_SUCCESS)
377 ret_val = Run_Update_Binary(path, &Zip, wipe_cache, UPDATE_BINARY_ZIP_TYPE);
378 }
Ethan Yonker941a8992016-12-05 09:04:30 -0600379 } else {
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500380 if (Zip.EntryExists(AB_OTA)) {
Ethan Yonker941a8992016-12-05 09:04:30 -0600381 LOGINFO("AB zip\n");
382 ret_val = Run_Update_Binary(path, &Zip, wipe_cache, AB_OTA_ZIP_TYPE);
383 } else {
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500384 if (Zip.EntryExists("ui.xml")) {
Ethan Yonker941a8992016-12-05 09:04:30 -0600385 LOGINFO("TWRP theme zip\n");
386 ret_val = Install_Theme(path, &Zip);
387 } else {
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500388 Zip.Close();
Ethan Yonker941a8992016-12-05 09:04:30 -0600389 ret_val = INSTALL_CORRUPT;
390 }
391 }
392 }
Ethan Yonker072c8d82016-08-26 22:22:24 -0500393 time(&stop);
394 int total_time = (int) difftime(stop, start);
Ethan Yonker20eb0bc2016-03-22 14:23:28 -0500395 if (ret_val == INSTALL_CORRUPT) {
Ethan Yonker941a8992016-12-05 09:04:30 -0600396 gui_err("invalid_zip_format=Invalid zip file format!");
Ethan Yonker072c8d82016-08-26 22:22:24 -0500397 } else {
398 LOGINFO("Install took %i second(s).\n", total_time);
Ethan Yonker20eb0bc2016-03-22 14:23:28 -0500399 }
Ethan Yonkerf9796a42014-11-08 07:28:03 -0600400 sysReleaseMap(&map);
401 return ret_val;
Dees_Troy32c8eb82012-09-11 15:28:06 -0400402}