summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asr.c18
-rw-r--r--src/common.c17
-rw-r--r--src/common.h4
-rw-r--r--src/idevicerestore.c75
-rw-r--r--src/ipsw.c20
-rw-r--r--src/ipsw.h3
-rw-r--r--src/restore.c17
7 files changed, 143 insertions, 11 deletions
diff --git a/src/asr.c b/src/asr.c
index b2aeaf5..304e8a3 100644
--- a/src/asr.c
+++ b/src/asr.c
@@ -216,9 +216,7 @@ int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file)
plist_t payload_info = NULL;
int attempts = 0;
- ipsw_file_seek(file, 0, SEEK_END);
- length = ipsw_file_tell(file);
- ipsw_file_seek(file, 0, SEEK_SET);
+ length = ipsw_file_size(file);
payload_info = plist_new_dict();
plist_dict_set_item(payload_info, "Port", plist_new_uint(1));
@@ -313,9 +311,14 @@ int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, ipsw_file_hand
return -1;
}
- ipsw_file_seek(file, oob_offset, SEEK_SET);
- if (ipsw_file_read(file, oob_data, oob_length) != oob_length) {
- error("ERROR: Unable to read OOB data from filesystem offset: %s\n", strerror(errno));
+ if (ipsw_file_seek(file, oob_offset, SEEK_SET) < 0) {
+ error("ERROR: Unable to seek to OOB offset 0x%" PRIx64 "\n", oob_offset);
+ free(oob_data);
+ return -1;
+ }
+ int64_t ir = ipsw_file_read(file, oob_data, oob_length);
+ if (ir != oob_length) {
+ error("ERROR: Unable to read OOB data from filesystem offset 0x%" PRIx64 ", oob_length %" PRIu64 ", read returned %" PRIi64"\n", oob_offset, oob_length, ir);
free(oob_data);
return -1;
}
@@ -335,8 +338,7 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file)
uint64_t i, length, bytes = 0;
double progress = 0;
- ipsw_file_seek(file, 0, SEEK_END);
- length = ipsw_file_tell(file);
+ length = ipsw_file_size(file);
ipsw_file_seek(file, 0, SEEK_SET);
data = (char*)malloc(ASR_PAYLOAD_CHUNK_SIZE + 20);
diff --git a/src/common.c b/src/common.c
index 068f2dd..0ad775c 100644
--- a/src/common.c
+++ b/src/common.c
@@ -695,3 +695,20 @@ int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *
plist_dict_set_item(target_dict, key, plist_copy(node));
return 0;
}
+
+char* path_get_basename(char* path)
+{
+#ifdef WIN32
+ char *p = path + strlen(path);
+ while (p > path) {
+ if ((*p == '/') || (*p == '\\')) {
+ return p+1;
+ }
+ p--;
+ }
+ return p;
+#else
+ char *p = strrchr(path, '/');
+ return p ? p + 1 : path;
+#endif
+}
diff --git a/src/common.h b/src/common.h
index 6708943..c2a96b0 100644
--- a/src/common.h
+++ b/src/common.h
@@ -128,6 +128,8 @@ struct idevicerestore_client_t {
int ignore_device_add_events;
plist_t macos_variant;
char* restore_variant;
+ char* filesystem;
+ int delete_fs;
};
extern struct idevicerestore_mode_t idevicerestore_modes[];
@@ -193,6 +195,8 @@ int _plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char *
int _plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key);
+char* path_get_basename(char* path);
+
#ifdef __cplusplus
}
#endif
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);
}
diff --git a/src/ipsw.c b/src/ipsw.c
index 58d817c..5b1d732 100644
--- a/src/ipsw.c
+++ b/src/ipsw.c
@@ -1308,7 +1308,8 @@ ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path)
{
ipsw_file_handle_t handle = (ipsw_file_handle_t)calloc(1, sizeof(struct ipsw_file_handle));
if (ipsw->zip) {
- int zindex = zip_name_locate(ipsw->zip, path, 0);
+ zip_stat_t zst;
+ zip_int64_t zindex = zip_name_locate(ipsw->zip, path, 0);
if (zindex < 0) {
error("ERROR: zip_name_locate: %s not found\n", path);
free(handle);
@@ -1320,8 +1321,12 @@ ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path)
free(handle);
return NULL;
}
-
+ zip_stat_init(&zst);
+ zip_stat(ipsw->zip, path, 0, &zst);
+ handle->size = zst.size;
+ handle->seekable = (zst.comp_method == ZIP_CM_STORE);
} else {
+ struct stat st;
char *filepath = build_path(ipsw->path, path);
handle->file = fopen(filepath, "rb");
free(filepath);
@@ -1330,6 +1335,9 @@ ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path)
free(handle);
return NULL;
}
+ fstat(fileno(handle->file), &st);
+ handle->size = st.st_size;
+ handle->seekable = 1;
}
return handle;
}
@@ -1344,6 +1352,14 @@ void ipsw_file_close(ipsw_file_handle_t handle)
free(handle);
}
+uint64_t ipsw_file_size(ipsw_file_handle_t handle)
+{
+ if (handle) {
+ return handle->size;
+ }
+ return 0;
+}
+
int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size)
{
if (handle && handle->zfile) {
diff --git a/src/ipsw.h b/src/ipsw.h
index 96bcb62..56faf94 100644
--- a/src/ipsw.h
+++ b/src/ipsw.h
@@ -49,12 +49,15 @@ typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size);
struct ipsw_file_handle {
FILE* file;
struct zip_file* zfile;
+ uint64_t size;
+ int seekable;
};
typedef struct ipsw_file_handle* ipsw_file_handle_t;
ipsw_file_handle_t ipsw_file_open(ipsw_archive_t, const char* path);
void ipsw_file_close(ipsw_file_handle_t handle);
+uint64_t ipsw_file_size(ipsw_file_handle_t handle);
int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size);
int ipsw_file_seek(ipsw_file_handle_t handle, int64_t offset, int whence);
int64_t ipsw_file_tell(ipsw_file_handle_t handle);
diff --git a/src/restore.c b/src/restore.c
index 8063f08..9e0268a 100644
--- a/src/restore.c
+++ b/src/restore.c
@@ -29,6 +29,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <libgen.h>
#include <libimobiledevice/restore.h>
#ifdef HAVE_REVERSE_PROXY
#include <libimobiledevice/reverse_proxy.h>
@@ -903,13 +904,23 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de
info("About to send filesystem...\n");
+ ipsw_archive_t ipsw_dummy = NULL;
ipsw_file_handle_t file = NULL;
char* fsname = NULL;
if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) {
error("ERROR: Unable to get path for filesystem component\n");
return -1;
}
- file = ipsw_file_open(client->ipsw, fsname);
+ if (client->filesystem) {
+ char* path = strdup(client->filesystem);
+ char* fsname_base = path_get_basename(path);
+ char* parent_dir = dirname(path);
+ ipsw_dummy = ipsw_open(parent_dir);
+ free(path);
+ file = ipsw_file_open(ipsw_dummy, fsname_base);
+ } else {
+ file = ipsw_file_open(client->ipsw, fsname);
+ }
if (!file) {
error("ERROR: Unable to open '%s' in ipsw\n", fsname);
free(fsname);
@@ -917,6 +928,7 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de
if (asr_open_with_timeout(device, &asr) < 0) {
ipsw_file_close(file);
+ ipsw_close(ipsw_dummy);
error("ERROR: Unable to connect to ASR\n");
return -1;
}
@@ -929,6 +941,7 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de
info("Validating the filesystem\n");
if (asr_perform_validation(asr, file) < 0) {
ipsw_file_close(file);
+ ipsw_close(ipsw_dummy);
error("ERROR: ASR was unable to validate the filesystem\n");
asr_free(asr);
return -1;
@@ -940,11 +953,13 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de
info("Sending filesystem now...\n");
if (asr_send_payload(asr, file) < 0) {
ipsw_file_close(file);
+ ipsw_close(ipsw_dummy);
error("ERROR: Unable to send payload to ASR\n");
asr_free(asr);
return -1;
}
ipsw_file_close(file);
+ ipsw_close(ipsw_dummy);
info("Done sending filesystem\n");