summaryrefslogtreecommitdiffstats
path: root/src/idevicerestore.c
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2023-11-02 12:54:47 +0100
committerGravatar Nikias Bassen2023-11-02 12:54:47 +0100
commitc871c591e36d2a4083e3dda4c70144a0321ce70f (patch)
treece6a990c037c78a84a5d2f99038a7e98e1425bf6 /src/idevicerestore.c
parent4072cd965eab44993700b980d8848b46ec3be72e (diff)
downloadidevicerestore-c871c591e36d2a4083e3dda4c70144a0321ce70f.tar.gz
idevicerestore-c871c591e36d2a4083e3dda4c70144a0321ce70f.tar.bz2
Extract OS component when using older ipsw archives
Older ipsw archives have the root filesystem stored in compressed format rather than just "stored". The "Verifying Filesystem" step would then fail as compressed files are not seekable in ZIP files. This commit introduces a detection for this and has the filesystem extracted should it be required. If not using a cache path, the temp file used for extraction will be deleted after the procedure is completed.
Diffstat (limited to 'src/idevicerestore.c')
-rw-r--r--src/idevicerestore.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index 56207a0..dc7750b 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -45,6 +45,8 @@
#define SHA384 sha384
#endif
+#include <libimobiledevice-glue/utils.h>
+
#include "dfu.h"
#include "tss.h"
#include "img3.h"
@@ -950,6 +952,73 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
info("All required components found in IPSW\n");
+ /* Get OS (filesystem) name from build identity */
+ char* os_path = NULL;
+ if (build_identity_get_component_path(build_identity, "OS", &os_path) < 0) {
+ error("ERROR: Unable to get path for filesystem component\n");
+ return -1;
+ }
+
+ /* check if IPSW has OS component 'stored' in ZIP archive, otherwise we need to extract it */
+ int needs_os_extraction = 0;
+ if (client->ipsw->zip) {
+ ipsw_file_handle_t zfile = ipsw_file_open(client->ipsw, os_path);
+ if (zfile) {
+ if (!zfile->seekable) {
+ needs_os_extraction = 1;
+ }
+ ipsw_file_close(zfile);
+ }
+ }
+
+ if (needs_os_extraction && !(client->flags & FLAG_SHSHONLY)) {
+ char* tmpf = NULL;
+ struct stat st;
+ if (client->cache_dir) {
+ memset(&st, '\0', sizeof(struct stat));
+ if (stat(client->cache_dir, &st) < 0) {
+ mkdir_with_parents(client->cache_dir, 0755);
+ }
+ char* ipsw_basename = path_get_basename(client->ipsw->path);
+ ipsw_basename = strdup(ipsw_basename);
+ char* p = strrchr(ipsw_basename, '.');
+ if (p && isalpha(*(p+1))) {
+ *p = '\0';
+ }
+ tmpf = string_build_path(client->cache_dir, ipsw_basename, NULL);
+ mkdir_with_parents(tmpf, 0755);
+ free(tmpf);
+ tmpf = string_build_path(client->cache_dir, ipsw_basename, os_path, NULL);
+ free(ipsw_basename);
+ } else {
+ tmpf = get_temp_filename(NULL);
+ client->delete_fs = 1;
+ }
+
+ /* check if we already have it extracted */
+ uint64_t fssize = 0;
+ ipsw_get_file_size(client->ipsw, os_path, &fssize);
+ memset(&st, '\0', sizeof(struct stat));
+ if (stat(tmpf, &st) == 0) {
+ if ((fssize > 0) && ((uint64_t)st.st_size == fssize)) {
+ info("Using cached filesystem from '%s'\n", tmpf);
+ client->filesystem = tmpf;
+ }
+ }
+
+ if (!client->filesystem) {
+ info("Extracting filesystem from IPSW: %s\n", os_path);
+ if (ipsw_extract_to_file_with_progress(client->ipsw, os_path, tmpf, 1) < 0) {
+ error("ERROR: Unable to extract filesystem from IPSW\n");
+ info("Removing %s\n", tmpf);
+ unlink(tmpf);
+ free(tmpf);
+ return -1;
+ }
+ client->filesystem = tmpf;
+ }
+ }
+
idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.2);
/* retrieve shsh blobs if required */
@@ -1338,6 +1407,12 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client)
if (client->ipsw) {
ipsw_close(client->ipsw);
}
+ if (client->filesystem) {
+ if (client->delete_fs) {
+ unlink(client->filesystem);
+ }
+ free(client->filesystem);
+ }
if (client->version) {
free(client->version);
}