From 3d2ef976694bf60c754e4127c8f4eb1251fc5bff Mon Sep 17 00:00:00 2001 From: tomriddly Date: Thu, 2 May 2024 13:53:06 +0800 Subject: tools/afcclient: get/put operations use '-f' to allow overwrite, '-r' to allow recursive Signed-off-by: tomriddly --- tools/afcclient.c | 183 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 142 insertions(+), 41 deletions(-) diff --git a/tools/afcclient.c b/tools/afcclient.c index adfb1ba..1cd6858 100644 --- a/tools/afcclient.c +++ b/tools/afcclient.c @@ -91,6 +91,16 @@ static idevice_subscription_context_t context = NULL; static char* curdir = NULL; static size_t curdir_len = 0; +static int file_exists(const char* path) +{ + struct stat tst; +#ifdef WIN32 + return (stat(path, &tst) == 0); +#else + return (lstat(path, &tst) == 0); +#endif +} + static int is_directory(const char* path) { struct stat tst; @@ -686,7 +696,7 @@ static void handle_remove(afc_client_t afc, int argc, char** argv) } } -static uint8_t get_single_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint64_t file_size) +static uint8_t get_single_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint64_t file_size, uint8_t force_overwrite) { uint64_t fh = 0; afc_error_t err = afc_file_open(afc, srcpath, AFC_FOPEN_RDONLY, &fh); @@ -694,6 +704,10 @@ static uint8_t get_single_file(afc_client_t afc, const char *srcpath, const char printf("Error: Failed to open file '%s': %s (%d)\n", srcpath, afc_strerror(err), err); return 0; } + if (file_exists(dstpath) && !force_overwrite) { + printf("Error: Failed to overwrite existing file without '-f' option: %s\n", dstpath); + return 0; + } FILE *f = fopen(dstpath, "wb"); if (!f) { printf("Error: Failed to open local file '%s': %s\n", dstpath, strerror(errno)); @@ -757,7 +771,7 @@ static uint8_t get_single_file(afc_client_t afc, const char *srcpath, const char return succeed; } -static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpath) +static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite, uint8_t recursive_get) { char **info = NULL; uint64_t file_size = 0; @@ -784,6 +798,10 @@ static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpa } uint8_t succeed = 1; if (is_dir) { + if (!recursive_get) { + printf("Error: Failed to get a directory without '-r' option: %s\n", srcpath); + return 0; + } char **entries = NULL; err = afc_read_directory(afc, srcpath, &entries); if (err != AFC_E_SUCCESS) { @@ -792,9 +810,15 @@ static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpa } char **p = entries; size_t srcpath_len = strlen(srcpath); - int srcpath_is_root = strcmp(srcpath, "/") == 0; - if (!is_directory(dstpath) && mkdir(dstpath, 0777) != 0) { - printf("Error: Failed to create folder '%s': %s\n", dstpath, strerror(errno)); + uint8_t srcpath_is_root = strcmp(srcpath, "/") == 0; + // if directory exists, check force_overwrite flag + if (is_directory(dstpath)) { + if (!force_overwrite) { + printf("Error: Failed to write into existing directory without '-f': %s\n", dstpath); + return 0; + } + } else if (mkdir(dstpath, 0777) != 0) { + printf("Error: Failed to create directory '%s': %s\n", dstpath, strerror(errno)); afc_dictionary_free(entries); return 0; } @@ -803,17 +827,22 @@ static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpa p++; continue; } - size_t len = srcpath_len + 1 + strlen(*p) + 1; + size_t len = srcpath_is_root ? strlen(*p) + 1 : srcpath_len + 1 + strlen(*p) + 1; char *testpath = (char *) malloc(len); if (srcpath_is_root) { snprintf(testpath, len, "/%s", *p); } else { snprintf(testpath, len, "%s/%s", srcpath, *p); } - size_t dst_len = strlen(dstpath) + 1 + strlen(*p) + 1; + uint8_t dst_is_root = strcmp(srcpath, "/") == 0; + size_t dst_len = dst_is_root ? strlen(*p) + 1 : strlen(dstpath) + 1 + strlen(*p) + 1; char *newdst = (char *) malloc(dst_len); - snprintf(newdst, dst_len, "%s/%s", dstpath, *p); - if (!get_file(afc, testpath, newdst)) { + if (dst_is_root) { + snprintf(newdst, dst_len, "/%s", *p); + } else { + snprintf(newdst, dst_len, "%s/%s", dstpath, *p); + } + if (!get_file(afc, testpath, newdst, force_overwrite, recursive_get)) { succeed = 0; break; } @@ -823,21 +852,38 @@ static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpa } afc_dictionary_free(entries); } else { - succeed = get_single_file(afc, srcpath, dstpath, file_size); + succeed = get_single_file(afc, srcpath, dstpath, file_size, force_overwrite); } return succeed; } static void handle_get(afc_client_t afc, int argc, char **argv) { - if (argc < 1 || argc > 2) { + if (argc < 1) { printf("Error: Invalid number of arguments\n"); return; } + uint8_t force_overwrite = 0, recursive_get = 0; char *srcpath = NULL; char *dstpath = NULL; - if (argc == 1) { - char *tmp = strdup(argv[0]); + int i = 0; + for ( ; i < argc; i++) { + if (!strcmp(argv[i], "--")) { + i++; + break; + } else if (!strcmp(argv[i], "-r")) { + recursive_get = 1; + } else if (!strcmp(argv[i], "-f")) { + force_overwrite = 1; + } else if (!strcmp(argv[i], "-rf") || !strcmp(argv[i], "-fr")) { + recursive_get = 1; + force_overwrite = 1; + } else { + break; + } + } + if (argc - i == 1) { + char *tmp = strdup(argv[i]); size_t src_len = strlen(tmp); if (src_len > 1 && tmp[src_len - 1] == '/') { tmp[src_len - 1] = '\0'; @@ -845,14 +891,14 @@ static void handle_get(afc_client_t afc, int argc, char **argv) srcpath = get_absolute_path(tmp); dstpath = strdup(path_get_basename(tmp)); free(tmp); - } else { - char *tmp = strdup(argv[0]); + } else if (argc - i == 2) { + char *tmp = strdup(argv[i]); size_t src_len = strlen(tmp); if (src_len > 1 && tmp[src_len - 1] == '/') { tmp[src_len - 1] = '\0'; } srcpath = get_absolute_path(tmp); - dstpath = strdup(argv[1]); + dstpath = strdup(argv[i + 1]); size_t dst_len = strlen(dstpath); if (dst_len > 1 && dstpath[dst_len - 1] == '/') { dstpath[dst_len - 1] = '\0'; @@ -863,23 +909,38 @@ static void handle_get(afc_client_t afc, int argc, char **argv) // target is a directory, put file under this target if (is_directory(dstpath)) { const char *basen = path_get_basename(argv[0]); - size_t len = strlen(dstpath) + 1 + strlen(basen) + 1; + uint8_t dst_is_root = strcmp(dstpath, "/") == 0; + size_t len = dst_is_root ? (strlen(basen) + 1) : (strlen(dstpath) + 1 + strlen(basen) + 1); char *newdst = (char *) malloc(len); - snprintf(newdst, len, "%s/%s", dstpath, basen); - get_file(afc, srcpath, newdst); + if (dst_is_root) { + snprintf(newdst, len, "/%s", basen); + } else { + snprintf(newdst, len, "%s/%s", dstpath, basen); + } + get_file(afc, srcpath, newdst, force_overwrite, recursive_get); free(srcpath); free(newdst); free(dstpath); } else { // target is not a dir or does not exist, just try to create or rewrite it - get_file(afc, srcpath, dstpath); + get_file(afc, srcpath, dstpath, force_overwrite, recursive_get); free(srcpath); free(dstpath); } } -static uint8_t put_single_file(afc_client_t afc, const char *srcpath, const char *dstpath) +static uint8_t put_single_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite) { + char **info = NULL; + afc_error_t ret = afc_get_file_info(afc, dstpath, &info); + // file exists, only overwrite with '-f' option was set + if (ret == AFC_E_SUCCESS && info) { + afc_dictionary_free(info); + if (!force_overwrite) { + printf("Error: Failed to write into existing file without '-f' option: %s\n", dstpath); + return 0; + } + } FILE *f = fopen(srcpath, "rb"); if (!f) { printf("Error: Failed to open local file '%s': %s\n", srcpath, strerror(errno)); @@ -949,20 +1010,27 @@ static uint8_t put_single_file(afc_client_t afc, const char *srcpath, const char return succeed; } -static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpath) +static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpath, uint8_t force_overwrite, uint8_t recursive_put) { if (is_directory(srcpath)) { + if (!recursive_put) { + printf("Error: Failed to put directory without '-r' option: %s\n", srcpath); + return 0; + } char **info = NULL; afc_error_t err = afc_get_file_info(afc, dstpath, &info); //create if target directory does not exist + afc_dictionary_free(info); if (err == AFC_E_OBJECT_NOT_FOUND) { err = afc_make_directory(afc, dstpath); if (err != AFC_E_SUCCESS) { printf("Error: Failed to create directory '%s': %s (%d)\n", dstpath, afc_strerror(err), err); return 0; } + } else if (!force_overwrite) { + printf("Error: Failed to put existing directory without '-f' option: %s\n", dstpath); + return 0; } - afc_dictionary_free(info); afc_get_file_info(afc, dstpath, &info); uint8_t is_dir = 0; if (info) { @@ -978,7 +1046,7 @@ static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpa afc_dictionary_free(info); } if (!is_dir) { - printf("Error: Failed to create or access directory: '%s'", dstpath); + printf("Error: Failed to create or access directory: '%s'\n", dstpath); return 0; } @@ -992,10 +1060,15 @@ static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpa } char *fpath = string_build_path(srcpath, ep->d_name, NULL); if (fpath) { - size_t len = strlen(srcpath) + 1 + strlen(ep->d_name) + 1; + uint8_t dst_is_root = strcmp(dstpath, "/") == 0; + size_t len = dst_is_root ? strlen(ep->d_name) + 1 : strlen(dstpath) + 1 + strlen(ep->d_name) + 1; char *newdst = (char *) malloc(len); - snprintf(newdst, len, "%s/%s", dstpath, ep->d_name); - if (!put_file(afc, fpath, newdst)) { + if (dst_is_root) { + snprintf(newdst, len, "/%s", ep->d_name); + } else { + snprintf(newdst, len, "%s/%s", dstpath, ep->d_name); + } + if (!put_file(afc, fpath, newdst, force_overwrite, recursive_put)) { free(newdst); free(fpath); return 0; @@ -1006,44 +1079,67 @@ static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpa } closedir(cur_dir); } else { - printf("Error: Failed to visit directory: '%s': %s", srcpath, strerror(errno)); + printf("Error: Failed to visit directory: '%s': %s\n", srcpath, strerror(errno)); return 0; } } else { - return put_single_file(afc, srcpath, dstpath); + return put_single_file(afc, srcpath, dstpath, force_overwrite); } return 1; } static void handle_put(afc_client_t afc, int argc, char **argv) { - if (argc < 1 || argc > 2) { + if (argc < 1) { printf("Error: Invalid number of arguments\n"); return; } - - char *srcpath = strdup(argv[0]); + int i = 0; + uint8_t force_overwrite = 0, recursive_put = 0; + for ( ; i < argc; i++) { + if (!strcmp(argv[i], "--")) { + i++; + break; + } else if (!strcmp(argv[i], "-r")) { + recursive_put = 1; + } else if (!strcmp(argv[i], "-f")) { + force_overwrite = 1; + } else if (!strcmp(argv[i], "-rf") || !strcmp(argv[i], "-fr")) { + recursive_put = 1; + force_overwrite = 1; + } else { + break; + } + } + if (i >= argc) { + printf("Error: Invalid number of arguments\n"); + return; + } + char *srcpath = strdup(argv[i]); size_t src_len = strlen(srcpath); if (src_len > 1 && srcpath[src_len - 1] == '/') { srcpath[src_len - 1] = '\0'; } char *dstpath = NULL; - if (argc == 1) { + if (argc - i == 1) { dstpath = get_absolute_path(path_get_basename(srcpath)); - } else { - char *tmp = strdup(argv[1]); + } else if (argc - i == 2) { + char *tmp = strdup(argv[i + 1]); size_t dst_len = strlen(tmp); if (dst_len > 1 && tmp[dst_len - 1] == '/') { tmp[dst_len - 1] = '\0'; } dstpath = get_absolute_path(tmp); free(tmp); + } else { + printf("Error: Invalid number of arguments\n"); + return; } char **info = NULL; afc_error_t err = afc_get_file_info(afc, dstpath, &info); // target does not exist, put directly if (err == AFC_E_OBJECT_NOT_FOUND) { - put_file(afc, srcpath, dstpath); + put_file(afc, srcpath, dstpath, force_overwrite, recursive_put); free(srcpath); free(dstpath); } else { @@ -1060,19 +1156,24 @@ static void handle_put(afc_client_t afc, int argc, char **argv) } afc_dictionary_free(info); } - // target is a dir, put under this target + // target is a directory, try to put under this directory if (is_dir) { const char *basen = path_get_basename(srcpath); - size_t len = strlen(dstpath) + 1 + strlen(basen) + 1; + uint8_t dst_is_root = strcmp(dstpath, "/") == 0; + size_t len = dst_is_root ? strlen(basen) + 1 : strlen(dstpath) + 1 + strlen(basen) + 1; char *newdst = (char *) malloc(len); - snprintf(newdst, len, "%s/%s", dstpath, basen); + if (dst_is_root) { + snprintf(newdst, len, "/%s", basen); + } else { + snprintf(newdst, len, "%s/%s", dstpath, basen); + } free(dstpath); dstpath = get_absolute_path(newdst); free(newdst); - put_file(afc, srcpath, dstpath); + put_file(afc, srcpath, dstpath, force_overwrite, recursive_put); } else { //target is common file, rewrite it - put_file(afc, srcpath, dstpath); + put_file(afc, srcpath, dstpath, force_overwrite, recursive_put); } free(srcpath); free(dstpath); -- cgit v1.1-32-gdbae