diff options
| author | 2010-01-25 01:31:10 +0100 | |
|---|---|---|
| committer | 2010-01-25 01:31:10 +0100 | |
| commit | 9f1677222b06f41c4ab309918511f3c3918a822e (patch) | |
| tree | b135afcee0eaa8c36e643b6383f915509b013882 | |
| parent | 8f133b0e0e89f4a44b80a442f70ef28cc7efa3df (diff) | |
| download | libimobiledevice-9f1677222b06f41c4ab309918511f3c3918a822e.tar.gz libimobiledevice-9f1677222b06f41c4ab309918511f3c3918a822e.tar.bz2 | |
Implement storing received files as backup including new Manifest
| -rw-r--r-- | tools/iphonebackup.c | 315 | 
1 files changed, 157 insertions, 158 deletions
| diff --git a/tools/iphonebackup.c b/tools/iphonebackup.c index 611c0f2..1ad4116 100644 --- a/tools/iphonebackup.c +++ b/tools/iphonebackup.c @@ -40,7 +40,8 @@ static int quit_flag = 0;  enum cmd_mode {  	CMD_BACKUP, -	CMD_RESTORE +	CMD_RESTORE, +	CMD_LEAVE  };  static plist_t mobilebackup_factory_info_plist() @@ -102,150 +103,24 @@ static plist_t mobilebackup_factory_info_plist()  	return ret;  } -static plist_t mobilebackup_factory_metadata_plist() -{ -	plist_t ret = NULL; -/* -Metadata key is: -<dict> -	<key>Path</key> -	<string>Library/SMS/sms.db</string> -	<key>Version</key> -	<string>3.0</string> -	<key>Greylist</key> -	<false/> -	<key>Domain</key> -	<string>HomeDomain</string> -</dict> -*/ -/* -<dict> -	<key>Metadata</key> -	<data><!-- binary plist --> -	YnBsaXN0MDDUAQIDBAUGBwhUUGF0aFdWZXJzaW9uWEdyZXlsaXN0VkRvbWFp -	bl8QEkxpYnJhcnkvU01TL3Ntcy5kYlMzLjAIWkhvbWVEb21haW4IERYeJy5D -	R0gAAAAAAAABAQAAAAAAAAAJAAAAAAAAAAAAAAAAAAAAUw== -	</data> -	<key>StorageVersion</key> -	<string>1.0</string> -	<key>Version</key> -	<string>3.0</string> -	<key>AuthVersion</key> -	<string>1.0</string> -	<key>IsEncrypted</key> -	<false/> -</dict> -*/ -	return ret; -} - -/** - * Generates a manifest data plist with all files and corresponding hashes - */ -static plist_t mobilebackup_factory_manifest_data_plist() -{ -	plist_t ret = NULL; -	plist_t value_node = NULL; -	char *uuid = NULL; -	GTimeVal tv = {0, 0}; - -	ret = plist_new_dict(); - -	/* get basic device information in one go */ -	lockdownd_get_value(client, NULL, "IntegratedCircuitCardIdentity", &value_node); - -	iphone_device_get_uuid(phone, &uuid); -	plist_dict_insert_item(ret, "DeviceId", plist_new_string(uuid)); -	free(uuid); - -	plist_dict_insert_item(ret, "Version", plist_new_string("6.2")); - -	/* TODO: add all Applications */ - -	/* TODO: add all Files */ -	plist_t files = plist_new_dict(); - -	/* single file entry */ -	plist_t info_node = plist_new_dict(); -	g_get_current_time(&tv); -	plist_dict_insert_item(info_node, "ModificationTime", plist_new_date(tv.tv_sec, tv.tv_usec)); -	plist_dict_insert_item(info_node, "FileLength", plist_new_uint(131072)); -	plist_dict_insert_item(info_node, "Domain", plist_new_string("HomeDomain")); - -	/* FIXME: calculate correct data hash */ -	/* Data hash is: sha1(<file>) */ -	plist_dict_insert_item(info_node, "DataHash", plist_new_data(NULL, 0)); -	plist_dict_insert_item(info_node, "Group ID", plist_new_uint(501)); -	plist_dict_insert_item(info_node, "User ID", plist_new_uint(501)); -	plist_dict_insert_item(info_node, "Mode ID", plist_new_uint(420)); - -	/* FIXME: calculate correct file hash */ -	/* File hash is: sha1(<Domain>-<Relative File Path>) */ -	plist_dict_insert_item(files, "3d0d7e5fb2ce288813306e4d4636395e047a3d28", info_node); -	plist_dict_insert_item(ret, "Files", files); - -	/* last node with ICCID */ -	if (value_node) -		plist_dict_insert_item(ret, "DeviceICCID", &value_node); - -	return ret; -} - -/** - * Generates a manifest plist with all needed information and hashes - */ -static plist_t mobilebackup_factory_manifest_plist(plist_t manifest_data) -{ -	char *buffer = NULL; -	char *s = NULL; -	uint32_t length; -	unsigned char sha1[20]; -	gsize sha1_len; -	GChecksum *checksum; -	plist_t ret = NULL; - -	if (!manifest_data) -		return ret; - -	ret = plist_new_dict(); -	plist_dict_insert_item(ret, "AuthVersion", plist_new_string("2.0")); - -	/* AuthSignature Hash is: sha1(<manifest_data>) */ -	plist_to_bin(manifest_data, &buffer, &length); - -	sha1_len = g_checksum_type_get_length(G_CHECKSUM_SHA1); -	checksum = g_checksum_new(G_CHECKSUM_SHA1); -	g_checksum_update(checksum, (guchar *)buffer, length); -	g_checksum_get_digest(checksum, sha1, &sha1_len); -	s = (char *)g_checksum_get_string(checksum); -	printf("SHA1 AuthSignature: %s\n", s); -	plist_dict_insert_item(ret, "AuthSignature", plist_new_data((char*)sha1, sha1_len)); -	g_checksum_free(checksum); - - -	plist_dict_insert_item(ret, "IsEncrypted", plist_new_uint(0)); -	plist_dict_insert_item(ret, "Data", plist_new_data(buffer, length)); - -	free(buffer); - -	return ret; -} -  enum plist_format_t {  	PLIST_FORMAT_XML,  	PLIST_FORMAT_BINARY  }; -static int plist_read_from_filename(char *filename, plist_t *plist) +static void buffer_to_filename(char *filename, char *buffer, uint32_t length)  { -	return 1; +	FILE *f; + +	f = fopen(filename, "ab"); +	fwrite(buffer, sizeof(char), length, f); +	fclose(f);  }  static int plist_write_to_filename(plist_t plist, char *filename, enum plist_format_t format)  {  	char *buffer = NULL;  	uint32_t length; -	FILE *f;  	if (!plist || !filename)  		return 0; @@ -257,9 +132,7 @@ static int plist_write_to_filename(plist_t plist, char *filename, enum plist_for  	else  		return 0; -	f = fopen(filename, "wb"); -	fwrite(buffer, sizeof(char), length, f); -	fclose(f); +	buffer_to_filename(filename, buffer, length);  	free(buffer); @@ -281,25 +154,50 @@ static int plist_strcmp(plist_t node, const char *str)  	return ret;  } +static plist_t device_link_message_factory_process_message_new(plist_t content) +{ +	plist_t ret = plist_new_array(); +	plist_array_append_item(ret, plist_new_string("DLMessageProcessMessage")); +	plist_array_append_item(ret, content); +	return ret; +} + +static void mobilebackup_cancel_backup_with_error(const char *reason) +{ +	plist_t node = plist_new_dict(); +	plist_dict_insert_item(node, "BackupMessageTypeKey", plist_new_string("BackupMessageError")); +	plist_dict_insert_item(node, "BackupErrorReasonKey", plist_new_string(reason)); + +	plist_t message = device_link_message_factory_process_message_new(node); + +	mobilebackup_send(mobilebackup, message); + +	plist_free(message); +	message = NULL; +} +  static void mobilebackup_write_status(char *path, int status)  { +	struct stat st;  	plist_t status_plist = plist_new_dict();  	plist_dict_insert_item(status_plist, "Backup Success", plist_new_bool(status));  	char *file_path = g_build_path(G_DIR_SEPARATOR_S, path, "Status.plist", NULL); +	if (stat(file_path, &st) == 0) +		remove(file_path);  	plist_write_to_filename(status_plist, file_path, PLIST_FORMAT_XML);  	g_free(file_path);  	plist_free(status_plist);  } -static void debug_plist(plist_t plist) +static void debug_plist(plist_t a)  {  	char *buffer = NULL;  	uint32_t length = 0; -	if (!plist) +	if (a == NULL)  		return; -	plist_to_xml(plist, &buffer, &length); +	plist_to_xml(a, &buffer, &length);  	printf("Printing %i bytes plist:\n%s\n", length, buffer);  	free(buffer); @@ -341,6 +239,9 @@ int main(int argc, char *argv[])  	char *backup_directory = NULL;  	struct stat st;  	plist_t node = NULL; +	plist_t node_tmp = NULL; +	char *buffer = NULL; +	uint64_t length = 0;  	/* we need to exit cleanly on running backups and restores or we cause havok */  	signal(SIGINT, clean_exit); @@ -440,6 +341,11 @@ int main(int argc, char *argv[])  		printf("Started \"%s\" service on port %d.\n", MOBILEBACKUP_SERVICE_NAME, port);  		mobilebackup_client_new(phone, port, &mobilebackup); +		if (quit_flag > 0) { +			printf("Aborting backup. Cancelled by user.\n"); +			cmd = CMD_LEAVE; +		} +  		switch(cmd) {  			case CMD_BACKUP:  			printf("Starting backup...\n"); @@ -451,29 +357,32 @@ int main(int argc, char *argv[])  			/* create Info.plist (Device infos, IC-Info.sidb, photos, app_ids, iTunesPrefs) */  			printf("Creating \"%s/Info.plist\".\n", backup_directory);  			plist_t info_plist = mobilebackup_factory_info_plist(); +			if (stat(info_path, &st) == 0) +				remove(info_path);  			plist_write_to_filename(info_plist, info_path, PLIST_FORMAT_XML);  			g_free(info_path); +			if (client) { +				lockdownd_client_free(client); +				client = NULL; +			} +  			/* create Manifest.plist (backup manifest (backup state)) */  			printf("Creating \"%s/Manifest.plist\".\n", backup_directory);  			char *manifest_path = g_build_path(G_DIR_SEPARATOR_S, backup_directory, "Manifest.plist", NULL); -			plist_t manifest_data = mobilebackup_factory_manifest_data_plist(); -			plist_t manifest_plist = mobilebackup_factory_manifest_plist(manifest_data); -			plist_write_to_filename(manifest_plist, manifest_path, PLIST_FORMAT_XML); -			g_free(manifest_path); +			plist_t manifest_plist = NULL; +			if (stat(manifest_path, &st) == 0) +				remove(manifest_path);  			/* create Status.plist with failed status for now */  			mobilebackup_write_status(backup_directory, 0); -			/* close down lockdown connection as it is no longer needed */ -			lockdownd_client_free(client); -			client = NULL; - -			/* request backup from device with manifest */ +			/* request backup from device with manifest from last backup */  			printf("Sending manifest and requesting backup.\n");  			node = plist_new_dict(); -			plist_dict_insert_item(node, "BackupManifestKey", manifest_plist); +			if (manifest_plist) +				plist_dict_insert_item(node, "BackupManifestKey", manifest_plist);  			plist_dict_insert_item(node, "BackupComputerBasePathKey", plist_new_string("/"));  			plist_dict_insert_item(node, "BackupMessageTypeKey", plist_new_string("BackupMessageBackupRequest"));  			plist_dict_insert_item(node, "BackupProtocolVersion", plist_new_string("1.6")); @@ -514,21 +423,66 @@ int main(int argc, char *argv[])  			/* receive and save DLSendFile files and metadata, ACK each */  			int file_index = 0; +			char *file_path = NULL; +			char *file_ext = NULL; +			char *filename_mdinfo = NULL; +			char *filename_mddata = NULL; +			char *filename_source = NULL;  			do {  				mobilebackup_receive(mobilebackup, &message);  				node = plist_array_get_item(message, 0);  				if (plist_strcmp(node, "DLSendFile"))  					break; -				printf("Receiving file %d...\n", file_index); -				/* TODO: save <hash>.mdinfo */ -				/* TODO: save <hash>.mddata */ -				debug_plist(message); +				/* get source filename and print it */ +				node_tmp = plist_array_get_item(message, 2); +				node = plist_dict_get_item(node_tmp, "DLFileSource"); +				plist_get_string_val(node, &filename_source); +				printf("Received file %s...", filename_source); +				free(filename_source); + +				/* save <hash>.mdinfo */ +				node = plist_dict_get_item(node_tmp, "BackupFileInfo"); +				if (node) { +					node = plist_dict_get_item(node_tmp, "DLFileDest"); +					plist_get_string_val(node, &file_path); +					file_ext = (char *)g_strconcat(file_path, ".mdinfo", NULL); +					filename_mdinfo = g_build_path(G_DIR_SEPARATOR_S, backup_directory, file_ext, NULL); +					node = plist_dict_get_item(node_tmp, "BackupFileInfo"); +					plist_write_to_filename(node, filename_mdinfo, PLIST_FORMAT_BINARY); +					g_free(file_ext); +					g_free(filename_mdinfo); +				} + +				/* save <hash>.mddata */ +				node = plist_dict_get_item(node_tmp, "BackupFileInfo"); +				if (node_tmp && file_path) { +					node = plist_dict_get_item(node_tmp, "DLFileDest"); +					plist_get_string_val(node, &file_path); +					file_ext = (char *)g_strconcat(file_path, ".mddata", NULL); +					filename_mddata = g_build_path(G_DIR_SEPARATOR_S, backup_directory, file_ext, NULL); +					node_tmp = plist_array_get_item(message, 1); +					plist_get_data_val(node_tmp, &buffer, &length); +					buffer_to_filename(filename_mddata, buffer, length); +					free(buffer); +					buffer = NULL; +					g_free(filename_mddata); +				} + +				printf("DONE\n"); + +				if (file_ext) +					free(file_ext); +  				plist_free(message);  				message = NULL; -				if (quit_flag) { -					/* FIXME: need to cancel the backup here */ +				if (quit_flag > 0) { +					/* need to cancel the backup here */ +					mobilebackup_cancel_backup_with_error("Cancelling DLSendFile"); + +					plist_free(message); +					message = NULL;  					break;  				} @@ -550,17 +504,58 @@ int main(int argc, char *argv[])  			printf("Received %d files from device.\n", file_index);  			if (!plist_strcmp(node, "DLMessageProcessMessage")) { -				node = plist_array_get_item(message, 1); -				node = plist_dict_get_item(node, "BackupMessageTypeKey"); +				node_tmp = plist_array_get_item(message, 1); +				node = plist_dict_get_item(node_tmp, "BackupMessageTypeKey");  				/* wait until received final backup finished message */  				if (node && !plist_strcmp(node, "BackupMessageBackupFinished")) {  					/* backup finished */ + +					/* process BackupFilesToDeleteKey */ +					node = plist_dict_get_item(node_tmp, "BackupFilesToDeleteKey"); +					if (node) { +						length = plist_array_get_size(node); +						i = 0; +						while ((node_tmp = plist_array_get_item(node, i++)) != NULL) { +							plist_get_string_val(node_tmp, &file_path); + +							file_ext = (char *)g_strconcat(file_path, ".mddata", NULL); +							filename_mddata = g_build_path(G_DIR_SEPARATOR_S, backup_directory, file_ext, NULL); +							g_free(file_ext); +							printf("Removing \"%s\"... ", filename_mddata); +							if (!remove( filename_mddata )) { +								printf("DONE\n"); +							} else +								printf("FAILED\n"); + +							file_ext = (char *)g_strconcat(file_path, ".mdinfo", NULL); +							filename_mdinfo = g_build_path(G_DIR_SEPARATOR_S, backup_directory, file_ext, NULL); +							g_free(file_ext); +							printf("Removing \"%s\"... ", filename_mdinfo); +							if (!remove( filename_mdinfo )) { +								printf("DONE\n"); +							} else +								printf("FAILED\n"); +						} +					} + +					/* save new Manifest.plist */ +					node_tmp = plist_array_get_item(message, 1); +					manifest_plist = plist_dict_get_item(node_tmp, "BackupManifestKey"); +					if (manifest_plist) { +						if (stat(manifest_path, &st) != 0) +							remove(manifest_path); +						plist_write_to_filename(manifest_plist, manifest_path, PLIST_FORMAT_XML); +					} +					  					/* create: Status.plist (Info on how the backup process turned out) */  					printf("Backup Successful.\n");  					mobilebackup_write_status(backup_directory, 1);  				}  			} +			if (manifest_path) +				g_free(manifest_path); +  			if (node)  				plist_free(node); @@ -575,6 +570,7 @@ int main(int argc, char *argv[])  			lockdownd_client_free(client);  			client = NULL;  			break; +			case CMD_LEAVE:  			default:  			break;  		} @@ -584,11 +580,14 @@ int main(int argc, char *argv[])  		client = NULL;  	} -	if (client) +	if (client) {  		lockdownd_client_free(client); +		client = NULL; +	}  	if (mobilebackup)  		mobilebackup_client_free(mobilebackup); +  	iphone_device_free(phone);  	return 0; | 
