Add download option.
Unlike upload option, download pulls down whole tree. For this reason --to is expected to be directory path.
This commit is contained in:
		
							
								
								
									
										105
									
								
								ios-deploy.c
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								ios-deploy.c
									
									
									
									
									
								
							| @@ -1017,7 +1017,7 @@ void read_dir(service_conn_t afcFd, afc_connection* afc_conn_p, const char* dir, | |||||||
|      |      | ||||||
|     afc_dictionary* afc_dict_p; |     afc_dictionary* afc_dict_p; | ||||||
|     char *key, *val; |     char *key, *val; | ||||||
|     int not_dir; |     int not_dir = 0; | ||||||
|  |  | ||||||
|     AFCFileInfoOpen(afc_conn_p, dir, &afc_dict_p); |     AFCFileInfoOpen(afc_conn_p, dir, &afc_dict_p); | ||||||
|     while((AFCKeyValueRead(afc_dict_p,&key,&val) == 0) && key && val) { |     while((AFCKeyValueRead(afc_dict_p,&key,&val) == 0) && key && val) { | ||||||
| @@ -1141,6 +1141,97 @@ void list_files(AMDeviceRef device) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void copy_file_callback(afc_connection* afc_conn_p, const char *name,int file) | ||||||
|  | { | ||||||
|  |     const char *local_name=name; | ||||||
|  |  | ||||||
|  |     if (*local_name=='/') local_name++; | ||||||
|  |  | ||||||
|  |     if (*local_name=='\0') return; | ||||||
|  |  | ||||||
|  |     if (file) { | ||||||
|  | 	afc_file_ref fref; | ||||||
|  | 	int err = AFCFileRefOpen(afc_conn_p,name,1,&fref); | ||||||
|  |  | ||||||
|  | 	if (err) { | ||||||
|  | 	    fprintf(stderr,"AFCFileRefOpen(\"%s\") failed: %d\n",name,err); | ||||||
|  | 	    return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	FILE *fp = fopen(local_name,"w"); | ||||||
|  |  | ||||||
|  | 	if (fp==NULL) { | ||||||
|  | 	    fprintf(stderr,"fopen(\"%s\",\"w\") failer: %s\n",local_name,strerror(errno)); | ||||||
|  | 	    AFCFileRefClose(afc_conn_p,fref); | ||||||
|  | 	    return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	char buf[4096]; | ||||||
|  | 	size_t sz=sizeof(buf); | ||||||
|  |  | ||||||
|  | 	while (AFCFileRefRead(afc_conn_p,fref,buf,&sz)==0 && sz) { | ||||||
|  | 	    fwrite(buf,sz,1,fp); | ||||||
|  | 	    sz = sizeof(buf); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	AFCFileRefClose(afc_conn_p,fref); | ||||||
|  | 	fclose(fp); | ||||||
|  |     } else { | ||||||
|  | 	if (mkdir(local_name,0777) && errno!=EEXIST) | ||||||
|  | 	    fprintf(stderr,"mkdir(\"%s\") failed: %s\n",local_name,strerror(errno)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void mkdirhier(char *path) | ||||||
|  | { | ||||||
|  |     char *slash; | ||||||
|  |     struct stat buf; | ||||||
|  |  | ||||||
|  |     if (path[0]=='.' && path[1]=='/') path+=2; | ||||||
|  |  | ||||||
|  |     if ((slash = strrchr(path,'/'))) { | ||||||
|  | 	*slash = '\0'; | ||||||
|  | 	if (stat(path,&buf)==0) { | ||||||
|  | 	    *slash = '/'; | ||||||
|  | 	    return; | ||||||
|  | 	} | ||||||
|  | 	mkdirhier(path); | ||||||
|  | 	mkdir (path,0777); | ||||||
|  | 	*slash = '/'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void download_tree(AMDeviceRef device) | ||||||
|  | { | ||||||
|  |     service_conn_t houseFd = start_house_arrest_service(device); | ||||||
|  |     afc_connection* afc_conn_p = NULL; | ||||||
|  |     char *dirname = NULL; | ||||||
|  |  | ||||||
|  |     if (AFCConnectionOpen(houseFd, 0, &afc_conn_p) == 0)  do { | ||||||
|  |  | ||||||
|  | 	if (target_filename) { | ||||||
|  | 	    dirname = strdup(target_filename); | ||||||
|  | 	    mkdirhier(dirname); | ||||||
|  | 	    if (mkdir(dirname,0777) && errno!=EEXIST) { | ||||||
|  | 		fprintf(stderr,"mkdir(\"%s\") failed: %s\n",dirname,strerror(errno)); | ||||||
|  | 		break; | ||||||
|  | 	    } | ||||||
|  | 	    if (chdir(dirname)) { | ||||||
|  | 		fprintf(stderr,"chdir(\"%s\") failed: %s\n",dirname,strerror(errno)); | ||||||
|  | 		break; | ||||||
|  | 	    } | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	read_dir(houseFd, afc_conn_p, "/", copy_file_callback); | ||||||
|  |  | ||||||
|  |     } while(0); | ||||||
|  |  | ||||||
|  |     if (dirname) free(dirname); | ||||||
|  |     if (afc_conn_p) AFCConnectionClose(afc_conn_p); | ||||||
|  | } | ||||||
|  |  | ||||||
| void upload_file(AMDeviceRef device) { | void upload_file(AMDeviceRef device) { | ||||||
|     service_conn_t houseFd = start_house_arrest_service(device); |     service_conn_t houseFd = start_house_arrest_service(device); | ||||||
|      |      | ||||||
| @@ -1226,6 +1317,8 @@ void handle_device(AMDeviceRef device) { | |||||||
|             list_files(device); |             list_files(device); | ||||||
|         } else if (strcmp("upload", command) == 0) { |         } else if (strcmp("upload", command) == 0) { | ||||||
|             upload_file(device); |             upload_file(device); | ||||||
|  |         } else if (strcmp("download", command) == 0) { | ||||||
|  |             download_tree(device); | ||||||
|         } |         } | ||||||
|         exit(0); |         exit(0); | ||||||
|     } |     } | ||||||
| @@ -1379,7 +1472,8 @@ void usage(const char* app) { | |||||||
|         "  -1, --bundle_id <bundle id>  specify bundle id for list and upload\n" |         "  -1, --bundle_id <bundle id>  specify bundle id for list and upload\n" | ||||||
|         "  -l, --list                   list files\n" |         "  -l, --list                   list files\n" | ||||||
|         "  -o, --upload <file>          upload file\n" |         "  -o, --upload <file>          upload file\n" | ||||||
|         "  -2, --to <target pathname>	use together with upload file. specify target for upload\n" |         "  -w, --download               download app tree\n" | ||||||
|  |         "  -2, --to <target pathname>   use together with up/download file/tree. specify target\n" | ||||||
|         "  -V, --version                print the executable version \n", |         "  -V, --version                print the executable version \n", | ||||||
|         app); |         app); | ||||||
| } | } | ||||||
| @@ -1409,12 +1503,13 @@ int main(int argc, char *argv[]) { | |||||||
|         { "list", no_argument, NULL, 'l' }, |         { "list", no_argument, NULL, 'l' }, | ||||||
|         { "bundle_id", required_argument, NULL, '1'}, |         { "bundle_id", required_argument, NULL, '1'}, | ||||||
|         { "upload", required_argument, NULL, 'o'}, |         { "upload", required_argument, NULL, 'o'}, | ||||||
|  |         { "download", no_argument, NULL, 'w'}, | ||||||
|         { "to", required_argument, NULL, '2'}, |         { "to", required_argument, NULL, '2'}, | ||||||
|         { NULL, 0, NULL, 0 }, |         { NULL, 0, NULL, 0 }, | ||||||
|     }; |     }; | ||||||
|     char ch; |     char ch; | ||||||
|  |  | ||||||
|     while ((ch = getopt_long(argc, argv, "VmcdvunlrILi:b:a:t:g:x:p:1:2:o:", longopts, NULL)) != -1) |     while ((ch = getopt_long(argc, argv, "VmcdvunlrILiw:b:a:t:g:x:p:1:2:o:", longopts, NULL)) != -1) | ||||||
|     { |     { | ||||||
|         switch (ch) { |         switch (ch) { | ||||||
|         case 'm': |         case 'm': | ||||||
| @@ -1479,6 +1574,10 @@ int main(int argc, char *argv[]) { | |||||||
|             command_only = true; |             command_only = true; | ||||||
|             command = "list"; |             command = "list"; | ||||||
|             break; |             break; | ||||||
|  |         case 'w': | ||||||
|  |             command_only = true; | ||||||
|  |             command = "download"; | ||||||
|  |             break; | ||||||
|         default: |         default: | ||||||
|             usage(argv[0]); |             usage(argv[0]); | ||||||
|             return exitcode_error; |             return exitcode_error; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Andy Polyakov
					Andy Polyakov