dav/sync.c

changeset 302
395763c0ee69
parent 299
c517502d3e38
child 313
d721250984d0
equal deleted inserted replaced
300:4e3769d4e782 302:395763c0ee69
29 #include <stdio.h> 29 #include <stdio.h>
30 #include <stdlib.h> 30 #include <stdlib.h>
31 #include <string.h> 31 #include <string.h>
32 #include <errno.h> 32 #include <errno.h>
33 #include <unistd.h> 33 #include <unistd.h>
34 #include <signal.h>
34 #include <time.h> 35 #include <time.h>
35 #include <libxml/xmlerror.h> 36 #include <libxml/xmlerror.h>
36 #include <sys/types.h> 37 #include <sys/types.h>
37 #include <ucx/string.h> 38 #include <ucx/string.h>
38 #include <ucx/utils.h> 39 #include <ucx/utils.h>
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) {

mercurial