From 9f0c8a85c65d3aab7afd4d3e69e3490e24e7d801 Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Tue, 7 Oct 2014 09:23:34 +0200 Subject: [PATCH 1/2] Add download option. Unlike upload option, download pulls down whole tree. For this reason --to is expected to be directory path. --- ios-deploy.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 3 deletions(-) diff --git a/ios-deploy.c b/ios-deploy.c index c32f027..e56606e 100644 --- a/ios-deploy.c +++ b/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; char *key, *val; - int not_dir; + int not_dir = 0; AFCFileInfoOpen(afc_conn_p, dir, &afc_dict_p); 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) { service_conn_t houseFd = start_house_arrest_service(device); @@ -1226,6 +1317,8 @@ void handle_device(AMDeviceRef device) { list_files(device); } else if (strcmp("upload", command) == 0) { upload_file(device); + } else if (strcmp("download", command) == 0) { + download_tree(device); } exit(0); } @@ -1379,7 +1472,8 @@ void usage(const char* app) { " -1, --bundle_id specify bundle id for list and upload\n" " -l, --list list files\n" " -o, --upload upload file\n" - " -2, --to use together with upload file. specify target for upload\n" + " -w, --download download app tree\n" + " -2, --to use together with up/download file/tree. specify target\n" " -V, --version print the executable version \n", app); } @@ -1409,12 +1503,13 @@ int main(int argc, char *argv[]) { { "list", no_argument, NULL, 'l' }, { "bundle_id", required_argument, NULL, '1'}, { "upload", required_argument, NULL, 'o'}, + { "download", no_argument, NULL, 'w'}, { "to", required_argument, NULL, '2'}, { NULL, 0, NULL, 0 }, }; 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) { case 'm': @@ -1479,6 +1574,10 @@ int main(int argc, char *argv[]) { command_only = true; command = "list"; break; + case 'w': + command_only = true; + command = "download"; + break; default: usage(argv[0]); return exitcode_error; From 7742c5d532a3583fa51ff7bc03ff40196e3a2bc1 Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Tue, 7 Oct 2014 11:23:33 +0200 Subject: [PATCH 2/2] Allow --list and --download to pick specific subdirectories. Note that in a way it introduces inconsistency with help message. This is because arguments to --list and --download are optional and has to be passed with '=', e.g. --list=/Documents. --- ios-deploy.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ios-deploy.c b/ios-deploy.c index e56606e..1189753 100644 --- a/ios-deploy.c +++ b/ios-deploy.c @@ -154,6 +154,7 @@ bool justlaunch = false; char *app_path = NULL; char *device_id = NULL; char *args = NULL; +char *list_root = NULL; int timeout = 0; int port = 12345; CFStringRef last_path = NULL; @@ -1136,7 +1137,7 @@ void list_files(AMDeviceRef device) afc_connection* afc_conn_p; if (AFCConnectionOpen(houseFd, 0, &afc_conn_p) == 0) { - read_dir(houseFd, afc_conn_p, "/", NULL); + read_dir(houseFd, afc_conn_p, list_root?list_root:"/", NULL); AFCConnectionClose(afc_conn_p); } } @@ -1224,7 +1225,7 @@ void download_tree(AMDeviceRef device) } } - read_dir(houseFd, afc_conn_p, "/", copy_file_callback); + read_dir(houseFd, afc_conn_p, list_root?list_root:"/", copy_file_callback); } while(0); @@ -1500,16 +1501,16 @@ int main(int argc, char *argv[]) { { "noinstall", no_argument, NULL, 'm' }, { "port", required_argument, NULL, 'p' }, { "uninstall", no_argument, NULL, 'r' }, - { "list", no_argument, NULL, 'l' }, + { "list", optional_argument, NULL, 'l' }, { "bundle_id", required_argument, NULL, '1'}, { "upload", required_argument, NULL, 'o'}, - { "download", no_argument, NULL, 'w'}, + { "download", optional_argument, NULL, 'w'}, { "to", required_argument, NULL, '2'}, { NULL, 0, NULL, 0 }, }; char ch; - while ((ch = getopt_long(argc, argv, "VmcdvunlrILiw:b:a:t:g:x:p:1:2:o:", longopts, NULL)) != -1) + while ((ch = getopt_long(argc, argv, "VmcdvunrILib:a:t:g:x:p:1:2:o:l::w::", longopts, NULL)) != -1) { switch (ch) { case 'm': @@ -1573,10 +1574,12 @@ int main(int argc, char *argv[]) { case 'l': command_only = true; command = "list"; + list_root = optarg; break; case 'w': command_only = true; command = "download"; + list_root = optarg; break; default: usage(argv[0]);