dav/sync.c

changeset 533
5b9f20aa88c2
parent 532
aeda47714978
child 536
877f7c4a203b
equal deleted inserted replaced
532:aeda47714978 533:5b9f20aa88c2
69 va_list ap; 69 va_list ap;
70 va_start(ap, msg); 70 va_start(ap, msg);
71 vfprintf(stderr, msg, ap); 71 vfprintf(stderr, msg, ap);
72 va_end(ap); 72 va_end(ap);
73 } 73 }
74
75 static DavPropName defprops[] = {
76 { "DAV:", "getetag" },
77 { DAV_NS, "status" },
78 { DAV_NS, "finfo" },
79 { DAV_NS, "tags" },
80 { DAV_NS, "xattributes" }
81 };
82 static size_t numdefprops = 5;
74 83
75 /* 84 /*
76 * strcmp version that works with NULL pointers 85 * strcmp version that works with NULL pointers
77 */ 86 */
78 static int nullstrcmp(const char *s1, const char *s2) { 87 static int nullstrcmp(const char *s1, const char *s2) {
192 void print_usage(char *cmd) { 201 void print_usage(char *cmd) {
193 fprintf(stderr, "Usage: %s command [options] arguments...\n\n", cmd); 202 fprintf(stderr, "Usage: %s command [options] arguments...\n\n", cmd);
194 203
195 fprintf(stderr, "Commands:\n"); 204 fprintf(stderr, "Commands:\n");
196 fprintf(stderr, " pull [-cldr] [-t <tags>] <directory>\n"); 205 fprintf(stderr, " pull [-cldr] [-t <tags>] <directory>\n");
197 fprintf(stderr, " push [-cldrVRM] [-t <tags>] <directory>\n"); 206 fprintf(stderr, " push [-cldrSRM] [-t <tags>] <directory>\n");
198 fprintf(stderr, " archive [-cldVRM] [-t <tags>] <directory>\n"); 207 fprintf(stderr, " archive [-cldSRM] [-t <tags>] <directory>\n");
199 fprintf(stderr, " restore [-ldRM] [-s <directory>] [file...]\n"); 208 fprintf(stderr,
209 " restore [-ldRM] [-V <version>] [-s <directory>] [file...]\n");
200 fprintf(stderr, " resolve-conflicts <directory>\n"); 210 fprintf(stderr, " resolve-conflicts <directory>\n");
201 fprintf(stderr, " delete-conflicts <directory>\n"); 211 fprintf(stderr, " delete-conflicts <directory>\n");
202 fprintf(stderr, " trash-info <directory>\n"); 212 fprintf(stderr, " trash-info <directory>\n");
203 fprintf(stderr, " empty-trash <directory>\n"); 213 fprintf(stderr, " empty-trash <directory>\n");
204 fprintf(stderr, " add-tag [-s <syncdir>] <file> <tag>\n"); 214 fprintf(stderr, " add-tag [-s <syncdir>] <file> <tag>\n");
212 fprintf(stderr, " -d Don't lock the repository\n"); 222 fprintf(stderr, " -d Don't lock the repository\n");
213 fprintf(stderr, " -t <tags> " 223 fprintf(stderr, " -t <tags> "
214 "Only sync files which have the specified tags\n"); 224 "Only sync files which have the specified tags\n");
215 fprintf(stderr, " -r " 225 fprintf(stderr, " -r "
216 "Remove resources not matching the tag filter\n"); 226 "Remove resources not matching the tag filter\n");
217 fprintf(stderr, " -V Enable versioning\n"); 227 fprintf(stderr, " -V <vers> Restore specific version\n");
228 fprintf(stderr, " -S Save previous file version\n");
218 fprintf(stderr, " -R Restore removed files\n"); 229 fprintf(stderr, " -R Restore removed files\n");
219 fprintf(stderr, " -M Restore modified files\n"); 230 fprintf(stderr, " -M Restore modified files\n");
220 fprintf(stderr, " -v Verbose output (all commands)\n\n"); 231 fprintf(stderr, " -v Verbose output (all commands)\n\n");
221 232
222 fprintf(stderr, "Config commands:\n"); 233 fprintf(stderr, "Config commands:\n");
682 if(ucx_map_cstr_get(conflicts, res->path)) { 693 if(ucx_map_cstr_get(conflicts, res->path)) {
683 rename_conflict_file(dir, db, res->path); 694 rename_conflict_file(dir, db, res->path);
684 } 695 }
685 696
686 // download the resource 697 // download the resource
687 if(sync_get_resource(a, dir, res, db, &sync_success)) { 698 if(sync_get_resource(a, dir, res->path, res, db, &sync_success)) {
688 fprintf(stderr, "resource download failed: %s\n", res->path); 699 fprintf(stderr, "resource download failed: %s\n", res->path);
689 sync_error++; 700 sync_error++;
690 } 701 }
691 } 702 }
692 703
906 } 917 }
907 918
908 int sync_get_resource( 919 int sync_get_resource(
909 CmdArgs *a, 920 CmdArgs *a,
910 SyncDirectory *dir, 921 SyncDirectory *dir,
922 const char *path,
911 DavResource *res, 923 DavResource *res,
912 SyncDatabase *db, 924 SyncDatabase *db,
913 int *counter) 925 int *counter)
914 { 926 {
915 LocalResource *local = ucx_map_cstr_get(db->resources, res->path); 927 LocalResource *local = ucx_map_cstr_get(db->resources, path);
916 char *local_path = util_concat_path(dir->path, res->path); 928 char *local_path = util_concat_path(dir->path, path);
917 929
918 char *etag = dav_get_string_property(res, "D:getetag"); 930 char *etag = dav_get_string_property(res, "D:getetag");
919 SYS_STAT s; 931 SYS_STAT s;
920 memset(&s, 0, sizeof(SYS_STAT)); 932 memset(&s, 0, sizeof(SYS_STAT));
921 933
932 fprintf(stderr, "Cannot open output file: %s\n", local_path); 944 fprintf(stderr, "Cannot open output file: %s\n", local_path);
933 free(local_path); 945 free(local_path);
934 free(tmp_path); 946 free(tmp_path);
935 return -1; 947 return -1;
936 } 948 }
937 printf("get: %s\n", res->path); 949 printf("get: %s\n", path);
938 if(dav_get_content(res, out, (dav_write_func)fwrite)) { 950 if(dav_get_content(res, out, (dav_write_func)fwrite)) {
939 ret = -1; 951 ret = -1;
940 } 952 }
941 fclose(out); 953 fclose(out);
942 954
943 if(ret == 0) { 955 if(ret == 0) {
944 (*counter)++; 956 (*counter)++;
945 957
946 if(sync_store_metadata(dir, tmp_path, local, res)) { 958 if(sync_store_metadata(dir, tmp_path, local, res)) {
947 fprintf(stderr, "Cannot store metadata: %s\n", res->path); 959 fprintf(stderr, "Cannot store metadata: %s\n", path);
948 } 960 }
949 961
950 if(dir->trash && dir->backuppull) { 962 if(dir->trash && dir->backuppull) {
951 move_to_trash(dir, local_path); 963 move_to_trash(dir, local_path);
952 } 964 }
968 } 980 }
969 981
970 if(!local) { 982 if(!local) {
971 // new local resource 983 // new local resource
972 local = calloc(1, sizeof(LocalResource)); 984 local = calloc(1, sizeof(LocalResource));
973 local->path = strdup(res->path); 985 local->path = strdup(path);
974 ucx_map_cstr_put(db->resources, local->path, local); 986 ucx_map_cstr_put(db->resources, local->path, local);
975 } 987 }
976 988
977 if(local->etag) { 989 if(local->etag) {
978 free(local->etag); 990 free(local->etag);
1175 return -1; 1187 return -1;
1176 } 1188 }
1177 if(scfg_check_dir(dir)) { 1189 if(scfg_check_dir(dir)) {
1178 return -1; 1190 return -1;
1179 } 1191 }
1180 if(cmd_getoption(a, "versioning")) { 1192 if(cmd_getoption(a, "snapshot")) {
1181 if(dir->versioning) { 1193 if(dir->versioning) {
1182 dir->versioning->always = TRUE; 1194 dir->versioning->always = TRUE;
1183 } else { 1195 } else {
1184 fprintf(stderr, "Error: versioning not configured for the sync directory\nAbort.\n"); 1196 fprintf(stderr, "Error: versioning not configured for the sync directory\nAbort.\n");
1185 return -1; 1197 return -1;
1427 1439
1428 // metadata updates 1440 // metadata updates
1429 for(UcxList *elm=ls_update;elm && !sync_shutdown;elm=elm->next) { 1441 for(UcxList *elm=ls_update;elm && !sync_shutdown;elm=elm->next) {
1430 LocalResource *local_res = elm->data; 1442 LocalResource *local_res = elm->data;
1431 1443
1432 DavResource *res = dav_resource_new(sn, local_res->path); 1444 DavResource *res = dav_resource_new(sn, local_res->path);
1433 if(dir->tagconfig) {
1434 DavPropName properties[] = {
1435 {DAV_NS,"tags"},
1436 };
1437 if(dav_load_prop(res, properties, 1)) {
1438 sync_error++;
1439 print_resource_error(sn, res->path);
1440 ret = -1;
1441 error = 1;
1442 continue;
1443 }
1444 }
1445
1446 if(local_res->metadata_updated) { 1445 if(local_res->metadata_updated) {
1447 if(!sync_update_metadata(dir, sn, res, local_res)) { 1446 if(!sync_update_metadata(dir, sn, res, local_res)) {
1448 LocalResource *dbres = ucx_map_cstr_remove(db->resources, local_res->path); 1447 LocalResource *dbres = ucx_map_cstr_remove(db->resources, local_res->path);
1449 ucx_map_cstr_put(db->resources, local_res->path, local_res); 1448 ucx_map_cstr_put(db->resources, local_res->path, local_res);
1450 } 1449 }
1533 if(!syncdir && a->argc == 0) { 1532 if(!syncdir && a->argc == 0) {
1534 fprintf(stderr, "No syncdir or files specified\n"); 1533 fprintf(stderr, "No syncdir or files specified\n");
1535 return -1; 1534 return -1;
1536 } 1535 }
1537 1536
1537 char *version = cmd_getoption(a, "version");
1538 if(version) {
1539 if(a->argc != 1) {
1540 fprintf(stderr, "If the -V option is enabled, only one file can be specified\n");
1541 return -1;
1542 }
1543 }
1544
1538 SyncDirectory *dir = NULL; 1545 SyncDirectory *dir = NULL;
1539 UcxMap *files = NULL; 1546 UcxMap *files = NULL;
1540 if(syncdir) { 1547 if(syncdir) {
1541 dir = scfg_get_dir(syncdir); 1548 dir = scfg_get_dir(syncdir);
1542 } 1549 }
1682 resources = ucx_list_sort(resources, (cmp_func)localres_cmp_path, NULL); 1689 resources = ucx_list_sort(resources, (cmp_func)localres_cmp_path, NULL);
1683 1690
1684 UCX_FOREACH(elm, resources) { 1691 UCX_FOREACH(elm, resources) {
1685 LocalResource *resource = elm->data; 1692 LocalResource *resource = elm->data;
1686 1693
1687 DavResource *res = dav_get(sn, resource->path, "D:getetag,idav:status,idav:finfo,idav:xattributes"); 1694 DavResource *res = dav_get(sn, resource->path, "D:getetag,idav:status,idav:version-collection,idav:finfo,idav:xattributes");
1688 if(!res) { 1695 if(!res) {
1689 printf("skip: %s\n", resource->path); 1696 printf("skip: %s\n", resource->path);
1690 continue; 1697 continue;
1691 //continue;
1692 } 1698 }
1693 char *status = dav_get_string_property(res, "idav:status"); 1699 char *status = dav_get_string_property(res, "idav:status");
1694 if(status && !strcmp(status, "broken")) { 1700 if(status && !strcmp(status, "broken")) {
1701 fprintf(stderr, "Resource %s broken\n", res->path);
1695 continue; 1702 continue;
1703 }
1704
1705 DavResource *vres = NULL;
1706 if(version) {
1707 if(dir->versioning->type == VERSIONING_SIMPLE) {
1708 vres = versioning_simple_find(res, version);
1709 } else if(dir->versioning->type == VERSIONING_DELTAV) {
1710 vres = versioning_deltav_find(res, version);
1711 }
1712 if(!vres) {
1713 fprintf(stderr, "Cannot find specified version for resource %s\n", res->path);
1714 ret = 1;
1715 break;
1716 }
1717 } else {
1718 vres = res;
1696 } 1719 }
1697 1720
1698 // download the resource 1721 // download the resource
1699 if(!sync_shutdown) { 1722 if(!sync_shutdown) {
1700 if(resource->isdirectory) { 1723 if(resource->isdirectory) {
1704 "Cannot create directory %s: %s", 1727 "Cannot create directory %s: %s",
1705 local_path, strerror(errno)); 1728 local_path, strerror(errno));
1706 } 1729 }
1707 free(local_path); 1730 free(local_path);
1708 } else { 1731 } else {
1709 if(sync_get_resource(a, dir, res, db, &sync_success)) { 1732 if(sync_get_resource(a, dir, res->path, vres, db, &sync_success)) {
1710 fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path); 1733 fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path);
1711 sync_error++; 1734 sync_error++;
1712 } 1735 }
1713 } 1736 }
1714 } 1737 }
1744 printf("Result: %d %s pulled, %d %s\n", 1767 printf("Result: %d %s pulled, %d %s\n",
1745 sync_success, str_success, 1768 sync_success, str_success,
1746 sync_error, str_error); 1769 sync_error, str_error);
1747 } 1770 }
1748 1771
1749 return 0; 1772 return ret;
1750 } 1773 }
1751 1774
1752 UcxList* local_scan(SyncDirectory *dir, SyncDatabase *db) { 1775 UcxList* local_scan(SyncDirectory *dir, SyncDatabase *db) {
1753 UcxList *resources = NULL; 1776 UcxList *resources = NULL;
1754 1777
2045 } else { 2068 } else {
2046 return 0; 2069 return 0;
2047 } 2070 }
2048 } 2071 }
2049 2072
2073 DavResource *versioning_simple_find(DavResource *res, const char *version) {
2074 char *vcol_href = dav_get_string_property_ns(res, DAV_NS, VERSION_PATH_PROPERTY);
2075 if(!vcol_href) {
2076 return NULL;
2077 }
2078 DavResource *vcol = dav_resource_new_href(res->session, vcol_href);
2079 if(!vcol) {
2080 return NULL;
2081 }
2082
2083
2084 if(dav_load_prop(vcol, defprops, numdefprops)) {
2085 print_resource_error(res->session, vcol->path);
2086 dav_resource_free(vcol);
2087 return NULL;
2088 }
2089
2090 DavResource *ret = NULL;
2091 DavResource *child = vcol->children;
2092 while(child) {
2093 DavResource *next = child->next;
2094 if(!strcmp(child->name, version)) {
2095 ret = child;
2096 } else {
2097 dav_resource_free(child);
2098 }
2099 child = next;
2100 }
2101 dav_resource_free(vcol);
2102
2103 return ret;
2104 }
2105
2106 // TODO: remove code dup (main.c: find_version)
2107 DavResource* versioning_deltav_find(DavResource *res, const char *version) {
2108 DavResource *list = dav_versiontree(res, "D:getetag,idav:status,idav:finfo,idav:xattributes,idav:tags");
2109 DavResource *ret = NULL;
2110 while(list) {
2111 DavResource *next = list->next;
2112 if(!ret) {
2113 char *vname = dav_get_string_property(list, "D:version-name");
2114 if(vname && !strcmp(vname, version)) {
2115 ret = list;
2116 }
2117 }
2118 if(list != ret) {
2119 dav_resource_free(list);
2120 }
2121 list = next;
2122 }
2123 return ret;
2124 }
2050 2125
2051 int sync_set_status(DavResource *res, char *status) { 2126 int sync_set_status(DavResource *res, char *status) {
2052 DavResource *resource = dav_resource_new(res->session, res->path); 2127 DavResource *resource = dav_resource_new(res->session, res->path);
2053 dav_set_string_property(resource, "idav:status", status); 2128 dav_set_string_property(resource, "idav:status", status);
2054 int ret = dav_store(resource); 2129 int ret = dav_store(resource);

mercurial