@@ -1246,9 +1246,10 @@ CFStringRef copy_bundle_id(CFURLRef app_url)
1246
1246
return bundle_id;
1247
1247
}
1248
1248
1249
+ typedef enum { READ_DIR_FILE, READ_DIR_BEFORE_DIR, READ_DIR_AFTER_DIR } read_dir_cb_reason;
1249
1250
1250
1251
void read_dir (AFCConnectionRef afc_conn_p, const char * dir,
1251
- void (*callback)(AFCConnectionRef conn, const char *dir, int file ))
1252
+ void (*callback)(AFCConnectionRef conn, const char *dir, read_dir_cb_reason reason ))
1252
1253
{
1253
1254
char *dir_ent;
1254
1255
@@ -1271,13 +1272,7 @@ void read_dir(AFCConnectionRef afc_conn_p, const char* dir,
1271
1272
AFCKeyValueClose (afc_dict_p);
1272
1273
1273
1274
if (not_dir) {
1274
- NSLogOut (@" %@ " , [NSString stringWithUTF8String: dir]);
1275
- } else {
1276
- NSLogOut (@" %@ /" , [NSString stringWithUTF8String: dir]);
1277
- }
1278
-
1279
- if (not_dir) {
1280
- if (callback) (*callback)(afc_conn_p, dir, not_dir);
1275
+ if (callback) (*callback)(afc_conn_p, dir, READ_DIR_FILE);
1281
1276
return ;
1282
1277
}
1283
1278
@@ -1287,9 +1282,13 @@ void read_dir(AFCConnectionRef afc_conn_p, const char* dir,
1287
1282
if (err != 0 ) {
1288
1283
// Couldn't open dir - was probably a file
1289
1284
return ;
1290
- } else {
1291
- if (callback) (*callback)(afc_conn_p, dir, not_dir);
1292
1285
}
1286
+
1287
+ // Call the callback on the directory before processing its
1288
+ // contents. This is used by copy file callback, which needs to
1289
+ // create the directory on the host before attempting to copy
1290
+ // files into it.
1291
+ if (callback) (*callback)(afc_conn_p, dir, READ_DIR_BEFORE_DIR);
1293
1292
1294
1293
while (true ) {
1295
1294
err = AFCDirectoryRead (afc_conn_p, afc_dir_p, &dir_ent);
@@ -1310,6 +1309,11 @@ void read_dir(AFCConnectionRef afc_conn_p, const char* dir,
1310
1309
}
1311
1310
1312
1311
AFCDirectoryClose (afc_conn_p, afc_dir_p);
1312
+
1313
+ // Call the callback on the directory after processing its
1314
+ // contents. This is used by the rmtree callback because it needs
1315
+ // to delete the directory's contents before the directory itself
1316
+ if (callback) (*callback)(afc_conn_p, dir, READ_DIR_AFTER_DIR);
1313
1317
}
1314
1318
1315
1319
@@ -1388,11 +1392,21 @@ AFCConnectionRef start_house_arrest_service(AMDeviceRef device) {
1388
1392
fclose (fd);
1389
1393
return content;
1390
1394
}
1395
+
1396
+ void list_files_callback (AFCConnectionRef conn, const char *name, read_dir_cb_reason reason)
1397
+ {
1398
+ if (reason == READ_DIR_FILE) {
1399
+ NSLogOut (@" %@ " , [NSString stringWithUTF8String: name]);
1400
+ } else if (reason == READ_DIR_BEFORE_DIR) {
1401
+ NSLogOut (@" %@ /" , [NSString stringWithUTF8String: name]);
1402
+ }
1403
+ }
1404
+
1391
1405
void list_files (AMDeviceRef device)
1392
1406
{
1393
1407
AFCConnectionRef afc_conn_p = start_house_arrest_service (device);
1394
1408
assert (afc_conn_p);
1395
- read_dir (afc_conn_p, list_root?list_root:" /" , NULL );
1409
+ read_dir (afc_conn_p, list_root?list_root:" /" , list_files_callback );
1396
1410
check_error (AFCConnectionClose (afc_conn_p));
1397
1411
}
1398
1412
@@ -1467,47 +1481,52 @@ void list_bundle_id(AMDeviceRef device)
1467
1481
check_error (AMDeviceDisconnect (device));
1468
1482
}
1469
1483
1470
- void copy_file_callback (AFCConnectionRef afc_conn_p, const char *name,int file )
1484
+ void copy_file_callback (AFCConnectionRef afc_conn_p, const char *name, read_dir_cb_reason reason )
1471
1485
{
1472
1486
const char *local_name=name;
1473
1487
1474
1488
if (*local_name==' /' ) local_name++;
1475
1489
1476
1490
if (*local_name==' \0 ' ) return ;
1477
1491
1478
- if (file) {
1479
- afc_file_ref fref;
1480
- int err = AFCFileRefOpen (afc_conn_p,name,1 ,&fref);
1492
+ if (reason == READ_DIR_FILE) {
1493
+ NSLogOut (@" %@ " , [NSString stringWithUTF8String: name]);
1494
+ afc_file_ref fref;
1495
+ int err = AFCFileRefOpen (afc_conn_p,name,1 ,&fref);
1481
1496
1482
- if (err) {
1483
- fprintf (stderr," AFCFileRefOpen(\" %s \" ) failed: %d \n " ,name,err);
1484
- return ;
1485
- }
1497
+ if (err) {
1498
+ fprintf (stderr," AFCFileRefOpen(\" %s \" ) failed: %d \n " ,name,err);
1499
+ return ;
1500
+ }
1486
1501
1487
- FILE *fp = fopen (local_name," w" );
1502
+ FILE *fp = fopen (local_name," w" );
1488
1503
1489
- if (fp==NULL ) {
1490
- fprintf (stderr," fopen(\" %s \" ,\" w\" ) failer: %s \n " ,local_name,strerror (errno));
1491
- AFCFileRefClose (afc_conn_p,fref);
1492
- return ;
1493
- }
1504
+ if (fp==NULL ) {
1505
+ fprintf (stderr," fopen(\" %s \" ,\" w\" ) failer: %s \n " ,local_name,strerror (errno));
1506
+ AFCFileRefClose (afc_conn_p,fref);
1507
+ return ;
1508
+ }
1494
1509
1495
- char buf[4096 ];
1496
- size_t sz=sizeof (buf);
1510
+ char buf[4096 ];
1511
+ size_t sz=sizeof (buf);
1497
1512
1498
- while (AFCFileRefRead (afc_conn_p,fref,buf,&sz)==0 && sz) {
1499
- fwrite (buf,sz,1 ,fp);
1500
- sz = sizeof (buf);
1501
- }
1513
+ while (AFCFileRefRead (afc_conn_p,fref,buf,&sz)==0 && sz) {
1514
+ fwrite (buf,sz,1 ,fp);
1515
+ sz = sizeof (buf);
1516
+ }
1502
1517
1503
- AFCFileRefClose (afc_conn_p,fref);
1504
- fclose (fp);
1505
- } else {
1506
- if (mkdir (local_name,0777 ) && errno!=EEXIST)
1507
- fprintf (stderr," mkdir(\" %s \" ) failed: %s \n " ,local_name,strerror (errno));
1518
+ AFCFileRefClose (afc_conn_p,fref);
1519
+ fclose (fp);
1520
+
1521
+ } else if (reason == READ_DIR_BEFORE_DIR) {
1522
+ NSLogOut (@" %@ /" , [NSString stringWithUTF8String: name]);
1523
+ if (mkdir (local_name,0777 ) && errno!=EEXIST) {
1524
+ fprintf (stderr," mkdir(\" %s \" ) failed: %s \n " ,local_name,strerror (errno));
1525
+ }
1508
1526
}
1509
1527
}
1510
1528
1529
+
1511
1530
void download_tree (AMDeviceRef device)
1512
1531
{
1513
1532
AFCConnectionRef afc_conn_p = start_house_arrest_service (device);
@@ -1547,7 +1566,6 @@ void upload_file(AMDeviceRef device)
1547
1566
{
1548
1567
AFCConnectionRef afc_conn_p = start_house_arrest_service (device);
1549
1568
assert (afc_conn_p);
1550
- // read_dir(houseFd, NULL, "/", NULL);
1551
1569
1552
1570
if (!target_filename)
1553
1571
{
@@ -1578,8 +1596,6 @@ void upload_single_file(AMDeviceRef device, AFCConnectionRef afc_conn_p, NSStrin
1578
1596
1579
1597
afc_file_ref file_ref;
1580
1598
1581
- // read_dir(houseFd, NULL, "/", NULL);
1582
-
1583
1599
size_t file_size;
1584
1600
void * file_content = read_file_to_memory ([sourcePath fileSystemRepresentation ], &file_size);
1585
1601
@@ -1643,6 +1659,23 @@ void remove_path(AMDeviceRef device) {
1643
1659
check_error (AFCConnectionClose (afc_conn_p));
1644
1660
}
1645
1661
1662
+ // Handles the READ_DIR_AFTER_DIR callback so that we delete the contents of the
1663
+ // directory before the directory itself
1664
+ void rmtree_callback (AFCConnectionRef conn, const char *name, read_dir_cb_reason reason)
1665
+ {
1666
+ if (reason == READ_DIR_FILE || reason == READ_DIR_AFTER_DIR) {
1667
+ NSLogVerbose (@" Deleting %s " , name);
1668
+ check_error (AFCRemovePath (conn, name));
1669
+ }
1670
+ }
1671
+
1672
+ void rmtree (AMDeviceRef device) {
1673
+ AFCConnectionRef afc_conn_p = start_house_arrest_service (device);
1674
+ assert (afc_conn_p);
1675
+ read_dir (afc_conn_p, target_filename, rmtree_callback);
1676
+ check_error (AFCConnectionClose (afc_conn_p));
1677
+ }
1678
+
1646
1679
void uninstall_app (AMDeviceRef device) {
1647
1680
CFRetain (device); // don't know if this is necessary?
1648
1681
@@ -1722,6 +1755,8 @@ void handle_device(AMDeviceRef device) {
1722
1755
make_directory (device);
1723
1756
} else if (strcmp (" rm" , command) == 0 ) {
1724
1757
remove_path (device);
1758
+ } else if (strcmp (" rmtree" , command) == 0 ) {
1759
+ rmtree (device);
1725
1760
} else if (strcmp (" exists" , command) == 0 ) {
1726
1761
exit (app_exists (device));
1727
1762
} else if (strcmp (" uninstall_only" , command) == 0 ) {
@@ -1968,6 +2003,7 @@ void usage(const char* app) {
1968
2003
@" -2, --to <target pathname> use together with up/download file/tree. specify target\n "
1969
2004
@" -D, --mkdir <dir> make directory on device\n "
1970
2005
@" -R, --rm <path> remove file or directory on device (directories must be empty)\n "
2006
+ @" -X, --rmtree <path> remove directory and all contained files recursively on device\n "
1971
2007
@" -V, --version print the executable version \n "
1972
2008
@" -e, --exists check if the app with given bundle_id is installed or not \n "
1973
2009
@" -B, --list_bundle_id list bundle_id \n "
@@ -2020,6 +2056,7 @@ int main(int argc, char *argv[]) {
2020
2056
{ " to" , required_argument, NULL , ' 2' },
2021
2057
{ " mkdir" , required_argument, NULL , ' D' },
2022
2058
{ " rm" , required_argument, NULL , ' R' },
2059
+ { " rmtree" ,required_argument, NULL , ' X' },
2023
2060
{ " exists" , no_argument, NULL , ' e' },
2024
2061
{ " list_bundle_id" , no_argument, NULL , ' B' },
2025
2062
{ " no-wifi" , no_argument, NULL , ' W' },
@@ -2033,7 +2070,7 @@ int main(int argc, char *argv[]) {
2033
2070
};
2034
2071
int ch;
2035
2072
2036
- while ((ch = getopt_long (argc, argv, " VmcdvunrILeD:R:i:b:a:t:p:1:2:o:l:w:9BWjNs:OE:CA:" , longopts, NULL )) != -1 )
2073
+ while ((ch = getopt_long (argc, argv, " VmcdvunrILeD:R:X: i:b:a:t:p:1:2:o:l:w:9BWjNs:OE:CA:" , longopts, NULL )) != -1 )
2037
2074
{
2038
2075
switch (ch) {
2039
2076
case ' m' :
@@ -2128,6 +2165,11 @@ int main(int argc, char *argv[]) {
2128
2165
target_filename = optarg;
2129
2166
command = " rm" ;
2130
2167
break ;
2168
+ case ' X' :
2169
+ command_only = true ;
2170
+ target_filename = optarg;
2171
+ command = " rmtree" ;
2172
+ break ;
2131
2173
case ' e' :
2132
2174
command_only = true ;
2133
2175
command = " exists" ;
0 commit comments