diff options
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); } |