dav/sync.c

changeset 567
b0ce8b27978b
parent 566
9a88920b15d8
child 568
a81cad6bb377
equal deleted inserted replaced
566:9a88920b15d8 567:b0ce8b27978b
97 } 97 }
98 if(!s1 && !s2) { 98 if(!s1 && !s2) {
99 return 0; 99 return 0;
100 } 100 }
101 return strcmp(s1, s2); 101 return strcmp(s1, s2);
102 }
103
104 static char* nullstrdup(const char *s) {
105 return s ? strdup(s) : NULL;
102 } 106 }
103 107
104 static void nullfree(void *p) { 108 static void nullfree(void *p) {
105 if(p) { 109 if(p) {
106 free(p); 110 free(p);
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;

mercurial