summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Joshua Hill2010-06-08 04:14:29 -0400
committerGravatar Joshua Hill2010-06-08 04:14:29 -0400
commit51b56ba5bf01af40835a43ad1104a7eff3160127 (patch)
tree0a7749bb4ffa8b67f3728d13f4881fbbc7c7313c /src
parent5346ce8f7cefe7b33dd8abc44e27cb0e0816f78b (diff)
downloadidevicerestore-51b56ba5bf01af40835a43ad1104a7eff3160127.tar.gz
idevicerestore-51b56ba5bf01af40835a43ad1104a7eff3160127.tar.bz2
Added a new asr.c file to stick all stuff related to filesystem and abstract the restore process to allow for easier porting
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/asr.c275
-rw-r--r--src/asr.h35
-rw-r--r--src/idevicerestore.c62
-rw-r--r--src/idevicerestore.h29
-rw-r--r--src/ipsw.c2
-rw-r--r--src/restore.c464
-rw-r--r--src/restore.h2
8 files changed, 587 insertions, 284 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index b641d00..a44640f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,6 +18,6 @@ AM_LDFLAGS =\
bin_PROGRAMS = idevicerestore
-idevicerestore_SOURCES = idevicerestore.c dfu.c tss.c img3.c ipsw.c normal.c restore.c recovery.c activate.c
+idevicerestore_SOURCES = idevicerestore.c dfu.c asr.c tss.c img3.c ipsw.c normal.c restore.c recovery.c activate.c
idevicerestore_CFLAGS = $(AM_CFLAGS)
idevicerestore_LDFLAGS = $(AM_LDFLAGS) \ No newline at end of file
diff --git a/src/asr.c b/src/asr.c
new file mode 100644
index 0000000..658f03f
--- /dev/null
+++ b/src/asr.c
@@ -0,0 +1,275 @@
+/*
+ * dfu.h
+ * Functions for handling idevices in normal mode
+ *
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libimobiledevice/libimobiledevice.h>
+
+#include "asr.h"
+#include "idevicerestore.h"
+
+#define ASR_PORT 12345
+#define ASR_BUFFER_SIZE 65536
+
+int asr_open_with_timeout(idevice_t device, idevice_connection_t* asr) {
+ int i = 0;
+ int attempts = 10;
+ idevice_connection_t connection = NULL;
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
+
+ *asr = NULL;
+
+ if (device == NULL) {
+ return -1;
+ }
+
+ debug("Connecting to ASR\n");
+ for (i = 1; i <= attempts; i++) {
+ device_error = idevice_connect(device, ASR_PORT, &connection);
+ if (device_error == IDEVICE_E_SUCCESS) {
+ break;
+ }
+
+ if (i >= attempts) {
+ error("ERROR: Unable to connect to ASR client\n");
+ return -1;
+ }
+
+ sleep(2);
+ debug("Retrying connection...\n");
+ }
+
+ *asr = connection;
+ return 0;
+}
+
+int asr_receive(idevice_connection_t asr, plist_t* data) {
+ uint32_t size = 0;
+ char* buffer = NULL;
+ plist_t request = NULL;
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
+
+ *data = NULL;
+
+ buffer = (char*) malloc(ASR_BUFFER_SIZE);
+ if (buffer == NULL) {
+ error("ERROR: Unable to allocate memory for ASR receive buffer\n");
+ return -1;
+ }
+ memset(buffer, '\0', ASR_BUFFER_SIZE);
+
+ device_error = idevice_connection_receive(asr, buffer, ASR_BUFFER_SIZE, &size);
+ if (device_error != IDEVICE_E_SUCCESS) {
+ error("ERROR: Unable to receive data from ASR\n");
+ free(buffer);
+ return -1;
+ }
+ plist_from_xml(buffer, size, &request);
+
+ *data = request;
+
+ debug("Received %d bytes:\n%s\n", size, buffer);
+ free(buffer);
+ return 0;
+}
+
+int asr_send(idevice_connection_t asr, plist_t* data) {
+ uint32_t size = 0;
+ char* buffer = NULL;
+
+ plist_to_xml(data, &buffer, &size);
+ if (asr_send_buffer(asr, buffer, size) < 0) {
+ error("ERROR: Unable to send plist to ASR\n");
+ free(buffer);
+ return -1;
+ }
+
+ free(buffer);
+ return 0;
+}
+
+int asr_send_buffer(idevice_connection_t asr, const char* data, uint32_t size) {
+ uint32_t bytes = 0;
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
+
+ device_error = idevice_connection_send(asr, data, size, &bytes);
+ if (device_error != IDEVICE_E_SUCCESS || bytes != size) {
+ error("ERROR: Unable to send data to ASR\n");
+ return -1;
+ }
+
+ debug("Sent %d bytes:\n%s", bytes, data);
+ return 0;
+}
+
+void asr_close(idevice_connection_t asr) {
+ if (asr != NULL) {
+ idevice_disconnect(asr);
+ asr = NULL;
+ }
+}
+
+int asr_perform_validation(idevice_connection_t asr, const char* filesystem) {
+ FILE* file = NULL;
+ uint64_t length = 0;
+ char* command = NULL;
+ plist_t node = NULL;
+ plist_t packet = NULL;
+ plist_t packet_info = NULL;
+ plist_t payload_info = NULL;
+
+ file = fopen(filesystem, "rb");
+ if (file == NULL) {
+ return -1;
+ }
+
+ fseek(file, 0, SEEK_END);
+ length = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ payload_info = plist_new_dict();
+ plist_dict_insert_item(payload_info, "Port", plist_new_uint(1));
+ plist_dict_insert_item(payload_info, "Size", plist_new_uint(length));
+
+ packet_info = plist_new_dict();
+ plist_dict_insert_item(packet_info, "FEC Slice Stride", plist_new_uint(40));
+ plist_dict_insert_item(packet_info, "Packet Payload Size", plist_new_uint(1450));
+ plist_dict_insert_item(packet_info, "Packets Per FEC", plist_new_uint(25));
+ plist_dict_insert_item(packet_info, "Payload", payload_info);
+ plist_dict_insert_item(packet_info, "Stream ID", plist_new_uint(1));
+ plist_dict_insert_item(packet_info, "Version", plist_new_uint(1));
+
+ if (asr_send(asr, packet_info)) {
+ error("ERROR: Unable to sent packet information to ASR\n");
+ plist_free(packet_info);
+ return -1;
+ }
+ plist_free(packet_info);
+
+ char* oob_data = NULL;
+ uint64_t oob_offset = 0;
+ uint64_t oob_length = 0;
+ plist_t oob_length_node = NULL;
+ plist_t oob_offset_node = NULL;
+ do {
+ if (asr_receive(asr, &packet) < 0) {
+ error("ERROR: Unable to receive validation packet\n");
+ return -1;
+ }
+
+ node = plist_dict_get_item(packet, "Command");
+ if (!node || plist_get_node_type(node) != PLIST_STRING) {
+ error("ERROR: Unable to find command node in validation request\n");
+ return -1;
+ }
+ plist_get_string_val(node, &command);
+
+ if (!strcmp(command, "OOBData")) {
+ oob_length_node = plist_dict_get_item(packet, "OOB Length");
+ if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) {
+ error("ERROR: Unable to find OOB data length\n");
+ return -1;
+ }
+ plist_get_uint_val(oob_length_node, &oob_length);
+
+ oob_offset_node = plist_dict_get_item(packet, "OOB Offset");
+ if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) {
+ error("ERROR: Unable to find OOB data offset\n");
+ return -1;
+ }
+ plist_get_uint_val(oob_offset_node, &oob_offset);
+
+ oob_data = (char*) malloc(oob_length);
+ if (oob_data == NULL) {
+ error("ERROR: Out of memory\n");
+ plist_free(packet);
+ return -1;
+ }
+
+ fseek(file, oob_offset, SEEK_SET);
+ if (fread(oob_data, 1, oob_length, file) != oob_length) {
+ error("ERROR: Unable to read OOB data from filesystem offset\n");
+ plist_free(packet);
+ free(oob_data);
+ return -1;
+ }
+
+ if (asr_send_buffer(asr, oob_data, oob_length) < 0) {
+ error("ERROR: Unable to send OOB data to ASR\n");
+ plist_free(packet);
+ free(oob_data);
+ return -1;
+ }
+
+ plist_free(packet);
+ free(oob_data);
+
+ }
+
+ } while (strcmp(packet, "Payload"));
+}
+
+int asr_send_payload(idevice_connection_t asr, const char* filesystem) {
+ int i = 0;
+ char data[1450];
+ FILE* file = NULL;
+ uint32_t bytes = 0;
+ uint32_t count = 0;
+ uint32_t length = 0;
+ double progress = 0;
+
+ file = fopen(filesystem, "rb");
+ if (file == NULL) {
+ return -1;
+ }
+
+ fseek(file, 0, SEEK_END);
+ length = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ for(i = length; i > 0; i -= 1450) {
+ int size = 1450;
+ if (i < 1450) {
+ size = i;
+ }
+
+ if (fread(data, 1, size, file) != (unsigned int) size) {
+ error("Error reading filesystem\n");
+ fclose(file);
+ return -1;
+ }
+
+ if (asr_send_buffer(asr, data, size) < 0) {
+ error("ERROR: Unable to send filesystem payload\n");
+ fclose(file);
+ return -1;
+ }
+
+ bytes += size;
+ progress = ((double) bytes/ (double) length) * 100.0;
+ print_progress_bar("Extracting", progress);
+
+ }
+
+ fclose(file);
+ return 0;
+}
diff --git a/src/asr.h b/src/asr.h
new file mode 100644
index 0000000..151c1d0
--- /dev/null
+++ b/src/asr.h
@@ -0,0 +1,35 @@
+/*
+ * dfu.h
+ * Functions for handling idevices in normal mode
+ *
+ * Copyright (c) 2010 Joshua Hill. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef IDEVICERESTORE_ASR_H
+#define IDEVICERESTORE_ASR_H
+
+#include <libimobiledevice/libimobiledevice.h>
+
+int asr_open_with_timeout(idevice_t device, idevice_connection_t* asr);
+int asr_send(idevice_connection_t asr, plist_t* data);
+int asr_receive(idevice_connection_t asr, plist_t* data);
+int asr_send_buffer(idevice_connection_t asr, const char* data, uint32_t size);
+void asr_close(idevice_connection_t asr);
+int asr_perform_validation(idevice_connection_t asr, const char* filesystem);
+int asr_send_payload(idevice_connection_t asr, const char* filesystem);
+
+#endif
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index cc97e2c..69363fb 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -602,23 +602,28 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char**
uint32_t component_size = 0;
char* component_data = NULL;
char* component_blob = NULL;
+ char* component_name = NULL;
- info("Extracting %s from %s\n", path, ipsw);
+ component_name = strrchr(path, '/');
+ if (component_name != NULL) component_name++;
+ else component_name = (char*) path;
+
+ info("Extracting %s\n", component_name);
if (ipsw_extract_to_memory(ipsw, path, &component_data, &component_size) < 0) {
- error("ERROR: Unable to extract %s from %s\n", path, ipsw);
+ error("ERROR: Unable to extract %s from %s\n", component_name, ipsw);
return -1;
}
img3 = img3_parse_file(component_data, component_size);
if (img3 == NULL) {
- error("ERROR: Unable to parse IMG3: %s\n", path);
+ error("ERROR: Unable to parse IMG3: %s\n", component_name);
free(component_data);
return -1;
}
free(component_data);
if (tss_get_blob_by_path(tss, path, &component_blob) < 0) {
- error("ERROR: Unable to get SHSH blob for TSS %s entry\n", path);
+ error("ERROR: Unable to get SHSH blob for TSS %s entry\n", component_name);
img3_free(img3);
return -1;
}
@@ -641,13 +646,7 @@ int get_signed_component(const char* ipsw, plist_t tss, const char* path, char**
img3_free(img3);
if (idevicerestore_debug) {
- char* out = strrchr(path, '/');
- if (out != NULL) {
- out++;
- } else {
- out = (char*) path;
- }
- write_file(out, component_data, component_size);
+ write_file(component_name, component_data, component_size);
}
*data = component_data;
@@ -676,3 +675,44 @@ int write_file(const char* filename, const void* data, size_t size) {
return size;
}
+
+int read_file(const char* filename, char** data, uint32_t* size) {
+ size_t bytes = 0;
+ size_t length = 0;
+ FILE* file = NULL;
+ char* buffer = NULL;
+ debug("Reading data from %s\n", filename);
+
+ *size = 0;
+ *data = NULL;
+
+ file = fopen(filename, "rb");
+ if (file == NULL) {
+ error("read_file: File %s not found\n", filename);
+ return -1;
+ }
+
+ fseek(file, 0, SEEK_END);
+ length = ftell(file);
+ rewind(file);
+
+ buffer = (char*) malloc(length);
+ if(buffer == NULL) {
+ error("ERROR: Out of memory\n");
+ fclose(file);
+ return -1;
+ }
+ bytes = fread(buffer, 1, length, file);
+ fclose(file);
+
+ if(bytes != length) {
+ error("ERROR: Unable to read entire file\n");
+ free(buffer);
+ return -1;
+ }
+
+ *size = length;
+ *data = buffer;
+ return 0;
+}
+
diff --git a/src/idevicerestore.h b/src/idevicerestore.h
index e4186c9..20578a9 100644
--- a/src/idevicerestore.h
+++ b/src/idevicerestore.h
@@ -63,6 +63,16 @@
#define DEVICE_IPOD3G 5
#define DEVICE_IPAD1G 6
+typedef struct idevicerestore_entry {
+ char* name;
+ char* path;
+ char* filename;
+ char* blob_data;
+ uint32_t blob_size;
+ struct idevicerestore_entry* next;
+ struct idevicerestore_entry* prev;
+} idevicerestore_entry_t;
+
typedef struct {
int device_id;
const char* product;
@@ -70,7 +80,21 @@ typedef struct {
int board_id;
int chip_id;
} idevicerestore_device_t;
-
+/*
+typedef struct {
+ int mode;
+ idevice_t device;
+ irecv_client_t recovery;
+ restored_client_t restore;
+ lockdownd_client_t lockdown;
+ int erase; // 1
+ int custom; // 2
+ int exclude; // 4
+ int verbose; // 8
+ idevicerestore_device_t* idevicerestore_device;
+ idevicerestore_entry_t** entries;
+} idevicerestore_context_t;
+*/
static idevicerestore_device_t idevicerestore_devices[] = {
{ 0, "iPhone1,1", "M68AP", 0, 8900 },
{ 1, "iPod1,1", "N45AP", 2, 8900 },
@@ -79,6 +103,7 @@ static idevicerestore_device_t idevicerestore_devices[] = {
{ 4, "iPhone2,1", "N88AP", 0, 8920 },
{ 5, "iPod3,1", "N18AP", 2, 8922 },
{ 6, "iPad1,1", "K48AP", 2, 8930 },
+ { 6, "iPhone4,1", "XXXAP", 0, 0 },
{ -1, NULL, NULL, -1, -1 }
};
@@ -90,6 +115,7 @@ extern int idevicerestore_custom;
extern int idevicerestore_exclude;
extern int idevicerestore_verbose;
extern idevicerestore_device_t* idevicerestore_device;
+extern idevicerestore_entry_t** idevicerestore_entries;
int check_mode(const char* uuid);
int check_device(const char* uuid);
@@ -100,6 +126,7 @@ int get_cpid(const char* uuid, uint32_t* cpid);
int extract_buildmanifest(const char* ipsw, plist_t* buildmanifest);
plist_t get_build_identity(plist_t buildmanifest, uint32_t identity);
int write_file(const char* filename, const void* data, size_t size);
+int read_file(const char* filename, char** data, uint32_t* size);
int get_shsh_blobs(uint64_t ecid, plist_t build_identity, plist_t* tss);
int extract_filesystem(const char* ipsw, plist_t buildmanifest, char** filesystem);
int get_signed_component(const char* ipsw, plist_t tss, const char* path, char** data, uint32_t* size);
diff --git a/src/ipsw.c b/src/ipsw.c
index 7ded33e..adbaea0 100644
--- a/src/ipsw.c
+++ b/src/ipsw.c
@@ -98,7 +98,7 @@ int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfi
int bytes = 0;
int count = 0;
double progress = 0;
- for (i = zstat.size; i > 0; i -= count) {
+ for(i = zstat.size; i > 0; i -= count) {
if (i < BUFSIZE)
size = i;
else
diff --git a/src/restore.c b/src/restore.c
index b5eea66..fc22b75 100644
--- a/src/restore.c
+++ b/src/restore.c
@@ -24,12 +24,11 @@
#include <string.h>
#include <libimobiledevice/restore.h>
+#include "asr.h"
#include "tss.h"
#include "restore.h"
#include "idevicerestore.h"
-#define ASR_PORT 12345
-
#define CREATE_PARTITION_MAP 12
#define CREATE_FILESYSTEM 13
#define RESTORE_IMAGE 14
@@ -110,7 +109,7 @@ int restore_check_device(const char* uuid) {
}
restore_error = restored_get_value(restore, "HardwareModel", &node);
- if(restore_error != RESTORE_E_SUCCESS) {
+ if (restore_error != RESTORE_E_SUCCESS) {
error("ERROR: Unable to get HardwareModel from restored\n");
restored_client_free(restore);
idevice_free(device);
@@ -124,13 +123,14 @@ int restore_check_device(const char* uuid) {
if (!node || plist_get_node_type(node) != PLIST_STRING) {
error("ERROR: Unable to get HardwareModel information\n");
- if(node) plist_free(node);
+ if (node)
+ plist_free(node);
return -1;
}
plist_get_string_val(node, &model);
- for(i = 0; idevicerestore_devices[i].model != NULL; i++) {
- if(!strcasecmp(model, idevicerestore_devices[i].model)) {
+ for (i = 0; idevicerestore_devices[i].model != NULL; i++) {
+ if (!strcasecmp(model, idevicerestore_devices[i].model)) {
break;
}
}
@@ -147,11 +147,31 @@ void restore_device_callback(const idevice_event_t* event, void* user_data) {
}
}
+int restore_reboot(const char* uuid) {
+ idevice_t device = NULL;
+ restored_client_t restore = NULL;
+ restored_error_t restore_error = RESTORE_E_SUCCESS;
+ if (restore_open_with_timeout(uuid, &device, &restore) < 0) {
+ error("ERROR: Unable to open device in restore mode\n");
+ return -1;
+ }
+
+ restore_error = restored_reboot(restore);
+ if (restore_error != RESTORE_E_SUCCESS) {
+ error("ERROR: Unable to reboot the device from restore mode\n");
+ restore_close(device, restore);
+ return -1;
+ }
+
+ restore_close(device, restore);
+ restore = NULL;
+ device = NULL;
+ return 0;
+}
+
int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_client_t* restore) {
int i = 0;
- int attempt = 10;
- char* type = NULL;
- uint64_t version = 0;
+ int attempts = 10;
idevice_t context = NULL;
restored_client_t client = NULL;
idevice_error_t device_error = IDEVICE_E_SUCCESS;
@@ -166,12 +186,12 @@ int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_clie
return -1;
}
- for (i = 1; i <= attempt; i++) {
+ for (i = 1; i <= attempts; i++) {
if (restore_device_connected == 1) {
break;
}
- if (i == attempt) {
+ if (i == attempts) {
error("ERROR: Unable to connect to device in restore mode\n");
}
@@ -190,7 +210,7 @@ int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_clie
return -1;
}
- restore_error = restored_query_type(client, &type, &version);
+ restore_error = restored_query_type(client, NULL, NULL);
if (restore_error != RESTORE_E_SUCCESS) {
restored_client_free(client);
idevice_event_unsubscribe();
@@ -208,7 +228,6 @@ void restore_close(idevice_t device, restored_client_t restore) {
restored_client_free(restore);
if (device)
idevice_free(device);
- //idevice_event_unsubscribe();
}
const char* restore_progress_string(unsigned int operation) {
@@ -262,202 +281,83 @@ const char* restore_progress_string(unsigned int operation) {
int restore_handle_progress_msg(restored_client_t client, plist_t msg) {
plist_t node = NULL;
- uint64_t operation = 0;
- uint64_t uprogress = 0;
uint64_t progress = 0;
+ uint64_t operation = 0;
node = plist_dict_get_item(msg, "Operation");
- if (node && PLIST_UINT == plist_get_node_type(node)) {
- plist_get_uint_val(node, &operation);
- } else {
+ if (!node || plist_get_node_type(node) != PLIST_UINT) {
debug("Failed to parse operation from ProgressMsg plist\n");
- return 0;
+ return -1;
}
+ plist_get_uint_val(node, &operation);
node = plist_dict_get_item(msg, "Progress");
- if (node && PLIST_UINT == plist_get_node_type(node)) {
- plist_get_uint_val(node, &uprogress);
- progress = uprogress;
- } else {
+ if (!node || plist_get_node_type(node) != PLIST_UINT) {
debug("Failed to parse progress from ProgressMsg plist \n");
- return 0;
+ return -1;
}
+ plist_get_uint_val(node, &progress);
+
+ if ((progress > 0) && (progress < 100)) {
+ print_progress_bar(restore_progress_string(operation), (double) progress);
- if ((progress > 0) && (progress < 100))
- info("%s - Progress: %llu%%\n", restore_progress_string(operation), progress);
- else
+ } else {
info("%s\n", restore_progress_string(operation));
+ }
return 0;
}
int restore_handle_status_msg(restored_client_t client, plist_t msg) {
info("Got status message\n");
+ debug_plist(msg);
return 0;
}
-int restore_send_filesystem(idevice_t device, restored_client_t client, const char* filesystem) {
+int restore_send_filesystem(idevice_t device, const char* filesystem) {
int i = 0;
- char buffer[0x1000];
- uint32_t recv_bytes = 0;
- memset(buffer, '\0', 0x1000);
- idevice_connection_t connection = NULL;
- idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
-
- for (i = 0; i < 5; i++) {
- ret = idevice_connect(device, ASR_PORT, &connection);
- if (ret == IDEVICE_E_SUCCESS)
- break;
+ FILE* file = NULL;
+ plist_t data = NULL;
+ idevice_connection_t asr = NULL;
+ idevice_error_t device_error = IDEVICE_E_UNKNOWN_ERROR;
- else
- sleep(1);
- }
-
- if (ret != IDEVICE_E_SUCCESS)
- return ret;
-
- memset(buffer, '\0', 0x1000);
- ret = idevice_connection_receive(connection, buffer, 0x1000, &recv_bytes);
- if (ret != IDEVICE_E_SUCCESS) {
- idevice_disconnect(connection);
- return ret;
- }
- info("Received %d bytes\n", recv_bytes);
- info("%s", buffer);
-
- FILE* fd = fopen(filesystem, "rb");
- if (fd == NULL) {
- idevice_disconnect(connection);
- return ret;
+ if (asr_open_with_timeout(device, &asr) < 0) {
+ error("ERROR: Unable to connect to ASR\n");
+ return -1;
}
-
- fseek(fd, 0, SEEK_END);
- uint64_t len = ftell(fd);
- fseek(fd, 0, SEEK_SET);
-
info("Connected to ASR\n");
- plist_t dict = plist_new_dict();
- plist_dict_insert_item(dict, "FEC Slice Stride", plist_new_uint(40));
- plist_dict_insert_item(dict, "Packet Payload Size", plist_new_uint(1450));
- plist_dict_insert_item(dict, "Packets Per FEC", plist_new_uint(25));
-
- plist_t payload = plist_new_dict();
- plist_dict_insert_item(payload, "Port", plist_new_uint(1));
- plist_dict_insert_item(payload, "Size", plist_new_uint(len));
- plist_dict_insert_item(dict, "Payload", payload);
-
- plist_dict_insert_item(dict, "Stream ID", plist_new_uint(1));
- plist_dict_insert_item(dict, "Version", plist_new_uint(1));
- char* xml = NULL;
- unsigned int dict_size = 0;
- unsigned int sent_bytes = 0;
- plist_to_xml(dict, &xml, &dict_size);
-
- ret = idevice_connection_send(connection, xml, dict_size, &sent_bytes);
- if (ret != IDEVICE_E_SUCCESS) {
- idevice_disconnect(connection);
- return ret;
+ // we don't really need to do anything with this,
+ // we're just clearing the output buffer
+ if (asr_receive(asr, &data) < 0) {
+ error("ERROR: Unable to receive data from ASR\n");
+ asr_close(asr);
+ return -1;
}
+ plist_free(data);
- info("Sent %d bytes\n", sent_bytes);
- info("%s", xml);
- plist_free(dict);
- free(xml);
-
- char* command = NULL;
- do {
- memset(buffer, '\0', 0x1000);
- ret = idevice_connection_receive(connection, buffer, 0x1000, &recv_bytes);
- if (ret != IDEVICE_E_SUCCESS) {
- idevice_disconnect(connection);
- return ret;
- }
- info("Received %d bytes\n", recv_bytes);
- info("%s", buffer);
-
- plist_t request = NULL;
- plist_from_xml(buffer, recv_bytes, &request);
- plist_t command_node = plist_dict_get_item(request, "Command");
- if (command_node && PLIST_STRING == plist_get_node_type(command_node)) {
- plist_get_string_val(command_node, &command);
- if (!strcmp(command, "OOBData")) {
- plist_t oob_length_node = plist_dict_get_item(request, "OOB Length");
- if (!oob_length_node || PLIST_UINT != plist_get_node_type(oob_length_node)) {
- error("Error fetching OOB Length\n");
- idevice_disconnect(connection);
- return IDEVICE_E_UNKNOWN_ERROR;
- }
- uint64_t oob_length = 0;
- plist_get_uint_val(oob_length_node, &oob_length);
-
- plist_t oob_offset_node = plist_dict_get_item(request, "OOB Offset");
- if (!oob_offset_node || PLIST_UINT != plist_get_node_type(oob_offset_node)) {
- error("Error fetching OOB Offset\n");
- idevice_disconnect(connection);
- return IDEVICE_E_UNKNOWN_ERROR;
- }
- uint64_t oob_offset = 0;
- plist_get_uint_val(oob_offset_node, &oob_offset);
-
- char* oob_data = (char*) malloc(oob_length);
- if (oob_data == NULL) {
- error("Out of memory\n");
- idevice_disconnect(connection);
- return IDEVICE_E_UNKNOWN_ERROR;
- }
-
- fseek(fd, oob_offset, SEEK_SET);
- if (fread(oob_data, 1, oob_length, fd) != oob_length) {
- error("Unable to read filesystem offset\n");
- idevice_disconnect(connection);
- free(oob_data);
- return ret;
- }
-
- ret = idevice_connection_send(connection, oob_data, oob_length, &sent_bytes);
- if (sent_bytes != oob_length || ret != IDEVICE_E_SUCCESS) {
- error("Unable to send %d bytes to asr\n", sent_bytes);
- idevice_disconnect(connection);
- free(oob_data);
- return ret;
- }
- plist_free(request);
- free(oob_data);
- }
- }
-
- } while (strcmp(command, "Payload"));
-
- fseek(fd, 0, SEEK_SET);
- char data[1450];
- for (i = len; i > 0; i -= 1450) {
- int size = 1450;
- if (i < 1450) {
- size = i;
- }
-
- if (fread(data, 1, size, fd) != (unsigned int) size) {
- fclose(fd);
- idevice_disconnect(connection);
- error("Error reading filesystem\n");
- return IDEVICE_E_UNKNOWN_ERROR;
- }
-
- ret = idevice_connection_send(connection, data, size, &sent_bytes);
- if (ret != IDEVICE_E_SUCCESS) {
- fclose(fd);
- }
+ // this step sends requested chunks of data from various offsets to asr so
+ // it can validate the filesystem before installing it
+ debug("Preparing to validate the filesystem\n");
+ if (asr_perform_validation(asr, filesystem) < 0) {
+ error("ERROR: ASR was unable to validate the filesystem\n");
+ asr_close(asr);
+ return -1;
+ }
+ info("Filesystem validated\n");
- if (i % (1450 * 1000) == 0) {
- info(".");
- }
+ // once the target filesystem has been validated, ASR then requests the
+ // entire filesystem to be sent.
+ debug("Preparing to send filesystem\n");
+ if (asr_send_payload(asr, filesystem) < 0) {
+ error("ERROR: Unable to send payload to ASR\n");
+ asr_close(asr);
+ return -1;
}
+ info("Filesystem finished\n");
- info("Done sending filesystem\n");
- fclose(fd);
- ret = idevice_disconnect(connection);
- return ret;
+ asr_close(asr);
+ return 0;
}
int restore_send_kernelcache(restored_client_t client, char* kernel_data, int len) {
@@ -550,11 +450,7 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) {
}
plist_dict_insert_item(dict, "NorImageData", norimage_array);
- int sz = 0;
- char* xml = NULL;
- plist_to_xml(dict, &xml, &sz);
- debug("%s", xml);
- free(xml);
+ debug_plist(dict);
restored_error_t ret = restored_send(client, dict);
if (ret != RESTORE_E_SUCCESS) {
@@ -567,105 +463,135 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss) {
return 0;
}
-int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) {
- idevice_t device = NULL;
- idevice_error_t device_error = idevice_new(&device, uuid);
- if (device_error != IDEVICE_E_SUCCESS) {
- error("ERROR: Unable to open device\n");
- plist_free(tss);
- return -1;
- }
+int restore_handle_data_request_msg(idevice_t device, restored_client_t restore, plist_t message, plist_t tss, const char* ipsw, const char* filesystem) {
+ char* type = NULL;
+ plist_t node = NULL;
- restored_client_t restore = NULL;
- restored_error_t restore_error = restored_client_new(device, &restore, "idevicerestore");
- if (restore_error != RESTORE_E_SUCCESS) {
- error("ERROR: Unable to start restored client\n");
- plist_free(tss);
- idevice_free(device);
- return -1;
+ // checks and see what kind of data restored is requests and pass
+ // the request to its own handler
+ node = plist_dict_get_item(message, "DataType");
+ if (node && PLIST_STRING == plist_get_node_type(node)) {
+ plist_get_string_val(node, &type);
+
+ // this request is sent when restored is ready to receive the filesystem
+ if (!strcmp(type, "SystemImageData")) {
+ restore_send_filesystem(device, filesystem);
+
+ }
+
+ else if (!strcmp(type, "KernelCache")) {
+ int kernelcache_size = 0;
+ char* kernelcache_data = NULL;
+ char* kernelcache_path = NULL;
+ if (tss_get_entry_path(tss, "KernelCache", &kernelcache_path) < 0) {
+ error("ERROR: Unable to find kernelcache path\n");
+ return -1;
+ }
+
+ if (get_signed_component(ipsw, tss, kernelcache_path, &kernelcache_data, &kernelcache_size) < 0) {
+ error("ERROR: Unable to get kernelcache file\n");
+ return -1;
+ }
+ restore_send_kernelcache(restore, kernelcache_data, kernelcache_size);
+ free(kernelcache_data);
+
+ }
+
+ else if (!strcmp(type, "NORData")) {
+ restore_send_nor(restore, ipsw, tss);
+
+ } else {
+ // Unknown DataType!!
+ debug("Unknown data request received\n");
+ }
}
+ return 0;
+}
+int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem) {
+ int error = 0;
char* type = NULL;
- uint64_t version = 0;
- if (restored_query_type(restore, &type, &version) != RESTORE_E_SUCCESS) {
- error("ERROR: Device is not in restore mode. QueryType returned \"%s\"\n", type);
- plist_free(tss);
- restored_client_free(restore);
- idevice_free(device);
+ char* kernel = NULL;
+ plist_t node = NULL;
+ plist_t message = NULL;
+ idevice_t device = NULL;
+ restored_client_t restore = NULL;
+ idevice_error_t device_error = IDEVICE_E_SUCCESS;
+ restored_error_t restore_error = RESTORE_E_SUCCESS;
+
+ // open our connection to the device and verify we're in restore mode
+ if (restore_open_with_timeout(uuid, &device, &restore) < 0) {
+ error("ERROR: Unable to open device in restore mode\n");
return -1;
}
info("Device has successfully entered restore mode\n");
- /* start restore process */
- char* kernelcache = NULL;
- info("Restore protocol version is %llu.\n", version);
+ // start the restore process
restore_error = restored_start_restore(restore);
- if (restore_error == RESTORE_E_SUCCESS) {
- while (!idevicerestore_quit) {
- plist_t message = NULL;
- restore_error = restored_receive(restore, &message);
- plist_t msgtype_node = plist_dict_get_item(message, "MsgType");
- if (msgtype_node && PLIST_STRING == plist_get_node_type(msgtype_node)) {
- char *msgtype = NULL;
- plist_get_string_val(msgtype_node, &msgtype);
- if (!strcmp(msgtype, "ProgressMsg")) {
- restore_error = restore_handle_progress_msg(restore, message);
-
- } else if (!strcmp(msgtype, "DataRequestMsg")) {
- // device is requesting data to be sent
- plist_t datatype_node = plist_dict_get_item(message, "DataType");
- if (datatype_node && PLIST_STRING == plist_get_node_type(datatype_node)) {
- char *datatype = NULL;
- plist_get_string_val(datatype_node, &datatype);
- if (!strcmp(datatype, "SystemImageData")) {
- restore_send_filesystem(device, restore, filesystem);
-
- } else if (!strcmp(datatype, "KernelCache")) {
- int kernelcache_size = 0;
- char* kernelcache_data = NULL;
- char* kernelcache_path = NULL;
- if (tss_get_entry_path(tss, "KernelCache", &kernelcache_path) < 0) {
- error("ERROR: Unable to find kernelcache path\n");
- return -1;
- }
-
- if (get_signed_component(ipsw, tss, kernelcache_path, &kernelcache_data, &kernelcache_size) < 0) {
- error("ERROR: Unable to get kernelcache file\n");
- return -1;
- }
- restore_send_kernelcache(restore, kernelcache_data, kernelcache_size);
- free(kernelcache_data);
-
- } else if (!strcmp(datatype, "NORData")) {
- restore_send_nor(restore, ipsw, tss);
-
- } else {
- // Unknown DataType!!
- error("Unknown DataType\n");
- return -1;
- }
- }
-
- } else if (!strcmp(msgtype, "StatusMsg")) {
- restore_error = restore_handle_status_msg(restore, message);
-
- } else {
- info("Received unknown message type: %s\n", msgtype);
- }
- }
+ if (restore_error != RESTORE_E_SUCCESS) {
+ error("ERROR: Unable to start the restore process\n");
+ restore_close(device, restore);
+ return -1;
+ }
- if (RESTORE_E_SUCCESS != restore_error) {
- error("Invalid return status %d\n", restore_error);
- //idevicerestore_quit = 1;
- }
+ // this is the restore process loop, it reads each message in from
+ // restored and passes that data on to it's specific handler
+ while (!idevicerestore_quit) {
+ restore_error = restored_receive(restore, &message);
+ if (restore_error != RESTORE_E_SUCCESS) {
+ debug("No data to read\n");
+ message = NULL;
+ continue;
+ }
+ // discover what kind of message has been received
+ node = plist_dict_get_item(message, "MsgType");
+ if (!node || plist_get_node_type(node) != PLIST_STRING) {
+ debug("Unknown message received\n");
+ debug_plist(message);
plist_free(message);
+ message = NULL;
+ continue;
}
- } else {
- error("ERROR: Could not start restore. %d\n", restore_error);
+ plist_get_string_val(node, &type);
+
+ // data request messages are sent by restored whenever it requires
+ // files sent to the server by the client. these data requests include
+ // SystemImageData, KernelCache, and NORData requests
+ if (!strcmp(type, "DataRequestMsg")) {
+ error = restore_handle_data_request_msg(device, restore, message, tss, ipsw, filesystem);
+ }
+
+ // progress notification messages sent by the restored inform the client
+ // of it's current operation and sometimes percent of progress is complete
+ else if (!strcmp(type, "ProgressMsg")) {
+ error = restore_handle_progress_msg(restore, message);
+ }
+
+ // status messages usually indicate the current state of the restored
+ // process or often to signal an error has been encountered
+ else if (!strcmp(type, "StatusMsg")) {
+ error = restore_handle_status_msg(restore, message);
+ }
+
+ // there might be some other message types i'm not aware of, but I think
+ // at least the "previous error logs" messages usually end up here
+ else {
+ debug("Unknown message type received\n");
+ debug_plist(message);
+ }
+
+ // finally, if any of these message handlers returned -1 then we encountered
+ // an unrecoverable error, so we need to bail.
+ if (error < 0) {
+ error("ERROR: Unable to successfully restore device\n");
+ idevicerestore_quit = 1;
+ }
+
+ plist_free(message);
+ message = NULL;
}
- restored_client_free(restore);
- idevice_free(device);
+ restore_close(device, restore);
return 0;
}
diff --git a/src/restore.h b/src/restore.h
index 7a2e27e..cf9cf51 100644
--- a/src/restore.h
+++ b/src/restore.h
@@ -37,6 +37,6 @@ int restore_send_nor(restored_client_t client, const char* ipsw, plist_t tss);
int restore_send_kernelcache(restored_client_t client, char *kernel_data, int len);
int restore_device(const char* uuid, const char* ipsw, plist_t tss, const char* filesystem);
int restore_open_with_timeout(const char* uuid, idevice_t* device, restored_client_t* client);
-int restore_send_filesystem(idevice_t device, restored_client_t client, const char *filesystem);
+int restore_send_filesystem(idevice_t device, const char* filesystem);
#endif