512 fprintf(stderr, "Cannot load database file: %s\n", dir->database); |
516 fprintf(stderr, "Cannot load database file: %s\n", dir->database); |
513 return -1; |
517 return -1; |
514 } |
518 } |
515 remove_deleted_conflicts(dir, db); |
519 remove_deleted_conflicts(dir, db); |
516 |
520 |
|
521 UcxMap *hashes = NULL; |
|
522 if(dir->hashing) { |
|
523 hashes = create_hash_index(db); |
|
524 } |
|
525 |
517 DavSession *sn = create_session(ctx, repo, dir->collection); |
526 DavSession *sn = create_session(ctx, repo, dir->collection); |
518 ucx_mempool_reg_destr(sn->mp, db, (ucx_destructor)destroy_db); |
527 ucx_mempool_reg_destr(sn->mp, db, (ucx_destructor)destroy_db); |
519 if (cmd_getoption(a, "verbose")) { |
528 if (cmd_getoption(a, "verbose")) { |
520 curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L); |
529 curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L); |
521 curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr); |
530 curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr); |
585 int sync_error = 0; |
594 int sync_error = 0; |
586 int sync_conflict = 0; |
595 int sync_conflict = 0; |
587 |
596 |
588 UcxList *res_modified = NULL; |
597 UcxList *res_modified = NULL; |
589 UcxList *res_new = NULL; |
598 UcxList *res_new = NULL; |
590 UcxList *res_moved = NULL; |
599 UcxList *res_moved = NULL; // type: MovedFile |
591 UcxList *res_copied = NULL; |
600 UcxList *res_copied = NULL; // type: MovedFile |
592 UcxList *res_conflict = NULL; |
601 UcxList *res_conflict = NULL; |
593 UcxList *res_mkdir = NULL; |
602 UcxList *res_mkdir = NULL; |
594 UcxList *res_metadata = NULL; |
603 UcxList *res_metadata = NULL; |
595 UcxList *res_broken = NULL; |
604 UcxList *res_broken = NULL; |
596 UcxMap *lres_removed = ucx_map_new(16); // contains LocalResource* |
605 UcxMap *lres_removed = ucx_map_new(16); // type: LocalResource* |
597 |
606 |
598 //UcxMap *svrres = ucx_map_new(db->resources->count); |
607 //UcxMap *svrres = ucx_map_new(db->resources->count); |
599 UcxMap *dbres = ucx_map_clone(db->resources, NULL, NULL); |
608 UcxMap *dbres = ucx_map_clone(db->resources, NULL, NULL); |
600 |
609 |
601 UcxList *stack = ucx_list_prepend(NULL, ls->children); |
610 UcxList *stack = ucx_list_prepend(NULL, ls->children); |
716 UCX_FOREACH(elm, res_conflict) { |
725 UCX_FOREACH(elm, res_conflict) { |
717 DavResource *res = elm->data; |
726 DavResource *res = elm->data; |
718 ucx_map_cstr_put(conflicts, res->path, res); |
727 ucx_map_cstr_put(conflicts, res->path, res); |
719 } |
728 } |
720 |
729 |
|
730 if(dir->hashing) { |
|
731 // check for moved/copied files |
|
732 UcxList *elm = res_new; |
|
733 UcxList *prev = NULL; |
|
734 UcxList *next = NULL; |
|
735 struct stat s; |
|
736 for(;elm;elm=next) { |
|
737 DavResource *res = elm->data; |
|
738 prev = elm->prev; |
|
739 next = elm->next; |
|
740 |
|
741 char *hash = sync_get_content_hash(res); |
|
742 if(!hash) { |
|
743 continue; |
|
744 } |
|
745 |
|
746 LocalResource *local = ucx_map_cstr_get(hashes, hash); |
|
747 if(!local) { |
|
748 continue; |
|
749 } |
|
750 |
|
751 char *local_path = util_concat_path(dir->path, local->path); |
|
752 int staterr = stat(local_path, &s); |
|
753 free(local_path); |
|
754 if(staterr) { |
|
755 // origin doesn't exist or is inaccessible |
|
756 continue; |
|
757 } |
|
758 |
|
759 MovedFile *mf = malloc(sizeof(MovedFile)); |
|
760 mf->content = local; |
|
761 mf->resource = res; |
|
762 if(ucx_map_cstr_get(lres_removed, local->path)) { |
|
763 mf->copy = FALSE; |
|
764 } else { |
|
765 mf->copy = TRUE; |
|
766 } |
|
767 |
|
768 res_moved = ucx_list_append(res_moved, mf); |
|
769 |
|
770 // remove item from res_new |
|
771 if(prev) { |
|
772 prev->next = next; |
|
773 } else { |
|
774 res_new = next; |
|
775 } |
|
776 if(next) { |
|
777 next->prev = prev; |
|
778 } |
|
779 } |
|
780 } |
|
781 |
|
782 // do copy/move operations |
|
783 UCX_FOREACH(elm, res_moved) { |
|
784 MovedFile *mf = elm->data; |
|
785 if(sync_shutdown) { |
|
786 break; |
|
787 } |
|
788 |
|
789 DavBool issplit = dav_get_property_ns(mf->resource, DAV_NS, "split") ? 1 : 0; |
|
790 if(ucx_map_cstr_get(conflicts, mf->resource->path)) { |
|
791 rename_conflict_file(dir, db, mf->resource->path, issplit); |
|
792 sync_conflict++; |
|
793 } |
|
794 |
|
795 // move file |
|
796 if(sync_move_resource(a, dir, mf->resource, mf->content, mf->copy, db, &sync_success)) { |
|
797 fprintf(stderr, "%s failed: %s\n", mf->copy?"copy":"move", mf->resource->path); |
|
798 sync_error++; |
|
799 } |
|
800 } |
|
801 |
721 // download all new, modified and conflict files |
802 // download all new, modified and conflict files |
722 UcxList *download = ucx_list_concat(res_modified, res_conflict); |
803 UcxList *download = ucx_list_concat(res_modified, res_conflict); |
723 download = ucx_list_concat(res_new, download); |
804 download = ucx_list_concat(res_new, download); |
724 UCX_FOREACH(elm, download) { |
805 UCX_FOREACH(elm, download) { |
725 DavResource *res = elm->data; |
806 DavResource *res = elm->data; |
1086 *err = 0; |
1167 *err = 0; |
1087 *blockcount = i; |
1168 *blockcount = i; |
1088 return updates; |
1169 return updates; |
1089 } |
1170 } |
1090 |
1171 |
1091 |
1172 int copy_file(const char *from, const char *to) { |
|
1173 FILE *in = sys_fopen(from, "rb"); |
|
1174 if(!in) { |
|
1175 return 1; |
|
1176 } |
|
1177 FILE *out = sys_fopen(to, "wb"); |
|
1178 if(!out) { |
|
1179 fclose(in); |
|
1180 return 1; |
|
1181 } |
|
1182 |
|
1183 ucx_stream_copy(in, out, (read_func)fread, (write_func)fwrite); |
|
1184 fclose(in); |
|
1185 fclose(out); |
|
1186 |
|
1187 return 0; |
|
1188 } |
|
1189 |
|
1190 typedef int (*renamefunc)(const char*,const char*); |
|
1191 |
|
1192 int sync_move_resource( |
|
1193 CmdArgs *a, |
|
1194 SyncDirectory *dir, |
|
1195 DavResource *res, |
|
1196 LocalResource *content, |
|
1197 DavBool copy, |
|
1198 SyncDatabase *db, |
|
1199 int *counter) |
|
1200 { |
|
1201 renamefunc fn = copy ? copy_file : sys_rename; |
|
1202 |
|
1203 char *new_path = util_concat_path(dir->path, res->path); |
|
1204 char *old_path = util_concat_path(dir->path, content->path); |
|
1205 |
|
1206 printf("%s: %s -> %s\n", copy?"copy":"move", content->path, res->path); |
|
1207 if(fn(old_path, new_path)) { |
|
1208 free(new_path); |
|
1209 free(old_path); |
|
1210 return 1; |
|
1211 } |
|
1212 (*counter)++; |
|
1213 |
|
1214 char *etag = dav_get_string_property(res, "D:getetag"); |
|
1215 char *content_hash = sync_get_content_hash(res); |
|
1216 |
|
1217 LocalResource *local = local_resource_copy(content, res->path); |
|
1218 ucx_map_cstr_put(db->resources, local->path, local); |
|
1219 |
|
1220 if(sync_store_metadata(dir, new_path, local, res)) { |
|
1221 fprintf(stderr, "Cannot store metadata: %s\n", res->path); |
|
1222 } |
|
1223 |
|
1224 if(local->etag) { |
|
1225 free(local->etag); |
|
1226 } |
|
1227 if(local->hash) { |
|
1228 free(local->hash); |
|
1229 } |
|
1230 |
|
1231 SYS_STAT s; |
|
1232 if(sys_stat(new_path, &s)) { |
|
1233 fprintf(stderr, |
|
1234 "Cannot stat file %s: %s\n", new_path, strerror(errno)); |
|
1235 } |
|
1236 |
|
1237 // set metadata from stat |
|
1238 local->etag = nullstrdup(etag); |
|
1239 local->hash = nullstrdup(content_hash); |
|
1240 |
|
1241 sync_set_metadata_from_stat(local, &s); |
|
1242 local->skipped = FALSE; |
|
1243 |
|
1244 return 0; |
|
1245 } |
1092 |
1246 |
1093 int sync_get_resource( |
1247 int sync_get_resource( |
1094 CmdArgs *a, |
1248 CmdArgs *a, |
1095 SyncDirectory *dir, |
1249 SyncDirectory *dir, |
1096 const char *path, |
1250 const char *path, |
1283 } |
1437 } |
1284 |
1438 |
1285 free(local_path); |
1439 free(local_path); |
1286 return ret; |
1440 return ret; |
1287 } |
1441 } |
1288 |
|
1289 int copy_file(const char *from, const char *to) { |
|
1290 FILE *in = sys_fopen(from, "rb"); |
|
1291 if(!in) { |
|
1292 return 1; |
|
1293 } |
|
1294 FILE *out = sys_fopen(to, "wb"); |
|
1295 if(!out) { |
|
1296 fclose(in); |
|
1297 return 1; |
|
1298 } |
|
1299 |
|
1300 ucx_stream_copy(in, out, (read_func)fread, (write_func)fwrite); |
|
1301 fclose(in); |
|
1302 fclose(out); |
|
1303 |
|
1304 return 0; |
|
1305 } |
|
1306 |
|
1307 typedef int (*renamefunc)(const char*,const char*); |
|
1308 |
1442 |
1309 void rename_conflict_file(SyncDirectory *dir, SyncDatabase *db, char *path, DavBool copy) { |
1443 void rename_conflict_file(SyncDirectory *dir, SyncDatabase *db, char *path, DavBool copy) { |
1310 char *local_path = create_local_path(dir, path); |
1444 char *local_path = create_local_path(dir, path); |
1311 char *parent = util_parent_path(local_path); |
1445 char *parent = util_parent_path(local_path); |
1312 |
1446 |
1795 local->origin); |
1929 local->origin); |
1796 if(origin_changed) { |
1930 if(origin_changed) { |
1797 // upload with put |
1931 // upload with put |
1798 printf("put: %s\n", local->path); |
1932 printf("put: %s\n", local->path); |
1799 err = sync_put_resource(dir, res, local, &sync_success); |
1933 err = sync_put_resource(dir, res, local, &sync_success); |
|
1934 |
|
1935 // TODO: if move, delete old resource |
1800 } else { |
1936 } else { |
1801 printf("%s: %s -> %s\n", copy ? "copy":"move", local->origin->path, local->path); |
1937 printf("%s: %s -> %s\n", copy ? "copy":"move", local->origin->path, local->path); |
1802 err = sync_move_remote_resource( |
1938 err = sync_move_remote_resource( |
1803 dir, |
1939 dir, |
1804 origin_res, |
1940 origin_res, |
2417 int ret = 0; |
2553 int ret = 0; |
2418 if(err == 0) { |
2554 if(err == 0) { |
2419 char *etag = dav_get_string_property(remote, "D:getetag"); |
2555 char *etag = dav_get_string_property(remote, "D:getetag"); |
2420 char *hash = sync_get_content_hash(remote); |
2556 char *hash = sync_get_content_hash(remote); |
2421 if(hash && res->hash) { |
2557 if(hash && res->hash) { |
2422 if(!strcmp(hash, res->hash)) { |
2558 if(strcmp(hash, res->hash)) { |
2423 ret = 1; |
2559 ret = 1; |
2424 } |
2560 } |
2425 } else if(!res->etag) { |
2561 } else if(!res->etag) { |
2426 // the resource is on the server and the client has no etag |
2562 // the resource is on the server and the client has no etag |
2427 ret = 1; |
2563 ret = 1; |