67 static void xmlerrorfnc(void * c, const char * msg, ... ) { |
67 static void xmlerrorfnc(void * c, const char * msg, ... ) { |
68 va_list ap; |
68 va_list ap; |
69 va_start(ap, msg); |
69 va_start(ap, msg); |
70 vfprintf(stderr, msg, ap); |
70 vfprintf(stderr, msg, ap); |
71 va_end(ap); |
71 va_end(ap); |
|
72 } |
|
73 |
|
74 /* |
|
75 * strcmp version that works with NULL pointers |
|
76 */ |
|
77 static int nullstrcmp(const char *s1, const char *s2) { |
|
78 if(!s1 && s2) { |
|
79 return -1; |
|
80 } |
|
81 if(s1 && s2) { |
|
82 return 1; |
|
83 } |
|
84 if(!s1 && !s2) { |
|
85 return 0; |
|
86 } |
|
87 return strcmp(s1, s2); |
72 } |
88 } |
73 |
89 |
74 int main(int argc, char **argv) { |
90 int main(int argc, char **argv) { |
75 if(argc < 2) { |
91 if(argc < 2) { |
76 fprintf(stderr, "Missing command\n"); |
92 fprintf(stderr, "Missing command\n"); |
309 if(res->isdirectory) { |
325 if(res->isdirectory) { |
310 return 1; |
326 return 1; |
311 } |
327 } |
312 |
328 |
313 DavBool changed = 0; |
329 DavBool changed = 0; |
314 UcxList *res_tags = sync_get_file_tags(dir, res, &changed); |
330 UcxList *res_tags = sync_get_file_tags(dir, res, &changed, NULL); |
315 |
331 |
316 int ret = matches_tagfilter(res_tags, tagfilter); |
332 int ret = matches_tagfilter(res_tags, tagfilter); |
317 UCX_FOREACH(elm, res_tags) { |
333 UCX_FOREACH(elm, res_tags) { |
318 DavTag *t = elm->data; |
334 DavTag *t = elm->data; |
319 free_dav_tag(t); |
335 free_dav_tag(t); |
1317 sync_error++; |
1333 sync_error++; |
1318 error = 1; |
1334 error = 1; |
1319 abort = 1; |
1335 abort = 1; |
1320 } |
1336 } |
1321 |
1337 |
1322 if(dir->tagconfig && local_res->tags_updated && !abort) { |
1338 if(local_res->metadata_updated && !abort) { |
1323 sync_update_metadata(dir, sn, res, local_res); |
1339 sync_update_metadata(dir, sn, res, local_res); |
1324 } |
1340 } |
1325 } else if(sn->error != DAV_OK) { |
1341 } else if(sn->error != DAV_OK) { |
1326 // dav_exists() failed |
1342 // dav_exists() failed |
1327 print_resource_error(sn, local_res->path); |
1343 print_resource_error(sn, local_res->path); |
1328 ret = -1; |
1344 ret = -1; |
1329 sync_error++; |
1345 sync_error++; |
1330 error = 1; |
1346 error = 1; |
1331 } |
1347 } |
1332 } else { |
1348 } else { |
1333 if(cdt && remote_resource_is_changed(sn, dir, db, local_res)) { |
1349 if(cdt && remote_resource_is_changed(sn, dir, db, res, local_res)) { |
1334 printf("conflict: %s\n", local_res->path); |
1350 printf("conflict: %s\n", local_res->path); |
1335 local_res->last_modified = 0; |
1351 local_res->last_modified = 0; |
1336 local_res->skipped = TRUE; |
1352 local_res->skipped = TRUE; |
1337 sync_skipped++; |
1353 sync_skipped++; |
1338 } else { |
1354 } else { |
1355 // metadata updates |
1371 // metadata updates |
1356 for(UcxList *elm=ls_update;elm && !sync_shutdown;elm=elm->next) { |
1372 for(UcxList *elm=ls_update;elm && !sync_shutdown;elm=elm->next) { |
1357 LocalResource *local_res = elm->data; |
1373 LocalResource *local_res = elm->data; |
1358 |
1374 |
1359 DavResource *res = dav_resource_new(sn, local_res->path); |
1375 DavResource *res = dav_resource_new(sn, local_res->path); |
|
1376 if(dir->tagconfig) { |
|
1377 DavPropName properties[] = { |
|
1378 {DAV_NS,"tags"}, |
|
1379 }; |
|
1380 if(dav_load_prop(res, properties, 1)) { |
|
1381 sync_error++; |
|
1382 print_resource_error(sn, res->path); |
|
1383 ret = -1; |
|
1384 error = 1; |
|
1385 continue; |
|
1386 } |
|
1387 } |
1360 |
1388 |
1361 if(local_res->metadata_updated) { |
1389 if(local_res->metadata_updated) { |
1362 if(!sync_update_metadata(dir, sn, res, local_res)) { |
1390 if(!sync_update_metadata(dir, sn, res, local_res)) { |
1363 LocalResource *dbres = ucx_map_cstr_remove(db->resources, local_res->path); |
1391 LocalResource *dbres = ucx_map_cstr_remove(db->resources, local_res->path); |
1364 ucx_map_cstr_put(db->resources, local_res->path, local_res); |
1392 ucx_map_cstr_put(db->resources, local_res->path, local_res); |
1762 res->etag = strdup(db_res->etag); |
1790 res->etag = strdup(db_res->etag); |
1763 } |
1791 } |
1764 if(db_res->tags_hash) { |
1792 if(db_res->tags_hash) { |
1765 res->tags_hash = strdup(db_res->tags_hash); |
1793 res->tags_hash = strdup(db_res->tags_hash); |
1766 } |
1794 } |
|
1795 if(db_res->remote_tags_hash) { |
|
1796 res->remote_tags_hash = strdup(db_res->remote_tags_hash); |
|
1797 } |
|
1798 if(db_res->xattr_hash) { |
|
1799 res->xattr_hash = strdup(db_res->xattr_hash); |
|
1800 } |
1767 |
1801 |
1768 if(dir->tagconfig && dir->tagconfig->detect_changes && !res->tags_updated) { |
1802 if(dir->tagconfig && dir->tagconfig->detect_changes && !res->tags_updated) { |
1769 UcxBuffer *tags = sync_get_file_tag_data(dir, res); |
1803 UcxBuffer *tags = sync_get_file_tag_data(dir, res); |
1770 if(tags) { |
1804 if(tags) { |
1771 if(db_res->tags_hash) { |
1805 if(db_res->tags_hash) { |
1821 |
1855 |
1822 int remote_resource_is_changed( |
1856 int remote_resource_is_changed( |
1823 DavSession *sn, |
1857 DavSession *sn, |
1824 SyncDirectory *dir, |
1858 SyncDirectory *dir, |
1825 SyncDatabase *db, |
1859 SyncDatabase *db, |
|
1860 DavResource *remote, |
1826 LocalResource *res) |
1861 LocalResource *res) |
1827 { |
1862 { |
|
1863 DavPropName properties[] = { |
|
1864 {"DAV:","getetag"}, |
|
1865 {DAV_NS,"tags"}, |
|
1866 {DAV_NS,VERSION_PATH_PROPERTY} |
|
1867 }; |
|
1868 int err = dav_load_prop(remote, properties, 3); |
|
1869 |
1828 if(res->restore) { |
1870 if(res->restore) { |
1829 return 0; |
1871 return 0; |
1830 } |
1872 } |
1831 |
1873 |
1832 DavResource *remote = dav_get(sn, res->path, "D:getetag"); |
|
1833 int ret = 0; |
1874 int ret = 0; |
1834 if(remote) { |
1875 if(err == 0) { |
1835 char *etag = dav_get_string_property(remote, "D:getetag"); |
1876 char *etag = dav_get_string_property(remote, "D:getetag"); |
1836 if(!res->etag) { |
1877 if(!res->etag) { |
1837 // the resource is on the server and the client has no etag |
1878 // the resource is on the server and the client has no etag |
1838 ret = 1; |
1879 ret = 1; |
1839 } else if(etag) { |
1880 } else if(etag) { |
1846 } |
1887 } |
1847 } else { |
1888 } else { |
1848 // something weird is happening, the server must support etags |
1889 // something weird is happening, the server must support etags |
1849 fprintf(stderr, "Warning: resource %s has no etag\n", remote->href); |
1890 fprintf(stderr, "Warning: resource %s has no etag\n", remote->href); |
1850 } |
1891 } |
1851 dav_resource_free(remote); |
|
1852 } |
1892 } |
1853 return ret; |
1893 return ret; |
1854 } |
1894 } |
1855 |
1895 |
1856 int resource_pathlen_cmp(LocalResource *res1, LocalResource *res2, void *n) { |
1896 int resource_pathlen_cmp(LocalResource *res1, LocalResource *res2, void *n) { |
1878 DavResource *resource = dav_resource_new(res->session, res->path); |
1918 DavResource *resource = dav_resource_new(res->session, res->path); |
1879 dav_remove_property(resource, "idav:status"); |
1919 dav_remove_property(resource, "idav:status"); |
1880 int ret = dav_store(resource); |
1920 int ret = dav_store(resource); |
1881 dav_resource_free(resource); |
1921 dav_resource_free(resource); |
1882 return ret; |
1922 return ret; |
1883 } |
|
1884 |
|
1885 UcxList* sync_merge_tags(UcxList *tags1, UcxList *tags2) { |
|
1886 // this map is used to check the existence of tags |
|
1887 UcxMap *tag_map = ucx_map_new(32); |
|
1888 // merged taglist |
|
1889 UcxList *new_tags = NULL; |
|
1890 |
|
1891 // add all local tags |
|
1892 UCX_FOREACH(elm, tags1) { |
|
1893 DavTag *t = elm->data; |
|
1894 ucx_map_cstr_put(tag_map, t->name, t); |
|
1895 DavTag *newt = calloc(1, sizeof(DavTag)); |
|
1896 newt->color = t->color ? strdup(t->color) : NULL; |
|
1897 newt->name = strdup(t->name); |
|
1898 new_tags = ucx_list_append(new_tags, newt); |
|
1899 } |
|
1900 // check if a remote tag is already in the map |
|
1901 // and if not add it to the new taglist |
|
1902 UCX_FOREACH(elm, tags2) { |
|
1903 DavTag *t = elm->data; |
|
1904 if(!ucx_map_cstr_get(tag_map, t->name)) { |
|
1905 DavTag *newt = calloc(1, sizeof(DavTag)); |
|
1906 newt->color = t->color ? strdup(t->color) : NULL; |
|
1907 newt->name = strdup(t->name); |
|
1908 new_tags = ucx_list_append(new_tags, newt); |
|
1909 } |
|
1910 } |
|
1911 |
|
1912 ucx_map_free(tag_map); |
|
1913 |
|
1914 return new_tags; |
|
1915 } |
1923 } |
1916 |
1924 |
1917 int sync_tags_equal(UcxList *tags1, UcxList *tags2) { |
1925 int sync_tags_equal(UcxList *tags1, UcxList *tags2) { |
1918 if(!tags1) { |
1926 if(!tags1) { |
1919 return tags2 ? 0 : 1; |
1927 return tags2 ? 0 : 1; |
1960 } |
1968 } |
1961 } |
1969 } |
1962 |
1970 |
1963 DavBool store_tags = FALSE; |
1971 DavBool store_tags = FALSE; |
1964 DavBool tags_changed = FALSE; |
1972 DavBool tags_changed = FALSE; |
1965 UcxList *local_tags = sync_get_file_tags(dir, local, &tags_changed); |
1973 UcxList *local_tags = sync_get_file_tags(dir, local, &tags_changed, NULL); |
1966 if(tags_changed) { |
1974 if(tags_changed) { |
1967 switch(dir->tagconfig->conflict) { |
1975 switch(dir->tagconfig->conflict) { |
1968 case TAG_NO_CONFLICT: |
1976 case TAG_NO_CONFLICT: |
1969 case TAG_KEEP_LOCAL: { |
1977 case TAG_KEEP_LOCAL: { |
1970 store_tags = FALSE; |
1978 store_tags = FALSE; |
1973 case TAG_KEEP_REMOTE: { |
1981 case TAG_KEEP_REMOTE: { |
1974 store_tags = TRUE; |
1982 store_tags = TRUE; |
1975 local->tags_updated = FALSE; |
1983 local->tags_updated = FALSE; |
1976 } |
1984 } |
1977 case TAG_MERGE: { |
1985 case TAG_MERGE: { |
1978 UcxList *new_tags = sync_merge_tags(local_tags, tags); |
1986 UcxList *new_tags = merge_tags(local_tags, tags); |
1979 // TODO: free tags and local_tags |
1987 // TODO: free tags and local_tags |
1980 tags = new_tags; |
1988 tags = new_tags; |
1981 store_tags = TRUE; |
1989 store_tags = TRUE; |
1982 // make sure the merged tags will be pushed the next time |
1990 // make sure the merged tags will be pushed the next time |
1983 local->tags_updated = TRUE; |
1991 local->tags_updated = TRUE; |
2104 UcxBuffer *tag_buf = res->cached_tags ? |
2112 UcxBuffer *tag_buf = res->cached_tags ? |
2105 res->cached_tags : |
2113 res->cached_tags : |
2106 sync_get_file_tag_data(dir, res); |
2114 sync_get_file_tag_data(dir, res); |
2107 |
2115 |
2108 if(tag_buf) { |
2116 if(tag_buf) { |
2109 char *newhash = dav_create_hash(tag_buf->space, tag_buf->size); |
2117 char *new_hash = dav_create_hash(tag_buf->space, tag_buf->size); |
2110 if(res->tags_hash) { |
2118 if(res->tags_hash) { |
2111 if(changed && strcmp(res->tags_hash, newhash)) { |
2119 if(changed && strcmp(res->tags_hash, new_hash)) { |
2112 *changed = TRUE; |
2120 *changed = TRUE; |
2113 } |
2121 } |
2114 free(res->tags_hash); |
2122 free(res->tags_hash); |
2115 } else { |
2123 } else { |
2116 if(changed) *changed = TRUE; |
2124 if(changed) *changed = TRUE; |
2117 } |
2125 } |
2118 res->tags_hash = newhash; |
2126 if(!newhash) { |
|
2127 *newhash = new_hash; |
|
2128 } else { |
|
2129 free(newhash); |
|
2130 } |
2119 |
2131 |
2120 switch(dir->tagconfig->local_format) { |
2132 switch(dir->tagconfig->local_format) { |
2121 default: break; |
2133 default: break; |
2122 case TAG_FORMAT_TEXT: { |
2134 case TAG_FORMAT_TEXT: { |
2123 tags = parse_text_taglist(tag_buf->space, tag_buf->size); |
2135 tags = parse_text_taglist(tag_buf->space, tag_buf->size); |
2164 |
2176 |
2165 #define VBEGIN_ERROR_MKCOL 1 |
2177 #define VBEGIN_ERROR_MKCOL 1 |
2166 #define VBEGIN_ERROR_MOVE 2 |
2178 #define VBEGIN_ERROR_MOVE 2 |
2167 #define VBEGIN_ERROR_PROPPATCH 3 |
2179 #define VBEGIN_ERROR_PROPPATCH 3 |
2168 #define VBEGIN_ERROR_CHECKOUT 4 |
2180 #define VBEGIN_ERROR_CHECKOUT 4 |
2169 int versioning_begin(SyncDirectory *dir, DavResource *res, int *exists) { |
2181 int versioning_begin(SyncDirectory *dir, DavResource *res) { |
2170 int ret = 0; |
2182 int ret = 0; |
2171 |
2183 |
2172 if(dir->versioning->type == VERSIONING_SIMPLE && *exists) { |
2184 if(dir->versioning->type == VERSIONING_SIMPLE && res->exists) { |
2173 DavResource *history_collection = dav_resource_new( |
2185 DavResource *history_collection = dav_resource_new( |
2174 res->session, |
2186 res->session, |
2175 dir->versioning->collection); |
2187 dir->versioning->collection); |
2176 |
2188 |
2177 // get the path to the version history collection for this resource |
2189 // get the path to the version history collection for this resource |
2178 // if propfind fails we just assume that it doesn't exist |
2190 // if propfind fails we just assume that it doesn't exist |
2179 // better error handling is done later (sync_put_resource) |
2191 // better error handling is done later (sync_put_resource) |
2180 // if there is no history collection for this resource, we create one |
2192 // if there is no history collection for this resource, we create one |
2181 |
|
2182 DavPropName prop; |
|
2183 prop.ns = DAV_NS; |
|
2184 prop.name = VERSION_PATH_PROPERTY; |
|
2185 *exists = dav_load_prop(res, &prop, 1); |
|
2186 |
2193 |
2187 char *history_href = NULL; |
2194 char *history_href = NULL; |
2188 char *vcol_path = dav_get_string_property_ns(res, DAV_NS, VERSION_PATH_PROPERTY); |
2195 char *vcol_path = dav_get_string_property_ns(res, DAV_NS, VERSION_PATH_PROPERTY); |
2189 if(!vcol_path) { |
2196 if(!vcol_path) { |
2190 DavResource *history_res = NULL; |
2197 DavResource *history_res = NULL; |
2287 // TODO |
2294 // TODO |
2288 } |
2295 } |
2289 return 0; |
2296 return 0; |
2290 } |
2297 } |
2291 |
2298 |
|
2299 static void update_metadata_hashes(LocalResource *local, MetadataHashes hashes) { |
|
2300 if(hashes.tags) { |
|
2301 if(local->tags_hash) { |
|
2302 free(local->tags_hash); |
|
2303 } |
|
2304 local->tags_hash = hashes.tags; |
|
2305 } |
|
2306 if(hashes.tags_remote) { |
|
2307 if(local->remote_tags_hash) { |
|
2308 free(local->remote_tags_hash); |
|
2309 } |
|
2310 local->remote_tags_hash = hashes.tags_remote; |
|
2311 } |
|
2312 if(hashes.xattr) { |
|
2313 if(local->xattr_hash) { |
|
2314 free(local->xattr_hash); |
|
2315 } |
|
2316 local->xattr_hash = hashes.xattr; |
|
2317 } |
|
2318 } |
|
2319 |
2292 int sync_put_resource( |
2320 int sync_put_resource( |
2293 SyncDirectory *dir, |
2321 SyncDirectory *dir, |
2294 DavResource *res, |
2322 DavResource *res, |
2295 LocalResource *local, |
2323 LocalResource *local, |
2296 int *counter) |
2324 int *counter) |
2313 } |
2341 } |
2314 |
2342 |
2315 dav_set_content(res, in, (dav_read_func)myread, (dav_seek_func)file_seek); |
2343 dav_set_content(res, in, (dav_read_func)myread, (dav_seek_func)file_seek); |
2316 dav_set_content_length(res, s.st_size); |
2344 dav_set_content_length(res, s.st_size); |
2317 |
2345 |
2318 if(dir->tagconfig) { |
2346 MetadataHashes hashes; |
2319 UcxList *tags = sync_get_file_tags(dir, local, NULL); |
2347 hashes = sync_set_metadata_properties(dir, res->session, res, local); |
2320 DavXmlNode *prop = create_xml_taglist(tags); |
2348 |
2321 if(prop) { |
2349 // before sync_put_resource, remote_resource_is_changed does a propfind |
2322 dav_set_property_ns(res, DAV_NS, "tags", prop); |
2350 // and sets res->exists |
2323 } |
2351 int exists = res->exists; |
2324 } |
|
2325 |
|
2326 int exists = dav_exists(res); |
|
2327 if(dir->versioning && dir->versioning->always) { |
2352 if(dir->versioning && dir->versioning->always) { |
2328 int err = versioning_begin(dir, res, &exists); |
2353 int err = versioning_begin(dir, res); |
2329 if(err) { |
2354 if(err) { |
2330 fprintf(stderr, "Cannot store version for resource: %s\n", res->href); |
2355 fprintf(stderr, "Cannot store version for resource: %s\n", res->href); |
2331 free(local_path); |
2356 free(local_path); |
2332 return -1; |
2357 return -1; |
2333 } |
2358 } |
2334 } else { |
|
2335 exists = dav_exists(res); |
|
2336 } |
2359 } |
2337 |
2360 |
2338 int ret = -1; |
2361 int ret = -1; |
2339 for(int i=0;i<=dir->max_retry;i++) { |
2362 for(int i=0;i<=dir->max_retry;i++) { |
2340 if(!exists && dav_create(res)) { |
2363 if(!exists && dav_create(res)) { |
2481 dav_resource_free(res); |
2506 dav_resource_free(res); |
2482 |
2507 |
2483 return ret; |
2508 return ret; |
2484 } |
2509 } |
2485 |
2510 |
2486 int sync_update_metadata(SyncDirectory *dir, DavSession *sn, DavResource *res, LocalResource *local) { |
2511 MetadataHashes sync_set_metadata_properties( |
2487 if(dir->tagconfig && local->tags_updated) { |
2512 SyncDirectory *dir, |
|
2513 DavSession *sn, |
|
2514 DavResource *res, |
|
2515 LocalResource *local) |
|
2516 { |
|
2517 MetadataHashes hashes = {NULL, NULL, NULL}; |
|
2518 if(dir->tagconfig) { |
2488 // get local tags |
2519 // get local tags |
2489 UcxList *tags = sync_get_file_tags(dir, local, NULL); |
2520 DavBool changed = 0; |
2490 |
2521 char *tags_hash = NULL; |
2491 DavXmlNode *prop = create_xml_taglist(tags); |
2522 UcxList *tags = sync_get_file_tags(dir, local, &changed, &tags_hash); |
2492 if(prop) { |
2523 if(changed || local->tags_updated) { |
2493 dav_set_property_ns(res, DAV_NS, "tags", prop); |
2524 hashes.tags = tags_hash; |
|
2525 |
|
2526 DavBool store_tags = TRUE; |
|
2527 // get remote tags |
|
2528 UcxList *remote_tags = NULL; |
|
2529 DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_NS, "tags"); |
|
2530 if(tagsprop) { |
|
2531 remote_tags = parse_dav_xml_taglist(tagsprop); |
|
2532 } |
|
2533 char *remote_hash = create_tags_hash(remote_tags); |
|
2534 if(nullstrcmp(remote_hash, local->remote_tags_hash)) { |
|
2535 // the tags have changed on the server |
|
2536 switch(dir->tagconfig->conflict) { |
|
2537 case TAG_NO_CONFLICT: break; |
|
2538 case TAG_KEEP_LOCAL: break; |
|
2539 case TAG_KEEP_REMOTE: { |
|
2540 store_tags = FALSE; |
|
2541 local->tags_updated = FALSE; |
|
2542 break; |
|
2543 } |
|
2544 case TAG_MERGE: { |
|
2545 UcxList *new_tags = merge_tags(tags, remote_tags); |
|
2546 free_taglist(tags); |
|
2547 tags = new_tags; |
|
2548 break; |
|
2549 } |
|
2550 } |
|
2551 } |
|
2552 |
|
2553 if(dir->tagconfig->local_format == TAG_FORMAT_CSV) { |
|
2554 // csv tag lists don't have colors, so we have to add |
|
2555 // the colors from the remote tag list |
|
2556 add_tag_colors(tags, remote_tags); |
|
2557 } |
|
2558 |
|
2559 if(store_tags) { |
|
2560 if(tags) { |
|
2561 DavXmlNode *tagprop = create_xml_taglist(tags); |
|
2562 dav_set_property_ns(res, DAV_NS, "tags", tagprop); |
|
2563 } else { |
|
2564 dav_remove_property_ns(res, DAV_NS, "tags"); |
|
2565 } |
|
2566 } |
|
2567 |
|
2568 free_taglist(remote_tags); |
2494 } else { |
2569 } else { |
2495 dav_remove_property_ns(res, DAV_NS, "tags"); |
2570 if(tags_hash) { |
2496 } |
2571 free(tags_hash); |
|
2572 } |
|
2573 } |
|
2574 free_taglist(tags); |
2497 } |
2575 } |
2498 |
2576 |
2499 if(local->finfo_updated) { |
2577 if(local->finfo_updated) { |
2500 struct stat s; |
2578 struct stat s; |
2501 s.st_mode = local->mode; |
2579 s.st_mode = local->mode; |
2506 } |
2584 } |
2507 |
2585 |
2508 if(local->xattr_updated) { |
2586 if(local->xattr_updated) { |
2509 if(local->xattr) { |
2587 if(local->xattr) { |
2510 resource_set_xattr(res, local->xattr); |
2588 resource_set_xattr(res, local->xattr); |
|
2589 hashes.xattr = strdup(local->xattr->hash); |
2511 } else { |
2590 } else { |
2512 dav_remove_property(res, "idav:xattributes"); |
2591 dav_remove_property(res, "idav:xattributes"); |
2513 } |
2592 } |
2514 } |
2593 } |
|
2594 return hashes; |
|
2595 } |
|
2596 |
|
2597 int sync_update_metadata( |
|
2598 SyncDirectory *dir, |
|
2599 DavSession *sn, |
|
2600 DavResource *res, |
|
2601 LocalResource *local) |
|
2602 { |
|
2603 MetadataHashes hashes = sync_set_metadata_properties(dir, sn, res, local); |
2515 |
2604 |
2516 int err = 0; |
2605 int err = 0; |
2517 printf("update: %s\n", local->path); |
2606 printf("update: %s\n", local->path); |
2518 if(dav_store(res)) { |
2607 if(dav_store(res)) { |
2519 print_resource_error(sn, local->path); |
2608 print_resource_error(sn, local->path); |
2520 err = 1; |
2609 err = 1; |
2521 } else { |
2610 } else { |
2522 if(dir->tagconfig && local->tags_updated) { |
2611 update_metadata_hashes(local, hashes); |
2523 UcxBuffer *tag_data = local->cached_tags; |
2612 } |
2524 if(local->tags_hash) { |
2613 |
2525 free(local->tags_hash); |
|
2526 local->tags_hash = NULL; |
|
2527 } |
|
2528 if(tag_data) { |
|
2529 char *hash = dav_create_hash(tag_data->space, tag_data->size); |
|
2530 local->tags_hash = hash; |
|
2531 } |
|
2532 local->tags_updated = FALSE; |
|
2533 } |
|
2534 if(local->xattr) { |
|
2535 local->xattr_hash = strdup(local->xattr->hash); |
|
2536 } |
|
2537 } |
|
2538 |
|
2539 // TODO: free stuff |
|
2540 return err; |
2614 return err; |
2541 } |
2615 } |
2542 |
2616 |
2543 void remove_deleted_conflicts(SyncDirectory *dir, SyncDatabase *db) { |
2617 void remove_deleted_conflicts(SyncDirectory *dir, SyncDatabase *db) { |
2544 char **dc = calloc(sizeof(void*), db->conflict->count); |
2618 char **dc = calloc(sizeof(void*), db->conflict->count); |
2893 int cmd_add_tag(CmdArgs *args) { |
2967 int cmd_add_tag(CmdArgs *args) { |
2894 if(args->argc != 2) { |
2968 if(args->argc != 2) { |
2895 fprintf(stderr, "Too %s arguments\n", args->argc <= 1 ? "few" : "many"); |
2969 fprintf(stderr, "Too %s arguments\n", args->argc <= 1 ? "few" : "many"); |
2896 return -1; |
2970 return -1; |
2897 } |
2971 } |
2898 return cmd_tagopt(args, CMD_TAG_ADD); |
2972 return cmd_tagop(args, CMD_TAG_ADD); |
2899 } |
2973 } |
2900 |
2974 |
2901 int cmd_remove_tag(CmdArgs *args) { |
2975 int cmd_remove_tag(CmdArgs *args) { |
2902 if(args->argc != 2) { |
2976 if(args->argc != 2) { |
2903 fprintf(stderr, "Too %s arguments\n", args->argc <= 1 ? "few" : "many"); |
2977 fprintf(stderr, "Too %s arguments\n", args->argc <= 1 ? "few" : "many"); |
2904 return -1; |
2978 return -1; |
2905 } |
2979 } |
2906 return cmd_tagopt(args, CMD_TAG_REMOVE); |
2980 return cmd_tagop(args, CMD_TAG_REMOVE); |
2907 } |
2981 } |
2908 |
2982 |
2909 int cmd_set_tags(CmdArgs *args) { |
2983 int cmd_set_tags(CmdArgs *args) { |
2910 if(args->argc < 1 || args->argc > 2) { |
2984 if(args->argc < 1 || args->argc > 2) { |
2911 fprintf(stderr, "Too %s arguments\n", args->argc < 1 ? "few" : "many"); |
2985 fprintf(stderr, "Too %s arguments\n", args->argc < 1 ? "few" : "many"); |
2912 return -1; |
2986 return -1; |
2913 } |
2987 } |
2914 return cmd_tagopt(args, CMD_TAG_SET); |
2988 return cmd_tagop(args, CMD_TAG_SET); |
2915 } |
2989 } |
2916 |
2990 |
2917 int cmd_list_tags(CmdArgs *args) { |
2991 int cmd_list_tags(CmdArgs *args) { |
2918 if(args->argc != 1) { |
2992 if(args->argc != 1) { |
2919 fprintf(stderr, "Too %s arguments\n", args->argc <= 1 ? "few" : "many"); |
2993 fprintf(stderr, "Too %s arguments\n", args->argc <= 1 ? "few" : "many"); |
2920 return -1; |
2994 return -1; |
2921 } |
2995 } |
2922 return cmd_tagopt(args, CMD_TAG_LIST); |
2996 return cmd_tagop(args, CMD_TAG_LIST); |
2923 } |
2997 } |
2924 |
2998 |
2925 int cmd_tagopt(CmdArgs *args, int cmd) { |
2999 int cmd_tagop(CmdArgs *args, int cmd) { |
2926 SyncFile file; |
3000 SyncFile file; |
2927 int ret = 0; |
3001 int ret = 0; |
2928 char *path = args->argv[0]; |
3002 char *path = args->argv[0]; |
2929 |
3003 |
2930 int err = sync_get_file(args, path, NULL, &file); |
3004 int err = sync_get_file(args, path, NULL, &file); |
2950 |
3024 |
2951 if(cmd != CMD_TAG_SET) { |
3025 if(cmd != CMD_TAG_SET) { |
2952 char *tag = args->argv[1]; |
3026 char *tag = args->argv[1]; |
2953 char *tagcolor = NULL; // TODO: get color |
3027 char *tagcolor = NULL; // TODO: get color |
2954 |
3028 |
2955 tags = sync_get_file_tags(file.dir, localres, NULL); |
3029 tags = sync_get_file_tags(file.dir, localres, NULL, NULL); |
2956 UcxList *x = NULL; |
3030 UcxList *x = NULL; |
2957 UCX_FOREACH(elm, tags) { |
3031 UCX_FOREACH(elm, tags) { |
2958 DavTag *t = elm->data; |
3032 DavTag *t = elm->data; |
2959 if(cmd == CMD_TAG_LIST) { |
3033 if(cmd == CMD_TAG_LIST) { |
2960 printf("%s\n", t->name); |
3034 printf("%s\n", t->name); |