# HG changeset patch # User Olaf Wintermann # Date 1553768353 -3600 # Node ID e59a989d890d3e53e3a306fd458068d7e722a58c # Parent d18f92483945e2f3b4f55cdc892f6c4308e0b277 adds content hash for splitted files diff -r d18f92483945 -r e59a989d890d dav/db.c --- a/dav/db.c Tue Mar 26 18:28:37 2019 +0100 +++ b/dav/db.c Thu Mar 28 11:19:13 2019 +0100 @@ -211,6 +211,8 @@ field = 9; } else if(xstreq(name, "blocksize")) { field = 10; + } else if(xstreq(name, "hash")) { + field = 11; } else if(xstreq(name, "skipped")) { res->skipped = TRUE; } else if(xstreq(name, "tags-updated")) { @@ -300,6 +302,11 @@ } res->blocksize = blsz; } + break; + } + case 11: { + res->hash = strdup((char*)value); + break; } } } else if(XML_READER_TYPE_END_ELEMENT) { @@ -401,6 +408,18 @@ return -1; } } + + if(res->hash) { + r = xmlTextWriterWriteElement( + writer, + BAD_CAST "hash", + BAD_CAST res->hash); + if(r < 0) { + fprintf(stderr, "Cannot write hash: %s\n", res->hash); + xmlFreeTextWriter(writer); + return -1; + } + } r = xmlTextWriterWriteFormatElement( writer, diff -r d18f92483945 -r e59a989d890d dav/db.h --- a/dav/db.h Tue Mar 26 18:28:37 2019 +0100 +++ b/dav/db.h Thu Mar 28 11:19:13 2019 +0100 @@ -54,6 +54,7 @@ char *name; char *path; char *etag; + char *hash; time_t last_modified; mode_t mode; uid_t uid; diff -r d18f92483945 -r e59a989d890d dav/sync.c --- a/dav/sync.c Tue Mar 26 18:28:37 2019 +0100 +++ b/dav/sync.c Thu Mar 28 11:19:13 2019 +0100 @@ -80,6 +80,7 @@ { DAV_NS, "finfo" }, { DAV_NS, "tags" }, { DAV_NS, "xattributes" }, + { DAV_NS, "content-hash" }, { DAV_NS, "split" } }; static size_t numdefprops = 6; @@ -2042,6 +2043,7 @@ {"DAV:", "getetag"}, {DAV_NS, "tags"}, {DAV_NS, "version-collection"}, + {DAV_NS, "content-hash"}, {DAV_NS, "split" } }; int err = dav_load_prop(remote, properties, 4); @@ -2053,7 +2055,12 @@ int ret = 0; if(err == 0) { char *etag = dav_get_string_property(remote, "D:getetag"); - if(!res->etag) { + char *hash = dav_get_string_property(remote, "idav:content-hash"); + if(hash || res->hash) { + if(!nullstrcmp(hash, res->hash)) { + ret = 1; + } + } else if(!res->etag) { // the resource is on the server and the client has no etag ret = 1; } else if(etag) { @@ -2735,7 +2742,11 @@ uint32_t session_flags = res->session->flags; res->session->flags ^= DAV_SESSION_ENCRYPT_NAME; + DAV_SHA_CTX *sha = dav_hash_init(); + while((r = fread(buffer, 1, blocksize, in)) > 0) { + dav_hash_update(sha, buffer, r); + int upload_block = 0; char *block_hash = dav_create_hash(buffer, r); if(blockindex >= local->numparts) { @@ -2796,6 +2807,15 @@ return NULL; } + // set content-hash + char content_hash[DAV_SHA256_DIGEST_LENGTH]; + dav_hash_final(sha, content_hash); + char *hash_hex = util_hexstr(content_hash, DAV_SHA256_DIGEST_LENGTH); + dav_set_string_property_ns(res, DAV_NS, "content-hash", hash_hex); + local->hash = hash_hex; + + // get etags from uploaded resources + // also delete everything, that is not part of the file UcxList *updated_parts = NULL; DavResource *parts = dav_query(res->session, "select D:getetag from %s order by name", res->path); if(!parts) { @@ -2932,6 +2952,11 @@ dav_set_content(res, in, (dav_read_func)myread, (dav_seek_func)file_seek); dav_set_content_length(res, s.st_size); } else { + // set split property + char blocksize_str[32]; + snprintf(blocksize_str, 32, "%zu", split_blocksize); + dav_set_string_property_ns(res, DAV_NS, "split", blocksize_str); + // splitted/partial upload parts = upload_parts( local,