dav/sync.c

changeset 53
ddc4efc9b0f8
parent 52
91517b874a86
child 54
fc34bd28a22a
equal deleted inserted replaced
52:91517b874a86 53:ddc4efc9b0f8
45 #include "scfg.h" 45 #include "scfg.h"
46 #include "sopt.h" 46 #include "sopt.h"
47 #include "db.h" 47 #include "db.h"
48 48
49 #include "sync.h" 49 #include "sync.h"
50 #include "ucx/properties.h"
50 51
51 static DavContext *ctx; 52 static DavContext *ctx;
52 53
53 static void xmlerrorfnc(void * c, const char * msg, ... ) { 54 static void xmlerrorfnc(void * c, const char * msg, ... ) {
54 // nothing 55 // nothing
87 88
88 return ret; 89 return ret;
89 } 90 }
90 91
91 void print_usage(char *cmd) { 92 void print_usage(char *cmd) {
92 93 fprintf(stderr, "Usage: %s command [options] arguments...\n\n", cmd);
94
95 fprintf(stderr, "Commands:\n");
96 fprintf(stderr, " pull [-c] <directory>\n");
97 fprintf(stderr, " push [-r] <directory>\n\n");
98
99 fprintf(stderr, "Options:\n");
100 fprintf(stderr, " -c Disable conflict detection\n");
101 fprintf(stderr, " -r Read changes from stdin\n\n");
93 } 102 }
94 103
95 int cmd_pull(CmdArgs *a) { 104 int cmd_pull(CmdArgs *a) {
96 if(a->argc != 1) { 105 if(a->argc != 1) {
97 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many"); 106 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many");
143 DavResource *res = stack->data; 152 DavResource *res = stack->data;
144 stack = ucx_list_remove(stack, stack); 153 stack = ucx_list_remove(stack, stack);
145 154
146 while(res) { 155 while(res) {
147 // download the resource 156 // download the resource
148 if(sync_get_resource(dir, res, db)) { 157 if(sync_get_resource(a, dir, res, db)) {
149 fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path); 158 fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path);
150 } 159 }
151 160
152 LocalResource *local = ucx_map_cstr_get(db->resources, res->path); 161 LocalResource *local = ucx_map_cstr_get(db->resources, res->path);
153 ucx_map_cstr_put(svrres, res->path, local); 162 ucx_map_cstr_put(svrres, res->path, local);
177 } 186 }
178 187
179 return 0; 188 return 0;
180 } 189 }
181 190
182 int sync_get_resource(SyncDirectory *dir, DavResource *res, SyncDatabase *db) { 191 int sync_get_resource(CmdArgs *a, SyncDirectory *dir, DavResource *res, SyncDatabase *db) {
183 LocalResource *removed = ucx_map_cstr_get(db->remove, res->path); 192 LocalResource *removed = ucx_map_cstr_get(db->remove, res->path);
184 if(removed) { 193 if(removed) {
185 return 0; 194 return 0;
186 } 195 }
196 int cdt = cmd_getoption(a, "conflict") ? 0 : 1;
187 197
188 LocalResource *local = ucx_map_cstr_get(db->resources, res->path); 198 LocalResource *local = ucx_map_cstr_get(db->resources, res->path);
189 char *local_path = util_concat_path(dir->path, res->path); 199 char *local_path = util_concat_path(dir->path, res->path);
190 200
191 char *etag = dav_get_property(res, "D:getetag"); 201 char *etag = dav_get_property(res, "D:getetag");
215 // resource is already up-to-date on the client 225 // resource is already up-to-date on the client
216 return 0; 226 return 0;
217 } 227 }
218 } 228 }
219 229
220 if(s.st_mtim.tv_sec != local->last_modified) { 230 if(cdt && s.st_mtim.tv_sec != local->last_modified) {
221 // file modified on the server and on the client 231 // file modified on the server and on the client
222 rename_local_file(dir, db, local->path); 232 rename_local_file(dir, db, local->path);
223 } 233 }
224 } else { 234 } else {
225 if(stat(local_path, &s)) { 235 if(stat(local_path, &s)) {
226 if(errno != ENOENT) { 236 if(errno != ENOENT) {
227 fprintf(stderr, "Cannot stat file: %s\n", local_path); 237 fprintf(stderr, "Cannot stat file: %s\n", local_path);
228 } 238 }
229 } else if(!S_ISDIR(s.st_mode)) { 239 } else if(cdt && !S_ISDIR(s.st_mode)) {
230 rename_local_file(dir, db, res->path); 240 rename_local_file(dir, db, res->path);
231 } 241 }
232 } 242 }
233 243
234 int ret = 0; 244 int ret = 0;
364 repo->password); 374 repo->password);
365 dav_session_set_flags(sn, get_repository_flags(repo)); 375 dav_session_set_flags(sn, get_repository_flags(repo));
366 sn->key = dav_context_get_key(ctx, repo->default_key); 376 sn->key = dav_context_get_key(ctx, repo->default_key);
367 377
368 // upload all changed files 378 // upload all changed files
369 UcxList *resources = local_scan(dir, db); 379 //UcxList *resources = local_scan(dir, db);
380 //UcxList *resources = read_changes(dir, db);
381 UcxList *resources = cmd_getoption(a, "read") ?
382 read_changes(dir, db) : local_scan(dir, db);
383
370 UCX_FOREACH(elm, resources) { 384 UCX_FOREACH(elm, resources) {
371 char *path = elm->data; 385 char *path = elm->data;
372 printf("put: %s\n", path); 386 printf("put: %s\n", path);
373 DavResource *res = dav_resource_new(sn, path); 387 DavResource *res = dav_resource_new(sn, path);
374 sync_put_resource(dir, res, db); 388 sync_put_resource(dir, res, db);
432 if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) { 446 if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
433 continue; 447 continue;
434 } 448 }
435 449
436 char *new_path = util_concat_path(p, ent->d_name); 450 char *new_path = util_concat_path(p, ent->d_name);
437 char *file_path = util_concat_path(dir->path, new_path); 451 int isdir;
438 struct stat s; 452 LocalResource *res = path_to_local_resource(dir, db, new_path, &isdir);
439 if(stat(file_path, &s)) { 453 if(isdir) {
440 fprintf(stderr, "Cannot stat file %s\n", file_path); 454 stack = ucx_list_prepend(stack, new_path);
455 } else if(res) {
456 resources = ucx_list_append(resources, strdup(res->path));
441 free(new_path); 457 free(new_path);
442 free(file_path);
443 continue;
444 }
445 free(file_path);
446
447 if(S_ISDIR(s.st_mode)) {
448 stack = ucx_list_prepend(stack, new_path);
449 } else { 458 } else {
450 LocalResource *res = ucx_map_cstr_get( 459 free(new_path);
451 db->resources,
452 new_path);
453 if(res) {
454 // the file is already in the database
455 // compare length and lastmodified date
456
457 if(res->last_modified == s.st_mtim.tv_sec
458 && res->size == s.st_size)
459 {
460 // skip this file
461 free(new_path);
462 } else {
463 // add file to list
464 resources = ucx_list_append(
465 resources,
466 new_path);
467
468 // update db entries
469 res->size = s.st_size;
470 res->last_modified = s.st_mtim.tv_sec;
471 }
472 } else {
473 // add file to list
474 LocalResource *res = calloc(1, sizeof(LocalResource));
475 res->path = strdup(new_path);
476 res->etag = NULL;
477 res->last_modified = s.st_mtim.tv_sec;
478 res->size = s.st_size;
479 ucx_map_cstr_put(db->resources, res->path, res);
480 resources = ucx_list_append(resources, new_path);
481 }
482 } 460 }
483 } 461 }
484 closedir(local_dir); 462 closedir(local_dir);
485 free(ent); 463 free(ent);
486 } 464 }
487 free(local_path); 465 free(local_path);
488 free(p); 466 free(p);
489 } 467 }
490 468
491 return resources; 469 return resources;
470 }
471
472 UcxList* read_changes(SyncDirectory *dir, SyncDatabase *db) {
473 UcxProperties *parser = ucx_properties_new();
474 parser->delimiter = ':';
475
476 UcxList *resources = NULL;
477 sstr_t name;
478 sstr_t value;
479
480 char buf[STDIN_BUF_SIZE];
481 size_t r;
482 while(!feof(stdin)) {
483 r = fread(buf, 1, STDIN_BUF_SIZE, stdin);
484 ucx_properties_fill(parser, buf, r);
485 while(ucx_properties_next(parser, &name, &value)) {
486 if(value.length == 0) {
487 fprintf(stderr, "Wrong input\n");
488 continue;
489 }
490 if(value.ptr[0] == '"'
491 && value.length > 2
492 && value.ptr[value.length - 1] == '"')
493 {
494 value.ptr[value.length - 1] = '\0';
495 value.ptr++;
496 value.length -= 2;
497 }
498 value = sstrdup(value);
499
500 if(!sstrcmp(name, S("put"))) {
501 int isdir;
502 LocalResource *res = path_to_local_resource(dir, db, value.ptr, &isdir);
503 if(res) {
504 resources = ucx_list_append(resources, strdup(res->path));
505 }
506 } else if(!sstrcmp(name, S("remove"))) {
507 int isdir;
508 //LocalResource *res = path_to_local_resource(dir, db, value.ptr, &isdir);
509 LocalResource *res = calloc(1, sizeof(LocalResource));
510 res->path = sstrdup(value).ptr;
511 if(res) {
512 ucx_map_sstr_put(db->remove, value, res);
513 ucx_map_sstr_remove(db->resources, value);
514 }
515
516 }
517
518 free(value.ptr);
519 }
520 }
521 ucx_properties_free(parser);
522
523 return resources;
524 }
525
526 LocalResource* path_to_local_resource(SyncDirectory *dir, SyncDatabase *db, char *path, int *isdir) {
527 char *file_path = util_concat_path(dir->path, path);
528 struct stat s;
529 if(stat(file_path, &s)) {
530 fprintf(stderr, "Cannot stat file %s\n", file_path);
531 free(file_path);
532 return NULL;
533 }
534 free(file_path);
535
536 if(!S_ISDIR(s.st_mode)) {
537 *isdir = 0;
538 LocalResource *res = ucx_map_cstr_get(db->resources, path);
539 if(res) {
540 // the file is already in the database
541 // compare length and lastmodified date
542
543 if(res->last_modified == s.st_mtim.tv_sec
544 && res->size == s.st_size)
545 {
546 // file unchanged
547 return NULL;
548 } else {
549 // update db entries
550 res->size = s.st_size;
551 res->last_modified = s.st_mtim.tv_sec;
552
553 return res;
554 }
555 } else {
556 LocalResource *res = calloc(1, sizeof(LocalResource));
557 res->path = strdup(path);
558 res->etag = NULL;
559 res->last_modified = s.st_mtim.tv_sec;
560 res->size = s.st_size;
561 ucx_map_cstr_put(db->resources, res->path, res);
562 return res;
563 }
564 } else {
565 *isdir = 1;
566 }
567 return NULL;
492 } 568 }
493 569
494 int sync_put_resource(SyncDirectory *dir, DavResource *res, SyncDatabase *db) { 570 int sync_put_resource(SyncDirectory *dir, DavResource *res, SyncDatabase *db) {
495 char *local_path = util_concat_path(dir->path, res->path); 571 char *local_path = util_concat_path(dir->path, res->path);
496 FILE *in = fopen(local_path, "r"); 572 FILE *in = fopen(local_path, "r");

mercurial