summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/afcclient.c295
1 files changed, 211 insertions, 84 deletions
diff --git a/tools/afcclient.c b/tools/afcclient.c
index 826ad5b..adfb1ba 100644
--- a/tools/afcclient.c
+++ b/tools/afcclient.c
@@ -36,6 +36,7 @@
36#include <signal.h> 36#include <signal.h>
37#include <ctype.h> 37#include <ctype.h>
38#include <unistd.h> 38#include <unistd.h>
39#include <dirent.h>
39 40
40#ifdef WIN32 41#ifdef WIN32
41#include <windows.h> 42#include <windows.h>
@@ -70,6 +71,7 @@
70#include <plist/plist.h> 71#include <plist/plist.h>
71 72
72#include <libimobiledevice-glue/termcolors.h> 73#include <libimobiledevice-glue/termcolors.h>
74#include <libimobiledevice-glue/utils.h>
73 75
74#undef st_mtime 76#undef st_mtime
75#undef st_birthtime 77#undef st_birthtime
@@ -759,7 +761,11 @@ static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpa
759{ 761{
760 char **info = NULL; 762 char **info = NULL;
761 uint64_t file_size = 0; 763 uint64_t file_size = 0;
762 afc_get_file_info(afc, srcpath, &info); 764 afc_error_t err = afc_get_file_info(afc, srcpath, &info);
765 if (err == AFC_E_OBJECT_NOT_FOUND) {
766 printf("Error: Failed to read from file '%s': %s (%d)\n", srcpath, afc_strerror(err), err);
767 return 0;
768 }
763 uint8_t is_dir = 0; 769 uint8_t is_dir = 0;
764 if (info) { 770 if (info) {
765 char **p = info; 771 char **p = info;
@@ -779,7 +785,7 @@ static uint8_t get_file(afc_client_t afc, const char *srcpath, const char *dstpa
779 uint8_t succeed = 1; 785 uint8_t succeed = 1;
780 if (is_dir) { 786 if (is_dir) {
781 char **entries = NULL; 787 char **entries = NULL;
782 afc_error_t err = afc_read_directory(afc, srcpath, &entries); 788 err = afc_read_directory(afc, srcpath, &entries);
783 if (err != AFC_E_SUCCESS) { 789 if (err != AFC_E_SUCCESS) {
784 printf("Error: Failed to list '%s': %s (%d)\n", srcpath, afc_strerror(err), err); 790 printf("Error: Failed to list '%s': %s (%d)\n", srcpath, afc_strerror(err), err);
785 return 0; 791 return 0;
@@ -830,18 +836,31 @@ static void handle_get(afc_client_t afc, int argc, char **argv)
830 } 836 }
831 char *srcpath = NULL; 837 char *srcpath = NULL;
832 char *dstpath = NULL; 838 char *dstpath = NULL;
833 size_t src_len = strlen(argv[0]);
834 if (strcmp(argv[0], "/") != 0 && argv[0][src_len - 1] == '/') {
835 argv[0][src_len - 1] = '\0';
836 }
837 if (argc == 1) { 839 if (argc == 1) {
838 srcpath = get_absolute_path(argv[0]); 840 char *tmp = strdup(argv[0]);
839 dstpath = strdup(path_get_basename(argv[0])); 841 size_t src_len = strlen(tmp);
842 if (src_len > 1 && tmp[src_len - 1] == '/') {
843 tmp[src_len - 1] = '\0';
844 }
845 srcpath = get_absolute_path(tmp);
846 dstpath = strdup(path_get_basename(tmp));
847 free(tmp);
840 } else { 848 } else {
841 srcpath = get_absolute_path(argv[0]); 849 char *tmp = strdup(argv[0]);
850 size_t src_len = strlen(tmp);
851 if (src_len > 1 && tmp[src_len - 1] == '/') {
852 tmp[src_len - 1] = '\0';
853 }
854 srcpath = get_absolute_path(tmp);
842 dstpath = strdup(argv[1]); 855 dstpath = strdup(argv[1]);
856 size_t dst_len = strlen(dstpath);
857 if (dst_len > 1 && dstpath[dst_len - 1] == '/') {
858 dstpath[dst_len - 1] = '\0';
859 }
860 free(tmp);
843 } 861 }
844 862
863 // target is a directory, put file under this target
845 if (is_directory(dstpath)) { 864 if (is_directory(dstpath)) {
846 const char *basen = path_get_basename(argv[0]); 865 const char *basen = path_get_basename(argv[0]);
847 size_t len = strlen(dstpath) + 1 + strlen(basen) + 1; 866 size_t len = strlen(dstpath) + 1 + strlen(basen) + 1;
@@ -852,104 +871,212 @@ static void handle_get(afc_client_t afc, int argc, char **argv)
852 free(newdst); 871 free(newdst);
853 free(dstpath); 872 free(dstpath);
854 } else { 873 } else {
874 // target is not a dir or does not exist, just try to create or rewrite it
855 get_file(afc, srcpath, dstpath); 875 get_file(afc, srcpath, dstpath);
856 free(srcpath); 876 free(srcpath);
857 free(dstpath); 877 free(dstpath);
858 } 878 }
859} 879}
860 880
861static void handle_put(afc_client_t afc, int argc, char** argv) 881static uint8_t put_single_file(afc_client_t afc, const char *srcpath, const char *dstpath)
882{
883 FILE *f = fopen(srcpath, "rb");
884 if (!f) {
885 printf("Error: Failed to open local file '%s': %s\n", srcpath, strerror(errno));
886 return 0;
887 }
888 struct timeval t1;
889 struct timeval t2;
890 struct timeval tdiff;
891 struct stat fst;
892 int progress = 0;
893 size_t bufsize = 0x100000;
894 char *buf = malloc(bufsize);
895
896 fstat(fileno(f), &fst);
897 if (fst.st_size >= 0x400000) {
898 progress = 1;
899 gettimeofday(&t1, NULL);
900 }
901 size_t total = 0;
902 int lastprog = 0;
903 uint64_t fh = 0;
904 afc_error_t err = afc_file_open(afc, dstpath, AFC_FOPEN_RW, &fh);
905 uint8_t succeed = 1;
906 while (err == AFC_E_SUCCESS) {
907 uint32_t bytes_read = fread(buf, 1, bufsize, f);
908 if (bytes_read == 0) {
909 if (!feof(f)) {
910 if (progress) {
911 printf("\n");
912 }
913 printf("Error: Failed to read from local file\n");
914 succeed = 0;
915 }
916 break;
917 }
918 uint32_t chunk = 0;
919 while (chunk < bytes_read) {
920 uint32_t bytes_written = 0;
921 err = afc_file_write(afc, fh, buf + chunk, bytes_read - chunk, &bytes_written);
922 if (err != AFC_E_SUCCESS) {
923 if (progress) {
924 printf("\n");
925 }
926 printf("Error: Failed to write to device file\n");
927 succeed = 0;
928 break;
929 }
930 chunk += bytes_written;
931 }
932 total += chunk;
933 if (progress) {
934 int prog = (int) ((double) total / (double) fst.st_size * 100.0f);
935 if (prog > lastprog) {
936 gettimeofday(&t2, NULL);
937 timeval_subtract(&tdiff, &t2, &t1);
938 double time_in_sec = (double) tdiff.tv_sec + (double) tdiff.tv_usec / 1000000;
939 printf("\r%d%% (%0.1f MB/s) ", prog, (double) total / 1048576.0f / time_in_sec);
940 fflush(stdout);
941 lastprog = prog;
942 }
943 }
944 }
945 printf("\n");
946 free(buf);
947 afc_file_close(afc, fh);
948 fclose(f);
949 return succeed;
950}
951
952static uint8_t put_file(afc_client_t afc, const char *srcpath, const char *dstpath)
953{
954 if (is_directory(srcpath)) {
955 char **info = NULL;
956 afc_error_t err = afc_get_file_info(afc, dstpath, &info);
957 //create if target directory does not exist
958 if (err == AFC_E_OBJECT_NOT_FOUND) {
959 err = afc_make_directory(afc, dstpath);
960 if (err != AFC_E_SUCCESS) {
961 printf("Error: Failed to create directory '%s': %s (%d)\n", dstpath, afc_strerror(err), err);
962 return 0;
963 }
964 }
965 afc_dictionary_free(info);
966 afc_get_file_info(afc, dstpath, &info);
967 uint8_t is_dir = 0;
968 if (info) {
969 char **p = info;
970 while (p && *p) {
971 if (!strcmp(*p, "st_ifmt")) {
972 p++;
973 is_dir = !strcmp(*p, "S_IFDIR");
974 break;
975 }
976 p++;
977 }
978 afc_dictionary_free(info);
979 }
980 if (!is_dir) {
981 printf("Error: Failed to create or access directory: '%s'", dstpath);
982 return 0;
983 }
984
985 // walk dir recursively to put files
986 DIR *cur_dir = opendir(srcpath);
987 if (cur_dir) {
988 struct dirent *ep;
989 while ((ep = readdir(cur_dir))) {
990 if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0)) {
991 continue;
992 }
993 char *fpath = string_build_path(srcpath, ep->d_name, NULL);
994 if (fpath) {
995 size_t len = strlen(srcpath) + 1 + strlen(ep->d_name) + 1;
996 char *newdst = (char *) malloc(len);
997 snprintf(newdst, len, "%s/%s", dstpath, ep->d_name);
998 if (!put_file(afc, fpath, newdst)) {
999 free(newdst);
1000 free(fpath);
1001 return 0;
1002 }
1003 free(newdst);
1004 free(fpath);
1005 }
1006 }
1007 closedir(cur_dir);
1008 } else {
1009 printf("Error: Failed to visit directory: '%s': %s", srcpath, strerror(errno));
1010 return 0;
1011 }
1012 } else {
1013 return put_single_file(afc, srcpath, dstpath);
1014 }
1015 return 1;
1016}
1017
1018static void handle_put(afc_client_t afc, int argc, char **argv)
862{ 1019{
863 if (argc < 1 || argc > 2) { 1020 if (argc < 1 || argc > 2) {
864 printf("Error: Invalid number of arguments\n"); 1021 printf("Error: Invalid number of arguments\n");
865 return; 1022 return;
866 } 1023 }
867 1024
1025 char *srcpath = strdup(argv[0]);
1026 size_t src_len = strlen(srcpath);
1027 if (src_len > 1 && srcpath[src_len - 1] == '/') {
1028 srcpath[src_len - 1] = '\0';
1029 }
868 char *dstpath = NULL; 1030 char *dstpath = NULL;
869 if (argc == 1) { 1031 if (argc == 1) {
870 dstpath = get_absolute_path(path_get_basename(argv[0])); 1032 dstpath = get_absolute_path(path_get_basename(srcpath));
871 } else { 1033 } else {
872 dstpath = get_absolute_path(argv[1]); 1034 char *tmp = strdup(argv[1]);
1035 size_t dst_len = strlen(tmp);
1036 if (dst_len > 1 && tmp[dst_len - 1] == '/') {
1037 tmp[dst_len - 1] = '\0';
1038 }
1039 dstpath = get_absolute_path(tmp);
1040 free(tmp);
873 } 1041 }
874 1042 char **info = NULL;
875 uint64_t fh = 0; 1043 afc_error_t err = afc_get_file_info(afc, dstpath, &info);
876 FILE *f = fopen(argv[0], "rb"); 1044 // target does not exist, put directly
877 if (f) { 1045 if (err == AFC_E_OBJECT_NOT_FOUND) {
878 afc_error_t err = afc_file_open(afc, dstpath, AFC_FOPEN_RW, &fh); 1046 put_file(afc, srcpath, dstpath);
879 if (err == AFC_E_OBJECT_IS_DIR) { 1047 free(srcpath);
880 const char* basen = path_get_basename(argv[0]); 1048 free(dstpath);
1049 } else {
1050 uint8_t is_dir = 0;
1051 if (info) {
1052 char **p = info;
1053 while (p && *p) {
1054 if (!strcmp(*p, "st_ifmt")) {
1055 p++;
1056 is_dir = !strcmp(*p, "S_IFDIR");
1057 break;
1058 }
1059 p++;
1060 }
1061 afc_dictionary_free(info);
1062 }
1063 // target is a dir, put under this target
1064 if (is_dir) {
1065 const char *basen = path_get_basename(srcpath);
881 size_t len = strlen(dstpath) + 1 + strlen(basen) + 1; 1066 size_t len = strlen(dstpath) + 1 + strlen(basen) + 1;
882 char* newdst = (char*)malloc(len); 1067 char *newdst = (char *) malloc(len);
883 snprintf(newdst, len, "%s/%s", dstpath, basen); 1068 snprintf(newdst, len, "%s/%s", dstpath, basen);
884 free(dstpath); 1069 free(dstpath);
885 dstpath = get_absolute_path(newdst); 1070 dstpath = get_absolute_path(newdst);
886 free(newdst); 1071 free(newdst);
887 err = afc_file_open(afc, dstpath, AFC_FOPEN_RW, &fh); 1072 put_file(afc, srcpath, dstpath);
888 }
889 if (err != AFC_E_SUCCESS) {
890 printf("Error: Failed to open file '%s' on device: %s (%d)\n", argv[1], afc_strerror(err), err);
891 } else { 1073 } else {
892 struct timeval t1; 1074 //target is common file, rewrite it
893 struct timeval t2; 1075 put_file(afc, srcpath, dstpath);
894 struct timeval tdiff;
895 struct stat fst;
896 int progress = 0;
897 size_t bufsize = 0x100000;
898 char* buf = malloc(bufsize);
899
900 fstat(fileno(f), &fst);
901 if (fst.st_size >= 0x400000) {
902 progress = 1;
903 gettimeofday(&t1, NULL);
904 }
905 size_t total = 0;
906 int lastprog = 0;
907 while (err == AFC_E_SUCCESS) {
908 uint32_t bytes_read = fread(buf, 1, bufsize, f);
909 if (bytes_read == 0) {
910 if (!feof(f)) {
911 if (progress) {
912 printf("\n");
913 }
914 printf("Error: Failed to read from local file\n");
915 }
916 break;
917 }
918 uint32_t chunk = 0;
919 while (chunk < bytes_read) {
920 uint32_t bytes_written = 0;
921 err = afc_file_write(afc, fh, buf+chunk, bytes_read-chunk, &bytes_written);
922 if (err != AFC_E_SUCCESS) {
923 if (progress) {
924 printf("\n");
925 }
926 printf("Error: Failed to write to device file\n");
927 break;
928 }
929 chunk += bytes_written;
930 }
931 total += chunk;
932 if (progress) {
933 int prog = (int)((double)total / (double)fst.st_size * 100.0f);
934 if (prog > lastprog) {
935 gettimeofday(&t2, NULL);
936 timeval_subtract(&tdiff, &t2, &t1);
937 double time_in_sec = (double)tdiff.tv_sec + (double)tdiff.tv_usec/1000000;
938 printf("\r%d%% (%0.1f MB/s) ", prog, (double)total/1048576.0f / time_in_sec);
939 fflush(stdout);
940 lastprog = prog;
941 }
942 }
943 }
944 printf("\n");
945 free(buf);
946 afc_file_close(afc, fh);
947 } 1076 }
948 fclose(f); 1077 free(srcpath);
949 } else { 1078 free(dstpath);
950 printf("Error: Failed to open local file '%s': %s\n", argv[0], strerror(errno));
951 } 1079 }
952 free(dstpath);
953} 1080}
954 1081
955static void handle_pwd(afc_client_t afc, int argc, char** argv) 1082static void handle_pwd(afc_client_t afc, int argc, char** argv)