diff options
author | Nikias Bassen | 2023-11-02 12:54:47 +0100 |
---|---|---|
committer | Nikias Bassen | 2023-11-02 12:54:47 +0100 |
commit | c871c591e36d2a4083e3dda4c70144a0321ce70f (patch) | |
tree | ce6a990c037c78a84a5d2f99038a7e98e1425bf6 /src/idevicerestore.c | |
parent | 4072cd965eab44993700b980d8848b46ec3be72e (diff) | |
download | idevicerestore-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.c | 75 |
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); } |