50 #include "assistant.h" |
51 #include "assistant.h" |
51 |
52 |
52 #include "sync.h" |
53 #include "sync.h" |
53 #include "libidav/session.h" |
54 #include "libidav/session.h" |
54 |
55 |
|
56 #include <pthread.h> |
|
57 |
55 static DavContext *ctx; |
58 static DavContext *ctx; |
|
59 |
|
60 static int sync_shutdown = 0; |
56 |
61 |
57 static void xmlerrorfnc(void * c, const char * msg, ... ) { |
62 static void xmlerrorfnc(void * c, const char * msg, ... ) { |
58 va_list ap; |
63 va_list ap; |
59 va_start(ap, msg); |
64 va_start(ap, msg); |
60 vfprintf(stderr, msg, ap); |
65 vfprintf(stderr, msg, ap); |
85 |
90 |
86 xmlGenericErrorFunc fnc = xmlerrorfnc; |
91 xmlGenericErrorFunc fnc = xmlerrorfnc; |
87 initGenericErrorDefaultFunc(&fnc); |
92 initGenericErrorDefaultFunc(&fnc); |
88 ctx = dav_context_new(); |
93 ctx = dav_context_new(); |
89 int cfgret = load_config(ctx) || load_sync_config(); |
94 int cfgret = load_config(ctx) || load_sync_config(); |
|
95 |
|
96 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; |
|
97 pthread_mutex_lock(&mutex); |
|
98 pthread_t tid; |
90 |
99 |
91 if(!strcmp(cmd, "check") || !strcmp(cmd, "check-config")) { |
100 if(!strcmp(cmd, "check") || !strcmp(cmd, "check-config")) { |
92 if(!cfgret) { |
101 if(!cfgret) { |
93 fprintf(stdout, "Configuration OK.\n"); |
102 fprintf(stdout, "Configuration OK.\n"); |
94 ret = EXIT_SUCCESS; |
103 ret = EXIT_SUCCESS; |
96 /* no output, the warnings are written by load_config */ |
105 /* no output, the warnings are written by load_config */ |
97 ret = EXIT_FAILURE; |
106 ret = EXIT_FAILURE; |
98 } |
107 } |
99 } else if(!cfgret) { |
108 } else if(!cfgret) { |
100 if(!strcmp(cmd, "pull")) { |
109 if(!strcmp(cmd, "pull")) { |
|
110 tid = start_sighandler(&mutex); |
101 ret = cmd_pull(args); |
111 ret = cmd_pull(args); |
|
112 stop_sighandler(&mutex, tid); |
102 } else if(!strcmp(cmd, "push")) { |
113 } else if(!strcmp(cmd, "push")) { |
|
114 tid = start_sighandler(&mutex); |
103 ret = cmd_push(args, FALSE); |
115 ret = cmd_push(args, FALSE); |
|
116 stop_sighandler(&mutex, tid); |
104 } else if(!strcmp(cmd, "archive")) { |
117 } else if(!strcmp(cmd, "archive")) { |
|
118 tid = start_sighandler(&mutex); |
105 ret = cmd_push(args, TRUE); |
119 ret = cmd_push(args, TRUE); |
|
120 stop_sighandler(&mutex, tid); |
106 } else if(!strcmp(cmd, "resolve-conflicts")) { |
121 } else if(!strcmp(cmd, "resolve-conflicts")) { |
107 ret = cmd_resolve_conflicts(args); |
122 ret = cmd_resolve_conflicts(args); |
108 } else if(!strcmp(cmd, "delete-conflicts")) { |
123 } else if(!strcmp(cmd, "delete-conflicts")) { |
109 ret = cmd_delete_conflicts(args); |
124 ret = cmd_delete_conflicts(args); |
110 } else if(!strcmp(cmd, "trash-info")) { |
125 } else if(!strcmp(cmd, "trash-info")) { |
162 fprintf(stderr, " list-directories\n"); |
177 fprintf(stderr, " list-directories\n"); |
163 fprintf(stderr, " check-config\n"); |
178 fprintf(stderr, " check-config\n"); |
164 fprintf(stderr, " check-repositories\n\n"); |
179 fprintf(stderr, " check-repositories\n\n"); |
165 } |
180 } |
166 |
181 |
|
182 static void handlesig(int sig) { |
|
183 if(sync_shutdown) { |
|
184 exit(-1); |
|
185 } |
|
186 fprintf(stderr, "abort\n"); |
|
187 sync_shutdown = 1; |
|
188 } |
|
189 |
|
190 static void* sighandler(void *data) { |
|
191 signal(SIGTERM, handlesig); |
|
192 signal(SIGINT, handlesig); |
|
193 |
|
194 pthread_mutex_t *mutex = data; |
|
195 pthread_mutex_lock(mutex); // block thread |
|
196 return NULL; |
|
197 } |
|
198 |
|
199 pthread_t start_sighandler(pthread_mutex_t *mutex) { |
|
200 pthread_t tid; |
|
201 if(pthread_create(&tid, NULL, sighandler, mutex)) { |
|
202 perror("pthread_create"); |
|
203 exit(-1); |
|
204 } |
|
205 return tid; |
|
206 } |
|
207 |
|
208 void stop_sighandler(pthread_mutex_t *mutex, pthread_t tid) { |
|
209 pthread_mutex_unlock(mutex); |
|
210 void *data; |
|
211 pthread_join(tid, &data); |
|
212 } |
|
213 |
167 static int res_matches_filter(SyncDirectory *dir, char *res_path) { |
214 static int res_matches_filter(SyncDirectory *dir, char *res_path) { |
168 // trash filter |
215 // trash filter |
169 if (dir->trash) { |
216 if (dir->trash) { |
170 sstr_t rpath = sstr(util_concat_path(dir->path, res_path)); |
217 sstr_t rpath = sstr(util_concat_path(dir->path, res_path)); |
171 if (sstrprefix(rpath, sstr(dir->trash))) { |
218 if (sstrprefix(rpath, sstr(dir->trash))) { |
334 res = res->next; |
381 res = res->next; |
335 continue; |
382 continue; |
336 } |
383 } |
337 |
384 |
338 // download the resource |
385 // download the resource |
339 if(sync_get_resource(a, dir, res, db, &sync_success)) { |
386 if(!sync_shutdown && sync_get_resource(a, dir, res, db, &sync_success)) { |
340 fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path); |
387 fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path); |
341 sync_error++; |
388 sync_error++; |
342 } |
389 } |
343 |
390 |
344 // add every resource from the server to svrres |
391 // add every resource from the server to svrres |
345 // then db-resources contains only resources which are not on the |
392 // then db-resources contains only resources which are not on the |
346 // server |
393 // server |
347 LocalResource *local = ucx_map_cstr_get(db->resources, res->path); |
394 LocalResource *local = ucx_map_cstr_remove(db->resources, res->path); |
348 ucx_map_cstr_put(svrres, res->path, local); |
395 if(local) { |
349 ucx_map_cstr_remove(db->resources, res->path); |
396 ucx_map_cstr_put(svrres, res->path, local); |
350 |
397 |
351 if(local->last_modified == 0) { |
398 if(local->last_modified == 0) { |
352 // stat this file later (directory) |
399 // stat this file later (directory) |
353 statls = ucx_list_prepend(statls, local); |
400 statls = ucx_list_prepend(statls, local); |
354 } |
401 } |
|
402 } // else: sync_shutdown is TRUE |
355 |
403 |
356 if(res->children) { |
404 if(res->children) { |
357 stack = ucx_list_prepend(stack, res->children); |
405 stack = ucx_list_prepend(stack, res->children); |
358 } |
406 } |
359 res = res->next; |
407 res = res->next; |
378 UcxList *rmdirs = NULL; |
426 UcxList *rmdirs = NULL; |
379 UCX_MAP_FOREACH(key, local, i) { |
427 UCX_MAP_FOREACH(key, local, i) { |
380 if (res_matches_filter(dir, local->path)) { |
428 if (res_matches_filter(dir, local->path)) { |
381 continue; |
429 continue; |
382 } |
430 } |
383 // sync_remove_resource does all necessary tests |
431 |
384 int ret = sync_remove_local_resource(dir, local); |
432 if(sync_shutdown) { |
385 if(ret == -1) { |
433 ucx_map_cstr_put(svrres, local->path, local_resource_copy(local)); |
386 rmdirs = ucx_list_append(rmdirs, local); |
434 } else { |
387 } else if(ret == 0) { |
435 // sync_remove_resource does all necessary tests |
388 sync_delete++; |
436 int ret = sync_remove_local_resource(dir, local); |
|
437 if(ret == -1) { |
|
438 rmdirs = ucx_list_append(rmdirs, local); |
|
439 } else if(ret == 0) { |
|
440 sync_delete++; |
|
441 } |
389 } |
442 } |
390 } |
443 } |
391 UCX_FOREACH(elm, rmdirs) { |
444 UCX_FOREACH(elm, rmdirs) { |
392 LocalResource *local_dir = elm->data; |
445 LocalResource *local_dir = elm->data; |
393 sync_remove_local_directory(dir, local_dir); |
446 sync_remove_local_directory(dir, local_dir); |
821 UcxMap *lclres = ucx_map_new(db->resources->count); |
874 UcxMap *lclres = ucx_map_new(db->resources->count); |
822 int ret = 0; |
875 int ret = 0; |
823 UCX_FOREACH(elm, resources) { |
876 UCX_FOREACH(elm, resources) { |
824 LocalResource *local_res = elm->data; |
877 LocalResource *local_res = elm->data; |
825 if (!res_matches_filter(dir, local_res->path+1)) { |
878 if (!res_matches_filter(dir, local_res->path+1)) { |
|
879 if(sync_shutdown) { |
|
880 LocalResource *lr = ucx_map_cstr_remove(db->resources, local_res->path); |
|
881 if(lr) { |
|
882 local_res->size = lr->size; |
|
883 local_res->last_modified = lr->last_modified; |
|
884 local_res->etag = lr->etag ? strdup(lr->etag) : NULL; |
|
885 local_resource_free(lr); |
|
886 ucx_map_cstr_put(lclres, local_res->path, local_res); |
|
887 } |
|
888 elm->data = NULL; |
|
889 continue; |
|
890 } |
|
891 |
|
892 |
826 if(res_isconflict(db, local_res)) { |
893 if(res_isconflict(db, local_res)) { |
827 printf("skip: %s\n", local_res->path); |
894 printf("skip: %s\n", local_res->path); |
828 sync_skipped++; |
895 sync_skipped++; |
829 continue; |
896 continue; |
830 } |
897 } |
831 |
898 |
832 // upload every changed file |
899 // upload every changed file |
833 int error = 0; |
900 int error = 0; |
834 if (local_resource_is_changed(dir, db, local_res)) { |
901 if (local_resource_is_changed(dir, db, local_res)) { |
835 DavResource *res = dav_resource_new(sn, local_res->path); |
902 DavResource *res = dav_resource_new(sn, local_res->path); |
836 if(!res) { |
903 if(!res) { |
884 if(ret == 0 && !archive) { |
951 if(ret == 0 && !archive) { |
885 UcxMapIterator i = ucx_map_iterator(db->resources); |
952 UcxMapIterator i = ucx_map_iterator(db->resources); |
886 LocalResource *local; |
953 LocalResource *local; |
887 UCX_MAP_FOREACH(key, local, i) { |
954 UCX_MAP_FOREACH(key, local, i) { |
888 if (!res_matches_filter(dir, local->path+1)) { |
955 if (!res_matches_filter(dir, local->path+1)) { |
889 if(sync_delete_remote_resource(sn, local, &sync_delete)) { |
956 if(sync_shutdown) { |
890 ucx_map_cstr_put(lclres, local->path, local); |
957 ucx_map_cstr_put(lclres, local->path, local_resource_copy(local)); |
|
958 } else if(sync_delete_remote_resource(sn, local, &sync_delete)) { |
|
959 ucx_map_cstr_put(lclres, local->path, local_resource_copy(local)); |
891 if(sn->error != DAV_NOT_FOUND) { |
960 if(sn->error != DAV_NOT_FOUND) { |
892 print_resource_error(sn, local->path); |
961 print_resource_error(sn, local->path); |
893 sync_error++; |
962 sync_error++; |
894 break; |
963 break; |
895 } |
964 } |
1066 res->path = util_concat_path(path, "/"); |
1135 res->path = util_concat_path(path, "/"); |
1067 res->last_modified = s.st_mtime; |
1136 res->last_modified = s.st_mtime; |
1068 res->isdirectory = 1; |
1137 res->isdirectory = 1; |
1069 return res; |
1138 return res; |
1070 } |
1139 } |
|
1140 } |
|
1141 |
|
1142 LocalResource* local_resource_copy(LocalResource *res) { |
|
1143 LocalResource *newres = calloc(1, sizeof(LocalResource)); |
|
1144 if(res->name) { |
|
1145 newres->name = strdup(res->name); |
|
1146 } |
|
1147 if(res->path) { |
|
1148 newres->path = strdup(res->path); |
|
1149 } |
|
1150 if(res->etag) { |
|
1151 newres->etag = strdup(res->etag); |
|
1152 } |
|
1153 newres->skipped = res->skipped; |
|
1154 newres->size = res->size; |
|
1155 newres->last_modified = res->last_modified; |
|
1156 newres->isdirectory = res->isdirectory; |
|
1157 return newres; |
1071 } |
1158 } |
1072 |
1159 |
1073 int local_resource_is_changed(SyncDirectory *dir, SyncDatabase *db, LocalResource *res) { |
1160 int local_resource_is_changed(SyncDirectory *dir, SyncDatabase *db, LocalResource *res) { |
1074 LocalResource *db_res = ucx_map_cstr_get(db->resources, res->path); |
1161 LocalResource *db_res = ucx_map_cstr_get(db->resources, res->path); |
1075 if(db_res) { |
1162 if(db_res) { |