86 int ret = EXIT_FAILURE; |
86 int ret = EXIT_FAILURE; |
87 if(!strcmp(cmd, "pull")) { |
87 if(!strcmp(cmd, "pull")) { |
88 ret = cmd_pull(args); |
88 ret = cmd_pull(args); |
89 } else if(!strcmp(cmd, "push")) { |
89 } else if(!strcmp(cmd, "push")) { |
90 ret = cmd_push(args); |
90 ret = cmd_push(args); |
|
91 } else if(!strcasecmp(cmd, "version") || !strcasecmp(cmd, "-version") || !strcasecmp(cmd, "--version")) { |
|
92 #ifdef DEBUG |
|
93 fprintf(stderr, "dav-synv %s unstable\n", DAV_VERSION); |
|
94 #else |
|
95 fprintf(stderr, "dav-sync %s\n", DAV_VERSION); |
|
96 #endif |
91 } |
97 } |
92 |
98 |
93 // TODO: cleanup sync config (don't forget to call regfree for regex) |
99 // TODO: cleanup sync config (don't forget to call regfree for regex) |
94 |
100 |
95 return ret; |
101 return ret; |
234 } |
240 } |
235 |
241 |
236 // delete every remotely removed resource |
242 // delete every remotely removed resource |
237 UcxMapIterator i = ucx_map_iterator(db->resources); |
243 UcxMapIterator i = ucx_map_iterator(db->resources); |
238 LocalResource *local; |
244 LocalResource *local; |
|
245 UcxList *rmdirs = NULL; |
239 UCX_MAP_FOREACH(key, local, i) { |
246 UCX_MAP_FOREACH(key, local, i) { |
240 if (res_matches_filter(dir, local->path)) { |
247 if (res_matches_filter(dir, local->path)) { |
241 continue; |
248 continue; |
242 } |
249 } |
243 // sync_remove_resource does all necessary tests |
250 // sync_remove_resource does all necessary tests |
244 sync_remove_local_resource(dir, local); |
251 if(sync_remove_local_resource(dir, local)) { |
|
252 rmdirs = ucx_list_append(rmdirs, local); |
|
253 } |
|
254 } |
|
255 UCX_FOREACH(elm, rmdirs) { |
|
256 LocalResource *local_dir = elm->data; |
|
257 sync_remove_local_directory(dir, local_dir); |
245 } |
258 } |
246 ucx_map_free(db->resources); |
259 ucx_map_free(db->resources); |
247 db->resources = svrres; |
260 db->resources = svrres; |
248 |
261 |
249 // TODO: cleanup - BUT DONT CLEANUP SYNC CONFIG (do this in main!) |
262 // TODO: cleanup - BUT DONT CLEANUP SYNC CONFIG (do this in main!) |
263 LocalResource *local = ucx_map_cstr_get(db->resources, res->path); |
276 LocalResource *local = ucx_map_cstr_get(db->resources, res->path); |
264 char *local_path = util_concat_path(dir->path, res->path); |
277 char *local_path = util_concat_path(dir->path, res->path); |
265 |
278 |
266 char *etag = dav_get_property(res, "D:getetag"); |
279 char *etag = dav_get_property(res, "D:getetag"); |
267 struct stat s; |
280 struct stat s; |
268 if(local) { |
281 if(local && !res->iscollection) { |
269 int exists = 1; |
282 int exists = 1; |
270 if(stat(local_path, &s)) { |
283 if(stat(local_path, &s)) { |
271 // Ignore the fact, that the file is locally removed. If the |
284 // Ignore the fact, that the file is locally removed. If the |
272 // server has an updated version, we read the file or the |
285 // server has an updated version, we read the file or the |
273 // next push will delete it on the server. |
286 // next push will delete it on the server. |
313 if(res->iscollection) { |
326 if(res->iscollection) { |
314 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; |
327 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; |
315 if(util_mkdir(local_path, mode) && errno != EEXIST) { |
328 if(util_mkdir(local_path, mode) && errno != EEXIST) { |
316 ret = -1; |
329 ret = -1; |
317 } |
330 } |
|
331 |
|
332 if(ret == 0) { |
|
333 if(!local) { |
|
334 // new local resource |
|
335 local = calloc(1, sizeof(LocalResource)); |
|
336 local->path = util_concat_path(res->path, "/"); |
|
337 local->last_modified = s.st_mtime; |
|
338 ucx_map_cstr_put(db->resources, local->path, local); |
|
339 } |
|
340 } |
318 } else { |
341 } else { |
319 if(!tmp_path) { |
342 if(!tmp_path) { |
320 fprintf(stderr, "Cannot create tmp path for %s\n", local_path); |
343 fprintf(stderr, "Cannot create tmp path for %s\n", local_path); |
321 free(local_path); |
344 free(local_path); |
322 return -1; |
345 return -1; |
379 free(tmp_path); |
402 free(tmp_path); |
380 free(local_path); |
403 free(local_path); |
381 return ret; |
404 return ret; |
382 } |
405 } |
383 |
406 |
384 void sync_remove_local_resource(SyncDirectory *dir, LocalResource *res) { |
407 int sync_remove_local_resource(SyncDirectory *dir, LocalResource *res) { |
385 char *local_path = util_concat_path(dir->path, res->path); |
408 char *local_path = util_concat_path(dir->path, res->path); |
386 struct stat s; |
409 struct stat s; |
387 if(stat(local_path, &s)) { |
410 if(stat(local_path, &s)) { |
388 free(local_path); |
411 free(local_path); |
389 return; |
412 return 0; |
|
413 } |
|
414 |
|
415 if(S_ISDIR(s.st_mode)) { |
|
416 free(local_path); |
|
417 return 1; |
390 } |
418 } |
391 |
419 |
392 if(s.st_mtime != res->last_modified) { |
420 if(s.st_mtime != res->last_modified) { |
393 free(local_path); |
421 free(local_path); |
394 return; |
422 return 0; |
395 } |
423 } |
396 |
424 |
397 printf("delete: %s\n", res->path); |
425 printf("delete: %s\n", res->path); |
398 |
426 |
399 if(dir->trash) { |
427 if(dir->trash) { |
400 move_to_trash(dir, local_path); |
428 move_to_trash(dir, local_path); |
401 } else if(unlink(local_path)) { |
429 } else if(unlink(local_path)) { |
402 fprintf(stderr, "Cannot remove file %s\n", local_path); |
430 fprintf(stderr, "Cannot remove file %s\n", local_path); |
403 } |
431 } |
|
432 free(local_path); |
|
433 |
|
434 return 0; |
|
435 } |
|
436 |
|
437 void sync_remove_local_directory(SyncDirectory *dir, LocalResource *res) { |
|
438 char *local_path = util_concat_path(dir->path, res->path); |
|
439 |
|
440 printf("delete: %s\n", res->path); |
|
441 if(rmdir(local_path)) { |
|
442 // TODO |
|
443 } |
|
444 |
404 free(local_path); |
445 free(local_path); |
405 } |
446 } |
406 |
447 |
407 void rename_local_file(SyncDirectory *dir, SyncDatabase *db, char *path) { |
448 void rename_local_file(SyncDirectory *dir, SyncDatabase *db, char *path) { |
408 char *local_path = util_concat_path(dir->path, path); |
449 char *local_path = util_concat_path(dir->path, path); |
547 UCX_FOREACH(elm, resources) { |
588 UCX_FOREACH(elm, resources) { |
548 LocalResource *local_res = elm->data; |
589 LocalResource *local_res = elm->data; |
549 if (!res_matches_filter(dir, local_res->path+1)) { |
590 if (!res_matches_filter(dir, local_res->path+1)) { |
550 // upload every changed file |
591 // upload every changed file |
551 if (local_resource_is_changed(dir, db, local_res)) { |
592 if (local_resource_is_changed(dir, db, local_res)) { |
552 printf("put: %s\n", local_res->path); |
|
553 DavResource *res = dav_resource_new(sn, local_res->path); |
593 DavResource *res = dav_resource_new(sn, local_res->path); |
554 if(sync_put_resource(dir, res, local_res)) { |
594 |
555 // TODO: I don't know what to do now |
595 if(local_res->isdirectory) { |
|
596 printf("mkcol: %s\n", local_res->path); |
|
597 if(sync_mkdir(dir, res, local_res)) { |
|
598 // TODO: I don't know what to do now |
|
599 } |
|
600 } else { |
|
601 printf("put: %s\n", local_res->path); |
|
602 if(sync_put_resource(dir, res, local_res)) { |
|
603 // TODO: I don't know what to do now |
|
604 } |
556 } |
605 } |
557 dav_resource_free(res); |
606 dav_resource_free(res); |
558 } |
607 } |
559 |
608 |
560 // remove every locally available resource from db->resource |
609 // remove every locally available resource from db->resource |
614 |
663 |
615 char *new_path = util_concat_path(p, ent->d_name); |
664 char *new_path = util_concat_path(p, ent->d_name); |
616 int isdir; |
665 int isdir; |
617 LocalResource *res = local_resource_new(dir, db, new_path, &isdir); |
666 LocalResource *res = local_resource_new(dir, db, new_path, &isdir); |
618 if(isdir) { |
667 if(isdir) { |
|
668 resources = ucx_list_append(resources, res); |
619 stack = ucx_list_prepend(stack, new_path); |
669 stack = ucx_list_prepend(stack, new_path); |
620 } else if(res) { |
670 } else if(res) { |
621 resources = ucx_list_append(resources, res); |
671 resources = ucx_list_append(resources, res); |
622 free(new_path); |
672 free(new_path); |
623 } else { |
673 } else { |
704 res->last_modified = s.st_mtime; |
754 res->last_modified = s.st_mtime; |
705 res->size = s.st_size; |
755 res->size = s.st_size; |
706 return res; |
756 return res; |
707 } else { |
757 } else { |
708 *isdir = 1; |
758 *isdir = 1; |
|
759 LocalResource *res = calloc(1, sizeof(LocalResource)); |
|
760 res->path = util_concat_path(path, "/"); |
|
761 res->last_modified = s.st_mtime; |
|
762 res->isdirectory = 1; |
|
763 return res; |
709 } |
764 } |
710 return NULL; |
765 return NULL; |
711 } |
766 } |
712 |
767 |
713 int local_resource_is_changed(SyncDirectory *dir, SyncDatabase *db, LocalResource *res) { |
768 int local_resource_is_changed(SyncDirectory *dir, SyncDatabase *db, LocalResource *res) { |
820 free(local_path); |
875 free(local_path); |
821 |
876 |
822 return ret; |
877 return ret; |
823 } |
878 } |
824 |
879 |
|
880 int sync_mkdir(SyncDirectory *dir, DavResource *res, LocalResource *local) { |
|
881 res->iscollection = 1; |
|
882 int ret = -1; |
|
883 for(int i=0;i<dir->max_retry;i++) { |
|
884 if(dav_create(res)) { |
|
885 continue; |
|
886 } |
|
887 ret = 0; |
|
888 break; |
|
889 } |
|
890 return ret; |
|
891 } |
|
892 |
825 int sync_delete_remote_resource(DavSession *sn, LocalResource *local_res) { |
893 int sync_delete_remote_resource(DavSession *sn, LocalResource *local_res) { |
826 DavResource *res = dav_get(sn, local_res->path, "D:getetag"); |
894 DavResource *res = dav_get(sn, local_res->path, "D:getetag"); |
827 if(!res) { |
895 if(!res) { |
828 return sn->error == DAV_NOT_FOUND ? 0 : 1; |
896 return sn->error == DAV_NOT_FOUND ? 0 : 1; |
829 } |
897 } |
830 |
898 |
831 char *etag = dav_get_property(res, "D:getetag"); |
|
832 if(etag) { |
|
833 if(strlen(etag) > 2 && etag[0] == 'W' && etag[1] == '/') { |
|
834 etag = etag + 2; |
|
835 } |
|
836 } |
|
837 |
|
838 int ret = 0; |
899 int ret = 0; |
839 if(etag && !strcmp(etag, local_res->etag)) { |
900 if(res->iscollection) { |
840 // local resource metadata == remote resource metadata |
|
841 // resource can be deleted |
|
842 printf("delete: %s\n", res->path); |
901 printf("delete: %s\n", res->path); |
843 if(dav_delete(res)) { |
902 if(dav_delete(res)) { |
844 if(sn->error != DAV_NOT_FOUND) { |
903 ret = 1; |
845 fprintf(stderr, "Cannot delete resource %s\n", res->path); |
904 fprintf(stderr, "Cannot delete resource %s\n", res->path); |
846 } |
|
847 } |
905 } |
848 } else { |
906 } else { |
849 ret = 1; |
907 char *etag = dav_get_property(res, "D:getetag"); |
|
908 if(etag) { |
|
909 if(strlen(etag) > 2 && etag[0] == 'W' && etag[1] == '/') { |
|
910 etag = etag + 2; |
|
911 } |
|
912 } |
|
913 |
|
914 if(etag && !strcmp(etag, local_res->etag)) { |
|
915 // local resource metadata == remote resource metadata |
|
916 // resource can be deleted |
|
917 printf("delete: %s\n", res->path); |
|
918 if(dav_delete(res)) { |
|
919 if(sn->error != DAV_NOT_FOUND) { |
|
920 fprintf(stderr, "Cannot delete resource %s\n", res->path); |
|
921 } |
|
922 } |
|
923 } else { |
|
924 ret = 1; |
|
925 } |
850 } |
926 } |
851 |
927 |
852 // cleanup |
928 // cleanup |
853 dav_resource_free(res); |
929 dav_resource_free(res); |
854 |
930 |