dav/sync.c

changeset 64
112dbf7ba8b0
parent 61
e9b102d5a6f6
child 65
d4077e8175f3
equal deleted inserted replaced
63:ee9da935645d 64:112dbf7ba8b0
191 // download the resource 191 // download the resource
192 if(sync_get_resource(a, dir, res, db)) { 192 if(sync_get_resource(a, dir, res, db)) {
193 fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path); 193 fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path);
194 } 194 }
195 195
196 // add every resource from the server to svrres
197 // then db-resources only contains resources which are not on the
198 // server
196 LocalResource *local = ucx_map_cstr_get(db->resources, res->path); 199 LocalResource *local = ucx_map_cstr_get(db->resources, res->path);
197 ucx_map_cstr_put(svrres, res->path, local); 200 ucx_map_cstr_put(svrres, res->path, local);
198 ucx_map_cstr_remove(db->resources, res->path); 201 ucx_map_cstr_remove(db->resources, res->path);
199 202
200 if(res->children) { 203 if(res->children) {
202 } 205 }
203 res = res->next; 206 res = res->next;
204 } 207 }
205 } 208 }
206 209
210 // delete every remotely removed resource
207 UcxMapIterator i = ucx_map_iterator(db->resources); 211 UcxMapIterator i = ucx_map_iterator(db->resources);
208 LocalResource *local; 212 LocalResource *local;
209 UCX_MAP_FOREACH(key, local, i) { 213 UCX_MAP_FOREACH(key, local, i) {
210 if (res_matches_filter(dir, local->path)) { 214 if (res_matches_filter(dir, local->path)) {
211 continue; 215 continue;
212 } 216 }
217 // sync_remove_resource does all necessary tests
213 sync_remove_resource(dir, local); 218 sync_remove_resource(dir, local);
214 } 219 }
215 ucx_map_free(db->resources); 220 ucx_map_free(db->resources);
216 db->resources = svrres; 221 db->resources = svrres;
217 222
229 int sync_get_resource(CmdArgs *a, SyncDirectory *dir, DavResource *res, SyncDatabase *db) { 234 int sync_get_resource(CmdArgs *a, SyncDirectory *dir, DavResource *res, SyncDatabase *db) {
230 LocalResource *removed = ucx_map_cstr_get(db->remove, res->path); 235 LocalResource *removed = ucx_map_cstr_get(db->remove, res->path);
231 if(removed) { 236 if(removed) {
232 return 0; 237 return 0;
233 } 238 }
234 int cdt = cmd_getoption(a, "conflict") ? 0 : 1; 239 int cdt = cmd_getoption(a, "conflict") ? 0 : 1; // conflict detection
235 240
236 LocalResource *local = ucx_map_cstr_get(db->resources, res->path); 241 LocalResource *local = ucx_map_cstr_get(db->resources, res->path);
237 char *local_path = util_concat_path(dir->path, res->path); 242 char *local_path = util_concat_path(dir->path, res->path);
238 243
239 char *etag = dav_get_property(res, "D:getetag"); 244 char *etag = dav_get_property(res, "D:getetag");
240 struct stat s; 245 struct stat s;
241 if(local) { 246 if(local) {
242 if(stat(local_path, &s)) { 247 if(stat(local_path, &s)) {
243 if(errno == ENOENT) { 248 // Ignore the fact, that the file is locally removed. If the
244 printf("removed: %s\n", res->path); 249 // server has an updated version, we readd the file or the
245 // the file is in the database, but doesn't exists 250 // next push will delete it on the server.
246 // mark the file as removed to delete it on next push 251 if(errno != ENOENT) {
247 ucx_map_cstr_remove(db->resources, local->path);
248 ucx_map_cstr_put(db->remove, local->path, local);
249 return 0;
250 } else {
251 fprintf(stderr, "Cannot stat file: %s\n", local_path); 252 fprintf(stderr, "Cannot stat file: %s\n", local_path);
252 free(local_path); 253 free(local_path);
253 return -1; 254 return -1;
254 } 255 }
255 } 256 }
272 } else { 273 } else {
273 if(stat(local_path, &s)) { 274 if(stat(local_path, &s)) {
274 if(errno != ENOENT) { 275 if(errno != ENOENT) {
275 fprintf(stderr, "Cannot stat file: %s\n", local_path); 276 fprintf(stderr, "Cannot stat file: %s\n", local_path);
276 } 277 }
277 } else if(cdt && !S_ISDIR(s.st_mode)) { 278 } else if(S_ISDIR(s.st_mode)) {
279 //fprintf(stderr, "Error: file %s is a directory\n", local_path);
280 } else if(cdt) {
281 // rename file on conflict
278 rename_local_file(dir, db, res->path); 282 rename_local_file(dir, db, res->path);
279 } 283 }
280 } 284 }
281 285
282 int ret = 0; 286 int ret = 0;
421 425
422 // upload all changed files 426 // upload all changed files
423 UcxList *resources = cmd_getoption(a, "read") ? 427 UcxList *resources = cmd_getoption(a, "read") ?
424 read_changes(dir, db) : local_scan(dir, db); 428 read_changes(dir, db) : local_scan(dir, db);
425 429
430 UcxMap *lclres = ucx_map_new(db->resources->count);
426 UCX_FOREACH(elm, resources) { 431 UCX_FOREACH(elm, resources) {
427 LocalResource *local_res = elm->data; 432 LocalResource *local_res = elm->data;
428 if (!res_matches_filter(dir, local_res->path+1)) { 433 if (!res_matches_filter(dir, local_res->path+1)) {
429 printf("put: %s\n", local_res->path); 434 // upload every changed file
430 ucx_map_cstr_put(db->resources, local_res->path, local_res); 435 if (local_resource_is_changed(dir, db, local_res)) {
431 DavResource *res = dav_resource_new(sn, local_res->path); 436 printf("put: %s\n", local_res->path);
432 if(sync_put_resource(dir, res, db)) { 437 DavResource *res = dav_resource_new(sn, local_res->path);
433 ucx_map_cstr_remove(db->resources, local_res->path); 438 if(sync_put_resource(dir, res, local_res)) {
434 } 439 // TODO: I don't know what to do now
435 dav_resource_free(res); 440 }
441 dav_resource_free(res);
442 }
443
444 // remove every locally available resource from db->resource
445 // the remaining elements are all deleted files
446 ucx_map_cstr_put(lclres, local_res->path, local_res);
447 ucx_map_cstr_remove(db->resources, local_res->path); // TODO: element leaked
436 } 448 }
437 } 449 }
438 ucx_list_free(resources); 450 ucx_list_free(resources);
439 451
440 // delete all removed files 452 // delete all removed files
441 UcxMapIterator i = ucx_map_iterator(db->remove); 453 UcxMapIterator i = ucx_map_iterator(db->resources);
442 LocalResource *local; 454 LocalResource *local;
443 UCX_MAP_FOREACH(key, local, i) { 455 UCX_MAP_FOREACH(key, local, i) {
456 // TODO: save deletion: check for remote changes
457
444 DavResource *res = dav_resource_new(sn, local->path); 458 DavResource *res = dav_resource_new(sn, local->path);
445 printf("delete: %s\n", res->path); 459 printf("delete: %s\n", res->path);
446 if(dav_delete(res)) { 460 if(dav_delete(res)) {
447 if(sn->error != DAV_NOT_FOUND) { 461 if(sn->error != DAV_NOT_FOUND) {
448 fprintf(stderr, "Cannot delete resource %s\n", res->path); 462 fprintf(stderr, "Cannot delete resource %s\n", res->path);
450 } 464 }
451 dav_resource_free(res); 465 dav_resource_free(res);
452 // TODO: free local resource 466 // TODO: free local resource
453 ucx_map_remove(db->remove, key); 467 ucx_map_remove(db->remove, key);
454 } 468 }
469 ucx_map_free(db->resources);
470 db->resources = lclres;
455 471
456 // TODO: free res 472 // TODO: free res
457 473
458 // store db 474 // store db
459 if(store_db(db, dir->database)) { 475 if(store_db(db, dir->database)) {
470 char *path = strdup("/"); 486 char *path = strdup("/");
471 UcxList *stack = ucx_list_prepend(NULL, path); 487 UcxList *stack = ucx_list_prepend(NULL, path);
472 while(stack) { 488 while(stack) {
473 // get a directory path from the stack and read all entries 489 // get a directory path from the stack and read all entries
474 // if an entry is a directory, put it on the stack 490 // if an entry is a directory, put it on the stack
475 // otherwise compare the metadata with the db content
476 491
477 char *p = stack->data; 492 char *p = stack->data;
478 stack = ucx_list_remove(stack, stack); 493 stack = ucx_list_remove(stack, stack);
479 char *local_path = util_concat_path(dir->path, p); 494 char *local_path = util_concat_path(dir->path, p);
480 DIR *local_dir = opendir(local_path); 495 DIR *local_dir = opendir(local_path);
488 continue; 503 continue;
489 } 504 }
490 505
491 char *new_path = util_concat_path(p, ent->d_name); 506 char *new_path = util_concat_path(p, ent->d_name);
492 int isdir; 507 int isdir;
493 LocalResource *res = path_to_local_resource(dir, db, new_path, &isdir); 508 LocalResource *res = local_resource_new(dir, db, new_path, &isdir);
494 if(isdir) { 509 if(isdir) {
495 stack = ucx_list_prepend(stack, new_path); 510 stack = ucx_list_prepend(stack, new_path);
496 } else if(res) { 511 } else if(res) {
497 resources = ucx_list_append(resources, res); 512 resources = ucx_list_append(resources, res);
498 free(new_path); 513 free(new_path);
538 } 553 }
539 value = sstrdup(value); 554 value = sstrdup(value);
540 555
541 if(!sstrcmp(name, S("put"))) { 556 if(!sstrcmp(name, S("put"))) {
542 int isdir; 557 int isdir;
543 LocalResource *res = path_to_local_resource(dir, db, value.ptr, &isdir); 558 LocalResource *res = local_resource_new(dir, db, value.ptr, &isdir);
544 if(res) { 559 if(res) {
545 resources = ucx_list_append(resources, res); 560 resources = ucx_list_append(resources, res);
546 } 561 }
547 } else if(!sstrcmp(name, S("remove"))) { 562 } else if(!sstrcmp(name, S("remove"))) {
548 LocalResource *res = calloc(1, sizeof(LocalResource)); 563 LocalResource *res = calloc(1, sizeof(LocalResource));
560 ucx_properties_free(parser); 575 ucx_properties_free(parser);
561 576
562 return resources; 577 return resources;
563 } 578 }
564 579
565 LocalResource* path_to_local_resource(SyncDirectory *dir, SyncDatabase *db, char *path, int *isdir) { 580 LocalResource* local_resource_new(SyncDirectory *dir, SyncDatabase *db, char *path, int *isdir) {
566
567 char *file_path = util_concat_path(dir->path, path); 581 char *file_path = util_concat_path(dir->path, path);
568 struct stat s; 582 struct stat s;
569 if(stat(file_path, &s)) { 583 if(stat(file_path, &s)) {
570 fprintf(stderr, "Cannot stat file %s\n", file_path); 584 fprintf(stderr, "Cannot stat file %s\n", file_path);
571 free(file_path); 585 free(file_path);
573 } 587 }
574 free(file_path); 588 free(file_path);
575 589
576 if(!S_ISDIR(s.st_mode)) { 590 if(!S_ISDIR(s.st_mode)) {
577 *isdir = 0; 591 *isdir = 0;
578 LocalResource *res = ucx_map_cstr_get(db->resources, path); 592 LocalResource *res = calloc(1, sizeof(LocalResource));
579 if(res) { 593 res->path = strdup(path);
580 // the file is already in the database 594 res->etag = NULL;
581 // compare length and lastmodified date 595 res->last_modified = s.st_mtime;
582 596 res->size = s.st_size;
583 if(res->last_modified == s.st_mtime 597 return res;
584 && res->size == s.st_size)
585 {
586 // file unchanged
587 return NULL;
588 } else {
589 // update db entries
590 res->size = s.st_size;
591 res->last_modified = s.st_mtime;
592
593 return res;
594 }
595 } else {
596 LocalResource *res = calloc(1, sizeof(LocalResource));
597 res->path = strdup(path);
598 res->etag = NULL;
599 res->last_modified = s.st_mtime;
600 res->size = s.st_size;
601 return res;
602 }
603 } else { 598 } else {
604 *isdir = 1; 599 *isdir = 1;
605 } 600 }
606 return NULL; 601 return NULL;
607 } 602 }
608 603
609 int sync_put_resource(SyncDirectory *dir, DavResource *res, SyncDatabase *db) { 604 int local_resource_is_changed(SyncDirectory *dir, SyncDatabase *db, LocalResource *res) {
605 LocalResource *db_res = ucx_map_cstr_get(db->resources, res->path);
606 if(db_res) {
607 if(db_res->etag) {
608 res->etag = strdup(db_res->etag);
609 }
610
611 if(db_res->last_modified == res->last_modified && db_res->size == res->size) {
612 return 0;
613 }
614 }
615 return 1;
616 }
617
618
619 int sync_put_resource(SyncDirectory *dir, DavResource *res, LocalResource *local) {
610 char *local_path = util_concat_path(dir->path, res->path); 620 char *local_path = util_concat_path(dir->path, res->path);
611 FILE *in = fopen(local_path, "r"); 621 FILE *in = fopen(local_path, "r");
612 if(!in) { 622 if(!in) {
613 fprintf(stderr, "Cannot open file %s\n", local_path); 623 fprintf(stderr, "Cannot open file %s\n", local_path);
614 free(local_path); 624 free(local_path);
628 } 638 }
629 ret = 0; 639 ret = 0;
630 break; 640 break;
631 } 641 }
632 642
633 if(ret == 0) { 643 if(ret == 0) {
634 LocalResource *local_res = ucx_map_cstr_get(db->resources, res->path); 644 // get new etag
635 if(local_res->etag) {
636 free(local_res->etag);
637 }
638
639 DavResource *up_res = dav_get(res->session, res->path, "D:getetag"); 645 DavResource *up_res = dav_get(res->session, res->path, "D:getetag");
640 char *etag = dav_get_property(up_res, "D:getetag"); 646 char *etag = dav_get_property(up_res, "D:getetag");
641 if(etag) { 647 if(etag) {
642 if(strlen(etag) > 2 && etag[0] == 'W' && etag[1] == '/') { 648 if(strlen(etag) > 2 && etag[0] == 'W' && etag[1] == '/') {
643 etag = etag + 2; 649 etag = etag + 2;
644 } 650 }
645 } 651 }
646 652
653 if(local->etag) {
654 free(local->etag);
655 }
647 656
648 if(etag) { 657 if(etag) {
649 local_res->etag = strdup(etag); 658 local->etag = strdup(etag);
650 } else { 659 } else {
651 local_res->etag = NULL; 660 local->etag = NULL;
652 } 661 }
662 dav_resource_free(up_res);
653 } 663 }
654 664
655 fclose(in); 665 fclose(in);
656 666
657 return 0; 667 return ret;
658 } 668 }
659 669
660 670
661 671
662 int cmd_sync(CmdArgs *a) { 672 int cmd_sync(CmdArgs *a) {

mercurial