@@ -127,6 +127,11 @@ int AMDeviceMountImage(AMDeviceRef device, CFStringRef image, CFDictionaryRef op
127
127
mach_error_t AMDeviceLookupApplications (AMDeviceRef device , CFDictionaryRef options , CFDictionaryRef * result );
128
128
129
129
bool found_device = false, debug = false, verbose = false, unbuffered = false, nostart = false, detect_only = false, install = true, uninstall = false;
130
+ bool command_only = false;
131
+ char * command = NULL ;
132
+ char * target_filename = NULL ;
133
+ char * upload_pathname = NULL ;
134
+ char * bundle_id = NULL ;
130
135
bool interactive = true;
131
136
char * app_path = NULL ;
132
137
char * device_id = NULL ;
@@ -794,7 +799,7 @@ void launch_debugger(AMDeviceRef device, CFURLRef url) {
794
799
perror ("failed launching lldb" );
795
800
796
801
close (pfd [0 ]);
797
- close (pfd [1 ]);
802
+ close (pfd [1 ]);
798
803
// Notify parent we're exiting
799
804
kill (parent , SIGLLDB );
800
805
// Pass lldb exit code
@@ -843,6 +848,187 @@ CFStringRef get_bundle_id(CFURLRef app_url)
843
848
return bundle_id ;
844
849
}
845
850
851
+ void read_dir (service_conn_t afcFd , afc_connection * afc_conn_p , const char * dir )
852
+ {
853
+ char * dir_ent ;
854
+
855
+ afc_connection afc_conn ;
856
+ if (!afc_conn_p ) {
857
+ afc_conn_p = & afc_conn ;
858
+ AFCConnectionOpen (afcFd , 0 , & afc_conn_p );
859
+ }
860
+
861
+ printf ("%s\n" , dir );
862
+
863
+ afc_dictionary afc_dict ;
864
+ afc_dictionary * afc_dict_p = & afc_dict ;
865
+ AFCFileInfoOpen (afc_conn_p , dir , & afc_dict_p );
866
+
867
+ afc_directory afc_dir ;
868
+ afc_directory * afc_dir_p = & afc_dir ;
869
+ afc_error_t err = AFCDirectoryOpen (afc_conn_p , dir , & afc_dir_p );
870
+
871
+ if (err != 0 )
872
+ {
873
+ // Couldn't open dir - was probably a file
874
+ return ;
875
+ }
876
+
877
+ while (true) {
878
+ err = AFCDirectoryRead (afc_conn_p , afc_dir_p , & dir_ent );
879
+
880
+ if (!dir_ent )
881
+ break ;
882
+
883
+ if (strcmp (dir_ent , "." ) == 0 || strcmp (dir_ent , ".." ) == 0 )
884
+ continue ;
885
+
886
+ char * dir_joined = malloc (strlen (dir ) + strlen (dir_ent ) + 2 );
887
+ strcpy (dir_joined , dir );
888
+ if (dir_joined [strlen (dir )- 1 ] != '/' )
889
+ strcat (dir_joined , "/" );
890
+ strcat (dir_joined , dir_ent );
891
+ read_dir (afcFd , afc_conn_p , dir_joined );
892
+ free (dir_joined );
893
+ }
894
+
895
+ AFCDirectoryClose (afc_conn_p , afc_dir_p );
896
+ }
897
+
898
+
899
+ // Used to send files to app-specific sandbox (Documents dir)
900
+ service_conn_t start_house_arrest_service (AMDeviceRef device ) {
901
+ AMDeviceConnect (device );
902
+ assert (AMDeviceIsPaired (device ));
903
+ assert (AMDeviceValidatePairing (device ) == 0 );
904
+ assert (AMDeviceStartSession (device ) == 0 );
905
+
906
+ service_conn_t houseFd ;
907
+
908
+ if (bundle_id == NULL ) {
909
+ printf ("Bundle id is not specified\n" );
910
+ exit (1 );
911
+ }
912
+
913
+ CFStringRef cf_bundle_id = CFStringCreateWithCString (NULL , bundle_id , kCFStringEncodingASCII );
914
+ if (AMDeviceStartHouseArrestService (device , cf_bundle_id , 0 , & houseFd , 0 ) != 0 )
915
+ {
916
+ printf ("Unable to find bundle with id: %s\n" , bundle_id );
917
+ exit (1 );
918
+ }
919
+
920
+ assert (AMDeviceStopSession (device ) == 0 );
921
+ assert (AMDeviceDisconnect (device ) == 0 );
922
+ CFRelease (cf_bundle_id );
923
+
924
+ return houseFd ;
925
+ }
926
+
927
+ char * get_filename_from_path (char * path )
928
+ {
929
+ char * ptr = path + strlen (path );
930
+ while (ptr > path )
931
+ {
932
+ if (* ptr == '/' )
933
+ break ;
934
+ -- ptr ;
935
+ }
936
+ if (ptr + 1 >= path + strlen (path ))
937
+ return NULL ;
938
+ if (ptr == path )
939
+ return ptr ;
940
+ return ptr + 1 ;
941
+ }
942
+
943
+ void * read_file_to_memory (char * path , size_t * file_size )
944
+ {
945
+ struct stat buf ;
946
+ int err = stat (path , & buf );
947
+ if (err < 0 )
948
+ {
949
+ return NULL ;
950
+ }
951
+
952
+ * file_size = buf .st_size ;
953
+ FILE * fd = fopen (path , "r" );
954
+ char * content = malloc (* file_size );
955
+ if (fread (content , * file_size , 1 , fd ) != 1 )
956
+ {
957
+ fclose (fd );
958
+ return NULL ;
959
+ }
960
+ fclose (fd );
961
+ return content ;
962
+ }
963
+
964
+ void list_files (AMDeviceRef device )
965
+ {
966
+ service_conn_t houseFd = start_house_arrest_service (device );
967
+
968
+ afc_connection afc_conn ;
969
+ afc_connection * afc_conn_p = & afc_conn ;
970
+ AFCConnectionOpen (houseFd , 0 , & afc_conn_p );
971
+
972
+ read_dir (houseFd , afc_conn_p , "/" );
973
+ }
974
+
975
+ void upload_file (AMDeviceRef device ) {
976
+ service_conn_t houseFd = start_house_arrest_service (device );
977
+
978
+ afc_file_ref file_ref ;
979
+
980
+ afc_connection afc_conn ;
981
+ afc_connection * afc_conn_p = & afc_conn ;
982
+ AFCConnectionOpen (houseFd , 0 , & afc_conn_p );
983
+
984
+ // read_dir(houseFd, NULL, "/");
985
+
986
+ if (!target_filename )
987
+ {
988
+ target_filename = get_filename_from_path (upload_pathname );
989
+ }
990
+
991
+ size_t file_size ;
992
+ void * file_content = read_file_to_memory (upload_pathname , & file_size );
993
+
994
+ if (!file_content )
995
+ {
996
+ printf ("Could not open file: %s\n" , upload_pathname );
997
+ exit (-1 );
998
+ }
999
+
1000
+ // Make sure the directory was created
1001
+ {
1002
+ char * dirpath = strdup (target_filename );
1003
+ char * c = dirpath , * lastSlash = dirpath ;
1004
+ while (* c ) {
1005
+ if (* c == '/' ) {
1006
+ lastSlash = c ;
1007
+ }
1008
+ c ++ ;
1009
+ }
1010
+ * lastSlash = '\0' ;
1011
+ assert (AFCDirectoryCreate (afc_conn_p , dirpath ) == 0 );
1012
+ }
1013
+
1014
+
1015
+ int ret = AFCFileRefOpen (afc_conn_p , target_filename , 3 , & file_ref );
1016
+ if (ret == 0x000a ) {
1017
+ printf ("Cannot write to %s. Permission error.\n" , target_filename );
1018
+ exit (1 );
1019
+ }
1020
+ if (ret == 0x0009 ) {
1021
+ printf ("Target %s is a directory.\n" , target_filename );
1022
+ exit (1 );
1023
+ }
1024
+ assert (ret == 0 );
1025
+ assert (AFCFileRefWrite (afc_conn_p , file_ref , file_content , file_size ) == 0 );
1026
+ assert (AFCFileRefClose (afc_conn_p , file_ref ) == 0 );
1027
+ assert (AFCConnectionClose (afc_conn_p ) == 0 );
1028
+
1029
+ free (file_content );
1030
+ }
1031
+
846
1032
void handle_device (AMDeviceRef device ) {
847
1033
if (found_device ) return ; // handle one device only
848
1034
CFStringRef found_device_id = AMDeviceCopyDeviceIdentifier (device );
@@ -861,6 +1047,15 @@ void handle_device(AMDeviceRef device) {
861
1047
printf ("[....] Found device (%s).\n" , CFStringGetCStringPtr (found_device_id , CFStringGetSystemEncoding ()));
862
1048
exit (0 );
863
1049
}
1050
+
1051
+ if (command_only ) {
1052
+ if (strcmp ("list" , command ) == 0 ) {
1053
+ list_files (device );
1054
+ } else if (strcmp ("upload" , command ) == 0 ) {
1055
+ upload_file (device );
1056
+ }
1057
+ exit (0 );
1058
+ }
864
1059
865
1060
866
1061
CFRetain (device ); // don't know if this is necessary?
@@ -982,6 +1177,10 @@ void usage(const char* app) {
982
1177
" -m, --noinstall directly start debugging without app install (-d not required)\n"
983
1178
" -p, --port <number> port used for device, default: 12345 \n"
984
1179
" -r, --uninstall uninstall the app before install (do not use with -m; app cache and data are cleared) \n"
1180
+ " -1, --bundle_id <bundle id> specify bundle id for list and upload\n"
1181
+ " -l, --list list files\n"
1182
+ " -o, --upload <file> upload file\n"
1183
+ " -2, --to <target pathname> use together with upload file. specify target for upload\n"
985
1184
" -V, --version print the executable version \n" ,
986
1185
app );
987
1186
}
@@ -1007,11 +1206,15 @@ int main(int argc, char *argv[]) {
1007
1206
{ "noinstall" , no_argument , NULL , 'm' },
1008
1207
{ "port" , required_argument , NULL , 'p' },
1009
1208
{ "uninstall" , no_argument , NULL , 'r' },
1209
+ { "list" , no_argument , NULL , 'l' },
1210
+ { "bundle_id" , required_argument , NULL , '1' },
1211
+ { "upload" , required_argument , NULL , 'o' },
1212
+ { "to" , required_argument , NULL , '2' },
1010
1213
{ NULL , 0 , NULL , 0 },
1011
1214
};
1012
1215
char ch ;
1013
1216
1014
- while ((ch = getopt_long (argc , argv , "VmcdvunrIi :b:a:t:g:x:p:" , longopts , NULL )) != -1 )
1217
+ while ((ch = getopt_long (argc , argv , "VmcdvunlrIi :b:a:t:g:x:p:1:2:o :" , longopts , NULL )) != -1 )
1015
1218
{
1016
1219
switch (ch ) {
1017
1220
case 'm' :
@@ -1057,13 +1260,28 @@ int main(int argc, char *argv[]) {
1057
1260
case 'r' :
1058
1261
uninstall = 1 ;
1059
1262
break ;
1263
+ case '1' :
1264
+ bundle_id = optarg ;
1265
+ break ;
1266
+ case '2' :
1267
+ target_filename = optarg ;
1268
+ break ;
1269
+ case 'o' :
1270
+ command_only = true;
1271
+ upload_pathname = optarg ;
1272
+ command = "upload" ;
1273
+ break ;
1274
+ case 'l' :
1275
+ command_only = true;
1276
+ command = "list" ;
1277
+ break ;
1060
1278
default :
1061
1279
usage (argv [0 ]);
1062
1280
return exitcode_error ;
1063
1281
}
1064
1282
}
1065
1283
1066
- if (!app_path && !detect_only ) {
1284
+ if (!app_path && !detect_only && ! command_only ) {
1067
1285
usage (argv [0 ]);
1068
1286
exit (exitcode_error );
1069
1287
}
@@ -1097,3 +1315,4 @@ int main(int argc, char *argv[]) {
1097
1315
AMDeviceNotificationSubscribe (& device_callback , 0 , 0 , NULL , & notify );
1098
1316
CFRunLoopRun ();
1099
1317
}
1318
+
0 commit comments