dav/sync.c

changeset 369
4322b8953bd5
parent 368
11797f33bc24
child 370
ab9c5afdc243
equal deleted inserted replaced
368:11797f33bc24 369:4322b8953bd5
546 if(sstrprefix(e, S("W/"))) { 546 if(sstrprefix(e, S("W/"))) {
547 e = sstrsubs(e, 2); 547 e = sstrsubs(e, 2);
548 } 548 }
549 if(!strcmp(e.ptr, local->etag)) { 549 if(!strcmp(e.ptr, local->etag)) {
550 // resource is already up-to-date on the client 550 // resource is already up-to-date on the client
551 sync_store_tags(dir, local_path, local, res);
551 free(local_path); 552 free(local_path);
552 return 0; 553 return 0;
553 } 554 }
554 } 555 }
555 556
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);

mercurial