diff options
| author | 2010-05-25 00:25:02 -0400 | |
|---|---|---|
| committer | 2010-05-25 00:25:02 -0400 | |
| commit | 507825f0130fec6d148f6177a11833321ffc7fce (patch) | |
| tree | 97dafd8d98d0e89b49cb8724075f65f6c93fef11 | |
| parent | 9457cfd1b496e1e5ba48d1b387a040e9402ed80b (diff) | |
| download | idevicerestore-507825f0130fec6d148f6177a11833321ffc7fce.tar.gz idevicerestore-507825f0130fec6d148f6177a11833321ffc7fce.tar.bz2 | |
Filesystem is now restoring, need to add in kernelcache restore and nor restore and everything should be good.
Note: The latest HEAD from marcan's usbmuxd is required for this program to work. Linux kernel drivers do some wacky stuff with iPod audio interfaces
| -rw-r--r-- | src/idevicerestore.c | 201 | ||||
| -rw-r--r-- | src/ipsw.c | 133 | ||||
| -rw-r--r-- | src/ipsw.h | 2 | 
3 files changed, 195 insertions, 141 deletions
| diff --git a/src/idevicerestore.c b/src/idevicerestore.c index d6551a4..27cc161 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -100,7 +100,7 @@ int main(int argc, char* argv[]) {  	lockdownd_error_t lockdown_error = LOCKDOWN_E_SUCCESS;  	info("Checking for device in normal mode...\n"); -	device_error = idevice_new(&device, uuid); +	device_error = 1;//idevice_new(&device, uuid);  	if (device_error != IDEVICE_E_SUCCESS) {  		info("Checking for the device in recovery mode...\n");  		recovery_error = irecv_open(&recovery); @@ -164,16 +164,16 @@ int main(int argc, char* argv[]) {  		return -1;  	} +	int  buildmanifest_size = 0; +	char* buildmanifest_data = NULL;  	info("Extracting BuildManifest.plist from IPSW\n"); -	ipsw_file* buildmanifest = ipsw_extract_file(ipsw, "BuildManifest.plist"); -	if (buildmanifest == NULL) { +	if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", &buildmanifest_data, &buildmanifest_size) < 0) {  		error("ERROR: Unable to extract BuildManifest.plist IPSW\n");  		return -1;  	}  	plist_t manifest = NULL; -	plist_from_xml(buildmanifest->data, buildmanifest->size, &manifest); -	ipsw_free_file(buildmanifest); +	plist_from_xml(buildmanifest_data, buildmanifest_size, &manifest);  	info("Creating TSS request\n");  	plist_t tss_request = tss_create_request(manifest, ecid); @@ -196,21 +196,21 @@ int main(int argc, char* argv[]) {  	// Get name of filesystem DMG in IPSW  	char* filesystem = NULL;  	plist_t filesystem_node = plist_dict_get_item(tss_request, "OS"); -	if(!filesystem_node || plist_get_node_type(filesystem_node) != PLIST_DICT) { +	if (!filesystem_node || plist_get_node_type(filesystem_node) != PLIST_DICT) {  		error("ERROR: Unable to find OS filesystem\n");  		plist_free(tss_request);  		return -1;  	}  	plist_t filesystem_info_node = plist_dict_get_item(filesystem_node, "Info"); -	if(!filesystem_info_node || plist_get_node_type(filesystem_info_node) != PLIST_DICT) { +	if (!filesystem_info_node || plist_get_node_type(filesystem_info_node) != PLIST_DICT) {  		error("ERROR: Unable to find filesystem info node\n");  		plist_free(tss_request);  		return -1;  	}  	plist_t filesystem_info_path_node = plist_dict_get_item(filesystem_info_node, "Path"); -	if(!filesystem_info_path_node || plist_get_node_type(filesystem_info_path_node) != PLIST_STRING) { +	if (!filesystem_info_path_node || plist_get_node_type(filesystem_info_path_node) != PLIST_STRING) {  		error("ERROR: Unable to find filesystem info path node\n");  		plist_free(tss_request);  		return -1; @@ -218,6 +218,12 @@ int main(int argc, char* argv[]) {  	plist_get_string_val(filesystem_info_path_node, &filesystem);  	plist_free(tss_request); +	info("Extracting filesystem from IPSW\n"); +	if(ipsw_extract_to_file(ipsw, filesystem, filesystem) < 0) { +		error("ERROR: Unable to extract filesystem\n"); +		return -1; +	} +  	if (idevicerestore_mode == NORMAL_MODE) {  		// Place the device in recovery mode  		info("Entering recovery mode...\n"); @@ -286,19 +292,24 @@ int main(int argc, char* argv[]) {  		return -1;  	} -	idevice_event_subscribe(&device_callback, NULL); +	//idevice_event_subscribe(&device_callback, NULL);  	info("Waiting for device to enter restore mode\n"); -	while(idevicerestore_mode != RESTORE_MODE) sleep(1); -	device_error = idevice_new(&device, uuid); -	if (device_error != IDEVICE_E_SUCCESS) { -		error("ERROR: Unable to open device\n"); -		plist_free(tss_response); -		return -1; +	while (idevicerestore_mode != RESTORE_MODE) { +		device_error = idevice_new(&device, uuid); +		if (device_error == IDEVICE_E_SUCCESS) { +			idevicerestore_mode = RESTORE_MODE; +			break; +		} +		sleep(2); +		info("Got response %d\n", device_error); +		info("Retrying connection...\n"); +		//plist_free(tss_response); +		//return -1;  	} - +	idevice_set_debug_level(5);  	restored_client_t restore = NULL;  	restored_error_t restore_error = restored_client_new(device, &restore, "idevicerestore"); -	if(restore_error != RESTORE_E_SUCCESS) { +	if (restore_error != RESTORE_E_SUCCESS) {  		error("ERROR: Unable to start restored client\n");  		plist_free(tss_response);  		idevice_free(device); @@ -329,38 +340,32 @@ int main(int argc, char* argv[]) {  			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")) { +				if (!strcmp(msgtype, "ProgressMsg")) {  					restore_error = progress_msg(restore, message); -				} -				else if(!strcmp(msgtype, "DataRequestMsg")) { +				} else if (!strcmp(msgtype, "DataRequestMsg")) {  					//restore_error = data_request_msg(device, restore, message, filesystem);  					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")) { +						if (!strcmp(datatype, "SystemImageData")) {  							send_system_data(device, restore, filesystem); -						} -						else if(!strcmp(datatype, "KernelCache")) { +						} else if (!strcmp(datatype, "KernelCache")) {  							send_kernel_data(device, restore, kernelcache); -						} -						else if(!strcmp(datatype, "NORData")) { +						} else if (!strcmp(datatype, "NORData")) {  							send_nor_data(device, restore); -						} -						else { +						} else {  							// Unknown DataType!!  							error("Unknown DataType\n");  							return -1;  						}  					} -				} -				else if(!strcmp(msgtype, "StatusMsg")) { +				} else if (!strcmp(msgtype, "StatusMsg")) {  					restore_error = status_msg(restore, message); -				} -				else { +				} else {  					printf("Received unknown message type: %s\n", msgtype);  				}  			} @@ -382,7 +387,7 @@ int main(int argc, char* argv[]) {  }  void device_callback(const idevice_event_t* event, void *user_data) { -	if(event->event == IDEVICE_DEVICE_ADD) { +	if (event->event == IDEVICE_DEVICE_ADD) {  		idevicerestore_mode = RESTORE_MODE;  	}  } @@ -411,16 +416,13 @@ int data_request_msg(idevice_t device, restored_client_t client, plist_t msg, co  	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")) { +		if (!strcmp(datatype, "SystemImageData")) {  			send_system_data(device, client, filesystem); -		} -		else if(!strcmp(datatype, "KernelCache")) { +		} else if (!strcmp(datatype, "KernelCache")) {  			send_kernel_data(device, client, kernel); -		} -		else if(!strcmp(datatype, "NORData")) { +		} else if (!strcmp(datatype, "NORData")) {  			send_nor_data(device, client); -		} -		else { +		} else {  			// Unknown DataType!!  			error("Unknown DataType\n");  			return -1; @@ -442,21 +444,21 @@ int send_system_data(idevice_t device, restored_client_t client, const char *fil  	idevice_connection_t connection = NULL;  	idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR; -	for(i = 0; i < 5; i++) { +	for (i = 0; i < 5; i++) {  		ret = idevice_connect(device, ASR_PORT, &connection); -		if(ret == IDEVICE_E_SUCCESS) +		if (ret == IDEVICE_E_SUCCESS)  			break;  		else  			sleep(1);  	} -	if(ret != IDEVICE_E_SUCCESS) +	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) { +	ret = idevice_connection_receive(connection, buffer, 0x1000, &recv_bytes); +	if (ret != IDEVICE_E_SUCCESS) {  		idevice_disconnect(connection);  		return ret;  	} @@ -464,7 +466,7 @@ int send_system_data(idevice_t device, restored_client_t client, const char *fil  	printf("%s", buffer);  	FILE* fd = fopen(filesystem, "rb"); -	if(fd == NULL) { +	if (fd == NULL) {  		idevice_disconnect(connection);  		return ret;  	} @@ -493,7 +495,7 @@ int send_system_data(idevice_t device, restored_client_t client, const char *fil  	plist_to_xml(dict, &xml, &dict_size);  	ret = idevice_connection_send(connection, xml, dict_size, &sent_bytes); -	if(ret != IDEVICE_E_SUCCESS) { +	if (ret != IDEVICE_E_SUCCESS) {  		idevice_disconnect(connection);  		return ret;  	} @@ -507,7 +509,7 @@ int send_system_data(idevice_t device, restored_client_t client, const char *fil  	do {  		memset(buffer, '\0', 0x1000);  		ret = idevice_connection_receive(connection, buffer, 0x1000, &recv_bytes); -		if(ret != IDEVICE_E_SUCCESS) { +		if (ret != IDEVICE_E_SUCCESS) {  			idevice_disconnect(connection);  			return ret;  		} @@ -519,7 +521,7 @@ int send_system_data(idevice_t device, restored_client_t client, const char *fil  		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")) { +			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)) {  					printf("Error fetching OOB Length\n"); @@ -539,14 +541,14 @@ int send_system_data(idevice_t device, restored_client_t client, const char *fil  				plist_get_uint_val(oob_offset_node, &oob_offset);  				char* oob_data = (char*) malloc(oob_length); -				if(oob_data == NULL) { +				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) { +				if (fread(oob_data, 1, oob_length, fd) != oob_length) {  					error("Unable to read filesystem offset\n");  					idevice_disconnect(connection);  					free(oob_data); @@ -554,7 +556,7 @@ int send_system_data(idevice_t device, restored_client_t client, const char *fil  				}  				ret = idevice_connection_send(connection, oob_data, oob_length, &sent_bytes); -				if(sent_bytes != oob_length || ret != IDEVICE_E_SUCCESS) { +				if (sent_bytes != oob_length || ret != IDEVICE_E_SUCCESS) {  					printf("Unable to send %d bytes to asr\n", sent_bytes);  					idevice_disconnect(connection);  					free(oob_data); @@ -565,17 +567,17 @@ int send_system_data(idevice_t device, restored_client_t client, const char *fil  			}  		} -	} while(strcmp(command, "Payload")); +	} while (strcmp(command, "Payload"));  	fseek(fd, 0, SEEK_SET);  	char data[1450]; -	for(i = len; i > 0; i -= 1450) { +	for (i = len; i > 0; i -= 1450) {  		int size = 1450; -		if(i < 1450) { +		if (i < 1450) {  			size = i;  		} -		if(fread(data, 1, size, fd) != (unsigned int)size) { +		if (fread(data, 1, size, fd) != (unsigned int) size) {  			fclose(fd);  			idevice_disconnect(connection);  			printf("Error reading filesystem\n"); @@ -583,11 +585,11 @@ int send_system_data(idevice_t device, restored_client_t client, const char *fil  		}  		ret = idevice_connection_send(connection, data, size, &sent_bytes); -		if(ret != IDEVICE_E_SUCCESS) { +		if (ret != IDEVICE_E_SUCCESS) {  			fclose(fd);  		} -		if(i % (1450*1000) == 0) { +		if (i % (1450 * 1000) == 0) {  			printf(".");  		}  	} @@ -601,7 +603,7 @@ int send_system_data(idevice_t device, restored_client_t client, const char *fil  int send_kernel_data(idevice_t device, restored_client_t client, const char *kernel) {  	printf("Sending kernelcache\n");  	FILE* fd = fopen(kernel, "rb"); -	if(fd == NULL) { +	if (fd == NULL) {  		info("Unable to open kernelcache");  		return -1;  	} @@ -611,13 +613,13 @@ int send_kernel_data(idevice_t device, restored_client_t client, const char *ker  	fseek(fd, 0, SEEK_SET);  	char* kernel_data = (char*) malloc(len); -	if(kernel_data == NULL) { +	if (kernel_data == NULL) {  		error("Unable to allocate memory for kernel data");  		fclose(fd);  		return -1;  	} -	if(fread(kernel_data, 1, len, fd) != len) { +	if (fread(kernel_data, 1, len, fd) != len) {  		error("Unable to read kernel data\n");  		free(kernel_data);  		fclose(fd); @@ -631,7 +633,7 @@ int send_kernel_data(idevice_t device, restored_client_t client, const char *ker  	plist_dict_insert_item(dict, "KernelCacheFile", kernelcache_node);  	restored_error_t ret = restored_send(client, dict); -	if(ret != RESTORE_E_SUCCESS) { +	if (ret != RESTORE_E_SUCCESS) {  		error("Unable to send kernelcache data\n");  		free(kernel_data);  		plist_free(dict); @@ -644,7 +646,6 @@ int send_kernel_data(idevice_t device, restored_client_t client, const char *ker  	return 0;  } -  int send_nor_data(idevice_t device, restored_client_t client) {  	info("Not implemented\n");  	return 0; @@ -734,9 +735,10 @@ int send_ibec(char* ipsw, plist_t tss) {  		return -1;  	} +	int ibec_size = 0; +	char* ibec_data = NULL;  	info("Extracting %s from %s\n", path, ipsw); -	ipsw_file* ibec = ipsw_extract_file(ipsw, path); -	if (ibec == NULL) { +	if (ipsw_extract_to_memory(ipsw, path, &ibec_data, &ibec_size)) {  		error("ERROR: Unable to extract %s from %s\n", path, ipsw);  		irecv_close(client);  		client = NULL; @@ -745,19 +747,19 @@ int send_ibec(char* ipsw, plist_t tss) {  		return -1;  	} -	img3_file* img3 = img3_parse_file(ibec->data, ibec->size); +	img3_file* img3 = img3_parse_file(ibec_data, ibec_size);  	if (img3 == NULL) {  		error("ERROR: Unable to parse IMG3: %s\n", path); -		ipsw_free_file(ibec);  		irecv_close(client);  		client = NULL; +		free(ibec_data);  		free(path);  		free(blob);  		return -1;  	} -	if (ibec) { -		ipsw_free_file(ibec); -		ibec = NULL; +	if (ibec_data) { +		free(ibec_data); +		ibec_data = NULL;  	}  	if (img3_replace_signature(img3, blob) < 0) { @@ -863,9 +865,10 @@ int send_applelogo(char* ipsw, plist_t tss) {  		return -1;  	} +	int applelogo_size = 0; +	char* applelogo_data = NULL;  	info("Extracting %s from %s\n", path, ipsw); -	ipsw_file* applelogo = ipsw_extract_file(ipsw, path); -	if (applelogo == NULL) { +	if (ipsw_extract_to_memory(ipsw, path, &applelogo_data, &applelogo_size) < 0) {  		error("ERROR: Unable to extract %s from %s\n", path, ipsw);  		irecv_close(client);  		client = NULL; @@ -874,19 +877,19 @@ int send_applelogo(char* ipsw, plist_t tss) {  		return -1;  	} -	img3_file* img3 = img3_parse_file(applelogo->data, applelogo->size); +	img3_file* img3 = img3_parse_file(applelogo_data, applelogo_size);  	if (img3 == NULL) {  		error("ERROR: Unable to parse IMG3: %s\n", path); -		ipsw_free_file(applelogo);  		irecv_close(client);  		client = NULL; +		free(applelogo_data);  		free(path);  		free(blob);  		return -1;  	} -	if (applelogo) { -		ipsw_free_file(applelogo); -		applelogo = NULL; +	if (applelogo_data) { +		free(applelogo_data); +		applelogo_data = NULL;  	}  	if (img3_replace_signature(img3, blob) < 0) { @@ -993,9 +996,10 @@ int send_devicetree(char* ipsw, plist_t tss) {  		return -1;  	} +	int devicetree_size = 0; +	char* devicetree_data = NULL;  	info("Extracting %s from %s\n", path, ipsw); -	ipsw_file* devicetree = ipsw_extract_file(ipsw, path); -	if (devicetree == NULL) { +	if (ipsw_extract_to_memory(ipsw, path, &devicetree_data, &devicetree_size) < 0) {  		error("ERROR: Unable to extract %s from %s\n", path, ipsw);  		irecv_close(client);  		client = NULL; @@ -1004,19 +1008,19 @@ int send_devicetree(char* ipsw, plist_t tss) {  		return -1;  	} -	img3_file* img3 = img3_parse_file(devicetree->data, devicetree->size); +	img3_file* img3 = img3_parse_file(devicetree_data, devicetree_size);  	if (img3 == NULL) {  		error("ERROR: Unable to parse IMG3: %s\n", path); -		ipsw_free_file(devicetree); +		free(devicetree_data);  		irecv_close(client);  		client = NULL;  		free(path);  		free(blob);  		return -1;  	} -	if (devicetree) { -		ipsw_free_file(devicetree); -		devicetree = NULL; +	if (devicetree_data) { +		free(devicetree_data); +		devicetree_data = NULL;  	}  	if (img3_replace_signature(img3, blob) < 0) { @@ -1122,9 +1126,10 @@ int send_ramdisk(char* ipsw, plist_t tss) {  		return -1;  	} +	int ramdisk_size = 0; +	char* ramdisk_data = NULL;  	info("Extracting %s from %s\n", path, ipsw); -	ipsw_file* ramdisk = ipsw_extract_file(ipsw, path); -	if (ramdisk == NULL) { +	if (ipsw_extract_to_memory(ipsw, path, &ramdisk_data, &ramdisk_size) < 0) {  		error("ERROR: Unable to extract %s from %s\n", path, ipsw);  		irecv_close(client);  		client = NULL; @@ -1133,19 +1138,19 @@ int send_ramdisk(char* ipsw, plist_t tss) {  		return -1;  	} -	img3_file* img3 = img3_parse_file(ramdisk->data, ramdisk->size); +	img3_file* img3 = img3_parse_file(ramdisk_data, ramdisk_size);  	if (img3 == NULL) {  		error("ERROR: Unable to parse IMG3: %s\n", path); -		ipsw_free_file(ramdisk); +		free(ramdisk_data);  		irecv_close(client);  		client = NULL;  		free(path);  		free(blob);  		return -1;  	} -	if (ramdisk) { -		ipsw_free_file(ramdisk); -		ramdisk = NULL; +	if (ramdisk_data) { +		free(ramdisk_data); +		ramdisk_data = NULL;  	}  	if (img3_replace_signature(img3, blob) < 0) { @@ -1251,9 +1256,10 @@ int send_kernelcache(char* ipsw, plist_t tss) {  		return -1;  	} +	int kernelcache_size = 0; +	char* kernelcache_data = NULL;  	info("Extracting %s from %s\n", path, ipsw); -	ipsw_file* kernelcache = ipsw_extract_file(ipsw, path); -	if (kernelcache == NULL) { +	if (ipsw_extract_to_memory(ipsw, path, &kernelcache_data, &kernelcache_size) < 0) {  		error("ERROR: Unable to extract %s from %s\n", path, ipsw);  		irecv_close(client);  		client = NULL; @@ -1262,19 +1268,19 @@ int send_kernelcache(char* ipsw, plist_t tss) {  		return -1;  	} -	img3_file* img3 = img3_parse_file(kernelcache->data, kernelcache->size); +	img3_file* img3 = img3_parse_file(kernelcache_data, kernelcache_size);  	if (img3 == NULL) {  		error("ERROR: Unable to parse IMG3: %s\n", path); -		ipsw_free_file(kernelcache); +		free(kernelcache_data);  		irecv_close(client);  		client = NULL;  		free(path);  		free(blob);  		return -1;  	} -	if (kernelcache) { -		ipsw_free_file(kernelcache); -		kernelcache = NULL; +	if (kernelcache_data) { +		free(kernelcache_data); +		kernelcache_data = NULL;  	}  	if (img3_replace_signature(img3, blob) < 0) { @@ -1344,6 +1350,7 @@ int send_kernelcache(char* ipsw, plist_t tss) {  	}  	if (client) { +		irecv_set_configuration(client, 4);  		irecv_close(client);  		client = NULL;  	} @@ -26,6 +26,8 @@  #include "ipsw.h"  #include "idevicerestore.h" +#define BUFSIZE 0x100000 +  typedef struct {  	struct zip* zip;  } ipsw_archive; @@ -36,13 +38,13 @@ void ipsw_close(ipsw_archive* archive);  ipsw_archive* ipsw_open(const char* ipsw) {  	int err = 0;  	ipsw_archive* archive = (ipsw_archive*) malloc(sizeof(ipsw_archive)); -	if(archive == NULL) { +	if (archive == NULL) {  		error("ERROR: Out of memory\n");  		return NULL;  	}  	archive->zip = zip_open(ipsw, 0, &err); -	if(archive->zip == NULL) { +	if (archive->zip == NULL) {  		error("ERROR: zip_open: %s: %d\n", ipsw, err);  		free(archive);  		return NULL; @@ -51,76 +53,121 @@ ipsw_archive* ipsw_open(const char* ipsw) {  	return archive;  } -ipsw_file* ipsw_extract_file(const char* ipsw, const char* filename) { +int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfile) {  	ipsw_archive* archive = ipsw_open(ipsw); -	if(archive == NULL || archive->zip == NULL) { +	if (archive == NULL || archive->zip == NULL) {  		error("ERROR: Invalid archive\n"); -		return NULL; +		return -1;  	} -	int zindex = zip_name_locate(archive->zip, filename, 0); -	if(zindex < 0) { -		error("ERROR: zip_name_locate: %s\n", filename); -		return NULL; +	int zindex = zip_name_locate(archive->zip, infile, 0); +	if (zindex < 0) { +		error("ERROR: zip_name_locate: %s\n", infile); +		return -1;  	}  	struct zip_stat zstat;  	zip_stat_init(&zstat); -	if(zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { -		error("ERROR: zip_stat_index: %s\n", filename); -		return NULL; +	if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { +		error("ERROR: zip_stat_index: %s\n", infile); +		return -1; +	} + +	char* buffer = (char*) malloc(BUFSIZE); +	if(buffer == NULL) { +		error("ERROR: Unable to allocate memory\n"); +		return -1;  	}  	struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); -	if(zfile == NULL) { -		error("ERROR: zip_fopen_index: %s\n", filename); -		return NULL; +	if (zfile == NULL) { +		error("ERROR: zip_fopen_index: %s\n", infile); +		return -1;  	} -	ipsw_file* file = (ipsw_file*) malloc(sizeof(ipsw_file)); -	if(file == NULL) { -		error("ERROR: Out of memory\n"); +	FILE* fd = fopen(outfile, "wb"); +	if(fd == NULL) { +		error("ERROR: Unable to open output file: %s\n", outfile);  		zip_fclose(zfile); -		return NULL; +		return -1;  	} -	file->size = zstat.size; -	file->index = zstat.index; -	file->name = strdup(zstat.name); -	file->data = (unsigned char*) malloc(file->size); -	if(file->data == NULL) { +	int i = 0; +	int size = 0; +	int count = 0; +	for (i = zstat.size; i > 0; i -= count) { +		if(i < BUFSIZE) size = i; +		else size = BUFSIZE; +		count = zip_fread(zfile, buffer, size); +		if (count < 0) { +			error("ERROR: zip_fread: %s\n", infile); +			zip_fclose(zfile); +			free(buffer); +			return -1; +		} +		fwrite(buffer, 1, count, fd); +		debug("."); +	} +	debug("\n"); + +	fclose(fd); +	zip_fclose(zfile); +	ipsw_close(archive); +	free(buffer); +	return 0; +} + +int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, int* psize) { +	ipsw_archive* archive = ipsw_open(ipsw); +	if (archive == NULL || archive->zip == NULL) { +		error("ERROR: Invalid archive\n"); +		return -1; +	} + +	int zindex = zip_name_locate(archive->zip, infile, 0); +	if (zindex < 0) { +		error("ERROR: zip_name_locate: %s\n", infile); +		return -1; +	} + +	struct zip_stat zstat; +	zip_stat_init(&zstat); +	if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { +		error("ERROR: zip_stat_index: %s\n", infile); +		return -1; +	} + +	struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); +	if (zfile == NULL) { +		error("ERROR: zip_fopen_index: %s\n", infile); +		return -1; +	} + +	int size = zstat.size; +	char* buffer = (unsigned char*) malloc(size); +	if (buffer == NULL) {  		error("ERROR: Out of memory\n"); -		ipsw_free_file(file);  		zip_fclose(zfile); -		return NULL; +		return -1;  	} -	if(zip_fread(zfile, file->data, file->size) != file->size) { -		error("ERROR: zip_fread: %s\n", filename); -		ipsw_free_file(file); +	if (zip_fread(zfile, buffer, size) != size) { +		error("ERROR: zip_fread: %s\n", infile);  		zip_fclose(zfile); -		return NULL; +		free(buffer); +		return -1;  	}  	zip_fclose(zfile);  	ipsw_close(archive); -	return file; -} -void ipsw_free_file(ipsw_file* file) { -	if(file != NULL) { -		if(file->name != NULL) { -			free(file->name); -		} -		if(file->data != NULL) { -			free(file->data); -		} -		free(file); -	} +	*pbuffer = buffer; +	*psize = size; +	return 0;  }  void ipsw_close(ipsw_archive* archive) { -	if(archive != NULL) { +	if (archive != NULL) {  		zip_unchange_all(archive->zip);  		zip_close(archive->zip);  		free(archive); @@ -31,7 +31,7 @@ typedef struct {  	unsigned char* data;  } ipsw_file; -ipsw_file* ipsw_extract_file(const char* ipsw, const char* filename); +int ipsw_extract_to_memory(const char* ipsw, const char* infile, char** pbuffer, int* psize);  void ipsw_free_file(ipsw_file* file);  #endif | 
