diff --git a/ios-deploy.c b/ios-deploy.c index c32f027..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; @@ -1017,7 +1018,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) { @@ -1136,11 +1137,102 @@ 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); } } +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, list_root?list_root:"/", 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 +1318,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 +1473,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); } @@ -1406,15 +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", optional_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, "VmcdvunrILib:a:t:g:x:p:1:2:o:l::w::", longopts, NULL)) != -1) { switch (ch) { case 'm': @@ -1478,6 +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]);