1315 int ret = dav_store(resource); |
1316 int ret = dav_store(resource); |
1316 dav_resource_free(resource); |
1317 dav_resource_free(resource); |
1317 return ret; |
1318 return ret; |
1318 } |
1319 } |
1319 |
1320 |
|
1321 UcxList* sync_merge_tags(UcxList *tags1, UcxList *tags2) { |
|
1322 // this map is used to check the existence of tags |
|
1323 UcxMap *tag_map = ucx_map_new(32); |
|
1324 // merged taglist |
|
1325 UcxList *new_tags = NULL; |
|
1326 |
|
1327 // add all local tags |
|
1328 UCX_FOREACH(elm, tags1) { |
|
1329 DavTag *t = elm->data; |
|
1330 ucx_map_cstr_put(tag_map, t->name, t); |
|
1331 DavTag *newt = calloc(1, sizeof(DavTag)); |
|
1332 newt->color = t->color ? strdup(t->color) : NULL; |
|
1333 newt->name = strdup(t->name); |
|
1334 new_tags = ucx_list_append(new_tags, newt); |
|
1335 } |
|
1336 // check if a remote tag is already in the map |
|
1337 // and if not add it to the new taglist |
|
1338 UCX_FOREACH(elm, tags2) { |
|
1339 DavTag *t = elm->data; |
|
1340 if(!ucx_map_cstr_get(tag_map, t->name)) { |
|
1341 DavTag *newt = calloc(1, sizeof(DavTag)); |
|
1342 newt->color = t->color ? strdup(t->color) : NULL; |
|
1343 newt->name = strdup(t->name); |
|
1344 new_tags = ucx_list_append(new_tags, newt); |
|
1345 } |
|
1346 } |
|
1347 |
|
1348 ucx_map_free(tag_map); |
|
1349 |
|
1350 return new_tags; |
|
1351 } |
|
1352 |
1320 int sync_store_tags(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res) { |
1353 int sync_store_tags(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res) { |
1321 if(!dir->tagconfig) { |
1354 if(!dir->tagconfig) { |
1322 return 0; |
1355 return 0; |
1323 } |
1356 } |
1324 |
1357 |
1325 UcxList *tags = NULL; |
1358 UcxList *tags = NULL; |
1326 if(dir->tagconfig) { |
1359 if(dir->tagconfig) { |
1327 DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_NS, "tags"); |
1360 DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_NS, "tags"); |
1328 if(tagsprop) { |
1361 if(tagsprop) { |
1329 tags = parse_dav_xml_taglist(tagsprop); |
1362 tags = parse_dav_xml_taglist(tagsprop); |
|
1363 |
1330 } |
1364 } |
1331 } |
1365 } |
1332 |
1366 |
1333 DavBool store_empty_tags = FALSE; |
1367 DavBool store_empty_tags = FALSE; |
1334 if(dir->tagconfig->conflict != TAG_NO_CONFLICT) { |
1368 if(dir->tagconfig->conflict != TAG_NO_CONFLICT) { |
1342 // TODO: free tags |
1376 // TODO: free tags |
1343 break; |
1377 break; |
1344 } |
1378 } |
1345 case TAG_KEEP_REMOTE: break; |
1379 case TAG_KEEP_REMOTE: break; |
1346 case TAG_MERGE: { |
1380 case TAG_MERGE: { |
1347 // this map is used to check the existence of tags |
1381 UcxList *new_tags = sync_merge_tags(local_tags, tags); |
1348 UcxMap *tag_map = ucx_map_new(32); |
|
1349 // merged taglist |
|
1350 UcxList *new_tags = NULL; |
|
1351 |
|
1352 // add all local tags |
|
1353 UCX_FOREACH(elm, local_tags) { |
|
1354 DavTag *t = elm->data; |
|
1355 ucx_map_cstr_put(tag_map, t->name, t); |
|
1356 DavTag *newt = calloc(1, sizeof(DavTag)); |
|
1357 newt->color = t->color ? strdup(t->color) : NULL; |
|
1358 newt->name = strdup(t->name); |
|
1359 new_tags = ucx_list_append(new_tags, newt); |
|
1360 } |
|
1361 // check if a remote tag is already in the map |
|
1362 // and if not add it to the new taglist |
|
1363 UCX_FOREACH(elm, tags) { |
|
1364 DavTag *t = elm->data; |
|
1365 if(!ucx_map_cstr_get(tag_map, t->name)) { |
|
1366 DavTag *newt = calloc(1, sizeof(DavTag)); |
|
1367 newt->color = t->color ? strdup(t->color) : NULL; |
|
1368 newt->name = strdup(t->name); |
|
1369 new_tags = ucx_list_append(new_tags, newt); |
|
1370 } |
|
1371 } |
|
1372 |
|
1373 ucx_map_free(tag_map); |
|
1374 // TODO: free tags and local_tags |
1382 // TODO: free tags and local_tags |
1375 |
|
1376 tags = new_tags; |
1383 tags = new_tags; |
1377 |
1384 store_empty_tags = TRUE; |
1378 store_empty_tags = TRUE; |
1385 // make sure the merged tags will be pushed the next time |
1379 |
1386 local->tags_updated = TRUE; |
1380 break; |
1387 break; |
1381 } |
1388 } |
1382 } |
1389 } |
1383 } else { |
1390 } else { |
1384 // TODO: free local_tags |
1391 // TODO: free local_tags |
1408 break; |
1415 break; |
1409 } |
1416 } |
1410 } |
1417 } |
1411 |
1418 |
1412 if(data) { |
1419 if(data) { |
1413 ret = xattr_set(path, dir->tagconfig->xattr_name, data->space, data->pos); |
1420 char *data_hash = dav_create_hash(data->space, data->size); |
|
1421 if(!local->tags_hash || strcmp(data_hash, local->tags_hash)) { |
|
1422 printf("update: %s\n", local->path); |
|
1423 ret = xattr_set(path, dir->tagconfig->xattr_name, data->space, data->pos); |
|
1424 } |
1414 ucx_buffer_free(data); |
1425 ucx_buffer_free(data); |
1415 } else { |
1426 } else { |
1416 ret = -1; |
1427 ret = -1; |
1417 } |
1428 } |
1418 } else { |
1429 } else { |
1427 } |
1438 } |
1428 |
1439 |
1429 UcxBuffer* sync_get_file_tag_data(SyncDirectory *dir, LocalResource *res) { |
1440 UcxBuffer* sync_get_file_tag_data(SyncDirectory *dir, LocalResource *res) { |
1430 if(!dir->tagconfig) { |
1441 if(!dir->tagconfig) { |
1431 return NULL; |
1442 return NULL; |
|
1443 } |
|
1444 if(res->cached_tags) { |
|
1445 return res->cached_tags; |
1432 } |
1446 } |
1433 UcxBuffer *buf = NULL; |
1447 UcxBuffer *buf = NULL; |
1434 if(dir->tagconfig->store == TAG_STORE_XATTR) { |
1448 if(dir->tagconfig->store == TAG_STORE_XATTR) { |
1435 ssize_t tag_length = 0; |
1449 ssize_t tag_length = 0; |
1436 char *local_path = util_concat_path(dir->path, res->path); |
1450 char *local_path = util_concat_path(dir->path, res->path); |
1443 if(tag_length > 0) { |
1457 if(tag_length > 0) { |
1444 buf = ucx_buffer_new(tag_data, (size_t)tag_length, UCX_BUFFER_AUTOFREE); |
1458 buf = ucx_buffer_new(tag_data, (size_t)tag_length, UCX_BUFFER_AUTOFREE); |
1445 buf->size = (size_t)tag_length; |
1459 buf->size = (size_t)tag_length; |
1446 } |
1460 } |
1447 } |
1461 } |
|
1462 res->cached_tags = buf; |
1448 return buf; |
1463 return buf; |
1449 } |
1464 } |
1450 |
1465 |
1451 UcxList* sync_get_file_tags(SyncDirectory *dir, LocalResource *res, DavBool *changed) { |
1466 UcxList* sync_get_file_tags(SyncDirectory *dir, LocalResource *res, DavBool *changed) { |
1452 if(changed) *changed = FALSE; |
1467 if(changed) *changed = FALSE; |
1486 case TAG_FORMAT_MACOS: { |
1501 case TAG_FORMAT_MACOS: { |
1487 tags = parse_macos_taglist(tag_buf->space, tag_buf->size); |
1502 tags = parse_macos_taglist(tag_buf->space, tag_buf->size); |
1488 break; |
1503 break; |
1489 } |
1504 } |
1490 } |
1505 } |
1491 if(!res->cached_tags) { |
1506 res->cached_tags = tag_buf; |
1492 // we created the buffer therefore we destroy it |
|
1493 ucx_buffer_free(tag_buf); |
|
1494 } |
|
1495 } else if(res->tags_hash) { |
1507 } else if(res->tags_hash) { |
1496 if(changed) *changed = TRUE; |
1508 if(changed) *changed = TRUE; |
1497 } |
1509 } |
1498 } |
1510 } |
1499 |
1511 |
1551 |
1563 |
1552 if(ret == 0) { |
1564 if(ret == 0) { |
1553 (*counter)++; |
1565 (*counter)++; |
1554 |
1566 |
1555 // check contentlength and get new etag |
1567 // check contentlength and get new etag |
1556 DavResource *up_res = dav_get(res->session, res->path, "D:getetag,idav:status"); |
1568 DavResource *up_res = dav_get(res->session, res->path, "D:getetag,idav:status,idav:tags"); |
1557 |
1569 |
1558 if(up_res) { |
1570 if(up_res) { |
1559 // the new content length must be equal or greater than the file size |
1571 // the new content length must be equal or greater than the file size |
1560 if(up_res->contentlength < s.st_size) { |
1572 if(up_res->contentlength < s.st_size) { |
1561 fprintf(stderr, "Incomplete Upload: %s", local_path); |
1573 fprintf(stderr, "Incomplete Upload: %s", local_path); |
1654 |
1666 |
1655 // cleanup |
1667 // cleanup |
1656 dav_resource_free(res); |
1668 dav_resource_free(res); |
1657 |
1669 |
1658 return ret; |
1670 return ret; |
|
1671 } |
|
1672 |
|
1673 int sync_update_tags(SyncDirectory *dir, DavSession *sn, DavResource *res, LocalResource *local) { |
|
1674 if(!dir->tagconfig) { |
|
1675 return 0; |
|
1676 } |
|
1677 |
|
1678 // get local tags |
|
1679 DavBool changed = FALSE; |
|
1680 UcxList *tags = sync_get_file_tags(dir, local, &changed); |
|
1681 if(!tags || !changed) { |
|
1682 return 0; |
|
1683 } |
|
1684 |
|
1685 // local tags changed |
|
1686 DavBool update_tags = TRUE; |
|
1687 if(dir->tagconfig->conflict != TAG_NO_CONFLICT) { |
|
1688 // get tags from the server |
|
1689 DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_NS, "tags"); |
|
1690 UcxList *remote_tags = NULL; |
|
1691 if(tagsprop) { |
|
1692 remote_tags = parse_dav_xml_taglist(tagsprop); |
|
1693 } |
|
1694 |
|
1695 if(remote_tags) { |
|
1696 // compare the local tags with server tags |
|
1697 DavBool tags_equal = TRUE; |
|
1698 UcxList *local_t = tags; |
|
1699 UcxList *remote_t = remote_tags; |
|
1700 while(local_t) { |
|
1701 if(!remote_t) { |
|
1702 tags_equal = FALSE; |
|
1703 break; |
|
1704 } |
|
1705 |
|
1706 DavTag *lt = local_t->data; |
|
1707 DavTag *rt = remote_t->data; |
|
1708 if(strcmp(lt->name, rt->name)) { |
|
1709 tags_equal = FALSE; |
|
1710 break; |
|
1711 } |
|
1712 |
|
1713 local_t = local_t->next; |
|
1714 remote_t = remote_t->next; |
|
1715 } |
|
1716 |
|
1717 if(!tags_equal) { |
|
1718 switch(dir->tagconfig->conflict) { |
|
1719 case TAG_KEEP_LOCAL: break; |
|
1720 case TAG_KEEP_REMOTE: |
|
1721 case TAG_MERGE: { |
|
1722 printf("skip update: %s\n", local->path); |
|
1723 update_tags = FALSE; |
|
1724 break; |
|
1725 } |
|
1726 } |
|
1727 } |
|
1728 |
|
1729 // TODO: free remote_tags |
|
1730 } |
|
1731 } |
|
1732 |
|
1733 if(update_tags) { |
|
1734 DavXmlNode *prop = create_xml_taglist(tags); |
|
1735 if(prop) { |
|
1736 dav_set_property_ns(res, DAV_NS, "tags", prop); |
|
1737 if(dav_store(res)) { |
|
1738 print_resource_error(sn, local->path); |
|
1739 } |
|
1740 } |
|
1741 } |
|
1742 |
|
1743 // TODO: free stuff |
|
1744 return 0; |
1659 } |
1745 } |
1660 |
1746 |
1661 |
1747 |
1662 void remove_deleted_conflicts(SyncDirectory *dir, SyncDatabase *db) { |
1748 void remove_deleted_conflicts(SyncDirectory *dir, SyncDatabase *db) { |
1663 char **dc = calloc(sizeof(void*), db->conflict->count); |
1749 char **dc = calloc(sizeof(void*), db->conflict->count); |