Skip to content

Commit b55ad12

Browse files
ptc-shuntgabebear
authored andcommitted
Rmtree command (#440)
* Added --rmtree command for recursive directory deletion. Generalized the read_dir function to invoke the callback both before and after processing the contents of a directory. Tidied up indentation in copy_file_callback. * Added missing call to check_error.
1 parent db36af1 commit b55ad12

File tree

1 file changed

+82
-40
lines changed

1 file changed

+82
-40
lines changed

src/ios-deploy/ios-deploy.m

Lines changed: 82 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,9 +1246,10 @@ CFStringRef copy_bundle_id(CFURLRef app_url)
12461246
return bundle_id;
12471247
}
12481248

1249+
typedef enum { READ_DIR_FILE, READ_DIR_BEFORE_DIR, READ_DIR_AFTER_DIR } read_dir_cb_reason;
12491250

12501251
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))
12521253
{
12531254
char *dir_ent;
12541255

@@ -1271,13 +1272,7 @@ void read_dir(AFCConnectionRef afc_conn_p, const char* dir,
12711272
AFCKeyValueClose(afc_dict_p);
12721273

12731274
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);
12811276
return;
12821277
}
12831278

@@ -1287,9 +1282,13 @@ void read_dir(AFCConnectionRef afc_conn_p, const char* dir,
12871282
if (err != 0) {
12881283
// Couldn't open dir - was probably a file
12891284
return;
1290-
} else {
1291-
if (callback) (*callback)(afc_conn_p, dir, not_dir);
12921285
}
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);
12931292

12941293
while(true) {
12951294
err = AFCDirectoryRead(afc_conn_p, afc_dir_p, &dir_ent);
@@ -1310,6 +1309,11 @@ void read_dir(AFCConnectionRef afc_conn_p, const char* dir,
13101309
}
13111310

13121311
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);
13131317
}
13141318

13151319

@@ -1388,11 +1392,21 @@ AFCConnectionRef start_house_arrest_service(AMDeviceRef device) {
13881392
fclose(fd);
13891393
return content;
13901394
}
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+
13911405
void list_files(AMDeviceRef device)
13921406
{
13931407
AFCConnectionRef afc_conn_p = start_house_arrest_service(device);
13941408
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);
13961410
check_error(AFCConnectionClose(afc_conn_p));
13971411
}
13981412

@@ -1467,47 +1481,52 @@ void list_bundle_id(AMDeviceRef device)
14671481
check_error(AMDeviceDisconnect(device));
14681482
}
14691483

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)
14711485
{
14721486
const char *local_name=name;
14731487

14741488
if (*local_name=='/') local_name++;
14751489

14761490
if (*local_name=='\0') return;
14771491

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);
14811496

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+
}
14861501

1487-
FILE *fp = fopen(local_name,"w");
1502+
FILE *fp = fopen(local_name,"w");
14881503

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+
}
14941509

1495-
char buf[4096];
1496-
size_t sz=sizeof(buf);
1510+
char buf[4096];
1511+
size_t sz=sizeof(buf);
14971512

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+
}
15021517

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+
}
15081526
}
15091527
}
15101528

1529+
15111530
void download_tree(AMDeviceRef device)
15121531
{
15131532
AFCConnectionRef afc_conn_p = start_house_arrest_service(device);
@@ -1547,7 +1566,6 @@ void upload_file(AMDeviceRef device)
15471566
{
15481567
AFCConnectionRef afc_conn_p = start_house_arrest_service(device);
15491568
assert(afc_conn_p);
1550-
// read_dir(houseFd, NULL, "/", NULL);
15511569

15521570
if (!target_filename)
15531571
{
@@ -1578,8 +1596,6 @@ void upload_single_file(AMDeviceRef device, AFCConnectionRef afc_conn_p, NSStrin
15781596

15791597
afc_file_ref file_ref;
15801598

1581-
// read_dir(houseFd, NULL, "/", NULL);
1582-
15831599
size_t file_size;
15841600
void* file_content = read_file_to_memory([sourcePath fileSystemRepresentation], &file_size);
15851601

@@ -1643,6 +1659,23 @@ void remove_path(AMDeviceRef device) {
16431659
check_error(AFCConnectionClose(afc_conn_p));
16441660
}
16451661

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+
16461679
void uninstall_app(AMDeviceRef device) {
16471680
CFRetain(device); // don't know if this is necessary?
16481681

@@ -1722,6 +1755,8 @@ void handle_device(AMDeviceRef device) {
17221755
make_directory(device);
17231756
} else if (strcmp("rm", command) == 0) {
17241757
remove_path(device);
1758+
} else if (strcmp("rmtree", command) == 0) {
1759+
rmtree(device);
17251760
} else if (strcmp("exists", command) == 0) {
17261761
exit(app_exists(device));
17271762
} else if (strcmp("uninstall_only", command) == 0) {
@@ -1968,6 +2003,7 @@ void usage(const char* app) {
19682003
@" -2, --to <target pathname> use together with up/download file/tree. specify target\n"
19692004
@" -D, --mkdir <dir> make directory on device\n"
19702005
@" -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"
19712007
@" -V, --version print the executable version \n"
19722008
@" -e, --exists check if the app with given bundle_id is installed or not \n"
19732009
@" -B, --list_bundle_id list bundle_id \n"
@@ -2020,6 +2056,7 @@ int main(int argc, char *argv[]) {
20202056
{ "to", required_argument, NULL, '2'},
20212057
{ "mkdir", required_argument, NULL, 'D'},
20222058
{ "rm", required_argument, NULL, 'R'},
2059+
{ "rmtree",required_argument, NULL, 'X'},
20232060
{ "exists", no_argument, NULL, 'e'},
20242061
{ "list_bundle_id", no_argument, NULL, 'B'},
20252062
{ "no-wifi", no_argument, NULL, 'W'},
@@ -2033,7 +2070,7 @@ int main(int argc, char *argv[]) {
20332070
};
20342071
int ch;
20352072

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)
20372074
{
20382075
switch (ch) {
20392076
case 'm':
@@ -2128,6 +2165,11 @@ int main(int argc, char *argv[]) {
21282165
target_filename = optarg;
21292166
command = "rm";
21302167
break;
2168+
case 'X':
2169+
command_only = true;
2170+
target_filename = optarg;
2171+
command = "rmtree";
2172+
break;
21312173
case 'e':
21322174
command_only = true;
21332175
command = "exists";

0 commit comments

Comments
 (0)