dav/sync.c

changeset 65
d4077e8175f3
parent 64
112dbf7ba8b0
child 66
f8c1f685e08e
equal deleted inserted replaced
64:112dbf7ba8b0 65:d4077e8175f3
85 int ret = EXIT_FAILURE; 85 int ret = EXIT_FAILURE;
86 if(!strcmp(cmd, "pull")) { 86 if(!strcmp(cmd, "pull")) {
87 ret = cmd_pull(args); 87 ret = cmd_pull(args);
88 } else if(!strcmp(cmd, "push")) { 88 } else if(!strcmp(cmd, "push")) {
89 ret = cmd_push(args); 89 ret = cmd_push(args);
90 } else if(!strcmp(cmd, "sync")) {
91 ret = cmd_sync(args);
92 } 90 }
93 91
94 // TODO: cleanup sync config (don't forget to call regfree for regex) 92 // TODO: cleanup sync config (don't forget to call regfree for regex)
95 93
96 return ret; 94 return ret;
107 fprintf(stderr, " -c Disable conflict detection\n"); 105 fprintf(stderr, " -c Disable conflict detection\n");
108 fprintf(stderr, " -r Read changes from stdin\n\n"); 106 fprintf(stderr, " -r Read changes from stdin\n\n");
109 } 107 }
110 108
111 static int res_matches_filter(SyncDirectory *dir, char *res_path) { 109 static int res_matches_filter(SyncDirectory *dir, char *res_path) {
110 // trash filter
111 if (dir->trash) {
112 sstr_t rpath = sstr(util_concat_path(dir->path, res_path));
113 if (sstrprefix(rpath, sstr(dir->trash))) {
114 free(rpath.ptr);
115 return 1;
116 }
117 free(rpath.ptr);
118 }
119
120 // include/exclude filter
112 UCX_FOREACH(inc, dir->include) { 121 UCX_FOREACH(inc, dir->include) {
113 regex_t* pattern = (regex_t*) inc->data; 122 regex_t* pattern = (regex_t*) inc->data;
114 if (regexec(pattern, res_path, 0, NULL, 0) == 0) { 123 if (regexec(pattern, res_path, 0, NULL, 0) == 0) {
115 UCX_FOREACH(exc, dir->exclude) { 124 UCX_FOREACH(exc, dir->exclude) {
116 regex_t* pattern = (regex_t*) exc->data; 125 regex_t* pattern = (regex_t*) exc->data;
213 UCX_MAP_FOREACH(key, local, i) { 222 UCX_MAP_FOREACH(key, local, i) {
214 if (res_matches_filter(dir, local->path)) { 223 if (res_matches_filter(dir, local->path)) {
215 continue; 224 continue;
216 } 225 }
217 // sync_remove_resource does all necessary tests 226 // sync_remove_resource does all necessary tests
218 sync_remove_resource(dir, local); 227 sync_remove_local_resource(dir, local);
219 } 228 }
220 ucx_map_free(db->resources); 229 ucx_map_free(db->resources);
221 db->resources = svrres; 230 db->resources = svrres;
222 231
223 // TODO: cleanup - BUT DONT CLEANUP SYNC CONFIG (do this in main!) 232 // TODO: cleanup - BUT DONT CLEANUP SYNC CONFIG (do this in main!)
230 239
231 return 0; 240 return 0;
232 } 241 }
233 242
234 int sync_get_resource(CmdArgs *a, SyncDirectory *dir, DavResource *res, SyncDatabase *db) { 243 int sync_get_resource(CmdArgs *a, SyncDirectory *dir, DavResource *res, SyncDatabase *db) {
235 LocalResource *removed = ucx_map_cstr_get(db->remove, res->path);
236 if(removed) {
237 return 0;
238 }
239 int cdt = cmd_getoption(a, "conflict") ? 0 : 1; // conflict detection 244 int cdt = cmd_getoption(a, "conflict") ? 0 : 1; // conflict detection
240 245
241 LocalResource *local = ucx_map_cstr_get(db->resources, res->path); 246 LocalResource *local = ucx_map_cstr_get(db->resources, res->path);
242 char *local_path = util_concat_path(dir->path, res->path); 247 char *local_path = util_concat_path(dir->path, res->path);
243 248
244 char *etag = dav_get_property(res, "D:getetag"); 249 char *etag = dav_get_property(res, "D:getetag");
245 struct stat s; 250 struct stat s;
246 if(local) { 251 if(local) {
252 int exists = 1;
247 if(stat(local_path, &s)) { 253 if(stat(local_path, &s)) {
248 // Ignore the fact, that the file is locally removed. If the 254 // Ignore the fact, that the file is locally removed. If the
249 // server has an updated version, we readd the file or the 255 // server has an updated version, we readd the file or the
250 // next push will delete it on the server. 256 // next push will delete it on the server.
251 if(errno != ENOENT) { 257 if(errno != ENOENT) {
252 fprintf(stderr, "Cannot stat file: %s\n", local_path); 258 fprintf(stderr, "Cannot stat file: %s\n", local_path);
253 free(local_path); 259 free(local_path);
254 return -1; 260 return -1;
261 } else {
262 exists = 0;
255 } 263 }
256 } 264 }
257 265
258 if(local->etag) { 266 if(local->etag) {
259 sstr_t e = sstr(etag); 267 sstr_t e = sstr(etag);
264 // resource is already up-to-date on the client 272 // resource is already up-to-date on the client
265 return 0; 273 return 0;
266 } 274 }
267 } 275 }
268 276
269 if(cdt && s.st_mtime != local->last_modified) { 277 if(cdt && exists && s.st_mtime != local->last_modified) {
270 // file modified on the server and on the client 278 // file modified on the server and on the client
271 rename_local_file(dir, db, local->path); 279 rename_local_file(dir, db, local->path);
272 } 280 }
273 } else { 281 } else {
274 if(stat(local_path, &s)) { 282 if(stat(local_path, &s)) {
326 334
327 free(local_path); 335 free(local_path);
328 return ret; 336 return ret;
329 } 337 }
330 338
331 void sync_remove_resource(SyncDirectory *dir, LocalResource *res) { 339 void sync_remove_local_resource(SyncDirectory *dir, LocalResource *res) {
332 char *local_path = util_concat_path(dir->path, res->path); 340 char *local_path = util_concat_path(dir->path, res->path);
333 struct stat s; 341 struct stat s;
334 if(stat(local_path, &s)) { 342 if(stat(local_path, &s)) {
335 free(local_path); 343 free(local_path);
336 return; 344 return;
340 free(local_path); 348 free(local_path);
341 return; 349 return;
342 } 350 }
343 351
344 printf("delete: %s\n", res->path); 352 printf("delete: %s\n", res->path);
345 if(unlink(local_path)) { 353
354 if(dir->trash) {
355 move_to_trash(dir, local_path);
356 } else if(unlink(local_path)) {
346 fprintf(stderr, "Cannot remove file %s\n", local_path); 357 fprintf(stderr, "Cannot remove file %s\n", local_path);
347 } 358 }
348 free(local_path); 359 free(local_path);
349 } 360 }
350 361
367 if(stat(new_path.ptr, &s)) { 378 if(stat(new_path.ptr, &s)) {
368 if(errno == ENOENT) { 379 if(errno == ENOENT) {
369 loop = 0; 380 loop = 0;
370 printf("conflict: %s\n", local_path); 381 printf("conflict: %s\n", local_path);
371 if(rename(local_path, new_path.ptr)) { 382 if(rename(local_path, new_path.ptr)) {
372 printf("errno: %d\n", errno); 383 //printf("errno: %d\n", errno);
373 fprintf( 384 fprintf(
374 stderr, 385 stderr,
375 "Cannot rename file %s to %s\n", 386 "Cannot rename file %s to %s\n",
376 local_path, 387 local_path,
377 new_path.ptr); 388 new_path.ptr);
380 } 391 }
381 rev++; 392 rev++;
382 free(new_path.ptr); 393 free(new_path.ptr);
383 } while(loop); 394 } while(loop);
384 free(parent); 395 free(parent);
396 }
397
398 void move_to_trash(SyncDirectory *dir, char *path) {
399 char *new_path = NULL;
400 for (int i=0;;i++) {
401 sstr_t np = ucx_asprintf(
402 ucx_default_allocator(),
403 "%s%d-%s",
404 dir->trash,
405 i,
406 util_resource_name(path));
407
408 struct stat s;
409 if(stat(np.ptr, &s)) {
410 if(errno == ENOENT) {
411 new_path = np.ptr;
412 }
413 break;
414 }
415 free(np.ptr);
416 };
417
418 if(!new_path) {
419 fprintf(stderr, "Cannot move file %s to trash.\n", path);
420 return;
421 }
422
423 if(rename(path, new_path)) {
424 //printf("errno: %d\n", errno);
425 fprintf(
426 stderr,
427 "Cannot rename file %s to %s\n",
428 path,
429 new_path);
430 }
431
432 free(new_path);
385 } 433 }
386 434
387 int cmd_push(CmdArgs *a) { 435 int cmd_push(CmdArgs *a) {
388 if(a->argc != 1) { 436 if(a->argc != 1) {
389 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many"); 437 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many");
451 499
452 // delete all removed files 500 // delete all removed files
453 UcxMapIterator i = ucx_map_iterator(db->resources); 501 UcxMapIterator i = ucx_map_iterator(db->resources);
454 LocalResource *local; 502 LocalResource *local;
455 UCX_MAP_FOREACH(key, local, i) { 503 UCX_MAP_FOREACH(key, local, i) {
456 // TODO: save deletion: check for remote changes 504 if(sync_delete_remote_resource(sn, local)) {
457 505 ucx_map_cstr_put(lclres, local->path, local);
458 DavResource *res = dav_resource_new(sn, local->path); 506 }
459 printf("delete: %s\n", res->path);
460 if(dav_delete(res)) {
461 if(sn->error != DAV_NOT_FOUND) {
462 fprintf(stderr, "Cannot delete resource %s\n", res->path);
463 }
464 }
465 dav_resource_free(res);
466 // TODO: free local resource
467 ucx_map_remove(db->remove, key);
468 } 507 }
469 ucx_map_free(db->resources); 508 ucx_map_free(db->resources);
470 db->resources = lclres; 509 db->resources = lclres;
471 510
472 // TODO: free res 511 // TODO: free res
665 fclose(in); 704 fclose(in);
666 705
667 return ret; 706 return ret;
668 } 707 }
669 708
670 709 int sync_delete_remote_resource(DavSession *sn, LocalResource *local_res) {
671 710 DavResource *res = dav_get(sn, local_res->path, "D:getetag");
672 int cmd_sync(CmdArgs *a) { 711 if(!res) {
673 return 0; 712 return sn->error == DAV_NOT_FOUND ? 0 : 1;
674 } 713 }
675 714
715 char *etag = dav_get_property(res, "D:getetag");
716 if(etag) {
717 if(strlen(etag) > 2 && etag[0] == 'W' && etag[1] == '/') {
718 etag = etag + 2;
719 }
720 }
721
722 int ret = 0;
723 if(!strcmp(etag, local_res->etag)) {
724 // local resource metadata == remote resource metadata
725 // resource can be deleted
726 printf("delete: %s\n", res->path);
727 if(dav_delete(res)) {
728 if(sn->error != DAV_NOT_FOUND) {
729 fprintf(stderr, "Cannot delete resource %s\n", res->path);
730 }
731 }
732 } else {
733 ret = 1;
734 }
735
736 // cleanup
737 dav_resource_free(res);
738
739 return ret;
740 }
741
742
743

mercurial