169 void print_usage(char *cmd) { |
169 void print_usage(char *cmd) { |
170 fprintf(stderr, "Usage: %s command [options] arguments...\n\n", cmd); |
170 fprintf(stderr, "Usage: %s command [options] arguments...\n\n", cmd); |
171 |
171 |
172 fprintf(stderr, "Commands:\n"); |
172 fprintf(stderr, "Commands:\n"); |
173 fprintf(stderr, " pull [-cldr] [-t <tags>] <directory>\n"); |
173 fprintf(stderr, " pull [-cldr] [-t <tags>] <directory>\n"); |
174 fprintf(stderr, " push [-cldr] [-t <tags>] <directory>\n"); |
174 fprintf(stderr, " push [-cldrDM] [-t <tags>] <directory>\n"); |
175 fprintf(stderr, " archive [-cld] [-t <tags>] <directory>\n"); |
175 fprintf(stderr, " archive [-cldDM] [-t <tags>] <directory>\n"); |
176 fprintf(stderr, " resolve-conflicts <directory>\n"); |
176 fprintf(stderr, " resolve-conflicts <directory>\n"); |
177 fprintf(stderr, " delete-conflicts <directory>\n"); |
177 fprintf(stderr, " delete-conflicts <directory>\n"); |
178 fprintf(stderr, " trash-info <directory>\n"); |
178 fprintf(stderr, " trash-info <directory>\n"); |
179 fprintf(stderr, " empty-trash <directory>\n"); |
179 fprintf(stderr, " empty-trash <directory>\n"); |
180 fprintf(stderr, " add-tag [-s <syncdir>] <file> <tag>\n"); |
180 fprintf(stderr, " add-tag [-s <syncdir>] <file> <tag>\n"); |
188 fprintf(stderr, " -d Don't lock the repository\n"); |
188 fprintf(stderr, " -d Don't lock the repository\n"); |
189 fprintf(stderr, " -t <tags> " |
189 fprintf(stderr, " -t <tags> " |
190 "Only sync files which have the specified tags\n"); |
190 "Only sync files which have the specified tags\n"); |
191 fprintf(stderr, " -r " |
191 fprintf(stderr, " -r " |
192 "Remove resources not matching the tag filter\n"); |
192 "Remove resources not matching the tag filter\n"); |
|
193 fprintf(stderr, " -D restore deleted files\n"); |
|
194 fprintf(stderr, " -M restore modified files\n"); |
193 fprintf(stderr, " -v verbose output (all commands)\n\n"); |
195 fprintf(stderr, " -v verbose output (all commands)\n\n"); |
194 |
196 |
195 fprintf(stderr, "Config commands:\n"); |
197 fprintf(stderr, "Config commands:\n"); |
196 fprintf(stderr, " add-directory\n"); |
198 fprintf(stderr, " add-directory\n"); |
197 fprintf(stderr, " list-directories\n"); |
199 fprintf(stderr, " list-directories\n"); |
355 LocalResource *local = ucx_map_cstr_remove(db->resources, path); |
357 LocalResource *local = ucx_map_cstr_remove(db->resources, path); |
356 if(local) { |
358 if(local) { |
357 local->keep = TRUE; |
359 local->keep = TRUE; |
358 } |
360 } |
359 |
361 |
|
362 } |
|
363 |
|
364 void res2map(DavResource *root, UcxMap *map) { |
|
365 UcxList *stack = ucx_list_prepend(NULL, root->children); |
|
366 while(stack) { |
|
367 DavResource *res = stack->data; |
|
368 stack = ucx_list_remove(stack, stack); |
|
369 |
|
370 while(res) { |
|
371 ucx_map_cstr_put(map, res->path, res); |
|
372 |
|
373 if(res->children) { |
|
374 stack = ucx_list_prepend(stack, res->children); |
|
375 } |
|
376 res = res->next; |
|
377 } |
|
378 } |
360 } |
379 } |
361 |
380 |
362 int cmd_pull(CmdArgs *a) { |
381 int cmd_pull(CmdArgs *a) { |
363 if(a->argc != 1) { |
382 if(a->argc != 1) { |
364 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many"); |
383 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many"); |
995 if (cmd_getoption(a, "verbose")) { |
1014 if (cmd_getoption(a, "verbose")) { |
996 curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L); |
1015 curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L); |
997 curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr); |
1016 curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr); |
998 } |
1017 } |
999 |
1018 |
1000 DavResource *root = dav_query(sn, "select - from / with depth = 0"); |
1019 DavBool restore_deleted = cmd_getoption(a, "restore-deleted") ? 1 : 0; |
|
1020 DavBool restore_modified = cmd_getoption(a, "restore-modified") ? 1 : 0; |
|
1021 DavBool restore = restore_deleted || restore_modified; |
|
1022 int depth = restore ? -1 : 0; |
|
1023 |
|
1024 DavResource *root = dav_query(sn, "select D:getetag,idav:status from / with depth = %d", depth); |
1001 if(!root) { |
1025 if(!root) { |
1002 print_resource_error(sn, "/"); |
1026 print_resource_error(sn, "/"); |
1003 dav_session_destroy(sn); |
1027 dav_session_destroy(sn); |
1004 fprintf(stderr, "Abort\n"); |
1028 fprintf(stderr, "Abort\n"); |
1005 return -1; |
1029 return -1; |
|
1030 } |
|
1031 |
|
1032 UcxMap *svrres = NULL; |
|
1033 if(restore) { |
|
1034 svrres = ucx_map_new(1024); |
|
1035 res2map(root, svrres); |
1006 } |
1036 } |
1007 |
1037 |
1008 int cdt = cmd_getoption(a, "conflict") ? 0 : 1; // conflict detection |
1038 int cdt = cmd_getoption(a, "conflict") ? 0 : 1; // conflict detection |
1009 |
1039 |
1010 // lock repository |
1040 // lock repository |
1081 sync_skipped++; |
1111 sync_skipped++; |
1082 continue; |
1112 continue; |
1083 } |
1113 } |
1084 |
1114 |
1085 // upload every changed file |
1115 // upload every changed file |
1086 int is_changed = local_resource_is_changed(dir, db, local_res); |
1116 int is_changed = local_resource_is_changed( |
|
1117 dir, |
|
1118 db, |
|
1119 local_res, |
|
1120 svrres, |
|
1121 restore_deleted, |
|
1122 restore_modified); |
1087 if (is_changed || local_res->tags_updated) { |
1123 if (is_changed || local_res->tags_updated) { |
1088 DavResource *res = dav_resource_new(sn, local_res->path); |
1124 DavResource *res = dav_resource_new(sn, local_res->path); |
1089 if(!res) { |
1125 if(!res) { |
1090 print_resource_error(sn, local_res->path); |
1126 print_resource_error(sn, local_res->path); |
1091 ret = -1; |
1127 ret = -1; |
1371 } |
1407 } |
1372 newres->tags_updated = res->tags_updated; |
1408 newres->tags_updated = res->tags_updated; |
1373 return newres; |
1409 return newres; |
1374 } |
1410 } |
1375 |
1411 |
1376 int local_resource_is_changed(SyncDirectory *dir, SyncDatabase *db, LocalResource *res) { |
1412 int local_resource_is_changed( |
|
1413 SyncDirectory *dir, |
|
1414 SyncDatabase *db, |
|
1415 LocalResource *res, |
|
1416 UcxMap *svrres, |
|
1417 DavBool restore_deleted, |
|
1418 DavBool restore_modified) |
|
1419 { |
1377 LocalResource *db_res = ucx_map_cstr_get(db->resources, res->path); |
1420 LocalResource *db_res = ucx_map_cstr_get(db->resources, res->path); |
1378 res->tags_updated = 0; |
1421 res->tags_updated = 0; |
1379 if(db_res) { |
1422 if(db_res) { |
|
1423 if(svrres) { |
|
1424 DavResource *remote = ucx_map_cstr_get(svrres, res->path); |
|
1425 if(restore_deleted && !remote) { |
|
1426 return 1; |
|
1427 } |
|
1428 if(!res->isdirectory && restore_modified && remote) { |
|
1429 char *etag = dav_get_string_property(remote, "D:getetag"); |
|
1430 if(!etag || (db_res->etag && strcmp(etag, db_res->etag))) { |
|
1431 res->restore = TRUE; |
|
1432 return 1; |
|
1433 } |
|
1434 } |
|
1435 } |
|
1436 |
1380 res->tags_updated = db_res->tags_updated; |
1437 res->tags_updated = db_res->tags_updated; |
1381 if(db_res->etag) { |
1438 if(db_res->etag) { |
1382 res->etag = strdup(db_res->etag); |
1439 res->etag = strdup(db_res->etag); |
1383 } |
1440 } |
1384 if(db_res->tags_hash) { |
1441 if(db_res->tags_hash) { |